resolved conflicts for merge of c66d53f9 to eclair-mr2
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..8c25d85 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();
 
@@ -117,6 +133,8 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
+    DataSource::RegisterDefaultSniffers();
+
 #if 1
     if (argc != 2) {
         fprintf(stderr, "usage: %s filename\n", argv[0]);
@@ -126,7 +144,7 @@
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
 
-#if 0
+#if 1
     sp<MediaSource> source = createSource(argv[1]);
 
     if (source == NULL) {
@@ -144,8 +162,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 +177,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 4ffc8e4..d26e558 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -52,21 +52,26 @@
 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;
+    CHECK(meta->findInt64(kKeyDuration, &durationUs));
 
-    int64_t durationUs = ((int64_t)durationUnits * 1000000) / timeScale;
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
 
-    sp<OMXCodec> decoder = OMXCodec::Create(
+    sp<MediaSource> rawSource;
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
+        rawSource = source;
+    } else {
+        rawSource = OMXCodec::Create(
             client->interface(), meta, false /* createEncoder */, source);
 
-    if (decoder == NULL) {
-        return;
+        if (rawSource == NULL) {
+            fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
+            return;
+        }
     }
 
-    decoder->start();
+    rawSource->start();
 
     if (gReproduceBug >= 3 && gReproduceBug <= 5) {
         status_t err;
@@ -74,24 +79,28 @@
         MediaSource::ReadOptions options;
         int64_t seekTimeUs = -1;
         for (;;) {
-            err = decoder->read(&buffer, &options);
+            err = rawSource->read(&buffer, &options);
             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;
                     }
@@ -134,7 +143,7 @@
             }
         }
 
-        decoder->stop();
+        rawSource->stop();
 
         return;
     }
@@ -151,12 +160,17 @@
         MediaBuffer *buffer;
 
         for (;;) {
-            status_t err = decoder->read(&buffer, &options);
+            status_t err = rawSource->read(&buffer, &options);
             options.clearSeekTo();
 
             if (err != OK) {
                 CHECK_EQ(buffer, NULL);
 
+                if (err == INFO_FORMAT_CHANGED) {
+                    printf("format changed.\n");
+                    continue;
+                }
+
                 break;
             }
 
@@ -188,7 +202,7 @@
         options.setSeekTo(0);
     }
 
-    decoder->stop();
+    rawSource->stop();
     printf("\n");
 
     int64_t delay = getNowUs() - startTime;
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/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index feb66e3..1efeb92 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -34,6 +34,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
+extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
 
 }  // namespace android
 
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/IOMX.cpp b/media/libmedia/IOMX.cpp
index 88a7064..76a9e7d 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -284,7 +284,7 @@
         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();
     }
@@ -302,7 +302,7 @@
         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();
     }
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index fb569da..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
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 0a6c365..b81684b 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -366,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/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 2cdc351..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;
     }
@@ -138,12 +145,6 @@
         return UNKNOWN_ERROR;
     }
     player_type playerType = getPlayerType(url);
-#if !defined(NO_OPENCORE) && defined(BUILD_WITH_FULL_STAGEFRIGHT)
-    if (playerType == STAGEFRIGHT_PLAYER) {
-        // Stagefright doesn't support metadata in this branch yet.
-        playerType = PV_PLAYER;
-    }
-#endif
     LOGV("player type = %d", playerType);
     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
     if (p == NULL) return NO_INIT;
@@ -182,12 +183,6 @@
     }
 
     player_type playerType = getPlayerType(fd, offset, length);
-#if !defined(NO_OPENCORE) && defined(BUILD_WITH_FULL_STAGEFRIGHT)
-    if (playerType == STAGEFRIGHT_PLAYER) {
-        // Stagefright doesn't support metadata in this branch yet.
-        playerType = PV_PLAYER;
-    }
-#endif
     LOGV("player type = %d", playerType);
     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
     if (p == NULL) {
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 9f71dae..c36e769 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -16,24 +16,26 @@
 
 LOCAL_SRC_FILES +=                \
         AMRExtractor.cpp          \
+        AudioPlayer.cpp           \
         CachingDataSource.cpp     \
+        CameraSource.cpp          \
         DataSource.cpp            \
         FileSource.cpp            \
         HTTPDataSource.cpp        \
         HTTPStream.cpp            \
         JPEGSource.cpp            \
-        MediaExtractor.cpp        \
         MP3Extractor.cpp          \
         MPEG4Extractor.cpp        \
         MPEG4Writer.cpp           \
+        MediaExtractor.cpp        \
         MediaPlayerImpl.cpp       \
         MmapSource.cpp            \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
-        AudioPlayer.cpp           \
-        stagefright_string.cpp
+        WAVExtractor.cpp          \
+        string.cpp
 
 endif
 
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 538facb..d7e3f66 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -210,15 +210,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..2a6dbc4 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+#include "include/MP3Extractor.h"
+#include "include/MPEG4Extractor.h"
+#include "include/WAVExtractor.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 +29,7 @@
     *x = 0;
 
     uint8_t byte[2];
-    if (read_at(offset, byte, 2) != 2) {
+    if (readAt(offset, byte, 2) != 2) {
         return false;
     }
 
@@ -86,6 +88,7 @@
     RegisterSniffer(SniffMP3);
     RegisterSniffer(SniffMPEG4);
     RegisterSniffer(SniffAMR);
+    RegisterSniffer(SniffWAV);
 }
 
 }  // namespace android
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 4dedebd..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/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..8dd8ea9 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);
+                    8000LL * (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..9d17064 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,13 +995,14 @@
         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;
     }
 
     if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
-        || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)) {
+        || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
+        || !memcmp(header, "ftypM4A ", 8)) {
         *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
         *confidence = 0.1;
 
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/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 87b5b24..04b1454 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -32,5 +32,6 @@
 const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
+const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 8535f52..19a1f85 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -18,12 +18,17 @@
 #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 "include/WAVExtractor.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 +46,7 @@
         }
 
         mime = tmp.string();
-        LOGI("Autodetected media content as '%s' with confidence %.2f",
+        LOGV("Autodetected media content as '%s' with confidence %.2f",
              mime, confidence);
     }
 
@@ -53,9 +58,32 @@
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
         return new AMRExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
+        return new WAVExtractor(source);
     }
 
     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 622ea7e..c1044a3 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -18,16 +18,17 @@
 #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/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaPlayerImpl.h>
 #include <media/stagefright/MetaData.h>
@@ -51,7 +52,7 @@
       mPlaying(false),
       mPaused(false),
       mSeeking(false) {
-    LOGI("MediaPlayerImpl(%s)", uri);
+    LOGV("MediaPlayerImpl(%s)", uri);
     DataSource::RegisterDefaultSniffers();
 
     status_t err = mClient.connect();
@@ -69,18 +70,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;
@@ -103,7 +93,7 @@
       mPlaying(false),
       mPaused(false),
       mSeeking(false) {
-    LOGI("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
+    LOGV("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
     DataSource::RegisterDefaultSniffers();
 
     status_t err = mClient.connect();
@@ -140,7 +130,7 @@
 }
 
 void MediaPlayerImpl::play() {
-    LOGI("play");
+    LOGV("play");
 
     if (mPlaying) {
         if (mPaused) {
@@ -241,7 +231,7 @@
         {
             Mutex::Autolock autoLock(mLock);
             if (mSeeking) {
-                LOGI("seek-options to %lld", mSeekTimeUs);
+                LOGV("seek-options to %lld", mSeekTimeUs);
                 options.setSeekTo(mSeekTimeUs);
 
                 mSeeking = false;
@@ -258,6 +248,13 @@
         status_t err = mVideoDecoder->read(&buffer, &options);
         CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
 
+        if (err == INFO_FORMAT_CHANGED) {
+            LOGV("format changed.");
+            depopulateISurface();
+            populateISurface();
+            continue;
+        }
+
         if (err == ERROR_END_OF_STREAM || err != OK) {
             eof = true;
             continue;
@@ -269,15 +266,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;
@@ -332,14 +323,14 @@
         if (delay_us < -15000) {
             // We're late.
 
-            LOGI("we're late by %lld ms, dropping a frame\n",
+            LOGV("we're late by %lld ms, dropping a frame\n",
                  -delay_us / 1000);
 
             buffer->release();
             buffer = NULL;
             return;
         } else if (delay_us > 100000) {
-            LOGI("we're much too early (by %lld ms)\n",
+            LOGV("we're much too early (by %lld ms)\n",
                  delay_us / 1000);
             usleep(100000);
             continue;
@@ -391,12 +382,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;
                 }
             }
 
@@ -410,17 +399,24 @@
 }
 
 void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
-    LOGI("setAudioSource");
+    LOGV("setAudioSource");
     mAudioSource = source;
 
     sp<MetaData> meta = source->getFormat();
 
-    mAudioDecoder = OMXCodec::Create(
-            mClient.interface(), meta, false /* createEncoder */, source);
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+        mAudioDecoder = source;
+    } else {
+        mAudioDecoder = OMXCodec::Create(
+                mClient.interface(), meta, false /* createEncoder */, source);
+    }
 }
 
 void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
-    LOGI("setVideoSource");
+    LOGV("setVideoSource");
     mVideoSource = source;
 
     sp<MetaData> meta = source->getFormat();
@@ -441,7 +437,7 @@
 }
 
 void MediaPlayerImpl::setSurface(const sp<Surface> &surface) {
-    LOGI("setSurface %p", surface.get());
+    LOGV("setSurface %p", surface.get());
     Mutex::Autolock autoLock(mLock);
 
     depopulateISurface();
@@ -455,7 +451,7 @@
 }
 
 void MediaPlayerImpl::setISurface(const sp<ISurface> &isurface) {
-    LOGI("setISurface %p", isurface.get());
+    LOGV("setISurface %p", isurface.get());
     Mutex::Autolock autoLock(mLock);
 
     depopulateISurface();
@@ -499,7 +495,7 @@
         host = string(host, 0, colon - host.c_str());
     }
 
-    LOGI("Connecting to host '%s', port %d, path '%s'",
+    LOGV("Connecting to host '%s', port %d, path '%s'",
          host.c_str(), port, path.c_str());
 
     HTTPStream *http = new HTTPStream;
@@ -533,7 +529,7 @@
 
             http->disconnect();
 
-            LOGI("Redirecting to %s\n", location.c_str());
+            LOGV("Redirecting to %s\n", location.c_str());
 
             host = string(location, 0, slashPos);
 
@@ -588,7 +584,7 @@
 }
 
 status_t MediaPlayerImpl::seekTo(int64_t time) {
-    LOGI("seekTo %lld", time);
+    LOGV("seekTo %lld", time);
 
     if (mPaused) {
         return UNKNOWN_ERROR;
@@ -621,6 +617,9 @@
     success = success && meta->findInt32(kKeyHeight, &decodedHeight);
     CHECK(success);
 
+    LOGV("mVideoWidth=%d, mVideoHeight=%d, decodedWidth=%d, decodedHeight=%d",
+         mVideoWidth, mVideoHeight, decodedWidth, decodedHeight);
+
     if (mSurface.get() != NULL) {
         mVideoRenderer =
             mClient.interface()->createRenderer(
@@ -651,7 +650,7 @@
 
 void MediaPlayerImpl::setAudioSink(
         const sp<MediaPlayerBase::AudioSink> &audioSink) {
-    LOGI("setAudioSink %p", audioSink.get());
+    LOGV("setAudioSink %p", audioSink.get());
     mAudioSink = audioSink;
 }
 
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/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ebf1e0c..6c0367a 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;
@@ -169,52 +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;
-    sp<OMXCodecObserver> observer = new OMXCodecObserver;
-    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->allocateNode(componentName, observer, &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;
@@ -222,20 +210,15 @@
     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 |= kRequiresAllocateBufferOnOutputPorts;
-        quirks |= kOutputDimensionsAre16Aligned;
     }
 
     if (!strncmp(componentName, "OMX.TI.", 7)) {
@@ -248,8 +231,94 @@
         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);
@@ -331,7 +400,7 @@
             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")
@@ -452,7 +521,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
@@ -493,9 +562,25 @@
     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)) {
@@ -516,12 +601,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);
@@ -554,8 +640,8 @@
             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);
 
@@ -564,14 +650,108 @@
     video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
     video_def->eColorFormat = colorFormat;
 
+    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)) {
@@ -639,6 +819,7 @@
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
 
+    video_def->eCompressionFormat = compressionFormat;
     video_def->eColorFormat = OMX_COLOR_FormatUnused;
 
     err = mOMX->setParameter(
@@ -687,6 +868,7 @@
       mInitialBufferSubmit(true),
       mSignalledEOS(false),
       mNoMoreOutputData(false),
+      mOutputPortSettingsHaveChanged(false),
       mSeekTimeUs(-1) {
     mPortStatus[kPortIndexInput] = ENABLED;
     mPortStatus[kPortIndexOutput] = ENABLED;
@@ -990,12 +1172,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);
@@ -1064,6 +1242,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:
@@ -1086,6 +1329,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);
@@ -1443,7 +1695,7 @@
     }
 
     OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
-    OMX_TICKS timestamp = 0;
+    OMX_TICKS timestampUs = 0;
     size_t srcLength = 0;
 
     if (err != OK) {
@@ -1463,15 +1715,11 @@
                (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);
         }
     }
 
@@ -1482,7 +1730,7 @@
 
     err = mOMX->emptyBuffer(
             mNode, info->mBuffer, 0, srcLength,
-            flags, timestamp);
+            flags, timestampUs);
 
     if (err != OK) {
         setState(ERROR);
@@ -1794,6 +2042,7 @@
     mInitialBufferSubmit = true;
     mSignalledEOS = false;
     mNoMoreOutputData = false;
+    mOutputPortSettingsHaveChanged = false;
     mSeekTimeUs = -1;
     mFilledBuffers.clear();
 
@@ -1864,6 +2113,8 @@
 }
 
 sp<MetaData> OMXCodec::getFormat() {
+    Mutex::Autolock autoLock(mLock);
+
     return mOutputFormat;
 }
 
@@ -1941,6 +2192,12 @@
         return ERROR_END_OF_STREAM;
     }
 
+    if (mOutputPortSettingsHaveChanged) {
+        mOutputPortSettingsHaveChanged = false;
+
+        return INFO_FORMAT_CHANGED;
+    }
+
     size_t index = *mFilledBuffers.begin();
     mFilledBuffers.erase(mFilledBuffers.begin());
 
@@ -2041,8 +2298,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) {
@@ -2410,7 +2665,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);
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 346b5aa..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/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/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
new file mode 100644
index 0000000..542c764
--- /dev/null
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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 "WAVExtractor"
+#include <utils/Log.h>
+
+#include "include/WAVExtractor.h"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+namespace android {
+
+static uint16_t WAVE_FORMAT_PCM = 1;
+
+static uint32_t U32_LE_AT(const uint8_t *ptr) {
+    return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
+}
+
+static uint16_t U16_LE_AT(const uint8_t *ptr) {
+    return ptr[1] << 8 | ptr[0];
+}
+
+struct WAVSource : public MediaSource {
+    WAVSource(
+            const sp<DataSource> &dataSource,
+            int32_t sampleRate, int32_t numChannels,
+            off_t offset, size_t size);
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+    virtual ~WAVSource();
+
+private:
+    static const size_t kMaxFrameSize;
+
+    sp<DataSource> mDataSource;
+    int32_t mSampleRate;
+    int32_t mNumChannels;
+    off_t mOffset;
+    size_t mSize;
+    bool mStarted;
+    MediaBufferGroup *mGroup;
+    off_t mCurrentPos;
+
+    WAVSource(const WAVSource &);
+    WAVSource &operator=(const WAVSource &);
+};
+
+WAVExtractor::WAVExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mValidFormat(false) {
+    mInitCheck = init();
+}
+
+WAVExtractor::~WAVExtractor() {
+}
+
+size_t WAVExtractor::countTracks() {
+    return mInitCheck == OK ? 1 : 0;
+}
+
+sp<MediaSource> WAVExtractor::getTrack(size_t index) {
+    if (mInitCheck != OK || index > 0) {
+        return NULL;
+    }
+
+    return new WAVSource(
+            mDataSource, mSampleRate, mNumChannels, mDataOffset, mDataSize);
+}
+
+sp<MetaData> WAVExtractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
+    if (mInitCheck != OK || index > 0) {
+        return NULL;
+    }
+
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+    meta->setInt32(kKeyChannelCount, mNumChannels);
+    meta->setInt32(kKeySampleRate, mSampleRate);
+
+    int64_t durationUs =
+        1000000LL * (mDataSize / (mNumChannels * 2)) / mSampleRate;
+
+    meta->setInt64(kKeyDuration, durationUs);
+
+    return meta;
+}
+
+status_t WAVExtractor::init() {
+    uint8_t header[12];
+    if (mDataSource->readAt(
+                0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return NO_INIT;
+    }
+
+    if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
+        return NO_INIT;
+    }
+
+    size_t totalSize = U32_LE_AT(&header[4]);
+
+    off_t offset = 12;
+    size_t remainingSize = totalSize;
+    while (remainingSize >= 8) {
+        uint8_t chunkHeader[8];
+        if (mDataSource->readAt(offset, chunkHeader, 8) < 8) {
+            return NO_INIT;
+        }
+
+        remainingSize -= 8;
+        offset += 8;
+        
+        uint32_t chunkSize = U32_LE_AT(&chunkHeader[4]);
+
+        if (chunkSize > remainingSize) {
+            return NO_INIT;
+        }
+
+        if (!memcmp(chunkHeader, "fmt ", 4)) {
+            if (chunkSize < 16) {
+                return NO_INIT;
+            }
+
+            uint8_t formatSpec[16];
+            if (mDataSource->readAt(offset, formatSpec, 16) < 16) {
+                return NO_INIT;
+            }
+
+            uint16_t format = U16_LE_AT(formatSpec);
+            if (format != WAVE_FORMAT_PCM) {
+                return ERROR_UNSUPPORTED;
+            }
+
+            mNumChannels = U16_LE_AT(&formatSpec[2]);
+            if (mNumChannels != 1 && mNumChannels != 2) {
+                return ERROR_UNSUPPORTED;
+            }
+
+            mSampleRate = U32_LE_AT(&formatSpec[4]);
+
+            if (U16_LE_AT(&formatSpec[14]) != 16) {
+                return ERROR_UNSUPPORTED;
+            }
+
+            mValidFormat = true;
+        } else if (!memcmp(chunkHeader, "data", 4)) {
+            if (mValidFormat) {
+                mDataOffset = offset;
+                mDataSize = chunkSize;
+
+                return OK;
+            }
+        }
+
+        offset += chunkSize;
+    }
+
+    return NO_INIT;
+}
+
+const size_t WAVSource::kMaxFrameSize = 32768;
+
+WAVSource::WAVSource(
+        const sp<DataSource> &dataSource,
+        int32_t sampleRate, int32_t numChannels,
+        off_t offset, size_t size)
+    : mDataSource(dataSource),
+      mSampleRate(sampleRate),
+      mNumChannels(numChannels),
+      mOffset(offset),
+      mSize(size),
+      mStarted(false),
+      mGroup(NULL) {
+}
+
+WAVSource::~WAVSource() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t WAVSource::start(MetaData *params) {
+    LOGV("WAVSource::start");
+
+    CHECK(!mStarted);
+
+    mGroup = new MediaBufferGroup;
+    mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+
+    mCurrentPos = mOffset;
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t WAVSource::stop() {
+    LOGV("WAVSource::stop");
+
+    CHECK(mStarted);
+
+    delete mGroup;
+    mGroup = NULL;
+
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> WAVSource::getFormat() {
+    LOGV("WAVSource::getFormat");
+
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+    meta->setInt32(kKeyChannelCount, mNumChannels);
+    meta->setInt32(kKeySampleRate, mSampleRate);
+
+    int64_t durationUs =
+        1000000LL * (mSize / (mNumChannels * 2)) / mSampleRate;
+
+    meta->setInt64(kKeyDuration, durationUs);
+
+    return meta;
+}
+
+status_t WAVSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+        int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2;
+        if (pos > mSize) {
+            pos = mSize;
+        }
+        mCurrentPos = pos + mOffset;
+    }
+
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+    if (err != OK) {
+        return err;
+    }
+
+    ssize_t n = mDataSource->readAt(
+            mCurrentPos, buffer->data(), kMaxFrameSize);
+
+    if (n <= 0) {
+        buffer->release();
+        buffer = NULL;
+
+        return ERROR_END_OF_STREAM;
+    }
+
+    mCurrentPos += n;
+
+    buffer->set_range(0, n);
+    buffer->meta_data()->setInt64(
+            kKeyTime,
+            1000000LL * (mCurrentPos - mOffset)
+                / (mNumChannels * 2) / mSampleRate);
+
+
+    *out = buffer;
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SniffWAV(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+    char header[12];
+    if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return false;
+    }
+
+    if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
+        return false;
+    }
+
+    *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
+    *confidence = 0.3f;
+
+    return true;
+}
+
+}  // 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 96%
rename from include/media/stagefright/HTTPStream.h
rename to media/libstagefright/include/HTTPStream.h
index 72e796c..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/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/include/OMX.h b/media/libstagefright/include/OMX.h
index d0bd61e..a4b62b2 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -99,7 +99,7 @@
             OMX_IN OMX_U32 nData1,
             OMX_IN OMX_U32 nData2,
             OMX_IN OMX_PTR pEventData);
-
+        
     OMX_ERRORTYPE OnEmptyBufferDone(
             node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
 
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/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/MP3Extractor.h b/media/libstagefright/include/WAVExtractor.h
similarity index 65%
copy from include/media/stagefright/MP3Extractor.h
copy to media/libstagefright/include/WAVExtractor.h
index 11ba01d..10b9700 100644
--- a/include/media/stagefright/MP3Extractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef MP3_EXTRACTOR_H_
+#ifndef WAV_EXTRACTOR_H_
 
-#define MP3_EXTRACTOR_H_
+#define WAV_EXTRACTOR_H_
 
 #include <media/stagefright/MediaExtractor.h>
 
@@ -25,31 +25,37 @@
 class DataSource;
 class String8;
 
-class MP3Extractor : public MediaExtractor {
+class WAVExtractor : public MediaExtractor {
 public:
     // Extractor assumes ownership of "source".
-    MP3Extractor(const sp<DataSource> &source);
+    WAVExtractor(const sp<DataSource> &source);
 
     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();
+    virtual ~WAVExtractor();
 
 private:
     sp<DataSource> mDataSource;
-    off_t mFirstFramePos;
-    sp<MetaData> mMeta;
-    uint32_t mFixedHeader;
+    status_t mInitCheck;
+    bool mValidFormat;
+    uint16_t mNumChannels;
+    uint32_t mSampleRate;
+    off_t mDataOffset;
+    size_t mDataSize;
 
-    MP3Extractor(const MP3Extractor &);
-    MP3Extractor &operator=(const MP3Extractor &);
+    status_t init();
+
+    WAVExtractor(const WAVExtractor &);
+    WAVExtractor &operator=(const WAVExtractor &);
 };
 
-bool SniffMP3(
+bool SniffWAV(
         const sp<DataSource> &source, String8 *mimeType, float *confidence);
 
 }  // namespace android
 
-#endif  // MP3_EXTRACTOR_H_
+#endif  // WAV_EXTRACTOR_H_
+
diff --git a/include/media/stagefright/stagefright_string.h b/media/libstagefright/include/stagefright_string.h
similarity index 92%
rename from include/media/stagefright/stagefright_string.h
rename to media/libstagefright/include/stagefright_string.h
index 1ed4c86..5dc7116 100644
--- a/include/media/stagefright/stagefright_string.h
+++ b/media/libstagefright/include/stagefright_string.h
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef STAGEFRIGHT_STRING_H_
+#ifndef STRING_H_
 
-#define STAGEFRIGHT_STRING_H_
+#define STRING_H_
 
 #include <utils/String8.h>
 
@@ -51,4 +51,4 @@
 
 }  // namespace android
 
-#endif  // STAGEFRIGHT_STRING_H_
+#endif  // STRING_H_
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 25da813..389c2c9 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -9,6 +9,7 @@
 LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
 
 LOCAL_SRC_FILES:=                 \
+        ColorConverter.cpp        \
 	OMX.cpp                   \
         OMXNodeInstance.cpp       \
         SoftwareRenderer.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 4ccd4bd..5b3cc1b 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -24,10 +24,10 @@
 #include "pv_omxcore.h"
 
 #include "../include/OMXNodeInstance.h"
+#include "../include/SoftwareRenderer.h"
 
 #include <binder/IMemory.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SoftwareRenderer.h>
 #include <media/stagefright/VideoRenderer.h>
 
 #include <OMX_Component.h>
@@ -233,7 +233,7 @@
             &OMXNodeInstance::kCallbacks);
 
     if (err != OMX_ErrorNone) {
-        LOGE("FAILED to allocate omx component '%s'", name);
+        LOGV("FAILED to allocate omx component '%s'", name);
 
         instance->onGetHandleFailed();
 
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index 39de504..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 %d", 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/stagefright_string.cpp b/media/libstagefright/string.cpp
similarity index 97%
rename from media/libstagefright/stagefright_string.cpp
rename to media/libstagefright/string.cpp
index 2aedb80..bd6204b 100644
--- a/media/libstagefright/stagefright_string.cpp
+++ b/media/libstagefright/string.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/stagefright_string.h>
+#include "include/stagefright_string.h"
 
 namespace android {