Squashed commit of the following:

commit 374ea382ee3a9e3ce17e4c6357fc40d02e362810
Author: Andreas Huber <andih@google.com>
Date:   Tue Jul 28 09:54:13 2009 -0700

    PV's OMX implementation now uses (spec-compliant) microseconds instead of milliseconds in buffer timestamps.

commit 8d02f8ab5d7b022ad4ad34db2a9bdeea6ce2acfe
Author: Andreas Huber <andih@google.com>
Date:   Mon Jul 27 14:24:26 2009 -0700

    Support for using an overlay for video playback on TI hardware.

    Appears to be currently constrained to CbYCrY 16-bit colorspace.

commit d17f321cb4b15c1fea378f33a7ef5998f23dd0fc
Author: Andreas Huber <andih@google.com>
Date:   Mon Jul 27 09:45:38 2009 -0700

    Added '--audio-only' commandline option to stagefright tool.

commit d8beef6be5c668c46451446d87e622933371cd75
Author: Andreas Huber <andih@google.com>
Date:   Fri Jul 24 13:35:00 2009 -0700

    Generalize the various workarounds for OMX nodes with their own unique interpretation of the spec.

commit c7dfd53eeadf8ed5a39bf2b19b014dcd62f3324d
Author: Andreas Huber <andih@google.com>
Date:   Thu Jul 23 16:06:36 2009 -0700

    Fixed erroneous TI AAC decoder behaviour wrt shutdown.

    The AAC decoder appears to not return out buffers on an Executing->Idle transition, implemented a workaround that does a flush on all ports followed by the Executing->Idle. Oh, and flush with OMX_ALL doesn't properly work either. Fun.

commit d6377282e75060881336578f166f9c7feacf3f8f
Author: Andreas Huber <andih@google.com>
Date:   Thu Jul 23 14:06:50 2009 -0700

    Apparently the "channels" parameter in AudioTrack's constructor no longer counts channels but is a bitmask of enabled destinations, update the code accordingly.

commit ff698c79e851a2e57d362e9c3a09828af4048087
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 16:54:44 2009 -0700

    Fix MPEG4 decoding using TI's hardware decoder that I broke earlier...

commit 2ef78bb87cd856eb7f0b3d7dd68782a8650c12bf
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 15:43:18 2009 -0700

    Now that the qcom decoder properly advertises its own custom colorspace, update dependent code to reflect this fact.

commit bbaec96910727080fd7c8a6907c04facb9f5220f
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 14:32:03 2009 -0700

    Finishing up previous, incomplete change.

commit 76f14a1ae816b6f434771f8d12bdad81196f351e
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 14:25:17 2009 -0700

    The TI video decoder now properly decoder AVC/H.264 content.

commit e106130d8c100d5c94603e43864a7a93cca10252
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 08:56:04 2009 -0700

    Experimental support for the TI H.264 decoder, various modifications to OMXDecoder, non-functional still.

commit 241c3062dec3447db1a1ee74558cb4b9098fc404
Author: Andreas Huber <andih@google.com>
Date:   Tue Jul 21 12:13:09 2009 -0700

    Enable TI hardware OMX decoders (except for AVC/H.264 which still has issues).

    This particular set of OMX nodes does not appear to properly return our buffers when sending the "disable" command on a port. Rather it reqires manually flushing that port and _then_ disabling it instead.

commit 1c34506a46e32ce25f2a86f3b4250dcfc037356a
Author: Andreas Huber <andih@google.com>
Date:   Tue Jul 21 08:51:35 2009 -0700

    Make it simpler to switch between the stagefright player and PVPlayer.

commit 249c6de05671d403f8dd51f095d49bf190430c9c
Author: Andreas Huber <andih@google.com>
Date:   Mon Jul 20 14:38:15 2009 -0700

    Prepare to use soon-to-be-available hardware decoders in the OMX decoder.
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 12bdead..d8db8b3 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -119,7 +119,8 @@
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
 
-    OMXDecoder *encoder = OMXDecoder::CreateEncoder(&client, enc_meta);
+    OMXDecoder *encoder =
+        OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
 
     encoder->setSource(decoder);
     // encoder->setSource(meta, new DummySource(width, height));
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 961942a..7e23574 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -102,6 +102,7 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
+    bool audioOnly = false;
     if (argc > 1 && !strcmp(argv[1], "--list")) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder = sm->getService(String16("media.player"));
@@ -121,6 +122,10 @@
         }
 
         return 0;
+    } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
+        audioOnly = true;
+        ++argv;
+        --argc;
     }
 
 #if 0
@@ -149,7 +154,11 @@
         const char *mime;
         meta->findCString(kKeyMIMEType, &mime);
 
-        if (!strncasecmp(mime, "video/", 6)) {
+        if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+            break;
+        }
+
+        if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
             break;
         }
     }
diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h
index 0859457..54a8047 100644
--- a/include/media/stagefright/OMXDecoder.h
+++ b/include/media/stagefright/OMXDecoder.h
@@ -26,6 +26,8 @@
 #include <utils/List.h>
 #include <utils/threads.h>
 
+#include <OMX_Video.h>
+
 namespace android {
 
 class OMXMediaBuffer;
@@ -35,10 +37,8 @@
                    public MediaBufferObserver {
 public:
     static OMXDecoder *Create(
-            OMXClient *client, const sp<MetaData> &data);
-
-    static OMXDecoder *CreateEncoder(
-            OMXClient *client, const sp<MetaData> &data);
+            OMXClient *client, const sp<MetaData> &data,
+            bool createEncoder = false);
 
     virtual ~OMXDecoder();
 
@@ -68,10 +68,22 @@
     };
 
     enum PortStatus {
-        kPortStatusActive   = 0,
-        kPortStatusDisabled = 1,
-        kPortStatusShutdown = 2,
-        kPortStatusFlushing = 3
+        kPortStatusActive             = 0,
+        kPortStatusDisabled           = 1,
+        kPortStatusShutdown           = 2,
+        kPortStatusFlushing           = 3,
+        kPortStatusFlushingToDisabled = 4,
+        kPortStatusFlushingToShutdown = 5,
+    };
+
+    enum Quirks {
+        kWantsRawNALFrames                   = 1,
+        kDoesntReturnBuffersOnDisable        = 2,
+        kDoesntFlushOnExecutingToIdle        = 4,
+        kDoesntProperlyFlushAllPortsAtOnce   = 8,
+        kRequiresAllocateBufferOnInputPorts  = 16,
+        kRequiresAllocateBufferOnOutputPorts = 32,
+        kRequiresLoadedToIdleAfterAllocation = 64
     };
 
     OMXClient *mClient;
@@ -79,6 +91,8 @@
     IOMX::node_id mNode;
     char *mComponentName;
     bool mIsMP3;
+    bool mIsAVC;
+    uint32_t mQuirks;
 
     MediaSource *mSource;
     sp<MetaData> mOutputFormat;
@@ -116,7 +130,8 @@
     bool mReachedEndOfInput;
 
     OMXDecoder(OMXClient *client, IOMX::node_id node,
-               const char *mime, const char *codec);
+               const char *mime, const char *codec,
+               uint32_t quirks);
 
     void setPortStatus(OMX_U32 port_index, PortStatus status);
     PortStatus getPortStatus(OMX_U32 port_index) const;
@@ -125,7 +140,13 @@
 
     void setAMRFormat();
     void setAACFormat();
-    void setVideoOutputFormat(OMX_U32 width, OMX_U32 height);
+
+    status_t setVideoPortFormatType(
+            OMX_U32 portIndex,
+            OMX_VIDEO_CODINGTYPE compressionFormat,
+            OMX_COLOR_FORMATTYPE colorFormat);
+
+    void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
     void setup();
     void dumpPortDefinition(OMX_U32 port_index);
 
@@ -144,6 +165,7 @@
 
     void freeInputBuffer(IOMX::buffer_id buffer);
     void freeOutputBuffer(IOMX::buffer_id buffer);
+    void freePortBuffers(OMX_U32 port_index);
 
     void postStart();
     void postEmptyBufferDone(IOMX::buffer_id buffer);
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
new file mode 100644
index 0000000..f7fa81b
--- /dev/null
+++ b/include/media/stagefright/TIHardwareRenderer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 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 TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+    TIHardwareRenderer(
+            const sp<ISurface> &surface,
+            size_t displayWidth, size_t displayHeight,
+            size_t decodedWidth, size_t decodedHeight);
+
+    virtual ~TIHardwareRenderer();
+
+    virtual void render(
+            const void *data, size_t size, void *platformPrivate);
+
+private:
+    sp<ISurface> mISurface;
+    size_t mDisplayWidth, mDisplayHeight;
+    size_t mDecodedWidth, mDecodedHeight;
+    size_t mFrameSize;
+    sp<Overlay> mOverlay;
+    Vector<void *> mOverlayAddresses;
+    size_t mIndex;
+
+    TIHardwareRenderer(const TIHardwareRenderer &);
+    TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+}  // namespace android
+
+#endif  // TI_HARDWARE_RENDERER_H_
+
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1d960c5..95d61cd 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -59,6 +59,8 @@
 #include <media/PVPlayer.h>
 #include "TestPlayerStub.h"
 
+//#undef USE_STAGEFRIGHT
+
 #if USE_STAGEFRIGHT
 #include "StagefrightPlayer.h"
 #endif
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 5944d9c..5be9224 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -26,6 +26,7 @@
         SurfaceRenderer.cpp       \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
+        TIHardwareRenderer.cpp    \
         Utils.cpp                 \
         AudioPlayer.cpp           \
         ESDS.cpp                  \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 17c72b9..d547556 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -87,7 +87,10 @@
     } else {
         mAudioTrack = new AudioTrack(
                 AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
-                numChannels, 8192, 0, &AudioCallback, this, 0);
+                (numChannels == 2)
+                    ? AudioSystem::CHANNEL_OUT_STEREO
+                    : AudioSystem::CHANNEL_OUT_MONO,
+                8192, 0, &AudioCallback, this, 0);
 
         assert(mAudioTrack->initCheck() == OK);
 
@@ -217,8 +220,10 @@
 
             Mutex::Autolock autoLock(mLock);
             mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+
             mPositionTimeRealUs =
-                ((mNumFramesPlayed + size_done / 4) * 1000000) / mSampleRate; // XXX
+                ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+                    / mSampleRate;
         }
 
         if (mInputBuffer->range_length() == 0) {
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 6b47a38..01cb2d9 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -73,8 +73,6 @@
 
     if (bitrate_index == 0 || bitrate_index == 0x0f) {
         // Disallow "free" bitrate.
-
-        LOGE("We disallow 'free' bitrate for now.");
         return false;
     }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index caaec06..4c883c6 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -73,6 +73,8 @@
 
     bool mNeedsNALFraming;
 
+    uint8_t *mSrcBuffer;
+
     MPEG4Source(const MPEG4Source &);
     MPEG4Source &operator=(const MPEG4Source &);
 };
@@ -743,7 +745,8 @@
       mBuffer(NULL),
       mBufferOffset(0),
       mBufferSizeRemaining(0),
-      mNeedsNALFraming(false) {
+      mNeedsNALFraming(false),
+      mSrcBuffer(NULL) {
     const char *mime;
     bool success = mFormat->findCString(kKeyMIMEType, &mime);
     assert(success);
@@ -777,8 +780,13 @@
     status_t err = mSampleTable->getMaxSampleSize(&max_size);
     assert(err == OK);
 
-    // Add padding for de-framing of AVC content just in case.
-    mGroup->add_buffer(new MediaBuffer(max_size + 2));
+    // Assume that a given buffer only contains at most 10 fragments,
+    // each fragment originally prefixed with a 2 byte length will
+    // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
+    // and thus will grow by 2 bytes per fragment.
+    mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
+
+    mSrcBuffer = new uint8_t[max_size];
 
     mStarted = true;
 
@@ -793,6 +801,9 @@
         mBuffer = NULL;
     }
 
+    delete[] mSrcBuffer;
+    mSrcBuffer = NULL;
+
     delete mGroup;
     mGroup = NULL;
 
@@ -832,33 +843,31 @@
         // fall through
     }
 
-    if (mBuffer == NULL) {
-        off_t offset;
-        size_t size;
-        status_t err = mSampleTable->getSampleOffsetAndSize(
-                mCurrentSampleIndex, &offset, &size);
+    off_t offset;
+    size_t size;
+    status_t err = mSampleTable->getSampleOffsetAndSize(
+            mCurrentSampleIndex, &offset, &size);
 
-        if (err != OK) {
-            return err;
-        }
+    if (err != OK) {
+        return err;
+    }
 
-        uint32_t dts;
-        err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+    uint32_t dts;
+    err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
 
-        if (err != OK) {
-            return err;
-        }
+    if (err != OK) {
+        return err;
+    }
 
-        err = mGroup->acquire_buffer(&mBuffer);
-        if (err != OK) {
-            assert(mBuffer == NULL);
-            return err;
-        }
+    err = mGroup->acquire_buffer(&mBuffer);
+    if (err != OK) {
+        assert(mBuffer == NULL);
+        return err;
+    }
 
-        assert(mBuffer->size() + 2 >= size);
-
+    if (!mIsAVC || !mNeedsNALFraming) {
         ssize_t num_bytes_read =
-            mDataSource->read_at(offset, (uint8_t *)mBuffer->data() + 2, size);
+            mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
@@ -867,50 +876,62 @@
             return err;
         }
 
-        mBuffer->set_range(2, size);
+        mBuffer->set_range(0, size);
         mBuffer->meta_data()->clear();
         mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
         mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
-
         ++mCurrentSampleIndex;
 
-        mBufferOffset = 2;
-        mBufferSizeRemaining = size;
-    }
-
-    if (!mIsAVC) {
         *out = mBuffer;
         mBuffer = NULL;
 
         return OK;
     }
 
-    uint8_t *data = (uint8_t *)mBuffer->data() + mBufferOffset;
-    assert(mBufferSizeRemaining >= 2);
+    ssize_t num_bytes_read =
+        mDataSource->read_at(offset, mSrcBuffer, size);
 
-    size_t nal_length = (data[0] << 8) | data[1];
-    assert(mBufferSizeRemaining >= 2 + nal_length);
-
-    if (mNeedsNALFraming) {
-        // Insert marker.
-        data[-2] = data[-1] = data[0] = 0;
-        data[1] = 1;
-
-        mBuffer->set_range(mBufferOffset - 2, nal_length + 4);
-    } else {
-        mBuffer->set_range(mBufferOffset + 2, nal_length);
-    }
-
-    mBufferOffset += nal_length + 2;
-    mBufferSizeRemaining -= nal_length + 2;
-
-    if (mBufferSizeRemaining > 0) {
-        *out = mBuffer->clone();
-    } else {
-        *out = mBuffer;
+    if (num_bytes_read < (ssize_t)size) {
+        mBuffer->release();
         mBuffer = NULL;
+
+        return err;
     }
 
+    uint8_t *dstData = (uint8_t *)mBuffer->data();
+    size_t srcOffset = 0;
+    size_t dstOffset = 0;
+    while (srcOffset < size) {
+        assert(srcOffset + 1 < size);
+        size_t nalLength =
+            (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+        assert(srcOffset + 1 + nalLength < size);
+        srcOffset += 2;
+
+        if (nalLength == 0) {
+            continue;
+        }
+
+        assert(dstOffset + 4 <= mBuffer->size());
+
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 1;
+        memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+        srcOffset += nalLength;
+        dstOffset += nalLength;
+    }
+
+    mBuffer->set_range(0, dstOffset);
+    mBuffer->meta_data()->clear();
+    mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+    mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+    ++mCurrentSampleIndex;
+
+    *out = mBuffer;
+    mBuffer = NULL;
+
     return OK;
 }
 
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 78fcdee..04c9a11 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -40,6 +40,7 @@
 #include <media/stagefright/SoftwareRenderer.h>
 #include <media/stagefright/SurfaceRenderer.h>
 #include <media/stagefright/TimeSource.h>
+#include <media/stagefright/TIHardwareRenderer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Surface.h>
 
@@ -311,6 +312,9 @@
         {
             Mutex::Autolock autoLock(mLock);
             mVideoPosition = pts_us;
+
+            LOGV("now_video = %.2f secs (%lld ms)",
+                 pts_us / 1E6, (pts_us + 500) / 1000);
         }
 
         if (seeking && mAudioPlayer != NULL) {
@@ -344,6 +348,7 @@
         if (mAudioPlayer != NULL
             && mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
             mTimeSourceDeltaUs = realtime_us - mediatime_us;
+            LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
         }
 
         int64_t now_us = mTimeSource->getRealTimeUs();
@@ -436,6 +441,7 @@
 }
 
 void MediaPlayerImpl::setAudioSource(MediaSource *source) {
+    LOGI("setAudioSource");
     mAudioSource = source;
 
     sp<MetaData> meta = source->getFormat();
@@ -646,17 +652,28 @@
     success = success && meta->findInt32(kKeyHeight, &decodedHeight);
     assert(success);
 
+    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
     if (mSurface.get() != NULL) {
+        LOGW("Using SurfaceRenderer.");
         mRenderer =
             new SurfaceRenderer(
                     mSurface, mVideoWidth, mVideoHeight,
                     decodedWidth, decodedHeight);
-    } else if (format == OMX_COLOR_FormatYUV420Planar
-        && !strncasecmp(component, "OMX.qcom.video.decoder.", 23)) {
+    } else if (format == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+        && !strncmp(component, "OMX.qcom.video.decoder.", 23)) {
+        LOGW("Using QComHardwareRenderer.");
         mRenderer =
             new QComHardwareRenderer(
                     mISurface, mVideoWidth, mVideoHeight,
                     decodedWidth, decodedHeight);
+    } else if (format == OMX_COLOR_FormatCbYCrY
+            && !strcmp(component, "OMX.TI.Video.Decoder")) {
+        LOGW("Using TIHardwareRenderer.");
+        mRenderer =
+            new TIHardwareRenderer(
+                    mISurface, mVideoWidth, mVideoHeight,
+                    decodedWidth, decodedHeight);
     } else {
         LOGW("Using software renderer.");
         mRenderer = new SoftwareRenderer(
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index c059a9d..1fc2ba0 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -20,6 +20,7 @@
 
 #undef NDEBUG
 #include <assert.h>
+#include <ctype.h>
 
 #include <OMX_Component.h>
 
@@ -54,14 +55,20 @@
 };
 
 static const CodecInfo kDecoderInfo[] = {
+    { "audio/mpeg", "OMX.TI.MP3.decode" },
     { "audio/mpeg", "OMX.PV.mp3dec" },
+    { "audio/3gpp", "OMX.TI.AMR.decode" },
     { "audio/3gpp", "OMX.PV.amrdec" },
+    { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
     { "audio/mp4a-latm", "OMX.PV.aacdec" },
     { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
+    { "video/mp4v-es", "OMX.TI.Video.Decoder" },
     { "video/mp4v-es", "OMX.PV.mpeg4dec" },
     { "video/3gpp", "OMX.qcom.video.decoder.h263" },
+    { "video/3gpp", "OMX.TI.Video.Decoder" },
     { "video/3gpp", "OMX.PV.h263dec" },
     { "video/avc", "OMX.qcom.video.decoder.avc" },
+    { "video/avc", "OMX.TI.Video.Decoder" },
     { "video/avc", "OMX.PV.avcdec" },
 };
 
@@ -92,7 +99,9 @@
 }
 
 // static
-OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
+OMXDecoder *OMXDecoder::Create(
+        OMXClient *client, const sp<MetaData> &meta,
+        bool createEncoder) {
     const char *mime;
     bool success = meta->findCString(kKeyMIMEType, &mime);
     assert(success);
@@ -102,9 +111,15 @@
     const char *codec = NULL;
     IOMX::node_id node = 0;
     for (int index = 0;; ++index) {
-        codec = GetCodec(
-                kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
-                mime, index);
+        if (createEncoder) {
+            codec = GetCodec(
+                    kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+                    mime, index);
+        } else {
+            codec = GetCodec(
+                    kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+                    mime, index);
+        }
 
         if (!codec) {
             return NULL;
@@ -118,7 +133,29 @@
         }
     }
 
-    OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec);
+    uint32_t quirks = 0;
+    if (!strcmp(codec, "OMX.PV.avcdec")) {
+        quirks |= kWantsRawNALFrames;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")
+        || !strcmp(codec, "OMX.TI.MP3.decode")) {
+        quirks |= kDoesntReturnBuffersOnDisable;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")) {
+        quirks |= kDoesntFlushOnExecutingToIdle;
+        quirks |= kDoesntProperlyFlushAllPortsAtOnce;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.encoder.", 23)) {
+        quirks |= kRequiresAllocateBufferOnInputPorts;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.decoder.", 23)) {
+        quirks |= kRequiresAllocateBufferOnOutputPorts;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.", 15)) {
+        quirks |= kRequiresLoadedToIdleAfterAllocation;
+    }
+
+    OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks);
 
     uint32_t type;
     const void *data;
@@ -169,52 +206,22 @@
     return decoder;
 }
 
-// static
-OMXDecoder *OMXDecoder::CreateEncoder(
-        OMXClient *client, const sp<MetaData> &meta) {
-    const char *mime;
-    bool success = meta->findCString(kKeyMIMEType, &mime);
-    assert(success);
-
-    sp<IOMX> omx = client->interface();
-
-    const char *codec = NULL;
-    IOMX::node_id node = 0;
-    for (int index = 0;; ++index) {
-        codec = GetCodec(
-                kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
-                mime, index);
-
-        if (!codec) {
-            return NULL;
-        }
-
-        LOGI("Attempting to allocate OMX node '%s'", codec);
-
-        status_t err = omx->allocate_node(codec, &node);
-        if (err == OK) {
-            break;
-        }
-    }
-
-    OMXDecoder *encoder = new OMXDecoder(client, node, mime, codec);
-
-    return encoder;
-}
-
 OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
-                       const char *mime, const char *codec)
+                       const char *mime, const char *codec,
+                       uint32_t quirks)
     : mClient(client),
       mOMX(mClient->interface()),
       mNode(node),
       mComponentName(strdup(codec)),
       mIsMP3(!strcasecmp(mime, "audio/mpeg")),
+      mIsAVC(!strcasecmp(mime, "video/avc")),
+      mQuirks(quirks),
       mSource(NULL),
       mCodecSpecificDataIterator(mCodecSpecificData.begin()),
       mState(OMX_StateLoaded),
       mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
       mShutdownInitiated(false),
-      mDealer(new MemoryDealer(3 * 1024 * 1024)),
+      mDealer(new MemoryDealer(5 * 1024 * 1024)),
       mSeeking(false),
       mStarted(false),
       mErrorCondition(OK),
@@ -261,7 +268,7 @@
     // mDealer->dump("Decoder Dealer");
 
     sp<MetaData> params = new MetaData;
-    if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+    if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
         params->setInt32(kKeyNeedsNALFraming, true);
     }
 
@@ -297,7 +304,7 @@
     }
 
     int attempt = 1;
-    while (mState != OMX_StateLoaded && attempt < 10) {
+    while (mState != OMX_StateLoaded && attempt < 20) {
         usleep(100000);
 
         ++attempt;
@@ -366,7 +373,11 @@
             mOutputBuffers.erase(mOutputBuffers.begin());
         }
 
-        status_t err = mOMX->send_command(mNode, OMX_CommandFlush, -1);
+        // XXX One of TI's decoders appears to ignore a flush if it doesn't
+        // currently hold on to any buffers on the port in question and
+        // never sends the completion event... FIXME
+
+        status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
         assert(err == OK);
 
         // Once flushing is completed buffers will again be scheduled to be
@@ -472,9 +483,121 @@
     assert(err == NO_ERROR);
 }
 
-void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
+status_t OMXDecoder::setVideoPortFormatType(
+        OMX_U32 portIndex,
+        OMX_VIDEO_CODINGTYPE compressionFormat,
+        OMX_COLOR_FORMATTYPE colorFormat) {
+    OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+    format.nSize = sizeof(format);
+    format.nVersion.s.nVersionMajor = 1;
+    format.nVersion.s.nVersionMinor = 1;
+    format.nPortIndex = portIndex;
+    format.nIndex = 0;
+    bool found = false;
+
+    OMX_U32 index = 0;
+    for (;;) {
+        format.nIndex = index;
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+
+        if (err != OK) {
+            return err;
+        }
+
+        // The following assertion is violated by TI's video decoder.
+        // assert(format.nIndex == index);
+
+        if (format.eCompressionFormat == compressionFormat
+            && format.eColorFormat == colorFormat) {
+            found = true;
+            break;
+        }
+
+        ++index;
+    }
+
+    if (!found) {
+        return UNKNOWN_ERROR;
+    }
+
+    status_t err = mOMX->set_parameter(
+            mNode, OMX_IndexParamVideoPortFormat,
+            &format, sizeof(format));
+
+    return err;
+}
+
+#if 1
+void OMXDecoder::setVideoOutputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
     LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
 
+#if 1
+    // Enabling this code appears to be the right thing(tm), but,...
+    // the TI decoder then loses the ability to output YUV420 and only outputs
+    // YCbYCr (16bit)
+    if (!strcasecmp("video/avc", mime)) {
+        OMX_PARAM_COMPONENTROLETYPE role;
+        role.nSize = sizeof(role);
+        role.nVersion.s.nVersionMajor = 1;
+        role.nVersion.s.nVersionMinor = 1;
+        strncpy((char *)role.cRole, "video_decoder.avc",
+                OMX_MAX_STRINGNAME_SIZE - 1);
+        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = mOMX->set_parameter(
+                mNode, OMX_IndexParamStandardComponentRole,
+                &role, sizeof(role));
+        assert(err == OK);
+    }
+#endif
+
+    OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+    if (!strcasecmp("video/avc", mime)) {
+        compressionFormat = OMX_VIDEO_CodingAVC;
+    } else if (!strcasecmp("video/mp4v-es", mime)) {
+        compressionFormat = OMX_VIDEO_CodingMPEG4;
+    } else if (!strcasecmp("video/3gpp", mime)) {
+        compressionFormat = OMX_VIDEO_CodingH263;
+    } else {
+        assert(!"Should not be here. Not a supported video mime type.");
+    }
+
+    setVideoPortFormatType(
+            kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
+
+#if 1
+    {
+        OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+        format.nSize = sizeof(format);
+        format.nVersion.s.nVersionMajor = 1;
+        format.nVersion.s.nVersionMinor = 1;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+
+        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+
+        static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+               || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+    }
+#endif
+
     OMX_PARAM_PORTDEFINITIONTYPE def;
     OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
 
@@ -502,7 +625,7 @@
     
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
-    // video_def.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
     video_def->eColorFormat = OMX_COLOR_FormatUnused;
 
     err = mOMX->set_parameter(
@@ -522,21 +645,189 @@
 
     assert(def.eDomain == OMX_PortDomainVideo);
     
+#if 0
     def.nBufferSize =
         (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2;  // YUV420
+#endif
 
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
-    video_def->nStride = width;
-    // video_def->nSliceHeight = height;
-    video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
-//    video_def->eColorFormat = OMX_COLOR_FormatYUV420Planar;
 
     err = mOMX->set_parameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     assert(err == NO_ERROR);
 }
 
+#else
+static void hexdump(const void *_data, size_t size) {
+    char line[256];
+    char tmp[16];
+
+    const uint8_t *data = (const uint8_t *)_data;
+    size_t offset = 0;
+    while (offset < size) {
+        sprintf(line, "0x%04x  ", offset);
+
+        size_t n = size - offset;
+        if (n > 16) {
+            n = 16;
+        }
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (i == 8) {
+                strcat(line, " ");
+            }
+
+            if (offset + i < size) {
+                sprintf(tmp, "%02x ", data[offset + i]);
+                strcat(line, tmp);
+            } else {
+                strcat(line, "   ");
+            }
+        }
+
+        strcat(line, " ");
+
+        for (size_t i = 0; i < n; ++i) {
+            if (isprint(data[offset + i])) {
+                sprintf(tmp, "%c", data[offset + i]);
+                strcat(line, tmp);
+            } else {
+                strcat(line, ".");
+            }
+        }
+
+        LOGI(line);
+
+        offset += 16;
+    }
+}
+
+static void DumpPortDefinitionType(const void *_param) {
+    OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param;
+
+    LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output",
+        param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize);
+
+    if (param->eDomain == OMX_PortDomainVideo) {
+        OMX_VIDEO_PORTDEFINITIONTYPE *video = &param->format.video;
+        LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d",
+            video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat);
+    } else {
+        hexdump(param, param->nSize);
+    }
+}
+
+void OMXDecoder::setVideoOutputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
+    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+#if 0
+    // Enabling this code appears to be the right thing(tm), but,...
+    // the decoder then loses the ability to output YUV420 and only outputs
+    // YCbYCr (16bit)
+    {
+        OMX_PARAM_COMPONENTROLETYPE role;
+        role.nSize = sizeof(role);
+        role.nVersion.s.nVersionMajor = 1;
+        role.nVersion.s.nVersionMinor = 1;
+        strncpy((char *)role.cRole, "video_decoder.avc",
+                OMX_MAX_STRINGNAME_SIZE - 1);
+        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = mOMX->set_parameter(
+                mNode, OMX_IndexParamStandardComponentRole,
+                &role, sizeof(role));
+        assert(err == OK);
+    }
+#endif
+
+    setVideoPortFormatType(
+            kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused);
+
+#if 1
+    {
+        OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+        format.nSize = sizeof(format);
+        format.nVersion.s.nVersionMajor = 1;
+        format.nVersion.s.nVersionMinor = 1;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+
+        LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat");
+        hexdump(&format, format.nSize);
+
+        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+               || format.eColorFormat == OMX_COLOR_FormatCbYCrY);
+
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+    }
+#endif
+
+    OMX_PORT_PARAM_TYPE ptype;
+    ptype.nSize = sizeof(ptype);
+    ptype.nVersion.s.nVersionMajor = 1;
+    ptype.nVersion.s.nVersionMinor = 1;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit");
+    hexdump(&ptype, ptype.nSize);
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexInput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+    DumpPortDefinitionType(&def);
+
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    def.nPortIndex = kPortIndexOutput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+    DumpPortDefinitionType(&def);
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+}
+
+#endif
+
 void OMXDecoder::setup() {
     const sp<MetaData> &meta = mSource->getFormat();
 
@@ -554,7 +845,7 @@
         success = success && meta->findInt32(kKeyHeight, &height);
         assert(success);
 
-        setVideoOutputFormat(width, height);
+        setVideoOutputFormat(mime, width, height);
     }
 
     // dumpPortDefinition(0);
@@ -644,10 +935,7 @@
 }
 
 void OMXDecoder::onStart() {
-    bool needs_qcom_hack =
-        !strncmp(mComponentName, "OMX.qcom.video.", 15);
-
-    if (!needs_qcom_hack) {
+    if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
         status_t err =
             mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
         assert(err == NO_ERROR);
@@ -656,7 +944,7 @@
     allocateBuffers(kPortIndexInput);
     allocateBuffers(kPortIndexOutput);
 
-    if (needs_qcom_hack) {
+    if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
         // XXX this should happen before AllocateBuffers, but qcom's
         // h264 vdec disagrees.
         status_t err =
@@ -691,13 +979,17 @@
 
     for (OMX_U32 i = 0; i < num_buffers; ++i) {
         sp<IMemory> mem = mDealer->allocate(buffer_size);
+        if (mem.get() == NULL) {
+            LOGE("[%s] allocating IMemory of size %ld FAILED.",
+                 mComponentName, buffer_size);
+        }
         assert(mem.get() != NULL);
 
         IOMX::buffer_id buffer;
         status_t err;
 
         if (port_index == kPortIndexInput
-            && !strncmp(mComponentName, "OMX.qcom.video.encoder.", 23)) {
+                && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
             // qcom's H.263 encoder appears to want to allocate its own input
             // buffers.
             err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
@@ -706,7 +998,7 @@
                      mComponentName, err);
             }
         } else if (port_index == kPortIndexOutput
-            && !strncmp(mComponentName, "OMX.qcom.video.decoder.", 23)) {
+                && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
 #if 1
             err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
 #else
@@ -817,18 +1109,59 @@
         case OMX_CommandFlush: {
             OMX_U32 port_index = data;
             LOGV("Port %ld flush complete.", port_index);
-            assert(getPortStatus(port_index) == kPortStatusFlushing);
 
-            setPortStatus(port_index, kPortStatusActive);
-            BufferList *buffers = &mBuffers.editItemAt(port_index);
-            while (!buffers->empty()) {
-                IOMX::buffer_id buffer = *buffers->begin();
-                buffers->erase(buffers->begin());
+            PortStatus status = getPortStatus(port_index);
 
-                if (port_index == kPortIndexInput) {
-                    postEmptyBufferDone(buffer);
-                } else {
-                    postInitialFillBuffer(buffer);
+            assert(status == kPortStatusFlushing
+                    || status == kPortStatusFlushingToDisabled
+                    || status == kPortStatusFlushingToShutdown);
+
+            switch (status) {
+                case kPortStatusFlushing:
+                {
+                    // This happens when we're flushing before a seek.
+                    setPortStatus(port_index, kPortStatusActive);
+                    BufferList *buffers = &mBuffers.editItemAt(port_index);
+                    while (!buffers->empty()) {
+                        IOMX::buffer_id buffer = *buffers->begin();
+                        buffers->erase(buffers->begin());
+
+                        if (port_index == kPortIndexInput) {
+                            postEmptyBufferDone(buffer);
+                        } else {
+                            postInitialFillBuffer(buffer);
+                        }
+                    }
+                    break;
+                }
+
+                case kPortStatusFlushingToDisabled:
+                {
+                    // Port settings have changed and the (buggy) OMX component
+                    // does not properly return buffers on disabling, we need to
+                    // do a flush first and _then_ disable the port in question.
+
+                    setPortStatus(port_index, kPortStatusDisabled);
+                    status_t err = mOMX->send_command(
+                            mNode, OMX_CommandPortDisable, port_index);
+                    assert(err == OK);
+
+                    freePortBuffers(port_index);
+                    break;
+                }
+
+                default:
+                {
+                    assert(status == kPortStatusFlushingToShutdown);
+
+                    setPortStatus(port_index, kPortStatusShutdown);
+                    if (getPortStatus(kPortIndexInput) == kPortStatusShutdown
+                        && getPortStatus(kPortIndexOutput) == kPortStatusShutdown) {
+                        status_t err = mOMX->send_command(
+                                mNode, OMX_CommandStateSet, OMX_StateIdle);
+                        assert(err == OK);
+                    }
+                    break;
                 }
             }
             break;
@@ -841,10 +1174,22 @@
 
 void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
     assert(getPortStatus(port_index) == kPortStatusActive);
-    setPortStatus(port_index, kPortStatusDisabled);
 
-    status_t err =
-        mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+    status_t err;
+
+    if (mQuirks & kDoesntReturnBuffersOnDisable) {
+        // Decoder does not properly return our buffers when disabled...
+        // Need to flush port instead and _then_ disable.
+
+        setPortStatus(port_index, kPortStatusFlushingToDisabled);
+
+        err = mOMX->send_command(mNode, OMX_CommandFlush, port_index);
+    } else {
+        setPortStatus(port_index, kPortStatusDisabled);
+
+        err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+    }
+
     assert(err == NO_ERROR);
 }
 
@@ -894,19 +1239,8 @@
             mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
         assert(err == NO_ERROR);
 
-        BufferList *ibuffers = &mBuffers.editItemAt(kPortIndexInput);
-        for (BufferList::iterator it = ibuffers->begin();
-             it != ibuffers->end(); ++it) {
-            freeInputBuffer(*it);
-        }
-        ibuffers->clear();
-
-        BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
-        for (BufferList::iterator it = obuffers->begin();
-             it != obuffers->end(); ++it) {
-            freeOutputBuffer(*it);
-        }
-        obuffers->clear();
+        freePortBuffers(kPortIndexInput);
+        freePortBuffers(kPortIndexOutput);
     }
 }
 
@@ -925,26 +1259,41 @@
 
     mShutdownInitiated = true;
 
-    status_t err =
-        mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
-    assert(err == NO_ERROR);
+    status_t err;
+    if (mQuirks & kDoesntFlushOnExecutingToIdle) {
+        if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
+            err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
+            assert(err == OK);
 
-    setPortStatus(kPortIndexInput, kPortStatusShutdown);
-    setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+            err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
+        } else {
+            err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+        }
+
+        setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
+        setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
+    } else {
+        err = mClient->send_command(
+                mNode, OMX_CommandStateSet, OMX_StateIdle);
+
+        setPortStatus(kPortIndexInput, kPortStatusShutdown);
+        setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+    }
+    assert(err == OK);
 }
 
 void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
-    int shift = 2 * port_index;
+    int shift = 3 * port_index;
 
-    mPortStatusMask &= ~(3 << shift);
+    mPortStatusMask &= ~(7 << shift);
     mPortStatusMask |= status << shift;
 }
 
 OMXDecoder::PortStatus OMXDecoder::getPortStatus(
         OMX_U32 port_index) const {
-    int shift = 2 * port_index;
+    int shift = 3 * port_index;
 
-    return static_cast<PortStatus>((mPortStatusMask >> shift) & 3);
+    return static_cast<PortStatus>((mPortStatusMask >> shift) & 7);
 }
 
 void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
@@ -964,6 +1313,8 @@
             break;
 
         case kPortStatusFlushing:
+        case kPortStatusFlushingToDisabled:
+        case kPortStatusFlushingToShutdown:
             LOGV("We're currently flushing, enqueue INPUT buffer %p.", buffer);
             mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
             err = NO_ERROR;
@@ -980,7 +1331,9 @@
 void OMXDecoder::onFillBufferDone(const omx_message &msg) {
     IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
 
-    LOGV("[%s] onFillBufferDone (%p)", mComponentName, buffer);
+    LOGV("[%s] on%sFillBufferDone (%p, size:%ld)", mComponentName,
+         msg.type == omx_message::INITIAL_FILL_BUFFER ? "Initial" : "",
+         buffer, msg.u.extended_buffer_data.range_length);
 
     status_t err;
     switch (getPortStatus(kPortIndexOutput)) {
@@ -995,6 +1348,8 @@
             break;
 
         case kPortStatusFlushing:
+        case kPortStatusFlushingToDisabled:
+        case kPortStatusFlushingToShutdown:
             LOGV("We're currently flushing, enqueue OUTPUT buffer %p.", buffer);
             mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
             err = NO_ERROR;
@@ -1035,7 +1390,7 @@
 
         size_t range_length = 0;
 
-        if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+        if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
             assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
 
             memcpy(mem->pointer(), kNALStartCode, 4);
@@ -1142,15 +1497,14 @@
     OMX_TICKS timestamp = 0;
 
     if (success) {
-        // XXX units should be microseconds but PV treats them as milliseconds.
-        timestamp = ((OMX_S64)units * 1000) / scale;
+        timestamp = ((OMX_S64)units * 1000000) / scale;
     }
 
     input_buffer->release();
     input_buffer = NULL;
 
-    LOGV("[%s] Calling EmptyBuffer on buffer %p",
-         mComponentName, buffer);
+    LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
+         mComponentName, buffer, src_length, flags);
 
     status_t err2 = mClient->emptyBuffer(
             mNode, buffer, 0, src_length, flags, timestamp);
@@ -1170,7 +1524,8 @@
     media_buffer->meta_data()->clear();
 
     media_buffer->meta_data()->setInt32(
-            kKeyTimeUnits, msg.u.extended_buffer_data.timestamp);
+            kKeyTimeUnits,
+            (msg.u.extended_buffer_data.timestamp + 500) / 1000);
     media_buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
 
     if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
@@ -1198,7 +1553,9 @@
 
     PortStatus outputStatus = getPortStatus(kPortIndexOutput);
     if (outputStatus == kPortStatusShutdown
-            || outputStatus == kPortStatusFlushing) {
+            || outputStatus == kPortStatusFlushing
+            || outputStatus == kPortStatusFlushingToDisabled
+            || outputStatus == kPortStatusFlushingToShutdown) {
         mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
     } else {
         LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
@@ -1326,4 +1683,18 @@
     postMessage(msg);
 }
 
+void OMXDecoder::freePortBuffers(OMX_U32 port_index) {
+    BufferList *buffers = &mBuffers.editItemAt(port_index);
+    while (!buffers->empty()) {
+        IOMX::buffer_id buffer = *buffers->begin();
+        buffers->erase(buffers->begin());
+
+        if (port_index == kPortIndexInput) {
+            freeInputBuffer(buffer);
+        } else {
+            freeOutputBuffer(buffer);
+        }
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/TIHardwareRenderer.cpp b/media/libstagefright/TIHardwareRenderer.cpp
new file mode 100644
index 0000000..ba42ef4
--- /dev/null
+++ b/media/libstagefright/TIHardwareRenderer.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 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_TAG "TIHardwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TIHardwareRenderer::TIHardwareRenderer(
+        const sp<ISurface> &surface,
+        size_t displayWidth, size_t displayHeight,
+        size_t decodedWidth, size_t decodedHeight)
+    : mISurface(surface),
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mDecodedWidth(decodedWidth),
+      mDecodedHeight(decodedHeight),
+      mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+    assert(mISurface.get() != NULL);
+    assert(mDecodedWidth > 0);
+    assert(mDecodedHeight > 0);
+
+    sp<OverlayRef> ref = mISurface->createOverlay(
+            mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
+
+    if (ref.get() == NULL) {
+        LOGE("Unable to create the overlay!");
+        return;
+    }
+
+    mOverlay = new Overlay(ref);
+
+    for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) {
+        mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i));
+    }
+    mIndex = mOverlayAddresses.size() - 1;
+}
+
+TIHardwareRenderer::~TIHardwareRenderer() {
+    if (mOverlay.get() != NULL) {
+        mOverlay->destroy();
+        mOverlay.clear();
+
+        // XXX apparently destroying an overlay is an asynchronous process...
+        sleep(1);
+    }
+}
+
+void TIHardwareRenderer::render(
+        const void *data, size_t size, void *platformPrivate) {
+    // assert(size == mFrameSize);
+
+    if (mOverlay.get() == NULL) {
+        return;
+    }
+
+#if 0
+    overlay_buffer_t buffer;
+    if (mOverlay->dequeueBuffer(&buffer) == OK) {
+        void *addr = mOverlay->getBufferAddress(buffer);
+
+        memcpy(addr, data, size);
+
+        mOverlay->queueBuffer(buffer);
+    }
+#else
+    memcpy(mOverlayAddresses[mIndex], data, size);
+    mOverlay->queueBuffer((void *)mIndex);
+
+    if (mIndex-- == 0) {
+        mIndex = mOverlayAddresses.size() - 1;
+    }
+#endif
+}
+
+}  // namespace android
+