am 3a814141: Merge change Iee0486e2 into eclair

Merge commit '3a8141416a0b1d517d4729eba4bcf914c468e20b' into eclair-mr2

* commit '3a8141416a0b1d517d4729eba4bcf914c468e20b':
  Dump media recorder PID in dumpsys media.player, and fix minor bugs.
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index e5a6ccb..e272a65 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -86,8 +86,8 @@
         x += k;
     }
 
-    buffer->meta_data()->setInt32(kKeyTimeUnits, mPhase);
-    buffer->meta_data()->setInt32(kKeyTimeScale, mSampleRate);
+    buffer->meta_data()->setInt64(
+            kKeyTime, ((int64_t)mPhase * 1000000) / mSampleRate);
 
     mPhase += numFramesPerBuffer;
 
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 323d448..0025c5e 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -23,7 +23,7 @@
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MmapSource.h>
 #include <media/stagefright/OMXClient.h>
@@ -32,8 +32,10 @@
 
 using namespace android;
 
-#if 0
+#if 1
 class DummySource : public MediaSource {
+    static const int32_t kFramerate = 24;  // fps
+
 public:
     DummySource(int width, int height)
         : mWidth(width),
@@ -52,6 +54,7 @@
     }
 
     virtual status_t start(MetaData *params) {
+        mNumFramesOutput = 0;
         return OK;
     }
 
@@ -61,6 +64,12 @@
 
     virtual status_t read(
             MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+        if (mNumFramesOutput == kFramerate * 10) {
+            // Stop returning data after 10 secs.
+            return ERROR_END_OF_STREAM;
+        }
+
+        // printf("DummySource::read\n");
         status_t err = mGroup.acquire_buffer(buffer);
         if (err != OK) {
             return err;
@@ -69,7 +78,13 @@
         char x = (char)((double)rand() / RAND_MAX * 255);
         memset((*buffer)->data(), x, mSize);
         (*buffer)->set_range(0, mSize);
+        (*buffer)->meta_data()->clear();
+        (*buffer)->meta_data()->setInt64(
+                kKeyTime, (mNumFramesOutput * 1000000) / kFramerate);
+        ++mNumFramesOutput;
 
+        // printf("DummySource::read - returning buffer\n");
+        // LOGI("DummySource::read - returning buffer");
         return OK;
     }
 
@@ -80,6 +95,7 @@
     MediaBufferGroup mGroup;
     int mWidth, mHeight;
     size_t mSize;
+    int64_t mNumFramesOutput;;
 
     DummySource(const DummySource &);
     DummySource &operator=(const DummySource &);
@@ -88,8 +104,8 @@
 sp<MediaSource> createSource(const char *filename) {
     sp<MediaSource> source;
 
-    sp<MPEG4Extractor> extractor =
-        new MPEG4Extractor(new MmapSource(filename));
+    sp<MediaExtractor> extractor =
+        MediaExtractor::Create(new MmapSource(filename));
 
     size_t num_tracks = extractor->countTracks();
 
@@ -144,8 +160,8 @@
     success = success && meta->findInt32(kKeyHeight, &height);
     CHECK(success);
 #else
-    int width = 320;
-    int height = 240;
+    int width = 800;
+    int height = 480;
     sp<MediaSource> decoder = new DummySource(width, height);
 #endif
 
@@ -159,19 +175,26 @@
         OMXCodec::Create(
                 client.interface(), enc_meta, true /* createEncoder */, decoder);
 
-#if 0
+#if 1
     sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
-    writer->addSource(enc_meta, encoder);
+    writer->addSource(encoder);
     writer->start();
-    sleep(20);
-    printf("stopping now.\n");
+    while (!writer->reachedEOS()) {
+        usleep(100000);
+    }
     writer->stop();
 #else
     encoder->start();
 
     MediaBuffer *buffer;
     while (encoder->read(&buffer) == OK) {
-        printf("got an output frame of size %d\n", buffer->range_length());
+        int32_t isSync;
+        if (!buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)) {
+            isSync = false;
+        }
+
+        printf("got an output frame of size %d%s\n", buffer->range_length(),
+               isSync ? " (SYNC)" : "");
 
         buffer->release();
         buffer = NULL;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index f8bb3c8..3b7cece 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -52,12 +52,8 @@
 static void playSource(OMXClient *client, const sp<MediaSource> &source) {
     sp<MetaData> meta = source->getFormat();
 
-    int32_t durationUnits;
-    int32_t timeScale;
-    CHECK(meta->findInt32(kKeyDuration, &durationUnits));
-    CHECK(meta->findInt32(kKeyTimeScale, &timeScale));
-
-    int64_t durationUs = ((int64_t)durationUnits * 1000000) / timeScale;
+    int64_t durationUs;
+    CHECK(meta->findInt64(kKeyDuration, &durationUs));
 
     sp<OMXCodec> decoder = OMXCodec::Create(
             client->interface(), meta, false /* createEncoder */, source);
@@ -78,20 +74,24 @@
             options.clearSeekTo();
 
             bool shouldSeek = false;
-            if (err != OK) {
+            if (err == INFO_FORMAT_CHANGED) {
+                CHECK_EQ(buffer, NULL);
+
+                printf("format changed.\n");
+                continue;
+            } else if (err != OK) {
                 printf("reached EOF.\n");
 
                 shouldSeek = true;
             } else {
-                int32_t timestampUnits;
-                CHECK(buffer->meta_data()->findInt32(kKeyTimeUnits, &timestampUnits));
-
-                int64_t timestampUs = ((int64_t)timestampUnits * 1000000) / timeScale;
+                int64_t timestampUs;
+                CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
 
                 bool failed = false;
 
                 if (seekTimeUs >= 0) {
                     int64_t diff = timestampUs - seekTimeUs;
+
                     if (diff < 0) {
                         diff = -diff;
                     }
@@ -157,6 +157,11 @@
             if (err != OK) {
                 CHECK_EQ(buffer, NULL);
 
+                if (err == INFO_FORMAT_CHANGED) {
+                    printf("format changed.\n");
+                    continue;
+                }
+
                 break;
             }
 
@@ -283,7 +288,7 @@
 
         CHECK(service.get() != NULL);
 
-        sp<IOMX> omx = service->createOMX();
+        sp<IOMX> omx = service->getOMX();
         CHECK(omx.get() != NULL);
 
         const char *kMimeTypes[] = {
@@ -329,11 +334,11 @@
 
         CHECK(service.get() != NULL);
 
-        sp<IOMX> omx = service->createOMX();
+        sp<IOMX> omx = service->getOMX();
         CHECK(omx.get() != NULL);
 
         List<String8> list;
-        omx->list_nodes(&list);
+        omx->listNodes(&list);
 
         for (List<String8>::iterator it = list.begin();
              it != list.end(); ++it) {
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 303444c..d5c1594 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -42,7 +42,7 @@
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
-    virtual sp<IOMX>            createOMX() = 0;
+    virtual sp<IOMX>            getOMX() = 0;
 
     // Take a peek at currently playing audio, for visualization purposes.
     // This returns a buffer of 16 bit mono PCM data, or NULL if no visualization buffer is currently available.
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 10e0197..6f3ba1c 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -42,57 +42,57 @@
     typedef void *buffer_id;
     typedef void *node_id;
 
-    virtual status_t list_nodes(List<String8> *list) = 0;
+    virtual status_t listNodes(List<String8> *list) = 0;
 
-    virtual status_t allocate_node(const char *name, node_id *node) = 0;
-    virtual status_t free_node(node_id node) = 0;
+    virtual status_t allocateNode(
+            const char *name, const sp<IOMXObserver> &observer,
+            node_id *node) = 0;
 
-    virtual status_t send_command(
+    virtual status_t freeNode(node_id node) = 0;
+
+    virtual status_t sendCommand(
             node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) = 0;
 
-    virtual status_t get_parameter(
+    virtual status_t getParameter(
             node_id node, OMX_INDEXTYPE index,
             void *params, size_t size) = 0;
 
-    virtual status_t set_parameter(
+    virtual status_t setParameter(
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size) = 0;
 
-    virtual status_t get_config(
+    virtual status_t getConfig(
             node_id node, OMX_INDEXTYPE index,
             void *params, size_t size) = 0;
 
-    virtual status_t set_config(
+    virtual status_t setConfig(
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size) = 0;
 
-    virtual status_t use_buffer(
+    virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer) = 0;
 
-    virtual status_t allocate_buffer(
+    virtual status_t allocateBuffer(
             node_id node, OMX_U32 port_index, size_t size,
             buffer_id *buffer) = 0;
 
-    virtual status_t allocate_buffer_with_backup(
+    virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer) = 0;
 
-    virtual status_t free_buffer(
+    virtual status_t freeBuffer(
             node_id node, OMX_U32 port_index, buffer_id buffer) = 0;
 
-    virtual status_t observe_node(
-            node_id node, const sp<IOMXObserver> &observer) = 0;
+    virtual status_t fillBuffer(node_id node, buffer_id buffer) = 0;
 
-    virtual void fill_buffer(node_id node, buffer_id buffer) = 0;
-
-    virtual void empty_buffer(
+    virtual status_t emptyBuffer(
             node_id node,
             buffer_id buffer,
             OMX_U32 range_offset, OMX_U32 range_length,
             OMX_U32 flags, OMX_TICKS timestamp) = 0;
 
-    virtual status_t get_extension_index(
+    virtual status_t getExtensionIndex(
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index) = 0;
@@ -162,7 +162,7 @@
 public:
     DECLARE_META_INTERFACE(OMXObserver);
 
-    virtual void on_message(const omx_message &msg) = 0;
+    virtual void onMessage(const omx_message &msg) = 0;
 };
 
 class IOMXRenderer : public IInterface {
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
index e35e19e..b0fc4b2 100644
--- a/include/media/stagefright/CachingDataSource.h
+++ b/include/media/stagefright/CachingDataSource.h
@@ -29,9 +29,9 @@
     CachingDataSource(
             const sp<DataSource> &source, size_t pageSize, int numPages);
 
-    status_t InitCheck() const;
+    virtual status_t initCheck() const;
 
-    virtual ssize_t read_at(off_t offset, void *data, size_t size);
+    virtual ssize_t readAt(off_t offset, void *data, size_t size);
 
 protected:
     virtual ~CachingDataSource();
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 7042e1a..ff3ea05 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -26,12 +26,11 @@
 
 namespace android {
 
-class ICamera;
-class ICameraClient;
 class IMemory;
+class ISurface;
+class Camera;
 
-class CameraSource : public MediaSource,
-                     public MediaBufferObserver {
+class CameraSource : public MediaSource {
 public:
     static CameraSource *Create();
 
@@ -45,24 +44,25 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
-    virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
-    virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
-
-    virtual void signalBufferReturned(MediaBuffer *buffer);
-
 private:
-    CameraSource(const sp<ICamera> &camera, const sp<ICameraClient> &client);
+    friend class CameraSourceListener;
 
-    sp<ICamera> mCamera;
-    sp<ICameraClient> mCameraClient;
+    sp<Camera> mCamera;
 
     Mutex mLock;
     Condition mFrameAvailableCondition;
     List<sp<IMemory> > mFrames;
+    List<int64_t> mFrameTimes;
 
-    int mNumFrames;
+    int mWidth, mHeight;
+    int64_t mFirstFrameTimeUs;
+    int32_t mNumFrames;
     bool mStarted;
 
+    CameraSource(const sp<Camera> &camera);
+
+    void dataCallback(int32_t msgType, const sp<IMemory> &data);
+
     CameraSource(const CameraSource &);
     CameraSource &operator=(const CameraSource &);
 };
diff --git a/include/media/stagefright/ColorConverter.h b/include/media/stagefright/ColorConverter.h
new file mode 100644
index 0000000..1e341b9
--- /dev/null
+++ b/include/media/stagefright/ColorConverter.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COLOR_CONVERTER_H_
+
+#define COLOR_CONVERTER_H_
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <OMX_Video.h>
+
+namespace android {
+
+struct ColorConverter {
+    ColorConverter(OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to);
+    ~ColorConverter();
+
+    bool isValid() const;
+
+    void convert(
+            size_t width, size_t height,
+            const void *srcBits, size_t srcSkip,
+            void *dstBits, size_t dstSkip);
+
+private:
+    OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
+    uint8_t *mClip;
+
+    uint8_t *initClip();
+
+    void convertCbYCrY(
+            size_t width, size_t height,
+            const void *srcBits, size_t srcSkip,
+            void *dstBits, size_t dstSkip);
+
+    void convertYUV420Planar(
+            size_t width, size_t height,
+            const void *srcBits, size_t srcSkip,
+            void *dstBits, size_t dstSkip);
+
+    void convertQCOMYUV420SemiPlanar(
+            size_t width, size_t height,
+            const void *srcBits, size_t srcSkip,
+            void *dstBits, size_t dstSkip);
+
+    ColorConverter(const ColorConverter &);
+    ColorConverter &operator=(const ColorConverter &);
+};
+
+}  // namespace android
+
+#endif  // COLOR_CONVERTER_H_
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index f46f0af..b843cd9 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -33,7 +33,9 @@
 public:
     DataSource() {}
 
-    virtual ssize_t read_at(off_t offset, void *data, size_t size) = 0;
+    virtual status_t initCheck() const = 0;
+
+    virtual ssize_t readAt(off_t offset, void *data, size_t size) = 0;
 
     // Convenience methods:
     bool getUInt16(off_t offset, uint16_t *x);
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index ccbe0ef..d7b42c3 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -29,12 +29,14 @@
 class FileSource : public DataSource {
 public:
     FileSource(const char *filename);
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off_t offset, void *data, size_t size);
+
+protected:
     virtual ~FileSource();
 
-    status_t InitCheck() const;
-
-    virtual ssize_t read_at(off_t offset, void *data, size_t size);
-
 private:
     FILE *mFile;
     Mutex mLock;
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index 0587c7c..d5dc9e6 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -19,28 +19,29 @@
 #define HTTP_DATASOURCE_H_
 
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/HTTPStream.h>
 
 namespace android {
 
+class HTTPStream;
+
 class HTTPDataSource : public DataSource {
 public:
     HTTPDataSource(const char *host, int port, const char *path);
     HTTPDataSource(const char *uri);
 
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off_t offset, void *data, size_t size);
+
+protected:
     virtual ~HTTPDataSource();
 
-    // XXXandih
-    status_t InitCheck() const { return OK; }
-
-    virtual ssize_t read_at(off_t offset, void *data, size_t size);
-
 private:
     enum {
         kBufferSize = 64 * 1024
     };
 
-    HTTPStream mHttp;
+    HTTPStream *mHttp;
     char *mHost;
     int mPort;
     char *mPath;
@@ -49,6 +50,8 @@
     size_t mBufferLength;
     off_t mBufferOffset;
 
+    status_t mInitCheck;
+
     HTTPDataSource(const HTTPDataSource &);
     HTTPDataSource &operator=(const HTTPDataSource &);
 };
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 2bb0ed6..73d0f77 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -36,6 +36,9 @@
     ERROR_BUFFER_TOO_SMALL  = MEDIA_ERROR_BASE - 9,
     ERROR_UNSUPPORTED       = MEDIA_ERROR_BASE - 10,
     ERROR_END_OF_STREAM     = MEDIA_ERROR_BASE - 11,
+
+    // Not technically an error.
+    INFO_FORMAT_CHANGED    = MEDIA_ERROR_BASE - 12,
 };
 
 }  // namespace android
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 67e45bd..d56d4b3 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -31,9 +31,17 @@
     static sp<MediaExtractor> Create(
             const sp<DataSource> &source, const char *mime = NULL);
 
+    static sp<MediaExtractor> CreateFromURI(
+            const char *uri, const char *mime = NULL);
+
     virtual size_t countTracks() = 0;
     virtual sp<MediaSource> getTrack(size_t index) = 0;
-    virtual sp<MetaData> getTrackMetaData(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    virtual sp<MetaData> getTrackMetaData(
+            size_t index, uint32_t flags = 0) = 0;
 
 protected:
     MediaExtractor() {}
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index d1fa114..96d57e7 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -51,6 +51,9 @@
     // buffer is available, an error is encountered of the end of the stream
     // is reached.
     // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+    // A result of INFO_FORMAT_CHANGED indicates that the format of this
+    // MediaSource has changed mid-stream, the client can continue reading
+    // but should be prepared for buffers of the new configuration.
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index abb45a9..c2d8f98 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -27,25 +27,26 @@
 
 namespace android {
 
+// The following keys map to int32_t data unless indicated otherwise.
 enum {
-    kKeyMIMEType          = 'mime',
+    kKeyMIMEType          = 'mime',  // cstring
     kKeyWidth             = 'widt',
     kKeyHeight            = 'heig',
     kKeyChannelCount      = '#chn',
     kKeySampleRate        = 'srte',
     kKeyBitRate           = 'brte',
-    kKeyESDS              = 'esds',
-    kKeyAVCC              = 'avcc',
-    kKeyTimeUnits         = '#tim',
-    kKeyTimeScale         = 'scal',
+    kKeyESDS              = 'esds',  // raw data
+    kKeyAVCC              = 'avcc',  // raw data
     kKeyWantsNALFragments = 'NALf',
     kKeyIsSyncFrame       = 'sync',
-    kKeyDuration          = 'dura',
+    kKeyTime              = 'time',  // int64_t (usecs)
+    kKeyDuration          = 'dura',  // int64_t (usecs)
     kKeyColorFormat       = 'colf',
-    kKeyPlatformPrivate   = 'priv',
-    kKeyDecoderComponent  = 'decC',
+    kKeyPlatformPrivate   = 'priv',  // pointer
+    kKeyDecoderComponent  = 'decC',  // cstring
     kKeyBufferID          = 'bfID',
     kKeyMaxInputSize      = 'inpS',
+    kKeyThumbnailTime     = 'thbT',  // int64_t (usecs)
 };
 
 enum {
@@ -62,6 +63,7 @@
         TYPE_NONE     = 'none',
         TYPE_C_STRING = 'cstr',
         TYPE_INT32    = 'in32',
+        TYPE_INT64    = 'in64',
         TYPE_FLOAT    = 'floa',
         TYPE_POINTER  = 'ptr ',
     };
@@ -71,11 +73,13 @@
 
     bool setCString(uint32_t key, const char *value);
     bool setInt32(uint32_t key, int32_t value);
+    bool setInt64(uint32_t key, int64_t value);
     bool setFloat(uint32_t key, float value);
     bool setPointer(uint32_t key, void *value);
 
     bool findCString(uint32_t key, const char **value);
     bool findInt32(uint32_t key, int32_t *value);
+    bool findInt64(uint32_t key, int64_t *value);
     bool findFloat(uint32_t key, float *value);
     bool findPointer(uint32_t key, void **value);
 
diff --git a/include/media/stagefright/MmapSource.h b/include/media/stagefright/MmapSource.h
index a8bd57f..1b39d53 100644
--- a/include/media/stagefright/MmapSource.h
+++ b/include/media/stagefright/MmapSource.h
@@ -30,13 +30,14 @@
     // Assumes ownership of "fd".
     MmapSource(int fd, int64_t offset, int64_t length);
 
-    virtual ~MmapSource();
+    virtual status_t initCheck() const;
 
-    status_t InitCheck() const;
-
-    virtual ssize_t read_at(off_t offset, void *data, size_t size);
+    virtual ssize_t readAt(off_t offset, void *data, size_t size);
     virtual status_t getSize(off_t *size);
 
+protected:
+    virtual ~MmapSource();
+
 private:
     int mFd;
     void *mBase;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 3f3dcf9..7890883 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -30,11 +30,15 @@
 
 struct OMXCodec : public MediaSource,
                   public MediaBufferObserver {
+    enum CreationFlags {
+        kPreferSoftwareCodecs = 1,
+    };
     static sp<OMXCodec> Create(
             const sp<IOMX> &omx,
             const sp<MetaData> &meta, bool createEncoder,
             const sp<MediaSource> &source,
-            const char *matchComponentName = NULL);
+            const char *matchComponentName = NULL,
+            uint32_t flags = 0);
 
     static void setComponentRole(
             const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
@@ -90,7 +94,6 @@
         kRequiresFlushCompleteEmulation      = 16,
         kRequiresAllocateBufferOnOutputPorts = 32,
         kRequiresFlushBeforeShutdown         = 64,
-        kOutputDimensionsAre16Aligned        = 128,
     };
 
     struct BufferInfo {
@@ -107,7 +110,6 @@
 
     sp<IOMX> mOMX;
     IOMX::node_id mNode;
-    sp<OMXCodecObserver> mObserver;
     uint32_t mQuirks;
     bool mIsEncoder;
     char *mMIME;
@@ -125,6 +127,7 @@
     bool mInitialBufferSubmit;
     bool mSignalledEOS;
     bool mNoMoreOutputData;
+    bool mOutputPortSettingsHaveChanged;
     int64_t mSeekTimeUs;
 
     Mutex mLock;
@@ -155,6 +158,8 @@
     void setVideoInputFormat(
             const char *mime, OMX_U32 width, OMX_U32 height);
 
+    status_t setupMPEG4EncoderParameters();
+
     void setVideoOutputFormat(
             const char *mime, OMX_U32 width, OMX_U32 height);
 
@@ -208,6 +213,14 @@
 
     void dumpPortStatus(OMX_U32 portIndex);
 
+    static uint32_t getComponentQuirks(const char *componentName);
+
+    static void findMatchingCodecs(
+            const char *mime,
+            bool createEncoder, const char *matchComponentName,
+            uint32_t flags,
+            Vector<String8> *matchingCodecs);
+
     OMXCodec(const OMXCodec &);
     OMXCodec &operator=(const OMXCodec &);
 };
diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h
index 352857a..bc67156 100644
--- a/include/media/stagefright/ShoutcastSource.h
+++ b/include/media/stagefright/ShoutcastSource.h
@@ -31,7 +31,6 @@
 public:
     // Assumes ownership of "http".
     ShoutcastSource(HTTPStream *http);
-    virtual ~ShoutcastSource();
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -41,6 +40,9 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
+protected:
+    virtual ~ShoutcastSource();
+
 private:
     HTTPStream *mHttp;
     size_t mMetaDataOffset;
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 98f7ef1..cca3e9b 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -35,7 +35,7 @@
     DECODE_FD,
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
-    CREATE_OMX,
+    GET_OMX,
     SNOOP
 };
 
@@ -123,10 +123,10 @@
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
-    virtual sp<IOMX> createOMX() {
+    virtual sp<IOMX> getOMX() {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        remote()->transact(CREATE_OMX, data, &reply);
+        remote()->transact(GET_OMX, data, &reply);
         return interface_cast<IOMX>(reply.readStrongBinder());
     }
 };
@@ -207,9 +207,9 @@
             reply->writeStrongBinder(retriever->asBinder());
             return NO_ERROR;
         } break;
-        case CREATE_OMX: {
+        case GET_OMX: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            sp<IOMX> omx = createOMX();
+            sp<IOMX> omx = getOMX();
             reply->writeStrongBinder(omx->asBinder());
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 0cec7bb..76a9e7d 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -24,7 +24,6 @@
     ALLOC_BUFFER,
     ALLOC_BUFFER_WITH_BACKUP,
     FREE_BUFFER,
-    OBSERVE_NODE,
     FILL_BUFFER,
     EMPTY_BUFFER,
     GET_EXTENSION_INDEX,
@@ -76,7 +75,7 @@
         : BpInterface<IOMX>(impl) {
     }
 
-    virtual status_t list_nodes(List<String8> *list) {
+    virtual status_t listNodes(List<String8> *list) {
         list->clear();
 
         Parcel data, reply;
@@ -93,10 +92,12 @@
         return OK;
     }
 
-    virtual status_t allocate_node(const char *name, node_id *node) {
+    virtual status_t allocateNode(
+            const char *name, const sp<IOMXObserver> &observer, node_id *node) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeCString(name);
+        data.writeStrongBinder(observer->asBinder());
         remote()->transact(ALLOCATE_NODE, data, &reply);
 
         status_t err = reply.readInt32();
@@ -109,7 +110,7 @@
         return err;
     }
 
-    virtual status_t free_node(node_id node) {
+    virtual status_t freeNode(node_id node) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeIntPtr((intptr_t)node);
@@ -118,7 +119,7 @@
         return reply.readInt32();
     }
 
-    virtual status_t send_command(
+    virtual status_t sendCommand(
             node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -130,7 +131,7 @@
         return reply.readInt32();
     }
 
-    virtual status_t get_parameter(
+    virtual status_t getParameter(
             node_id node, OMX_INDEXTYPE index,
             void *params, size_t size) {
         Parcel data, reply;
@@ -151,7 +152,7 @@
         return OK;
     }
 
-    virtual status_t set_parameter(
+    virtual status_t setParameter(
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size) {
         Parcel data, reply;
@@ -165,7 +166,7 @@
         return reply.readInt32();
     }
 
-    virtual status_t get_config(
+    virtual status_t getConfig(
             node_id node, OMX_INDEXTYPE index,
             void *params, size_t size) {
         Parcel data, reply;
@@ -186,7 +187,7 @@
         return OK;
     }
 
-    virtual status_t set_config(
+    virtual status_t setConfig(
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size) {
         Parcel data, reply;
@@ -200,7 +201,7 @@
         return reply.readInt32();
     }
 
-    virtual status_t use_buffer(
+    virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer) {
         Parcel data, reply;
@@ -222,7 +223,7 @@
         return err;
     }
 
-    virtual status_t allocate_buffer(
+    virtual status_t allocateBuffer(
             node_id node, OMX_U32 port_index, size_t size,
             buffer_id *buffer) {
         Parcel data, reply;
@@ -244,7 +245,7 @@
         return err;
     }
 
-    virtual status_t allocate_buffer_with_backup(
+    virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer) {
         Parcel data, reply;
@@ -266,7 +267,7 @@
         return err;
     }
 
-    virtual status_t free_buffer(
+    virtual status_t freeBuffer(
             node_id node, OMX_U32 port_index, buffer_id buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -278,26 +279,17 @@
         return reply.readInt32();
     }
 
-    virtual status_t observe_node(
-            node_id node, const sp<IOMXObserver> &observer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
-        data.writeStrongBinder(observer->asBinder());
-        remote()->transact(OBSERVE_NODE, data, &reply);
-
-        return reply.readInt32();
-    }
-
-    virtual void fill_buffer(node_id node, buffer_id buffer) {
+    virtual status_t fillBuffer(node_id node, buffer_id buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeIntPtr((intptr_t)node);
         data.writeIntPtr((intptr_t)buffer);
-        remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+        remote()->transact(FILL_BUFFER, data, &reply);
+
+        return reply.readInt32();
     }
 
-    virtual void empty_buffer(
+    virtual status_t emptyBuffer(
             node_id node,
             buffer_id buffer,
             OMX_U32 range_offset, OMX_U32 range_length,
@@ -310,10 +302,12 @@
         data.writeInt32(range_length);
         data.writeInt32(flags);
         data.writeInt64(timestamp);
-        remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+        remote()->transact(EMPTY_BUFFER, data, &reply);
+
+        return reply.readInt32();
     }
 
-    virtual status_t get_extension_index(
+    virtual status_t getExtensionIndex(
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index) {
@@ -375,7 +369,7 @@
             CHECK_INTERFACE(IOMX, data, reply);
 
             List<String8> list;
-            list_nodes(&list);
+            listNodes(&list);
 
             reply->writeInt32(list.size());
             for (List<String8>::iterator it = list.begin();
@@ -390,8 +384,14 @@
         {
             CHECK_INTERFACE(IOMX, data, reply);
 
+            const char *name = data.readCString();
+
+            sp<IOMXObserver> observer =
+                interface_cast<IOMXObserver>(data.readStrongBinder());
+
             node_id node;
-            status_t err = allocate_node(data.readCString(), &node);
+
+            status_t err = allocateNode(name, observer, &node);
             reply->writeInt32(err);
             if (err == OK) {
                 reply->writeIntPtr((intptr_t)node);
@@ -406,7 +406,7 @@
 
             node_id node = (void*)data.readIntPtr();
 
-            reply->writeInt32(free_node(node));
+            reply->writeInt32(freeNode(node));
                 
             return NO_ERROR;
         }
@@ -421,7 +421,7 @@
                 static_cast<OMX_COMMANDTYPE>(data.readInt32());
 
             OMX_S32 param = data.readInt32();
-            reply->writeInt32(send_command(node, cmd, param));
+            reply->writeInt32(sendCommand(node, cmd, param));
 
             return NO_ERROR;
         }
@@ -439,7 +439,7 @@
             void *params = malloc(size);
             data.read(params, size);
 
-            status_t err = get_parameter(node, index, params, size);
+            status_t err = getParameter(node, index, params, size);
 
             reply->writeInt32(err);
 
@@ -463,7 +463,7 @@
             size_t size = data.readInt32();
             void *params = const_cast<void *>(data.readInplace(size));
 
-            reply->writeInt32(set_parameter(node, index, params, size));
+            reply->writeInt32(setParameter(node, index, params, size));
 
             return NO_ERROR;
         }
@@ -481,7 +481,7 @@
             void *params = malloc(size);
             data.read(params, size);
 
-            status_t err = get_config(node, index, params, size);
+            status_t err = getConfig(node, index, params, size);
 
             reply->writeInt32(err);
 
@@ -505,7 +505,7 @@
             size_t size = data.readInt32();
             void *params = const_cast<void *>(data.readInplace(size));
 
-            reply->writeInt32(set_config(node, index, params, size));
+            reply->writeInt32(setConfig(node, index, params, size));
 
             return NO_ERROR;
         }
@@ -520,7 +520,7 @@
                 interface_cast<IMemory>(data.readStrongBinder());
 
             buffer_id buffer;
-            status_t err = use_buffer(node, port_index, params, &buffer);
+            status_t err = useBuffer(node, port_index, params, &buffer);
             reply->writeInt32(err);
 
             if (err == OK) {
@@ -539,7 +539,7 @@
             size_t size = data.readInt32();
 
             buffer_id buffer;
-            status_t err = allocate_buffer(node, port_index, size, &buffer);
+            status_t err = allocateBuffer(node, port_index, size, &buffer);
             reply->writeInt32(err);
 
             if (err == OK) {
@@ -559,7 +559,7 @@
                 interface_cast<IMemory>(data.readStrongBinder());
 
             buffer_id buffer;
-            status_t err = allocate_buffer_with_backup(
+            status_t err = allocateBufferWithBackup(
                     node, port_index, params, &buffer);
 
             reply->writeInt32(err);
@@ -578,19 +578,7 @@
             node_id node = (void*)data.readIntPtr();
             OMX_U32 port_index = data.readInt32();
             buffer_id buffer = (void*)data.readIntPtr();
-            reply->writeInt32(free_buffer(node, port_index, buffer));
-
-            return NO_ERROR;
-        }
-
-        case OBSERVE_NODE:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            node_id node = (void*)data.readIntPtr();
-            sp<IOMXObserver> observer =
-                interface_cast<IOMXObserver>(data.readStrongBinder());
-            reply->writeInt32(observe_node(node, observer));
+            reply->writeInt32(freeBuffer(node, port_index, buffer));
 
             return NO_ERROR;
         }
@@ -601,7 +589,7 @@
 
             node_id node = (void*)data.readIntPtr();
             buffer_id buffer = (void*)data.readIntPtr();
-            fill_buffer(node, buffer);
+            reply->writeInt32(fillBuffer(node, buffer));
 
             return NO_ERROR;
         }
@@ -617,9 +605,10 @@
             OMX_U32 flags = data.readInt32();
             OMX_TICKS timestamp = data.readInt64();
 
-            empty_buffer(
-                    node, buffer, range_offset, range_length,
-                    flags, timestamp);
+            reply->writeInt32(
+                    emptyBuffer(
+                        node, buffer, range_offset, range_length,
+                        flags, timestamp));
 
             return NO_ERROR;
         }
@@ -632,7 +621,7 @@
             const char *parameter_name = data.readCString();
             
             OMX_INDEXTYPE index;
-            status_t err = get_extension_index(node, parameter_name, &index);
+            status_t err = getExtensionIndex(node, parameter_name, &index);
 
             reply->writeInt32(err);
 
@@ -683,7 +672,7 @@
         : BpInterface<IOMXObserver>(impl) {
     }
 
-    virtual void on_message(const omx_message &msg) {
+    virtual void onMessage(const omx_message &msg) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
         data.write(&msg, sizeof(msg));
@@ -705,7 +694,7 @@
             data.read(&msg, sizeof(msg));
 
             // XXX Could use readInplace maybe?
-            on_message(msg);
+            onMessage(msg);
 
             return NO_ERROR;
         }
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f21eb73..6fc9fa2 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -18,8 +18,9 @@
 
 ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
 
-LOCAL_SRC_FILES +=              \
-    StagefrightPlayer.cpp
+LOCAL_SRC_FILES +=                      \
+    StagefrightPlayer.cpp               \
+    StagefrightMetadataRetriever.cpp
 
 LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1
 
@@ -50,7 +51,7 @@
 	$(JNI_H_INCLUDE)                                                \
 	$(call include-path-for, graphics corecg)                       \
 	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
-	$(TOP)/frameworks/base/media/libstagefright/omx
+	$(TOP)/frameworks/base/media/libstagefright/include
 
 LOCAL_MODULE:= libmediaplayerservice
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9d2c779..de5b542 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -284,8 +284,14 @@
     return c;
 }
 
-sp<IOMX> MediaPlayerService::createOMX() {
-    return new OMX;
+sp<IOMX> MediaPlayerService::getOMX() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mOMX.get() == NULL) {
+        mOMX = new OMX;
+    }
+
+    return mOMX;
 }
 
 status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
@@ -360,11 +366,44 @@
         size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
 extern "C" void free_malloc_leak_info(uint8_t* info);
 
+// Use the String-class below instead of String8 to allocate all memory
+// beforehand and not reenter the heap while we are examining it...
+struct MyString8 {
+    static const size_t MAX_SIZE = 256 * 1024;
+
+    MyString8()
+        : mPtr((char *)malloc(MAX_SIZE)) {
+        *mPtr = '\0';
+    }
+
+    ~MyString8() {
+        free(mPtr);
+    }
+
+    void append(const char *s) {
+        strcat(mPtr, s);
+    }
+
+    const char *string() const {
+        return mPtr;
+    }
+
+    size_t size() const {
+        return strlen(mPtr);
+    }
+
+private:
+    char *mPtr;
+
+    MyString8(const MyString8 &);
+    MyString8 &operator=(const MyString8 &);
+};
+
 void memStatus(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
-    String8 result;
+    MyString8 result;
 
     typedef struct {
         size_t size;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 43c4915..b00f5b7 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -185,7 +185,7 @@
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     virtual sp<IMemory>         snoop();
-    virtual sp<IOMX>            createOMX();
+    virtual sp<IOMX>            getOMX();
 
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
@@ -284,6 +284,7 @@
                 SortedVector< wp<Client> >  mClients;
                 SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients;
                 int32_t                     mNextConnId;
+                sp<IOMX>                    mOMX;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 8eabe5d..866c7bd 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -38,6 +38,7 @@
 #include "VorbisMetadataRetriever.h"
 #include "MidiMetadataRetriever.h"
 #include "MetadataRetrieverClient.h"
+#include "StagefrightMetadataRetriever.h"
 
 /* desktop Linux needs a little help with gettid() */
 #if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
@@ -118,9 +119,15 @@
             LOGV("create midi metadata retriever");
             p = new MidiMetadataRetriever();
             break;
+#if BUILD_WITH_FULL_STAGEFRIGHT
+        case STAGEFRIGHT_PLAYER:
+            LOGV("create StagefrightMetadataRetriever");
+            p = new StagefrightMetadataRetriever;
+            break;
+#endif
         default:
             // TODO:
-            // support for STAGEFRIGHT_PLAYER and TEST_PLAYER
+            // support for TEST_PLAYER
             LOGE("player type %d is not supported",  playerType);
             break;
     }
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
new file mode 100644
index 0000000..7a3aee8
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -0,0 +1,197 @@
+/*
+**
+** Copyright 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 "StagefrightMetadataRetriever"
+#include <utils/Log.h>
+
+#include "StagefrightMetadataRetriever.h"
+
+#include <media/stagefright/CachingDataSource.h>
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPDataSource.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>
+
+namespace android {
+
+StagefrightMetadataRetriever::StagefrightMetadataRetriever() {
+    LOGV("StagefrightMetadataRetriever()");
+
+    DataSource::RegisterDefaultSniffers();
+    CHECK_EQ(mClient.connect(), OK);
+}
+
+StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
+    LOGV("~StagefrightMetadataRetriever()");
+    mClient.disconnect();
+}
+
+status_t StagefrightMetadataRetriever::setDataSource(const char *uri) {
+    LOGV("setDataSource(%s)", uri);
+
+    mExtractor = MediaExtractor::CreateFromURI(uri);
+
+    return mExtractor.get() != NULL ? OK : UNKNOWN_ERROR;
+}
+
+status_t StagefrightMetadataRetriever::setDataSource(
+        int fd, int64_t offset, int64_t length) {
+    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+
+    mExtractor = MediaExtractor::Create(
+            new MmapSource(fd, offset, length));
+
+    return OK;
+}
+
+VideoFrame *StagefrightMetadataRetriever::captureFrame() {
+    LOGV("captureFrame");
+
+    if (mExtractor.get() == NULL) {
+        LOGV("no extractor.");
+        return NULL;
+    }
+
+    size_t n = mExtractor->countTracks();
+    size_t i;
+    for (i = 0; i < n; ++i) {
+        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+        if (!strncasecmp(mime, "video/", 6)) {
+            break;
+        }
+    }
+
+    if (i == n) {
+        LOGV("no video track found.");
+        return NULL;
+    }
+
+    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
+            i, MediaExtractor::kIncludeExtensiveMetaData);
+
+    sp<MediaSource> source = mExtractor->getTrack(i);
+
+    if (source.get() == NULL) {
+        LOGV("unable to instantiate video track.");
+        return NULL;
+    }
+
+    sp<MetaData> meta = source->getFormat();
+
+    sp<MediaSource> decoder =
+        OMXCodec::Create(
+                mClient.interface(), meta, false, source,
+                NULL, OMXCodec::kPreferSoftwareCodecs);
+
+    if (decoder.get() == NULL) {
+        LOGV("unable to instantiate video decoder.");
+
+        return NULL;
+    }
+
+    decoder->start();
+
+    // Read one output buffer, ignore format change notifications
+    // and spurious empty buffers.
+
+    MediaSource::ReadOptions options;
+    int64_t thumbNailTime;
+    if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
+        options.setSeekTo(thumbNailTime);
+    }
+
+    MediaBuffer *buffer = NULL;
+    status_t err;
+    do {
+        if (buffer != NULL) {
+            buffer->release();
+            buffer = NULL;
+        }
+        err = decoder->read(&buffer, &options);
+        options.clearSeekTo();
+    } while (err == INFO_FORMAT_CHANGED
+             || (buffer != NULL && buffer->range_length() == 0));
+
+    if (err != OK) {
+        CHECK_EQ(buffer, NULL);
+
+        LOGV("decoding frame failed.");
+        decoder->stop();
+
+        return NULL;
+    }
+
+    LOGV("successfully decoded video frame.");
+
+    meta = decoder->getFormat();
+
+    int32_t width, height;
+    CHECK(meta->findInt32(kKeyWidth, &width));
+    CHECK(meta->findInt32(kKeyHeight, &height));
+
+    VideoFrame *frame = new VideoFrame;
+    frame->mWidth = width;
+    frame->mHeight = height;
+    frame->mDisplayWidth = width;
+    frame->mDisplayHeight = height;
+    frame->mSize = width * height * 2;
+    frame->mData = new uint8_t[frame->mSize];
+
+    int32_t srcFormat;
+    CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
+
+    ColorConverter converter(
+            (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
+    CHECK(converter.isValid());
+
+    converter.convert(
+            width, height,
+            (const uint8_t *)buffer->data() + buffer->range_offset(),
+            0,
+            frame->mData, width * 2);
+
+    buffer->release();
+    buffer = NULL;
+
+    decoder->stop();
+
+    return frame;
+}
+
+MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
+    LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
+
+    return NULL;
+}
+
+const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
+    LOGV("extractMetadata %d (extractor: %s)",
+         keyCode, mExtractor.get() != NULL ? "YES" : "NO");
+
+    return NULL;
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.h b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
new file mode 100644
index 0000000..16127d7
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
@@ -0,0 +1,53 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef STAGEFRIGHT_METADATA_RETRIEVER_H_
+
+#define STAGEFRIGHT_METADATA_RETRIEVER_H_
+
+#include <media/MediaMetadataRetrieverInterface.h>
+
+#include <media/stagefright/OMXClient.h>
+
+namespace android {
+
+class MediaExtractor;
+
+struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface {
+    StagefrightMetadataRetriever();
+    virtual ~StagefrightMetadataRetriever();
+
+    virtual status_t setDataSource(const char *url);
+    virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+
+    virtual VideoFrame *captureFrame();
+    virtual MediaAlbumArt *extractAlbumArt();
+    virtual const char *extractMetadata(int keyCode);
+
+private:
+    OMXClient mClient;
+    sp<MediaExtractor> mExtractor;
+
+    StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
+
+    StagefrightMetadataRetriever &operator=(
+            const StagefrightMetadataRetriever &);
+};
+
+}  // namespace android
+
+#endif  // STAGEFRIGHT_METADATA_RETRIEVER_H_
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
index 8627708..aa49429 100644
--- a/media/libmediaplayerservice/TestPlayerStub.cpp
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -176,7 +176,7 @@
     mContentUrl = NULL;
 
     if (mPlayer) {
-        LOG_ASSERT(mDeletePlayer != NULL);
+        LOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null");
         (*mDeletePlayer)(mPlayer);
         mPlayer = NULL;
     }
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 8d85ce2..1e3c5a4 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -18,7 +18,8 @@
 #define LOG_TAG "AMRExtractor"
 #include <utils/Log.h>
 
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
@@ -86,7 +87,7 @@
     return new AMRSource(mDataSource, mIsWide);
 }
 
-sp<MetaData> AMRExtractor::getTrackMetaData(size_t index) {
+sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -155,7 +156,7 @@
     *out = NULL;
 
     uint8_t header;
-    ssize_t n = mDataSource->read_at(mOffset, &header, 1);
+    ssize_t n = mDataSource->readAt(mOffset, &header, 1);
 
     if (n < 1) {
         return ERROR_IO;
@@ -191,7 +192,7 @@
     // Round up bits to bytes and add 1 for the header byte.
     frameSize = (frameSize + 7) / 8 + 1;
 
-    n = mDataSource->read_at(mOffset, buffer->data(), frameSize);
+    n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
 
     if (n != (ssize_t)frameSize) {
         buffer->release();
@@ -201,10 +202,7 @@
     }
 
     buffer->set_range(0, frameSize);
-    buffer->meta_data()->setInt32(
-            kKeyTimeUnits, (mCurrentTimeUs + 500) / 1000);
-    buffer->meta_data()->setInt32(
-            kKeyTimeScale, 1000);
+    buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
 
     mOffset += frameSize;
     mCurrentTimeUs += 20000;  // Each frame is 20ms
@@ -220,7 +218,7 @@
         const sp<DataSource> &source, String8 *mimeType, float *confidence) {
     char header[9];
 
-    if (source->read_at(0, header, sizeof(header)) != sizeof(header)) {
+    if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
         return false;
     }
 
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 3c343a3..b774609 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -17,6 +17,7 @@
 LOCAL_SRC_FILES +=                \
         AMRExtractor.cpp          \
         CachingDataSource.cpp     \
+        CameraSource.cpp          \
         DataSource.cpp            \
         FileSource.cpp            \
         HTTPDataSource.cpp        \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 319488e..7b4d178 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -209,15 +209,9 @@
                 break;
             }
 
-            int32_t units, scale;
-            bool success =
-                mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units);
-            success = success &&
-                mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale);
-            CHECK(success);
-
             Mutex::Autolock autoLock(mLock);
-            mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+            CHECK(mInputBuffer->meta_data()->findInt64(
+                        kKeyTime, &mPositionTimeMediaUs));
 
             mPositionTimeRealUs =
                 ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
index fd00576..23f4897 100644
--- a/media/libstagefright/CachingDataSource.cpp
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -61,11 +61,11 @@
     mData = NULL;
 }
 
-status_t CachingDataSource::InitCheck() const {
-    return OK;
+status_t CachingDataSource::initCheck() const {
+    return mSource->initCheck();
 }
 
-ssize_t CachingDataSource::read_at(off_t offset, void *data, size_t size) {
+ssize_t CachingDataSource::readAt(off_t offset, void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
     size_t total = 0;
@@ -82,7 +82,7 @@
         if (page == NULL) {
             page = allocate_page();
             page->mOffset = offset - offset % mPageSize;
-            ssize_t n = mSource->read_at(page->mOffset, page->mData, mPageSize);
+            ssize_t n = mSource->readAt(page->mOffset, page->mData, mPageSize);
             if (n < 0) {
                 page->mLength = 0;
             } else {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 596ab67..e9d8557 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -21,120 +21,142 @@
 #include <binder/IServiceManager.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
-#include <ui/ICameraClient.h>
-#include <ui/ICameraService.h>
+#include <ui/Camera.h>
+#include <ui/CameraParameters.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/ISurface.h>
 #include <ui/Overlay.h>
-#include <utils/String16.h>
+#include <utils/String8.h>
 
 namespace android {
 
-class CameraBuffer : public MediaBuffer {
-public:
-    CameraBuffer(const sp<IMemory> &frame)
-        : MediaBuffer(frame->pointer(), frame->size()),
-          mFrame(frame) {
-    }
+static int64_t getNowUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
 
-    sp<IMemory> releaseFrame() {
-        sp<IMemory> frame = mFrame;
-        mFrame.clear();
-        return frame;
-    }
+    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
+}
 
-private:
-    sp<IMemory> mFrame;
-};
-
-class CameraSourceClient : public BnCameraClient {
-public:
-    CameraSourceClient()
-        : mSource(NULL) {
-    }
-
-    virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
-        CHECK(mSource != NULL);
-        mSource->notifyCallback(msgType, ext1, ext2);
-    }
-
-    virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {
-        CHECK(mSource != NULL);
-        mSource->dataCallback(msgType, data);
-    }
-
-    void setCameraSource(CameraSource *source) {
-        mSource = source;
-    }
-
-private:
-    CameraSource *mSource;
-};
-
-class DummySurface : public BnSurface {
-public:
+struct DummySurface : public BnSurface {
     DummySurface() {}
 
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) {
+        return NULL;
+    }
+
     virtual status_t registerBuffers(const BufferHeap &buffers) {
         return OK;
     }
 
-    virtual void postBuffer(ssize_t offset) {
-    }
+    virtual void postBuffer(ssize_t offset) {}
+    virtual void unregisterBuffers() {}
 
-    virtual void unregisterBuffers() {
-    }
-    
     virtual sp<OverlayRef> createOverlay(
             uint32_t w, uint32_t h, int32_t format) {
         return NULL;
     }
+
+protected:
+    virtual ~DummySurface() {}
+
+    DummySurface(const DummySurface &);
+    DummySurface &operator=(const DummySurface &);
 };
 
+struct CameraSourceListener : public CameraListener {
+    CameraSourceListener(const sp<CameraSource> &source);
+
+    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
+    virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr);
+
+    virtual void postDataTimestamp(
+            nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+
+protected:
+    virtual ~CameraSourceListener();
+
+private:
+    wp<CameraSource> mSource;
+
+    CameraSourceListener(const CameraSourceListener &);
+    CameraSourceListener &operator=(const CameraSourceListener &);
+};
+
+CameraSourceListener::CameraSourceListener(const sp<CameraSource> &source)
+    : mSource(source) {
+}
+
+CameraSourceListener::~CameraSourceListener() {
+}
+
+void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
+    LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
+}
+
+void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr) {
+    LOGV("postData(%d, ptr:%p, size:%d)",
+         msgType, dataPtr->pointer(), dataPtr->size());
+
+    sp<CameraSource> source = mSource.promote();
+    if (source.get() != NULL) {
+        source->dataCallback(msgType, dataPtr);
+    }
+}
+
+void CameraSourceListener::postDataTimestamp(
+        nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
+    LOGV("postDataTimestamp(%lld, %d, ptr:%p, size:%d)",
+         timestamp, msgType, dataPtr->pointer(), dataPtr->size());
+}
+
 // static
 CameraSource *CameraSource::Create() {
-    sp<IServiceManager> sm = defaultServiceManager();
+    sp<Camera> camera = Camera::connect();
 
-    sp<ICameraService> service =
-        interface_cast<ICameraService>(
-                sm->getService(String16("media.camera")));
+    if (camera.get() == NULL) {
+        return NULL;
+    }
 
-    sp<CameraSourceClient> client = new CameraSourceClient;
-    sp<ICamera> camera = service->connect(client);
-
-    CameraSource *source = new CameraSource(camera, client);
-    client->setCameraSource(source);
-
-    return source;
+    return new CameraSource(camera);
 }
 
-CameraSource::CameraSource(
-        const sp<ICamera> &camera, const sp<ICameraClient> &client)
+CameraSource::CameraSource(const sp<Camera> &camera)
     : mCamera(camera),
-      mCameraClient(client),
+      mWidth(0),
+      mHeight(0),
+      mFirstFrameTimeUs(0),
       mNumFrames(0),
       mStarted(false) {
-    printf("params: \"%s\"\n", mCamera->getParameters().string());
+    String8 s = mCamera->getParameters();
+    printf("params: \"%s\"\n", s.string());
+
+    CameraParameters params(s);
+    params.getPreviewSize(&mWidth, &mHeight);
 }
 
 CameraSource::~CameraSource() {
     if (mStarted) {
         stop();
     }
-
-    mCamera->disconnect();
 }
 
 status_t CameraSource::start(MetaData *) {
     CHECK(!mStarted);
 
-    status_t err = mCamera->lock();
+    mCamera->setListener(new CameraSourceListener(this));
+
+    sp<ISurface> dummy = new DummySurface;
+    status_t err = mCamera->setPreviewDisplay(dummy);
     CHECK_EQ(err, OK);
 
-    err = mCamera->setPreviewDisplay(new DummySurface);
-    CHECK_EQ(err, OK);
-    mCamera->setPreviewCallbackFlag(1);
-    mCamera->startPreview();
+    mCamera->setPreviewCallbackFlags(
+            FRAME_CALLBACK_FLAG_ENABLE_MASK
+            | FRAME_CALLBACK_FLAG_COPY_OUT_MASK);
+
+    err = mCamera->startPreview();
     CHECK_EQ(err, OK);
 
     mStarted = true;
@@ -146,7 +168,6 @@
     CHECK(mStarted);
 
     mCamera->stopPreview();
-    mCamera->unlock();
 
     mStarted = false;
 
@@ -157,8 +178,8 @@
     sp<MetaData> meta = new MetaData;
     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
     meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
-    meta->setInt32(kKeyWidth, 480);
-    meta->setInt32(kKeyHeight, 320);
+    meta->setInt32(kKeyWidth, mWidth);
+    meta->setInt32(kKeyHeight, mHeight);
 
     return meta;
 }
@@ -175,6 +196,7 @@
     }
 
     sp<IMemory> frame;
+    int64_t frameTime;
 
     {
         Mutex::Autolock autoLock(mLock);
@@ -184,41 +206,33 @@
 
         frame = *mFrames.begin();
         mFrames.erase(mFrames.begin());
+
+        frameTime = *mFrameTimes.begin();
+        mFrameTimes.erase(mFrameTimes.begin());
     }
 
-    int count = mNumFrames++;
-
-    *buffer = new CameraBuffer(frame);
+    *buffer = new MediaBuffer(frame->size());
+    memcpy((*buffer)->data(), frame->pointer(), frame->size());
+    (*buffer)->set_range(0, frame->size());
 
     (*buffer)->meta_data()->clear();
-    (*buffer)->meta_data()->setInt32(kKeyTimeScale, 15);
-    (*buffer)->meta_data()->setInt32(kKeyTimeUnits, count);
-
-    (*buffer)->add_ref();
-    (*buffer)->setObserver(this);
+    (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
 
     return OK;
 }
 
-void CameraSource::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
-    printf("notifyCallback %d, %d, %d\n", msgType, ext1, ext2);
-}
-
 void CameraSource::dataCallback(int32_t msgType, const sp<IMemory> &data) {
     Mutex::Autolock autoLock(mLock);
 
+    int64_t nowUs = getNowUs();
+    if (mNumFrames == 0) {
+        mFirstFrameTimeUs = nowUs;
+    }
+    ++mNumFrames;
+
     mFrames.push_back(data);
+    mFrameTimes.push_back(nowUs - mFirstFrameTimeUs);
     mFrameAvailableCondition.signal();
 }
 
-void CameraSource::signalBufferReturned(MediaBuffer *_buffer) {
-    CameraBuffer *buffer = static_cast<CameraBuffer *>(_buffer);
-
-    mCamera->releaseRecordingFrame(buffer->releaseFrame());
-
-    buffer->setObserver(NULL);
-    buffer->release();
-    buffer = NULL;
-}
-
 }  // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index daac539..210b2f6 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+#include "include/MP3Extractor.h"
+#include "include/MPEG4Extractor.h"
+
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MP3Extractor.h>
-#include <media/stagefright/MPEG4Extractor.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -27,7 +28,7 @@
     *x = 0;
 
     uint8_t byte[2];
-    if (read_at(offset, byte, 2) != 2) {
+    if (readAt(offset, byte, 2) != 2) {
         return false;
     }
 
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
index 53b92a0..28d338c 100644
--- a/media/libstagefright/ESDS.cpp
+++ b/media/libstagefright/ESDS.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/ESDS.h>
+#include "include/ESDS.h"
 
 #include <string.h>
 
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index f6b90b2..f318ee3 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -30,11 +30,11 @@
     }
 }
 
-status_t FileSource::InitCheck() const {
+status_t FileSource::initCheck() const {
     return mFile != NULL ? OK : NO_INIT;
 }
 
-ssize_t FileSource::read_at(off_t offset, void *data, size_t size) {
+ssize_t FileSource::readAt(off_t offset, void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
     int err = fseeko(mFile, offset, SEEK_SET);
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 698223b..5536801 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -14,17 +14,19 @@
  * limitations under the License.
  */
 
+#include "include/stagefright_string.h"
+#include "include/HTTPStream.h"
+
 #include <stdlib.h>
 
 #include <media/stagefright/HTTPDataSource.h>
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/string.h>
 
 namespace android {
 
 HTTPDataSource::HTTPDataSource(const char *uri)
-    : mHost(NULL),
+    : mHttp(new HTTPStream),
+      mHost(NULL),
       mPort(0),
       mPath(NULL),
       mBuffer(malloc(kBufferSize)),
@@ -65,33 +67,40 @@
     mPort = port;
     mPath = strdup(path.c_str());
 
-    status_t err = mHttp.connect(mHost, mPort);
-    CHECK_EQ(err, OK);
+    mInitCheck = mHttp->connect(mHost, mPort);
 }
 
 HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
-    : mHost(strdup(host)),
+    : mHttp(new HTTPStream),
+      mHost(strdup(host)),
       mPort(port),
       mPath(strdup(path)),
       mBuffer(malloc(kBufferSize)),
       mBufferLength(0),
       mBufferOffset(0) {
-    status_t err = mHttp.connect(mHost, mPort);
-    CHECK_EQ(err, OK);
+    mInitCheck = mHttp->connect(mHost, mPort);
+}
+
+status_t HTTPDataSource::initCheck() const {
+    return mInitCheck;
 }
 
 HTTPDataSource::~HTTPDataSource() {
-    mHttp.disconnect();
+    mHttp->disconnect();
 
     free(mBuffer);
     mBuffer = NULL;
 
     free(mPath);
     mPath = NULL;
+
+    delete mHttp;
+    mHttp = NULL;
 }
 
-ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
-    if (offset >= mBufferOffset && offset < mBufferOffset + mBufferLength) {
+ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
+    if (offset >= mBufferOffset
+            && offset < (off_t)(mBufferOffset + mBufferLength)) {
         size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
 
         size_t copy = num_bytes_available;
@@ -119,19 +128,19 @@
     status_t err;
     int attempt = 1;
     for (;;) {
-        if ((err = mHttp.send("GET ")) != OK
-            || (err = mHttp.send(mPath)) != OK
-            || (err = mHttp.send(" HTTP/1.1\r\n")) != OK
-            || (err = mHttp.send(host)) != OK
-            || (err = mHttp.send(range)) != OK
-            || (err = mHttp.send("\r\n")) != OK
-            || (err = mHttp.receive_header(&http_status)) != OK) {
+        if ((err = mHttp->send("GET ")) != OK
+            || (err = mHttp->send(mPath)) != OK
+            || (err = mHttp->send(" HTTP/1.1\r\n")) != OK
+            || (err = mHttp->send(host)) != OK
+            || (err = mHttp->send(range)) != OK
+            || (err = mHttp->send("\r\n")) != OK
+            || (err = mHttp->receive_header(&http_status)) != OK) {
 
             if (attempt == 3) {
                 return err;
             }
 
-            mHttp.connect(mHost, mPort);
+            mHttp->connect(mHost, mPort);
             ++attempt;
         } else {
             break;
@@ -143,14 +152,14 @@
     }
 
     string value;
-    if (!mHttp.find_header_value("Content-Length", &value)) {
+    if (!mHttp->find_header_value("Content-Length", &value)) {
         return UNKNOWN_ERROR;
     }
 
     char *end;
     unsigned long contentLength = strtoul(value.c_str(), &end, 10);
 
-    ssize_t num_bytes_received = mHttp.receive(mBuffer, contentLength);
+    ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
 
     if (num_bytes_received <= 0) {
         return num_bytes_received;
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 6af7df9..02f9439 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "include/HTTPStream.h"
+
 #include <sys/socket.h>
 
 #include <arpa/inet.h>
@@ -25,7 +27,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaDebug.h>
 
 namespace android {
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index d1dfd83..a4be2dd 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -119,7 +119,7 @@
     MediaBuffer *buffer;
     mGroup->acquire_buffer(&buffer);
 
-    ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset);
+    ssize_t n = mSource->readAt(mOffset, buffer->data(), mSize - mOffset);
 
     if (n <= 0) {
         buffer->release();
@@ -156,13 +156,13 @@
 
     for (;;) {
         uint8_t marker;
-        if (mSource->read_at(i++, &marker, 1) != 1) {
+        if (mSource->readAt(i++, &marker, 1) != 1) {
             return ERROR_IO;
         }
 
         CHECK_EQ(marker, 0xff);
 
-        if (mSource->read_at(i++, &marker, 1) != 1) {
+        if (mSource->readAt(i++, &marker, 1) != 1) {
             return ERROR_IO;
         }
 
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 7fd699f..736f1a9 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -18,8 +18,9 @@
 #define LOG_TAG "MP3Extractor"
 #include <utils/Log.h>
 
+#include "include/MP3Extractor.h"
+
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/MP3Extractor.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
@@ -147,7 +148,12 @@
             *out_bitrate = bitrate;
         }
 
-        *frame_size = 144000 * bitrate / sampling_rate + padding;
+        if (version == 3 /* V1 */) {
+            *frame_size = 144000 * bitrate / sampling_rate + padding;
+        } else {
+            // V2 or V2.5
+            *frame_size = 72000 * bitrate / sampling_rate + padding;
+        }
     }
 
     if (out_sampling_rate) {
@@ -166,6 +172,33 @@
 static bool Resync(
         const sp<DataSource> &source, uint32_t match_header,
         off_t *inout_pos, uint32_t *out_header) {
+    if (*inout_pos == 0) {
+        // Skip an optional ID3 header if syncing at the very beginning
+        // of the datasource.
+
+        uint8_t id3header[10];
+        if (source->readAt(0, id3header, sizeof(id3header))
+                < (ssize_t)sizeof(id3header)) {
+            // If we can't even read these 10 bytes, we might as well bail out,
+            // even if there _were_ 10 bytes of valid mp3 audio data...
+            return false;
+        }
+
+        if (id3header[0] == 'I' && id3header[1] == 'D' && id3header[2] == '3') {
+            // Skip the ID3v2 header.
+
+            size_t len =
+                ((id3header[6] & 0x7f) << 21)
+                | ((id3header[7] & 0x7f) << 14)
+                | ((id3header[8] & 0x7f) << 7)
+                | (id3header[9] & 0x7f);
+
+            len += 10;
+
+            *inout_pos += len;
+        }
+    }
+
     // Everything must match except for
     // protection, bitrate, padding, private bits and mode extension.
     const uint32_t kMask = 0xfffe0ccf;
@@ -195,7 +228,7 @@
             buffer_length = buffer_length - buffer_offset;
             buffer_offset = 0;
 
-            ssize_t n = source->read_at(
+            ssize_t n = source->readAt(
                     pos, &buffer[buffer_length], kMaxFrameSize - buffer_length);
 
             if (n <= 0) {
@@ -232,7 +265,7 @@
         valid = true;
         for (int j = 0; j < 3; ++j) {
             uint8_t tmp[4];
-            if (source->read_at(test_pos, tmp, 4) < 4) {
+            if (source->readAt(test_pos, tmp, 4) < 4) {
                 valid = false;
                 break;
             }
@@ -338,10 +371,9 @@
 
         off_t fileSize;
         if (mDataSource->getSize(&fileSize) == OK) {
-            mMeta->setInt32(
+            mMeta->setInt64(
                     kKeyDuration,
-                    8 * (fileSize - mFirstFramePos) / bitrate);
-            mMeta->setInt32(kKeyTimeScale, 1000);
+                    8000 * (fileSize - mFirstFramePos) / bitrate);
         }
     }
 }
@@ -362,7 +394,7 @@
             mMeta, mDataSource, mFirstFramePos, mFixedHeader);
 }
 
-sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
+sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
     if (mFirstFramePos < 0 || index != 0) {
         return NULL;
     }
@@ -448,7 +480,7 @@
 
     size_t frame_size;
     for (;;) {
-        ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), 4);
+        ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), 4);
         if (n < 4) {
             buffer->release();
             buffer = NULL;
@@ -482,7 +514,7 @@
 
     CHECK(frame_size <= buffer->size());
 
-    ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), frame_size);
+    ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), frame_size);
     if (n < (ssize_t)frame_size) {
         buffer->release();
         buffer = NULL;
@@ -492,8 +524,7 @@
 
     buffer->set_range(0, frame_size);
 
-    buffer->meta_data()->setInt32(kKeyTimeUnits, mCurrentTimeUs / 1000);
-    buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+    buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
 
     mCurrentPos += frame_size;
     mCurrentTimeUs += 1152 * 1000000 / 44100;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 9174d19..5c3720e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -17,6 +17,9 @@
 #define LOG_TAG "MPEG4Extractor"
 #include <utils/Log.h>
 
+#include "include/MPEG4Extractor.h"
+#include "include/SampleTable.h"
+
 #include <arpa/inet.h>
 
 #include <ctype.h>
@@ -25,14 +28,12 @@
 #include <string.h>
 
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/MPEG4Extractor.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/SampleTable.h>
 #include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
@@ -43,6 +44,7 @@
     // Caller retains ownership of both "dataSource" and "sampleTable".
     MPEG4Source(const sp<MetaData> &format,
                 const sp<DataSource> &dataSource,
+                int32_t timeScale,
                 const sp<SampleTable> &sampleTable);
 
     virtual status_t start(MetaData *params = NULL);
@@ -177,7 +179,8 @@
     return n;
 }
 
-sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
+sp<MetaData> MPEG4Extractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
     status_t err;
     if ((err = readMetaData()) != OK) {
         return NULL;
@@ -197,6 +200,25 @@
         return NULL;
     }
 
+    if ((flags & kIncludeExtensiveMetaData)
+            && !track->includes_expensive_metadata) {
+        track->includes_expensive_metadata = true;
+
+        const char *mime;
+        CHECK(track->meta->findCString(kKeyMIMEType, &mime));
+        if (!strncasecmp("video/", mime, 6)) {
+            uint32_t sampleIndex;
+            uint32_t sampleTime;
+            if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
+                    && track->sampleTable->getDecodingTime(
+                        sampleIndex, &sampleTime) == OK) {
+                track->meta->setInt64(
+                        kKeyThumbnailTime,
+                        ((int64_t)sampleTime * 1000000) / track->timescale);
+            }
+        }
+    }
+
     return track->meta;
 }
 
@@ -227,7 +249,7 @@
 
 status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
     uint32_t hdr[2];
-    if (mDataSource->read_at(*offset, hdr, 8) < 8) {
+    if (mDataSource->readAt(*offset, hdr, 8) < 8) {
         return ERROR_IO;
     }
     uint64_t chunk_size = ntohl(hdr[0]);
@@ -235,7 +257,7 @@
     off_t data_offset = *offset + 8;
 
     if (chunk_size == 1) {
-        if (mDataSource->read_at(*offset + 8, &chunk_size, 8) < 8) {
+        if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
             return ERROR_IO;
         }
         chunk_size = ntoh64(chunk_size);
@@ -252,7 +274,7 @@
 
     char buffer[256];
     if (chunk_size <= sizeof(buffer)) {
-        if (mDataSource->read_at(*offset, buffer, chunk_size) < chunk_size) {
+        if (mDataSource->readAt(*offset, buffer, chunk_size) < chunk_size) {
             return ERROR_IO;
         }
 
@@ -298,7 +320,7 @@
             CHECK(chunk_data_size >= 4);
 
             uint8_t version;
-            if (mDataSource->read_at(data_offset, &version, 1) < 1) {
+            if (mDataSource->readAt(data_offset, &version, 1) < 1) {
                 return ERROR_IO;
             }
 
@@ -312,7 +334,7 @@
                 }
 
                 uint8_t buffer[36 + 60];
-                if (mDataSource->read_at(
+                if (mDataSource->readAt(
                             data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
                     return ERROR_IO;
                 }
@@ -329,7 +351,7 @@
                 }
 
                 uint8_t buffer[24 + 60];
-                if (mDataSource->read_at(
+                if (mDataSource->readAt(
                             data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
                     return ERROR_IO;
                 }
@@ -351,6 +373,7 @@
             mLastTrack = track;
 
             track->meta = new MetaData;
+            track->includes_expensive_metadata = false;
             track->timescale = 0;
             track->sampleTable = new SampleTable(mDataSource);
             track->meta->setCString(kKeyMIMEType, "application/octet-stream");
@@ -366,7 +389,7 @@
             }
 
             uint8_t version;
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         data_offset, &version, sizeof(version))
                     < (ssize_t)sizeof(version)) {
                 return ERROR_IO;
@@ -383,18 +406,17 @@
             }
 
             uint32_t timescale;
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         timescale_offset, &timescale, sizeof(timescale))
                     < (ssize_t)sizeof(timescale)) {
                 return ERROR_IO;
             }
 
             mLastTrack->timescale = ntohl(timescale);
-            mLastTrack->meta->setInt32(kKeyTimeScale, mLastTrack->timescale);
 
             int64_t duration;
             if (version == 1) {
-                if (mDataSource->read_at(
+                if (mDataSource->readAt(
                             timescale_offset + 4, &duration, sizeof(duration))
                         < (ssize_t)sizeof(duration)) {
                     return ERROR_IO;
@@ -402,14 +424,15 @@
                 duration = ntoh64(duration);
             } else {
                 int32_t duration32;
-                if (mDataSource->read_at(
+                if (mDataSource->readAt(
                             timescale_offset + 4, &duration32, sizeof(duration32))
                         < (ssize_t)sizeof(duration32)) {
                     return ERROR_IO;
                 }
                 duration = ntohl(duration32);
             }
-            mLastTrack->meta->setInt32(kKeyDuration, duration);
+            mLastTrack->meta->setInt64(
+                    kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
 
             *offset += chunk_size;
             break;
@@ -422,7 +445,7 @@
             }
 
             uint8_t buffer[24];
-            if (mDataSource->read_at(data_offset, buffer, 24) < 24) {
+            if (mDataSource->readAt(data_offset, buffer, 24) < 24) {
                 return ERROR_IO;
             }
 
@@ -449,7 +472,7 @@
 
             uint8_t buffer[8];
             CHECK(chunk_data_size >= (off_t)sizeof(buffer));
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         data_offset, buffer, 8) < 8) {
                 return ERROR_IO;
             }
@@ -492,7 +515,7 @@
                 return ERROR_MALFORMED;
             }
 
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
                 return ERROR_IO;
             }
@@ -544,7 +567,7 @@
                 return ERROR_MALFORMED;
             }
 
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
                 return ERROR_IO;
             }
@@ -655,7 +678,7 @@
                 return ERROR_BUFFER_TOO_SMALL;
             }
 
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         data_offset, buffer, chunk_data_size) < chunk_data_size) {
                 return ERROR_IO;
             }
@@ -679,7 +702,7 @@
                 return ERROR_BUFFER_TOO_SMALL;
             }
 
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         data_offset, buffer, chunk_data_size) < chunk_data_size) {
                 return ERROR_IO;
             }
@@ -722,7 +745,7 @@
     }
 
     return new MPEG4Source(
-            track->meta, mDataSource, track->sampleTable);
+            track->meta, mDataSource, track->timescale, track->sampleTable);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -730,10 +753,11 @@
 MPEG4Source::MPEG4Source(
         const sp<MetaData> &format,
         const sp<DataSource> &dataSource,
+        int32_t timeScale,
         const sp<SampleTable> &sampleTable)
     : mFormat(format),
       mDataSource(dataSource),
-      mTimescale(0),
+      mTimescale(timeScale),
       mSampleTable(sampleTable),
       mCurrentSampleIndex(0),
       mIsAVC(false),
@@ -746,9 +770,6 @@
     bool success = mFormat->findCString(kKeyMIMEType, &mime);
     CHECK(success);
 
-    success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
-    CHECK(success);
-
     mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
 }
 
@@ -868,7 +889,7 @@
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
             ssize_t num_bytes_read =
-                mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
+                mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
             if (num_bytes_read < (ssize_t)size) {
                 mBuffer->release();
@@ -879,8 +900,8 @@
 
             mBuffer->set_range(0, size);
             mBuffer->meta_data()->clear();
-            mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
-            mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+            mBuffer->meta_data()->setInt64(
+                    kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
             ++mCurrentSampleIndex;
         }
 
@@ -923,7 +944,7 @@
         // the start code (0x00 00 00 01).
 
         ssize_t num_bytes_read =
-            mDataSource->read_at(offset, mSrcBuffer, size);
+            mDataSource->readAt(offset, mSrcBuffer, size);
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
@@ -959,8 +980,8 @@
 
         mBuffer->set_range(0, dstOffset);
         mBuffer->meta_data()->clear();
-        mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
-        mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+        mBuffer->meta_data()->setInt64(
+                kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
         ++mCurrentSampleIndex;
 
         *out = mBuffer;
@@ -974,7 +995,7 @@
         const sp<DataSource> &source, String8 *mimeType, float *confidence) {
     uint8_t header[8];
 
-    ssize_t n = source->read_at(4, header, sizeof(header));
+    ssize_t n = source->readAt(4, header, sizeof(header));
     if (n < (ssize_t)sizeof(header)) {
         return false;
     }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index fa35768..9a7a873 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -399,15 +399,11 @@
         info.size = buffer->range_length();
         info.offset = offset;
 
-        int32_t units, scale;
-        bool success =
-            buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
-        CHECK(success);
-        success =
-            buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
-        CHECK(success);
+        int64_t timestampUs;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
 
-        info.timestamp = (int64_t)units * 1000 / scale;
+        // Our timestamp is in ms.
+        info.timestamp = (timestampUs + 500) / 1000;
 
         mSampleInfos.push_back(info);
 
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index f3c0e73..b973745 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -108,10 +108,10 @@
 }
 
 void MediaBuffer::set_range(size_t offset, size_t length) {
-    if (offset < 0 || offset + length > mSize) {
+    if (offset + length > mSize) {
         LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
     }
-    CHECK(offset >= 0 && offset + length <= mSize);
+    CHECK(offset + length <= mSize);
 
     mRangeOffset = offset;
     mRangeLength = length;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 8535f52..d51802c 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -18,12 +18,16 @@
 #define LOG_TAG "MediaExtractor"
 #include <utils/Log.h>
 
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+#include "include/MP3Extractor.h"
+#include "include/MPEG4Extractor.h"
+
+#include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPDataSource.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MP3Extractor.h>
-#include <media/stagefright/MPEG4Extractor.h>
 #include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MmapSource.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -41,7 +45,7 @@
         }
 
         mime = tmp.string();
-        LOGI("Autodetected media content as '%s' with confidence %.2f",
+        LOGV("Autodetected media content as '%s' with confidence %.2f",
              mime, confidence);
     }
 
@@ -58,4 +62,25 @@
     return NULL;
 }
 
+// static
+sp<MediaExtractor> MediaExtractor::CreateFromURI(
+        const char *uri, const char *mime) {
+    sp<DataSource> source;
+    if (!strncasecmp("file://", uri, 7)) {
+        source = new MmapSource(uri + 7);
+    } else if (!strncasecmp("http://", uri, 7)) {
+        source = new HTTPDataSource(uri);
+        source = new CachingDataSource(source, 64 * 1024, 10);
+    } else {
+        // Assume it's a filename.
+        source = new MmapSource(uri);
+    }
+
+    if (source == NULL || source->initCheck() != OK) {
+        return NULL;
+    }
+
+    return Create(source, mime);
+}
+
 }  // namespace android
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 2e609e3..76f4182 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -18,15 +18,15 @@
 #define LOG_TAG "MediaPlayerImpl"
 #include "utils/Log.h"
 
+#include "include/stagefright_string.h"
+#include "include/HTTPStream.h"
+
 #include <OMX_Component.h>
 
 #include <unistd.h>
 
 #include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/CachingDataSource.h>
 // #include <media/stagefright/CameraSource.h>
-#include <media/stagefright/HTTPDataSource.h>
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaPlayerImpl.h>
@@ -69,18 +69,7 @@
         mVideoDecoder = CameraSource::Create();
 #endif
     } else {
-        sp<DataSource> source;
-        if (!strncasecmp("file://", uri, 7)) {
-            source = new MmapSource(uri + 7);
-        } else if (!strncasecmp("http://", uri, 7)) {
-            source = new HTTPDataSource(uri);
-            source = new CachingDataSource(source, 64 * 1024, 10);
-        } else {
-            // Assume it's a filename.
-            source = new MmapSource(uri);
-        }
-
-        mExtractor = MediaExtractor::Create(source);
+        mExtractor = MediaExtractor::CreateFromURI(uri);
 
         if (mExtractor == NULL) {
             return;
@@ -250,6 +239,13 @@
         status_t err = mVideoDecoder->read(&buffer, &options);
         CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
 
+        if (err == INFO_FORMAT_CHANGED) {
+            LOGI("format changed.");
+            depopulateISurface();
+            populateISurface();
+            continue;
+        }
+
         if (err == ERROR_END_OF_STREAM || err != OK) {
             eof = true;
             continue;
@@ -261,15 +257,9 @@
             continue;
         }
 
-        int32_t units, scale;
-        bool success =
-            buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
-        CHECK(success);
-        success =
-            buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
-        CHECK(success);
+        int64_t pts_us;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &pts_us));
 
-        int64_t pts_us = (int64_t)units * 1000000 / scale;
         {
             Mutex::Autolock autoLock(mLock);
             mVideoPosition = pts_us;
@@ -379,12 +369,10 @@
 
             sp<MediaSource> source = mExtractor->getTrack(i);
 
-            int32_t units, scale;
-            if (meta->findInt32(kKeyDuration, &units)
-                && meta->findInt32(kKeyTimeScale, &scale)) {
-                int64_t duration_us = (int64_t)units * 1000000 / scale;
-                if (duration_us > mDuration) {
-                    mDuration = duration_us;
+            int64_t durationUs;
+            if (meta->findInt64(kKeyDuration, &durationUs)) {
+                if (durationUs > mDuration) {
+                    mDuration = durationUs;
                 }
             }
 
@@ -609,6 +597,9 @@
     success = success && meta->findInt32(kKeyHeight, &decodedHeight);
     CHECK(success);
 
+    LOGI("mVideoWidth=%d, mVideoHeight=%d, decodedWidth=%d, decodedHeight=%d",
+         mVideoWidth, mVideoHeight, decodedWidth, decodedHeight);
+
     if (mSurface.get() != NULL) {
         mVideoRenderer =
             mClient.interface()->createRenderer(
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 6b067cb..63b476e 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -58,6 +58,10 @@
     return setData(key, TYPE_INT32, &value, sizeof(value));
 }
 
+bool MetaData::setInt64(uint32_t key, int64_t value) {
+    return setData(key, TYPE_INT64, &value, sizeof(value));
+}
+
 bool MetaData::setFloat(uint32_t key, float value) {
     return setData(key, TYPE_FLOAT, &value, sizeof(value));
 }
@@ -94,6 +98,21 @@
     return true;
 }
 
+bool MetaData::findInt64(uint32_t key, int64_t *value) {
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
+        return false;
+    }
+
+    CHECK_EQ(size, sizeof(*value));
+
+    *value = *(int64_t *)data;
+
+    return true;
+}
+
 bool MetaData::findFloat(uint32_t key, float *value) {
     uint32_t type;
     const void *data;
diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp
index 47d95f9..42749cf 100644
--- a/media/libstagefright/MmapSource.cpp
+++ b/media/libstagefright/MmapSource.cpp
@@ -34,7 +34,10 @@
       mBase(NULL),
       mSize(0) {
     LOGV("MmapSource '%s'", filename);
-    CHECK(mFd >= 0);
+
+    if (mFd < 0) {
+        return;
+    }
 
     off_t size = lseek(mFd, 0, SEEK_END);
     mSize = (size_t)size;
@@ -78,12 +81,12 @@
     }
 }
 
-status_t MmapSource::InitCheck() const {
+status_t MmapSource::initCheck() const {
     return mFd == -1 ? NO_INIT : OK;
 }
 
-ssize_t MmapSource::read_at(off_t offset, void *data, size_t size) {
-    LOGV("read_at offset:%ld data:%p size:%d", offset, data, size);
+ssize_t MmapSource::readAt(off_t offset, void *data, size_t size) {
+    LOGV("readAt offset:%ld data:%p size:%d", offset, data, size);
     CHECK(offset >= 0);
 
     size_t avail = 0;
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index dba7a2a..9de873e 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -35,7 +35,7 @@
 
     CHECK(service.get() != NULL);
 
-    mOMX = service->createOMX();
+    mOMX = service->getOMX();
     CHECK(mOMX.get() != NULL);
 
     return OK;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 1a23fb2..41a9fe9 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,11 +18,12 @@
 #define LOG_TAG "OMXCodec"
 #include <utils/Log.h>
 
+#include "include/ESDS.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>
@@ -39,6 +40,8 @@
 
 namespace android {
 
+static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
 struct CodecInfo {
     const char *mime;
     const char *codec;
@@ -85,12 +88,15 @@
 #define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
 
 struct OMXCodecObserver : public BnOMXObserver {
-    OMXCodecObserver(const wp<OMXCodec> &target)
-        : mTarget(target) {
+    OMXCodecObserver() {
+    }
+
+    void setCodec(const sp<OMXCodec> &target) {
+        mTarget = target;
     }
 
     // from IOMXObserver
-    virtual void on_message(const omx_message &msg) {
+    virtual void onMessage(const omx_message &msg) {
         sp<OMXCodec> codec = mTarget.promote();
 
         if (codec.get() != NULL) {
@@ -166,51 +172,37 @@
     params->nVersion.s.nStep = 0;
 }
 
-// static
-sp<OMXCodec> OMXCodec::Create(
-        const sp<IOMX> &omx,
-        const sp<MetaData> &meta, bool createEncoder,
-        const sp<MediaSource> &source,
-        const char *matchComponentName) {
-    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;
-        }
-
-        // If a specific codec is requested, skip the non-matching ones.
-        if (matchComponentName && strcmp(componentName, matchComponentName)) {
-            continue;
-        }
-
-        LOGV("Attempting to allocate OMX node '%s'", componentName);
-
-        status_t err = omx->allocate_node(componentName, &node);
-        if (err == OK) {
-            LOGI("Successfully allocated OMX node '%s'", componentName);
-            break;
-        }
+static bool IsSoftwareCodec(const char *componentName) {
+    if (!strncmp("OMX.PV.", componentName, 7)) {
+        return true;
     }
 
+    return false;
+}
+
+static int CompareSoftwareCodecsFirst(
+        const String8 *elem1, const String8 *elem2) {
+    bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string());
+    bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string());
+
+    if (isSoftwareCodec1) {
+        if (isSoftwareCodec2) { return 0; }
+        return -1;
+    }
+
+    if (isSoftwareCodec2) {
+        return 1;
+    }
+
+    return 0;
+}
+
+// static
+uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
     uint32_t quirks = 0;
+
     if (!strcmp(componentName, "OMX.PV.avcdec")) {
         quirks |= kWantsNALFragments;
-        quirks |= kOutputDimensionsAre16Aligned;
     }
     if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
         quirks |= kNeedsFlushBeforeDisable;
@@ -218,21 +210,16 @@
     if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
         quirks |= kNeedsFlushBeforeDisable;
         quirks |= kRequiresFlushCompleteEmulation;
-
-        // The following is currently necessary for proper shutdown
-        // behaviour, but NOT enabled by default in order to make the
-        // bug reproducible...
-        // quirks |= kRequiresFlushBeforeShutdown;
     }
     if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
         quirks |= kRequiresLoadedToIdleAfterAllocation;
         quirks |= kRequiresAllocateBufferOnInputPorts;
+        quirks |= kRequiresAllocateBufferOnOutputPorts;
     }
     if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
         // XXX Required on P....on only.
         quirks |= kRequiresAllocateBufferOnInputPorts;
         quirks |= kRequiresAllocateBufferOnOutputPorts;
-        quirks |= kOutputDimensionsAre16Aligned;
     }
 
     if (!strncmp(componentName, "OMX.TI.", 7)) {
@@ -245,10 +232,98 @@
         quirks |= kRequiresAllocateBufferOnOutputPorts;
     }
 
+    return quirks;
+}
+
+// static
+void OMXCodec::findMatchingCodecs(
+        const char *mime,
+        bool createEncoder, const char *matchComponentName,
+        uint32_t flags,
+        Vector<String8> *matchingCodecs) {
+    matchingCodecs->clear();
+
+    for (int index = 0;; ++index) {
+        const char *componentName;
+
+        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) {
+            break;
+        }
+
+        // If a specific codec is requested, skip the non-matching ones.
+        if (matchComponentName && strcmp(componentName, matchComponentName)) {
+            continue;
+        }
+
+        matchingCodecs->push(String8(componentName));
+    }
+
+    if (flags & kPreferSoftwareCodecs) {
+        matchingCodecs->sort(CompareSoftwareCodecsFirst);
+    }
+}
+
+// static
+sp<OMXCodec> OMXCodec::Create(
+        const sp<IOMX> &omx,
+        const sp<MetaData> &meta, bool createEncoder,
+        const sp<MediaSource> &source,
+        const char *matchComponentName,
+        uint32_t flags) {
+    const char *mime;
+    bool success = meta->findCString(kKeyMIMEType, &mime);
+    CHECK(success);
+
+    Vector<String8> matchingCodecs;
+    findMatchingCodecs(
+            mime, createEncoder, matchComponentName, flags, &matchingCodecs);
+
+    if (matchingCodecs.isEmpty()) {
+        return NULL;
+    }
+
+    sp<OMXCodecObserver> observer = new OMXCodecObserver;
+    IOMX::node_id node = 0;
+    success = false;
+
+    const char *componentName;
+    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+        componentName = matchingCodecs[i].string();
+
+        LOGV("Attempting to allocate OMX node '%s'", componentName);
+
+        status_t err = omx->allocateNode(componentName, observer, &node);
+        if (err == OK) {
+            LOGV("Successfully allocated OMX node '%s'", componentName);
+
+            success = true;
+            break;
+        }
+    }
+
+    if (!success) {
+        return NULL;
+    }
+
     sp<OMXCodec> codec = new OMXCodec(
-            omx, node, quirks, createEncoder, mime, componentName,
+            omx, node, getComponentQuirks(componentName),
+            createEncoder, mime, componentName,
             source);
 
+    observer->setCodec(codec);
+
     uint32_t type;
     const void *data;
     size_t size;
@@ -326,12 +401,14 @@
             size -= length;
         }
 
-        LOGI("AVC profile = %d (%s), level = %d",
+        LOGV("AVC profile = %d (%s), level = %d",
              (int)profile, AVCProfileToString(profile), (int)level / 10);
 
         if (!strcmp(componentName, "OMX.TI.Video.Decoder")
             && (profile != kAVCProfileBaseline || level > 39)) {
-            // This stream exceeds the decoder's capabilities.
+            // This stream exceeds the decoder's capabilities. The decoder
+            // does not handle this gracefully and would clobber the heap
+            // and wreak havoc instead...
 
             LOGE("Profile and/or level exceed the decoder's capabilities.");
             return NULL;
@@ -406,7 +483,7 @@
     InitOMXParams(&def);
     def.nPortIndex = portIndex;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
@@ -415,7 +492,7 @@
 
     }
 
-    err = mOMX->set_parameter(
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 }
@@ -433,7 +510,7 @@
     OMX_U32 index = 0;
     for (;;) {
         format.nIndex = index;
-        status_t err = mOMX->get_parameter(
+        status_t err = mOMX->getParameter(
                 mNode, OMX_IndexParamVideoPortFormat,
                 &format, sizeof(format));
 
@@ -445,7 +522,7 @@
         // CHECK_EQ(format.nIndex, index);
 
 #if 1
-        CODEC_LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+        CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
              portIndex,
              index, format.eCompressionFormat, format.eColorFormat);
 #endif
@@ -478,17 +555,33 @@
         return UNKNOWN_ERROR;
     }
 
-    CODEC_LOGI("found a match.");
-    status_t err = mOMX->set_parameter(
+    CODEC_LOGV("found a match.");
+    status_t err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoPortFormat,
             &format, sizeof(format));
 
     return err;
 }
 
+static size_t getFrameSize(
+        OMX_COLOR_FORMATTYPE colorFormat, int32_t width, int32_t height) {
+    switch (colorFormat) {
+        case OMX_COLOR_FormatYCbYCr:
+        case OMX_COLOR_FormatCbYCrY:
+            return width * height * 2;
+
+        case OMX_COLOR_FormatYUV420SemiPlanar:
+            return (width * height * 3) / 2;
+
+        default:
+            CHECK(!"Should not be here. Unsupported color format.");
+            break;
+    }
+}
+
 void OMXCodec::setVideoInputFormat(
         const char *mime, OMX_U32 width, OMX_U32 height) {
-    CODEC_LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
+    CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
 
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
@@ -509,12 +602,13 @@
         colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
     }
 
-    setVideoPortFormatType(
+    CHECK_EQ(setVideoPortFormatType(
             kPortIndexInput, OMX_VIDEO_CodingUnused,
-            colorFormat);
+            colorFormat), OK);
 
-    setVideoPortFormatType(
-            kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
+    CHECK_EQ(setVideoPortFormatType(
+            kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
+            OK);
 
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
@@ -522,7 +616,7 @@
 
     OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
     CHECK_EQ(err, OK);
@@ -534,7 +628,7 @@
     video_def->eCompressionFormat = compressionFormat;
     video_def->eColorFormat = OMX_COLOR_FormatUnused;
 
-    err = mOMX->set_parameter(
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
@@ -543,12 +637,12 @@
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexInput;
 
-    err = mOMX->get_parameter(
+    err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
-    def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
-    CODEC_LOGI("Setting nBufferSize = %ld", def.nBufferSize);
+    def.nBufferSize = getFrameSize(colorFormat, width, height);
+    CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
 
     CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
 
@@ -557,14 +651,108 @@
     video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
     video_def->eColorFormat = colorFormat;
 
-    err = mOMX->set_parameter(
+    video_def->xFramerate = 24 << 16;  // XXX crucial!
+
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
+
+    switch (compressionFormat) {
+        case OMX_VIDEO_CodingMPEG4:
+        {
+            CHECK_EQ(setupMPEG4EncoderParameters(), OK);
+            break;
+        }
+
+        case OMX_VIDEO_CodingH263:
+            break;
+
+        default:
+            CHECK(!"Support for this compressionFormat to be implemented.");
+            break;
+    }
+}
+
+status_t OMXCodec::setupMPEG4EncoderParameters() {
+    OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type;
+    InitOMXParams(&mpeg4type);
+    mpeg4type.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->getParameter(
+            mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
+    CHECK_EQ(err, OK);
+
+    mpeg4type.nSliceHeaderSpacing = 0;
+    mpeg4type.bSVH = OMX_FALSE;
+    mpeg4type.bGov = OMX_FALSE;
+
+    mpeg4type.nAllowedPictureTypes =
+        OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+
+    mpeg4type.nPFrames = 23;
+    mpeg4type.nBFrames = 0;
+
+    mpeg4type.nIDCVLCThreshold = 0;
+    mpeg4type.bACPred = OMX_TRUE;
+    mpeg4type.nMaxPacketSize = 256;
+    mpeg4type.nTimeIncRes = 1000;
+    mpeg4type.nHeaderExtension = 0;
+    mpeg4type.bReversibleVLC = OMX_FALSE;
+
+    mpeg4type.eProfile = OMX_VIDEO_MPEG4ProfileCore;
+    mpeg4type.eLevel = OMX_VIDEO_MPEG4Level2;
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
+    CHECK_EQ(err, OK);
+
+    // ----------------
+
+    OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
+    InitOMXParams(&bitrateType);
+    bitrateType.nPortIndex = kPortIndexOutput;
+
+    err = mOMX->getParameter(
+            mNode, OMX_IndexParamVideoBitrate,
+            &bitrateType, sizeof(bitrateType));
+    CHECK_EQ(err, OK);
+
+    bitrateType.eControlRate = OMX_Video_ControlRateVariable;
+    bitrateType.nTargetBitrate = 1000000;
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamVideoBitrate,
+            &bitrateType, sizeof(bitrateType));
+    CHECK_EQ(err, OK);
+
+    // ----------------
+
+    OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
+    InitOMXParams(&errorCorrectionType);
+    errorCorrectionType.nPortIndex = kPortIndexOutput;
+
+    err = mOMX->getParameter(
+            mNode, OMX_IndexParamVideoErrorCorrection,
+            &errorCorrectionType, sizeof(errorCorrectionType));
+    CHECK_EQ(err, OK);
+
+    errorCorrectionType.bEnableHEC = OMX_FALSE;
+    errorCorrectionType.bEnableResync = OMX_TRUE;
+    errorCorrectionType.nResynchMarkerSpacing = 256;
+    errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
+    errorCorrectionType.bEnableRVLC = OMX_FALSE;
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamVideoErrorCorrection,
+            &errorCorrectionType, sizeof(errorCorrectionType));
+    CHECK_EQ(err, OK);
+
+    return OK;
 }
 
 void OMXCodec::setVideoOutputFormat(
         const char *mime, OMX_U32 width, OMX_U32 height) {
-    CODEC_LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+    CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
 
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
@@ -588,7 +776,7 @@
         format.nPortIndex = kPortIndexOutput;
         format.nIndex = 0;
 
-        status_t err = mOMX->get_parameter(
+        status_t err = mOMX->getParameter(
                 mNode, OMX_IndexParamVideoPortFormat,
                 &format, sizeof(format));
         CHECK_EQ(err, OK);
@@ -601,7 +789,7 @@
                || format.eColorFormat == OMX_COLOR_FormatCbYCrY
                || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
 
-        err = mOMX->set_parameter(
+        err = mOMX->setParameter(
                 mNode, OMX_IndexParamVideoPortFormat,
                 &format, sizeof(format));
         CHECK_EQ(err, OK);
@@ -614,7 +802,7 @@
 
     OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
     CHECK_EQ(err, OK);
@@ -632,9 +820,10 @@
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
 
+    video_def->eCompressionFormat = compressionFormat;
     video_def->eColorFormat = OMX_COLOR_FormatUnused;
 
-    err = mOMX->set_parameter(
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
@@ -643,7 +832,7 @@
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
-    err = mOMX->get_parameter(
+    err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
     CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
@@ -656,7 +845,7 @@
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
 
-    err = mOMX->set_parameter(
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 }
@@ -680,13 +869,11 @@
       mInitialBufferSubmit(true),
       mSignalledEOS(false),
       mNoMoreOutputData(false),
+      mOutputPortSettingsHaveChanged(false),
       mSeekTimeUs(-1) {
     mPortStatus[kPortIndexInput] = ENABLED;
     mPortStatus[kPortIndexOutput] = ENABLED;
 
-    mObserver = new OMXCodecObserver(this);
-    mOMX->observe_node(mNode, mObserver);
-
     setComponentRole();
 }
 
@@ -744,7 +931,7 @@
 
         roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
 
-        status_t err = omx->set_parameter(
+        status_t err = omx->setParameter(
                 node, OMX_IndexParamStandardComponentRole,
                 &roleParams, sizeof(roleParams));
 
@@ -761,10 +948,7 @@
 OMXCodec::~OMXCodec() {
     CHECK(mState == LOADED || mState == ERROR);
 
-    status_t err = mOMX->observe_node(mNode, NULL);
-    CHECK_EQ(err, OK);
-
-    err = mOMX->free_node(mNode);
+    status_t err = mOMX->freeNode(mNode);
     CHECK_EQ(err, OK);
 
     mNode = NULL;
@@ -786,7 +970,7 @@
 
     status_t err;
     if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
-        err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+        err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
         CHECK_EQ(err, OK);
         setState(LOADED_TO_IDLE);
     }
@@ -795,7 +979,7 @@
     CHECK_EQ(err, OK);
 
     if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
-        err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+        err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
         CHECK_EQ(err, OK);
 
         setState(LOADED_TO_IDLE);
@@ -832,7 +1016,7 @@
     InitOMXParams(&def);
     def.nPortIndex = portIndex;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
     if (err != OK) {
@@ -849,14 +1033,14 @@
         IOMX::buffer_id buffer;
         if (portIndex == kPortIndexInput
                 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
-            err = mOMX->allocate_buffer_with_backup(
+            err = mOMX->allocateBufferWithBackup(
                     mNode, portIndex, mem, &buffer);
         } else if (portIndex == kPortIndexOutput
                 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
-            err = mOMX->allocate_buffer_with_backup(
+            err = mOMX->allocateBufferWithBackup(
                     mNode, portIndex, mem, &buffer);
         } else {
-            err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
+            err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
         }
 
         if (err != OK) {
@@ -923,7 +1107,7 @@
                 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
 
                 status_t err =
-                    mOMX->free_buffer(mNode, kPortIndexInput, buffer);
+                    mOMX->freeBuffer(mNode, kPortIndexInput, buffer);
                 CHECK_EQ(err, OK);
 
                 buffers->removeAt(i);
@@ -969,7 +1153,7 @@
                 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
 
                 status_t err =
-                    mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
+                    mOMX->freeBuffer(mNode, kPortIndexOutput, buffer);
                 CHECK_EQ(err, OK);
 
                 buffers->removeAt(i);
@@ -989,12 +1173,8 @@
 
                 buffer->meta_data()->clear();
 
-                buffer->meta_data()->setInt32(
-                        kKeyTimeUnits,
-                        (msg.u.extended_buffer_data.timestamp + 500) / 1000);
-
-                buffer->meta_data()->setInt32(
-                        kKeyTimeScale, 1000);
+                buffer->meta_data()->setInt64(
+                        kKeyTime, msg.u.extended_buffer_data.timestamp);
 
                 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
                     buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
@@ -1063,6 +1243,71 @@
     }
 }
 
+// Has the format changed in any way that the client would have to be aware of?
+static bool formatHasNotablyChanged(
+        const sp<MetaData> &from, const sp<MetaData> &to) {
+    if (from.get() == NULL && to.get() == NULL) {
+        return false;
+    }
+
+    if ((from.get() == NULL && to.get() != NULL)
+        || (from.get() != NULL && to.get() == NULL)) {
+        return true;
+    }
+
+    const char *mime_from, *mime_to;
+    CHECK(from->findCString(kKeyMIMEType, &mime_from));
+    CHECK(to->findCString(kKeyMIMEType, &mime_to));
+
+    if (strcasecmp(mime_from, mime_to)) {
+        return true;
+    }
+
+    if (!strcasecmp(mime_from, MEDIA_MIMETYPE_VIDEO_RAW)) {
+        int32_t colorFormat_from, colorFormat_to;
+        CHECK(from->findInt32(kKeyColorFormat, &colorFormat_from));
+        CHECK(to->findInt32(kKeyColorFormat, &colorFormat_to));
+
+        if (colorFormat_from != colorFormat_to) {
+            return true;
+        }
+
+        int32_t width_from, width_to;
+        CHECK(from->findInt32(kKeyWidth, &width_from));
+        CHECK(to->findInt32(kKeyWidth, &width_to));
+
+        if (width_from != width_to) {
+            return true;
+        }
+
+        int32_t height_from, height_to;
+        CHECK(from->findInt32(kKeyHeight, &height_from));
+        CHECK(to->findInt32(kKeyHeight, &height_to));
+
+        if (height_from != height_to) {
+            return true;
+        }
+    } else if (!strcasecmp(mime_from, MEDIA_MIMETYPE_AUDIO_RAW)) {
+        int32_t numChannels_from, numChannels_to;
+        CHECK(from->findInt32(kKeyChannelCount, &numChannels_from));
+        CHECK(to->findInt32(kKeyChannelCount, &numChannels_to));
+
+        if (numChannels_from != numChannels_to) {
+            return true;
+        }
+
+        int32_t sampleRate_from, sampleRate_to;
+        CHECK(from->findInt32(kKeySampleRate, &sampleRate_from));
+        CHECK(to->findInt32(kKeySampleRate, &sampleRate_to));
+
+        if (sampleRate_from != sampleRate_to) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
     switch (cmd) {
         case OMX_CommandStateSet:
@@ -1085,6 +1330,15 @@
             if (mState == RECONFIGURING) {
                 CHECK_EQ(portIndex, kPortIndexOutput);
 
+                sp<MetaData> oldOutputFormat = mOutputFormat;
+                initOutputFormat(mSource->getFormat());
+
+                // Don't notify clients if the output port settings change
+                // wasn't of importance to them, i.e. it may be that just the
+                // number of buffers has changed and nothing else.
+                mOutputPortSettingsHaveChanged =
+                    formatHasNotablyChanged(oldOutputFormat, mOutputFormat);
+
                 enablePortAsync(portIndex);
 
                 status_t err = allocateBuffersOnPort(portIndex);
@@ -1139,7 +1393,7 @@
                     mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
 
                     status_t err =
-                        mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+                        mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
                     CHECK_EQ(err, OK);
                 }
             } else {
@@ -1179,7 +1433,7 @@
         {
             CODEC_LOGV("Now Idle.");
             if (mState == LOADED_TO_IDLE) {
-                status_t err = mOMX->send_command(
+                status_t err = mOMX->sendCommand(
                         mNode, OMX_CommandStateSet, OMX_StateExecuting);
 
                 CHECK_EQ(err, OK);
@@ -1196,7 +1450,7 @@
                     countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
                     mPortBuffers[kPortIndexOutput].size());
 
-                status_t err = mOMX->send_command(
+                status_t err = mOMX->sendCommand(
                         mNode, OMX_CommandStateSet, OMX_StateLoaded);
 
                 CHECK_EQ(err, OK);
@@ -1279,7 +1533,7 @@
         CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
 
         status_t err =
-            mOMX->free_buffer(mNode, portIndex, info->mBuffer);
+            mOMX->freeBuffer(mNode, portIndex, info->mBuffer);
 
         if (err != OK) {
             stickyErr = err;
@@ -1339,7 +1593,7 @@
     }
 
     status_t err =
-        mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
+        mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
     CHECK_EQ(err, OK);
 
     return true;
@@ -1352,7 +1606,7 @@
     mPortStatus[portIndex] = DISABLING;
 
     status_t err =
-        mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
+        mOMX->sendCommand(mNode, OMX_CommandPortDisable, portIndex);
     CHECK_EQ(err, OK);
 
     freeBuffersOnPort(portIndex, true);
@@ -1365,7 +1619,7 @@
     mPortStatus[portIndex] = ENABLING;
 
     status_t err =
-        mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
+        mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
     CHECK_EQ(err, OK);
 }
 
@@ -1417,10 +1671,11 @@
             memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
         }
 
-        mOMX->empty_buffer(
+        status_t err = mOMX->emptyBuffer(
                 mNode, info->mBuffer, 0, size,
                 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
                 0);
+        CHECK_EQ(err, OK);
 
         info->mOwnedByComponent = true;
 
@@ -1441,7 +1696,7 @@
     }
 
     OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
-    OMX_TICKS timestamp = 0;
+    OMX_TICKS timestampUs = 0;
     size_t srcLength = 0;
 
     if (err != OK) {
@@ -1461,28 +1716,29 @@
                (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;
-
-            CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
+        if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
+            CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d)",
                  info->mBuffer, srcLength);
-            CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
-                 timestamp, timestamp / 1E6);
+            CODEC_LOGV("Calling emptyBuffer with timestamp %lld us (%.2f secs)",
+                 timestampUs, timestampUs / 1E6);
         }
     }
 
-    mOMX->empty_buffer(
-            mNode, info->mBuffer, 0, srcLength,
-            flags, timestamp);
-
-    info->mOwnedByComponent = true;
-
     if (srcBuffer != NULL) {
         srcBuffer->release();
         srcBuffer = NULL;
     }
+
+    err = mOMX->emptyBuffer(
+            mNode, info->mBuffer, 0, srcLength,
+            flags, timestampUs);
+
+    if (err != OK) {
+        setState(ERROR);
+        return;
+    }
+
+    info->mOwnedByComponent = true;
 }
 
 void OMXCodec::fillOutputBuffer(BufferInfo *info) {
@@ -1495,7 +1751,8 @@
     }
 
     CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
-    mOMX->fill_buffer(mNode, info->mBuffer);
+    status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
+    CHECK_EQ(err, OK);
 
     info->mOwnedByComponent = true;
 }
@@ -1539,7 +1796,7 @@
     InitOMXParams(&pcmParams);
     pcmParams.nPortIndex = portIndex;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
 
     CHECK_EQ(err, OK);
@@ -1560,7 +1817,7 @@
         pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
     }
 
-    err = mOMX->set_parameter(
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
 
     CHECK_EQ(err, OK);
@@ -1573,14 +1830,14 @@
         def.nPortIndex = kPortIndexInput;
 
         status_t err =
-            mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+            mOMX->getParameter(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));
+        err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
         CHECK_EQ(err, OK);
     }
 
@@ -1604,14 +1861,14 @@
         def.nPortIndex = kPortIndexInput;
 
         status_t err =
-            mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+            mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
 
         CHECK_EQ(err, OK);
 
         def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
         def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
 
-        err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+        err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
         CHECK_EQ(err, OK);
     }
 
@@ -1636,7 +1893,7 @@
         InitOMXParams(&profile);
         profile.nPortIndex = kPortIndexInput;
 
-        status_t err = mOMX->get_parameter(
+        status_t err = mOMX->getParameter(
                 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
         CHECK_EQ(err, OK);
 
@@ -1644,7 +1901,7 @@
         profile.nSampleRate = sampleRate;
         profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
 
-        err = mOMX->set_parameter(
+        err = mOMX->setParameter(
                 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
         CHECK_EQ(err, OK);
     }
@@ -1668,7 +1925,7 @@
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
@@ -1717,7 +1974,7 @@
 
     def.nBufferCountActual = def.nBufferCountMin;
 
-    err = mOMX->set_parameter(
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 }
@@ -1728,7 +1985,7 @@
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexInput;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
@@ -1742,7 +1999,7 @@
     def.nBufferSize = compressedSize;
     def.nBufferCountActual = def.nBufferCountMin;
 
-    err = mOMX->set_parameter(
+    err = mOMX->setParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 }
@@ -1786,6 +2043,7 @@
     mInitialBufferSubmit = true;
     mSignalledEOS = false;
     mNoMoreOutputData = false;
+    mOutputPortSettingsHaveChanged = false;
     mSeekTimeUs = -1;
     mFilledBuffers.clear();
 
@@ -1832,7 +2090,7 @@
                 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
 
                 status_t err =
-                    mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+                    mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
                 CHECK_EQ(err, OK);
             }
 
@@ -1856,6 +2114,8 @@
 }
 
 sp<MetaData> OMXCodec::getFormat() {
+    Mutex::Autolock autoLock(mLock);
+
     return mOutputFormat;
 }
 
@@ -1869,9 +2129,24 @@
         return UNKNOWN_ERROR;
     }
 
+    bool seeking = false;
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        seeking = true;
+    }
+
     if (mInitialBufferSubmit) {
         mInitialBufferSubmit = false;
 
+        if (seeking) {
+            CHECK(seekTimeUs >= 0);
+            mSeekTimeUs = seekTimeUs;
+
+            // There's no reason to trigger the code below, there's
+            // nothing to flush yet.
+            seeking = false;
+        }
+
         drainInputBuffers();
 
         if (mState == EXECUTING) {
@@ -1881,8 +2156,7 @@
         }
     }
 
-    int64_t seekTimeUs;
-    if (options && options->getSeekTo(&seekTimeUs)) {
+    if (seeking) {
         CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
 
         mSignalledEOS = false;
@@ -1919,6 +2193,12 @@
         return ERROR_END_OF_STREAM;
     }
 
+    if (mOutputPortSettingsHaveChanged) {
+        mOutputPortSettingsHaveChanged = false;
+
+        return INFO_FORMAT_CHANGED;
+    }
+
     size_t index = *mFilledBuffers.begin();
     mFilledBuffers.erase(mFilledBuffers.begin());
 
@@ -2019,8 +2299,6 @@
 
     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) {
@@ -2164,7 +2442,7 @@
     InitOMXParams(&def);
     def.nPortIndex = portIndex;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
@@ -2230,7 +2508,7 @@
                 InitOMXParams(&params);
                 params.nPortIndex = portIndex;
 
-                err = mOMX->get_parameter(
+                err = mOMX->getParameter(
                         mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
                 CHECK_EQ(err, OK);
 
@@ -2249,7 +2527,7 @@
                 InitOMXParams(&amr);
                 amr.nPortIndex = portIndex;
 
-                err = mOMX->get_parameter(
+                err = mOMX->getParameter(
                         mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
                 CHECK_EQ(err, OK);
 
@@ -2281,7 +2559,7 @@
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
-    status_t err = mOMX->get_parameter(
+    status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
@@ -2307,7 +2585,7 @@
                 InitOMXParams(&params);
                 params.nPortIndex = kPortIndexOutput;
 
-                err = mOMX->get_parameter(
+                err = mOMX->getParameter(
                         mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
                 CHECK_EQ(err, OK);
 
@@ -2339,7 +2617,7 @@
                 InitOMXParams(&amr);
                 amr.nPortIndex = kPortIndexOutput;
 
-                err = mOMX->get_parameter(
+                err = mOMX->getParameter(
                         mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
                 CHECK_EQ(err, OK);
 
@@ -2388,7 +2666,7 @@
                 CHECK(!"Unknown compression format.");
             }
 
-            if (mQuirks & kOutputDimensionsAre16Aligned) {
+            if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
                 // This component appears to be lying to me.
                 mOutputFormat->setInt32(
                         kKeyWidth, (video_def->nFrameWidth + 15) & -16);
@@ -2436,8 +2714,9 @@
             return OK;
         }
 
+        sp<OMXCodecObserver> observer = new OMXCodecObserver;
         IOMX::node_id node;
-        status_t err = omx->allocate_node(componentName, &node);
+        status_t err = omx->allocateNode(componentName, observer, &node);
 
         if (err != OK) {
             continue;
@@ -2455,7 +2734,7 @@
         param.nPortIndex = queryDecoders ? 0 : 1;
 
         for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
-            err = omx->get_parameter(
+            err = omx->getParameter(
                     node, OMX_IndexParamVideoProfileLevelQuerySupported,
                     &param, sizeof(param));
 
@@ -2470,7 +2749,7 @@
             caps->mProfileLevels.push(profileLevel);
         }
 
-        CHECK_EQ(omx->free_node(node), OK);
+        CHECK_EQ(omx->freeNode(node), OK);
     }
 }
 
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 8efa7c7..4aec0e9 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -17,11 +17,12 @@
 #define LOG_TAG "SampleTable"
 #include <utils/Log.h>
 
+#include "include/SampleTable.h"
+
 #include <arpa/inet.h>
 
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SampleTable.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
@@ -54,7 +55,7 @@
 }
 
 status_t SampleTable::setChunkOffsetParams(
-        uint32_t type, off_t data_offset, off_t data_size) {
+        uint32_t type, off_t data_offset, size_t data_size) {
     if (mChunkOffsetOffset >= 0) {
         return ERROR_MALFORMED;
     }
@@ -69,7 +70,7 @@
     }
 
     uint8_t header[8];
-    if (mDataSource->read_at(
+    if (mDataSource->readAt(
                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return ERROR_IO;
     }
@@ -95,7 +96,7 @@
 }
 
 status_t SampleTable::setSampleToChunkParams(
-        off_t data_offset, off_t data_size) {
+        off_t data_offset, size_t data_size) {
     if (mSampleToChunkOffset >= 0) {
         return ERROR_MALFORMED;
     }
@@ -107,7 +108,7 @@
     }
 
     uint8_t header[8];
-    if (mDataSource->read_at(
+    if (mDataSource->readAt(
                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return ERROR_IO;
     }
@@ -127,7 +128,7 @@
 }
 
 status_t SampleTable::setSampleSizeParams(
-        uint32_t type, off_t data_offset, off_t data_size) {
+        uint32_t type, off_t data_offset, size_t data_size) {
     if (mSampleSizeOffset >= 0) {
         return ERROR_MALFORMED;
     }
@@ -141,7 +142,7 @@
     }
 
     uint8_t header[12];
-    if (mDataSource->read_at(
+    if (mDataSource->readAt(
                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return ERROR_IO;
     }
@@ -187,13 +188,13 @@
 }
 
 status_t SampleTable::setTimeToSampleParams(
-        off_t data_offset, off_t data_size) {
+        off_t data_offset, size_t data_size) {
     if (mTimeToSample != NULL || data_size < 8) {
         return ERROR_MALFORMED;
     }
 
     uint8_t header[8];
-    if (mDataSource->read_at(
+    if (mDataSource->readAt(
                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return ERROR_IO;
     }
@@ -207,7 +208,7 @@
     mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
 
     size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
-    if (mDataSource->read_at(
+    if (mDataSource->readAt(
                 data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
         return ERROR_IO;
     }
@@ -219,7 +220,7 @@
     return OK;
 }
 
-status_t SampleTable::setSyncSampleParams(off_t data_offset, off_t data_size) {
+status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) {
     if (mSyncSampleOffset >= 0 || data_size < 8) {
         return ERROR_MALFORMED;
     }
@@ -227,7 +228,7 @@
     mSyncSampleOffset = data_offset;
 
     uint8_t header[8];
-    if (mDataSource->read_at(
+    if (mDataSource->readAt(
                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return ERROR_IO;
     }
@@ -263,7 +264,7 @@
     if (mChunkOffsetType == kChunkOffsetType32) {
         uint32_t offset32;
 
-        if (mDataSource->read_at(
+        if (mDataSource->readAt(
                     mChunkOffsetOffset + 8 + 4 * chunk_index,
                     &offset32,
                     sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
@@ -275,7 +276,7 @@
         CHECK_EQ(mChunkOffsetType, kChunkOffsetType64);
 
         uint64_t offset64;
-        if (mDataSource->read_at(
+        if (mDataSource->readAt(
                     mChunkOffsetOffset + 8 + 8 * chunk_index,
                     &offset64,
                     sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
@@ -312,7 +313,7 @@
     uint32_t index = 0;
     while (index < mNumSampleToChunkOffsets) {
         uint8_t buffer[12];
-        if (mDataSource->read_at(mSampleToChunkOffset + 8 + index * 12,
+        if (mDataSource->readAt(mSampleToChunkOffset + 8 + index * 12,
                                  buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
             return ERROR_IO;
         }
@@ -361,7 +362,7 @@
     switch (mSampleSizeFieldSize) {
         case 32:
         {
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         mSampleSizeOffset + 12 + 4 * sample_index,
                         sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
                 return ERROR_IO;
@@ -374,7 +375,7 @@
         case 16:
         {
             uint16_t x;
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         mSampleSizeOffset + 12 + 2 * sample_index,
                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
                 return ERROR_IO;
@@ -387,7 +388,7 @@
         case 8:
         {
             uint8_t x;
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         mSampleSizeOffset + 12 + sample_index,
                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
                 return ERROR_IO;
@@ -402,7 +403,7 @@
             CHECK_EQ(mSampleSizeFieldSize, 4);
 
             uint8_t x;
-            if (mDataSource->read_at(
+            if (mDataSource->readAt(
                         mSampleSizeOffset + 12 + sample_index / 2,
                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
                 return ERROR_IO;
@@ -553,7 +554,7 @@
     uint32_t right = mNumSyncSamples;
     while (left < right) {
         uint32_t mid = (left + right) / 2;
-        if (mDataSource->read_at(
+        if (mDataSource->readAt(
                     mSyncSampleOffset + 8 + (mid - 1) * 4, &x, 4) != 4) {
             return ERROR_IO;
         }
@@ -574,5 +575,52 @@
     return OK;
 }
 
+status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
+    if (mSyncSampleOffset < 0) {
+        // All samples are sync-samples.
+        *sample_index = 0;
+        return OK;
+    }
+
+    uint32_t bestSampleIndex = 0;
+    size_t maxSampleSize = 0;
+
+    static const size_t kMaxNumSyncSamplesToScan = 20;
+
+    // Consider the first kMaxNumSyncSamplesToScan sync samples and
+    // pick the one with the largest (compressed) size as the thumbnail.
+
+    size_t numSamplesToScan = mNumSyncSamples;
+    if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
+        numSamplesToScan = kMaxNumSyncSamplesToScan;
+    }
+
+    for (size_t i = 0; i < numSamplesToScan; ++i) {
+        uint32_t x;
+        if (mDataSource->readAt(
+                    mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
+            return ERROR_IO;
+        }
+        x = ntohl(x);
+        --x;
+
+        // Now x is a sample index.
+        size_t sampleSize;
+        status_t err = getSampleSize(x, &sampleSize);
+        if (err != OK) {
+            return err;
+        }
+
+        if (i == 0 || sampleSize > maxSampleSize) {
+            bestSampleIndex = x;
+            maxSampleSize = sampleSize;
+        }
+    }
+
+    *sample_index = bestSampleIndex;
+
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
index 8e8f4fa..ec25430 100644
--- a/media/libstagefright/ShoutcastSource.cpp
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
+#include "include/stagefright_string.h"
+#include "include/HTTPStream.h"
+
 #include <stdlib.h>
 
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/ShoutcastSource.h>
-#include <media/stagefright/string.h>
 
 namespace android {
 
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 3d85f75..dd8005c 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -22,10 +22,11 @@
 #define LOG_TAG "TimedEventQueue"
 #include <utils/Log.h>
 
+#include "include/TimedEventQueue.h"
+
 #include <sys/time.h>
 
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/TimedEventQueue.h>
 
 namespace android {
 
diff --git a/include/media/stagefright/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
similarity index 94%
rename from include/media/stagefright/AMRExtractor.h
rename to media/libstagefright/include/AMRExtractor.h
index c8710d3..debf006 100644
--- a/include/media/stagefright/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -30,7 +30,7 @@
 
     virtual size_t countTracks();
     virtual sp<MediaSource> getTrack(size_t index);
-    virtual sp<MetaData> getTrackMetaData(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     static sp<MetaData> makeAMRFormat(bool isWide);
 
diff --git a/include/media/stagefright/ESDS.h b/media/libstagefright/include/ESDS.h
similarity index 100%
rename from include/media/stagefright/ESDS.h
rename to media/libstagefright/include/ESDS.h
diff --git a/include/media/stagefright/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
similarity index 97%
rename from include/media/stagefright/HTTPStream.h
rename to media/libstagefright/include/HTTPStream.h
index 3d0d67a..43ef614 100644
--- a/include/media/stagefright/HTTPStream.h
+++ b/media/libstagefright/include/HTTPStream.h
@@ -18,10 +18,11 @@
 
 #define HTTP_STREAM_H_
 
+#include "stagefright_string.h"
+
 #include <sys/types.h>
 
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/string.h>
 #include <utils/KeyedVector.h>
 
 namespace android {
diff --git a/include/media/stagefright/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
similarity index 94%
rename from include/media/stagefright/MP3Extractor.h
rename to media/libstagefright/include/MP3Extractor.h
index 11ba01d..074973b 100644
--- a/include/media/stagefright/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -32,7 +32,7 @@
 
     virtual size_t countTracks();
     virtual sp<MediaSource> getTrack(size_t index);
-    virtual sp<MetaData> getTrackMetaData(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
 protected:
     virtual ~MP3Extractor();
diff --git a/include/media/stagefright/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
similarity index 93%
rename from include/media/stagefright/MPEG4Extractor.h
rename to media/libstagefright/include/MPEG4Extractor.h
index 932e30f..ce4736d 100644
--- a/include/media/stagefright/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -33,7 +33,7 @@
 
     size_t countTracks();
     sp<MediaSource> getTrack(size_t index);
-    sp<MetaData> getTrackMetaData(size_t index);
+    sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
 protected:
     virtual ~MPEG4Extractor();
@@ -44,6 +44,7 @@
         sp<MetaData> meta;
         uint32_t timescale;
         sp<SampleTable> sampleTable;
+        bool includes_expensive_metadata;
     };
 
     sp<DataSource> mDataSource;
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/include/OMX.h
similarity index 61%
rename from media/libstagefright/omx/OMX.h
rename to media/libstagefright/include/OMX.h
index 6325f79..a4b62b2 100644
--- a/media/libstagefright/omx/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -19,66 +19,67 @@
 
 #include <media/IOMX.h>
 #include <utils/threads.h>
+#include <utils/KeyedVector.h>
 
 namespace android {
 
-class NodeMeta;
+class OMXNodeInstance;
 
-class OMX : public BnOMX {
+class OMX : public BnOMX,
+            public IBinder::DeathRecipient {
 public:
     OMX();
 
-    virtual status_t list_nodes(List<String8> *list);
+    virtual status_t listNodes(List<String8> *list);
 
-    virtual status_t allocate_node(const char *name, node_id *node);
-    virtual status_t free_node(node_id node);
+    virtual status_t allocateNode(
+            const char *name, const sp<IOMXObserver> &observer, node_id *node);
 
-    virtual status_t send_command(
+    virtual status_t freeNode(node_id node);
+
+    virtual status_t sendCommand(
             node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
 
-    virtual status_t get_parameter(
+    virtual status_t getParameter(
             node_id node, OMX_INDEXTYPE index,
             void *params, size_t size);
 
-    virtual status_t set_parameter(
+    virtual status_t setParameter(
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size);
 
-    virtual status_t get_config(
+    virtual status_t getConfig(
             node_id node, OMX_INDEXTYPE index,
             void *params, size_t size);
 
-    virtual status_t set_config(
+    virtual status_t setConfig(
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size);
 
-    virtual status_t use_buffer(
+    virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer);
 
-    virtual status_t allocate_buffer(
+    virtual status_t allocateBuffer(
             node_id node, OMX_U32 port_index, size_t size,
             buffer_id *buffer);
 
-    virtual status_t allocate_buffer_with_backup(
+    virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer);
 
-    virtual status_t free_buffer(
+    virtual status_t freeBuffer(
             node_id node, OMX_U32 port_index, buffer_id buffer);
 
-    virtual status_t observe_node(
-            node_id node, const sp<IOMXObserver> &observer);
+    virtual status_t fillBuffer(node_id node, buffer_id buffer);
 
-    virtual void fill_buffer(node_id node, buffer_id buffer);
-
-    virtual void empty_buffer(
+    virtual status_t emptyBuffer(
             node_id node,
             buffer_id buffer,
             OMX_U32 range_offset, OMX_U32 range_length,
             OMX_U32 flags, OMX_TICKS timestamp);
 
-    virtual status_t get_extension_index(
+    virtual status_t getExtensionIndex(
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index);
@@ -90,44 +91,38 @@
             size_t encodedWidth, size_t encodedHeight,
             size_t displayWidth, size_t displayHeight);
 
-private:
-    static OMX_CALLBACKTYPE kCallbacks;
-
-    Mutex mLock;
-
-    struct CallbackDispatcher;
-    sp<CallbackDispatcher> mDispatcher;
-
-    static OMX_ERRORTYPE OnEvent(
-            OMX_IN OMX_HANDLETYPE hComponent,
-            OMX_IN OMX_PTR pAppData,
-            OMX_IN OMX_EVENTTYPE eEvent,
-            OMX_IN OMX_U32 nData1,
-            OMX_IN OMX_U32 nData2,
-            OMX_IN OMX_PTR pEventData);
-
-    static OMX_ERRORTYPE OnEmptyBufferDone(
-            OMX_IN OMX_HANDLETYPE hComponent,
-            OMX_IN OMX_PTR pAppData,
-            OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
-
-    static OMX_ERRORTYPE OnFillBufferDone(
-            OMX_IN OMX_HANDLETYPE hComponent,
-            OMX_IN OMX_PTR pAppData,
-            OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+    virtual void binderDied(const wp<IBinder> &the_late_who);
 
     OMX_ERRORTYPE OnEvent(
-            NodeMeta *meta,
+            node_id node,
             OMX_IN OMX_EVENTTYPE eEvent,
             OMX_IN OMX_U32 nData1,
             OMX_IN OMX_U32 nData2,
             OMX_IN OMX_PTR pEventData);
         
     OMX_ERRORTYPE OnEmptyBufferDone(
-            NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+            node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
 
     OMX_ERRORTYPE OnFillBufferDone(
-            NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+            node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+    void invalidateNodeID(node_id node);
+
+private:
+    Mutex mLock;
+
+    struct CallbackDispatcher;
+    sp<CallbackDispatcher> mDispatcher;
+
+    int32_t mNodeCounter;
+
+    KeyedVector<wp<IBinder>, OMXNodeInstance *> mLiveNodes;
+    KeyedVector<node_id, OMXNodeInstance *> mNodeIDToInstance;
+
+    node_id makeNodeID(OMXNodeInstance *instance);
+    OMXNodeInstance *findInstance(node_id node);
+
+    void invalidateNodeID_l(node_id node);
 
     OMX(const OMX &);
     OMX &operator=(const OMX &);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
new file mode 100644
index 0000000..09a8816
--- /dev/null
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OMX_NODE_INSTANCE_H_
+
+#define OMX_NODE_INSTANCE_H_
+
+#include "OMX.h"
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class IOMXObserver;
+
+struct OMXNodeInstance {
+    OMXNodeInstance(
+            OMX *owner, const sp<IOMXObserver> &observer);
+
+    void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
+
+    OMX *owner();
+    sp<IOMXObserver> observer();
+    OMX::node_id nodeID();
+
+    status_t freeNode();
+
+    status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param);
+    status_t getParameter(OMX_INDEXTYPE index, void *params, size_t size);
+
+    status_t setParameter(
+            OMX_INDEXTYPE index, const void *params, size_t size);
+
+    status_t getConfig(OMX_INDEXTYPE index, void *params, size_t size);
+    status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size);
+
+    status_t useBuffer(
+            OMX_U32 portIndex, const sp<IMemory> &params,
+            OMX::buffer_id *buffer);
+
+    status_t allocateBuffer(
+            OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer);
+
+    status_t allocateBufferWithBackup(
+            OMX_U32 portIndex, const sp<IMemory> &params,
+            OMX::buffer_id *buffer);
+
+    status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
+
+    status_t fillBuffer(OMX::buffer_id buffer);
+
+    status_t emptyBuffer(
+            OMX::buffer_id buffer,
+            OMX_U32 rangeOffset, OMX_U32 rangeLength,
+            OMX_U32 flags, OMX_TICKS timestamp);
+
+    status_t getExtensionIndex(
+            const char *parameterName, OMX_INDEXTYPE *index);
+
+    void onMessage(const omx_message &msg);
+    void onObserverDied();
+    void onGetHandleFailed();
+
+    static OMX_CALLBACKTYPE kCallbacks;
+
+private:
+    Mutex mLock;
+
+    OMX *mOwner;
+    OMX::node_id mNodeID;
+    OMX_HANDLETYPE mHandle;
+    sp<IOMXObserver> mObserver;
+
+    struct ActiveBuffer {
+        OMX_U32 mPortIndex;
+        OMX::buffer_id mID;
+    };
+    Vector<ActiveBuffer> mActiveBuffers;
+
+    ~OMXNodeInstance();
+
+    void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
+    void removeActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
+    void freeActiveBuffers();
+
+    static OMX_ERRORTYPE OnEvent(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_IN OMX_PTR pAppData,
+            OMX_IN OMX_EVENTTYPE eEvent,
+            OMX_IN OMX_U32 nData1,
+            OMX_IN OMX_U32 nData2,
+            OMX_IN OMX_PTR pEventData);
+
+    static OMX_ERRORTYPE OnEmptyBufferDone(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_IN OMX_PTR pAppData,
+            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+    static OMX_ERRORTYPE OnFillBufferDone(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_IN OMX_PTR pAppData,
+            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+    OMXNodeInstance(const OMXNodeInstance &);
+    OMXNodeInstance &operator=(const OMXNodeInstance &);
+};
+
+}  // namespace android
+
+#endif  // OMX_NODE_INSTANCE_H_
+
diff --git a/include/media/stagefright/QComHardwareRenderer.h b/media/libstagefright/include/QComHardwareRenderer.h
similarity index 100%
rename from include/media/stagefright/QComHardwareRenderer.h
rename to media/libstagefright/include/QComHardwareRenderer.h
diff --git a/include/media/stagefright/SampleTable.h b/media/libstagefright/include/SampleTable.h
similarity index 86%
rename from include/media/stagefright/SampleTable.h
rename to media/libstagefright/include/SampleTable.h
index 808d142..ead3431 100644
--- a/include/media/stagefright/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -35,17 +35,17 @@
 
     // type can be 'stco' or 'co64'.
     status_t setChunkOffsetParams(
-            uint32_t type, off_t data_offset, off_t data_size);
+            uint32_t type, off_t data_offset, size_t data_size);
 
-    status_t setSampleToChunkParams(off_t data_offset, off_t data_size);
+    status_t setSampleToChunkParams(off_t data_offset, size_t data_size);
 
     // type can be 'stsz' or 'stz2'.
     status_t setSampleSizeParams(
-            uint32_t type, off_t data_offset, off_t data_size);
+            uint32_t type, off_t data_offset, size_t data_size);
 
-    status_t setTimeToSampleParams(off_t data_offset, off_t data_size);
+    status_t setTimeToSampleParams(off_t data_offset, size_t data_size);
 
-    status_t setSyncSampleParams(off_t data_offset, off_t data_size);
+    status_t setSyncSampleParams(off_t data_offset, size_t data_size);
 
     ////////////////////////////////////////////////////////////////////////////
 
@@ -75,6 +75,8 @@
     status_t findClosestSyncSample(
             uint32_t start_sample_index, uint32_t *sample_index);
 
+    status_t findThumbnailSample(uint32_t *sample_index);
+
 protected:
     ~SampleTable();
 
diff --git a/include/media/stagefright/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
similarity index 86%
rename from include/media/stagefright/SoftwareRenderer.h
rename to media/libstagefright/include/SoftwareRenderer.h
index 1545493..9eed089 100644
--- a/include/media/stagefright/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -18,7 +18,7 @@
 
 #define SOFTWARE_RENDERER_H_
 
-#include <OMX_Video.h>
+#include <media/stagefright/ColorConverter.h>
 #include <media/stagefright/VideoRenderer.h>
 #include <utils/RefBase.h>
 
@@ -41,13 +41,8 @@
             const void *data, size_t size, void *platformPrivate);
 
 private:
-    uint8_t *initClip();
-
-    void renderCbYCrY(const void *data, size_t size);
-    void renderYUV420Planar(const void *data, size_t size);
-    void renderQCOMYUV420SemiPlanar(const void *data, size_t size);
-
     OMX_COLOR_FORMATTYPE mColorFormat;
+    ColorConverter mConverter;
     sp<ISurface> mISurface;
     size_t mDisplayWidth, mDisplayHeight;
     size_t mDecodedWidth, mDecodedHeight;
@@ -55,8 +50,6 @@
     sp<MemoryHeapBase> mMemoryHeap;
     int mIndex;
 
-    uint8_t *mClip;
-
     SoftwareRenderer(const SoftwareRenderer &);
     SoftwareRenderer &operator=(const SoftwareRenderer &);
 };
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/media/libstagefright/include/TIHardwareRenderer.h
similarity index 100%
rename from include/media/stagefright/TIHardwareRenderer.h
rename to media/libstagefright/include/TIHardwareRenderer.h
diff --git a/include/media/stagefright/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
similarity index 100%
rename from include/media/stagefright/TimedEventQueue.h
rename to media/libstagefright/include/TimedEventQueue.h
diff --git a/include/media/stagefright/string.h b/media/libstagefright/include/stagefright_string.h
similarity index 100%
rename from include/media/stagefright/string.h
rename to media/libstagefright/include/stagefright_string.h
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 4cadccd..edbc04e 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -10,7 +10,9 @@
 LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
 
 LOCAL_SRC_FILES:=                 \
+        ColorConverter.cpp        \
 	OMX.cpp                   \
+        OMXNodeInstance.cpp       \
         QComHardwareRenderer.cpp  \
         SoftwareRenderer.cpp      \
         TIHardwareRenderer.cpp
diff --git a/media/libstagefright/omx/ColorConverter.cpp b/media/libstagefright/omx/ColorConverter.cpp
new file mode 100644
index 0000000..e74782f
--- /dev/null
+++ b/media/libstagefright/omx/ColorConverter.cpp
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ColorConverter::ColorConverter(
+        OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
+    : mSrcFormat(from),
+      mDstFormat(to),
+      mClip(NULL) {
+}
+
+ColorConverter::~ColorConverter() {
+    delete[] mClip;
+    mClip = NULL;
+}
+
+bool ColorConverter::isValid() const {
+    if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
+        return false;
+    }
+
+    switch (mSrcFormat) {
+        case OMX_COLOR_FormatYUV420Planar:
+        case OMX_COLOR_FormatCbYCrY:
+        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
+void ColorConverter::convert(
+        size_t width, size_t height,
+        const void *srcBits, size_t srcSkip,
+        void *dstBits, size_t dstSkip) {
+    CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565);
+
+    switch (mSrcFormat) {
+        case OMX_COLOR_FormatYUV420Planar:
+            convertYUV420Planar(
+                    width, height, srcBits, srcSkip, dstBits, dstSkip);
+            break;
+
+        case OMX_COLOR_FormatCbYCrY:
+            convertCbYCrY(
+                    width, height, srcBits, srcSkip, dstBits, dstSkip);
+            break;
+
+        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
+            convertQCOMYUV420SemiPlanar(
+                    width, height, srcBits, srcSkip, dstBits, dstSkip);
+            break;
+
+        default:
+        {
+            CHECK(!"Should not be here. Unknown color conversion.");
+            break;
+        }
+    }
+}
+
+void ColorConverter::convertCbYCrY(
+        size_t width, size_t height,
+        const void *srcBits, size_t srcSkip,
+        void *dstBits, size_t dstSkip) {
+    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
+    CHECK(dstSkip >= width * 2);
+    CHECK((dstSkip & 3) == 0);
+
+    uint8_t *kAdjustedClip = initClip();
+
+    uint32_t *dst_ptr = (uint32_t *)dstBits;
+
+    const uint8_t *src = (const uint8_t *)srcBits;
+
+    for (size_t y = 0; y < height; ++y) {
+        for (size_t x = 0; x < width; x += 2) {
+            signed y1 = (signed)src[2 * x + 1] - 16;
+            signed y2 = (signed)src[2 * x + 3] - 16;
+            signed u = (signed)src[2 * x] - 128;
+            signed v = (signed)src[2 * x + 2] - 128;
+
+            signed u_b = u * 517;
+            signed u_g = -u * 100;
+            signed v_g = -v * 208;
+            signed v_r = v * 409;
+
+            signed tmp1 = y1 * 298;
+            signed b1 = (tmp1 + u_b) / 256;
+            signed g1 = (tmp1 + v_g + u_g) / 256;
+            signed r1 = (tmp1 + v_r) / 256;
+
+            signed tmp2 = y2 * 298;
+            signed b2 = (tmp2 + u_b) / 256;
+            signed g2 = (tmp2 + v_g + u_g) / 256;
+            signed r2 = (tmp2 + v_r) / 256;
+
+            uint32_t rgb1 =
+                ((kAdjustedClip[r1] >> 3) << 11)
+                | ((kAdjustedClip[g1] >> 2) << 5)
+                | (kAdjustedClip[b1] >> 3);
+
+            uint32_t rgb2 =
+                ((kAdjustedClip[r2] >> 3) << 11)
+                | ((kAdjustedClip[g2] >> 2) << 5)
+                | (kAdjustedClip[b2] >> 3);
+
+            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+        }
+
+        src += width * 2;
+        dst_ptr += dstSkip / 4;
+    }
+}
+
+void ColorConverter::convertYUV420Planar(
+        size_t width, size_t height,
+        const void *srcBits, size_t srcSkip,
+        void *dstBits, size_t dstSkip) {
+    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
+    CHECK(dstSkip >= width * 2);
+    CHECK((dstSkip & 3) == 0);
+
+    uint8_t *kAdjustedClip = initClip();
+
+    uint32_t *dst_ptr = (uint32_t *)dstBits;
+    const uint8_t *src_y = (const uint8_t *)srcBits;
+
+    const uint8_t *src_u =
+        (const uint8_t *)src_y + width * height;
+
+    const uint8_t *src_v =
+        (const uint8_t *)src_u + (width / 2) * (height / 2);
+
+    for (size_t y = 0; y < height; ++y) {
+        for (size_t x = 0; x < width; x += 2) {
+            // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
+            // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
+            // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
+
+            // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
+            // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
+            // R = .................. + 409/256 * (V - 128)
+
+            // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
+            // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
+            // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
+
+            // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
+            // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
+            // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
+
+            // clip range -278 .. 535
+
+            signed y1 = (signed)src_y[x] - 16;
+            signed y2 = (signed)src_y[x + 1] - 16;
+
+            signed u = (signed)src_u[x / 2] - 128;
+            signed v = (signed)src_v[x / 2] - 128;
+
+            signed u_b = u * 517;
+            signed u_g = -u * 100;
+            signed v_g = -v * 208;
+            signed v_r = v * 409;
+
+            signed tmp1 = y1 * 298;
+            signed b1 = (tmp1 + u_b) / 256;
+            signed g1 = (tmp1 + v_g + u_g) / 256;
+            signed r1 = (tmp1 + v_r) / 256;
+
+            signed tmp2 = y2 * 298;
+            signed b2 = (tmp2 + u_b) / 256;
+            signed g2 = (tmp2 + v_g + u_g) / 256;
+            signed r2 = (tmp2 + v_r) / 256;
+
+            uint32_t rgb1 =
+                ((kAdjustedClip[r1] >> 3) << 11)
+                | ((kAdjustedClip[g1] >> 2) << 5)
+                | (kAdjustedClip[b1] >> 3);
+
+            uint32_t rgb2 =
+                ((kAdjustedClip[r2] >> 3) << 11)
+                | ((kAdjustedClip[g2] >> 2) << 5)
+                | (kAdjustedClip[b2] >> 3);
+
+            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+        }
+
+        src_y += width;
+
+        if (y & 1) {
+            src_u += width / 2;
+            src_v += width / 2;
+        }
+
+        dst_ptr += dstSkip / 4;
+    }
+}
+
+void ColorConverter::convertQCOMYUV420SemiPlanar(
+        size_t width, size_t height,
+        const void *srcBits, size_t srcSkip,
+        void *dstBits, size_t dstSkip) {
+    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
+    CHECK(dstSkip >= width * 2);
+    CHECK((dstSkip & 3) == 0);
+
+    uint8_t *kAdjustedClip = initClip();
+
+    uint32_t *dst_ptr = (uint32_t *)dstBits;
+    const uint8_t *src_y = (const uint8_t *)srcBits;
+
+    const uint8_t *src_u =
+        (const uint8_t *)src_y + width * height;
+
+    for (size_t y = 0; y < height; ++y) {
+        for (size_t x = 0; x < width; x += 2) {
+            signed y1 = (signed)src_y[x] - 16;
+            signed y2 = (signed)src_y[x + 1] - 16;
+
+            signed u = (signed)src_u[x & ~1] - 128;
+            signed v = (signed)src_u[(x & ~1) + 1] - 128;
+
+            signed u_b = u * 517;
+            signed u_g = -u * 100;
+            signed v_g = -v * 208;
+            signed v_r = v * 409;
+
+            signed tmp1 = y1 * 298;
+            signed b1 = (tmp1 + u_b) / 256;
+            signed g1 = (tmp1 + v_g + u_g) / 256;
+            signed r1 = (tmp1 + v_r) / 256;
+
+            signed tmp2 = y2 * 298;
+            signed b2 = (tmp2 + u_b) / 256;
+            signed g2 = (tmp2 + v_g + u_g) / 256;
+            signed r2 = (tmp2 + v_r) / 256;
+
+            uint32_t rgb1 =
+                ((kAdjustedClip[b1] >> 3) << 11)
+                | ((kAdjustedClip[g1] >> 2) << 5)
+                | (kAdjustedClip[r1] >> 3);
+
+            uint32_t rgb2 =
+                ((kAdjustedClip[b2] >> 3) << 11)
+                | ((kAdjustedClip[g2] >> 2) << 5)
+                | (kAdjustedClip[r2] >> 3);
+
+            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+        }
+
+        src_y += width;
+
+        if (y & 1) {
+            src_u += width;
+        }
+
+        dst_ptr += dstSkip / 4;
+    }
+}
+
+uint8_t *ColorConverter::initClip() {
+    static const signed kClipMin = -278;
+    static const signed kClipMax = 535;
+
+    if (mClip == NULL) {
+        mClip = new uint8_t[kClipMax - kClipMin + 1];
+
+        for (signed i = kClipMin; i <= kClipMax; ++i) {
+            mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
+        }
+    }
+
+    return &mClip[-kClipMin];
+}
+
+}  // namespace android
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 8b83dd6..e361018 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -18,65 +18,28 @@
 #define LOG_TAG "OMX"
 #include <utils/Log.h>
 
-#include <sys/socket.h>
-
-#include "OMX.h"
+#include "../include/OMX.h"
 #include "OMXRenderer.h"
 
 #include "pv_omxcore.h"
 
+#include "../include/OMXNodeInstance.h"
+#include "../include/QComHardwareRenderer.h"
+#include "../include/SoftwareRenderer.h"
+#include "../include/TIHardwareRenderer.h"
+
 #include <binder/IMemory.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
-#include <media/stagefright/SoftwareRenderer.h>
-#include <media/stagefright/TIHardwareRenderer.h>
 #include <media/stagefright/VideoRenderer.h>
 
 #include <OMX_Component.h>
 
 namespace android {
 
-class NodeMeta {
-public:
-    NodeMeta(OMX *owner)
-        : mOwner(owner),
-          mHandle(NULL) {
-    }
-
-    OMX *owner() const {
-        return mOwner;
-    }
-
-    void setHandle(OMX_HANDLETYPE handle) {
-        CHECK_EQ(mHandle, NULL);
-        mHandle = handle;
-    }
-
-    OMX_HANDLETYPE handle() const {
-        return mHandle;
-    }
-
-    void setObserver(const sp<IOMXObserver> &observer) {
-        mObserver = observer;
-    }
-
-    sp<IOMXObserver> observer() {
-        return mObserver;
-    }
-
-private:
-    OMX *mOwner;
-    OMX_HANDLETYPE mHandle;
-    sp<IOMXObserver> mObserver;
-
-    NodeMeta(const NodeMeta &);
-    NodeMeta &operator=(const NodeMeta &);
-};
-
 ////////////////////////////////////////////////////////////////////////////////
 
 struct OMX::CallbackDispatcher : public RefBase {
-    CallbackDispatcher();
+    CallbackDispatcher(OMX *owner);
 
     void post(const omx_message &msg);
 
@@ -85,6 +48,8 @@
 
 private:
     Mutex mLock;
+
+    OMX *mOwner;
     bool mDone;
     Condition mQueueChanged;
     List<omx_message> mQueue;
@@ -100,8 +65,9 @@
     CallbackDispatcher &operator=(const CallbackDispatcher &);
 };
 
-OMX::CallbackDispatcher::CallbackDispatcher()
-    : mDone(false) {
+OMX::CallbackDispatcher::CallbackDispatcher(OMX *owner)
+    : mOwner(owner),
+      mDone(false) {
     pthread_attr_t attr;
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
@@ -130,12 +96,12 @@
 }
 
 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);
+    OMXNodeInstance *instance = mOwner->findInstance(msg.node);
+    if (instance == NULL) {
+        LOGV("Would have dispatched a message to a node that's already gone.");
+        return;
     }
+    instance->onMessage(msg);
 }
 
 // static
@@ -213,46 +179,30 @@
     BufferMeta &operator=(const BufferMeta &);
 };
 
-// static
-OMX_CALLBACKTYPE OMX::kCallbacks = {
-    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
-};
-
-// static
-OMX_ERRORTYPE OMX::OnEvent(
-        OMX_IN OMX_HANDLETYPE hComponent,
-        OMX_IN OMX_PTR pAppData,
-        OMX_IN OMX_EVENTTYPE eEvent,
-        OMX_IN OMX_U32 nData1,
-        OMX_IN OMX_U32 nData2,
-        OMX_IN OMX_PTR pEventData) {
-    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
-    return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData);
-}
-
-// static
-OMX_ERRORTYPE OMX::OnEmptyBufferDone(
-        OMX_IN OMX_HANDLETYPE hComponent,
-        OMX_IN OMX_PTR pAppData,
-        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
-    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
-    return meta->owner()->OnEmptyBufferDone(meta, pBuffer);
-}
-
-// static
-OMX_ERRORTYPE OMX::OnFillBufferDone(
-        OMX_IN OMX_HANDLETYPE hComponent,
-        OMX_IN OMX_PTR pAppData,
-        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
-    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
-    return meta->owner()->OnFillBufferDone(meta, pBuffer);
-}
-
 OMX::OMX()
-    : mDispatcher(new CallbackDispatcher) {
+    : mDispatcher(new CallbackDispatcher(this)),
+      mNodeCounter(0) {
 }
 
-status_t OMX::list_nodes(List<String8> *list) {
+void OMX::binderDied(const wp<IBinder> &the_late_who) {
+    OMXNodeInstance *instance;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+
+        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
+        CHECK(index >= 0);
+
+        instance = mLiveNodes.editValueAt(index);
+        mLiveNodes.removeItemsAt(index);
+
+        invalidateNodeID_l(instance->nodeID());
+    }
+
+    instance->onObserverDied();
+}
+
+status_t OMX::listNodes(List<String8> *list) {
     OMX_MasterInit();  // XXX Put this somewhere else.
 
     list->clear();
@@ -269,204 +219,132 @@
     return OK;
 }
 
-status_t OMX::allocate_node(const char *name, node_id *node) {
+status_t OMX::allocateNode(
+        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
     Mutex::Autolock autoLock(mLock);
 
     *node = 0;
 
     OMX_MasterInit();  // XXX Put this somewhere else.
 
-    NodeMeta *meta = new NodeMeta(this);
+    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
 
     OMX_HANDLETYPE handle;
     OMX_ERRORTYPE err = OMX_MasterGetHandle(
-            &handle, const_cast<char *>(name), meta, &kCallbacks);
+            &handle, const_cast<char *>(name), instance,
+            &OMXNodeInstance::kCallbacks);
 
     if (err != OMX_ErrorNone) {
-        LOGE("FAILED to allocate omx component '%s'", name);
+        LOGV("FAILED to allocate omx component '%s'", name);
 
-        delete meta;
-        meta = NULL;
+        instance->onGetHandleFailed();
 
         return UNKNOWN_ERROR;
     }
 
-    meta->setHandle(handle);
+    *node = makeNodeID(instance);
 
-    *node = meta;
+    instance->setHandle(*node, handle);
+
+    mLiveNodes.add(observer->asBinder(), instance);
+    observer->asBinder()->linkToDeath(this);
 
     return OK;
 }
 
-status_t OMX::free_node(node_id node) {
-    Mutex::Autolock autoLock(mLock);
+status_t OMX::freeNode(node_id node) {
+    OMXNodeInstance *instance = findInstance(node);
 
-    NodeMeta *meta = static_cast<NodeMeta *>(node);
+    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
+    CHECK(index >= 0);
+    mLiveNodes.removeItemsAt(index);
+    instance->observer()->asBinder()->unlinkToDeath(this);
 
-    OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
-
-    delete meta;
-    meta = NULL;
-
-    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+    return instance->freeNode();
 }
 
-status_t OMX::send_command(
+status_t OMX::sendCommand(
         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
-    Mutex::Autolock autoLock(mLock);
-
-    NodeMeta *meta = static_cast<NodeMeta *>(node);
-    OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
-
-    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+    return findInstance(node)->sendCommand(cmd, param);
 }
 
-status_t OMX::get_parameter(
+status_t OMX::getParameter(
         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_GetParameter(meta->handle(), index, params);
-
-    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+    return findInstance(node)->getParameter(
+            index, params, size);
 }
 
-status_t OMX::set_parameter(
+status_t OMX::setParameter(
         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_SetParameter(meta->handle(), index, const_cast<void *>(params));
-
-    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+    return findInstance(node)->setParameter(
+            index, params, size);
 }
 
-status_t OMX::get_config(
+status_t OMX::getConfig(
         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;
+    return findInstance(node)->getConfig(
+            index, params, size);
 }
 
-status_t OMX::set_config(
+status_t OMX::setConfig(
         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;
+    return findInstance(node)->setConfig(
+            index, params, size);
 }
 
-status_t OMX::use_buffer(
+status_t OMX::useBuffer(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer) {
-    Mutex::Autolock autoLock(mLock);
-
-    BufferMeta *buffer_meta = new BufferMeta(this, params);
-
-    OMX_BUFFERHEADERTYPE *header;
-
-    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
-    OMX_ERRORTYPE err =
-        OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
-                      params->size(), static_cast<OMX_U8 *>(params->pointer()));
-
-    if (err != OMX_ErrorNone) {
-        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
-
-        delete buffer_meta;
-        buffer_meta = NULL;
-
-        *buffer = 0;
-        return UNKNOWN_ERROR;
-    }
-
-    *buffer = header;
-
-    return OK;
+    return findInstance(node)->useBuffer(
+            port_index, params, buffer);
 }
 
-status_t OMX::allocate_buffer(
+status_t OMX::allocateBuffer(
         node_id node, OMX_U32 port_index, size_t size,
         buffer_id *buffer) {
-    Mutex::Autolock autoLock(mLock);
-
-    BufferMeta *buffer_meta = new BufferMeta(this, size);
-
-    OMX_BUFFERHEADERTYPE *header;
-
-    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
-    OMX_ERRORTYPE err =
-        OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
-                           buffer_meta, size);
-
-    if (err != OMX_ErrorNone) {
-        delete buffer_meta;
-        buffer_meta = NULL;
-
-        *buffer = 0;
-        return UNKNOWN_ERROR;
-    }
-
-    *buffer = header;
-
-    return OK;
+    return findInstance(node)->allocateBuffer(
+            port_index, size, buffer);
 }
 
-status_t OMX::allocate_buffer_with_backup(
+status_t OMX::allocateBufferWithBackup(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer) {
-    Mutex::Autolock autoLock(mLock);
-
-    BufferMeta *buffer_meta = new BufferMeta(this, params, true);
-
-    OMX_BUFFERHEADERTYPE *header;
-
-    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
-    OMX_ERRORTYPE err =
-        OMX_AllocateBuffer(
-                node_meta->handle(), &header, port_index, buffer_meta,
-                params->size());
-
-    if (err != OMX_ErrorNone) {
-        delete buffer_meta;
-        buffer_meta = NULL;
-
-        *buffer = 0;
-        return UNKNOWN_ERROR;
-    }
-
-    *buffer = header;
-
-    return OK;
+    return findInstance(node)->allocateBufferWithBackup(
+            port_index, params, buffer);
 }
 
-status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
-    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
+status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
+    return findInstance(node)->freeBuffer(
+            port_index, buffer);
+}
 
-    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
-    OMX_ERRORTYPE err =
-        OMX_FreeBuffer(node_meta->handle(), port_index, header);
+status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
+    return findInstance(node)->fillBuffer(buffer);
+}
 
-    delete buffer_meta;
-    buffer_meta = NULL;
+status_t OMX::emptyBuffer(
+        node_id node,
+        buffer_id buffer,
+        OMX_U32 range_offset, OMX_U32 range_length,
+        OMX_U32 flags, OMX_TICKS timestamp) {
+    return findInstance(node)->emptyBuffer(
+            buffer, range_offset, range_length, flags, timestamp);
+}
 
-    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+status_t OMX::getExtensionIndex(
+        node_id node,
+        const char *parameter_name,
+        OMX_INDEXTYPE *index) {
+    return findInstance(node)->getExtensionIndex(
+            parameter_name, index);
 }
 
 OMX_ERRORTYPE OMX::OnEvent(
-        NodeMeta *meta,
+        node_id node,
         OMX_IN OMX_EVENTTYPE eEvent,
         OMX_IN OMX_U32 nData1,
         OMX_IN OMX_U32 nData2,
@@ -475,7 +353,7 @@
 
     omx_message msg;
     msg.type = omx_message::EVENT;
-    msg.node = meta;
+    msg.node = node;
     msg.u.event_data.event = eEvent;
     msg.u.event_data.data1 = nData1;
     msg.u.event_data.data2 = nData2;
@@ -484,14 +362,14 @@
 
     return OMX_ErrorNone;
 }
-    
+
 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
-        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
     LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
 
     omx_message msg;
     msg.type = omx_message::EMPTY_BUFFER_DONE;
-    msg.node = meta;
+    msg.node = node;
     msg.u.buffer_data.buffer = pBuffer;
 
     mDispatcher->post(msg);
@@ -500,14 +378,12 @@
 }
 
 OMX_ERRORTYPE OMX::OnFillBufferDone(
-        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
     LOGV("OnFillBufferDone buffer=%p", pBuffer);
-    BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
-    buffer_meta->CopyFromOMX(pBuffer);
 
     omx_message msg;
     msg.type = omx_message::FILL_BUFFER_DONE;
-    msg.node = meta;
+    msg.node = node;
     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;
@@ -520,62 +396,31 @@
     return OMX_ErrorNone;
 }
 
-status_t OMX::observe_node(
-        node_id node, const sp<IOMXObserver> &observer) {
-    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
+    // mLock is already held.
 
-    node_meta->setObserver(observer);
+    node_id node = (node_id)++mNodeCounter;
+    mNodeIDToInstance.add(node, instance);
 
-    return OK;
+    return node;
 }
 
-void OMX::fill_buffer(node_id node, buffer_id buffer) {
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
-    header->nFilledLen = 0;
-    header->nOffset = 0;
-    header->nFlags = 0;
+OMXNodeInstance *OMX::findInstance(node_id node) {
+    Mutex::Autolock autoLock(mLock);
 
-    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+    ssize_t index = mNodeIDToInstance.indexOfKey(node);
 
-    OMX_ERRORTYPE err =
-        OMX_FillThisBuffer(node_meta->handle(), header);
-    CHECK_EQ(err, OMX_ErrorNone);
+    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
 }
 
-void OMX::empty_buffer(
-        node_id node,
-        buffer_id buffer,
-        OMX_U32 range_offset, OMX_U32 range_length,
-        OMX_U32 flags, OMX_TICKS timestamp) {
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
-    header->nFilledLen = range_length;
-    header->nOffset = range_offset;
-    header->nFlags = flags;
-    header->nTimeStamp = timestamp;
-
-    BufferMeta *buffer_meta =
-        static_cast<BufferMeta *>(header->pAppPrivate);
-    buffer_meta->CopyToOMX(header);
-
-    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
-
-    OMX_ERRORTYPE err =
-        OMX_EmptyThisBuffer(node_meta->handle(), header);
-    CHECK_EQ(err, OMX_ErrorNone);
+void OMX::invalidateNodeID(node_id node) {
+    Mutex::Autolock autoLock(mLock);
+    invalidateNodeID_l(node);
 }
 
-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;
+void OMX::invalidateNodeID_l(node_id node) {
+    // mLock is held.
+    mNodeIDToInstance.removeItem(node);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
new file mode 100644
index 0000000..ab8be53
--- /dev/null
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -0,0 +1,460 @@
+/*
+ * 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 "OMXNodeInstance"
+#include <utils/Log.h>
+
+#include "../include/OMXNodeInstance.h"
+
+#include "pv_omxcore.h"
+
+#include <binder/IMemory.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+struct BufferMeta {
+    BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
+        : mMem(mem),
+          mIsBackup(is_backup) {
+    }
+
+    BufferMeta(size_t size)
+        : mSize(size),
+          mIsBackup(false) {
+    }
+
+    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
+        if (!mIsBackup) {
+            return;
+        }
+
+        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
+               header->pBuffer + header->nOffset,
+               header->nFilledLen);
+    }
+
+    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
+        if (!mIsBackup) {
+            return;
+        }
+
+        memcpy(header->pBuffer + header->nOffset,
+               (const OMX_U8 *)mMem->pointer() + header->nOffset,
+               header->nFilledLen);
+    }
+
+private:
+    sp<IMemory> mMem;
+    size_t mSize;
+    bool mIsBackup;
+
+    BufferMeta(const BufferMeta &);
+    BufferMeta &operator=(const BufferMeta &);
+};
+
+// static
+OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
+    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
+};
+
+OMXNodeInstance::OMXNodeInstance(
+        OMX *owner, const sp<IOMXObserver> &observer)
+    : mOwner(owner),
+      mNodeID(NULL),
+      mHandle(NULL),
+      mObserver(observer) {
+}
+
+OMXNodeInstance::~OMXNodeInstance() {
+    CHECK_EQ(mHandle, NULL);
+}
+
+void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
+    CHECK_EQ(mHandle, NULL);
+    mNodeID = node_id;
+    mHandle = handle;
+}
+
+OMX *OMXNodeInstance::owner() {
+    return mOwner;
+}
+
+sp<IOMXObserver> OMXNodeInstance::observer() {
+    return mObserver;
+}
+
+OMX::node_id OMXNodeInstance::nodeID() {
+    return mNodeID;
+}
+
+static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
+    return (err == OMX_ErrorNone) ? OK : UNKNOWN_ERROR;
+}
+
+status_t OMXNodeInstance::freeNode() {
+    // Transition the node from its current state all the way down
+    // to "Loaded".
+    // This ensures that all active buffers are properly freed even
+    // for components that don't do this themselves on a call to
+    // "FreeHandle".
+
+    OMX_STATETYPE state;
+    CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
+    switch (state) {
+        case OMX_StateExecuting:
+        {
+            LOGV("forcing Executing->Idle");
+            sendCommand(OMX_CommandStateSet, OMX_StateIdle);
+            OMX_ERRORTYPE err;
+            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
+                   && state != OMX_StateIdle) {
+                usleep(100000);
+            }
+            CHECK_EQ(err, OMX_ErrorNone);
+
+            // fall through
+        }
+
+        case OMX_StateIdle:
+        {
+            LOGV("forcing Idle->Loaded");
+            sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
+
+            freeActiveBuffers();
+
+            OMX_ERRORTYPE err;
+            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
+                   && state != OMX_StateLoaded) {
+                LOGV("waiting for Loaded state...");
+                usleep(100000);
+            }
+            CHECK_EQ(err, OMX_ErrorNone);
+
+            // fall through
+        }
+
+        case OMX_StateLoaded:
+            break;
+
+        default:
+            CHECK(!"should not be here, unknown state.");
+            break;
+    }
+
+    OMX_ERRORTYPE err = OMX_MasterFreeHandle(mHandle);
+    mHandle = NULL;
+
+    if (err != OMX_ErrorNone) {
+        LOGE("FreeHandle FAILED with error 0x%08x.", err);
+    }
+
+    mOwner->invalidateNodeID(mNodeID);
+    mNodeID = NULL;
+
+    LOGV("OMXNodeInstance going away.");
+    delete this;
+
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::sendCommand(
+        OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::getParameter(
+        OMX_INDEXTYPE index, void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::setParameter(
+        OMX_INDEXTYPE index, const void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_ERRORTYPE err = OMX_SetParameter(
+            mHandle, index, const_cast<void *>(params));
+
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::getConfig(
+        OMX_INDEXTYPE index, void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::setConfig(
+        OMX_INDEXTYPE index, const void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_ERRORTYPE err = OMX_SetConfig(
+            mHandle, index, const_cast<void *>(params));
+
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::useBuffer(
+        OMX_U32 portIndex, const sp<IMemory> &params,
+        OMX::buffer_id *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    BufferMeta *buffer_meta = new BufferMeta(params);
+
+    OMX_BUFFERHEADERTYPE *header;
+
+    OMX_ERRORTYPE err = OMX_UseBuffer(
+            mHandle, &header, portIndex, buffer_meta,
+            params->size(), static_cast<OMX_U8 *>(params->pointer()));
+
+    if (err != OMX_ErrorNone) {
+        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
+
+        delete buffer_meta;
+        buffer_meta = NULL;
+
+        *buffer = 0;
+
+        return UNKNOWN_ERROR;
+    }
+
+    *buffer = header;
+
+    addActiveBuffer(portIndex, *buffer);
+
+    return OK;
+}
+
+status_t OMXNodeInstance::allocateBuffer(
+        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    BufferMeta *buffer_meta = new BufferMeta(size);
+
+    OMX_BUFFERHEADERTYPE *header;
+
+    OMX_ERRORTYPE err = OMX_AllocateBuffer(
+            mHandle, &header, portIndex, buffer_meta, size);
+
+    if (err != OMX_ErrorNone) {
+        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
+
+        delete buffer_meta;
+        buffer_meta = NULL;
+
+        *buffer = 0;
+
+        return UNKNOWN_ERROR;
+    }
+
+    *buffer = header;
+
+    addActiveBuffer(portIndex, *buffer);
+
+    return OK;
+}
+
+status_t OMXNodeInstance::allocateBufferWithBackup(
+        OMX_U32 portIndex, const sp<IMemory> &params,
+        OMX::buffer_id *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    BufferMeta *buffer_meta = new BufferMeta(params, true);
+
+    OMX_BUFFERHEADERTYPE *header;
+
+    OMX_ERRORTYPE err = OMX_AllocateBuffer(
+            mHandle, &header, portIndex, buffer_meta, params->size());
+
+    if (err != OMX_ErrorNone) {
+        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
+
+        delete buffer_meta;
+        buffer_meta = NULL;
+
+        *buffer = 0;
+
+        return UNKNOWN_ERROR;
+    }
+
+    *buffer = header;
+
+    addActiveBuffer(portIndex, *buffer);
+
+    return OK;
+}
+
+status_t OMXNodeInstance::freeBuffer(
+        OMX_U32 portIndex, OMX::buffer_id buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    removeActiveBuffer(portIndex, buffer);
+
+    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
+
+    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
+
+    delete buffer_meta;
+    buffer_meta = NULL;
+
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    header->nFilledLen = 0;
+    header->nOffset = 0;
+    header->nFlags = 0;
+
+    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
+
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::emptyBuffer(
+        OMX::buffer_id buffer,
+        OMX_U32 rangeOffset, OMX_U32 rangeLength,
+        OMX_U32 flags, OMX_TICKS timestamp) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    header->nFilledLen = rangeLength;
+    header->nOffset = rangeOffset;
+    header->nFlags = flags;
+    header->nTimeStamp = timestamp;
+
+    BufferMeta *buffer_meta =
+        static_cast<BufferMeta *>(header->pAppPrivate);
+    buffer_meta->CopyToOMX(header);
+
+    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
+
+    return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::getExtensionIndex(
+        const char *parameterName, OMX_INDEXTYPE *index) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
+            mHandle, const_cast<char *>(parameterName), index);
+
+    return StatusFromOMXError(err);
+}
+
+void OMXNodeInstance::onMessage(const omx_message &msg) {
+    if (msg.type == omx_message::FILL_BUFFER_DONE) {
+        OMX_BUFFERHEADERTYPE *buffer =
+            static_cast<OMX_BUFFERHEADERTYPE *>(
+                    msg.u.extended_buffer_data.buffer);
+
+        BufferMeta *buffer_meta =
+            static_cast<BufferMeta *>(buffer->pAppPrivate);
+
+        buffer_meta->CopyFromOMX(buffer);
+    }
+
+    mObserver->onMessage(msg);
+}
+
+void OMXNodeInstance::onObserverDied() {
+    LOGE("!!! Observer died. Quickly, do something, ... anything...");
+
+    // Try to force shutdown of the node and hope for the best.
+    freeNode();
+}
+
+void OMXNodeInstance::onGetHandleFailed() {
+    delete this;
+}
+
+// static
+OMX_ERRORTYPE OMXNodeInstance::OnEvent(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_EVENTTYPE eEvent,
+        OMX_IN OMX_U32 nData1,
+        OMX_IN OMX_U32 nData2,
+        OMX_IN OMX_PTR pEventData) {
+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
+    return instance->owner()->OnEvent(
+            instance->nodeID(), eEvent, nData1, nData2, pEventData);
+}
+
+// static
+OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
+    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
+}
+
+// static
+OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
+    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
+}
+
+void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
+    ActiveBuffer active;
+    active.mPortIndex = portIndex;
+    active.mID = id;
+    mActiveBuffers.push(active);
+}
+
+void OMXNodeInstance::removeActiveBuffer(
+        OMX_U32 portIndex, OMX::buffer_id id) {
+    bool found = false;
+    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
+        if (mActiveBuffers[i].mPortIndex == portIndex
+            && mActiveBuffers[i].mID == id) {
+            found = true;
+            mActiveBuffers.removeItemsAt(i);
+            break;
+        }
+    }
+
+    if (!found) {
+        LOGW("Attempt to remove an active buffer we know nothing about...");
+    }
+}
+
+void OMXNodeInstance::freeActiveBuffers() {
+    // Make sure to count down here, as freeBuffer will in turn remove
+    // the active buffer from the vector...
+    for (size_t i = mActiveBuffers.size(); i--;) {
+        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
+    }
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
index 7dc368f..8e78c77 100644
--- a/media/libstagefright/omx/QComHardwareRenderer.cpp
+++ b/media/libstagefright/omx/QComHardwareRenderer.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
+#include "../include/QComHardwareRenderer.h"
+
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryHeapPmem.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
 #include <ui/ISurface.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index 4ed6869..ef6ede0 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -17,21 +17,21 @@
 #define LOG_TAG "SoftwareRenderer"
 #include <utils/Log.h>
 
+#include "../include/SoftwareRenderer.h"
+
 #include <binder/MemoryHeapBase.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SoftwareRenderer.h>
 #include <ui/ISurface.h>
 
 namespace android {
 
-#define QCOM_YUV        0
-
 SoftwareRenderer::SoftwareRenderer(
         OMX_COLOR_FORMATTYPE colorFormat,
         const sp<ISurface> &surface,
         size_t displayWidth, size_t displayHeight,
         size_t decodedWidth, size_t decodedHeight)
     : mColorFormat(colorFormat),
+      mConverter(colorFormat, OMX_COLOR_Format16bitRGB565),
       mISurface(surface),
       mDisplayWidth(displayWidth),
       mDisplayHeight(displayHeight),
@@ -39,12 +39,12 @@
       mDecodedHeight(decodedHeight),
       mFrameSize(mDecodedWidth * mDecodedHeight * 2),  // RGB565
       mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
-      mIndex(0),
-      mClip(NULL) {
+      mIndex(0) {
     CHECK(mISurface.get() != NULL);
     CHECK(mDecodedWidth > 0);
     CHECK(mDecodedHeight > 0);
     CHECK(mMemoryHeap->heapID() >= 0);
+    CHECK(mConverter.isValid());
 
     ISurface::BufferHeap bufferHeap(
             mDisplayWidth, mDisplayHeight,
@@ -58,278 +58,19 @@
 
 SoftwareRenderer::~SoftwareRenderer() {
     mISurface->unregisterBuffers();
-
-    delete[] mClip;
-    mClip = NULL;
 }
 
 void SoftwareRenderer::render(
         const void *data, size_t size, void *platformPrivate) {
-    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
-
-    switch (mColorFormat) {
-        case OMX_COLOR_FormatYUV420Planar:
-            return renderYUV420Planar(data, size);
-
-        case OMX_COLOR_FormatCbYCrY:
-            return renderCbYCrY(data, size);
-
-        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
-            return renderQCOMYUV420SemiPlanar(data, size);
-
-        default:
-        {
-            LOGW("Cannot render color format %ld", mColorFormat);
-            break;
-        }
-    }
-}
-
-void SoftwareRenderer::renderYUV420Planar(
-        const void *data, size_t size) {
-    if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
-        LOGE("size is %d, expected %d",
-                size, (mDecodedHeight * mDecodedWidth * 3) / 2);
-    }
-    CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
-
-    uint8_t *kAdjustedClip = initClip();
-
     size_t offset = mIndex * mFrameSize;
-
     void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
 
-    uint32_t *dst_ptr = (uint32_t *)dst;
-
-    const uint8_t *src_y = (const uint8_t *)data;
-
-    const uint8_t *src_u =
-        (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
-
-#if !QCOM_YUV
-    const uint8_t *src_v =
-        (const uint8_t *)src_u + (mDecodedWidth / 2) * (mDecodedHeight / 2);
-#endif
-
-    for (size_t y = 0; y < mDecodedHeight; ++y) {
-        for (size_t x = 0; x < mDecodedWidth; x += 2) {
-            // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
-            // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
-            // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
-
-            // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
-            // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
-            // R = .................. + 409/256 * (V - 128)
-
-            // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
-            // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
-            // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
-
-            // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
-            // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
-            // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
-
-            // clip range -278 .. 535
-
-            signed y1 = (signed)src_y[x] - 16;
-            signed y2 = (signed)src_y[x + 1] - 16;
-
-#if QCOM_YUV
-            signed u = (signed)src_u[x & ~1] - 128;
-            signed v = (signed)src_u[(x & ~1) + 1] - 128;
-#else
-            signed u = (signed)src_u[x / 2] - 128;
-            signed v = (signed)src_v[x / 2] - 128;
-#endif
-
-            signed u_b = u * 517;
-            signed u_g = -u * 100;
-            signed v_g = -v * 208;
-            signed v_r = v * 409;
-
-            signed tmp1 = y1 * 298;
-            signed b1 = (tmp1 + u_b) / 256;
-            signed g1 = (tmp1 + v_g + u_g) / 256;
-            signed r1 = (tmp1 + v_r) / 256;
-
-            signed tmp2 = y2 * 298;
-            signed b2 = (tmp2 + u_b) / 256;
-            signed g2 = (tmp2 + v_g + u_g) / 256;
-            signed r2 = (tmp2 + v_r) / 256;
-
-            uint32_t rgb1 =
-                ((kAdjustedClip[r1] >> 3) << 11)
-                | ((kAdjustedClip[g1] >> 2) << 5)
-                | (kAdjustedClip[b1] >> 3);
-
-            uint32_t rgb2 =
-                ((kAdjustedClip[r2] >> 3) << 11)
-                | ((kAdjustedClip[g2] >> 2) << 5)
-                | (kAdjustedClip[b2] >> 3);
-
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
-        }
-
-        src_y += mDecodedWidth;
-
-        if (y & 1) {
-#if QCOM_YUV
-            src_u += mDecodedWidth;
-#else
-            src_u += mDecodedWidth / 2;
-            src_v += mDecodedWidth / 2;
-#endif
-        }
-
-        dst_ptr += mDecodedWidth / 2;
-    }
+    mConverter.convert(
+            mDecodedWidth, mDecodedHeight,
+            data, 0, dst, 2 * mDecodedWidth);
 
     mISurface->postBuffer(offset);
     mIndex = 1 - mIndex;
 }
 
-void SoftwareRenderer::renderCbYCrY(
-        const void *data, size_t size) {
-    if (size != (mDecodedHeight * mDecodedWidth * 2)) {
-        LOGE("size is %d, expected %d",
-                size, (mDecodedHeight * mDecodedWidth * 2));
-    }
-    CHECK(size >= (mDecodedWidth * mDecodedHeight * 2));
-
-    uint8_t *kAdjustedClip = initClip();
-
-    size_t offset = mIndex * mFrameSize;
-    void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
-    uint32_t *dst_ptr = (uint32_t *)dst;
-
-    const uint8_t *src = (const uint8_t *)data;
-
-    for (size_t y = 0; y < mDecodedHeight; ++y) {
-        for (size_t x = 0; x < mDecodedWidth; x += 2) {
-            signed y1 = (signed)src[2 * x + 1] - 16;
-            signed y2 = (signed)src[2 * x + 3] - 16;
-            signed u = (signed)src[2 * x] - 128;
-            signed v = (signed)src[2 * x + 2] - 128;
-
-            signed u_b = u * 517;
-            signed u_g = -u * 100;
-            signed v_g = -v * 208;
-            signed v_r = v * 409;
-
-            signed tmp1 = y1 * 298;
-            signed b1 = (tmp1 + u_b) / 256;
-            signed g1 = (tmp1 + v_g + u_g) / 256;
-            signed r1 = (tmp1 + v_r) / 256;
-
-            signed tmp2 = y2 * 298;
-            signed b2 = (tmp2 + u_b) / 256;
-            signed g2 = (tmp2 + v_g + u_g) / 256;
-            signed r2 = (tmp2 + v_r) / 256;
-
-            uint32_t rgb1 =
-                ((kAdjustedClip[r1] >> 3) << 11)
-                | ((kAdjustedClip[g1] >> 2) << 5)
-                | (kAdjustedClip[b1] >> 3);
-
-            uint32_t rgb2 =
-                ((kAdjustedClip[r2] >> 3) << 11)
-                | ((kAdjustedClip[g2] >> 2) << 5)
-                | (kAdjustedClip[b2] >> 3);
-
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
-        }
-
-        src += mDecodedWidth * 2;
-        dst_ptr += mDecodedWidth / 2;
-    }
-
-    mISurface->postBuffer(offset);
-    mIndex = 1 - mIndex;
-}
-
-void SoftwareRenderer::renderQCOMYUV420SemiPlanar(
-        const void *data, size_t size) {
-    if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
-        LOGE("size is %d, expected %d",
-                size, (mDecodedHeight * mDecodedWidth * 3) / 2);
-    }
-    CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
-
-    uint8_t *kAdjustedClip = initClip();
-
-    size_t offset = mIndex * mFrameSize;
-
-    void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
-
-    uint32_t *dst_ptr = (uint32_t *)dst;
-
-    const uint8_t *src_y = (const uint8_t *)data;
-
-    const uint8_t *src_u =
-        (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
-
-    for (size_t y = 0; y < mDecodedHeight; ++y) {
-        for (size_t x = 0; x < mDecodedWidth; x += 2) {
-            signed y1 = (signed)src_y[x] - 16;
-            signed y2 = (signed)src_y[x + 1] - 16;
-
-            signed u = (signed)src_u[x & ~1] - 128;
-            signed v = (signed)src_u[(x & ~1) + 1] - 128;
-
-            signed u_b = u * 517;
-            signed u_g = -u * 100;
-            signed v_g = -v * 208;
-            signed v_r = v * 409;
-
-            signed tmp1 = y1 * 298;
-            signed b1 = (tmp1 + u_b) / 256;
-            signed g1 = (tmp1 + v_g + u_g) / 256;
-            signed r1 = (tmp1 + v_r) / 256;
-
-            signed tmp2 = y2 * 298;
-            signed b2 = (tmp2 + u_b) / 256;
-            signed g2 = (tmp2 + v_g + u_g) / 256;
-            signed r2 = (tmp2 + v_r) / 256;
-
-            uint32_t rgb1 =
-                ((kAdjustedClip[b1] >> 3) << 11)
-                | ((kAdjustedClip[g1] >> 2) << 5)
-                | (kAdjustedClip[r1] >> 3);
-
-            uint32_t rgb2 =
-                ((kAdjustedClip[b2] >> 3) << 11)
-                | ((kAdjustedClip[g2] >> 2) << 5)
-                | (kAdjustedClip[r2] >> 3);
-
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
-        }
-
-        src_y += mDecodedWidth;
-
-        if (y & 1) {
-            src_u += mDecodedWidth;
-        }
-
-        dst_ptr += mDecodedWidth / 2;
-    }
-
-    mISurface->postBuffer(offset);
-    mIndex = 1 - mIndex;
-}
-
-uint8_t *SoftwareRenderer::initClip() {
-    static const signed kClipMin = -278;
-    static const signed kClipMax = 535;
-
-    if (mClip == NULL) {
-        mClip = new uint8_t[kClipMax - kClipMin + 1];
-
-        for (signed i = kClipMin; i <= kClipMax; ++i) {
-            mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
-        }
-    }
-
-    return &mClip[-kClipMin];
-}
-
 }  // namespace android
diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
index ebade4a..6dde86a 100644
--- a/media/libstagefright/omx/TIHardwareRenderer.cpp
+++ b/media/libstagefright/omx/TIHardwareRenderer.cpp
@@ -17,7 +17,8 @@
 #define LOG_TAG "TIHardwareRenderer"
 #include <utils/Log.h>
 
-#include <media/stagefright/TIHardwareRenderer.h>
+#include "../include/TIHardwareRenderer.h"
+
 #include <media/stagefright/MediaDebug.h>
 #include <ui/ISurface.h>
 #include <ui/Overlay.h>
diff --git a/media/libstagefright/string.cpp b/media/libstagefright/string.cpp
index 5b16784..bd6204b 100644
--- a/media/libstagefright/string.cpp
+++ b/media/libstagefright/string.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/string.h>
+#include "include/stagefright_string.h"
 
 namespace android {