Various fixes to enable recording on passion and nexus1.

Change-Id: I75a461c9882e2449082ad754ee7b231c1ceec039
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 845c854..5a87f4c 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -147,7 +147,7 @@
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
 
-#if 1
+#if 0
     sp<MediaSource> source = createSource(argv[1]);
 
     if (source == NULL) {
@@ -165,14 +165,15 @@
     success = success && meta->findInt32(kKeyHeight, &height);
     CHECK(success);
 #else
-    int width = 800;
+    int width = 720;
     int height = 480;
     sp<MediaSource> decoder = new DummySource(width, height);
 #endif
 
     sp<MetaData> enc_meta = new MetaData;
     // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
-    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
 
@@ -213,6 +214,8 @@
 
 #if 0
     CameraSource *source = CameraSource::Create();
+    source->start();
+
     printf("source = %p\n", source);
 
     for (int i = 0; i < 100; ++i) {
@@ -227,6 +230,8 @@
         buffer = NULL;
     }
 
+    source->stop();
+
     delete source;
     source = NULL;
 #endif
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 075b1e3..f57ddc1 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -142,13 +142,6 @@
       mFirstFrameTimeUs(0),
       mNumFrames(0),
       mStarted(false) {
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("ro.hardware", value, NULL) && !strcmp(value, "sholes")) {
-        // The hardware encoder(s) do not support yuv420, but only YCbYCr,
-        // fortunately the camera also supports this, so we needn't transcode.
-        mCamera->setParameters(String8("preview-format=yuv422i-yuyv"));
-    }
-
     String8 s = mCamera->getParameters();
     printf("params: \"%s\"\n", s.string());
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 2cf0ddf..e0e2b93 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -24,6 +24,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/Utils.h>
 
@@ -65,10 +66,15 @@
     static void *ThreadWrapper(void *me);
     void threadEntry();
 
+    status_t makeAVCCodecSpecificData(
+            const uint8_t *data, size_t size);
+
     Track(const Track &);
     Track &operator=(const Track &);
 };
 
+#define USE_NALLEN_FOUR         1
+
 MPEG4Writer::MPEG4Writer(const char *filename)
     : mFile(fopen(filename, "wb")),
       mOffset(0),
@@ -213,23 +219,55 @@
     return old_offset;
 }
 
+static void StripStartcode(MediaBuffer *buffer) {
+    if (buffer->range_length() < 4) {
+        return;
+    }
+
+    const uint8_t *ptr =
+        (const uint8_t *)buffer->data() + buffer->range_offset();
+
+    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
+        buffer->set_range(
+                buffer->range_offset() + 4, buffer->range_length() - 4);
+    }
+}
+
 off_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) {
     Mutex::Autolock autoLock(mLock);
 
+    StripStartcode(buffer);
+
     off_t old_offset = mOffset;
 
     size_t length = buffer->range_length();
+
+#if USE_NALLEN_FOUR
+    uint8_t x = length >> 24;
+    fwrite(&x, 1, 1, mFile);
+    x = (length >> 16) & 0xff;
+    fwrite(&x, 1, 1, mFile);
+    x = (length >> 8) & 0xff;
+    fwrite(&x, 1, 1, mFile);
+    x = length & 0xff;
+    fwrite(&x, 1, 1, mFile);
+#else
     CHECK(length < 65536);
 
     uint8_t x = length >> 8;
     fwrite(&x, 1, 1, mFile);
     x = length & 0xff;
     fwrite(&x, 1, 1, mFile);
+#endif
 
     fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
            1, length, mFile);
 
+#if USE_NALLEN_FOUR
+    mOffset += length + 4;
+#else
     mOffset += length + 2;
+#endif
 
     return old_offset;
 }
@@ -380,6 +418,60 @@
     return NULL;
 }
 
+status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
+        const uint8_t *data, size_t size) {
+    if (mCodecSpecificData != NULL) {
+        return ERROR_MALFORMED;
+    }
+
+    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
+        // Must start with a start-code.
+        return ERROR_MALFORMED;
+    }
+
+    size_t picParamOffset = 4;
+    while (picParamOffset + 3 < size
+            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
+        ++picParamOffset;
+    }
+
+    if (picParamOffset + 3 >= size) {
+        // Could not find start-code for pictureParameterSet.
+        return ERROR_MALFORMED;
+    }
+
+    size_t seqParamSetLength = picParamOffset - 4;
+    size_t picParamSetLength = size - picParamOffset - 4;
+
+    mCodecSpecificDataSize =
+        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
+
+    mCodecSpecificData = malloc(mCodecSpecificDataSize);
+    uint8_t *header = (uint8_t *)mCodecSpecificData;
+    header[0] = 1;
+    header[1] = 0x42;  // profile
+    header[2] = 0x80;
+    header[3] = 0x1e;  // level
+
+#if USE_NALLEN_FOUR
+    header[4] = 0xfc | 3;  // length size == 4 bytes
+#else
+    header[4] = 0xfc | 1;  // length size == 2 bytes
+#endif
+
+    header[5] = 0xe0 | 1;
+    header[6] = seqParamSetLength >> 8;
+    header[7] = seqParamSetLength & 0xff;
+    memcpy(&header[8], &data[4], seqParamSetLength);
+    header += 8 + seqParamSetLength;
+    header[0] = 1;
+    header[1] = picParamSetLength >> 8;
+    header[2] = picParamSetLength & 0xff;
+    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
+
+    return OK;
+}
+
 void MPEG4Writer::Track::threadEntry() {
     sp<MetaData> meta = mSource->getFormat();
     const char *mime;
@@ -399,54 +491,40 @@
 
         ++count;
 
-        if (is_avc && count < 3) {
-            size_t size = buffer->range_length();
+        int32_t isCodecConfig;
+        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
+                && isCodecConfig) {
+            if (is_avc) {
+                status_t err = makeAVCCodecSpecificData(
+                        (const uint8_t *)buffer->data()
+                            + buffer->range_offset(),
+                        buffer->range_length());
 
-            switch (count) {
-                case 1:
-                {
-                    CHECK_EQ(mCodecSpecificData, NULL);
-                    mCodecSpecificData = malloc(size + 8);
-                    uint8_t *header = (uint8_t *)mCodecSpecificData;
-                    header[0] = 1;
-                    header[1] = 0x42;  // profile
-                    header[2] = 0x80;
-                    header[3] = 0x1e;  // level
-                    header[4] = 0xfc | 3;
-                    header[5] = 0xe0 | 1;
-                    header[6] = size >> 8;
-                    header[7] = size & 0xff;
-                    memcpy(&header[8],
-                            (const uint8_t *)buffer->data() + buffer->range_offset(),
-                            size);
-
-                    mCodecSpecificDataSize = size + 8;
+                if (err != OK) {
+                    LOGE("failed to parse avc codec specific data.");
+                    break;
+                }
+            } else if (is_mpeg4) {
+                if (mCodecSpecificData != NULL) {
                     break;
                 }
 
-                case 2:
-                {
-                    size_t offset = mCodecSpecificDataSize;
-                    mCodecSpecificDataSize += size + 3;
-                    mCodecSpecificData = realloc(mCodecSpecificData, mCodecSpecificDataSize);
-                    uint8_t *header = (uint8_t *)mCodecSpecificData;
-                    header[offset] = 1;
-                    header[offset + 1] = size >> 8;
-                    header[offset + 2] = size & 0xff;
-                    memcpy(&header[offset + 3],
-                            (const uint8_t *)buffer->data() + buffer->range_offset(),
-                            size);
-                    break;
-                }
+                mCodecSpecificDataSize = buffer->range_length();
+                mCodecSpecificData = malloc(mCodecSpecificDataSize);
+                memcpy(mCodecSpecificData,
+                        (const uint8_t *)buffer->data()
+                            + buffer->range_offset(),
+                       buffer->range_length());
             }
 
             buffer->release();
             buffer = NULL;
 
             continue;
-        }
+        } else if (count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
+            // The TI mpeg4 encoder does not properly set the
+            // codec-specific-data flag.
 
-        if (mCodecSpecificData == NULL && is_mpeg4) {
             const uint8_t *data =
                 (const uint8_t *)buffer->data() + buffer->range_offset();
 
@@ -474,13 +552,70 @@
             memcpy(mCodecSpecificData, data, offset);
 
             buffer->set_range(buffer->range_offset() + offset, size - offset);
+
+            if (size == offset) {
+                buffer->release();
+                buffer = NULL;
+
+                continue;
+            }
+        } else if (is_avc && count < 3) {
+            // The TI video encoder does not flag codec specific data
+            // as such and also splits up SPS and PPS across two buffers.
+
+            const uint8_t *data =
+                (const uint8_t *)buffer->data() + buffer->range_offset();
+
+            size_t size = buffer->range_length();
+
+            CHECK(count == 2 || mCodecSpecificData == NULL);
+
+            size_t offset = mCodecSpecificDataSize;
+            mCodecSpecificDataSize += size + 4;
+            mCodecSpecificData =
+                realloc(mCodecSpecificData, mCodecSpecificDataSize);
+
+            memcpy((uint8_t *)mCodecSpecificData + offset,
+                   "\x00\x00\x00\x01", 4);
+
+            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
+
+            buffer->release();
+            buffer = NULL;
+
+            if (count == 2) {
+                void *tmp = mCodecSpecificData;
+                size = mCodecSpecificDataSize;
+                mCodecSpecificData = NULL;
+                mCodecSpecificDataSize = 0;
+
+                status_t err = makeAVCCodecSpecificData(
+                        (const uint8_t *)tmp, size);
+
+                free(tmp);
+                tmp = NULL;
+
+                if (err != OK) {
+                    LOGE("failed to parse avc codec specific data.");
+                    break;
+                }
+            }
+
+            continue;
         }
 
         off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer)
                               : mOwner->addSample(buffer);
 
         SampleInfo info;
-        info.size = is_avc ? buffer->range_length() + 2 : buffer->range_length();
+        info.size = is_avc
+#if USE_NALLEN_FOUR
+            ? buffer->range_length() + 4
+#else
+            ? buffer->range_length() + 2
+#endif
+            : buffer->range_length();
+
         info.offset = offset;
 
         int64_t timestampUs;
@@ -733,19 +868,29 @@
 
           mOwner->beginBox("stts");
             mOwner->writeInt32(0);  // version=0, flags=0
-            mOwner->writeInt32(mSampleInfos.size() - 1);
+            mOwner->writeInt32(mSampleInfos.size());
 
             List<SampleInfo>::iterator it = mSampleInfos.begin();
             int64_t last = (*it).timestamp;
+            int64_t lastDuration = 1;
+
             ++it;
             while (it != mSampleInfos.end()) {
                 mOwner->writeInt32(1);
-                mOwner->writeInt32((*it).timestamp - last);
+                lastDuration = (*it).timestamp - last;
+                mOwner->writeInt32(lastDuration);
 
                 last = (*it).timestamp;
 
                 ++it;
             }
+
+            // We don't really know how long the last frame lasts, since
+            // there is no frame time after it, just repeat the previous
+            // frame's duration.
+            mOwner->writeInt32(1);
+            mOwner->writeInt32(lastDuration);
+
           mOwner->endBox();  // stts
 
           mOwner->beginBox("stsz");
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 6037088..41ce239 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -137,6 +137,7 @@
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
@@ -679,6 +680,7 @@
         case OMX_COLOR_FormatCbYCrY:
             return width * height * 2;
 
+        case OMX_COLOR_FormatYUV420Planar:
         case OMX_COLOR_FormatYUV420SemiPlanar:
             return (width * height * 3) / 2;
 
@@ -706,7 +708,7 @@
 
     OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
     if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
-        colorFormat = OMX_COLOR_FormatYCbYCr;
+        colorFormat = OMX_COLOR_FormatYUV420Planar;
     }
 
     CHECK_EQ(setVideoPortFormatType(
@@ -764,6 +766,14 @@
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
+    err = mOMX->getParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
     switch (compressionFormat) {
         case OMX_VIDEO_CodingMPEG4:
         {
@@ -911,7 +921,7 @@
     CHECK_EQ(err, OK);
 
     bitrateType.eControlRate = OMX_Video_ControlRateVariable;
-    bitrateType.nTargetBitrate = 1000000;
+    bitrateType.nTargetBitrate = 3000000;
 
     err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoBitrate,
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index c1a010c..5db516e 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -264,6 +264,8 @@
         return UNKNOWN_ERROR;
     }
 
+    CHECK_EQ(header->pAppPrivate, buffer_meta);
+
     *buffer = header;
 
     addActiveBuffer(portIndex, *buffer);
@@ -294,6 +296,8 @@
         return UNKNOWN_ERROR;
     }
 
+    CHECK_EQ(header->pAppPrivate, buffer_meta);
+
     *buffer = header;
     *buffer_data = header->pBuffer;
 
@@ -325,6 +329,8 @@
         return UNKNOWN_ERROR;
     }
 
+    CHECK_EQ(header->pAppPrivate, buffer_meta);
+
     *buffer = header;
 
     addActiveBuffer(portIndex, *buffer);