Merge "Fix mpeg4/h.263 software decoder."
diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
index c3ef0d2..ec3ad47 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
@@ -43,8 +43,17 @@
     memset(mHandle, 0, sizeof(tagvideoDecControls));
     mFormat = new MetaData;
     mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
-    CHECK(mSource->getFormat()->findInt32(kKeyWidth, &mWidth));
-    CHECK(mSource->getFormat()->findInt32(kKeyHeight, &mHeight));
+
+    // CHECK(mSource->getFormat()->findInt32(kKeyWidth, &mWidth));
+    // CHECK(mSource->getFormat()->findInt32(kKeyHeight, &mHeight));
+
+    // We'll ignore the dimension advertised by the source, the decoder
+    // appears to require us to always start with the default dimensions
+    // of 352 x 288 to operate correctly and later react to changes in
+    // the dimensions as needed.
+    mWidth = 352;
+    mHeight = 288;
+
     mFormat->setInt32(kKeyWidth, mWidth);
     mFormat->setInt32(kKeyHeight, mHeight);
     mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
@@ -60,6 +69,20 @@
     mHandle = NULL;
 }
 
+void M4vH263Decoder::allocateFrames(int32_t width, int32_t height) {
+    size_t frameSize =
+        (((width + 15) & - 16) * ((height + 15) & - 16) * 3) / 2;
+
+    for (uint32_t i = 0; i < 2; ++i) {
+        mFrames[i] = new MediaBuffer(frameSize);
+        mFrames[i]->setObserver(this);
+    }
+
+    PVSetReferenceYUV(
+            mHandle,
+            (uint8_t *)mFrames[1]->data());
+}
+
 status_t M4vH263Decoder::start(MetaData *) {
     CHECK(!mStarted);
 
@@ -85,7 +108,8 @@
 
         const void *codec_specific_data;
         size_t codec_specific_data_size;
-        esds.getCodecSpecificInfo(&codec_specific_data, &codec_specific_data_size);
+        esds.getCodecSpecificInfo(
+                &codec_specific_data, &codec_specific_data_size);
 
         vol_data[0] = (uint8_t *) malloc(codec_specific_data_size);
         memcpy(vol_data[0], codec_specific_data, codec_specific_data_size);
@@ -102,12 +126,14 @@
     CHECK_EQ(mode, actualMode);
 
     PVSetPostProcType((VideoDecControls *) mHandle, 0);
-    size_t frameSize = (((mWidth + 15) & - 16) * ((mHeight + 15) & - 16) * 3) / 2;
-    for (uint32_t i = 0; i < 2; ++i) {
-        mFrames[i] = new MediaBuffer(frameSize);
-        mFrames[i]->setObserver(this);
+
+    int32_t width, height;
+    PVGetVideoDimensions(mHandle, &width, &height);
+    if (mode == H263_MODE && (width == 0 || height == 0)) {
+        width = 352;
+        height = 288;
     }
-    PVSetReferenceYUV(mHandle, (uint8_t *)mFrames[1]->data());
+    allocateFrames(width, height);
 
     mSource->start();
 
@@ -152,24 +178,41 @@
         return err;
     }
 
-    uint8_t *bitstream = (uint8_t *) inputBuffer->data() + inputBuffer->range_offset();
+    uint8_t *bitstream =
+        (uint8_t *) inputBuffer->data() + inputBuffer->range_offset();
+
     uint32_t timestamp = 0xFFFFFFFF;
     int32_t bufferSize = inputBuffer->range_length();
     uint32_t useExtTimestamp = 0;
-    CHECK_EQ(PV_TRUE, PVDecodeVideoFrame(mHandle, &bitstream, &timestamp, &bufferSize,
-            &useExtTimestamp,  (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data()));
+    if (PVDecodeVideoFrame(
+                mHandle, &bitstream, &timestamp, &bufferSize,
+                &useExtTimestamp,
+                (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data())
+            != PV_TRUE) {
+        LOGE("failed to decode video frame.");
 
-    // Check whether video dimension is changed.
-    // If so, notify the client about the change.
+        inputBuffer->release();
+        inputBuffer = NULL;
+
+        return UNKNOWN_ERROR;
+    }
+
     int32_t width, height;
     PVGetVideoDimensions(mHandle, &width, &height);
-    if (mWidth != width || mHeight != height) {
-        mFormat->setInt32(kKeyWidth, width);
-        mFormat->setInt32(kKeyHeight, height);
+    if (width != mWidth || height != mHeight) {
+        ++mNumSamplesOutput;  // The client will never get to see this frame.
+
+        inputBuffer->release();
+        inputBuffer = NULL;
+
+        mWidth = width;
+        mHeight = height;
+        mFormat->setInt32(kKeyWidth, mWidth);
+        mFormat->setInt32(kKeyHeight, mHeight);
+
         return INFO_FORMAT_CHANGED;
     }
 
-    PVSetReferenceYUV(mHandle, (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data());
     *out = mFrames[mNumSamplesOutput & 0x01];
     (*out)->add_ref();
 
@@ -179,6 +222,7 @@
 
     ++mNumSamplesOutput;
     inputBuffer->release();
+    inputBuffer = NULL;
 
     return OK;
 }
diff --git a/media/libstagefright/include/M4vH263Decoder.h b/media/libstagefright/include/M4vH263Decoder.h
index 880ec7c..ec49e80 100644
--- a/media/libstagefright/include/M4vH263Decoder.h
+++ b/media/libstagefright/include/M4vH263Decoder.h
@@ -55,6 +55,7 @@
 
     int64_t mNumSamplesOutput;
 
+    void allocateFrames(int32_t width, int32_t height);
     void releaseFrames();
 
     M4vH263Decoder(const M4vH263Decoder &);