stagefright: add adaptive playback support to SoftMPEG decoder.

This covers both MPEG4 and H263 adaptive playback.

Bug: 17326758
Change-Id: I80a67b7f3ceab05e792f0a459439a8274bd78e20
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index 0d1ab71..5b2ab84 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -134,6 +134,12 @@
         }
 
         uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
+        uint32_t *start_code = (uint32_t *)bitstream;
+        bool volHeader = *start_code == 0xB0010000;
+        if (volHeader) {
+            PVCleanUpVideoDecoder(mHandle);
+            mInitialized = false;
+        }
 
         if (!mInitialized) {
             uint8_t *vol_data[1];
@@ -141,7 +147,7 @@
 
             vol_data[0] = NULL;
 
-            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+            if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
                 vol_data[0] = bitstream;
                 vol_size = inHeader->nFilledLen;
             }
@@ -169,21 +175,26 @@
 
             PVSetPostProcType((VideoDecControls *) mHandle, 0);
 
+            bool hasFrameData = false;
             if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
                 inInfo->mOwnedByUs = false;
                 inQueue.erase(inQueue.begin());
                 inInfo = NULL;
                 notifyEmptyBufferDone(inHeader);
                 inHeader = NULL;
+            } else if (volHeader) {
+                hasFrameData = true;
             }
 
             mInitialized = true;
 
-            if (mode == MPEG4_MODE && portSettingsChanged()) {
+            if (mode == MPEG4_MODE && handlePortSettingsChange()) {
                 return;
             }
 
-            continue;
+            if (!hasFrameData) {
+                continue;
+            }
         }
 
         if (!mFramesConfigured) {
@@ -223,7 +234,9 @@
             return;
         }
 
-        if (portSettingsChanged()) {
+        // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
+        // decoder may detect size change after PVDecodeVideoFrame.
+        if (handlePortSettingsChange()) {
             return;
         }
 
@@ -269,7 +282,7 @@
     }
 }
 
-bool SoftMPEG4::portSettingsChanged() {
+bool SoftMPEG4::handlePortSettingsChange() {
     uint32_t disp_width, disp_height;
     PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height);
 
@@ -282,25 +295,20 @@
     ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
             disp_width, disp_height, buf_width, buf_height);
 
-    if (mCropWidth != disp_width
-            || mCropHeight != disp_height) {
+    bool cropChanged = false;
+    if (mCropWidth != disp_width || mCropHeight != disp_height) {
         mCropLeft = 0;
         mCropTop = 0;
         mCropWidth = disp_width;
         mCropHeight = disp_height;
-
-        notify(OMX_EventPortSettingsChanged,
-               1,
-               OMX_IndexConfigCommonOutputCrop,
-               NULL);
+        cropChanged = true;
     }
 
-    if (buf_width != mWidth || buf_height != mHeight) {
-        mWidth = buf_width;
-        mHeight = buf_height;
-
-        updatePortDefinitions();
-
+    bool portWillReset = false;
+    const bool fakeStride = true;
+    SoftVideoDecoderOMXComponent::handlePortSettingsChange(
+            &portWillReset, buf_width, buf_height, cropChanged, fakeStride);
+    if (portWillReset) {
         if (mMode == MODE_H263) {
             PVCleanUpVideoDecoder(mHandle);
 
@@ -318,13 +326,9 @@
         }
 
         mFramesConfigured = false;
-
-        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-        mOutputPortSettingsChange = AWAITING_DISABLED;
-        return true;
     }
 
-    return false;
+    return portWillReset;
 }
 
 void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
index de14aaf..8a06a00 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
@@ -67,7 +67,7 @@
     status_t initDecoder();
 
     virtual void updatePortDefinitions();
-    bool portSettingsChanged();
+    bool handlePortSettingsChange();
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4);
 };
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
index b3c350f..b03ec8c 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
@@ -1426,7 +1426,7 @@
         video->nBitsForMBID = CalcNumBits((uint)video->nTotalMB - 1); /* otherwise calculate above */
     }
     size = (int32)video->width * video->height;
-    if (video->currVop->predictionType == P_VOP && size > video->videoDecControls->size)
+    if (currVop->predictionType == P_VOP && size > video->videoDecControls->size)
     {
         status = PV_FAIL;
         goto return_point;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index cc98da0..1899b40 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -65,8 +65,8 @@
     CHECK(format->findInt32("color-format", &colorFormatNew));
 
     int32_t widthNew, heightNew;
-    CHECK(format->findInt32("width", &widthNew));
-    CHECK(format->findInt32("height", &heightNew));
+    CHECK(format->findInt32("stride", &widthNew));
+    CHECK(format->findInt32("slice-height", &heightNew));
 
     int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew;
     if (!format->findRect(
diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
index 4a6ab63..8cb8ed7 100644
--- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
+++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
@@ -66,7 +66,8 @@
     virtual void updatePortDefinitions(bool updateCrop = true);
 
     void handlePortSettingsChange(
-            bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged = false);
+            bool *portWillReset, uint32_t width, uint32_t height,
+            bool cropChanged = false, bool fakeStride = false);
 
     void copyYV12FrameToOutputBuffer(
             uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index e533fdd..741ac96 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -151,7 +151,7 @@
 }
 
 void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
-        bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged) {
+        bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged, bool fakeStride) {
     *portWillReset = false;
     bool sizeChanged = (width != mWidth || height != mHeight);
 
@@ -177,6 +177,19 @@
             *portWillReset = true;
         } else {
             updatePortDefinitions(updateCrop);
+
+            if (fakeStride) {
+                // MAJOR HACK that is not pretty, it's just to fool the renderer to read the correct
+                // data.
+                // Some software decoders (e.g. SoftMPEG4) fill decoded frame directly to output
+                // buffer without considering the output buffer stride and slice height. So this is
+                // used to signal how the buffer is arranged.  The alternative is to re-arrange the
+                // output buffer in SoftMPEG4, but that results in memcopies.
+                OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
+                def->format.video.nStride = mWidth;
+                def->format.video.nSliceHeight = mHeight;
+            }
+
             notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
                    OMX_IndexConfigCommonOutputCrop, NULL);
         }