Squashed commit of the following:

commit 5bb012f0065f7ffaaeb4f569d71f0e3a8d6b19c3
Author: Andreas Huber <andih@google.com>
Date:   Fri Aug 14 10:40:08 2009 -0700

    An attempt at fixing export using the qcom encoders. More quirks.

commit 0690e76bfa48118a68287ccf1bbfa82febaa620c
Author: Andreas Huber <andih@google.com>
Date:   Fri Aug 14 09:08:28 2009 -0700

    Callbacks are now dispatched from a separate thread in OMX.

commit c6571a039526df29b6343f9a1971dbc019088c61
Author: Andreas Huber <andih@google.com>
Date:   Thu Aug 13 15:42:25 2009 -0700

    Massive API changes throughout stagefright, smart pointers everywhere.

commit 900612af6a0555664d9ba195112cd859491265f4
Author: Andreas Huber <andih@google.com>
Date:   Thu Aug 13 13:33:12 2009 -0700

    OMXCodecs now properly shutdown.

commit 96732f05e1b0603dcd1b11f16a23512592eeb4f5
Author: Andreas Huber <andih@google.com>
Date:   Thu Aug 13 12:04:04 2009 -0700

    More work on JPEG decoding using the hardware OMX component.

commit 63839a073ac393e3a130434ba467969053b694ad
Author: Andreas Huber <andih@google.com>
Date:   Wed Aug 12 13:13:31 2009 -0700

    An attempt to drive the JPEG decoder OMX node.

commit 3ac2fe5ab2926eda81b2123610b2434c645294ff
Author: Andreas Huber <andih@google.com>
Date:   Tue Aug 11 16:38:21 2009 -0700

    Renamed StateMachine to OMXCodec and put it in its proper place.

commit 247da75a96bf8881956413023dd49a84d5b4f5b2
Author: Andreas Huber <andih@google.com>
Date:   Tue Aug 11 16:06:19 2009 -0700

    Statemachine is now a full-fledged MediaSource.

commit 045244f6771fa0b9b329495c953afda900a84b71
Author: Andreas Huber <andih@google.com>
Date:   Fri Aug 7 09:16:54 2009 -0700

    Properly setup the input format when exporting to AMR audio.

commit 271b984cb32c5cd9e46e3f90ae121f334e4b8da9
Author: Andreas Huber <andih@google.com>
Date:   Thu Aug 6 09:59:38 2009 -0700

    Added some code to test audio encoding to the OMX harness.

commit 79af4748e4af33bd66d3fbac606e332a69741cf4
Author: Andreas Huber <andih@google.com>
Date:   Wed Aug 5 14:36:22 2009 -0700

    Merge the old OMXDecoder and the new, shiny, StateMachine code.

commit 91cf5dd77a8762bc10a0b2ffce35e3bbeb262231
Author: Andreas Huber <andih@google.com>
Date:   Tue Aug 4 17:41:43 2009 -0700

    A new harness to test OMX node compliance (and quirks).
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d1dbc5c..ec3241c 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -18,6 +18,8 @@
     SEND_COMMAND,
     GET_PARAMETER,
     SET_PARAMETER,
+    GET_CONFIG,
+    SET_CONFIG,
     USE_BUFFER,
     ALLOC_BUFFER,
     ALLOC_BUFFER_WITH_BACKUP,
@@ -25,6 +27,7 @@
     OBSERVE_NODE,
     FILL_BUFFER,
     EMPTY_BUFFER,
+    GET_EXTENSION_INDEX,
     CREATE_RENDERER,
     OBSERVER_ON_MSG,
     RENDERER_RENDER,
@@ -147,6 +150,41 @@
         return reply.readInt32();
     }
 
+    virtual status_t get_config(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(index);
+        data.writeInt32(size);
+        data.write(params, size);
+        remote()->transact(GET_CONFIG, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err != OK) {
+            return err;
+        }
+
+        reply.read(params, size);
+
+        return OK;
+    }
+
+    virtual status_t set_config(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(index);
+        data.writeInt32(size);
+        data.write(params, size);
+        remote()->transact(SET_CONFIG, data, &reply);
+
+        return reply.readInt32();
+    }
+
     virtual status_t use_buffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer) {
@@ -260,6 +298,27 @@
         remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
+    virtual status_t get_extension_index(
+            node_id node,
+            const char *parameter_name,
+            OMX_INDEXTYPE *index) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeCString(parameter_name);
+
+        remote()->transact(GET_EXTENSION_INDEX, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err == OK) {
+            *index = static_cast<OMX_INDEXTYPE>(reply.readInt32());
+        } else {
+            *index = OMX_IndexComponentStartUnused;
+        }
+
+        return err;
+    }
+
     virtual sp<IOMXRenderer> createRenderer(
             const sp<ISurface> &surface,
             const char *componentName,
@@ -394,6 +453,48 @@
             return NO_ERROR;
         }
 
+        case GET_CONFIG:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+            size_t size = data.readInt32();
+
+            // XXX I am not happy with this but Parcel::readInplace didn't work.
+            void *params = malloc(size);
+            data.read(params, size);
+
+            status_t err = get_config(node, index, params, size);
+
+            reply->writeInt32(err);
+
+            if (err == OK) {
+                reply->write(params, size);
+            }
+
+            free(params);
+            params = NULL;
+
+            return NO_ERROR;
+        }
+
+        case SET_CONFIG:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+            size_t size = data.readInt32();
+            void *params = const_cast<void *>(data.readInplace(size));
+
+            reply->writeInt32(set_config(node, index, params, size));
+
+            return NO_ERROR;
+        }
+
         case USE_BUFFER:
         {
             CHECK_INTERFACE(IOMX, data, reply);
@@ -508,6 +609,25 @@
             return NO_ERROR;
         }
 
+        case GET_EXTENSION_INDEX:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            const char *parameter_name = data.readCString();
+            
+            OMX_INDEXTYPE index;
+            status_t err = get_extension_index(node, parameter_name, &index);
+
+            reply->writeInt32(err);
+
+            if (err == OK) {
+                reply->writeInt32(index);
+            }
+
+            return OK;
+        }
+
         case CREATE_RENDERER:
         {
             CHECK_INTERFACE(IOMX, data, reply);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 00ba1ac..0c40b91 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -17,6 +17,7 @@
         MediaSource.cpp           \
         MetaData.cpp              \
         MmapSource.cpp            \
+        OMXCodec.cpp              \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
         TimeSource.cpp            \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index d547556..e8571b5 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -28,8 +28,7 @@
 namespace android {
 
 AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
-    : mSource(NULL),
-      mAudioTrack(NULL),
+    : mAudioTrack(NULL),
       mInputBuffer(NULL),
       mSampleRate(0),
       mLatencyUs(0),
@@ -48,7 +47,7 @@
     }
 }
 
-void AudioPlayer::setSource(MediaSource *source) {
+void AudioPlayer::setSource(const sp<MediaSource> &source) {
     assert(mSource == NULL);
     mSource = source;
 }
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
index 0fd71d5..d599cd5 100644
--- a/media/libstagefright/CachingDataSource.cpp
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -25,7 +25,7 @@
 namespace android {
 
 CachingDataSource::CachingDataSource(
-        DataSource *source, size_t pageSize, int numPages)
+        const sp<DataSource> &source, size_t pageSize, int numPages)
     : mSource(source),
       mData(malloc(pageSize * numPages)),
       mPageSize(pageSize),
@@ -61,9 +61,6 @@
 
     free(mData);
     mData = NULL;
-
-    delete mSource;
-    mSource = NULL;
 }
 
 status_t CachingDataSource::InitCheck() const {
@@ -78,7 +75,7 @@
         Page *page = mFirst;
         while (page != NULL) {
             if (page->mOffset >= 0 && offset >= page->mOffset
-                && offset < page->mOffset + page->mLength) {
+                && offset < page->mOffset + (off_t)page->mLength) {
                 break;
             }
             page = page->mNext;
@@ -102,7 +99,7 @@
                 return n;
             }
 
-            if (offset >= page->mOffset + page->mLength) {
+            if (offset >= page->mOffset + (off_t)page->mLength) {
                 break;
             }
         } else {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 6e6b43d..02a276b 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -22,6 +22,19 @@
 
 namespace android {
 
+bool DataSource::getUInt16(off_t offset, uint16_t *x) {
+    *x = 0;
+
+    uint8_t byte[2];
+    if (read_at(offset, byte, 2) != 2) {
+        return false;
+    }
+
+    *x = (byte[0] << 8) | byte[1];
+
+    return true;
+}
+
 status_t DataSource::getSize(off_t *size) {
     *size = 0;
 
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 01cb2d9..44258ba 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -165,7 +165,7 @@
 }
 
 static bool Resync(
-        DataSource *source, uint32_t match_header,
+        const sp<DataSource> &source, uint32_t match_header,
         off_t *inout_pos, uint32_t *out_header) {
     // Everything must match except for
     // protection, bitrate, padding, private bits and mode extension.
@@ -281,11 +281,9 @@
 class MP3Source : public MediaSource {
 public:
     MP3Source(
-            const sp<MetaData> &meta, DataSource *source,
+            const sp<MetaData> &meta, const sp<DataSource> &source,
             off_t first_frame_pos, uint32_t fixed_header);
 
-    virtual ~MP3Source();
-
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
 
@@ -294,9 +292,12 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
+protected:
+    virtual ~MP3Source();
+
 private:
     sp<MetaData> mMeta;
-    DataSource *mDataSource;
+    sp<DataSource> mDataSource;
     off_t mFirstFramePos;
     uint32_t mFixedHeader;
     off_t mCurrentPos;
@@ -309,7 +310,7 @@
     MP3Source &operator=(const MP3Source &);
 };
 
-MP3Extractor::MP3Extractor(DataSource *source)
+MP3Extractor::MP3Extractor(const sp<DataSource> &source)
     : mDataSource(source),
       mFirstFramePos(-1),
       mFixedHeader(0) {
@@ -347,28 +348,22 @@
 }
 
 MP3Extractor::~MP3Extractor() {
-    delete mDataSource;
-    mDataSource = NULL;
 }
 
-status_t MP3Extractor::countTracks(int *num_tracks) {
-    *num_tracks = mFirstFramePos < 0 ? 0 : 1;
-
-    return OK;
+size_t MP3Extractor::countTracks() {
+    return (mFirstFramePos < 0) ? 0 : 1;
 }
 
-status_t MP3Extractor::getTrack(int index, MediaSource **source) {
+sp<MediaSource> MP3Extractor::getTrack(size_t index) {
     if (mFirstFramePos < 0 || index != 0) {
-        return ERROR_OUT_OF_RANGE;
+        return NULL;
     }
 
-    *source = new MP3Source(
+    return new MP3Source(
             mMeta, mDataSource, mFirstFramePos, mFixedHeader);
-
-    return OK;
 }
 
-sp<MetaData> MP3Extractor::getTrackMetaData(int index) {
+sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
     if (mFirstFramePos < 0 || index != 0) {
         return NULL;
     }
@@ -379,7 +374,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 MP3Source::MP3Source(
-        const sp<MetaData> &meta, DataSource *source,
+        const sp<MetaData> &meta, const sp<DataSource> &source,
         off_t first_frame_pos, uint32_t fixed_header)
     : mMeta(meta),
       mDataSource(source),
@@ -509,7 +504,8 @@
     return OK;
 }
 
-bool SniffMP3(DataSource *source, String8 *mimeType, float *confidence) {
+bool SniffMP3(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
     off_t pos = 0;
     uint32_t header;
     if (!Resync(source, 0, &pos, &header)) {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 4c883c6..662d5fb 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -42,10 +42,9 @@
 class MPEG4Source : public MediaSource {
 public:
     // Caller retains ownership of both "dataSource" and "sampleTable".
-    MPEG4Source(const sp<MetaData> &format, DataSource *dataSource,
-                SampleTable *sampleTable);
-
-    virtual ~MPEG4Source();
+    MPEG4Source(const sp<MetaData> &format,
+                const sp<DataSource> &dataSource,
+                const sp<SampleTable> &sampleTable);
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -55,11 +54,14 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
+protected:
+    virtual ~MPEG4Source();
+
 private:
     sp<MetaData> mFormat;
-    DataSource *mDataSource;
+    sp<DataSource> mDataSource;
     int32_t mTimescale;
-    SampleTable *mSampleTable;
+    sp<SampleTable> mSampleTable;
     uint32_t mCurrentSampleIndex;
 
     bool mIsAVC;
@@ -141,7 +143,7 @@
     }
 }
 
-MPEG4Extractor::MPEG4Extractor(DataSource *source)
+MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
     : mDataSource(source),
       mHaveMetadata(false),
       mFirstTrack(NULL),
@@ -153,39 +155,29 @@
     while (track) {
         Track *next = track->next;
 
-        delete track->sampleTable;
-        track->sampleTable = NULL;
-
         delete track;
         track = next;
     }
     mFirstTrack = mLastTrack = NULL;
-
-    delete mDataSource;
-    mDataSource = NULL;
 }
 
-status_t MPEG4Extractor::countTracks(int *num_tracks) {
+size_t MPEG4Extractor::countTracks() {
     status_t err;
     if ((err = readMetaData()) != OK) {
-        return err;
+        return 0;
     }
 
-    *num_tracks = 0;
+    size_t n = 0;
     Track *track = mFirstTrack;
     while (track) {
-        ++*num_tracks;
+        ++n;
         track = track->next;
     }
 
-    return OK;
+    return n;
 }
 
-sp<MetaData> MPEG4Extractor::getTrackMetaData(int index) {
-    if (index < 0) {
-        return NULL;
-    }
-
+sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
     status_t err;
     if ((err = readMetaData()) != OK) {
         return NULL;
@@ -701,39 +693,32 @@
     return OK;
 }
 
-status_t MPEG4Extractor::getTrack(int index, MediaSource **source) {
-    *source = NULL;
-
-    if (index < 0) {
-        return ERROR_OUT_OF_RANGE;
-    }
-
+sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
     status_t err;
     if ((err = readMetaData()) != OK) {
-        return err;
+        return NULL;
     }
 
     Track *track = mFirstTrack;
     while (index > 0) {
         if (track == NULL) {
-            return ERROR_OUT_OF_RANGE;
+            return NULL;
         }
 
         track = track->next;
         --index;
     }
 
-    *source = new MPEG4Source(
+    return new MPEG4Source(
             track->meta, mDataSource, track->sampleTable);
-
-    return OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 MPEG4Source::MPEG4Source(
         const sp<MetaData> &format,
-        DataSource *dataSource, SampleTable *sampleTable)
+        const sp<DataSource> &dataSource,
+        const sp<SampleTable> &sampleTable)
     : mFormat(format),
       mDataSource(dataSource),
       mTimescale(0),
@@ -935,7 +920,8 @@
     return OK;
 }
 
-bool SniffMPEG4(DataSource *source, String8 *mimeType, float *confidence) {
+bool SniffMPEG4(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
     uint8_t header[8];
 
     ssize_t n = source->read_at(4, header, sizeof(header));
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index b53bb29..10c4629 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -32,7 +32,8 @@
 
 class MPEG4Writer::Track {
 public:
-    Track(MPEG4Writer *owner, const sp<MetaData> &meta, MediaSource *source);
+    Track(MPEG4Writer *owner,
+          const sp<MetaData> &meta, const sp<MediaSource> &source);
     ~Track();
 
     void start();
@@ -44,7 +45,7 @@
 private:
     MPEG4Writer *mOwner;
     sp<MetaData> mMeta;
-    MediaSource *mSource;
+    sp<MediaSource> mSource;
     volatile bool mDone;
 
     pthread_t mThread;
@@ -83,7 +84,8 @@
     mTracks.clear();
 }
 
-void MPEG4Writer::addSource(const sp<MetaData> &meta, MediaSource *source) {
+void MPEG4Writer::addSource(
+        const sp<MetaData> &meta, const sp<MediaSource> &source) {
     Track *track = new Track(this, meta, source);
     mTracks.push_back(track);
 }
@@ -255,7 +257,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 MPEG4Writer::Track::Track(
-        MPEG4Writer *owner, const sp<MetaData> &meta, MediaSource *source)
+        MPEG4Writer *owner,
+        const sp<MetaData> &meta, const sp<MediaSource> &source)
     : mOwner(owner),
       mMeta(meta),
       mSource(source),
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index bc66794..5f78e12 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -27,7 +27,8 @@
 namespace android {
 
 // static
-MediaExtractor *MediaExtractor::Create(DataSource *source, const char *mime) {
+sp<MediaExtractor> MediaExtractor::Create(
+        const sp<DataSource> &source, const char *mime) {
     String8 tmp;
     if (mime == NULL) {
         float confidence;
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index f2e62f5..2d7b628 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -34,32 +34,28 @@
 #include <media/stagefright/MediaPlayerImpl.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXCodec.h>
 #include <media/stagefright/OMXDecoder.h>
 #include <media/stagefright/ShoutcastSource.h>
 #include <media/stagefright/TimeSource.h>
 #include <ui/PixelFormat.h>
 #include <ui/Surface.h>
 
+#define USE_OMX_CODEC   1
+
 namespace android {
 
 MediaPlayerImpl::MediaPlayerImpl(const char *uri)
     : mInitCheck(NO_INIT),
-      mExtractor(NULL), 
       mTimeSource(NULL),
-      mAudioSource(NULL),
-      mAudioDecoder(NULL),
       mAudioPlayer(NULL),
-      mVideoSource(NULL),
-      mVideoDecoder(NULL),
       mVideoWidth(0),
       mVideoHeight(0),
       mVideoPosition(0),
       mDuration(0),
       mPlaying(false),
       mPaused(false),
-      mSeeking(false),
-      mFrameSize(0),
-      mUseSoftwareColorConversion(false) {
+      mSeeking(false) {
     LOGI("MediaPlayerImpl(%s)", uri);
     DataSource::RegisterDefaultSniffers();
 
@@ -78,7 +74,7 @@
         mVideoDecoder = CameraSource::Create();
 #endif
     } else {
-        DataSource *source = NULL;
+        sp<DataSource> source;
         if (!strncasecmp("file://", uri, 7)) {
             source = new MmapSource(uri + 7);
         } else if (!strncasecmp("http://", uri, 7)) {
@@ -103,22 +99,15 @@
 
 MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
     : mInitCheck(NO_INIT),
-      mExtractor(NULL), 
       mTimeSource(NULL),
-      mAudioSource(NULL),
-      mAudioDecoder(NULL),
       mAudioPlayer(NULL),
-      mVideoSource(NULL),
-      mVideoDecoder(NULL),
       mVideoWidth(0),
       mVideoHeight(0),
       mVideoPosition(0),
       mDuration(0),
       mPlaying(false),
       mPaused(false),
-      mSeeking(false),
-      mFrameSize(0),
-      mUseSoftwareColorConversion(false) {
+      mSeeking(false) {
     LOGI("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
     DataSource::RegisterDefaultSniffers();
 
@@ -148,23 +137,6 @@
     stop();
     setSurface(NULL);
 
-    LOGV("Shutting down audio.");
-    delete mAudioDecoder;
-    mAudioDecoder = NULL;
-
-    delete mAudioSource;
-    mAudioSource = NULL;
-
-    LOGV("Shutting down video.");
-    delete mVideoDecoder;
-    mVideoDecoder = NULL;
-
-    delete mVideoSource;
-    mVideoSource = NULL;
-
-    delete mExtractor;
-    mExtractor = NULL;
-
     if (mInitCheck == OK) {
         mClient.disconnect();
     }
@@ -384,12 +356,11 @@
 
 void MediaPlayerImpl::init() {
     if (mExtractor != NULL) {
-        int num_tracks;
-        assert(mExtractor->countTracks(&num_tracks) == OK);
+        size_t num_tracks = mExtractor->countTracks();
 
         mDuration = 0;
 
-        for (int i = 0; i < num_tracks; ++i) {
+        for (size_t i = 0; i < num_tracks; ++i) {
             const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
             assert(meta != NULL);
 
@@ -411,10 +382,7 @@
                 continue;
             }
 
-            MediaSource *source;
-            if (mExtractor->getTrack(i, &source) != OK) {
-                continue;
-            }
+            sp<MediaSource> source = mExtractor->getTrack(i);
 
             int32_t units, scale;
             if (meta->findInt32(kKeyDuration, &units)
@@ -434,17 +402,22 @@
     }
 }
 
-void MediaPlayerImpl::setAudioSource(MediaSource *source) {
+void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
     LOGI("setAudioSource");
     mAudioSource = source;
 
     sp<MetaData> meta = source->getFormat();
 
-    mAudioDecoder = OMXDecoder::Create(&mClient, meta);
-    mAudioDecoder->setSource(source);
+#if !USE_OMX_CODEC
+    mAudioDecoder = OMXDecoder::Create(
+            &mClient, meta, false /* createEncoder */, source);
+#else
+    mAudioDecoder = OMXCodec::Create(
+            mClient.interface(), meta, false /* createEncoder */, source);
+#endif
 }
 
-void MediaPlayerImpl::setVideoSource(MediaSource *source) {
+void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
     LOGI("setVideoSource");
     mVideoSource = source;
 
@@ -456,8 +429,13 @@
     success = meta->findInt32(kKeyHeight, &mVideoHeight);
     assert(success);
 
-    mVideoDecoder = OMXDecoder::Create(&mClient, meta);
-    ((OMXDecoder *)mVideoDecoder)->setSource(source);
+#if !USE_OMX_CODEC
+    mVideoDecoder = OMXDecoder::Create(
+            &mClient, meta, false /* createEncoder */, source);
+#else
+    mVideoDecoder = OMXCodec::Create(
+            mClient.interface(), meta, false /* createEncoder */, source);
+#endif
 
     if (mISurface.get() != NULL || mSurface.get() != NULL) {
         depopulateISurface();
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 3e7cf3c..5423ffa 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -132,7 +132,7 @@
     }
 
     Mutex::Autolock autoLock(mLock);
-    ssize_t index = mObservers.indexOfKey(msg.u.buffer_data.node);
+    ssize_t index = mObservers.indexOfKey(msg.node);
 
     if (index >= 0) {
         mObservers.editValueAt(index)->postMessage(msg);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
new file mode 100644
index 0000000..35d599c
--- /dev/null
+++ b/media/libstagefright/OMXCodec.cpp
@@ -0,0 +1,1962 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "OMXCodec"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <binder/ProcessState.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/ESDS.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXCodec.h>
+#include <utils/Vector.h>
+
+#include <OMX_Audio.h>
+#include <OMX_Component.h>
+
+namespace android {
+
+struct CodecInfo {
+    const char *mime;
+    const char *codec;
+};
+
+static const CodecInfo kDecoderInfo[] = {
+    { "image/jpeg", "OMX.TI.JPEG.decode" },
+    { "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" },
+};
+
+static const CodecInfo kEncoderInfo[] = {
+    { "audio/3gpp", "OMX.TI.AMR.encode" },
+    { "audio/3gpp", "OMX.PV.amrencnb" },
+    { "audio/mp4a-latm", "OMX.TI.AAC.encode" },
+    { "audio/mp4a-latm", "OMX.PV.aacenc" },
+    { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
+    { "video/mp4v-es", "OMX.TI.Video.encoder" },
+    { "video/mp4v-es", "OMX.PV.mpeg4enc" },
+    { "video/3gpp", "OMX.qcom.video.encoder.h263" },
+    { "video/3gpp", "OMX.TI.Video.encoder" },
+    { "video/3gpp", "OMX.PV.h263enc" },
+    { "video/avc", "OMX.TI.Video.encoder" },
+    { "video/avc", "OMX.PV.avcenc" },
+};
+
+struct OMXCodecObserver : public BnOMXObserver {
+    OMXCodecObserver(const wp<OMXCodec> &target)
+        : mTarget(target) {
+    }
+
+    // from IOMXObserver
+    virtual void on_message(const omx_message &msg) {
+        sp<OMXCodec> codec = mTarget.promote();
+
+        if (codec.get() != NULL) {
+            codec->on_message(msg);
+        }
+    }
+
+protected:
+    virtual ~OMXCodecObserver() {}
+
+private:
+    wp<OMXCodec> mTarget;
+
+    OMXCodecObserver(const OMXCodecObserver &);
+    OMXCodecObserver &operator=(const OMXCodecObserver &);
+};
+
+static const char *GetCodec(const CodecInfo *info, size_t numInfos,
+                            const char *mime, int index) {
+    CHECK(index >= 0);
+    for(size_t i = 0; i < numInfos; ++i) {
+        if (!strcasecmp(mime, info[i].mime)) {
+            if (index == 0) {
+                return info[i].codec;
+            }
+
+            --index;
+        }
+    }
+
+    return NULL;
+}
+
+// static
+sp<OMXCodec> OMXCodec::Create(
+        const sp<IOMX> &omx,
+        const sp<MetaData> &meta, bool createEncoder,
+        const sp<MediaSource> &source) {
+    const char *mime;
+    bool success = meta->findCString(kKeyMIMEType, &mime);
+    CHECK(success);
+
+    const char *componentName = NULL;
+    IOMX::node_id node = 0;
+    for (int index = 0;; ++index) {
+        if (createEncoder) {
+            componentName = GetCodec(
+                    kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+                    mime, index);
+        } else {
+            componentName = GetCodec(
+                    kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+                    mime, index);
+        }
+
+        if (!componentName) {
+            return NULL;
+        }
+
+        LOGV("Attempting to allocate OMX node '%s'", componentName);
+
+        status_t err = omx->allocate_node(componentName, &node);
+        if (err == OK) {
+            break;
+        }
+    }
+
+    uint32_t quirks = 0;
+    if (!strcmp(componentName, "OMX.PV.avcdec")) {
+        quirks |= kWantsRawNALFrames;
+    }
+    if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
+        quirks |= kNeedsFlushBeforeDisable;
+    }
+    if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
+        quirks |= kNeedsFlushBeforeDisable;
+    }
+    if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
+        quirks |= kRequiresLoadedToIdleAfterAllocation;
+        quirks |= kRequiresAllocateBufferOnInputPorts;
+    }
+
+    sp<OMXCodec> codec = new OMXCodec(
+            omx, node, quirks, createEncoder, mime, componentName,
+            source);
+
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (meta->findData(kKeyESDS, &type, &data, &size)) {
+        ESDS esds((const char *)data, size);
+        CHECK_EQ(esds.InitCheck(), OK);
+
+        const void *codec_specific_data;
+        size_t codec_specific_data_size;
+        esds.getCodecSpecificInfo(
+                &codec_specific_data, &codec_specific_data_size);
+
+        printf("found codec-specific data of size %d\n",
+               codec_specific_data_size);
+
+        codec->addCodecSpecificData(
+                codec_specific_data, codec_specific_data_size);
+    } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+        printf("found avcc of size %d\n", size);
+
+        const uint8_t *ptr = (const uint8_t *)data + 6;
+        size -= 6;
+        while (size >= 2) {
+            size_t length = ptr[0] << 8 | ptr[1];
+
+            ptr += 2;
+            size -= 2;
+
+            // printf("length = %d, size = %d\n", length, size);
+
+            CHECK(size >= length);
+
+            codec->addCodecSpecificData(ptr, length);
+
+            ptr += length;
+            size -= length;
+
+            if (size <= 1) {
+                break;
+            }
+
+            ptr++;  // XXX skip trailing 0x01 byte???
+            --size;
+        }
+    }
+
+    if (!strcasecmp("audio/3gpp", mime)) {
+        codec->setAMRFormat();
+    }
+    if (!createEncoder && !strcasecmp("audio/mp4a-latm", mime)) {
+        codec->setAACFormat();
+    }
+    if (!strncasecmp(mime, "video/", 6)) {
+        int32_t width, height;
+        bool success = meta->findInt32(kKeyWidth, &width);
+        success = success && meta->findInt32(kKeyHeight, &height);
+        assert(success);
+
+        if (createEncoder) {
+            codec->setVideoInputFormat(mime, width, height);
+        } else {
+            codec->setVideoOutputFormat(mime, width, height);
+        }
+    }
+    if (!strcasecmp(mime, "image/jpeg")
+        && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
+        OMX_COLOR_FORMATTYPE format =
+            OMX_COLOR_Format32bitARGB8888;
+            // OMX_COLOR_FormatYUV420PackedPlanar;
+            // OMX_COLOR_FormatCbYCrY;
+            // OMX_COLOR_FormatYUV411Planar;
+
+        int32_t width, height;
+        bool success = meta->findInt32(kKeyWidth, &width);
+        success = success && meta->findInt32(kKeyHeight, &height);
+        assert(success);
+
+        codec->setImageOutputFormat(format, width, height);
+    }
+
+    codec->initOutputFormat(meta);
+
+    return codec;
+}
+
+status_t OMXCodec::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 1
+        LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+             portIndex,
+             index, format.eCompressionFormat, format.eColorFormat);
+#endif
+
+        if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
+            if (portIndex == kPortIndexInput
+                    && colorFormat == format.eColorFormat) {
+                // eCompressionFormat does not seem right.
+                found = true;
+                break;
+            }
+            if (portIndex == kPortIndexOutput
+                    && compressionFormat == format.eCompressionFormat) {
+                // eColorFormat does not seem right.
+                found = true;
+                break;
+            }
+        }
+
+        if (format.eCompressionFormat == compressionFormat
+            && format.eColorFormat == colorFormat) {
+            found = true;
+            break;
+        }
+
+        ++index;
+    }
+
+    if (!found) {
+        return UNKNOWN_ERROR;
+    }
+
+    LOGI("found a match.");
+    status_t err = mOMX->set_parameter(
+            mNode, OMX_IndexParamVideoPortFormat,
+            &format, sizeof(format));
+
+    return err;
+}
+
+void OMXCodec::setVideoInputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
+    LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
+
+    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 {
+        LOGE("Not a supported video mime type: %s", mime);
+        CHECK(!"Should not be here. Not a supported video mime type.");
+    }
+
+    OMX_COLOR_FORMATTYPE colorFormat =
+        0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
+
+    if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
+        colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+    }
+
+    setVideoPortFormatType(
+            kPortIndexInput, OMX_VIDEO_CodingUnused,
+            colorFormat);
+
+    setVideoPortFormatType(
+            kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    CHECK_EQ(err, OK);
+    CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    video_def->eCompressionFormat = compressionFormat;
+    video_def->eColorFormat = OMX_COLOR_FormatUnused;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    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));
+    CHECK_EQ(err, OK);
+
+    def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
+    LOGI("setting nBufferSize = %ld", def.nBufferSize);
+
+    CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+    video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
+    video_def->eColorFormat = colorFormat;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setVideoOutputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
+    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+    // 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 (!strcmp("OMX.TI.Video.Decoder", mComponentName)
+        && !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));
+        CHECK_EQ(err, OK);
+    }
+
+    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 {
+        LOGE("Not a supported video mime type: %s", mime);
+        CHECK(!"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));
+        CHECK_EQ(err, OK);
+        CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
+
+        static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+        CHECK(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));
+        CHECK_EQ(err, OK);
+    }
+#endif
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexInput;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    CHECK_EQ(err, OK);
+
+#if 1
+    // XXX Need a (much) better heuristic to compute input buffer sizes.
+    const size_t X = 64 * 1024;
+    if (def.nBufferSize < X) {
+        def.nBufferSize = X;
+    }
+#endif
+
+    CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    video_def->eColorFormat = OMX_COLOR_FormatUnused;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexOutput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+    CHECK_EQ(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;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+}
+
+
+OMXCodec::OMXCodec(
+        const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+        bool isEncoder, 
+        const char *mime,
+        const char *componentName,
+        const sp<MediaSource> &source)
+    : mOMX(omx),
+      mNode(node),
+      mQuirks(quirks),
+      mIsEncoder(isEncoder),
+      mMIME(strdup(mime)),
+      mComponentName(strdup(componentName)),
+      mSource(source),
+      mCodecSpecificDataIndex(0),
+      mDealer(new MemoryDealer(5 * 1024 * 1024)),
+      mState(LOADED),
+      mSignalledEOS(false),
+      mNoMoreOutputData(false),
+      mSeekTimeUs(-1) {
+    mPortStatus[kPortIndexInput] = ENABLED;
+    mPortStatus[kPortIndexOutput] = ENABLED;
+
+    mObserver = new OMXCodecObserver(this);
+    mOMX->observe_node(mNode, mObserver);
+}
+
+OMXCodec::~OMXCodec() {
+    CHECK_EQ(mState, LOADED);
+
+    status_t err = mOMX->observe_node(mNode, NULL);
+    CHECK_EQ(err, OK);
+
+    err = mOMX->free_node(mNode);
+    CHECK_EQ(err, OK);
+
+    mNode = NULL;
+    setState(DEAD);
+
+    clearCodecSpecificData();
+
+    free(mComponentName);
+    mComponentName = NULL;
+    
+    free(mMIME);
+    mMIME = NULL;
+}
+
+status_t OMXCodec::init() {
+    Mutex::Autolock autoLock(mLock);
+
+    CHECK_EQ(mState, LOADED);
+
+    status_t err;
+    if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
+        err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+        CHECK_EQ(err, OK);
+
+        setState(LOADED_TO_IDLE);
+    }
+
+    err = allocateBuffers();
+    CHECK_EQ(err, OK);
+
+    if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
+        err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+        CHECK_EQ(err, OK);
+
+        setState(LOADED_TO_IDLE);
+    }
+
+    while (mState != EXECUTING && mState != ERROR) {
+        mAsyncCompletion.wait(mLock);
+    }
+
+    return mState == ERROR ? UNKNOWN_ERROR : OK;
+}
+
+// static
+bool OMXCodec::isIntermediateState(State state) {
+    return state == LOADED_TO_IDLE
+        || state == IDLE_TO_EXECUTING
+        || state == EXECUTING_TO_IDLE
+        || state == IDLE_TO_LOADED
+        || state == RECONFIGURING;
+}
+
+status_t OMXCodec::allocateBuffers() {
+    status_t err = allocateBuffersOnPort(kPortIndexInput);
+
+    if (err != OK) {
+        return err;
+    }
+
+    return allocateBuffersOnPort(kPortIndexOutput);
+}
+
+status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nVersion.s.nRevision = 0;
+    def.nVersion.s.nStep = 0;
+    def.nPortIndex = portIndex;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    if (err != OK) {
+        return err;
+    }
+
+    for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+        sp<IMemory> mem = mDealer->allocate(def.nBufferSize);
+        CHECK(mem.get() != NULL);
+
+        IOMX::buffer_id buffer;
+        if (portIndex == kPortIndexInput
+                && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+            err = mOMX->allocate_buffer_with_backup(
+                    mNode, portIndex, mem, &buffer);
+        } else {
+            err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
+        }
+
+        if (err != OK) {
+            LOGE("allocate_buffer_with_backup failed");
+            return err;
+        }
+
+        BufferInfo info;
+        info.mBuffer = buffer;
+        info.mOwnedByComponent = false;
+        info.mMem = mem;
+        info.mMediaBuffer = NULL;
+
+        if (portIndex == kPortIndexOutput) {
+            info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
+            info.mMediaBuffer->setObserver(this);
+        }
+
+        mPortBuffers[portIndex].push(info);
+
+        LOGV("allocated buffer %p on %s port", buffer,
+             portIndex == kPortIndexInput ? "input" : "output");
+    }
+
+    dumpPortStatus(portIndex);
+
+    return OK;
+}
+
+void OMXCodec::on_message(const omx_message &msg) {
+    Mutex::Autolock autoLock(mLock);
+
+    switch (msg.type) {
+        case omx_message::EVENT:
+        {
+            onEvent(
+                 msg.u.event_data.event, msg.u.event_data.data1,
+                 msg.u.event_data.data2);
+
+            break;
+        }
+
+        case omx_message::EMPTY_BUFFER_DONE:
+        {
+            IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+
+            LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
+
+            Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+            size_t i = 0;
+            while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
+                ++i;
+            }
+
+            CHECK(i < buffers->size());
+            if (!(*buffers)[i].mOwnedByComponent) {
+                LOGW("We already own input buffer %p, yet received "
+                     "an EMPTY_BUFFER_DONE.", buffer);
+            }
+
+            buffers->editItemAt(i).mOwnedByComponent = false;
+
+            if (mPortStatus[kPortIndexInput] == DISABLING) {
+                LOGV("Port is disabled, freeing buffer %p", buffer);
+
+                status_t err =
+                    mOMX->free_buffer(mNode, kPortIndexInput, buffer);
+                CHECK_EQ(err, OK);
+
+                buffers->removeAt(i);
+            } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
+                CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
+                drainInputBuffer(&buffers->editItemAt(i));
+            }
+
+            break;
+        }
+
+        case omx_message::FILL_BUFFER_DONE:
+        {
+            IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+            OMX_U32 flags = msg.u.extended_buffer_data.flags;
+
+            LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
+                 buffer,
+                 msg.u.extended_buffer_data.range_length,
+                 flags);
+
+            LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
+                 msg.u.extended_buffer_data.timestamp,
+                 msg.u.extended_buffer_data.timestamp / 1E6);
+
+            Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+            size_t i = 0;
+            while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
+                ++i;
+            }
+
+            CHECK(i < buffers->size());
+            BufferInfo *info = &buffers->editItemAt(i);
+
+            if (!info->mOwnedByComponent) {
+                LOGW("We already own output buffer %p, yet received "
+                     "a FILL_BUFFER_DONE.", buffer);
+            }
+
+            info->mOwnedByComponent = false;
+
+            if (mPortStatus[kPortIndexOutput] == DISABLING) {
+                LOGV("Port is disabled, freeing buffer %p", buffer);
+
+                status_t err =
+                    mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
+                CHECK_EQ(err, OK);
+
+                buffers->removeAt(i);
+            } else if (flags & OMX_BUFFERFLAG_EOS) {
+                LOGV("No more output data.");
+                mNoMoreOutputData = true;
+                mBufferFilled.signal();
+            } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
+                CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
+                
+                MediaBuffer *buffer = info->mMediaBuffer;
+
+                buffer->set_range(
+                        msg.u.extended_buffer_data.range_offset,
+                        msg.u.extended_buffer_data.range_length);
+
+                buffer->meta_data()->clear();
+
+                buffer->meta_data()->setInt32(
+                        kKeyTimeUnits,
+                        (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+
+                buffer->meta_data()->setInt32(
+                        kKeyTimeScale, 1000);
+
+                if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
+                    buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
+                }
+
+                buffer->meta_data()->setPointer(
+                        kKeyPlatformPrivate,
+                        msg.u.extended_buffer_data.platform_private);
+
+                buffer->meta_data()->setPointer(
+                        kKeyBufferID,
+                        msg.u.extended_buffer_data.buffer);
+
+                mFilledBuffers.push_back(i);
+                mBufferFilled.signal();
+            }
+
+            break;
+        }
+
+        default:
+        {
+            CHECK(!"should not be here.");
+            break;
+        }
+    }
+}
+
+void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+    switch (event) {
+        case OMX_EventCmdComplete:
+        {
+            onCmdComplete((OMX_COMMANDTYPE)data1, data2);
+            break;
+        }
+
+        case OMX_EventError:
+        {
+            LOGE("ERROR(%ld, %ld)", data1, data2);
+
+            setState(ERROR);
+            break;
+        }
+
+        case OMX_EventPortSettingsChanged:
+        {
+            onPortSettingsChanged(data1);
+            break;
+        }
+
+        case OMX_EventBufferFlag:
+        {
+            LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
+
+            if (data1 == kPortIndexOutput) {
+                mNoMoreOutputData = true;
+            }
+            break;
+        }
+
+        default:
+        {
+            LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
+            break;
+        }
+    }
+}
+
+void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
+    switch (cmd) {
+        case OMX_CommandStateSet:
+        {
+            onStateChange((OMX_STATETYPE)data);
+            break;
+        }
+
+        case OMX_CommandPortDisable:
+        {
+            OMX_U32 portIndex = data;
+            LOGV("PORT_DISABLED(%ld)", portIndex);
+
+            CHECK(mState == EXECUTING || mState == RECONFIGURING);
+            CHECK_EQ(mPortStatus[portIndex], DISABLING);
+            CHECK_EQ(mPortBuffers[portIndex].size(), 0);
+
+            mPortStatus[portIndex] = DISABLED;
+
+            if (mState == RECONFIGURING) {
+                CHECK_EQ(portIndex, kPortIndexOutput);
+
+                enablePortAsync(portIndex);
+
+                status_t err = allocateBuffersOnPort(portIndex);
+                CHECK_EQ(err, OK);
+            }
+            break;
+        }
+
+        case OMX_CommandPortEnable:
+        {
+            OMX_U32 portIndex = data;
+            LOGV("PORT_ENABLED(%ld)", portIndex);
+
+            CHECK(mState == EXECUTING || mState == RECONFIGURING);
+            CHECK_EQ(mPortStatus[portIndex], ENABLING);
+
+            mPortStatus[portIndex] = ENABLED;
+
+            if (mState == RECONFIGURING) {
+                CHECK_EQ(portIndex, kPortIndexOutput);
+
+                setState(EXECUTING);
+
+                fillOutputBuffers();
+            }
+            break;
+        }
+
+        case OMX_CommandFlush:
+        {
+            OMX_U32 portIndex = data;
+
+            LOGV("FLUSH_DONE(%ld)", portIndex);
+
+            CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
+            mPortStatus[portIndex] = ENABLED;
+
+            CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
+                     mPortBuffers[portIndex].size());
+
+            if (mState == RECONFIGURING) {
+                CHECK_EQ(portIndex, kPortIndexOutput);
+
+                disablePortAsync(portIndex);
+            } else {
+                // We're flushing both ports in preparation for seeking.
+
+                if (mPortStatus[kPortIndexInput] == ENABLED
+                    && mPortStatus[kPortIndexOutput] == ENABLED) {
+                    LOGV("Finished flushing both ports, now continuing from"
+                         " seek-time.");
+
+                    drainInputBuffers();
+                    fillOutputBuffers();
+                }
+            }
+
+            break;
+        }
+
+        default:
+        {
+            LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
+            break;
+        }
+    }
+}
+
+void OMXCodec::onStateChange(OMX_STATETYPE newState) {
+    switch (newState) {
+        case OMX_StateIdle:
+        {
+            LOGV("Now Idle.");
+            if (mState == LOADED_TO_IDLE) {
+                status_t err = mOMX->send_command(
+                        mNode, OMX_CommandStateSet, OMX_StateExecuting);
+
+                CHECK_EQ(err, OK);
+
+                setState(IDLE_TO_EXECUTING);
+            } else {
+                CHECK_EQ(mState, EXECUTING_TO_IDLE);
+
+                CHECK_EQ(
+                    countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
+                    mPortBuffers[kPortIndexInput].size());
+
+                CHECK_EQ(
+                    countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
+                    mPortBuffers[kPortIndexOutput].size());
+
+                status_t err = mOMX->send_command(
+                        mNode, OMX_CommandStateSet, OMX_StateLoaded);
+
+                CHECK_EQ(err, OK);
+
+                err = freeBuffersOnPort(kPortIndexInput);
+                CHECK_EQ(err, OK);
+
+                err = freeBuffersOnPort(kPortIndexOutput);
+                CHECK_EQ(err, OK);
+
+                mPortStatus[kPortIndexInput] = ENABLED;
+                mPortStatus[kPortIndexOutput] = ENABLED;
+
+                setState(IDLE_TO_LOADED);
+            }
+            break;
+        }
+
+        case OMX_StateExecuting:
+        {
+            CHECK_EQ(mState, IDLE_TO_EXECUTING);
+
+            LOGV("Now Executing.");
+
+            setState(EXECUTING);
+
+            drainInputBuffers();
+            fillOutputBuffers();
+            break;
+        }
+
+        case OMX_StateLoaded:
+        {
+            CHECK_EQ(mState, IDLE_TO_LOADED);
+
+            LOGV("Now Loaded.");
+
+            setState(LOADED);
+            break;
+        }
+
+        default:
+        {
+            CHECK(!"should not be here.");
+            break;
+        }
+    }
+}
+
+// static
+size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
+    size_t n = 0;
+    for (size_t i = 0; i < buffers.size(); ++i) {
+        if (!buffers[i].mOwnedByComponent) {
+            ++n;
+        }
+    }
+
+    return n;
+}
+
+status_t OMXCodec::freeBuffersOnPort(
+        OMX_U32 portIndex, bool onlyThoseWeOwn) {
+    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
+
+    status_t stickyErr = OK;
+
+    for (size_t i = buffers->size(); i-- > 0;) {
+        BufferInfo *info = &buffers->editItemAt(i);
+
+        if (onlyThoseWeOwn && info->mOwnedByComponent) {
+            continue;
+        }
+
+        CHECK_EQ(info->mOwnedByComponent, false);
+
+        status_t err =
+            mOMX->free_buffer(mNode, portIndex, info->mBuffer);
+
+        if (err != OK) {
+            stickyErr = err;
+        }
+
+        if (info->mMediaBuffer != NULL) {
+            info->mMediaBuffer->setObserver(NULL);
+
+            // Make sure nobody but us owns this buffer at this point.
+            CHECK_EQ(info->mMediaBuffer->refcount(), 0);
+
+            info->mMediaBuffer->release();
+        }
+
+        buffers->removeAt(i);
+    }
+
+    CHECK(onlyThoseWeOwn || buffers->isEmpty());
+
+    return stickyErr;
+}
+
+void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
+    LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
+
+    CHECK_EQ(mState, EXECUTING);
+    CHECK_EQ(portIndex, kPortIndexOutput);
+    setState(RECONFIGURING);
+
+    if (mQuirks & kNeedsFlushBeforeDisable) {
+        flushPortAsync(portIndex);
+    } else {
+        disablePortAsync(portIndex);
+    }
+}
+
+void OMXCodec::flushPortAsync(OMX_U32 portIndex) {
+    CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+    CHECK_EQ(mPortStatus[portIndex], ENABLED);
+    mPortStatus[portIndex] = SHUTTING_DOWN;
+
+    status_t err =
+        mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
+    CHECK_EQ(err, OK);
+}
+
+void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
+    CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+    CHECK_EQ(mPortStatus[portIndex], ENABLED);
+    mPortStatus[portIndex] = DISABLING;
+
+    status_t err =
+        mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
+    CHECK_EQ(err, OK);
+
+    freeBuffersOnPort(portIndex, true);
+}
+
+void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
+    CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+    CHECK_EQ(mPortStatus[portIndex], DISABLED);
+    mPortStatus[portIndex] = ENABLING;
+
+    status_t err =
+        mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
+    CHECK_EQ(err, OK);
+}
+
+void OMXCodec::fillOutputBuffers() {
+    CHECK_EQ(mState, EXECUTING);
+
+    Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+    for (size_t i = 0; i < buffers->size(); ++i) {
+        fillOutputBuffer(&buffers->editItemAt(i));
+    }
+}
+
+void OMXCodec::drainInputBuffers() {
+    CHECK_EQ(mState, EXECUTING);
+
+    Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+    for (size_t i = 0; i < buffers->size(); ++i) {
+        drainInputBuffer(&buffers->editItemAt(i));
+    }
+}
+
+void OMXCodec::drainInputBuffer(BufferInfo *info) {
+    CHECK_EQ(info->mOwnedByComponent, false);
+
+    if (mSignalledEOS) {
+        return;
+    }
+
+    if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
+        const CodecSpecificData *specific =
+            mCodecSpecificData[mCodecSpecificDataIndex];
+
+        size_t size = specific->mSize;
+
+        if (!strcasecmp(mMIME, "video/avc")
+            && !(mQuirks & kWantsRawNALFrames)) {
+            static const uint8_t kNALStartCode[4] =
+                    { 0x00, 0x00, 0x00, 0x01 };
+
+            CHECK(info->mMem->size() >= specific->mSize + 4);
+
+            size += 4;
+
+            memcpy(info->mMem->pointer(), kNALStartCode, 4);
+            memcpy((uint8_t *)info->mMem->pointer() + 4,
+                   specific->mData, specific->mSize);
+        } else {
+            CHECK(info->mMem->size() >= specific->mSize);
+            memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
+        }
+
+        mOMX->empty_buffer(
+                mNode, info->mBuffer, 0, size,
+                OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
+                0);
+
+        info->mOwnedByComponent = true;
+
+        ++mCodecSpecificDataIndex;
+        return;
+    }
+
+    MediaBuffer *srcBuffer;
+    status_t err;
+    if (mSeekTimeUs >= 0) {
+        MediaSource::ReadOptions options;
+        options.setSeekTo(mSeekTimeUs);
+        mSeekTimeUs = -1;
+
+        err = mSource->read(&srcBuffer, &options);
+    } else {
+        err = mSource->read(&srcBuffer);
+    }
+
+    OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
+    OMX_TICKS timestamp = 0;
+    size_t srcLength = 0;
+
+    if (err != OK) {
+        LOGV("signalling end of input stream.");
+        flags |= OMX_BUFFERFLAG_EOS;
+
+        mSignalledEOS = true;
+    } else {
+        srcLength = srcBuffer->range_length();
+
+        if (info->mMem->size() < srcLength) {
+            LOGE("info->mMem->size() = %d, srcLength = %d",
+                 info->mMem->size(), srcLength);
+        }
+        CHECK(info->mMem->size() >= srcLength);
+        memcpy(info->mMem->pointer(),
+               (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
+               srcLength);
+
+        int32_t units, scale;
+        if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
+            && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
+            timestamp = ((OMX_TICKS)units * 1000000) / scale;
+
+            LOGV("Calling empty_buffer on buffer %p (length %d)",
+                 info->mBuffer, srcLength);
+            LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
+                 timestamp, timestamp / 1E6);
+        }
+    }
+
+    mOMX->empty_buffer(
+            mNode, info->mBuffer, 0, srcLength,
+            flags, timestamp);
+
+    info->mOwnedByComponent = true;
+
+    if (srcBuffer != NULL) {
+        srcBuffer->release();
+        srcBuffer = NULL;
+    }
+}
+
+void OMXCodec::fillOutputBuffer(BufferInfo *info) {
+    CHECK_EQ(info->mOwnedByComponent, false);
+
+    LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
+    mOMX->fill_buffer(mNode, info->mBuffer);
+
+    info->mOwnedByComponent = true;
+}
+
+void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
+    Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+    for (size_t i = 0; i < buffers->size(); ++i) {
+        if ((*buffers)[i].mBuffer == buffer) {
+            drainInputBuffer(&buffers->editItemAt(i));
+            return;
+        }
+    }
+
+    CHECK(!"should not be here.");
+}
+
+void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
+    Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+    for (size_t i = 0; i < buffers->size(); ++i) {
+        if ((*buffers)[i].mBuffer == buffer) {
+            fillOutputBuffer(&buffers->editItemAt(i));
+            return;
+        }
+    }
+
+    CHECK(!"should not be here.");
+}
+
+void OMXCodec::setState(State newState) {
+    mState = newState;
+    mAsyncCompletion.signal();
+
+    // This may cause some spurious wakeups but is necessary to
+    // unblock the reader if we enter ERROR state.
+    mBufferFilled.signal();
+}
+
+void OMXCodec::setAMRFormat() {
+    if (!mIsEncoder) {
+        OMX_AUDIO_PARAM_AMRTYPE def;
+        def.nSize = sizeof(def);
+        def.nVersion.s.nVersionMajor = 1;
+        def.nVersion.s.nVersionMinor = 1;
+        def.nPortIndex = kPortIndexInput;
+
+        status_t err =
+            mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+
+        CHECK_EQ(err, OK);
+
+        def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+        def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
+
+        err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+        CHECK_EQ(err, OK);
+    }
+
+    ////////////////////////
+
+    if (mIsEncoder) {
+        sp<MetaData> format = mSource->getFormat();
+        int32_t sampleRate;
+        int32_t numChannels;
+        CHECK(format->findInt32(kKeySampleRate, &sampleRate));
+        CHECK(format->findInt32(kKeyChannelCount, &numChannels));
+
+        OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
+        pcmParams.nSize = sizeof(pcmParams);
+        pcmParams.nVersion.s.nVersionMajor = 1;
+        pcmParams.nVersion.s.nVersionMinor = 1;
+        pcmParams.nPortIndex = kPortIndexInput;
+
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+        CHECK_EQ(err, OK);
+
+        pcmParams.nChannels = numChannels;
+        pcmParams.eNumData = OMX_NumericalDataSigned;
+        pcmParams.bInterleaved = OMX_TRUE;
+        pcmParams.nBitPerSample = 16;
+        pcmParams.nSamplingRate = sampleRate;
+        pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
+
+        if (numChannels == 1) {
+            pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+        } else {
+            CHECK_EQ(numChannels, 2);
+
+            pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+        }
+
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+        CHECK_EQ(err, OK);
+    }
+}
+
+void OMXCodec::setAACFormat() {
+    OMX_AUDIO_PARAM_AACPROFILETYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexInput;
+
+    status_t err =
+        mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+    err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setImageOutputFormat(
+        OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
+    LOGV("setImageOutputFormat(%ld, %ld)", width, height);
+
+#if 0
+    OMX_INDEXTYPE index;
+    status_t err = mOMX->get_extension_index(
+            mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
+    CHECK_EQ(err, OK);
+
+    err = mOMX->set_config(mNode, index, &format, sizeof(format));
+    CHECK_EQ(err, OK);
+#endif
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    CHECK_EQ(def.eDomain, OMX_PortDomainImage);
+
+    OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+    
+    CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
+    imageDef->eColorFormat = format;
+    imageDef->nFrameWidth = width;
+    imageDef->nFrameHeight = height;
+
+    switch (format) {
+        case OMX_COLOR_FormatYUV420PackedPlanar:
+        case OMX_COLOR_FormatYUV411Planar:
+        {
+            def.nBufferSize = (width * height * 3) / 2;
+            break;
+        }
+
+        case OMX_COLOR_FormatCbYCrY:
+        {
+            def.nBufferSize = width * height * 2;
+            break;
+        }
+
+        case OMX_COLOR_Format32bitARGB8888:
+        {
+            def.nBufferSize = width * height * 4;
+            break;
+        }
+
+        default:
+            CHECK(!"Should not be here. Unknown color format.");
+            break;
+    }
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    ////
+
+    def.nPortIndex = kPortIndexInput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
+    imageDef->nFrameWidth = width;
+    imageDef->nFrameHeight = height;
+
+    def.nBufferSize = 128 * 1024;
+    def.nBufferCountActual = def.nBufferCountMin;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+}
+
+void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
+    CodecSpecificData *specific =
+        (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
+
+    specific->mSize = size;
+    memcpy(specific->mData, data, size);
+
+    mCodecSpecificData.push(specific);
+}
+
+void OMXCodec::clearCodecSpecificData() {
+    for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
+        free(mCodecSpecificData.editItemAt(i));
+    }
+    mCodecSpecificData.clear();
+    mCodecSpecificDataIndex = 0;
+}
+
+status_t OMXCodec::start(MetaData *) {
+    if (mState != LOADED) {
+        return UNKNOWN_ERROR;
+    }
+    
+    sp<MetaData> params = new MetaData;
+    if (!strcasecmp(mMIME, "video/avc") && !(mQuirks & kWantsRawNALFrames)) {
+        params->setInt32(kKeyNeedsNALFraming, true);
+    }
+    status_t err = mSource->start(params.get());
+
+    if (err != OK) {
+        return err;
+    }
+
+    mCodecSpecificDataIndex = 0;
+    mSignalledEOS = false;
+    mNoMoreOutputData = false;
+    mSeekTimeUs = -1;
+    mFilledBuffers.clear();
+
+    return init();
+}
+
+status_t OMXCodec::stop() {
+    LOGI("stop");
+
+    Mutex::Autolock autoLock(mLock);
+
+    while (isIntermediateState(mState)) {
+        mAsyncCompletion.wait(mLock);
+    }
+
+    switch (mState) {
+        case LOADED:
+        case ERROR:
+            break;
+
+        case EXECUTING:
+        {
+            setState(EXECUTING_TO_IDLE);
+
+            mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+            mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+
+            status_t err =
+                mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+            CHECK_EQ(err, OK);
+
+            while (mState != LOADED && mState != ERROR) {
+                mAsyncCompletion.wait(mLock);
+            }
+
+            break;
+        }
+
+        default:
+        {
+            CHECK(!"should not be here.");
+            break;
+        }
+    }
+
+    mSource->stop();
+
+    return OK;
+}
+
+sp<MetaData> OMXCodec::getFormat() {
+    return mOutputFormat;
+}
+
+status_t OMXCodec::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    *buffer = NULL;
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mState != EXECUTING && mState != RECONFIGURING) {
+        return UNKNOWN_ERROR;
+    }
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
+
+        mSignalledEOS = false;
+        mNoMoreOutputData = false;
+
+        CHECK(seekTimeUs >= 0);
+        mSeekTimeUs = seekTimeUs;
+
+        mFilledBuffers.clear();
+
+        CHECK_EQ(mState, EXECUTING);
+
+        flushPortAsync(kPortIndexInput);
+        flushPortAsync(kPortIndexOutput);
+    }
+
+    while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
+        mBufferFilled.wait(mLock);
+    }
+
+    if (mState == ERROR) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (mFilledBuffers.empty()) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    size_t index = *mFilledBuffers.begin();
+    mFilledBuffers.erase(mFilledBuffers.begin());
+
+    BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
+    info->mMediaBuffer->add_ref();
+    *buffer = info->mMediaBuffer;
+
+    return OK;
+}
+
+void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+    for (size_t i = 0; i < buffers->size(); ++i) {
+        BufferInfo *info = &buffers->editItemAt(i);
+
+        if (info->mMediaBuffer == buffer) {
+            CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
+            fillOutputBuffer(info);
+            return;
+        }
+    }
+
+    CHECK(!"should not be here.");
+}
+
+static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
+    static const char *kNames[] = {
+        "OMX_IMAGE_CodingUnused",
+        "OMX_IMAGE_CodingAutoDetect",
+        "OMX_IMAGE_CodingJPEG",
+        "OMX_IMAGE_CodingJPEG2K",
+        "OMX_IMAGE_CodingEXIF",
+        "OMX_IMAGE_CodingTIFF",
+        "OMX_IMAGE_CodingGIF",
+        "OMX_IMAGE_CodingPNG",
+        "OMX_IMAGE_CodingLZW",
+        "OMX_IMAGE_CodingBMP",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
+
+static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
+    static const char *kNames[] = {
+        "OMX_COLOR_FormatUnused",
+        "OMX_COLOR_FormatMonochrome",
+        "OMX_COLOR_Format8bitRGB332",
+        "OMX_COLOR_Format12bitRGB444",
+        "OMX_COLOR_Format16bitARGB4444",
+        "OMX_COLOR_Format16bitARGB1555",
+        "OMX_COLOR_Format16bitRGB565",
+        "OMX_COLOR_Format16bitBGR565",
+        "OMX_COLOR_Format18bitRGB666",
+        "OMX_COLOR_Format18bitARGB1665",
+        "OMX_COLOR_Format19bitARGB1666", 
+        "OMX_COLOR_Format24bitRGB888",
+        "OMX_COLOR_Format24bitBGR888",
+        "OMX_COLOR_Format24bitARGB1887",
+        "OMX_COLOR_Format25bitARGB1888",
+        "OMX_COLOR_Format32bitBGRA8888",
+        "OMX_COLOR_Format32bitARGB8888",
+        "OMX_COLOR_FormatYUV411Planar",
+        "OMX_COLOR_FormatYUV411PackedPlanar",
+        "OMX_COLOR_FormatYUV420Planar",
+        "OMX_COLOR_FormatYUV420PackedPlanar",
+        "OMX_COLOR_FormatYUV420SemiPlanar",
+        "OMX_COLOR_FormatYUV422Planar",
+        "OMX_COLOR_FormatYUV422PackedPlanar",
+        "OMX_COLOR_FormatYUV422SemiPlanar",
+        "OMX_COLOR_FormatYCbYCr",
+        "OMX_COLOR_FormatYCrYCb",
+        "OMX_COLOR_FormatCbYCrY",
+        "OMX_COLOR_FormatCrYCbY",
+        "OMX_COLOR_FormatYUV444Interleaved",
+        "OMX_COLOR_FormatRawBayer8bit",
+        "OMX_COLOR_FormatRawBayer10bit",
+        "OMX_COLOR_FormatRawBayer8bitcompressed",
+        "OMX_COLOR_FormatL2", 
+        "OMX_COLOR_FormatL4", 
+        "OMX_COLOR_FormatL8", 
+        "OMX_COLOR_FormatL16", 
+        "OMX_COLOR_FormatL24", 
+        "OMX_COLOR_FormatL32",
+        "OMX_COLOR_FormatYUV420PackedSemiPlanar",
+        "OMX_COLOR_FormatYUV422PackedSemiPlanar",
+        "OMX_COLOR_Format18BitBGR666",
+        "OMX_COLOR_Format24BitARGB6666",
+        "OMX_COLOR_Format24BitABGR6666",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+    if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
+        return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
+    } else if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
+
+static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
+    static const char *kNames[] = {
+        "OMX_VIDEO_CodingUnused",
+        "OMX_VIDEO_CodingAutoDetect",
+        "OMX_VIDEO_CodingMPEG2",
+        "OMX_VIDEO_CodingH263",
+        "OMX_VIDEO_CodingMPEG4",
+        "OMX_VIDEO_CodingWMV",
+        "OMX_VIDEO_CodingRV",
+        "OMX_VIDEO_CodingAVC",
+        "OMX_VIDEO_CodingMJPEG",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
+
+static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
+    static const char *kNames[] = {
+        "OMX_AUDIO_CodingUnused",
+        "OMX_AUDIO_CodingAutoDetect",
+        "OMX_AUDIO_CodingPCM",
+        "OMX_AUDIO_CodingADPCM",
+        "OMX_AUDIO_CodingAMR",
+        "OMX_AUDIO_CodingGSMFR",
+        "OMX_AUDIO_CodingGSMEFR",
+        "OMX_AUDIO_CodingGSMHR",
+        "OMX_AUDIO_CodingPDCFR",
+        "OMX_AUDIO_CodingPDCEFR",
+        "OMX_AUDIO_CodingPDCHR",
+        "OMX_AUDIO_CodingTDMAFR",
+        "OMX_AUDIO_CodingTDMAEFR",
+        "OMX_AUDIO_CodingQCELP8",
+        "OMX_AUDIO_CodingQCELP13",
+        "OMX_AUDIO_CodingEVRC",
+        "OMX_AUDIO_CodingSMV",
+        "OMX_AUDIO_CodingG711",
+        "OMX_AUDIO_CodingG723",
+        "OMX_AUDIO_CodingG726",
+        "OMX_AUDIO_CodingG729",
+        "OMX_AUDIO_CodingAAC",
+        "OMX_AUDIO_CodingMP3",
+        "OMX_AUDIO_CodingSBC",
+        "OMX_AUDIO_CodingVORBIS",
+        "OMX_AUDIO_CodingWMA",
+        "OMX_AUDIO_CodingRA",
+        "OMX_AUDIO_CodingMIDI",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
+
+static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
+    static const char *kNames[] = {
+        "OMX_AUDIO_PCMModeLinear",
+        "OMX_AUDIO_PCMModeALaw",
+        "OMX_AUDIO_PCMModeMULaw",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
+
+
+void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = portIndex;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
+
+    CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
+          || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
+
+    printf("  nBufferCountActual = %ld\n", def.nBufferCountActual);
+    printf("  nBufferCountMin = %ld\n", def.nBufferCountMin);
+    printf("  nBufferSize = %ld\n", def.nBufferSize);
+
+    switch (def.eDomain) {
+        case OMX_PortDomainImage:
+        {
+            const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+
+            printf("\n");
+            printf("  // Image\n");
+            printf("  nFrameWidth = %ld\n", imageDef->nFrameWidth);
+            printf("  nFrameHeight = %ld\n", imageDef->nFrameHeight);
+            printf("  nStride = %ld\n", imageDef->nStride);
+
+            printf("  eCompressionFormat = %s\n",
+                   imageCompressionFormatString(imageDef->eCompressionFormat));
+
+            printf("  eColorFormat = %s\n",
+                   colorFormatString(imageDef->eColorFormat));
+
+            break;
+        }
+
+        case OMX_PortDomainVideo:
+        {
+            OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+
+            printf("\n");
+            printf("  // Video\n");
+            printf("  nFrameWidth = %ld\n", videoDef->nFrameWidth);
+            printf("  nFrameHeight = %ld\n", videoDef->nFrameHeight);
+            printf("  nStride = %ld\n", videoDef->nStride);
+
+            printf("  eCompressionFormat = %s\n",
+                   videoCompressionFormatString(videoDef->eCompressionFormat));
+
+            printf("  eColorFormat = %s\n",
+                   colorFormatString(videoDef->eColorFormat));
+
+            break;
+        }
+
+        case OMX_PortDomainAudio:
+        {
+            OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
+
+            printf("\n");
+            printf("  // Audio\n");
+            printf("  eEncoding = %s\n",
+                   audioCodingTypeString(audioDef->eEncoding));
+
+            if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
+                OMX_AUDIO_PARAM_PCMMODETYPE params;
+                params.nSize = sizeof(params);
+                params.nVersion.s.nVersionMajor = 1;
+                params.nVersion.s.nVersionMinor = 1;
+                params.nPortIndex = portIndex;
+
+                err = mOMX->get_parameter(
+                        mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
+                CHECK_EQ(err, OK);
+
+                printf("  nSamplingRate = %ld\n", params.nSamplingRate);
+                printf("  nChannels = %ld\n", params.nChannels);
+                printf("  bInterleaved = %d\n", params.bInterleaved);
+                printf("  nBitPerSample = %ld\n", params.nBitPerSample);
+
+                printf("  eNumData = %s\n",
+                       params.eNumData == OMX_NumericalDataSigned
+                        ? "signed" : "unsigned");
+
+                printf("  ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
+            }
+
+            break;
+        }
+
+        default:
+        {
+            printf("  // Unknown\n");
+            break;
+        }
+    }
+
+    printf("}\n");
+}
+
+void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
+    mOutputFormat = new MetaData;
+    mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    switch (def.eDomain) {
+        case OMX_PortDomainImage:
+        {
+            OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+            CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
+
+            mOutputFormat->setCString(kKeyMIMEType, "image/raw");
+            mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
+            mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
+            mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
+            break;
+        }
+
+        case OMX_PortDomainAudio:
+        {
+            OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
+
+            CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
+
+            OMX_AUDIO_PARAM_PCMMODETYPE params;
+            params.nSize = sizeof(params);
+            params.nVersion.s.nVersionMajor = 1;
+            params.nVersion.s.nVersionMinor = 1;
+            params.nPortIndex = kPortIndexOutput;
+
+            err = mOMX->get_parameter(
+                    mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
+            CHECK_EQ(err, OK);
+
+            CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
+            CHECK_EQ(params.nBitPerSample, 16);
+            CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
+
+            int32_t numChannels, sampleRate;
+            inputFormat->findInt32(kKeyChannelCount, &numChannels);
+            inputFormat->findInt32(kKeySampleRate, &sampleRate);
+
+            mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
+            mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+            mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+            break;
+        }
+
+        case OMX_PortDomainVideo:
+        {
+            OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+            if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/raw");
+            } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
+            } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
+            } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/avc");
+            } else {
+                CHECK(!"Unknown compression format.");
+            }
+
+            if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
+                // This component appears to be lying to me.
+                mOutputFormat->setInt32(
+                        kKeyWidth, (video_def->nFrameWidth + 15) & -16);
+                mOutputFormat->setInt32(
+                        kKeyHeight, (video_def->nFrameHeight + 15) & -16);
+            } else {
+                mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
+                mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
+            }
+
+            mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
+            break;
+        }
+
+        default:
+        {
+            CHECK(!"should not be here, neither audio nor video.");
+            break;
+        }
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index a00872f..94cca43 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -102,9 +102,10 @@
 }
 
 // static
-OMXDecoder *OMXDecoder::Create(
+sp<OMXDecoder> OMXDecoder::Create(
         OMXClient *client, const sp<MetaData> &meta,
-        bool createEncoder) {
+        bool createEncoder,
+        const sp<MediaSource> &source) {
     const char *mime;
     bool success = meta->findCString(kKeyMIMEType, &mime);
     assert(success);
@@ -158,8 +159,9 @@
         quirks |= kRequiresLoadedToIdleAfterAllocation;
     }
 
-    OMXDecoder *decoder = new OMXDecoder(
-            client, node, mime, codec, createEncoder, quirks);
+    sp<OMXDecoder> decoder = new OMXDecoder(
+            client, node, mime, codec, createEncoder, quirks,
+            source);
 
     uint32_t type;
     const void *data;
@@ -213,7 +215,8 @@
 OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
                        const char *mime, const char *codec,
                        bool is_encoder,
-                       uint32_t quirks)
+                       uint32_t quirks,
+                       const sp<MediaSource> &source)
     : mClient(client),
       mOMX(mClient->interface()),
       mNode(node),
@@ -223,7 +226,7 @@
       mIsAVC(!strcasecmp(mime, "video/avc")),
       mIsEncoder(is_encoder),
       mQuirks(quirks),
-      mSource(NULL),
+      mSource(source),
       mCodecSpecificDataIterator(mCodecSpecificData.begin()),
       mState(OMX_StateLoaded),
       mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
@@ -237,6 +240,8 @@
 
     mBuffers.push();  // input buffers
     mBuffers.push();  // output buffers
+
+    setup();
 }
 
 OMXDecoder::~OMXDecoder() {
@@ -263,15 +268,6 @@
     mComponentName = NULL;
 }
 
-void OMXDecoder::setSource(MediaSource *source) {
-    Mutex::Autolock autoLock(mLock);
-
-    assert(mSource == NULL);
-
-    mSource = source;
-    setup();
-}
-
 status_t OMXDecoder::start(MetaData *) {
     assert(!mStarted);
 
@@ -580,6 +576,10 @@
     OMX_COLOR_FORMATTYPE colorFormat =
         0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
 
+    if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
+        colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+    }
+
     setVideoPortFormatType(
             kPortIndexInput, OMX_VIDEO_CodingUnused,
             colorFormat);
@@ -1621,7 +1621,7 @@
 void OMXDecoder::postEmptyBufferDone(IOMX::buffer_id buffer) {
     omx_message msg;
     msg.type = omx_message::EMPTY_BUFFER_DONE;
-    msg.u.buffer_data.node = mNode;
+    msg.node = mNode;
     msg.u.buffer_data.buffer = buffer;
     postMessage(msg);
 }
@@ -1629,7 +1629,7 @@
 void OMXDecoder::postInitialFillBuffer(IOMX::buffer_id buffer) {
     omx_message msg;
     msg.type = omx_message::INITIAL_FILL_BUFFER;
-    msg.u.buffer_data.node = mNode;
+    msg.node = mNode;
     msg.u.buffer_data.buffer = buffer;
     postMessage(msg);
 }
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 8f1fa67..75bfde3 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -31,7 +31,7 @@
 static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
 static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
 
-SampleTable::SampleTable(DataSource *source)
+SampleTable::SampleTable(const sp<DataSource> &source)
     : mDataSource(source),
       mChunkOffsetOffset(-1),
       mChunkOffsetType(0),
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index d44e3a3..39fa27e 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -75,6 +75,102 @@
     NodeMeta &operator=(const NodeMeta &);
 };
 
+////////////////////////////////////////////////////////////////////////////////
+
+struct OMX::CallbackDispatcher : public RefBase {
+    CallbackDispatcher();
+
+    void post(const omx_message &msg);
+
+protected:
+    virtual ~CallbackDispatcher();
+
+private:
+    Mutex mLock;
+    bool mDone;
+    Condition mQueueChanged;
+    List<omx_message> mQueue;
+
+    pthread_t mThread;
+
+    void dispatch(const omx_message &msg);
+
+    static void *ThreadWrapper(void *me);
+    void threadEntry();
+
+    CallbackDispatcher(const CallbackDispatcher &);
+    CallbackDispatcher &operator=(const CallbackDispatcher &);
+};
+
+OMX::CallbackDispatcher::CallbackDispatcher()
+    : mDone(false) {
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    pthread_create(&mThread, &attr, ThreadWrapper, this);
+
+    pthread_attr_destroy(&attr);
+}
+
+OMX::CallbackDispatcher::~CallbackDispatcher() {
+    {
+        Mutex::Autolock autoLock(mLock);
+
+        mDone = true;
+        mQueueChanged.signal();
+    }
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+}
+
+void OMX::CallbackDispatcher::post(const omx_message &msg) {
+    Mutex::Autolock autoLock(mLock);
+    mQueue.push_back(msg);
+    mQueueChanged.signal();
+}
+
+void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
+    NodeMeta *meta = static_cast<NodeMeta *>(msg.node);
+
+    sp<IOMXObserver> observer = meta->observer();
+    if (observer.get() != NULL) {
+        observer->on_message(msg);
+    }
+}
+
+// static
+void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
+    static_cast<CallbackDispatcher *>(me)->threadEntry();
+
+    return NULL;
+}
+
+void OMX::CallbackDispatcher::threadEntry() {
+    for (;;) {
+        omx_message msg;
+
+        {
+            Mutex::Autolock autoLock(mLock);
+            while (!mDone && mQueue.empty()) {
+                mQueueChanged.wait(mLock);
+            }
+
+            if (mDone) {
+                break;
+            }
+
+            msg = *mQueue.begin();
+            mQueue.erase(mQueue.begin());
+        }
+
+        dispatch(msg);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 class BufferMeta {
 public:
     BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
@@ -154,7 +250,8 @@
     return meta->owner()->OnFillBufferDone(meta, pBuffer);
 }
 
-OMX::OMX() {
+OMX::OMX()
+    : mDispatcher(new CallbackDispatcher) {
 }
 
 status_t OMX::list_nodes(List<String8> *list) {
@@ -249,6 +346,29 @@
     return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
 }
 
+status_t OMX::get_config(
+        node_id node, OMX_INDEXTYPE index,
+        void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    NodeMeta *meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err = OMX_GetConfig(meta->handle(), index, params);
+
+    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::set_config(
+        node_id node, OMX_INDEXTYPE index,
+        const void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    NodeMeta *meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err =
+        OMX_SetConfig(meta->handle(), index, const_cast<void *>(params));
+
+    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
 status_t OMX::use_buffer(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer) {
@@ -357,15 +477,12 @@
 
     omx_message msg;
     msg.type = omx_message::EVENT;
-    msg.u.event_data.node = meta;
+    msg.node = meta;
     msg.u.event_data.event = eEvent;
     msg.u.event_data.data1 = nData1;
     msg.u.event_data.data2 = nData2;
 
-    sp<IOMXObserver> observer = meta->observer();
-    if (observer.get() != NULL) {
-        observer->on_message(msg);
-    }
+    mDispatcher->post(msg);
 
     return OMX_ErrorNone;
 }
@@ -376,13 +493,10 @@
 
     omx_message msg;
     msg.type = omx_message::EMPTY_BUFFER_DONE;
-    msg.u.buffer_data.node = meta;
+    msg.node = meta;
     msg.u.buffer_data.buffer = pBuffer;
 
-    sp<IOMXObserver> observer = meta->observer();
-    if (observer.get() != NULL) {
-        observer->on_message(msg);
-    }
+    mDispatcher->post(msg);
 
     return OMX_ErrorNone;
 }
@@ -395,7 +509,7 @@
 
     omx_message msg;
     msg.type = omx_message::FILL_BUFFER_DONE;
-    msg.u.extended_buffer_data.node = meta;
+    msg.node = meta;
     msg.u.extended_buffer_data.buffer = pBuffer;
     msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
     msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
@@ -403,10 +517,7 @@
     msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
     msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
 
-    sp<IOMXObserver> observer = meta->observer();
-    if (observer.get() != NULL) {
-        observer->on_message(msg);
-    }
+    mDispatcher->post(msg);
 
     return OMX_ErrorNone;
 }
@@ -455,6 +566,20 @@
     assert(err == OMX_ErrorNone);
 }
 
+status_t OMX::get_extension_index(
+        node_id node,
+        const char *parameter_name,
+        OMX_INDEXTYPE *index) {
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+    OMX_ERRORTYPE err =
+        OMX_GetExtensionIndex(
+                node_meta->handle(),
+                const_cast<char *>(parameter_name), index);
+
+    return err == OMX_ErrorNone ? OK : UNKNOWN_ERROR;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 sp<IOMXRenderer> OMX::createRenderer(
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h
index 8ac311c..6325f79 100644
--- a/media/libstagefright/omx/OMX.h
+++ b/media/libstagefright/omx/OMX.h
@@ -44,6 +44,14 @@
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size);
 
+    virtual status_t get_config(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size);
+
+    virtual status_t set_config(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size);
+
     virtual status_t use_buffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer);
@@ -70,6 +78,11 @@
             OMX_U32 range_offset, OMX_U32 range_length,
             OMX_U32 flags, OMX_TICKS timestamp);
 
+    virtual status_t get_extension_index(
+            node_id node,
+            const char *parameter_name,
+            OMX_INDEXTYPE *index);
+
     virtual sp<IOMXRenderer> createRenderer(
             const sp<ISurface> &surface,
             const char *componentName,
@@ -82,6 +95,9 @@
 
     Mutex mLock;
 
+    struct CallbackDispatcher;
+    sp<CallbackDispatcher> mDispatcher;
+
     static OMX_ERRORTYPE OnEvent(
             OMX_IN OMX_HANDLETYPE hComponent,
             OMX_IN OMX_PTR pAppData,