Squashed commit of the following:

commit c80992e419ed567abef451042f09c4958534b90d
Author: Andreas Huber <andih@google.com>
Date:   Wed May 11 14:00:07 2011 -0700

    Support for the mp3 audio decoder as a software OMX component.

    Change-Id: I66e10c4d0be4c3aecdef1c21b15a2c7359ceb807

commit a358d0e1bf2a88897887445f42ccdda0f5f2f528
Author: Andreas Huber <andih@google.com>
Date:   Wed May 11 13:11:23 2011 -0700

    Support for G.711 alaw and mulaw decoders as software OMX components

    Change-Id: Ia5c76c02cb83a9f94ce39a27b2251e5880218f03

commit 79088b9c9a5c8b8c97ea66cb4f90a2b0f0d34553
Author: Andreas Huber <andih@google.com>
Date:   Thu May 5 15:43:32 2011 -0700

    Instead of using an RGB surface and conversion yuv420->rgb565

    convert from OMX_COLOR_FormatYUV420Planar to HAL_PIXEL_FORMAT_YV12 instead.

    Change-Id: I8c4fc3c54c963f0d4ba6377f3c4ab4e0013152e5
    related-to-bug: 4394005

commit 69469d3bd84425777b11b9fc938c5e0c61af26a7
Author: Andreas Huber <andih@google.com>
Date:   Tue May 10 15:46:42 2011 -0700

    voip mustn't link against libstagefright.so

    Change-Id: I4d0ba9a8b9dc9380b792a1bd04bcda231964862c

commit 2a9a9eeeeeb36ae3a9e680469c3016d509ff08c3
Author: Andreas Huber <andih@google.com>
Date:   Tue May 10 14:37:10 2011 -0700

    Remove most non-OMX software decoders by default

    Change-Id: Ic56514bc1b56b8fa952e8c4a164ea7379ecb69d0

commit a4de62c37b335c318217765403a9fb282b20a216
Author: Andreas Huber <andih@google.com>
Date:   Mon May 9 16:50:02 2011 -0700

    Conditionally build the old-style software decoders.

    Change-Id: I5de609e1d76c92d26d6eb81d1551462258f3f15f

commit 5d8b039f9449dc3dad1e77c42c80cc0b54b0c846
Author: Andreas Huber <andih@google.com>
Date:   Mon May 9 16:13:12 2011 -0700

    Support for MPEG4 and H.263 video decoders as soft OMX components.

    Change-Id: I5e3a4835afab89f98e3aa128d013628f5830eafe

commit b25a1bfbeb0ff6e62e1cc694ce2599c91489c7d0
Author: Andreas Huber <andih@google.com>
Date:   Mon May 9 11:49:10 2011 -0700

    Boost Soft OMX thread priority, fix timestamp handling in vorbis Soft OMX decoder.

    Change-Id: I68d26d4999f06fcc451d69e5303663fab0cba9e8

commit c0574362f8dc3319ce84d981097867062a698527
Author: Andreas Huber <andih@google.com>
Date:   Mon May 9 11:28:53 2011 -0700

    Support for the AMR decoders (NB and WB) as Soft OMX components.

    Change-Id: Ia565f59833fb52653e23f26536e7e41fc329a754

commit 3e5575a8f0e27a490cb7bde77bd9456087837f08
Author: Andreas Huber <andih@google.com>
Date:   Wed May 4 13:41:25 2011 -0700

    Signal an error if the aac decoder failed to initialize from codec specific data.

    Change-Id: I01da7831bdf722edd7d6dc5974486daa2cf2b209
    related-to-bug: 4272179

commit f94aeaa9886e772ff4823e671ed237096649f4af
Author: Andreas Huber <andih@google.com>
Date:   Tue May 3 13:07:38 2011 -0700

    Software OMX nodes don't (yet?) support native_window mode.

    Change-Id: I7d9ca9164ef4abf66b573ca21dba12d672f8b12d

commit eefdfabac8dc659e00daa56da69aea705c49cb67
Author: Andreas Huber <andih@google.com>
Date:   Tue May 3 12:57:16 2011 -0700

    Fixing the OMX tests to refer to appropriate files from test content.

    Change-Id: I5b61c3498749bfb876abbd3946a5132356e3f6ff

commit f31b7326aef14b6a1b7946520a9688f092e844d5
Author: Andreas Huber <andih@google.com>
Date:   Tue May 3 11:08:38 2011 -0700

    Soft OMX components are now dynamiclly loaded/unloaded, not directly linked against.

    Change-Id: I1e2ecfbfab67a8869886f738eaf0c7b3c948b6d9

commit b7f0343879e4df06f0a1c9bfece24df557954e2f
Author: Andreas Huber <andih@google.com>
Date:   Mon May 2 15:58:36 2011 -0700

    Support for the AVC software decoder as an OMX component.

    Change-Id: I13c12df435ba4afbd968a9fc659f66b91c818bc2

commit 5bb9e616d6c8e1b13d531fe996b9a9affdfb2977
Author: Andreas Huber <andih@google.com>
Date:   Fri Apr 29 12:05:37 2011 -0700

    Fix Vorbis OMX decoder's component role.

    Change-Id: I5e871e5e11b3f951c93590210e63fd7987c467b5

commit 089c91f2333062e196c7afd5fb0ca914878aa474
Author: Andreas Huber <andih@google.com>
Date:   Fri Apr 29 12:05:18 2011 -0700

    Support vorbis_decoder OMX testing.

    Change-Id: I1985be178a12ae3f8768bc72067d9236238be170

commit 56e241fa36fc37219bc536b823bdc2ab82dc1fad
Author: Andreas Huber <andih@google.com>
Date:   Fri Apr 29 12:01:46 2011 -0700

    SoftVorbis OMX component now respects the number of valid frames per page.

    Change-Id: I82a117a064d9b083fc58a54ad900a987a763ef03

commit fcd618ec520c376fdb78f4cbb44b8d9f5d213e2b
Author: Andreas Huber <andih@google.com>
Date:   Fri Apr 29 10:59:38 2011 -0700

    Support for the vorbis audio decoder as a soft OMX component.

    Change-Id: Iaeb057e58ca306d3dce205c0445b74d5aefef492

commit d1fcc3203fc8003ad79c6e96b3a1fc4261743f16
Author: Andreas Huber <andih@google.com>
Date:   Fri Apr 29 10:07:50 2011 -0700

    VPX decoder now properly resizes buffers after a port settings change.

    Change-Id: I110749a31b6cba087891d8e5dfe420830bdbf831

commit 35c7168243cb69849d88911144a2c7fdfed5c54e
Author: Andreas Huber <andih@google.com>
Date:   Thu Apr 28 13:23:34 2011 -0700

    Support for the VPX video decoder as a Software OMX component.

    Change-Id: Ic345add2d6d768d4af631160153f2e9b97fcea71

commit 923b2534b4211fc5405377b5190bfa6f2dd27f32
Author: Andreas Huber <andih@google.com>
Date:   Thu Apr 28 11:34:40 2011 -0700

    Table-based registration of soft omx components.

    Change-Id: I7f45f0fa5b3a7950776e69c66349731f7674e937

commit 04a88f3edb2266a463da9c4481b80178be460902
Author: Andreas Huber <andih@google.com>
Date:   Thu Apr 28 11:22:31 2011 -0700

    Apparently OMX_GetParameter is valid in any state other than OMX_StateInvalid

    OMX_SetParameter is still constrained to OMX_StateLoaded or a disabled port.

    Change-Id: I1032d7cf4011982d306aa369d4158a82830d26fb

commit 9d70ca68445e7c40f5c9b2d12466e468f514de88
Author: Andreas Huber <andih@google.com>
Date:   Wed Apr 27 15:03:18 2011 -0700

    Use the new soft OMX aac decoder for HTTP live playback.

    Change-Id: Ifbcfb732a9edb855cb46b49f6d0ac942170ee28f

commit 213fe4a10ea93cce08e8622dc3908053f29878a1
Author: Andreas Huber <andih@google.com>
Date:   Tue Apr 12 16:39:45 2011 -0700

    Foundation for supporting software decoders as OMX components

    Change-Id: I7fdab256563b35d1d090617abaea9a26b198d816

Change-Id: I83e9236beed4af985d10333c203f065df9e09a42
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index 2d9bcc6..65b642c 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -48,3 +48,29 @@
 LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
 
 include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        SoftMPEG4.cpp
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/src \
+	$(LOCAL_PATH)/include \
+        frameworks/base/media/libstagefright/include \
+        frameworks/base/include/media/stagefright/openmax \
+
+LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+        libstagefright_m4vh263dec
+
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright libstagefright_omx libstagefright_foundation libutils
+
+LOCAL_MODULE := libstagefright_soft_mpeg4dec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
new file mode 100644
index 0000000..13e1662
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftMPEG4"
+#include <utils/Log.h>
+
+#include "SoftMPEG4.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include "mp4dec_api.h"
+
+namespace android {
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftMPEG4::SoftMPEG4(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mMode(MODE_MPEG4),
+      mHandle(new tagvideoDecControls),
+      mInputBufferCount(0),
+      mWidth(352),
+      mHeight(288),
+      mCropLeft(0),
+      mCropTop(0),
+      mCropRight(mWidth - 1),
+      mCropBottom(mHeight - 1),
+      mSignalledError(false),
+      mInitialized(false),
+      mFramesConfigured(false),
+      mNumSamplesOutput(0),
+      mOutputPortSettingsChange(NONE) {
+    if (!strcmp(name, "OMX.google.h263.decoder")) {
+        mMode = MODE_H263;
+    } else {
+        CHECK(!strcmp(name, "OMX.google.mpeg4.decoder"));
+    }
+
+    initPorts();
+    CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftMPEG4::~SoftMPEG4() {
+    if (mInitialized) {
+        PVCleanUpVideoDecoder(mHandle);
+    }
+
+    delete mHandle;
+    mHandle = NULL;
+}
+
+void SoftMPEG4::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumInputBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainVideo;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.video.cMIMEType =
+        (mMode == MODE_MPEG4)
+            ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4)
+            : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
+
+    def.format.video.pNativeRender = NULL;
+    def.format.video.nFrameWidth = mWidth;
+    def.format.video.nFrameHeight = mHeight;
+    def.format.video.nStride = def.format.video.nFrameWidth;
+    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+    def.format.video.nBitrate = 0;
+    def.format.video.xFramerate = 0;
+    def.format.video.bFlagErrorConcealment = OMX_FALSE;
+
+    def.format.video.eCompressionFormat =
+        mMode == MODE_MPEG4 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
+
+    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
+    def.format.video.pNativeWindow = NULL;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumOutputBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainVideo;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
+    def.format.video.pNativeRender = NULL;
+    def.format.video.nFrameWidth = mWidth;
+    def.format.video.nFrameHeight = mHeight;
+    def.format.video.nStride = def.format.video.nFrameWidth;
+    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+    def.format.video.nBitrate = 0;
+    def.format.video.xFramerate = 0;
+    def.format.video.bFlagErrorConcealment = OMX_FALSE;
+    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
+    def.format.video.pNativeWindow = NULL;
+
+    def.nBufferSize =
+        (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
+
+    addPort(def);
+}
+
+status_t SoftMPEG4::initDecoder() {
+    memset(mHandle, 0, sizeof(tagvideoDecControls));
+    return OK;
+}
+
+OMX_ERRORTYPE SoftMPEG4::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamVideoPortFormat:
+        {
+            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex != 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if (formatParams->nPortIndex == 0) {
+                formatParams->eCompressionFormat =
+                    (mMode == MODE_MPEG4)
+                        ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
+
+                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
+                formatParams->xFramerate = 0;
+            } else {
+                CHECK_EQ(formatParams->nPortIndex, 1u);
+
+                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
+                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
+                formatParams->xFramerate = 0;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftMPEG4::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (mMode == MODE_MPEG4) {
+                if (strncmp((const char *)roleParams->cRole,
+                            "video_decoder.mpeg4",
+                            OMX_MAX_STRINGNAME_SIZE - 1)) {
+                    return OMX_ErrorUndefined;
+                }
+            } else {
+                if (strncmp((const char *)roleParams->cRole,
+                            "video_decoder.h263",
+                            OMX_MAX_STRINGNAME_SIZE - 1)) {
+                    return OMX_ErrorUndefined;
+                }
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamVideoPortFormat:
+        {
+            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex != 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftMPEG4::getConfig(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexConfigCommonOutputCrop:
+        {
+            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
+
+            if (rectParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            rectParams->nLeft = mCropLeft;
+            rectParams->nTop = mCropTop;
+            rectParams->nWidth = mCropRight - mCropLeft + 1;
+            rectParams->nHeight = mCropBottom - mCropTop + 1;
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return OMX_ErrorUnsupportedIndex;
+    }
+}
+
+void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
+    if (mSignalledError || mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+        PortInfo *port = editPortInfo(1);
+
+        OMX_BUFFERHEADERTYPE *outHeader =
+            port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
+
+        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inHeader);
+
+            ++mInputBufferCount;
+
+            outHeader->nFilledLen = 0;
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+            List<BufferInfo *>::iterator it = outQueue.begin();
+            while ((*it)->mHeader != outHeader) {
+                ++it;
+            }
+
+            BufferInfo *outInfo = *it;
+            outInfo->mOwnedByUs = false;
+            outQueue.erase(it);
+            outInfo = NULL;
+
+            notifyFillBufferDone(outHeader);
+            outHeader = NULL;
+            return;
+        }
+
+        uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
+
+        if (!mInitialized) {
+            uint8_t *vol_data[1];
+            int32_t vol_size = 0;
+
+            vol_data[0] = NULL;
+
+            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+                vol_data[0] = bitstream;
+                vol_size = inHeader->nFilledLen;
+            }
+
+            MP4DecodingMode mode =
+                (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
+
+            Bool success = PVInitVideoDecoder(
+                    mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
+
+            if (!success) {
+                LOGW("PVInitVideoDecoder failed. Unsupported content?");
+
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                return;
+            }
+
+            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
+            if (mode != actualMode) {
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                return;
+            }
+
+            PVSetPostProcType((VideoDecControls *) mHandle, 0);
+
+            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+                inInfo->mOwnedByUs = false;
+                inQueue.erase(inQueue.begin());
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+            }
+
+            mInitialized = true;
+
+            if (mode == MPEG4_MODE && portSettingsChanged()) {
+                return;
+            }
+
+            continue;
+        }
+
+        if (!mFramesConfigured) {
+            PortInfo *port = editPortInfo(1);
+            OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
+
+            PVSetReferenceYUV(mHandle, outHeader->pBuffer);
+
+            mFramesConfigured = true;
+        }
+
+        uint32_t timestamp = 0xFFFFFFFF;
+        int32_t bufferSize = inHeader->nFilledLen;
+
+        uint32_t useExtTimestamp = 0;
+        if (PVDecodeVideoFrame(
+                    mHandle, &bitstream, &timestamp, &bufferSize,
+                    &useExtTimestamp,
+                    outHeader->pBuffer) != PV_TRUE) {
+            LOGE("failed to decode video frame.");
+
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+
+        if (portSettingsChanged()) {
+            return;
+        }
+
+        outHeader->nTimeStamp = inHeader->nTimeStamp;
+
+        inInfo->mOwnedByUs = false;
+        inQueue.erase(inQueue.begin());
+        inInfo = NULL;
+        notifyEmptyBufferDone(inHeader);
+        inHeader = NULL;
+
+        ++mInputBufferCount;
+
+        outHeader->nOffset = 0;
+        outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+        outHeader->nFlags = 0;
+
+        List<BufferInfo *>::iterator it = outQueue.begin();
+        while ((*it)->mHeader != outHeader) {
+            ++it;
+        }
+
+        BufferInfo *outInfo = *it;
+        outInfo->mOwnedByUs = false;
+        outQueue.erase(it);
+        outInfo = NULL;
+
+        notifyFillBufferDone(outHeader);
+        outHeader = NULL;
+
+        ++mNumSamplesOutput;
+    }
+}
+
+bool SoftMPEG4::portSettingsChanged() {
+    int32_t disp_width, disp_height;
+    PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
+
+    int32_t buf_width, buf_height;
+    PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
+
+    CHECK_LE(disp_width, buf_width);
+    CHECK_LE(disp_height, buf_height);
+
+    LOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
+            disp_width, disp_height, buf_width, buf_height);
+
+    if (mCropRight != disp_width - 1
+            || mCropBottom != disp_height - 1) {
+        mCropLeft = 0;
+        mCropTop = 0;
+        mCropRight = disp_width - 1;
+        mCropBottom = disp_height - 1;
+
+        notify(OMX_EventPortSettingsChanged,
+               1,
+               OMX_IndexConfigCommonOutputCrop,
+               NULL);
+    }
+
+    if (buf_width != mWidth || buf_height != mHeight) {
+        mWidth = buf_width;
+        mHeight = buf_height;
+
+        updatePortDefinitions();
+
+        if (mMode == MODE_H263) {
+            PVCleanUpVideoDecoder(mHandle);
+
+            uint8_t *vol_data[1];
+            int32_t vol_size = 0;
+
+            vol_data[0] = NULL;
+            if (!PVInitVideoDecoder(
+                    mHandle, vol_data, &vol_size, 1, mWidth, mHeight,
+                    H263_MODE)) {
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                return true;
+            }
+        }
+
+        mFramesConfigured = false;
+
+        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+        mOutputPortSettingsChange = AWAITING_DISABLED;
+        return true;
+    }
+
+    return false;
+}
+
+void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
+    if (portIndex == 0 && mInitialized) {
+        CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
+    }
+}
+
+void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+    if (portIndex != 1) {
+        return;
+    }
+
+    switch (mOutputPortSettingsChange) {
+        case NONE:
+            break;
+
+        case AWAITING_DISABLED:
+        {
+            CHECK(!enabled);
+            mOutputPortSettingsChange = AWAITING_ENABLED;
+            break;
+        }
+
+        default:
+        {
+            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+            CHECK(enabled);
+            mOutputPortSettingsChange = NONE;
+            break;
+        }
+    }
+}
+
+void SoftMPEG4::updatePortDefinitions() {
+    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
+    def->format.video.nFrameWidth = mWidth;
+    def->format.video.nFrameHeight = mHeight;
+    def->format.video.nStride = def->format.video.nFrameWidth;
+    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+    def = &editPortInfo(1)->mDef;
+    def->format.video.nFrameWidth = mWidth;
+    def->format.video.nFrameHeight = mHeight;
+    def->format.video.nStride = def->format.video.nFrameWidth;
+    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+    def->nBufferSize =
+        (((def->format.video.nFrameWidth + 15) & -16)
+            * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftMPEG4(name, callbacks, appData, component);
+}
+
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
new file mode 100644
index 0000000..dff08a7
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_MPEG4_H_
+
+#define SOFT_MPEG4_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct tagvideoDecControls;
+
+namespace android {
+
+struct SoftMPEG4 : public SimpleSoftOMXComponent {
+    SoftMPEG4(const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftMPEG4();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE getConfig(OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+    enum {
+        kNumInputBuffers  = 4,
+        kNumOutputBuffers = 2,
+    };
+
+    enum {
+        MODE_MPEG4,
+        MODE_H263,
+
+    } mMode;
+
+    tagvideoDecControls *mHandle;
+
+    size_t mInputBufferCount;
+
+    int32_t mWidth, mHeight;
+    int32_t mCropLeft, mCropTop, mCropRight, mCropBottom;
+
+    bool mSignalledError;
+    bool mInitialized;
+    bool mFramesConfigured;
+
+    int32_t mNumSamplesOutput;
+
+    enum {
+        NONE,
+        AWAITING_DISABLED,
+        AWAITING_ENABLED
+    } mOutputPortSettingsChange;
+
+    void initPorts();
+    status_t initDecoder();
+
+    void updatePortDefinitions();
+    bool portSettingsChanged();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4);
+};
+
+}  // namespace android
+
+#endif  // SOFT_MPEG4_H_
+
+