am f4dc9da3: Merge snapshot variant of donut back into the main tree

Merge commit 'f4dc9da3724c20837e3a361060acd139775541ac'

* commit 'f4dc9da3724c20837e3a361060acd139775541ac':
  donut snapshot
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
new file mode 100644
index 0000000..fd681a2
--- /dev/null
+++ b/cmds/stagefright/Android.mk
@@ -0,0 +1,66 @@
+ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	stagefright.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libstagefright
+
+LOCAL_C_INCLUDES:= \
+	frameworks/base/media/libstagefright \
+	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+        $(TOP)/external/opencore/android
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= stagefright
+
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=         \
+        record.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libstagefright
+
+LOCAL_C_INCLUDES:= \
+	frameworks/base/media/libstagefright \
+	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+        $(TOP)/external/opencore/android
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= record
+
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+# include $(CLEAR_VARS)
+# 
+# LOCAL_SRC_FILES:=         \
+#         play.cpp
+# 
+# LOCAL_SHARED_LIBRARIES := \
+# 	libstagefright
+# 
+# LOCAL_C_INCLUDES:= \
+# 	frameworks/base/media/libstagefright \
+# 	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+#         $(TOP)/external/opencore/android
+# 
+# LOCAL_CFLAGS += -Wno-multichar
+# 
+# LOCAL_MODULE:= play
+# 
+# include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/cmds/stagefright/WaveWriter.h b/cmds/stagefright/WaveWriter.h
new file mode 100644
index 0000000..a0eb66e
--- /dev/null
+++ b/cmds/stagefright/WaveWriter.h
@@ -0,0 +1,71 @@
+/*
+ * 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 ANDROID_WAVEWRITER_H_
+
+#define ANDROID_WAVEWRITER_H_
+
+namespace android {
+
+class WaveWriter {
+public:
+    WaveWriter(const char *filename,
+               uint16_t num_channels, uint32_t sampling_rate)
+        : mFile(fopen(filename, "wb")),
+          mTotalBytes(0) {
+        fwrite("RIFFxxxxWAVEfmt \x10\x00\x00\x00\x01\x00", 1, 22, mFile); 
+        write_u16(num_channels);
+        write_u32(sampling_rate);
+        write_u32(sampling_rate * num_channels * 2);
+        write_u16(num_channels * 2);
+        write_u16(16);
+        fwrite("dataxxxx", 1, 8, mFile);
+    }
+
+    ~WaveWriter() {
+        fseek(mFile, 40, SEEK_SET);
+        write_u32(mTotalBytes);
+
+        fseek(mFile, 4, SEEK_SET);
+        write_u32(36 + mTotalBytes);
+
+        fclose(mFile);
+        mFile = NULL;
+    }
+
+    void Append(const void *data, size_t size) {
+        fwrite(data, 1, size, mFile);
+        mTotalBytes += size;
+    }
+
+private:
+    void write_u16(uint16_t x) {
+        fputc(x & 0xff, mFile);
+        fputc(x >> 8, mFile);
+    }
+
+    void write_u32(uint32_t x) {
+        write_u16(x & 0xffff);
+        write_u16(x >> 16);
+    }
+
+    FILE *mFile;
+    size_t mTotalBytes;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_WAVEWRITER_H_
diff --git a/cmds/stagefright/play.cpp b/cmds/stagefright/play.cpp
new file mode 100644
index 0000000..c6e778e
--- /dev/null
+++ b/cmds/stagefright/play.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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 <binder/ProcessState.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/TimedEventQueue.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXDecoder.h>
+
+using namespace android;
+
+struct NewPlayer {
+    NewPlayer();
+    ~NewPlayer();
+
+    void setSource(const char *uri);
+    void start();
+    void pause();
+    void stop();
+
+private:
+    struct PlayerEvent : public TimedEventQueue::Event {
+        PlayerEvent(NewPlayer *player,
+                    void (NewPlayer::*method)(int64_t realtime_us))
+            : mPlayer(player),
+              mMethod(method) {
+        }
+
+        virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
+            (mPlayer->*mMethod)(realtime_us);
+        }
+
+    private:
+        NewPlayer *mPlayer;
+        void (NewPlayer::*mMethod)(int64_t realtime_us);
+
+        PlayerEvent(const PlayerEvent &);
+        PlayerEvent &operator=(const PlayerEvent &);
+    };
+
+    struct PlayVideoFrameEvent : public TimedEventQueue::Event {
+        PlayVideoFrameEvent(NewPlayer *player, MediaBuffer *buffer)
+            : mPlayer(player),
+              mBuffer(buffer) {
+        }
+
+        virtual ~PlayVideoFrameEvent() {
+            if (mBuffer != NULL) {
+                mBuffer->release();
+                mBuffer = NULL;
+            }
+        }
+
+        virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
+            mPlayer->onPlayVideoFrame(realtime_us, mBuffer);
+            mBuffer = NULL;
+        }
+
+    private:
+        NewPlayer *mPlayer;
+        MediaBuffer *mBuffer;
+
+        PlayVideoFrameEvent(const PlayVideoFrameEvent &);
+        PlayVideoFrameEvent &operator=(const PlayVideoFrameEvent &);
+    };
+
+    OMXClient mClient;
+
+    MPEG4Extractor *mExtractor;
+    MediaSource *mAudioSource;
+    OMXDecoder *mAudioDecoder;
+    MediaSource *mVideoSource;
+    OMXDecoder *mVideoDecoder;
+
+    int32_t mVideoWidth, mVideoHeight;
+
+    TimedEventQueue mQueue;
+    wp<TimedEventQueue::Event> mPlayVideoFrameEvent;
+
+    int64_t mMediaTimeUsStart;
+    int64_t mRealTimeUsStart;
+
+    void setAudioSource(MediaSource *source);
+    void setVideoSource(MediaSource *source);
+
+    int64_t approxRealTime(int64_t mediatime_us) const;
+
+    void onStart(int64_t realtime_us);
+    void onPause(int64_t realtime_us);
+    void onFetchVideoFrame(int64_t realtime_us);
+    void onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer);
+
+    static int64_t getMediaBufferTimeUs(MediaBuffer *buffer);
+
+    NewPlayer(const NewPlayer &);
+    NewPlayer &operator=(const NewPlayer &);
+};
+
+NewPlayer::NewPlayer()
+    : mExtractor(NULL),
+      mAudioSource(NULL),
+      mAudioDecoder(NULL),
+      mVideoSource(NULL),
+      mVideoDecoder(NULL),
+      mVideoWidth(0),
+      mVideoHeight(0) {
+    status_t err = mClient.connect();
+    assert(err == OK);
+}
+
+NewPlayer::~NewPlayer() {
+    stop();
+
+    mClient.disconnect();
+}
+
+void NewPlayer::setSource(const char *uri) {
+    stop();
+
+    mExtractor = new MPEG4Extractor(new MmapSource(uri));
+
+    int num_tracks;
+    status_t err = mExtractor->countTracks(&num_tracks);
+    assert(err == OK);
+
+    for (int i = 0; i < num_tracks; ++i) {
+        const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+        assert(meta != NULL);
+
+        const char *mime;
+        if (!meta->findCString(kKeyMIMEType, &mime)) {
+            continue;
+        }
+
+        bool is_audio = false;
+        bool is_acceptable = false;
+        if (!strncasecmp(mime, "audio/", 6)) {
+            is_audio = true;
+            is_acceptable = (mAudioSource == NULL);
+        } else if (!strncasecmp(mime, "video/", 6)) {
+            is_acceptable = (mVideoSource == NULL);
+        }
+
+        if (!is_acceptable) {
+            continue;
+        }
+
+        MediaSource *source;
+        if (mExtractor->getTrack(i, &source) != OK) {
+            continue;
+        }
+
+        if (is_audio) {
+            setAudioSource(source);
+        } else {
+            setVideoSource(source);
+        }
+    }
+}
+
+void NewPlayer::setAudioSource(MediaSource *source) {
+    mAudioSource = source;
+
+    sp<MetaData> meta = source->getFormat();
+
+    mAudioDecoder = OMXDecoder::Create(&mClient, meta);
+    mAudioDecoder->setSource(source);
+}
+
+void NewPlayer::setVideoSource(MediaSource *source) {
+    mVideoSource = source;
+
+    sp<MetaData> meta = source->getFormat();
+
+    bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
+    assert(success);
+
+    success = meta->findInt32(kKeyHeight, &mVideoHeight);
+    assert(success);
+
+    mVideoDecoder = OMXDecoder::Create(&mClient, meta);
+    mVideoDecoder->setSource(source);
+}
+
+void NewPlayer::start() {
+    mQueue.start();
+    mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onStart));
+}
+
+void NewPlayer::pause() {
+    mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onPause));
+}
+
+void NewPlayer::stop() {
+    mQueue.stop();
+
+    delete mVideoDecoder;
+    mVideoDecoder = NULL;
+    delete mVideoSource;
+    mVideoSource = NULL;
+    mVideoWidth = mVideoHeight = 0;
+
+    delete mAudioDecoder;
+    mAudioDecoder = NULL;
+    delete mAudioSource;
+    mAudioSource = NULL;
+
+    delete mExtractor;
+    mExtractor = NULL;
+}
+
+int64_t NewPlayer::approxRealTime(int64_t mediatime_us) const {
+    return mRealTimeUsStart + (mediatime_us - mMediaTimeUsStart);
+}
+
+void NewPlayer::onStart(int64_t realtime_us) {
+    mRealTimeUsStart = TimedEventQueue::getRealTimeUs();
+
+    if (mVideoDecoder != NULL) {
+        mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
+    }
+}
+
+void NewPlayer::onFetchVideoFrame(int64_t realtime_us) {
+    MediaBuffer *buffer;
+    status_t err = mVideoDecoder->read(&buffer);
+    assert(err == OK);
+
+    int64_t mediatime_us = getMediaBufferTimeUs(buffer);
+
+    sp<TimedEventQueue::Event> event = new PlayVideoFrameEvent(this, buffer);
+    mPlayVideoFrameEvent = event;
+
+    mQueue.postTimedEvent(event, approxRealTime(mediatime_us));
+}
+
+// static
+int64_t NewPlayer::getMediaBufferTimeUs(MediaBuffer *buffer) {
+    int32_t units, scale;
+    bool success =
+        buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+    assert(success);
+    success =
+        buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+    assert(success);
+
+    return (int64_t)units * 1000000 / scale;
+}
+
+void NewPlayer::onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer) {
+    LOGI("playing video frame (mediatime: %.2f sec)\n",
+         getMediaBufferTimeUs(buffer) / 1E6);
+    fflush(stdout);
+
+    buffer->release();
+    buffer = NULL;
+
+    mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
+}
+
+void NewPlayer::onPause(int64_t realtime_us) {
+}
+
+int main(int argc, char **argv) {
+    android::ProcessState::self()->startThreadPool();
+
+    if (argc != 2) {
+        fprintf(stderr, "usage: %s filename\n", argv[0]);
+        return 1;
+    }
+
+    NewPlayer player;
+    player.setSource(argv[1]);
+    player.start();
+    sleep(10);
+    player.stop();
+
+    return 0;
+}
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
new file mode 100644
index 0000000..d8db8b3
--- /dev/null
+++ b/cmds/stagefright/record.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXDecoder.h>
+
+using namespace android;
+
+class DummySource : public MediaSource {
+public:
+    DummySource(int width, int height)
+        : mSize((width * height * 3) / 2) {
+        mGroup.add_buffer(new MediaBuffer(mSize));
+    }
+
+    virtual ::status_t getMaxSampleSize(size_t *max_size) {
+        *max_size = mSize;
+        return ::OK;
+    }
+
+    virtual ::status_t read(MediaBuffer **buffer) {
+        ::status_t err = mGroup.acquire_buffer(buffer);
+        if (err != ::OK) {
+            return err;
+        }
+
+        char x = (char)((double)rand() / RAND_MAX * 255);
+        memset((*buffer)->data(), x, mSize);
+        (*buffer)->set_range(0, mSize);
+
+        return ::OK;
+    }
+
+private:
+    MediaBufferGroup mGroup;
+    size_t mSize;
+
+    DummySource(const DummySource &);
+    DummySource &operator=(const DummySource &);
+};
+
+int main(int argc, char **argv) {
+    android::ProcessState::self()->startThreadPool();
+
+#if 1
+    if (argc != 2) {
+        fprintf(stderr, "usage: %s filename\n", argv[0]);
+        return 1;
+    }
+
+    MPEG4Extractor extractor(new MmapSource(argv[1]));
+    int num_tracks;
+    assert(extractor.countTracks(&num_tracks) == ::OK);
+
+    MediaSource *source = NULL;
+    sp<MetaData> meta;
+    for (int i = 0; i < num_tracks; ++i) {
+        meta = extractor.getTrackMetaData(i);
+        assert(meta.get() != NULL);
+
+        const char *mime;
+        if (!meta->findCString(kKeyMIMEType, &mime)) {
+            continue;
+        }
+
+        if (strncasecmp(mime, "video/", 6)) {
+            continue;
+        }
+
+        if (extractor.getTrack(i, &source) != ::OK) {
+            source = NULL;
+            continue;
+        }
+        break;
+    }
+
+    if (source == NULL) {
+        fprintf(stderr, "Unable to find a suitable video track.\n");
+        return 1;
+    }
+
+    OMXClient client;
+    assert(client.connect() == android::OK);
+
+    OMXDecoder *decoder = OMXDecoder::Create(&client, meta);
+    decoder->setSource(source);
+
+    int width, height;
+    bool success = meta->findInt32(kKeyWidth, &width);
+    success = success && meta->findInt32(kKeyHeight, &height);
+    assert(success);
+
+    sp<MetaData> enc_meta = new MetaData;
+    // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
+    enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
+    enc_meta->setInt32(kKeyWidth, width);
+    enc_meta->setInt32(kKeyHeight, height);
+
+    OMXDecoder *encoder =
+        OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
+
+    encoder->setSource(decoder);
+    // encoder->setSource(meta, new DummySource(width, height));
+
+#if 1
+    MPEG4Writer writer("/sdcard/output.mp4");
+    writer.addSource(enc_meta, encoder);
+    writer.start();
+    sleep(120);
+    writer.stop();
+#else
+    encoder->start();
+
+    MediaBuffer *buffer;
+    while (encoder->read(&buffer) == ::OK) {
+        printf("got an output frame of size %d\n", buffer->range_length());
+
+        buffer->release();
+        buffer = NULL;
+    }
+
+    encoder->stop();
+#endif
+
+    delete encoder;
+    encoder = NULL;
+
+    delete decoder;
+    decoder = NULL;
+
+    client.disconnect();
+
+    delete source;
+    source = NULL;
+#endif
+
+#if 0
+    CameraSource *source = CameraSource::Create();
+    printf("source = %p\n", source);
+
+    for (int i = 0; i < 100; ++i) {
+        MediaBuffer *buffer;
+        status_t err = source->read(&buffer);
+        assert(err == OK);
+
+        printf("got a frame, data=%p, size=%d\n",
+               buffer->data(), buffer->range_length());
+
+        buffer->release();
+        buffer = NULL;
+    }
+
+    delete source;
+    source = NULL;
+#endif
+
+    return 0;
+}
+
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
new file mode 100644
index 0000000..7e23574
--- /dev/null
+++ b/cmds/stagefright/stagefright.cpp
@@ -0,0 +1,209 @@
+/*
+ * 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 <sys/time.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/CachingDataSource.h>
+#include <media/stagefright/ESDS.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaPlayerImpl.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXDecoder.h>
+
+#include "WaveWriter.h"
+
+using namespace android;
+
+////////////////////////////////////////////////////////////////////////////////
+
+static bool convertToWav(
+        OMXClient *client, const sp<MetaData> &meta, MediaSource *source) {
+    printf("convertToWav\n");
+
+    OMXDecoder *decoder = OMXDecoder::Create(client, meta);
+
+    int32_t sampleRate;
+    bool success = meta->findInt32(kKeySampleRate, &sampleRate);
+    assert(success);
+
+    int32_t numChannels;
+    success = meta->findInt32(kKeyChannelCount, &numChannels);
+    assert(success);
+
+    const char *mime;
+    success = meta->findCString(kKeyMIMEType, &mime);
+    assert(success);
+
+    if (!strcasecmp("audio/3gpp", mime)) {
+        numChannels = 1;  // XXX
+    }
+
+    WaveWriter writer("/sdcard/Music/shoutcast.wav", numChannels, sampleRate);
+
+    decoder->setSource(source);
+    for (int i = 0; i < 100; ++i) {
+        MediaBuffer *buffer;
+
+        ::status_t err = decoder->read(&buffer);
+        if (err != ::OK) {
+            break;
+        }
+
+        writer.Append((const char *)buffer->data() + buffer->range_offset(),
+                      buffer->range_length());
+
+        buffer->release();
+        buffer = NULL;
+    }
+
+    delete decoder;
+    decoder = NULL;
+
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static int64_t getNowUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
+}
+
+int main(int argc, char **argv) {
+    android::ProcessState::self()->startThreadPool();
+
+    bool audioOnly = false;
+    if (argc > 1 && !strcmp(argv[1], "--list")) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("media.player"));
+        sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+        assert(service.get() != NULL);
+
+        sp<IOMX> omx = service->createOMX();
+        assert(omx.get() != NULL);
+
+        List<String8> list;
+        omx->list_nodes(&list);
+
+        for (List<String8>::iterator it = list.begin();
+             it != list.end(); ++it) {
+            printf("%s\n", (*it).string());
+        }
+
+        return 0;
+    } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
+        audioOnly = true;
+        ++argv;
+        --argc;
+    }
+
+#if 0
+    MediaPlayerImpl player(argv[1]);
+    player.play();
+
+    sleep(10000);
+#else
+    DataSource::RegisterDefaultSniffers();
+
+    OMXClient client;
+    status_t err = client.connect();
+
+    MmapSource *dataSource = new MmapSource(argv[1]);
+    MediaExtractor *extractor = MediaExtractor::Create(dataSource);
+    dataSource = NULL;
+
+    int numTracks;
+    err = extractor->countTracks(&numTracks);
+
+    sp<MetaData> meta;
+    int i;
+    for (i = 0; i < numTracks; ++i) {
+        meta = extractor->getTrackMetaData(i);
+
+        const char *mime;
+        meta->findCString(kKeyMIMEType, &mime);
+
+        if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+            break;
+        }
+
+        if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
+            break;
+        }
+    }
+
+    OMXDecoder *decoder = OMXDecoder::Create(&client, meta);
+
+    if (decoder != NULL) {
+        MediaSource *source;
+        err = extractor->getTrack(i, &source);
+
+        decoder->setSource(source);
+
+        decoder->start();
+
+        int64_t startTime = getNowUs();
+
+        int n = 0;
+        MediaBuffer *buffer;
+        while ((err = decoder->read(&buffer)) == OK) {
+            if ((++n % 16) == 0) {
+                printf(".");
+                fflush(stdout);
+            }
+
+            buffer->release();
+            buffer = NULL;
+        }
+        decoder->stop();
+        printf("\n");
+
+        int64_t delay = getNowUs() - startTime;
+        printf("avg. %.2f fps\n", n * 1E6 / delay);
+
+        delete decoder;
+        decoder = NULL;
+
+        delete source;
+        source = NULL;
+    }
+
+    delete extractor;
+    extractor = NULL;
+
+    client.disconnect();
+#endif
+
+    return 0;
+}
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 13e51ee..503cb31 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -26,8 +26,8 @@
 
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
 #include <utils/threads.h>
 
 
@@ -39,21 +39,10 @@
 {
 public:
 
-    // input sources values must always be defined in the range
-    // [AudioRecord::DEFAULT_INPUT, AudioRecord::NUM_INPUT_SOURCES[
-    enum input_source {
-        DEFAULT_INPUT   =-1,
-        MIC_INPUT       = 0,
-        VOICE_UPLINK_INPUT = 1,
-        VOICE_DOWNLINK_INPUT = 2,
-        VOICE_CALL_INPUT = 3,
-        NUM_INPUT_SOURCES
-    };
-
     static const int DEFAULT_SAMPLE_RATE = 8000;
 
     /* Events used by AudioRecord callback function (callback_t).
-     * 
+     *
      * to keep in sync with frameworks/base/media/java/android/media/AudioRecord.java
      */
     enum event_type {
@@ -61,7 +50,7 @@
         EVENT_OVERRUN = 1,          // PCM buffer overrun occured.
         EVENT_MARKER = 2,           // Record head is at the specified marker position
                                     // (See setMarkerPosition()).
-        EVENT_NEW_POS = 3,          // Record head is at a new position 
+        EVENT_NEW_POS = 3,          // Record head is at a new position
                                     // (See setPositionUpdatePeriod()).
     };
 
@@ -123,11 +112,11 @@
      *
      * Parameters:
      *
-     * inputSource:        Select the audio input to record to (e.g. AudioRecord::MIC_INPUT).
+     * inputSource:        Select the audio input to record to (e.g. AUDIO_SOURCE_DEFAULT).
      * sampleRate:         Track sampling rate in Hz.
-     * format:             PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+     * format:             Audio format (e.g AudioSystem::PCM_16_BIT for signed
      *                     16 bits per sample).
-     * channelCount:       Number of PCM channels (e.g 2 for stereo).
+     * channels:           Channel mask: see AudioSystem::audio_channels.
      * frameCount:         Total size of track PCM buffer in frames. This defines the
      *                     latency of the track.
      * flags:              A bitmask of acoustic values from enum record_flags.  It enables
@@ -148,7 +137,7 @@
                         AudioRecord(int inputSource,
                                     uint32_t sampleRate = 0,
                                     int format          = 0,
-                                    int channelCount    = 0,
+                                    uint32_t channels = AudioSystem::CHANNEL_IN_MONO,
                                     int frameCount      = 0,
                                     uint32_t flags      = 0,
                                     callback_t cbf = 0,
@@ -166,14 +155,14 @@
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful intialization
      *  - INVALID_OPERATION: AudioRecord is already intitialized or record device is already in use
-     *  - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+     *  - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - PERMISSION_DENIED: recording is not allowed for the requesting process
      * */
             status_t    set(int inputSource     = 0,
                             uint32_t sampleRate = 0,
                             int format          = 0,
-                            int channelCount    = 0,
+                            uint32_t channels = AudioSystem::CHANNEL_IN_MONO,
                             int frameCount      = 0,
                             uint32_t flags      = 0,
                             callback_t cbf = 0,
@@ -199,6 +188,7 @@
 
             int         format() const;
             int         channelCount() const;
+            int         channels() const;
             uint32_t    frameCount() const;
             int         frameSize() const;
             int         inputSource() const;
@@ -222,8 +212,8 @@
 
     /* Sets marker position. When record reaches the number of frames specified,
      * a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
-     * with marker == 0 cancels marker notification callback. 
-     * If the AudioRecord has been opened with no callback function associated, 
+     * with marker == 0 cancels marker notification callback.
+     * If the AudioRecord has been opened with no callback function associated,
      * the operation will fail.
      *
      * Parameters:
@@ -238,10 +228,10 @@
             status_t    getMarkerPosition(uint32_t *marker);
 
 
-    /* Sets position update period. Every time the number of frames specified has been recorded, 
-     * a callback with event type EVENT_NEW_POS is called. 
-     * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification 
-     * callback. 
+    /* Sets position update period. Every time the number of frames specified has been recorded,
+     * a callback with event type EVENT_NEW_POS is called.
+     * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
+     * callback.
      * If the AudioRecord has been opened with no callback function associated,
      * the operation will fail.
      *
@@ -257,8 +247,8 @@
             status_t    getPositionUpdatePeriod(uint32_t *updatePeriod);
 
 
-    /* Gets record head position. The position is the  total number of frames 
-     * recorded since record start. 
+    /* Gets record head position. The position is the  total number of frames
+     * recorded since record start.
      *
      * Parameters:
      *
@@ -270,8 +260,16 @@
      */
             status_t    getPosition(uint32_t *position);
 
-            
-            
+    /* returns a handle on the audio input used by this AudioRecord.
+     *
+     * Parameters:
+     *  none.
+     *
+     * Returned value:
+     *  handle on audio hardware input
+     */
+            audio_io_handle_t    getInput() { return mInput; }
+
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -342,6 +340,7 @@
     bool                    mMarkerReached;
     uint32_t                mNewPosition;
     uint32_t                mUpdatePeriod;
+    audio_io_handle_t       mInput;
 };
 
 }; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 3a3a714..1243502 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -24,36 +24,130 @@
 namespace android {
 
 typedef void (*audio_error_callback)(status_t err);
+typedef void * audio_io_handle_t;
+
+class IAudioPolicyService;
+class String8;
 
 class AudioSystem
 {
 public:
 
     enum stream_type {
-        DEFAULT         =-1,
-        VOICE_CALL      = 0,
-        SYSTEM          = 1,
-        RING            = 2,
-        MUSIC           = 3,
-        ALARM           = 4,
-        NOTIFICATION    = 5,
-        BLUETOOTH_SCO   = 6,
+        DEFAULT          =-1,
+        VOICE_CALL       = 0,
+        SYSTEM           = 1,
+        RING             = 2,
+        MUSIC            = 3,
+        ALARM            = 4,
+        NOTIFICATION     = 5,
+        BLUETOOTH_SCO    = 6,
         ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
+        DTMF             = 8,
+        TTS              = 9,
         NUM_STREAM_TYPES
     };
 
-    enum audio_output_type {
-        AUDIO_OUTPUT_DEFAULT      =-1,
-        AUDIO_OUTPUT_HARDWARE     = 0,
-        AUDIO_OUTPUT_A2DP         = 1,
-        NUM_AUDIO_OUTPUT_TYPES
+    // Audio sub formats (see AudioSystem::audio_format).
+    enum pcm_sub_format {
+        PCM_SUB_16_BIT          = 0x1, // must be 1 for backward compatibility
+        PCM_SUB_8_BIT           = 0x2, // must be 2 for backward compatibility
     };
 
+    // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify
+    // bit rate, stereo mode, version...
+    enum mp3_sub_format {
+        //TODO
+    };
+
+    // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned,
+    // encoding mode for recording...
+    enum amr_sub_format {
+        //TODO
+    };
+
+    // AAC sub format field definition: specify profile or bitrate for recording...
+    enum aac_sub_format {
+        //TODO
+    };
+
+    // VORBIS sub format field definition: specify quality for recording...
+    enum vorbis_sub_format {
+        //TODO
+    };
+
+    // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits).
+    // The main format indicates the main codec type. The sub format field indicates options and parameters
+    // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate
+    // or profile. It can also be used for certain formats to give informations not present in the encoded
+    // audio stream (e.g. octet alignement for AMR).
     enum audio_format {
-        FORMAT_DEFAULT = 0,
-        PCM_16_BIT,
-        PCM_8_BIT,
-        INVALID_FORMAT
+        INVALID_FORMAT      = -1,
+        FORMAT_DEFAULT      = 0,
+        PCM                 = 0x00000000, // must be 0 for backward compatibility
+        MP3                 = 0x01000000,
+        AMR_NB              = 0x02000000,
+        AMR_WB              = 0x03000000,
+        AAC                 = 0x04000000,
+        HE_AAC_V1           = 0x05000000,
+        HE_AAC_V2           = 0x06000000,
+        VORBIS              = 0x07000000,
+        MAIN_FORMAT_MASK    = 0xFF000000,
+        SUB_FORMAT_MASK     = 0x00FFFFFF,
+        // Aliases
+        PCM_16_BIT          = (PCM|PCM_SUB_16_BIT),
+        PCM_8_BIT          = (PCM|PCM_SUB_8_BIT)
+    };
+
+
+    // Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java
+    enum audio_channels {
+        // output channels
+        CHANNEL_OUT_FRONT_LEFT = 0x4,
+        CHANNEL_OUT_FRONT_RIGHT = 0x8,
+        CHANNEL_OUT_FRONT_CENTER = 0x10,
+        CHANNEL_OUT_LOW_FREQUENCY = 0x20,
+        CHANNEL_OUT_BACK_LEFT = 0x40,
+        CHANNEL_OUT_BACK_RIGHT = 0x80,
+        CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
+        CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
+        CHANNEL_OUT_BACK_CENTER = 0x400,
+        CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
+        CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
+        CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+        CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
+        CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+        CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+                CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
+        CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+                CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER),
+
+        // input channels
+        CHANNEL_IN_LEFT = 0x4,
+        CHANNEL_IN_RIGHT = 0x8,
+        CHANNEL_IN_FRONT = 0x10,
+        CHANNEL_IN_BACK = 0x20,
+        CHANNEL_IN_LEFT_PROCESSED = 0x40,
+        CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+        CHANNEL_IN_FRONT_PROCESSED = 0x100,
+        CHANNEL_IN_BACK_PROCESSED = 0x200,
+        CHANNEL_IN_PRESSURE = 0x400,
+        CHANNEL_IN_X_AXIS = 0x800,
+        CHANNEL_IN_Y_AXIS = 0x1000,
+        CHANNEL_IN_Z_AXIS = 0x2000,
+        CHANNEL_IN_VOICE_UPLINK = 0x4000,
+        CHANNEL_IN_VOICE_DNLINK = 0x8000,
+        CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
+        CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
+        CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK|
+                CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED|
+                CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS |
+                CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
     };
 
     enum audio_mode {
@@ -65,15 +159,6 @@
         NUM_MODES  // not a valid entry, denotes end-of-list
     };
 
-    enum audio_routes {
-        ROUTE_EARPIECE       = (1 << 0),
-        ROUTE_SPEAKER        = (1 << 1),
-        ROUTE_BLUETOOTH_SCO  = (1 << 2),
-        ROUTE_HEADSET        = (1 << 3),
-        ROUTE_BLUETOOTH_A2DP = (1 << 4),
-        ROUTE_ALL            = -1UL,
-    };
-
     enum audio_in_acoustics {
         AGC_ENABLE    = 0x0001,
         AGC_DISABLE   = 0,
@@ -87,36 +172,37 @@
      * only privileged processes can have access to them
      */
 
-    // routing helper functions
-    static status_t speakerphone(bool state);
-    static status_t isSpeakerphoneOn(bool* state);
-    static status_t bluetoothSco(bool state);
-    static status_t isBluetoothScoOn(bool* state);
+    // mute/unmute microphone
     static status_t muteMicrophone(bool state);
     static status_t isMicrophoneMuted(bool *state);
 
+    // set/get master volume
     static status_t setMasterVolume(float value);
-    static status_t setMasterMute(bool mute);
     static status_t getMasterVolume(float* volume);
+    // mute/unmute audio outputs
+    static status_t setMasterMute(bool mute);
     static status_t getMasterMute(bool* mute);
 
-    static status_t setStreamVolume(int stream, float value);
+    // set/get stream volume on specified output
+    static status_t setStreamVolume(int stream, float value, void *output);
+    static status_t getStreamVolume(int stream, float* volume, void *output);
+
+    // mute/unmute stream
     static status_t setStreamMute(int stream, bool mute);
-    static status_t getStreamVolume(int stream, float* volume);
     static status_t getStreamMute(int stream, bool* mute);
 
+    // set audio mode in audio hardware (see AudioSystem::audio_mode)
     static status_t setMode(int mode);
-    static status_t getMode(int* mode);
 
-    static status_t setRouting(int mode, uint32_t routes, uint32_t mask);
-    static status_t getRouting(int mode, uint32_t* routes);
-
+    // returns true if tracks are active on AudioSystem::MUSIC stream
     static status_t isMusicActive(bool *state);
 
-    // Temporary interface, do not use
-    // TODO: Replace with a more generic key:value get/set mechanism
-    static status_t setParameter(const char* key, const char* value);
-    
+    // set/get audio hardware parameters. The function accepts a list of parameters
+    // key value pairs in the form: key1=value1;key2=value2;...
+    // Some keys are reserved for standard parameters (See AudioParameter class).
+    static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+    static String8  getParameters(audio_io_handle_t ioHandle, const String8& keys);
+
     static void setErrorCallback(audio_error_callback cb);
 
     // helper function to obtain AudioFlinger service handle
@@ -130,47 +216,247 @@
     static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
 
     static bool routedToA2dpOutput(int streamType);
-    
-    static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount, 
+
+    static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
         size_t* buffSize);
 
+
+    //
+    // AudioPolicyService interface
+    //
+
+    enum audio_devices {
+        // output devices
+        DEVICE_OUT_EARPIECE = 0x1,
+        DEVICE_OUT_SPEAKER = 0x2,
+        DEVICE_OUT_WIRED_HEADSET = 0x4,
+        DEVICE_OUT_WIRED_HEADPHONE = 0x8,
+        DEVICE_OUT_BLUETOOTH_SCO = 0x10,
+        DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+        DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+        DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
+        DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+        DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+        DEVICE_OUT_AUX_DIGITAL = 0x400,
+        DEVICE_OUT_FM_HEADPHONE = 0x800,
+        DEVICE_OUT_FM_SPEAKER = 0x1000,
+        DEVICE_OUT_TTY = 0x2000,
+        DEVICE_OUT_DEFAULT = 0x8000,
+        DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
+                DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+                DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_FM_HEADPHONE |
+                DEVICE_OUT_FM_SPEAKER | DEVICE_OUT_TTY | DEVICE_OUT_DEFAULT),
+
+        // input devices
+        DEVICE_IN_COMMUNICATION = 0x10000,
+        DEVICE_IN_AMBIENT = 0x20000,
+        DEVICE_IN_BUILTIN_MIC = 0x40000,
+        DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+        DEVICE_IN_WIRED_HEADSET = 0x100000,
+        DEVICE_IN_AUX_DIGITAL = 0x200000,
+        DEVICE_IN_VOICE_CALL = 0x400000,
+        DEVICE_IN_DEFAULT = 0x80000000,
+
+        DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
+                DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
+                DEVICE_IN_VOICE_CALL| DEVICE_IN_DEFAULT)
+    };
+
+    // device connection states used for setDeviceConnectionState()
+    enum device_connection_state {
+        DEVICE_STATE_UNAVAILABLE,
+        DEVICE_STATE_AVAILABLE,
+        NUM_DEVICE_STATES
+    };
+
+    // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks)
+    enum output_flags {
+        OUTPUT_FLAG_INDIRECT = 0x0,
+        OUTPUT_FLAG_DIRECT = 0x1
+    };
+
+    // device categories used for setForceUse()
+    enum forced_config {
+        FORCE_NONE,
+        FORCE_SPEAKER,
+        FORCE_HEADPHONES,
+        FORCE_BT_SCO,
+        FORCE_BT_A2DP,
+        FORCE_WIRED_ACCESSORY,
+        NUM_FORCE_CONFIG,
+        FORCE_DEFAULT = FORCE_NONE
+    };
+
+    // usages used for setForceUse()
+    enum force_use {
+        FOR_COMMUNICATION,
+        FOR_MEDIA,
+        FOR_RECORD,
+        NUM_FORCE_USE
+    };
+
+    // types of io configuration change events received with ioConfigChanged()
+    enum io_config_event {
+        OUTPUT_OPENED,
+        OUTPUT_CLOSED,
+        OUTPUT_CONFIG_CHANGED,
+        INPUT_OPENED,
+        INPUT_CLOSED,
+        INPUT_CONFIG_CHANGED,
+        STREAM_CONFIG_CHANGED,
+        NUM_CONFIG_EVENTS
+    };
+
+    // audio output descritor used to cache output configurations in client process to avoid frequent calls
+    // through IAudioFlinger
+    class OutputDescriptor {
+    public:
+        OutputDescriptor()
+        : samplingRate(0), format(0), channels(0), frameCount(0), latency(0)  {}
+
+        uint32_t samplingRate;
+        int32_t format;
+        int32_t channels;
+        size_t frameCount;
+        uint32_t latency;
+    };
+
+    //
+    // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
+    //
+    static status_t setDeviceConnectionState(audio_devices device, device_connection_state state, const char *device_address);
+    static device_connection_state getDeviceConnectionState(audio_devices device, const char *device_address);
+    static status_t setPhoneState(int state);
+    static status_t setRingerMode(uint32_t mode, uint32_t mask);
+    static status_t setForceUse(force_use usage, forced_config config);
+    static forced_config getForceUse(force_use usage);
+    static audio_io_handle_t getOutput(stream_type stream,
+                                        uint32_t samplingRate = 0,
+                                        uint32_t format = FORMAT_DEFAULT,
+                                        uint32_t channels = CHANNEL_OUT_STEREO,
+                                        output_flags flags = OUTPUT_FLAG_INDIRECT);
+    static status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+    static status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+    static void releaseOutput(audio_io_handle_t output);
+    static audio_io_handle_t getInput(int inputSource,
+                                    uint32_t samplingRate = 0,
+                                    uint32_t format = FORMAT_DEFAULT,
+                                    uint32_t channels = CHANNEL_IN_MONO,
+                                    audio_in_acoustics acoustics = (audio_in_acoustics)0);
+    static status_t startInput(audio_io_handle_t input);
+    static status_t stopInput(audio_io_handle_t input);
+    static void releaseInput(audio_io_handle_t input);
+    static status_t initStreamVolume(stream_type stream,
+                                      int indexMin,
+                                      int indexMax);
+    static status_t setStreamVolumeIndex(stream_type stream, int index);
+    static status_t getStreamVolumeIndex(stream_type stream, int *index);
+
+    static const sp<IAudioPolicyService>& get_audio_policy_service();
+
     // ----------------------------------------------------------------------------
 
+    static uint32_t popCount(uint32_t u);
+    static bool isOutputDevice(audio_devices device);
+    static bool isInputDevice(audio_devices device);
+    static bool isA2dpDevice(audio_devices device);
+    static bool isBluetoothScoDevice(audio_devices device);
+    static bool isLowVisibility(stream_type stream);
+    static bool isOutputChannel(uint32_t channel);
+    static bool isInputChannel(uint32_t channel);
+    static bool isValidFormat(uint32_t format);
+    static bool isLinearPCM(uint32_t format);
+
 private:
 
     class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
     {
     public:
-        AudioFlingerClient() {      
+        AudioFlingerClient() {
         }
-        
+
         // DeathRecipient
         virtual void binderDied(const wp<IBinder>& who);
-        
+
         // IAudioFlingerClient
-        virtual void a2dpEnabledChanged(bool enabled);
-        
+
+        // indicate a change in the configuration of an output or input: keeps the cached
+        // values for output/input parameters upto date in client process
+        virtual void ioConfigChanged(int event, void *param1, void *param2);
     };
-    static int getOutput(int streamType);
+
+    class AudioPolicyServiceClient: public IBinder::DeathRecipient
+    {
+    public:
+        AudioPolicyServiceClient() {
+        }
+
+        // DeathRecipient
+        virtual void binderDied(const wp<IBinder>& who);
+    };
 
     static sp<AudioFlingerClient> gAudioFlingerClient;
-
+    static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
     friend class AudioFlingerClient;
+    friend class AudioPolicyServiceClient;
 
     static Mutex gLock;
     static sp<IAudioFlinger> gAudioFlinger;
     static audio_error_callback gAudioErrorCallback;
-    static int gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
-    static int gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
-    static uint32_t gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
-    static bool gA2dpEnabled;
-    
+
     static size_t gInBuffSize;
     // previous parameters for recording buffer size queries
     static uint32_t gPrevInSamplingRate;
     static int gPrevInFormat;
     static int gPrevInChannelCount;
 
+    static sp<IAudioPolicyService> gAudioPolicyService;
+
+    // mapping between stream types and outputs
+    static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
+    // list of output descritor containing cached parameters (sampling rate, framecount, channel count...)
+    static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
+};
+
+class AudioParameter {
+
+public:
+    AudioParameter() {}
+    AudioParameter(const String8& keyValuePairs);
+    virtual ~AudioParameter();
+
+    // reserved parameter keys for changeing standard parameters with setParameters() function.
+    // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input
+    // configuration changes and act accordingly.
+    //  keyRouting: to change audio routing, value is an int in AudioSystem::audio_devices
+    //  keySamplingRate: to change sampling rate routing, value is an int
+    //  keyFormat: to change audio format, value is an int in AudioSystem::audio_format
+    //  keyChannels: to change audio channel configuration, value is an int in AudioSystem::audio_channels
+    //  keyFrameCount: to change audio output frame count, value is an int
+    static const char *keyRouting;
+    static const char *keySamplingRate;
+    static const char *keyFormat;
+    static const char *keyChannels;
+    static const char *keyFrameCount;
+
+    String8 toString();
+
+    status_t add(const String8& key, const String8& value);
+    status_t addInt(const String8& key, const int value);
+    status_t addFloat(const String8& key, const float value);
+
+    status_t remove(const String8& key);
+
+    status_t get(const String8& key, String8& value);
+    status_t getInt(const String8& key, int& value);
+    status_t getFloat(const String8& key, float& value);
+
+    size_t size() { return mParameters.size(); }
+
+private:
+    String8 mKeyValuePairs;
+    KeyedVector <String8, String8> mParameters;
 };
 
 };  // namespace android
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 7c86a65..981c2f6 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -26,8 +26,8 @@
 
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
 #include <utils/threads.h>
 
 
@@ -117,9 +117,9 @@
      * streamType:         Select the type of audio stream this track is attached to
      *                     (e.g. AudioSystem::MUSIC).
      * sampleRate:         Track sampling rate in Hz.
-     * format:             PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+     * format:             Audio format (e.g AudioSystem::PCM_16_BIT for signed
      *                     16 bits per sample).
-     * channelCount:       Number of PCM channels (e.g 2 for stereo).
+     * channels:           Channel mask: see AudioSystem::audio_channels.
      * frameCount:         Total size of track PCM buffer in frames. This defines the
      *                     latency of the track.
      * flags:              Reserved for future use.
@@ -133,7 +133,7 @@
                         AudioTrack( int streamType,
                                     uint32_t sampleRate  = 0,
                                     int format           = 0,
-                                    int channelCount     = 0,
+                                    int channels         = 0,
                                     int frameCount       = 0,
                                     uint32_t flags       = 0,
                                     callback_t cbf       = 0,
@@ -152,7 +152,7 @@
                         AudioTrack( int streamType,
                                     uint32_t sampleRate = 0,
                                     int format          = 0,
-                                    int channelCount    = 0,
+                                    int channels        = 0,
                                     const sp<IMemory>& sharedBuffer = 0,
                                     uint32_t flags      = 0,
                                     callback_t cbf      = 0,
@@ -169,13 +169,13 @@
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful intialization
      *  - INVALID_OPERATION: AudioTrack is already intitialized
-     *  - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+     *  - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
      *  - NO_INIT: audio server or audio hardware not initialized
      * */
             status_t    set(int streamType      =-1,
                             uint32_t sampleRate = 0,
                             int format          = 0,
-                            int channelCount    = 0,
+                            int channels        = 0,
                             int frameCount      = 0,
                             uint32_t flags      = 0,
                             callback_t cbf      = 0,
@@ -330,6 +330,16 @@
      */
             status_t    reload();
 
+    /* returns a handle on the audio output used by this AudioTrack.
+     *
+     * Parameters:
+     *  none.
+     *
+     * Returned value:
+     *  handle on audio hardware output
+     */
+            audio_io_handle_t    getOutput();
+
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -387,7 +397,6 @@
     sp<AudioTrackThread>    mAudioTrackThread;
 
     float                   mVolume[2];
-    uint32_t                mSampleRate;
     uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
@@ -395,6 +404,7 @@
     uint8_t                 mFormat;
     uint8_t                 mChannelCount;
     uint8_t                 mMuted;
+    uint32_t                mChannels;
     status_t                mStatus;
     uint32_t                mLatency;
 
@@ -410,6 +420,7 @@
     bool                    mMarkerReached;
     uint32_t                mNewPosition;
     uint32_t                mUpdatePeriod;
+    uint32_t                mFlags;
 };
 
 
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 3e59d85..26e6972 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -23,11 +23,11 @@
 
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
 #include <media/IAudioTrack.h>
 #include <media/IAudioRecord.h>
 #include <media/IAudioFlingerClient.h>
-
+#include <utils/String8.h>
 
 namespace android {
 
@@ -50,11 +50,12 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
+                                void *output,
                                 status_t *status) = 0;
 
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                int inputSource,
+                                void *input,
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
@@ -65,11 +66,11 @@
     /* query the audio hardware state. This state never changes,
      * and therefore can be cached.
      */
-    virtual     uint32_t    sampleRate(int output) const = 0;
-    virtual     int         channelCount(int output) const = 0;
-    virtual     int         format(int output) const = 0;
-    virtual     size_t      frameCount(int output) const = 0;
-    virtual     uint32_t    latency(int output) const = 0;
+    virtual     uint32_t    sampleRate(void *output) const = 0;
+    virtual     int         channelCount(void *output) const = 0;
+    virtual     int         format(void *output) const = 0;
+    virtual     size_t      frameCount(void *output) const = 0;
+    virtual     uint32_t    latency(void *output) const = 0;
 
     /* set/get the audio hardware state. This will probably be used by
      * the preference panel, mostly.
@@ -83,19 +84,14 @@
     /* set/get stream type state. This will probably be used by
      * the preference panel, mostly.
      */
-    virtual     status_t    setStreamVolume(int stream, float value) = 0;
+    virtual     status_t    setStreamVolume(int stream, float value, void *output) = 0;
     virtual     status_t    setStreamMute(int stream, bool muted) = 0;
 
-    virtual     float       streamVolume(int stream) const = 0;
+    virtual     float       streamVolume(int stream, void *output) const = 0;
     virtual     bool        streamMute(int stream) const = 0;
 
-    // set/get audio routing
-    virtual     status_t    setRouting(int mode, uint32_t routes, uint32_t mask) = 0;
-    virtual     uint32_t    getRouting(int mode) const = 0;
-
-    // set/get audio mode
+    // set audio mode
     virtual     status_t    setMode(int mode) = 0;
-    virtual     int         getMode() const = 0;
 
     // mic mute/state
     virtual     status_t    setMicMute(bool state) = 0;
@@ -104,22 +100,34 @@
     // is a music stream active?
     virtual     bool        isMusicActive() const = 0;
 
-    // pass a generic configuration parameter to libaudio
-    // Temporary interface, do not use
-    // TODO: Replace with a more generic key:value get/set mechanism
-    virtual     status_t  setParameter(const char* key, const char* value) = 0;
+    virtual     status_t    setParameters(void *ioHandle, const String8& keyValuePairs) = 0;
+    virtual     String8     getParameters(void *ioHandle, const String8& keys) = 0;
     
     // register a current process for audio output change notifications
     virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
     
     // retrieve the audio recording buffer size
     virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
-    
-    // force AudioFlinger thread out of standby
-    virtual     void        wakeUp() = 0;
 
-    // is A2DP output enabled
-    virtual     bool        isA2dpEnabled() const = 0;
+    virtual void *openOutput(uint32_t *pDevices,
+                                    uint32_t *pSamplingRate,
+                                    uint32_t *pFormat,
+                                    uint32_t *pChannels,
+                                    uint32_t *pLatencyMs,
+                                    uint32_t flags) = 0;
+    virtual void *openDuplicateOutput(void *output1, void *output2) = 0;
+    virtual status_t closeOutput(void *output) = 0;
+    virtual status_t suspendOutput(void *output) = 0;
+    virtual status_t restoreOutput(void *output) = 0;
+
+    virtual void *openInput(uint32_t *pDevices,
+                                    uint32_t *pSamplingRate,
+                                    uint32_t *pFormat,
+                                    uint32_t *pChannels,
+                                    uint32_t acoustics) = 0;
+    virtual status_t closeInput(void *input) = 0;
+
+    virtual status_t setStreamOutput(uint32_t stream, void *output) = 0;
 };
 
 
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index c3deb0b..78142ce 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -19,8 +19,8 @@
 
 
 #include <utils/RefBase.h>
-#include <utils/IInterface.h>
-
+#include <binder/IInterface.h>
+#include <utils/KeyedVector.h>
 
 namespace android {
 
@@ -31,8 +31,8 @@
 public:
     DECLARE_META_INTERFACE(AudioFlingerClient);
 
-    // Notifies a change of audio output from/to hardware to/from A2DP.
-    virtual void a2dpEnabledChanged(bool enabled) = 0;
+    // Notifies a change of audio input/output configuration.
+    virtual void ioConfigChanged(int event, void *param1, void *param2) = 0;
 
 };
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
new file mode 100644
index 0000000..4804bbd
--- /dev/null
+++ b/include/media/IAudioPolicyService.h
@@ -0,0 +1,90 @@
+/*
+ * 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 ANDROID_IAUDIOPOLICYSERVICE_H
+#define ANDROID_IAUDIOPOLICYSERVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <media/AudioSystem.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioPolicyService : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(AudioPolicyService);
+
+    //
+    // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
+    //
+    virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+                                              AudioSystem::device_connection_state state,
+                                              const char *device_address) = 0;
+    virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+                                                                          const char *device_address) = 0;
+    virtual status_t setPhoneState(int state) = 0;
+    virtual status_t setRingerMode(uint32_t mode, uint32_t mask) = 0;
+    virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0;
+    virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0;
+    virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+                                        uint32_t samplingRate = 0,
+                                        uint32_t format = AudioSystem::FORMAT_DEFAULT,
+                                        uint32_t channels = 0,
+                                        AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0;
+    virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
+    virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
+    virtual void releaseOutput(audio_io_handle_t output) = 0;
+    virtual audio_io_handle_t getInput(int inputSource,
+                                    uint32_t samplingRate = 0,
+                                    uint32_t format = AudioSystem::FORMAT_DEFAULT,
+                                    uint32_t channels = 0,
+                                    AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0) = 0;
+    virtual status_t startInput(audio_io_handle_t input) = 0;
+    virtual status_t stopInput(audio_io_handle_t input) = 0;
+    virtual void releaseInput(audio_io_handle_t input) = 0;
+    virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+                                      int indexMin,
+                                      int indexMax) = 0;
+    virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index) = 0;
+    virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioPolicyService : public BnInterface<IAudioPolicyService>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOPOLICYSERVICE_H
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index 9d45d2d..46735de 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -22,8 +22,8 @@
 
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
 
 
 namespace android {
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 12f2111..de6426a 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -22,8 +22,8 @@
 
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
 
 
 namespace android {
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index c677e83..9baba8e 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -19,9 +19,9 @@
 #define ANDROID_IMEDIAMETADATARETRIEVER_H
 
 #include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
 
 namespace android {
 
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index a683e74..b6f654f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -18,11 +18,12 @@
 #define ANDROID_IMEDIAPLAYER_H
 
 #include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
 
 namespace android {
 
+class Parcel;
 class ISurface;
 
 class IMediaPlayer: public IInterface
@@ -45,6 +46,36 @@
     virtual status_t        setAudioStreamType(int type) = 0;
     virtual status_t        setLooping(int loop) = 0;
     virtual status_t        setVolume(float leftVolume, float rightVolume) = 0;
+
+    // Invoke a generic method on the player by using opaque parcels
+    // for the request and reply.
+    // @param request Parcel that must start with the media player
+    // interface token.
+    // @param[out] reply Parcel to hold the reply data. Cannot be null.
+    // @return OK if the invocation was made successfully.
+    virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;
+
+    // Set a new metadata filter.
+    // @param filter A set of allow and drop rules serialized in a Parcel.
+    // @return OK if the invocation was made successfully.
+    virtual status_t        setMetadataFilter(const Parcel& filter) = 0;
+
+    // Retrieve a set of metadata.
+    // @param update_only Include only the metadata that have changed
+    //                    since the last invocation of getMetadata.
+    //                    The set is built using the unfiltered
+    //                    notifications the native player sent to the
+    //                    MediaPlayerService during that period of
+    //                    time. If false, all the metadatas are considered.
+    // @param apply_filter If true, once the metadata set has been built based
+    //                     on the value update_only, the current filter is
+    //                     applied.
+    // @param[out] metadata On exit contains a set (possibly empty) of metadata.
+    //                      Valid only if the call returned OK.
+    // @return OK if the invocation was made successfully.
+    virtual status_t        getMetadata(bool update_only,
+                                        bool apply_filter,
+                                        Parcel *metadata) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -61,4 +92,3 @@
 }; // namespace android
 
 #endif // ANDROID_IMEDIAPLAYER_H
-
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
index 5d32811..eee6c97 100644
--- a/include/media/IMediaPlayerClient.h
+++ b/include/media/IMediaPlayerClient.h
@@ -18,8 +18,8 @@
 #define ANDROID_IMEDIAPLAYERCLIENT_H
 
 #include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
 
 namespace android {
 
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index d1d96b1..39b5e57 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -17,9 +17,10 @@
 #ifndef ANDROID_IMEDIAPLAYERSERVICE_H
 #define ANDROID_IMEDIAPLAYERSERVICE_H
 
+#include <utils/Errors.h>  // for status_t
 #include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
 
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaPlayer.h>
@@ -28,6 +29,7 @@
 namespace android {
 
 class IMediaRecorder;
+class IOMX;
 
 class IMediaPlayerService: public IInterface
 {
@@ -36,11 +38,11 @@
 
     virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid) = 0;
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
-
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
+    virtual sp<IOMX>            createOMX() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 64d3a40..24ac82b 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -18,7 +18,7 @@
 #ifndef ANDROID_IMEDIARECORDER_H
 #define ANDROID_IMEDIARECORDER_H
 
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
 
 namespace android {
 
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
new file mode 100644
index 0000000..5c61c50
--- /dev/null
+++ b/include/media/IOMX.h
@@ -0,0 +1,176 @@
+/*
+ * 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 ANDROID_IOMX_H_
+
+#define ANDROID_IOMX_H_
+
+#include <binder/IInterface.h>
+#include <utils/List.h>
+#include <utils/String8.h>
+
+#include <OMX_Core.h>
+
+#define IOMX_USES_SOCKETS       0
+
+namespace android {
+
+class IMemory;
+class IOMXObserver;
+
+class IOMX : public IInterface {
+public:
+    DECLARE_META_INTERFACE(OMX);
+
+    typedef void *buffer_id;
+    typedef void *node_id;
+
+#if IOMX_USES_SOCKETS
+    // If successful, returns a socket descriptor used for further
+    // communication. Caller assumes ownership of "*sd".
+    virtual status_t connect(int *sd) = 0;
+#endif
+
+    virtual status_t list_nodes(List<String8> *list) = 0;
+
+    virtual status_t allocate_node(const char *name, node_id *node) = 0;
+    virtual status_t free_node(node_id node) = 0;
+
+    virtual status_t send_command(
+            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) = 0;
+
+    virtual status_t get_parameter(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size) = 0;
+
+    virtual status_t set_parameter(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size) = 0;
+
+    virtual status_t use_buffer(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer) = 0;
+
+    virtual status_t allocate_buffer(
+            node_id node, OMX_U32 port_index, size_t size,
+            buffer_id *buffer) = 0;
+
+    virtual status_t allocate_buffer_with_backup(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer) = 0;
+
+    virtual status_t free_buffer(
+            node_id node, OMX_U32 port_index, buffer_id buffer) = 0;
+
+#if !IOMX_USES_SOCKETS
+    virtual status_t observe_node(
+            node_id node, const sp<IOMXObserver> &observer) = 0;
+
+    virtual void fill_buffer(node_id node, buffer_id buffer) = 0;
+
+    virtual void empty_buffer(
+            node_id node,
+            buffer_id buffer,
+            OMX_U32 range_offset, OMX_U32 range_length,
+            OMX_U32 flags, OMX_TICKS timestamp) = 0;
+#endif
+};
+
+struct omx_message {
+    enum {
+        EVENT,
+        EMPTY_BUFFER_DONE,
+        FILL_BUFFER_DONE,
+
+#if IOMX_USES_SOCKETS
+        EMPTY_BUFFER,
+        FILL_BUFFER,
+        SEND_COMMAND,
+        DISCONNECT,
+        DISCONNECTED,
+#endif
+
+        // reserved for OMXDecoder use.
+        START,
+        INITIAL_FILL_BUFFER,
+
+        // reserved for OMXObserver use.
+        QUIT_OBSERVER,
+    } type;
+
+    union {
+        // if type == EVENT
+        struct {
+            IOMX::node_id node;
+            OMX_EVENTTYPE event;
+            OMX_U32 data1;
+            OMX_U32 data2;
+        } event_data;
+
+        // if type == EMPTY_BUFFER_DONE || type == FILL_BUFFER
+        //    || type == INITIAL_FILL_BUFFER
+        struct {
+            IOMX::node_id node;
+            IOMX::buffer_id buffer;
+        } buffer_data;
+
+        // if type == EMPTY_BUFFER || type == FILL_BUFFER_DONE
+        struct {
+            IOMX::node_id node;
+            IOMX::buffer_id buffer;
+            OMX_U32 range_offset;
+            OMX_U32 range_length;
+            OMX_U32 flags;
+            OMX_TICKS timestamp;
+            OMX_PTR platform_private;  // ignored if type == EMPTY_BUFFER
+        } extended_buffer_data;
+
+        // if type == SEND_COMMAND
+        struct {
+            IOMX::node_id node;
+            OMX_COMMANDTYPE cmd;
+            OMX_S32 param;
+        } send_command_data;
+
+    } u;
+};
+
+class IOMXObserver : public IInterface {
+public:
+    DECLARE_META_INTERFACE(OMXObserver);
+
+    virtual void on_message(const omx_message &msg) = 0;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BnOMX : public BnInterface<IOMX> {
+public:
+    virtual status_t onTransact(
+            uint32_t code, const Parcel &data, Parcel *reply,
+            uint32_t flags = 0);
+};
+
+class BnOMXObserver : public BnInterface<IOMXObserver> {
+public:
+    virtual status_t onTransact(
+            uint32_t code, const Parcel &data, Parcel *reply,
+            uint32_t flags = 0);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_IOMX_H_
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 7bf555a..f723cfd 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -19,20 +19,32 @@
 
 #ifdef __cplusplus
 
+#include <sys/types.h>
 #include <ui/ISurface.h>
 #include <utils/RefBase.h>
+#include <utils/Errors.h>
 
 #include <media/mediaplayer.h>
 #include <media/AudioSystem.h>
+#include <media/Metadata.h>
 
 namespace android {
 
+class Parcel;
+template<typename T> class SortedVector;
+
 enum player_type {
     PV_PLAYER = 1,
     SONIVOX_PLAYER = 2,
-    VORBIS_PLAYER = 3
+    VORBIS_PLAYER = 3,
+    STAGEFRIGHT_PLAYER = 4,
+    // Test players are available only in the 'test' and 'eng' builds.
+    // The shared library with the test player is passed passed as an
+    // argument to the 'test:' url in the setDataSource call.
+    TEST_PLAYER = 5,
 };
 
+
 #define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
 #define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
 #define DEFAULT_AUDIOSINK_SAMPLERATE 44100
@@ -45,10 +57,12 @@
 class MediaPlayerBase : public RefBase
 {
 public:
-
     // AudioSink: abstraction layer for audio output
     class AudioSink : public RefBase {
     public:
+        typedef void (*AudioCallback)(
+                AudioSink *audioSink, void *buffer, size_t size, void *cookie);
+
         virtual             ~AudioSink() {}
         virtual bool        ready() const = 0; // audio output is open and ready
         virtual bool        realtime() const = 0; // audio output is real-time output
@@ -58,7 +72,17 @@
         virtual ssize_t     frameSize() const = 0;
         virtual uint32_t    latency() const = 0;
         virtual float       msecsPerFrame() const = 0;
-        virtual status_t    open(uint32_t sampleRate, int channelCount, int format=AudioSystem::PCM_16_BIT, int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT) = 0;
+
+        // If no callback is specified, use the "write" API below to submit
+        // audio data. Otherwise return a full buffer of audio data on each
+        // callback.
+        virtual status_t    open(
+                uint32_t sampleRate, int channelCount,
+                int format=AudioSystem::PCM_16_BIT,
+                int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
+                AudioCallback cb = NULL,
+                void *cookie = NULL) = 0;
+
         virtual void        start() = 0;
         virtual ssize_t     write(const void* buffer, size_t size) = 0;
         virtual void        stop() = 0;
@@ -88,6 +112,26 @@
     virtual player_type playerType() = 0;
     virtual void        setNotifyCallback(void* cookie, notify_callback_f notifyFunc) {
                             mCookie = cookie; mNotify = notifyFunc; }
+    // Invoke a generic method on the player by using opaque parcels
+    // for the request and reply.
+    //
+    // @param request Parcel that is positioned at the start of the
+    //                data sent by the java layer.
+    // @param[out] reply Parcel to hold the reply data. Cannot be null.
+    // @return OK if the call was successful.
+    virtual status_t    invoke(const Parcel& request, Parcel *reply) = 0;
+
+    // The Client in the MetadataPlayerService calls this method on
+    // the native player to retrieve all or a subset of metadata.
+    //
+    // @param ids SortedList of metadata ID to be fetch. If empty, all
+    //            the known metadata should be returned.
+    // @param[inout] records Parcel where the player appends its metadata.
+    // @return OK if the call was successful.
+    virtual status_t    getMetadata(const media::Metadata::Filter& ids,
+                                    Parcel *records) {
+        return INVALID_OPERATION;
+    };
 
 protected:
     virtual void        sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); }
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
new file mode 100644
index 0000000..241868a
--- /dev/null
+++ b/include/media/Metadata.h
@@ -0,0 +1,133 @@
+/*
+ * 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 ANDROID_MEDIA_METADATA_H__
+#define ANDROID_MEDIA_METADATA_H__
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+class Parcel;
+
+namespace media {
+
+// Metadata is a class to build/serialize a set of metadata in a Parcel.
+//
+// This class should be kept in sync with android/media/Metadata.java.
+// It provides all the metadata ids available and methods to build the
+// header, add records and adjust the set size header field.
+//
+// Typical Usage:
+// ==============
+//  Parcel p;
+//  media::Metadata data(&p);
+//
+//  data.appendHeader();
+//  data.appendBool(Metadata::kPauseAvailable, true);
+//   ... more append ...
+//  data.updateLength();
+//
+
+class Metadata {
+  public:
+    typedef int32_t Type;
+    typedef SortedVector<Type> Filter;
+
+    static const Type kAny = 0;
+
+    // Keep in sync with android/media/Metadata.java
+    static const Type kTitle = 1;           // String
+    static const Type kComment = 2;         // String
+    static const Type kCopyright = 3;       // String
+    static const Type kAlbum = 4;           // String
+    static const Type kArtist = 5;          // String
+    static const Type kAuthor = 6;          // String
+    static const Type kComposer = 7;        // String
+    static const Type kGenre = 8;           // String
+    static const Type kDate = 9;            // Date
+    static const Type kDuration = 10;       // Integer(millisec)
+    static const Type kCdTrackNum = 11;     // Integer 1-based
+    static const Type kCdTrackMax = 12;     // Integer
+    static const Type kRating = 13;         // String
+    static const Type kAlbumArt = 14;       // byte[]
+    static const Type kVideoFrame = 15;     // Bitmap
+    static const Type kCaption = 16;        // TimedText
+
+    static const Type kBitRate = 17;       // Integer, Aggregate rate of
+    // all the streams in bps.
+
+    static const Type kAudioBitRate = 18; // Integer, bps
+    static const Type kVideoBitRate = 19; // Integer, bps
+    static const Type kAudioSampleRate = 20; // Integer, Hz
+    static const Type kVideoframeRate = 21;  // Integer, Hz
+
+    // See RFC2046 and RFC4281.
+    static const Type kMimeType = 22;      // String
+    static const Type kAudioCodec = 23;    // String
+    static const Type kVideoCodec = 24;    // String
+
+    static const Type kVideoHeight = 25;   // Integer
+    static const Type kVideoWidth = 26;    // Integer
+    static const Type kNumTracks = 27;     // Integer
+    static const Type kDrmCrippled = 28;   // Boolean
+
+    // Playback capabilities.
+    static const Type kPauseAvailable = 29;        // Boolean
+    static const Type kSeekBackwardAvailable = 30; // Boolean
+    static const Type kSeekForwardAvailable = 31;  // Boolean
+
+    // @param p[inout] The parcel to append the metadata records
+    // to. The global metadata header should have been set already.
+    explicit Metadata(Parcel *p);
+    ~Metadata();
+
+    // Rewind the underlying parcel, undoing all the changes.
+    void resetParcel();
+
+    // Append the size and 'META' marker.
+    bool appendHeader();
+
+    // Once all the records have been added, call this to update the
+    // lenght field in the header.
+    void updateLength();
+
+    // append* are methods to append metadata.
+    // @param key Is the metadata Id.
+    // @param val Is the value of the metadata.
+    // @return true if successful, false otherwise.
+    // TODO: add more as needed to handle other types.
+    bool appendBool(Type key, bool val);
+    bool appendInt32(Type key, int32_t val);
+
+  private:
+    Metadata(const Metadata&);
+    Metadata& operator=(const Metadata&);
+
+
+    // Checks the key is valid and not already present.
+    bool checkKey(Type key);
+
+    Parcel *mData;
+    size_t mBegin;
+};
+
+}  // namespace android::media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_METADATA_H__
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
index 8122df6..8a66152 100644
--- a/include/media/PVPlayer.h
+++ b/include/media/PVPlayer.h
@@ -19,6 +19,7 @@
 
 #include <utils/Errors.h>
 #include <media/MediaPlayerInterface.h>
+#include <media/Metadata.h>
 
 #define MAX_OPENCORE_INSTANCES 25
 
@@ -52,6 +53,10 @@
     virtual status_t    reset();
     virtual status_t    setLooping(int loop);
     virtual player_type playerType() { return PV_PLAYER; }
+    virtual status_t    invoke(const Parcel& request, Parcel *reply);
+    virtual status_t    getMetadata(
+        const SortedVector<media::Metadata::Type>& ids,
+        Parcel *records);
 
     // make available to PlayerDriver
     void        sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
@@ -62,6 +67,7 @@
     static void         run_set_video_surface(status_t s, void *cookie, bool cancelled);
     static void         run_set_audio_output(status_t s, void *cookie, bool cancelled);
     static void         run_prepare(status_t s, void *cookie, bool cancelled);
+    static void         check_for_live_streaming(status_t s, void *cookie, bool cancelled);
 
     PlayerDriver*               mPlayerDriver;
     char *                      mDataSourcePath;
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index f2719d3..3db8a0f 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -20,7 +20,7 @@
 
 #include <utils/Errors.h>  // for status_t
 #include <utils/threads.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
 #include <media/IMediaMetadataRetriever.h>
 
 namespace android {
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 513ffe1..26b054b 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_MEDIAPLAYER_H
 #define ANDROID_MEDIAPLAYER_H
 
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
 #include <ui/Surface.h>
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaPlayer.h>
@@ -97,6 +97,8 @@
     MEDIA_INFO_BAD_INTERLEAVING = 800,
     // The media is not seekable (e.g live stream).
     MEDIA_INFO_NOT_SEEKABLE = 801,
+    // New media metadata is available.
+    MEDIA_INFO_METADATA_UPDATE = 802,
 };
 
 
@@ -151,7 +153,9 @@
             void            notify(int msg, int ext1, int ext2);
     static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
-
+            status_t        invoke(const Parcel& request, Parcel *reply);
+            status_t        setMetadataFilter(const Parcel& filter);
+            status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
 private:
             void            clear_l();
             status_t        seekTo_l(int msec);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 9b54ca9..ad27903 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -18,7 +18,10 @@
 #ifndef ANDROID_MEDIARECORDER_H
 #define ANDROID_MEDIARECORDER_H
 
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
 #include <media/IMediaPlayerClient.h>
 
 namespace android {
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index fbef1db..7749566 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -17,7 +17,10 @@
 #ifndef MEDIASCANNER_H
 #define MEDIASCANNER_H
 
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
 #include <pthread.h>
 
 namespace android {
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
new file mode 100644
index 0000000..0f2e528
--- /dev/null
+++ b/include/media/stagefright/AudioPlayer.h
@@ -0,0 +1,98 @@
+/*
+ * 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 AUDIO_PLAYER_H_
+
+#define AUDIO_PLAYER_H_
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/TimeSource.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaSource;
+class AudioTrack;
+
+class AudioPlayer : public TimeSource {
+public:
+    AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink);
+    ~AudioPlayer();
+
+    // Caller retains ownership of "source".
+    void setSource(MediaSource *source);
+
+    // Return time in us.
+    virtual int64_t getRealTimeUs();
+
+    void start();
+
+    void pause();
+    void resume();
+
+    void stop();
+
+    // Returns the timestamp of the last buffer played (in us).
+    int64_t getMediaTimeUs();
+
+    // Returns true iff a mapping is established, i.e. the AudioPlayer
+    // has played at least one frame of audio.
+    bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
+
+    status_t seekTo(int64_t time_us);
+
+private:
+    MediaSource *mSource;
+    AudioTrack *mAudioTrack;
+
+    MediaBuffer *mInputBuffer;
+
+    int mSampleRate;
+    int64_t mLatencyUs;
+    size_t mFrameSize;
+
+    Mutex mLock;
+    int64_t mNumFramesPlayed;
+
+    int64_t mPositionTimeMediaUs;
+    int64_t mPositionTimeRealUs;
+
+    bool mSeeking;
+    int64_t mSeekTimeUs;
+
+    bool mStarted;
+
+    sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+    static void AudioCallback(int event, void *user, void *info);
+    void AudioCallback(int event, void *info);
+
+    static void AudioSinkCallback(
+            MediaPlayerBase::AudioSink *audioSink,
+            void *data, size_t size, void *me);
+
+    void fillBuffer(void *data, size_t size);
+
+    int64_t getRealTimeUsLocked() const;
+
+    AudioPlayer(const AudioPlayer &);
+    AudioPlayer &operator=(const AudioPlayer &);
+};
+
+}  // namespace android
+
+#endif  // AUDIO_PLAYER_H_
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
new file mode 100644
index 0000000..e129958
--- /dev/null
+++ b/include/media/stagefright/AudioSource.h
@@ -0,0 +1,51 @@
+/*
+ * 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 AUDIO_SOURCE_H_
+
+#define AUDIO_SOURCE_H_
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class AudioRecord;
+
+class AudioSource {
+public:
+    AudioSource(int inputSource);
+    virtual ~AudioSource();
+
+    status_t initCheck() const;
+
+    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);
+
+private:
+    AudioRecord *mRecord;
+    status_t mInitCheck;
+
+    AudioSource(const AudioSource &);
+    AudioSource &operator=(const AudioSource &);
+};
+
+}  // namespace android
+
+#endif  // AUDIO_SOURCE_H_
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
new file mode 100644
index 0000000..e275cb4
--- /dev/null
+++ b/include/media/stagefright/CachingDataSource.h
@@ -0,0 +1,60 @@
+/*
+ * 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 CACHING_DATASOURCE_H_
+
+#define CACHING_DATASOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CachingDataSource : public DataSource {
+public:
+    // Assumes ownership of "source".
+    CachingDataSource(DataSource *source, size_t pageSize, int numPages);
+    virtual ~CachingDataSource();
+
+    status_t InitCheck() const;
+
+    virtual ssize_t read_at(off_t offset, void *data, size_t size);
+
+private:
+    struct Page {
+        Page *mPrev, *mNext;
+        off_t mOffset;
+        size_t mLength;
+        void *mData;
+    };
+
+    DataSource *mSource;
+    void *mData;
+    size_t mPageSize;
+    Page *mFirst, *mLast;
+
+    Page *allocate_page();
+
+    Mutex mLock;
+
+    CachingDataSource(const CachingDataSource &);
+    CachingDataSource &operator=(const CachingDataSource &);
+};
+
+}  // namespace android
+
+#endif  // CACHING_DATASOURCE_H_
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
new file mode 100644
index 0000000..7042e1a
--- /dev/null
+++ b/include/media/stagefright/CameraSource.h
@@ -0,0 +1,72 @@
+/*
+ * 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 CAMERA_SOURCE_H_
+
+#define CAMERA_SOURCE_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ICamera;
+class ICameraClient;
+class IMemory;
+
+class CameraSource : public MediaSource,
+                     public MediaBufferObserver {
+public:
+    static CameraSource *Create();
+
+    virtual ~CameraSource();
+
+    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);
+
+    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);
+
+    sp<ICamera> mCamera;
+    sp<ICameraClient> mCameraClient;
+
+    Mutex mLock;
+    Condition mFrameAvailableCondition;
+    List<sp<IMemory> > mFrames;
+
+    int mNumFrames;
+    bool mStarted;
+
+    CameraSource(const CameraSource &);
+    CameraSource &operator=(const CameraSource &);
+};
+
+}  // namespace android
+
+#endif  // CAMERA_SOURCE_H_
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
new file mode 100644
index 0000000..31eea27
--- /dev/null
+++ b/include/media/stagefright/DataSource.h
@@ -0,0 +1,61 @@
+/*
+ * 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 DATA_SOURCE_H_
+
+#define DATA_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class String8;
+
+class DataSource {
+public:
+    DataSource() {}
+    virtual ~DataSource() {}
+
+    virtual ssize_t read_at(off_t offset, void *data, size_t size) = 0;
+
+    // May return ERROR_UNSUPPORTED.
+    virtual status_t getSize(off_t *size);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    bool sniff(String8 *mimeType, float *confidence);
+
+    typedef bool (*SnifferFunc)(
+            DataSource *source, String8 *mimeType, float *confidence);
+
+    static void RegisterSniffer(SnifferFunc func);
+    static void RegisterDefaultSniffers();
+
+private:
+    static Mutex gSnifferMutex;
+    static List<SnifferFunc> gSniffers;
+
+    DataSource(const DataSource &);
+    DataSource &operator=(const DataSource &);
+};
+
+}  // namespace android
+
+#endif  // DATA_SOURCE_H_
diff --git a/include/media/stagefright/ESDS.h b/include/media/stagefright/ESDS.h
new file mode 100644
index 0000000..01bcd18
--- /dev/null
+++ b/include/media/stagefright/ESDS.h
@@ -0,0 +1,64 @@
+/*
+ * 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 ESDS_H_
+
+#define ESDS_H_
+
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+class ESDS {
+public:
+    ESDS(const void *data, size_t size);
+    ~ESDS();
+
+    status_t InitCheck() const;
+
+    status_t getCodecSpecificInfo(const void **data, size_t *size) const;
+
+private:
+    enum {
+        kTag_ESDescriptor            = 0x03,
+        kTag_DecoderConfigDescriptor = 0x04,
+        kTag_DecoderSpecificInfo     = 0x05
+    };
+
+    uint8_t *mData;
+    size_t mSize;
+
+    status_t mInitCheck;
+
+    size_t mDecoderSpecificOffset;
+    size_t mDecoderSpecificLength;
+
+    status_t skipDescriptorHeader(
+            size_t offset, size_t size,
+            uint8_t *tag, size_t *data_offset, size_t *data_size) const;
+
+    status_t parse();
+    status_t parseESDescriptor(size_t offset, size_t size);
+    status_t parseDecoderConfigDescriptor(size_t offset, size_t size);
+
+    ESDS(const ESDS &);
+    ESDS &operator=(const ESDS &);
+};
+
+}  // namespace android
+#endif  // ESDS_H_
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
new file mode 100644
index 0000000..ccbe0ef
--- /dev/null
+++ b/include/media/stagefright/FileSource.h
@@ -0,0 +1,49 @@
+/*
+ * 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 FILE_SOURCE_H_
+
+#define FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class FileSource : public DataSource {
+public:
+    FileSource(const char *filename);
+    virtual ~FileSource();
+
+    status_t InitCheck() const;
+
+    virtual ssize_t read_at(off_t offset, void *data, size_t size);
+
+private:
+    FILE *mFile;
+    Mutex mLock;
+
+    FileSource(const FileSource &);
+    FileSource &operator=(const FileSource &);
+};
+
+}  // namespace android
+
+#endif  // FILE_SOURCE_H_
+
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
new file mode 100644
index 0000000..0587c7c
--- /dev/null
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -0,0 +1,59 @@
+/*
+ * 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 HTTP_DATASOURCE_H_
+
+#define HTTP_DATASOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPStream.h>
+
+namespace android {
+
+class HTTPDataSource : public DataSource {
+public:
+    HTTPDataSource(const char *host, int port, const char *path);
+    HTTPDataSource(const char *uri);
+
+    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;
+    char *mHost;
+    int mPort;
+    char *mPath;
+
+    void *mBuffer;
+    size_t mBufferLength;
+    off_t mBufferOffset;
+
+    HTTPDataSource(const HTTPDataSource &);
+    HTTPDataSource &operator=(const HTTPDataSource &);
+};
+
+}  // namespace android
+
+#endif  // HTTP_DATASOURCE_H_
+
diff --git a/include/media/stagefright/HTTPStream.h b/include/media/stagefright/HTTPStream.h
new file mode 100644
index 0000000..3d0d67a
--- /dev/null
+++ b/include/media/stagefright/HTTPStream.h
@@ -0,0 +1,74 @@
+/*
+ * 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 HTTP_STREAM_H_
+
+#define HTTP_STREAM_H_
+
+#include <sys/types.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/string.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class HTTPStream {
+public:
+    HTTPStream();
+    ~HTTPStream();
+
+    status_t connect(const char *server, int port = 80);
+    status_t disconnect();
+
+    status_t send(const char *data, size_t size);
+
+    // Assumes data is a '\0' terminated string.
+    status_t send(const char *data);
+
+    // Receive up to "size" bytes of data.
+    ssize_t receive(void *data, size_t size);
+
+    status_t receive_header(int *http_status);
+
+    // The header key used to retrieve the status line.
+    static const char *kStatusKey;
+
+    bool find_header_value(
+            const string &key, string *value) const;
+
+private:
+    enum State {
+        READY,
+        CONNECTED
+    };
+
+    State mState;
+    int mSocket;
+
+    KeyedVector<string, string> mHeaders;
+
+    // Receive a line of data terminated by CRLF, line will be '\0' terminated
+    // _excluding_ the termianting CRLF.
+    status_t receive_line(char *line, size_t size);
+
+    HTTPStream(const HTTPStream &);
+    HTTPStream &operator=(const HTTPStream &);
+};
+
+}  // namespace android
+
+#endif  // HTTP_STREAM_H_
diff --git a/include/media/stagefright/MP3Extractor.h b/include/media/stagefright/MP3Extractor.h
new file mode 100644
index 0000000..09cfb70
--- /dev/null
+++ b/include/media/stagefright/MP3Extractor.h
@@ -0,0 +1,53 @@
+/*
+ * 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 MP3_EXTRACTOR_H_
+
+#define MP3_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class String8;
+
+class MP3Extractor : public MediaExtractor {
+public:
+    // Extractor assumes ownership of "source".
+    MP3Extractor(DataSource *source);
+
+    ~MP3Extractor();
+
+    status_t countTracks(int *num_tracks);
+    status_t getTrack(int index, MediaSource **source);
+    sp<MetaData> getTrackMetaData(int index);
+
+private:
+    DataSource *mDataSource;
+    off_t mFirstFramePos;
+    sp<MetaData> mMeta;
+    uint32_t mFixedHeader;
+
+    MP3Extractor(const MP3Extractor &);
+    MP3Extractor &operator=(const MP3Extractor &);
+};
+
+bool SniffMP3(DataSource *source, String8 *mimeType, float *confidence);
+
+}  // namespace android
+
+#endif  // MP3_EXTRACTOR_H_
diff --git a/include/media/stagefright/MPEG4Extractor.h b/include/media/stagefright/MPEG4Extractor.h
new file mode 100644
index 0000000..51a7e82
--- /dev/null
+++ b/include/media/stagefright/MPEG4Extractor.h
@@ -0,0 +1,65 @@
+/*
+ * 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 MPEG4_EXTRACTOR_H_
+
+#define MPEG4_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class SampleTable;
+class String8;
+
+class MPEG4Extractor : public MediaExtractor {
+public:
+    // Extractor assumes ownership of "source".
+    MPEG4Extractor(DataSource *source);
+    ~MPEG4Extractor();
+
+    status_t countTracks(int *num_tracks);
+    status_t getTrack(int index, MediaSource **source);
+    sp<MetaData> getTrackMetaData(int index);
+
+private:
+    struct Track {
+        Track *next;
+        sp<MetaData> meta;
+        uint32_t timescale;
+        SampleTable *sampleTable;
+    };
+
+    DataSource *mDataSource;
+    bool mHaveMetadata;
+
+    Track *mFirstTrack, *mLastTrack;
+
+    uint32_t mHandlerType;
+
+    status_t readMetaData();
+    status_t parseChunk(off_t *offset, int depth);
+
+    MPEG4Extractor(const MPEG4Extractor &);
+    MPEG4Extractor &operator=(const MPEG4Extractor &);
+};
+
+bool SniffMPEG4(DataSource *source, String8 *mimeType, float *confidence);
+
+}  // namespace android
+
+#endif  // MPEG4_EXTRACTOR_H_
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
new file mode 100644
index 0000000..40d6127
--- /dev/null
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -0,0 +1,73 @@
+/*
+ * 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 MPEG4_WRITER_H_
+
+#define MPEG4_WRITER_H_
+
+#include <stdio.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaBuffer;
+class MediaSource;
+class MetaData;
+
+class MPEG4Writer {
+public:
+    MPEG4Writer(const char *filename);
+    ~MPEG4Writer();
+
+    // Caller retains ownership of both meta and source.
+    void addSource(const sp<MetaData> &meta, MediaSource *source);
+    void start();
+    void stop();
+
+    void beginBox(const char *fourcc);
+    void writeInt8(int8_t x);
+    void writeInt16(int16_t x);
+    void writeInt32(int32_t x);
+    void writeInt64(int64_t x);
+    void writeCString(const char *s);
+    void writeFourcc(const char *fourcc);
+    void write(const void *data, size_t size);
+    void endBox();
+
+private:
+    class Track;
+
+    FILE *mFile;
+    off_t mOffset;
+    off_t mMdatOffset;
+    Mutex mLock;
+
+    List<Track *> mTracks;
+
+    List<off_t> mBoxes;
+
+    off_t addSample(MediaBuffer *buffer);
+
+    MPEG4Writer(const MPEG4Writer &);
+    MPEG4Writer &operator=(const MPEG4Writer &);
+};
+
+}  // namespace android
+
+#endif  // MPEG4_WRITER_H_
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
new file mode 100644
index 0000000..c72ed66
--- /dev/null
+++ b/include/media/stagefright/MediaBuffer.h
@@ -0,0 +1,113 @@
+/*
+ * 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 MEDIA_BUFFER_H_
+
+#define MEDIA_BUFFER_H_
+
+#include <pthread.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBuffer;
+class MediaBufferObserver;
+class MetaData;
+
+class MediaBufferObserver {
+public:
+    MediaBufferObserver() {}
+    virtual ~MediaBufferObserver() {}
+
+    virtual void signalBufferReturned(MediaBuffer *buffer) = 0;
+
+private:
+    MediaBufferObserver(const MediaBufferObserver &);
+    MediaBufferObserver &operator=(const MediaBufferObserver &);
+};
+
+class MediaBuffer {
+public:
+    // The underlying data remains the responsibility of the caller!
+    MediaBuffer(void *data, size_t size);
+
+    MediaBuffer(size_t size);
+
+    // Decrements the reference count and returns the buffer to its
+    // associated MediaBufferGroup if the reference count drops to 0.
+    void release();
+
+    // Increments the reference count.
+    void add_ref();
+
+    void *data() const;
+    size_t size() const;
+
+    size_t range_offset() const;
+    size_t range_length() const;
+
+    void set_range(size_t offset, size_t length);
+
+    sp<MetaData> meta_data();
+
+    // Clears meta data and resets the range to the full extent.
+    void reset();
+
+    void setObserver(MediaBufferObserver *group);
+
+    // Returns a clone of this MediaBuffer increasing its reference count.
+    // The clone references the same data but has its own range and
+    // MetaData.
+    MediaBuffer *clone();
+
+protected:
+    virtual ~MediaBuffer();
+
+private:
+    friend class MediaBufferGroup;
+    friend class OMXDecoder;
+
+    // For use by OMXDecoder, reference count must be 1, drop reference
+    // count to 0 without signalling the observer.
+    void claim();
+
+    MediaBufferObserver *mObserver;
+    MediaBuffer *mNextBuffer;
+    int mRefCount;
+
+    void *mData;
+    size_t mSize, mRangeOffset, mRangeLength;
+
+    bool mOwnsData;
+
+    sp<MetaData> mMetaData;
+
+    MediaBuffer *mOriginal;
+
+    void setNextBuffer(MediaBuffer *buffer);
+    MediaBuffer *nextBuffer();
+
+    int refcount() const;
+
+    MediaBuffer(const MediaBuffer &);
+    MediaBuffer &operator=(const MediaBuffer &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_BUFFER_H_
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
new file mode 100644
index 0000000..e95a9c2
--- /dev/null
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -0,0 +1,57 @@
+/*
+ * 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 MEDIA_BUFFER_GROUP_H_
+
+#define MEDIA_BUFFER_GROUP_H_
+
+#include <utils/Errors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaBuffer;
+class MetaData;
+
+class MediaBufferGroup : public MediaBufferObserver {
+public:
+    MediaBufferGroup();
+    ~MediaBufferGroup();
+
+    void add_buffer(MediaBuffer *buffer);
+
+    // Blocks until a buffer is available and returns it to the caller,
+    // the returned buffer will have a reference count of 1.
+    status_t acquire_buffer(MediaBuffer **buffer);
+
+protected:
+    virtual void signalBufferReturned(MediaBuffer *buffer);
+
+private:
+    friend class MediaBuffer;
+
+    Mutex mLock;
+    Condition mCondition;
+
+    MediaBuffer *mFirstBuffer, *mLastBuffer;
+
+    MediaBufferGroup(const MediaBufferGroup &);
+    MediaBufferGroup &operator=(const MediaBufferGroup &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_BUFFER_GROUP_H_
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
new file mode 100644
index 0000000..2bb0ed6
--- /dev/null
+++ b/include/media/stagefright/MediaErrors.h
@@ -0,0 +1,43 @@
+/*
+ * 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 MEDIA_ERRORS_H_
+
+#define MEDIA_ERRORS_H_
+
+#include <utils/Errors.h>
+
+namespace android {
+
+enum {
+    MEDIA_ERROR_BASE        = -1000,
+
+    ERROR_ALREADY_CONNECTED = MEDIA_ERROR_BASE,
+    ERROR_NOT_CONNECTED     = MEDIA_ERROR_BASE - 1,
+    ERROR_UNKNOWN_HOST      = MEDIA_ERROR_BASE - 2,
+    ERROR_CANNOT_CONNECT    = MEDIA_ERROR_BASE - 3,
+    ERROR_IO                = MEDIA_ERROR_BASE - 4,
+    ERROR_CONNECTION_LOST   = MEDIA_ERROR_BASE - 5,
+    ERROR_MALFORMED         = MEDIA_ERROR_BASE - 7,
+    ERROR_OUT_OF_RANGE      = MEDIA_ERROR_BASE - 8,
+    ERROR_BUFFER_TOO_SMALL  = MEDIA_ERROR_BASE - 9,
+    ERROR_UNSUPPORTED       = MEDIA_ERROR_BASE - 10,
+    ERROR_END_OF_STREAM     = MEDIA_ERROR_BASE - 11,
+};
+
+}  // namespace android
+
+#endif  // MEDIA_ERRORS_H_
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
new file mode 100644
index 0000000..38f8e5b
--- /dev/null
+++ b/include/media/stagefright/MediaExtractor.h
@@ -0,0 +1,49 @@
+/*
+ * 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 MEDIA_EXTRACTOR_H_
+
+#define MEDIA_EXTRACTOR_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class DataSource;
+class MediaSource;
+class MetaData;
+
+class MediaExtractor {
+public:
+    static MediaExtractor *Create(DataSource *source, const char *mime = NULL);
+
+    virtual ~MediaExtractor() {}
+
+    virtual status_t countTracks(int *num_tracks) = 0;
+    virtual status_t getTrack(int index, MediaSource **source) = 0;
+    virtual sp<MetaData> getTrackMetaData(int index) = 0;
+
+protected:
+    MediaExtractor() {}
+
+private:
+    MediaExtractor(const MediaExtractor &);
+    MediaExtractor &operator=(const MediaExtractor &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_EXTRACTOR_H_
diff --git a/include/media/stagefright/MediaPlayerImpl.h b/include/media/stagefright/MediaPlayerImpl.h
new file mode 100644
index 0000000..c48400c
--- /dev/null
+++ b/include/media/stagefright/MediaPlayerImpl.h
@@ -0,0 +1,132 @@
+/*
+ * 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 MEDIA_PLAYER_IMPL_H_
+
+#define MEDIA_PLAYER_IMPL_H_
+
+#include <pthread.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class AudioPlayer;
+class ISurface;
+class MediaExtractor;
+class MediaBuffer;
+class MediaSource;
+class MemoryHeapPmem;
+class MetaData;
+class OMXDecoder;
+class Surface;
+class TimeSource;
+class VideoRenderer;
+
+class MediaPlayerImpl {
+public:
+    MediaPlayerImpl(const char *uri);
+
+    status_t initCheck() const;
+
+    // Assumes ownership of "fd".
+    MediaPlayerImpl(int fd, int64_t offset, int64_t length);
+
+    ~MediaPlayerImpl();
+
+    void play();
+    void pause();
+    bool isPlaying() const;
+
+    void setSurface(const sp<Surface> &surface);
+    void setISurface(const sp<ISurface> &isurface);
+
+    void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
+
+    int32_t getWidth() const { return mVideoWidth; }
+    int32_t getHeight() const { return mVideoHeight; }
+
+    int64_t getDuration();
+    int64_t getPosition();
+    status_t seekTo(int64_t time);
+
+private:
+    status_t mInitCheck;
+
+    OMXClient mClient;
+
+    MediaExtractor *mExtractor;
+
+    TimeSource *mTimeSource;
+
+    MediaSource *mAudioSource;
+    OMXDecoder *mAudioDecoder;
+    AudioPlayer *mAudioPlayer;
+
+    MediaSource *mVideoSource;
+    MediaSource *mVideoDecoder;
+    int32_t mVideoWidth, mVideoHeight;
+    int64_t mVideoPosition;
+
+    int64_t mDuration;
+
+    bool mPlaying;
+    bool mPaused;
+
+    int64_t mTimeSourceDeltaUs;
+
+    sp<Surface> mSurface;
+    sp<ISurface> mISurface;
+    VideoRenderer *mRenderer;
+
+    sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+    Mutex mLock;
+    pthread_t mVideoThread;
+
+    bool mSeeking;
+    int64_t mSeekTimeUs;
+
+    size_t mFrameSize;
+    bool mUseSoftwareColorConversion;
+
+    void init();
+
+    static void *VideoWrapper(void *me);
+    void videoEntry();
+
+    void setAudioSource(MediaSource *source);
+    void setVideoSource(MediaSource *source);
+
+    MediaSource *makeShoutcastSource(const char *path);
+
+    void displayOrDiscardFrame(MediaBuffer *buffer, int64_t pts_us);
+    void populateISurface();
+    void depopulateISurface();
+    void sendFrameToISurface(MediaBuffer *buffer);
+
+    void stop();
+
+    MediaPlayerImpl(const MediaPlayerImpl &);
+    MediaPlayerImpl &operator=(const MediaPlayerImpl &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_PLAYER_IMPL_H_
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
new file mode 100644
index 0000000..eb07f68
--- /dev/null
+++ b/include/media/stagefright/MediaSource.h
@@ -0,0 +1,91 @@
+/*
+ * 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 MEDIA_SOURCE_H_
+
+#define MEDIA_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBuffer;
+class MetaData;
+
+struct MediaSource {
+    MediaSource();
+    virtual ~MediaSource();
+
+    // To be called before any other methods on this object, except
+    // getFormat().
+    virtual status_t start(MetaData *params = NULL) = 0;
+
+    // Any blocking read call returns immediately with a result of NO_INIT.
+    // It is an error to call any methods other than start after this call
+    // returns. Any buffers the object may be holding onto at the time of
+    // the stop() call are released.
+    // Also, it is imperative that any buffers output by this object and
+    // held onto by callers be released before a call to stop() !!!
+    virtual status_t stop() = 0;
+
+    // Returns the format of the data output by this media source.
+    virtual sp<MetaData> getFormat() = 0;
+
+    struct ReadOptions;
+
+    // Returns a new buffer of data. Call blocks until a
+    // 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.
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+
+    // Options that modify read() behaviour. The default is to
+    // a) not request a seek
+    // b) not be late, i.e. lateness_us = 0
+    struct ReadOptions {
+        ReadOptions();
+
+        // Reset everything back to defaults.
+        void reset();
+
+        void setSeekTo(int64_t time_us);
+        void clearSeekTo();
+        bool getSeekTo(int64_t *time_us) const;
+
+        void setLateBy(int64_t lateness_us);
+        int64_t getLateBy() const;
+
+    private:
+        enum Options {
+            kSeekTo_Option      = 1,
+        };
+
+        uint32_t mOptions;
+        int64_t mSeekTimeUs;
+        int64_t mLatenessUs;
+    };
+
+private:
+    MediaSource(const MediaSource &);
+    MediaSource &operator=(const MediaSource &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_SOURCE_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
new file mode 100644
index 0000000..04805da
--- /dev/null
+++ b/include/media/stagefright/MetaData.h
@@ -0,0 +1,132 @@
+/*
+ * 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 META_DATA_H_
+
+#define META_DATA_H_
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+enum {
+    kKeyMIMEType         = 'mime',
+    kKeyWidth            = 'widt',
+    kKeyHeight           = 'heig',
+    kKeyChannelCount     = '#chn',
+    kKeySampleRate       = 'srte',
+    kKeyBitRate          = 'brte',
+    kKeyESDS             = 'esds',
+    kKeyAVCC             = 'avcc',
+    kKeyTimeUnits        = '#tim',
+    kKeyTimeScale        = 'scal',
+    kKeyNeedsNALFraming  = 'NALf',
+    kKeyIsSyncFrame      = 'sync',
+    kKeyDuration         = 'dura',
+    kKeyColorFormat      = 'colf',
+    kKeyPlatformPrivate  = 'priv',
+    kKeyDecoderComponent = 'decC',
+};
+
+enum {
+    kTypeESDS        = 'esds',
+    kTypeAVCC        = 'avcc',
+};
+
+class MetaData : public RefBase {
+public:
+    MetaData();
+    MetaData(const MetaData &from);
+
+    enum Type {
+        TYPE_NONE     = 'none',
+        TYPE_C_STRING = 'cstr',
+        TYPE_INT32    = 'in32',
+        TYPE_FLOAT    = 'floa',
+        TYPE_POINTER  = 'ptr ',
+    };
+
+    void clear();
+    bool remove(uint32_t key);
+
+    bool setCString(uint32_t key, const char *value);
+    bool setInt32(uint32_t key, int32_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 findFloat(uint32_t key, float *value);
+    bool findPointer(uint32_t key, void **value);
+
+    bool setData(uint32_t key, uint32_t type, const void *data, size_t size);
+
+    bool findData(uint32_t key, uint32_t *type,
+                  const void **data, size_t *size) const;
+
+protected:
+    virtual ~MetaData();
+
+private:
+    struct typed_data {
+        typed_data();
+        ~typed_data();
+
+        typed_data(const MetaData::typed_data &);
+        typed_data &operator=(const MetaData::typed_data &);
+
+        void clear();
+        void setData(uint32_t type, const void *data, size_t size);
+        void getData(uint32_t *type, const void **data, size_t *size) const;
+
+    private:
+        uint32_t mType;
+        size_t mSize;
+
+        union {
+            void *ext_data;
+            float reservoir;
+        } u;
+
+        bool usesReservoir() const {
+            return mSize <= sizeof(u.reservoir);
+        }
+
+        void allocateStorage(size_t size);
+        void freeStorage();
+
+        void *storage() {
+            return usesReservoir() ? &u.reservoir : u.ext_data;
+        }
+
+        const void *storage() const {
+            return usesReservoir() ? &u.reservoir : u.ext_data;
+        }
+    };
+
+    KeyedVector<uint32_t, typed_data> mItems;
+
+    // MetaData &operator=(const MetaData &);
+};
+
+}  // namespace android
+
+#endif  // META_DATA_H_
diff --git a/include/media/stagefright/MmapSource.h b/include/media/stagefright/MmapSource.h
new file mode 100644
index 0000000..a8bd57f
--- /dev/null
+++ b/include/media/stagefright/MmapSource.h
@@ -0,0 +1,52 @@
+/*
+ * 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 MMAP_SOURCE_H_
+
+#define MMAP_SOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+class MmapSource : public DataSource {
+public:
+    MmapSource(const char *filename);
+
+    // Assumes ownership of "fd".
+    MmapSource(int fd, int64_t offset, int64_t length);
+
+    virtual ~MmapSource();
+
+    status_t InitCheck() const;
+
+    virtual ssize_t read_at(off_t offset, void *data, size_t size);
+    virtual status_t getSize(off_t *size);
+
+private:
+    int mFd;
+    void *mBase;
+    size_t mSize;
+
+    MmapSource(const MmapSource &);
+    MmapSource &operator=(const MmapSource &);
+};
+
+}  // namespace android
+
+#endif  // MMAP_SOURCE_H_
+
diff --git a/include/media/stagefright/OMXClient.h b/include/media/stagefright/OMXClient.h
new file mode 100644
index 0000000..454c38b
--- /dev/null
+++ b/include/media/stagefright/OMXClient.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OMX_CLIENT_H_
+
+#define OMX_CLIENT_H_
+
+#include <media/IOMX.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class OMXObserver {
+public:
+    OMXObserver();
+    virtual ~OMXObserver();
+
+    void postMessage(const omx_message &msg);
+
+protected:
+    virtual void onOMXMessage(const omx_message &msg) = 0;
+
+private:
+    friend class OMXClient;
+
+    pthread_t mThread;
+    Mutex mLock;
+    Condition mQueueNotEmpty;
+    List<omx_message> mQueue;
+
+    void start();
+    void stop();
+
+    static void *ThreadWrapper(void *me);
+    void threadEntry();
+
+    OMXObserver(const OMXObserver &);
+    OMXObserver &operator=(const OMXObserver &);
+};
+
+class OMXClient;
+
+class OMXClientReflector : public BnOMXObserver {
+public:
+    OMXClientReflector(OMXClient *client);
+
+    virtual void on_message(const omx_message &msg);
+    void reset();
+
+private:
+    OMXClient *mClient;
+
+    OMXClientReflector(const OMXClientReflector &);
+    OMXClientReflector &operator=(const OMXClientReflector &);
+};
+
+class OMXClient {
+public:
+    friend class OMXClientReflector;
+
+    OMXClient();
+    ~OMXClient();
+
+    status_t connect();
+    void disconnect();
+
+    sp<IOMX> interface() {
+        return mOMX;
+    }
+
+    status_t registerObserver(IOMX::node_id node, OMXObserver *observer);
+    void unregisterObserver(IOMX::node_id node);
+
+    status_t fillBuffer(IOMX::node_id node, IOMX::buffer_id buffer);
+
+    status_t emptyBuffer(
+            IOMX::node_id node, IOMX::buffer_id buffer,
+            OMX_U32 range_offset, OMX_U32 range_length,
+            OMX_U32 flags, OMX_TICKS timestamp);
+
+    status_t send_command(
+            IOMX::node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
+
+private:
+    sp<IOMX> mOMX;
+
+    int mSock;
+    Mutex mLock;
+    pthread_t mThread;
+
+    KeyedVector<IOMX::node_id, OMXObserver *> mObservers;
+
+    sp<OMXClientReflector> mReflector;
+
+#if IOMX_USES_SOCKETS
+    static void *ThreadWrapper(void *me);
+    void threadEntry();
+#endif
+
+    bool onOMXMessage(const omx_message &msg);
+
+    OMXClient(const OMXClient &);
+    OMXClient &operator=(const OMXClient &);
+};
+
+}  // namespace android
+
+#endif  // OMX_CLIENT_H_
diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h
new file mode 100644
index 0000000..e76fd4c
--- /dev/null
+++ b/include/media/stagefright/OMXDecoder.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OMX_DECODER_H_
+
+#define OMX_DECODER_H_
+
+#include <binder/MemoryDealer.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+#include <OMX_Video.h>
+
+namespace android {
+
+class OMXMediaBuffer;
+
+class OMXDecoder : public MediaSource,
+                   public OMXObserver,
+                   public MediaBufferObserver {
+public:
+    static OMXDecoder *Create(
+            OMXClient *client, const sp<MetaData> &data,
+            bool createEncoder = false);
+
+    virtual ~OMXDecoder();
+
+    // Caller retains ownership of "source".
+    void setSource(MediaSource *source);
+
+    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);
+
+    void addCodecSpecificData(const void *data, size_t size);
+
+    // from OMXObserver
+    virtual void onOMXMessage(const omx_message &msg);
+
+    // from MediaBufferObserver
+    virtual void signalBufferReturned(MediaBuffer *buffer);
+
+private:
+    enum {
+        kPortIndexInput  = 0,
+        kPortIndexOutput = 1
+    };
+
+    enum PortStatus {
+        kPortStatusActive             = 0,
+        kPortStatusDisabled           = 1,
+        kPortStatusShutdown           = 2,
+        kPortStatusFlushing           = 3,
+        kPortStatusFlushingToDisabled = 4,
+        kPortStatusFlushingToShutdown = 5,
+    };
+
+    enum Quirks {
+        kWantsRawNALFrames                   = 1,
+        kDoesntReturnBuffersOnDisable        = 2,
+        kDoesntFlushOnExecutingToIdle        = 4,
+        kDoesntProperlyFlushAllPortsAtOnce   = 8,
+        kRequiresAllocateBufferOnInputPorts  = 16,
+        kRequiresAllocateBufferOnOutputPorts = 32,
+        kRequiresLoadedToIdleAfterAllocation = 64,
+        kMeasuresTimeInMilliseconds          = 128,
+    };
+
+    OMXClient *mClient;
+    sp<IOMX> mOMX;
+    IOMX::node_id mNode;
+    char *mComponentName;
+    bool mIsMP3;
+    bool mIsAVC;
+    uint32_t mQuirks;
+
+    MediaSource *mSource;
+    sp<MetaData> mOutputFormat;
+
+    Mutex mLock;
+    Condition mOutputBufferAvailable;
+
+    List<MediaBuffer *> mOutputBuffers;
+
+    struct CodecSpecificData {
+        void *data;
+        size_t size;
+    };
+
+    List<CodecSpecificData> mCodecSpecificData;
+    List<CodecSpecificData>::iterator mCodecSpecificDataIterator;
+
+    volatile OMX_STATETYPE mState;
+    OMX_U32 mPortStatusMask;
+    bool mShutdownInitiated;
+
+    typedef List<IOMX::buffer_id> BufferList;
+    Vector<BufferList> mBuffers;
+
+    KeyedVector<IOMX::buffer_id, sp<IMemory> > mBufferMap;
+    KeyedVector<IOMX::buffer_id, OMXMediaBuffer *> mMediaBufferMap;
+
+    sp<MemoryDealer> mDealer;
+
+    bool mSeeking;
+    int64_t mSeekTimeUs;
+
+    bool mStarted;
+    status_t mErrorCondition;
+    bool mReachedEndOfInput;
+
+    OMXDecoder(OMXClient *client, IOMX::node_id node,
+               const char *mime, const char *codec,
+               uint32_t quirks);
+
+    void setPortStatus(OMX_U32 port_index, PortStatus status);
+    PortStatus getPortStatus(OMX_U32 port_index) const;
+
+    void allocateBuffers(OMX_U32 port_index);
+
+    void setAMRFormat();
+    void setAACFormat();
+
+    status_t setVideoPortFormatType(
+            OMX_U32 portIndex,
+            OMX_VIDEO_CODINGTYPE compressionFormat,
+            OMX_COLOR_FORMATTYPE colorFormat);
+
+    void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
+    void setup();
+    void dumpPortDefinition(OMX_U32 port_index);
+
+    void onStart();
+    void onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
+    void onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data);
+    void onEventPortSettingsChanged(OMX_U32 port_index);
+    void onStateChanged(OMX_STATETYPE to);
+    void onEmptyBufferDone(IOMX::buffer_id buffer);
+    void onFillBufferDone(const omx_message &msg);
+
+    void onRealEmptyBufferDone(IOMX::buffer_id buffer);
+    void onRealFillBufferDone(const omx_message &msg);
+
+    void initiateShutdown();
+
+    void freeInputBuffer(IOMX::buffer_id buffer);
+    void freeOutputBuffer(IOMX::buffer_id buffer);
+    void freePortBuffers(OMX_U32 port_index);
+
+    void postStart();
+    void postEmptyBufferDone(IOMX::buffer_id buffer);
+    void postInitialFillBuffer(IOMX::buffer_id buffer);
+
+    OMXDecoder(const OMXDecoder &);
+    OMXDecoder &operator=(const OMXDecoder &);
+};
+
+}  // namespace android
+
+#endif  // OMX_DECODER_H_
diff --git a/include/media/stagefright/QComHardwareRenderer.h b/include/media/stagefright/QComHardwareRenderer.h
new file mode 100644
index 0000000..8292dd5
--- /dev/null
+++ b/include/media/stagefright/QComHardwareRenderer.h
@@ -0,0 +1,57 @@
+/*
+ * 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 QCOM_HARDWARE_RENDERER_H_
+
+#define QCOM_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapPmem;
+
+class QComHardwareRenderer : public VideoRenderer {
+public:
+    QComHardwareRenderer(
+            const sp<ISurface> &surface,
+            size_t displayWidth, size_t displayHeight,
+            size_t decodedWidth, size_t decodedHeight);
+
+    virtual ~QComHardwareRenderer();
+
+    virtual void render(
+            const void *data, size_t size, void *platformPrivate);
+
+private:
+    sp<ISurface> mISurface;
+    size_t mDisplayWidth, mDisplayHeight;
+    size_t mDecodedWidth, mDecodedHeight;
+    size_t mFrameSize;
+    sp<MemoryHeapPmem> mMemoryHeap;
+
+    bool getOffset(void *platformPrivate, size_t *offset);
+    void publishBuffers(uint32_t pmem_fd);
+
+    QComHardwareRenderer(const QComHardwareRenderer &);
+    QComHardwareRenderer &operator=(const QComHardwareRenderer &);
+};
+
+}  // namespace android
+
+#endif  // QCOM_HARDWARE_RENDERER_H_
diff --git a/include/media/stagefright/SampleTable.h b/include/media/stagefright/SampleTable.h
new file mode 100644
index 0000000..712da10
--- /dev/null
+++ b/include/media/stagefright/SampleTable.h
@@ -0,0 +1,107 @@
+/*
+ * 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 SAMPLE_TABLE_H_
+
+#define SAMPLE_TABLE_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class DataSource;
+
+class SampleTable {
+public:
+    // Caller retains ownership of "source".
+    SampleTable(DataSource *source);
+    ~SampleTable();
+
+    // type can be 'stco' or 'co64'.
+    status_t setChunkOffsetParams(
+            uint32_t type, off_t data_offset, off_t data_size);
+
+    status_t setSampleToChunkParams(off_t data_offset, off_t data_size);
+
+    // type can be 'stsz' or 'stz2'.
+    status_t setSampleSizeParams(
+            uint32_t type, off_t data_offset, off_t data_size);
+
+    status_t setTimeToSampleParams(off_t data_offset, off_t data_size);
+
+    status_t setSyncSampleParams(off_t data_offset, off_t data_size);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    uint32_t countChunkOffsets() const;
+    status_t getChunkOffset(uint32_t chunk_index, off_t *offset);
+
+    status_t getChunkForSample(
+            uint32_t sample_index, uint32_t *chunk_index,
+            uint32_t *chunk_relative_sample_index, uint32_t *desc_index);
+
+    uint32_t countSamples() const;
+    status_t getSampleSize(uint32_t sample_index, size_t *sample_size);
+
+    status_t getSampleOffsetAndSize(
+            uint32_t sample_index, off_t *offset, size_t *size);
+
+    status_t getMaxSampleSize(size_t *size);
+
+    status_t getDecodingTime(uint32_t sample_index, uint32_t *time);
+
+    enum {
+        kSyncSample_Flag = 1
+    };
+    status_t findClosestSample(
+            uint32_t req_time, uint32_t *sample_index, uint32_t flags);
+
+    status_t findClosestSyncSample(
+            uint32_t start_sample_index, uint32_t *sample_index);
+
+private:
+    DataSource *mDataSource;
+    Mutex mLock;
+
+    off_t mChunkOffsetOffset;
+    uint32_t mChunkOffsetType;
+    uint32_t mNumChunkOffsets;
+
+    off_t mSampleToChunkOffset;
+    uint32_t mNumSampleToChunkOffsets;
+
+    off_t mSampleSizeOffset;
+    uint32_t mSampleSizeFieldSize;
+    uint32_t mDefaultSampleSize;
+    uint32_t mNumSampleSizes;
+
+    uint32_t mTimeToSampleCount;
+    uint32_t *mTimeToSample;
+
+    off_t mSyncSampleOffset;
+    uint32_t mNumSyncSamples;
+
+    SampleTable(const SampleTable &);
+    SampleTable &operator=(const SampleTable &);
+};
+
+}  // namespace android
+
+#endif  // SAMPLE_TABLE_H_
diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h
new file mode 100644
index 0000000..352857a
--- /dev/null
+++ b/include/media/stagefright/ShoutcastSource.h
@@ -0,0 +1,59 @@
+/*
+ * 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 SHOUTCAST_SOURCE_H_
+
+#define SHOUTCAST_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class HTTPStream;
+class MediaBufferGroup;
+
+class ShoutcastSource : public MediaSource {
+public:
+    // Assumes ownership of "http".
+    ShoutcastSource(HTTPStream *http);
+    virtual ~ShoutcastSource();
+
+    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);
+
+private:
+    HTTPStream *mHttp;
+    size_t mMetaDataOffset;
+    size_t mBytesUntilMetaData;
+
+    MediaBufferGroup *mGroup;
+    bool mStarted;
+
+    ShoutcastSource(const ShoutcastSource &);
+    ShoutcastSource &operator= (const ShoutcastSource &);
+};
+
+}  // namespace android
+
+#endif  // SHOUTCAST_SOURCE_H_
+
diff --git a/include/media/stagefright/SoftwareRenderer.h b/include/media/stagefright/SoftwareRenderer.h
new file mode 100644
index 0000000..705b914
--- /dev/null
+++ b/include/media/stagefright/SoftwareRenderer.h
@@ -0,0 +1,55 @@
+/*
+ * 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 SOFTWARE_RENDERER_H_
+
+#define SOFTWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapBase;
+
+class SoftwareRenderer : public VideoRenderer {
+public:
+    SoftwareRenderer(
+            const sp<ISurface> &surface,
+            size_t displayWidth, size_t displayHeight,
+            size_t decodedWidth, size_t decodedHeight);
+
+    virtual ~SoftwareRenderer();
+
+    virtual void render(
+            const void *data, size_t size, void *platformPrivate);
+
+private:
+    sp<ISurface> mISurface;
+    size_t mDisplayWidth, mDisplayHeight;
+    size_t mDecodedWidth, mDecodedHeight;
+    size_t mFrameSize;
+    sp<MemoryHeapBase> mMemoryHeap;
+    int mIndex;
+
+    SoftwareRenderer(const SoftwareRenderer &);
+    SoftwareRenderer &operator=(const SoftwareRenderer &);
+};
+
+}  // namespace android
+
+#endif  // SOFTWARE_RENDERER_H_
diff --git a/include/media/stagefright/SurfaceRenderer.h b/include/media/stagefright/SurfaceRenderer.h
new file mode 100644
index 0000000..298ab50
--- /dev/null
+++ b/include/media/stagefright/SurfaceRenderer.h
@@ -0,0 +1,51 @@
+/*
+ * 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 SURFACE_RENDERER_H_
+
+#define SURFACE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class Surface;
+
+class SurfaceRenderer : public VideoRenderer {
+public:
+    SurfaceRenderer(
+            const sp<Surface> &surface,
+            size_t displayWidth, size_t displayHeight,
+            size_t decodedWidth, size_t decodedHeight);
+
+    virtual ~SurfaceRenderer();
+
+    virtual void render(
+            const void *data, size_t size, void *platformPrivate);
+
+private:
+    sp<Surface> mSurface;
+    size_t mDisplayWidth, mDisplayHeight;
+    size_t mDecodedWidth, mDecodedHeight;
+
+    SurfaceRenderer(const SurfaceRenderer &);
+    SurfaceRenderer &operator=(const SurfaceRenderer &);
+};
+
+}  // namespace android
+
+#endif  // SURFACE_RENDERER_H_
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
new file mode 100644
index 0000000..f7fa81b
--- /dev/null
+++ b/include/media/stagefright/TIHardwareRenderer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+    TIHardwareRenderer(
+            const sp<ISurface> &surface,
+            size_t displayWidth, size_t displayHeight,
+            size_t decodedWidth, size_t decodedHeight);
+
+    virtual ~TIHardwareRenderer();
+
+    virtual void render(
+            const void *data, size_t size, void *platformPrivate);
+
+private:
+    sp<ISurface> mISurface;
+    size_t mDisplayWidth, mDisplayHeight;
+    size_t mDecodedWidth, mDecodedHeight;
+    size_t mFrameSize;
+    sp<Overlay> mOverlay;
+    Vector<void *> mOverlayAddresses;
+    size_t mIndex;
+
+    TIHardwareRenderer(const TIHardwareRenderer &);
+    TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+}  // namespace android
+
+#endif  // TI_HARDWARE_RENDERER_H_
+
diff --git a/include/media/stagefright/TimeSource.h b/include/media/stagefright/TimeSource.h
new file mode 100644
index 0000000..443673d
--- /dev/null
+++ b/include/media/stagefright/TimeSource.h
@@ -0,0 +1,51 @@
+/*
+ * 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 TIME_SOURCE_H_
+
+#define TIME_SOURCE_H_
+
+#include <stdint.h>
+
+namespace android {
+
+class TimeSource {
+public:
+    TimeSource() {}
+    virtual ~TimeSource() {}
+
+    virtual int64_t getRealTimeUs() = 0;
+
+private:
+    TimeSource(const TimeSource &);
+    TimeSource &operator=(const TimeSource &);
+};
+
+class SystemTimeSource : public TimeSource {
+public:
+    SystemTimeSource();
+
+    virtual int64_t getRealTimeUs();
+
+private:
+    static int64_t GetSystemTimeUs();
+
+    int64_t mStartTimeUs;
+};
+
+}  // namespace android
+
+#endif  // TIME_SOURCE_H_
diff --git a/include/media/stagefright/TimedEventQueue.h b/include/media/stagefright/TimedEventQueue.h
new file mode 100644
index 0000000..a264421
--- /dev/null
+++ b/include/media/stagefright/TimedEventQueue.h
@@ -0,0 +1,106 @@
+/*
+ * 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 TIMED_EVENT_QUEUE_H_
+
+#define TIMED_EVENT_QUEUE_H_
+
+#include <pthread.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct TimedEventQueue {
+
+    struct Event : public RefBase {
+        Event() {}
+        virtual ~Event() {}
+
+    protected:
+        virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0;
+
+    private:
+        friend class TimedEventQueue;
+
+        Event(const Event &);
+        Event &operator=(const Event &);
+    };
+
+    TimedEventQueue();
+    ~TimedEventQueue();
+
+    // Start executing the event loop.
+    void start();
+
+    // Stop executing the event loop, if flush is false, any pending
+    // events are discarded, otherwise the queue will stop (and this call
+    // return) once all pending events have been handled.
+    void stop(bool flush = false);
+
+    // Posts an event to the front of the queue (after all events that
+    // have previously been posted to the front but before timed events).
+    void postEvent(const sp<Event> &event);
+
+    void postEventToBack(const sp<Event> &event);
+
+    // It is an error to post an event with a negative delay.
+    void postEventWithDelay(const sp<Event> &event, int64_t delay_us);
+
+    // If the event is to be posted at a time that has already passed,
+    // it will fire as soon as possible.
+    void postTimedEvent(const sp<Event> &event, int64_t realtime_us);
+
+    // Returns true iff event is currently in the queue and has been
+    // successfully cancelled. In this case the event will have been
+    // removed from the queue and won't fire.
+    bool cancelEvent(const sp<Event> &event);
+
+    static int64_t getRealTimeUs();
+
+private:
+    struct QueueItem {
+        sp<Event> event;
+        int64_t realtime_us;
+    };
+
+    struct StopEvent : public TimedEventQueue::Event {
+        virtual void fire(TimedEventQueue *queue, int64_t now_us) {
+            queue->mStopped = true;
+        }
+    };
+
+    pthread_t mThread;
+    List<QueueItem> mQueue;
+    Mutex mLock;
+    Condition mQueueNotEmptyCondition;
+    Condition mQueueHeadChangedCondition;
+
+    bool mRunning;
+    bool mStopped;
+
+    static void *ThreadWrapper(void *me);
+    void threadEntry();
+
+    TimedEventQueue(const TimedEventQueue &);
+    TimedEventQueue &operator=(const TimedEventQueue &);
+};
+
+}  // namespace android
+
+#endif  // TIMED_EVENT_QUEUE_H_
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
new file mode 100644
index 0000000..30c7f11
--- /dev/null
+++ b/include/media/stagefright/Utils.h
@@ -0,0 +1,37 @@
+/*
+ * 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 UTILS_H_
+
+#define UTILS_H_
+
+#include <stdint.h>
+
+namespace android {
+
+#define FOURCC(c1, c2, c3, c4) \
+    (c1 << 24 | c2 << 16 | c3 << 8 | c4)
+
+uint16_t U16_AT(const uint8_t *ptr);
+uint32_t U32_AT(const uint8_t *ptr);
+uint64_t U64_AT(const uint8_t *ptr);
+
+uint64_t ntoh64(uint64_t x);
+uint64_t hton64(uint64_t x);
+
+}  // namespace android
+
+#endif  // UTILS_H_
diff --git a/include/media/stagefright/VideoRenderer.h b/include/media/stagefright/VideoRenderer.h
new file mode 100644
index 0000000..f80b277
--- /dev/null
+++ b/include/media/stagefright/VideoRenderer.h
@@ -0,0 +1,41 @@
+/*
+ * 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 VIDEO_RENDERER_H_
+
+#define VIDEO_RENDERER_H_
+
+#include <sys/types.h>
+
+namespace android {
+
+class VideoRenderer {
+public:
+    virtual ~VideoRenderer() {}
+
+    virtual void render(
+            const void *data, size_t size, void *platformPrivate) = 0;
+
+protected:
+    VideoRenderer() {}
+
+    VideoRenderer(const VideoRenderer &);
+    VideoRenderer &operator=(const VideoRenderer &);
+};
+
+}  // namespace android
+
+#endif  // VIDEO_RENDERER_H_
diff --git a/include/media/stagefright/string.h b/include/media/stagefright/string.h
new file mode 100644
index 0000000..5dc7116
--- /dev/null
+++ b/include/media/stagefright/string.h
@@ -0,0 +1,54 @@
+/*
+ * 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 STRING_H_
+
+#define STRING_H_
+
+#include <utils/String8.h>
+
+namespace android {
+
+class string {
+public:
+    typedef size_t size_type;
+    static size_type npos;
+
+    string();
+    string(const char *s);
+    string(const char *s, size_t length);
+    string(const string &from, size_type start, size_type length = npos);
+
+    const char *c_str() const;
+    size_type size() const;
+
+    void clear();
+    void erase(size_type from, size_type length);
+
+    size_type find(char c) const;
+
+    bool operator<(const string &other) const;
+    bool operator==(const string &other) const;
+
+    string &operator+=(char c);
+
+private:
+    String8 mString;
+};
+
+}  // namespace android
+
+#endif  // STRING_H_
diff --git a/include/private/binder/Static.h b/include/private/binder/Static.h
new file mode 100644
index 0000000..5b0f9fc
--- /dev/null
+++ b/include/private/binder/Static.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <utils/threads.h>
+
+#include <binder/IBinder.h>
+#include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For ServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+}   // namespace android
diff --git a/include/private/utils/binder_module.h b/include/private/binder/binder_module.h
similarity index 100%
rename from include/private/utils/binder_module.h
rename to include/private/binder/binder_module.h
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 496a739..8e2db20 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -55,17 +55,18 @@
                     uint32_t    volumeLR;
                 };
                 uint32_t    sampleRate;
+                // NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
+                // 8 bit PCM data: in this case,  mCblk->frameSize is based on a sample size of
+                // 16 bit because data is converted to 16 bit before being stored in buffer
+                uint32_t    frameSize;
                 uint8_t     channels;
                 uint8_t     flowControlFlag; // underrun (out) or overrrun (in) indication
                 uint8_t     out;        // out equals 1 for AudioTrack and 0 for AudioRecord
-                uint8_t     forceReady; 
+                uint8_t     forceReady;
                 uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
                 uint16_t    waitTimeMs;      // Cumulated wait time
-                // Padding ensuring that data buffer starts on a cache line boundary (32 bytes). 
-                // See AudioFlinger::TrackBase constructor
-                int32_t     Padding[1];
-                // Cache line boundary
-                
+                // Cache line boundary (32 bytes)
+
                             audio_track_cblk_t();
                 uint32_t    stepUser(uint32_t frameCount);
                 bool        stepServer(uint32_t frameCount);
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index a85f275..523aed0 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -26,6 +26,8 @@
 #endif
 
 #include <private/pixelflinger/ggl_context.h>
+#include <hardware/copybit.h>
+#include <hardware/gralloc.h>
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
@@ -39,7 +41,7 @@
 class EGLBufferObjectManager;
 
 namespace gl {
- 
+
 struct ogles_context_t;
 struct matrixx_t;
 struct transform_t;
@@ -96,7 +98,7 @@
 
 struct vertex_t {
     enum {
-        // these constant matter for our clipping 
+        // these constant matter for our clipping
         CLIP_L          = 0x0001,   // clipping flags
         CLIP_R          = 0x0002,
         CLIP_B          = 0x0004,
@@ -106,7 +108,7 @@
 
         EYE             = 0x0040,
         RESERVED        = 0x0080,
-        
+
         USER_CLIP_0     = 0x0100,   // user clipping flags
         USER_CLIP_1     = 0x0200,
         USER_CLIP_2     = 0x0400,
@@ -121,7 +123,7 @@
         USER_CLIP_ALL   = 0x3F00,
         CLIP_ALL        = 0x3F3F,
     };
-    
+
     // the fields below are arranged to minimize d-cache usage
     // we group together, by cache-line, the fields most likely to be used
 
@@ -130,7 +132,7 @@
     vec4_t          eye;
     };
     vec4_t          clip;
-    
+
     uint32_t        flags;
     size_t          index;  // cache tag, and vertex index
     GLfixed         fog;
@@ -142,7 +144,7 @@
     vec4_t          color;
     vec4_t          texture[GGL_TEXTURE_UNIT_COUNT];
     uint32_t        reserved1[4];
-    
+
     inline void clear() {
         flags = index = locked = mru = 0;
     }
@@ -199,7 +201,7 @@
     GLenum          indicesType;
     buffer_t const* array_buffer;
     buffer_t const* element_array_buffer;
-    
+
     void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
     void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
 
@@ -410,7 +412,7 @@
     matrixx_t       matrix;
     uint32_t        flags;
     uint32_t        ops;
-    
+
     union {
         struct {
             void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
@@ -509,17 +511,17 @@
     GLint       x;
     GLint       y;
     GLsizei     w;
-    GLsizei     h; 
+    GLsizei     h;
     struct {
         GLint       x;
         GLint       y;
-    } surfaceport;  
+    } surfaceport;
     struct {
         GLint       x;
         GLint       y;
         GLsizei     w;
-        GLsizei     h; 
-    } scissor;  
+        GLsizei     h;
+    } scissor;
 };
 
 // ----------------------------------------------------------------------------
@@ -594,6 +596,14 @@
     void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
 };
 
+struct copybits_context_t {
+    // A handle to the blit engine, if it exists, else NULL.
+    copybit_device_t*       blitEngine;
+    int32_t                 minScale;
+    int32_t                 maxScale;
+    buffer_handle_t         drawSurfaceBuffer;
+};
+
 struct ogles_context_t {
     context_t               rasterizer;
     array_machine_t         arrays         __attribute__((aligned(32)));
@@ -617,6 +627,14 @@
     uint32_t                transformTextures : 1;
     EGLSurfaceManager*      surfaceManager;
     EGLBufferObjectManager* bufferObjectManager;
+
+    // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is
+    // defined, but it is always present because ogles_context_t is a public
+    // struct that is used by clients of libagl. We want the size and offsets
+    // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined.
+
+    copybits_context_t      copybits;
+
     GLenum                  error;
 
     static inline ogles_context_t* get() {
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
new file mode 100644
index 0000000..926fddb
--- /dev/null
+++ b/include/private/ui/RegionHelper.h
@@ -0,0 +1,281 @@
+/*
+ * 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 ANDROID_UI_PRIVATE_REGION_HELPER_H
+#define ANDROID_UI_PRIVATE_REGION_HELPER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+template<typename RECT>
+class region_operator
+{
+    typedef typename RECT::value_type TYPE;    
+    static const TYPE max_value = 0x7FFFFFF;
+
+public:
+    /* 
+     * Common boolean operations:
+     * value is computed as 0b101 op 0b110
+     *    other boolean operation are possible, simply compute
+     *    their corresponding value with the above formulae and use
+     *    it when instantiating a region_operator.
+     */
+    static const uint32_t LHS = 0x5;  // 0b101
+    static const uint32_t RHS = 0x6;  // 0b110
+    enum {
+        op_nand = LHS & ~RHS,
+        op_and  = LHS &  RHS,
+        op_or   = LHS |  RHS,
+        op_xor  = LHS ^  RHS
+    };
+
+    struct region {
+        RECT const* rects;
+        size_t count;
+        TYPE dx;
+        TYPE dy;
+        inline region(const region& rhs) 
+            : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
+        inline region(RECT const* r, size_t c) 
+            : rects(r), count(c), dx(), dy() { }
+        inline region(RECT const* r, size_t c, TYPE dx, TYPE dy) 
+            : rects(r), count(c), dx(dx), dy(dy) { }
+    };
+
+    class region_rasterizer {
+        friend class region_operator;
+        virtual void operator()(const RECT& rect) = 0;
+    public:
+        virtual ~region_rasterizer() { };
+    };
+    
+    inline region_operator(int op, const region& lhs, const region& rhs) 
+        : op_mask(op), spanner(lhs, rhs) 
+    {
+    }
+
+    void operator()(region_rasterizer& rasterizer) {
+        RECT current;
+        do {
+            SpannerInner spannerInner(spanner.lhs, spanner.rhs);
+            int inside = spanner.next(current.top, current.bottom);
+            spannerInner.prepare(inside);
+            do {
+                TYPE left, right;
+                int inside = spannerInner.next(current.left, current.right);
+                if ((op_mask >> inside) & 1) {
+                    if (current.left < current.right && 
+                            current.top < current.bottom) {
+                        rasterizer(current);
+                    }
+                }
+            } while(!spannerInner.isDone());            
+        } while(!spanner.isDone());
+    }
+
+private:    
+    uint32_t op_mask;
+
+    class SpannerBase
+    {
+    public:
+        enum {
+            lhs_before_rhs   = 0,
+            lhs_after_rhs    = 1,
+            lhs_coincide_rhs = 2
+        };
+
+    protected:
+        TYPE lhs_head;
+        TYPE lhs_tail;
+        TYPE rhs_head;
+        TYPE rhs_tail;
+
+        inline int next(TYPE& head, TYPE& tail,
+                bool& more_lhs, bool& more_rhs) 
+        {
+            int inside;
+            more_lhs = false;
+            more_rhs = false;
+            if (lhs_head < rhs_head) {
+                inside = lhs_before_rhs;
+                head = lhs_head;
+                if (lhs_tail <= rhs_head) {
+                    tail = lhs_tail;
+                    more_lhs = true;
+                } else {
+                    lhs_head = rhs_head;
+                    tail = rhs_head;
+                }
+            } else if (rhs_head < lhs_head) {
+                inside = lhs_after_rhs;
+                head = rhs_head;
+                if (rhs_tail <= lhs_head) {
+                    tail = rhs_tail;
+                    more_rhs = true;
+                } else {
+                    rhs_head = lhs_head;
+                    tail = lhs_head;
+                }
+            } else {
+                inside = lhs_coincide_rhs;
+                head = lhs_head;
+                if (lhs_tail <= rhs_tail) {
+                    tail = rhs_head = lhs_tail;
+                    more_lhs = true;
+                }
+                if (rhs_tail <= lhs_tail) {
+                    tail = lhs_head = rhs_tail;
+                    more_rhs = true;
+                }
+            }
+            return inside;
+        }
+    };
+
+    class Spanner : protected SpannerBase 
+    {
+        friend class region_operator;
+        region lhs;
+        region rhs;
+
+    public:
+        inline Spanner(const region& lhs, const region& rhs)
+            : lhs(lhs), rhs(rhs) 
+        {
+            SpannerBase::lhs_head = lhs.rects->top      + lhs.dy;
+            SpannerBase::lhs_tail = lhs.rects->bottom   + lhs.dy;
+            SpannerBase::rhs_head = rhs.rects->top      + rhs.dy;
+            SpannerBase::rhs_tail = rhs.rects->bottom   + rhs.dy;
+        }
+
+        inline bool isDone() const {
+            return !rhs.count && !lhs.count;
+        }
+
+        inline int next(TYPE& top, TYPE& bottom) 
+        {
+            bool more_lhs = false;
+            bool more_rhs = false;
+            int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs);
+            if (more_lhs) {
+                advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+            }
+            if (more_rhs) {
+                advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+            }
+            return inside;
+        }
+
+    private:
+        static inline 
+        void advance(region& reg, TYPE& aTop, TYPE& aBottom) {
+            // got to next span
+            size_t count = reg.count;
+            RECT const * rects = reg.rects;
+            RECT const * const end = rects + count;
+            const int top = rects->top;
+            while (rects != end && rects->top == top) {
+                rects++;
+                count--;
+            }
+            if (rects != end) {
+                aTop    = rects->top    + reg.dy;
+                aBottom = rects->bottom + reg.dy;
+            } else {
+                aTop    = max_value;
+                aBottom = max_value;
+            }
+            reg.rects = rects;
+            reg.count = count;
+        }
+    };
+
+    class SpannerInner : protected SpannerBase 
+    {
+        region lhs;
+        region rhs;
+        
+    public:
+        inline SpannerInner(const region& lhs, const region& rhs)
+            : lhs(lhs), rhs(rhs) 
+        {
+        }
+
+        inline void prepare(int inside) {
+            SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
+            SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+            SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
+            SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+            if (inside == SpannerBase::lhs_before_rhs) {
+                SpannerBase::rhs_head = max_value;
+                SpannerBase::rhs_tail = max_value;
+            } else if (inside == SpannerBase::lhs_after_rhs) {
+                SpannerBase::lhs_head = max_value;
+                SpannerBase::lhs_tail = max_value;
+            } else {
+                // use both spans
+            }
+        }
+
+        inline bool isDone() const {
+            return SpannerBase::lhs_head == max_value && 
+                   SpannerBase::rhs_head == max_value;
+        }
+
+        inline int next(TYPE& left, TYPE& right) 
+        {
+            bool more_lhs = false;
+            bool more_rhs = false;
+            int inside = SpannerBase::next(left, right, more_lhs, more_rhs);
+            if (more_lhs) {
+                advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+            }
+            if (more_rhs) {
+                advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+            }
+            return inside;
+        }
+
+    private:
+        static inline 
+        void advance(region& reg, TYPE& left, TYPE& right) {
+            if (reg.rects && reg.count) {
+                const int cur_span_top = reg.rects->top;
+                reg.rects++;
+                reg.count--;
+                if (!reg.count || reg.rects->top != cur_span_top) {
+                    left  = max_value;
+                    right = max_value;
+                } else {
+                    left  = reg.rects->left  + reg.dx;
+                    right = reg.rects->right + reg.dx;
+                }
+            }
+        }
+    };
+
+    Spanner spanner;
+};
+
+// ----------------------------------------------------------------------------
+};
+
+#endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
index 546d0ad..c9f6b5e 100644
--- a/include/private/ui/SharedState.h
+++ b/include/private/ui/SharedState.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <utils/Debug.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -32,16 +33,12 @@
 
 struct surface_info_t { // 4 longs, 16 bytes
     enum {
-        eBufferDirty    = 0x01
+        eBufferDirty    = 0x01,
+        eNeedNewBuffer  = 0x02
     };
-    uint16_t    w;
-    uint16_t    h;
-    uint16_t    stride;
-    uint16_t    bpr;
-    uint16_t    reserved;
-    uint8_t     format;
+    uint8_t     reserved[11];
     uint8_t     flags;
-    ssize_t     bits_offset;
+    status_t    status;
 };
 
 // ---------------------------------------------------------------------------
@@ -101,6 +98,8 @@
 
 struct per_client_cblk_t   // 4KB max
 {
+    per_client_cblk_t() : lock(Mutex::SHARED) { }
+
                 Mutex           lock;
                 Condition       cv;
                 layer_cblk_t    layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
@@ -110,8 +109,6 @@
         INSPECT  = 0x00000002
     };
 
-    per_client_cblk_t();
-
     // these functions are used by the clients
     status_t validate(size_t i) const;
     int32_t lock_layer(size_t i, uint32_t flags);
@@ -138,30 +135,19 @@
 
 struct surface_flinger_cblk_t   // 4KB max
 {
-    surface_flinger_cblk_t();
-    
     uint8_t         connected;
     uint8_t         reserved[3];
     uint32_t        pad[7];
- 
     display_cblk_t  displays[NUM_DISPLAY_MAX];
 };
 
 // ---------------------------------------------------------------------------
 
-template<bool> struct CTA;
-template<> struct CTA<true> { };
+COMPILE_TIME_ASSERT(sizeof(layer_cblk_t) == 128)
+COMPILE_TIME_ASSERT(sizeof(per_client_cblk_t) <= 4096)
+COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
 
-// compile-time assertions. just to avoid catastrophes.
-inline void compile_time_asserts() {
-    CTA<sizeof(layer_cblk_t) == 128> sizeof__layer_cblk_t__eq_128;
-    (void)sizeof__layer_cblk_t__eq_128; // we don't want a warning
-    CTA<sizeof(per_client_cblk_t) <= 4096> sizeof__per_client_cblk_t__le_4096;
-    (void)sizeof__per_client_cblk_t__le_4096;  // we don't want a warning
-    CTA<sizeof(surface_flinger_cblk_t) <= 4096> sizeof__surface_flinger_cblk_t__le_4096;
-    (void)sizeof__surface_flinger_cblk_t__le_4096;  // we don't want a warning
-}
-
+// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_UI_SHARED_STATE_H
diff --git a/include/private/ui/SurfaceBuffer.h b/include/private/ui/SurfaceBuffer.h
new file mode 100644
index 0000000..bf68406
--- /dev/null
+++ b/include/private/ui/SurfaceBuffer.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 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 ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+#define ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+
+#include <private/ui/android_natives_priv.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class BufferMapper;
+class Parcel;
+class Rect;
+class Surface;
+class SurfaceBuffer;
+
+// ---------------------------------------------------------------------------
+
+class SurfaceBuffer 
+    : public EGLNativeBase<
+        android_native_buffer_t, 
+        SurfaceBuffer, 
+        LightRefBase<SurfaceBuffer> >
+{
+public:
+    status_t lock(uint32_t usage, void** vaddr);
+    status_t lock(uint32_t usage, const Rect& rect, void** vaddr);
+    status_t unlock();
+
+protected:
+            SurfaceBuffer();
+            SurfaceBuffer(const Parcel& reply);
+    virtual ~SurfaceBuffer();
+    bool mOwner;
+
+    inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
+    inline BufferMapper& getBufferMapper() { return mBufferMapper; }
+    
+private:
+    friend class Surface;
+    friend class BpSurface;
+    friend class BnSurface;
+    friend class LightRefBase<SurfaceBuffer>;    
+
+    SurfaceBuffer& operator = (const SurfaceBuffer& rhs);
+    const SurfaceBuffer& operator = (const SurfaceBuffer& rhs) const;
+
+    static status_t writeToParcel(Parcel* reply, 
+            android_native_buffer_t const* buffer);
+    
+    BufferMapper& mBufferMapper;
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+
diff --git a/include/private/ui/SurfaceFlingerSynchro.h b/include/private/ui/SurfaceFlingerSynchro.h
index ff91b61..7386d33 100644
--- a/include/private/ui/SurfaceFlingerSynchro.h
+++ b/include/private/ui/SurfaceFlingerSynchro.h
@@ -21,7 +21,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <utils/Errors.h>
-#include <utils/threads.h>
 #include <ui/ISurfaceComposer.h>
 
 namespace android {
@@ -31,7 +30,6 @@
 class SurfaceFlingerSynchro
 {
 public:
-
                 // client constructor
                 SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
                 ~SurfaceFlingerSynchro();
@@ -40,34 +38,8 @@
     status_t    signal();
     
 private:
-    class Barrier {
-    public:
-        Barrier();
-        ~Barrier();
-        void open();
-        void close();
-        void waitAndClose();
-        status_t waitAndClose(nsecs_t timeout);
-    private:
-        enum { OPENED, CLOSED };
-        mutable     Mutex       lock;
-        mutable     Condition   cv;
-        volatile    int         state;
-    };
-
     friend class SurfaceFlinger;
-
-                // server constructor
-                SurfaceFlingerSynchro();
-                
-    void        open();
-    
-                // wait until there is some work to do
-    status_t    wait();
-    status_t    wait(nsecs_t timeout);
-    
     sp<ISurfaceComposer> mSurfaceComposer;
-    Barrier              mBarrier;
 };
 
 }; // namespace android
diff --git a/include/private/ui/android_natives_priv.h b/include/private/ui/android_natives_priv.h
new file mode 100644
index 0000000..ee843e9
--- /dev/null
+++ b/include/private/ui/android_natives_priv.h
@@ -0,0 +1,62 @@
+/*
+ * 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 ANDROID_ANDROID_NATIVES_PRIV_H
+#define ANDROID_ANDROID_NATIVES_PRIV_H
+
+#include <ui/egl/android_natives.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+struct android_native_buffer_t
+{
+#ifdef __cplusplus
+    android_native_buffer_t() { 
+        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+        common.version = sizeof(android_native_buffer_t);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+#endif
+
+    struct android_native_base_t common;
+
+    int width;
+    int height;
+    int stride;
+    int format;
+    int usage;
+    
+    void* reserved[2];
+
+    buffer_handle_t handle;
+
+    void* reserved_proc[8];
+};
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif /* ANDROID_ANDROID_NATIVES_PRIV_H */
diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h
index f1439b7..d95ae0d 100644
--- a/include/private/utils/Static.h
+++ b/include/private/utils/Static.h
@@ -20,14 +20,6 @@
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 
-#ifndef LIBUTILS_NATIVE
-#include <utils/IBinder.h>
-#include <utils/IMemory.h>
-#include <utils/ProcessState.h>
-#include <utils/IPermissionController.h>
-#include <utils/IServiceManager.h>
-#endif
-
 namespace android {
 // For TextStream.cpp
 extern Vector<int32_t> gTextBuffers;
@@ -40,19 +32,4 @@
 extern void initialize_string16();
 extern void terminate_string16();
 
-
-
-#ifndef LIBUTILS_NATIVE
-
-// For ProcessState.cpp
-extern Mutex gProcessMutex;
-extern sp<ProcessState> gProcess;
-
-// For ServiceManager.cpp
-extern Mutex gDefaultServiceManagerLock;
-extern sp<IServiceManager> gDefaultServiceManager;
-extern sp<IPermissionController> gPermissionController;
-
-#endif
-
 }   // namespace android
diff --git a/include/private/utils/futex_synchro.h b/include/private/utils/futex_synchro.h
deleted file mode 100644
index ac2ab19..0000000
--- a/include/private/utils/futex_synchro.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 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 _FUTEX_SYNCHRO_H
-#define _FUTEX_SYNCHRO_H
-
-#ifndef HAVE_FUTEX
-#error "HAVE_FUTEX not defined"
-#endif
-
-#define FUTEX_WAIT_INFINITE (0)
-
-typedef struct futex_mutex_t futex_mutex_t;
-
-struct futex_mutex_t 
-{
-    volatile int value;
-};
-
-typedef struct futex_cond_t futex_cond_t;
-
-struct futex_cond_t 
-{
-    volatile int value;
-};
-
-
-#if __cplusplus
-extern "C" {
-#endif
-
-void futex_mutex_init(futex_mutex_t *m);
-int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
-void futex_mutex_unlock(futex_mutex_t *m);
-int futex_mutex_trylock(futex_mutex_t *m);
-
-void futex_cond_init(futex_cond_t *c);
-int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
-void futex_cond_signal(futex_cond_t *c);
-void futex_cond_broadcast(futex_cond_t *c);
-
-#if __cplusplus
-} // extern "C"
-#endif
-
-#endif // _FUTEX_SYNCHRO_H
-
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 8020da2..9d442c3 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -2,31 +2,34 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	AudioTrack.cpp \
-	IAudioFlinger.cpp \
-	IAudioFlingerClient.cpp \
-	IAudioTrack.cpp \
-	IAudioRecord.cpp \
-	AudioRecord.cpp \
-	AudioSystem.cpp \
-	mediaplayer.cpp \
-	IMediaPlayerService.cpp \
-	IMediaPlayerClient.cpp \
-	IMediaPlayer.cpp \
-	IMediaRecorder.cpp \
-	mediarecorder.cpp \
-	IMediaMetadataRetriever.cpp \
-	mediametadataretriever.cpp \
-	ToneGenerator.cpp \
-	JetPlayer.cpp
+    AudioTrack.cpp \
+    IAudioFlinger.cpp \
+    IAudioFlingerClient.cpp \
+    IAudioTrack.cpp \
+    IAudioRecord.cpp \
+    AudioRecord.cpp \
+    AudioSystem.cpp \
+    mediaplayer.cpp \
+    IMediaPlayerService.cpp \
+    IMediaPlayerClient.cpp \
+    IMediaPlayer.cpp \
+    IMediaRecorder.cpp \
+    Metadata.cpp \
+    mediarecorder.cpp \
+    IMediaMetadataRetriever.cpp \
+    mediametadataretriever.cpp \
+    ToneGenerator.cpp \
+    JetPlayer.cpp \
+    IOMX.cpp \
+ 	IAudioPolicyService.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libui libcutils libutils libsonivox
+	libui libcutils libutils libbinder libsonivox
 
 LOCAL_MODULE:= libmedia
 
 ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
+LOCAL_LDLIBS += -ldl -lpthread
 endif
 
 ifneq ($(TARGET_SIMULATOR),true)
@@ -34,6 +37,7 @@
 endif
 
 LOCAL_C_INCLUDES := \
-	$(call include-path-for, graphics corecg)
+	$(call include-path-for, graphics corecg) \
+        $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index e56efbb..5e35564 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -28,12 +28,13 @@
 
 #include <media/AudioSystem.h>
 #include <media/AudioRecord.h>
+#include <media/mediarecorder.h>
 
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
 #include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/MemoryDealer.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
 #include <utils/Timers.h>
 #include <cutils/atomic.h>
 
@@ -45,7 +46,7 @@
 // ---------------------------------------------------------------------------
 
 AudioRecord::AudioRecord()
-    : mStatus(NO_INIT)
+    : mStatus(NO_INIT), mInput(0)
 {
 }
 
@@ -53,15 +54,15 @@
         int inputSource,
         uint32_t sampleRate,
         int format,
-        int channelCount,
+        uint32_t channels,
         int frameCount,
         uint32_t flags,
         callback_t cbf,
         void* user,
         int notificationFrames)
-    : mStatus(NO_INIT)
+    : mStatus(NO_INIT), mInput(0)
 {
-    mStatus = set(inputSource, sampleRate, format, channelCount,
+    mStatus = set(inputSource, sampleRate, format, channels,
             frameCount, flags, cbf, user, notificationFrames);
 }
 
@@ -78,6 +79,7 @@
         }
         mAudioRecord.clear();
         IPCThreadState::self()->flushCommands();
+        AudioSystem::releaseInput(mInput);
     }
 }
 
@@ -85,7 +87,7 @@
         int inputSource,
         uint32_t sampleRate,
         int format,
-        int channelCount,
+        uint32_t channels,
         int frameCount,
         uint32_t flags,
         callback_t cbf,
@@ -94,7 +96,7 @@
         bool threadCanCallJava)
 {
 
-    LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount);
+    LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
     if (mAudioRecord != 0) {
         return INVALID_OPERATION;
     }
@@ -104,8 +106,8 @@
         return NO_INIT;
     }
 
-    if (inputSource == DEFAULT_INPUT) {
-        inputSource = MIC_INPUT;
+    if (inputSource == AUDIO_SOURCE_DEFAULT) {
+        inputSource = AUDIO_SOURCE_MIC;
     }
 
     if (sampleRate == 0) {
@@ -115,15 +117,21 @@
     if (format == 0) {
         format = AudioSystem::PCM_16_BIT;
     }
-    if (channelCount == 0) {
-        channelCount = 1;
-    }
-
     // validate parameters
-    if (format != AudioSystem::PCM_16_BIT) {
+    if (!AudioSystem::isValidFormat(format)) {
+        LOGE("Invalid format");
         return BAD_VALUE;
     }
-    if (channelCount != 1 && channelCount != 2) {
+
+    if (!AudioSystem::isInputChannel(channels)) {
+        return BAD_VALUE;
+    }
+    int channelCount = AudioSystem::popCount(channels);
+
+    mInput = AudioSystem::getInput(inputSource,
+                                    sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);
+    if (mInput == 0) {
+        LOGE("Could not get audio output for stream type %d", inputSource);
         return BAD_VALUE;
     }
 
@@ -132,14 +140,22 @@
     if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
             != NO_ERROR) {
         LOGE("AudioSystem could not query the input buffer size.");
-        return NO_INIT;    
+        return NO_INIT;
     }
+
     if (inputBuffSizeInBytes == 0) {
         LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
             sampleRate, channelCount, format);
         return BAD_VALUE;
     }
+
     int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
+    if (AudioSystem::isLinearPCM(format)) {
+        frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? sizeof(int16_t) : sizeof(int8_t));
+    } else {
+        frameSizeInBytes = sizeof(int8_t);
+    }
+
 
     // We use 2* size of input buffer for ping pong use of record buffer.
     int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
@@ -157,11 +173,11 @@
 
     // open record channel
     status_t status;
-    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), inputSource,
+    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
                                                        sampleRate, format,
                                                        channelCount,
                                                        frameCount,
-                                                       ((uint16_t)flags) << 16, 
+                                                       ((uint16_t)flags) << 16,
                                                        &status);
     if (record == 0) {
         LOGE("AudioFlinger could not create record track, status: %d", status);
@@ -188,7 +204,7 @@
     mFormat = format;
     // Update buffer size in case it has been limited by AudioFlinger during track creation
     mFrameCount = mCblk->frameCount;
-    mChannelCount = channelCount;
+    mChannelCount = (uint8_t)channelCount;
     mActive = 0;
     mCbf = cbf;
     mNotificationFrames = notificationFrames;
@@ -234,7 +250,11 @@
 
 int AudioRecord::frameSize() const
 {
-    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+    if (AudioSystem::isLinearPCM(mFormat)) {
+        return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+    } else {
+        return sizeof(uint8_t);
+    }
 }
 
 int AudioRecord::inputSource() const
@@ -262,15 +282,18 @@
      }
 
     if (android_atomic_or(1, &mActive) == 0) {
-        mNewPosition = mCblk->user + mUpdatePeriod;
-        mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
-        mCblk->waitTimeMs = 0;
-        if (t != 0) {
-           t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
-        } else {
-            setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+        ret = AudioSystem::startInput(mInput);
+        if (ret == NO_ERROR) {
+            mNewPosition = mCblk->user + mUpdatePeriod;
+            mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+            mCblk->waitTimeMs = 0;
+            if (t != 0) {
+               t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+            } else {
+                setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+            }
+            ret = mAudioRecord->start();
         }
-        ret = mAudioRecord->start();
     }
 
     if (t != 0) {
@@ -301,6 +324,7 @@
         } else {
             setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
         }
+        AudioSystem::stopInput(mInput);
     }
 
     if (t != 0) {
@@ -421,7 +445,7 @@
         "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
 
     cblk->waitTimeMs = 0;
-    
+
     if (framesReq > framesReady) {
         framesReq = framesReady;
     }
@@ -437,7 +461,7 @@
     audioBuffer->channelCount= mChannelCount;
     audioBuffer->format      = mFormat;
     audioBuffer->frameCount  = framesReq;
-    audioBuffer->size        = framesReq*mChannelCount*sizeof(int16_t);
+    audioBuffer->size        = framesReq*cblk->frameSize;
     audioBuffer->raw         = (int8_t*)cblk->buffer(u);
     active = mActive;
     return active ? status_t(NO_ERROR) : status_t(STOPPED);
@@ -468,7 +492,7 @@
 
     do {
 
-        audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
+        audioBuffer.frameCount = userSize/frameSize();
 
         // Calling obtainBuffer() with a negative wait count causes
         // an (almost) infinite wait time.
@@ -519,8 +543,8 @@
 
     do {
         audioBuffer.frameCount = frames;
-        // Calling obtainBuffer() with a wait count of 1 
-        // limits wait time to WAIT_PERIOD_MS. This prevents from being 
+        // Calling obtainBuffer() with a wait count of 1
+        // limits wait time to WAIT_PERIOD_MS. This prevents from being
         // stuck here not being able to handle timed events (position, markers).
         status_t err = obtainBuffer(&audioBuffer, 1);
         if (err < NO_ERROR) {
@@ -548,14 +572,14 @@
         if (readSize > reqSize) readSize = reqSize;
 
         audioBuffer.size = readSize;
-        audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
+        audioBuffer.frameCount = readSize/frameSize();
         frames -= audioBuffer.frameCount;
 
         releaseBuffer(&audioBuffer);
 
     } while (frames);
 
-    
+
     // Manage overrun callback
     if (mActive && (mCblk->framesAvailable_l() == 0)) {
         LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index a21a7a4..1fc1024 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -18,10 +18,20 @@
 //#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
 #include <media/AudioSystem.h>
+#include <media/IAudioPolicyService.h>
 #include <math.h>
 
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
 namespace android {
 
 // client singleton for AudioFlinger binder interface
@@ -30,10 +40,9 @@
 sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 // Cached values
-int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
-int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
-uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
-bool AudioSystem::gA2dpEnabled;
+DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
+DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
+
 // Cached values for recording queries
 uint32_t AudioSystem::gPrevInSamplingRate = 16000;
 int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT;
@@ -65,44 +74,12 @@
         binder->linkToDeath(gAudioFlingerClient);
         gAudioFlinger = interface_cast<IAudioFlinger>(binder);
         gAudioFlinger->registerClient(gAudioFlingerClient);
-        // Cache frequently accessed parameters 
-        for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
-            gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output);
-            gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output);
-            gOutLatency[output] = gAudioFlinger->latency(output);
-        }
-        gA2dpEnabled = gAudioFlinger->isA2dpEnabled();
     }
     LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
+
     return gAudioFlinger;
 }
 
-// routing helper functions
-status_t AudioSystem::speakerphone(bool state) {
-    uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE;
-    return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
-}
-
-status_t AudioSystem::isSpeakerphoneOn(bool* state) {
-    uint32_t routes = 0;
-    status_t s = getRouting(MODE_IN_CALL, &routes);
-    *state = !!(routes & ROUTE_SPEAKER);
-    return s;
-}
-
-status_t AudioSystem::bluetoothSco(bool state) {
-    uint32_t mask = ROUTE_BLUETOOTH_SCO;
-    uint32_t routes = state ? mask : ROUTE_EARPIECE;
-    return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
-}
-
-status_t AudioSystem::isBluetoothScoOn(bool* state) {
-    uint32_t routes = 0;
-    status_t s = getRouting(MODE_IN_CALL, &routes);
-    *state = !!(routes & ROUTE_BLUETOOTH_SCO);
-    return s;
-}
-
 status_t AudioSystem::muteMicrophone(bool state) {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
@@ -148,12 +125,12 @@
     return NO_ERROR;
 }
 
-status_t AudioSystem::setStreamVolume(int stream, float value)
+status_t AudioSystem::setStreamVolume(int stream, float value, void *output)
 {
     if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-    af->setStreamVolume(stream, value);
+    af->setStreamVolume(stream, value, output);
     return NO_ERROR;
 }
 
@@ -166,12 +143,12 @@
     return NO_ERROR;
 }
 
-status_t AudioSystem::getStreamVolume(int stream, float* volume)
+status_t AudioSystem::getStreamVolume(int stream, float* volume, void *output)
 {
     if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-    *volume = af->streamVolume(stream);
+    *volume = af->streamVolume(stream, output);
     return NO_ERROR;
 }
 
@@ -192,29 +169,6 @@
     return af->setMode(mode);
 }
 
-status_t AudioSystem::getMode(int* mode)
-{
-    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-    if (af == 0) return PERMISSION_DENIED;
-    *mode = af->getMode();
-    return NO_ERROR;
-}
-
-status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask)
-{
-    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-    if (af == 0) return PERMISSION_DENIED;
-    return af->setRouting(mode, routes, mask);
-}
-
-status_t AudioSystem::getRouting(int mode, uint32_t* routes)
-{
-    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-    if (af == 0) return PERMISSION_DENIED;
-    uint32_t r = af->getRouting(mode);
-    *routes = r;
-    return NO_ERROR;
-}
 
 status_t AudioSystem::isMusicActive(bool* state) {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -223,12 +177,20 @@
     return NO_ERROR;
 }
 
-// Temporary interface, do not use
-// TODO: Replace with a more generic key:value get/set mechanism
-status_t AudioSystem::setParameter(const char* key, const char* value) {
+
+status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-    return af->setParameter(key, value);
+    return af->setParameters(ioHandle, keyValuePairs);
+}
+
+String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    String8 result = String8("");
+    if (af == 0) return result;
+
+    result = af->getParameters(ioHandle, keys);
+    return result;
 }
 
 // convert volume steps to natural log scale
@@ -257,55 +219,108 @@
 
 status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
 {
-    int output = getOutput(streamType);
-    
-    if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+    OutputDescriptor *outputDesc;
+    audio_io_handle_t output;
 
-    // gOutSamplingRate[] is updated by getOutput() which calls get_audio_flinger()
-    LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]);
-    
-    *samplingRate = gOutSamplingRate[output];
-    
+    if (streamType == DEFAULT) {
+        streamType = MUSIC;
+    }
+
+    output = getOutput((stream_type)streamType);
+    if (output == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    gLock.lock();
+    outputDesc = AudioSystem::gOutputs.valueFor(output);
+    if (outputDesc == 0) {
+        LOGV("getOutputSamplingRate() no output descriptor for output %p in gOutputs", output);
+        gLock.unlock();
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        *samplingRate = af->sampleRate(output);
+    } else {
+        LOGV("getOutputSamplingRate() reading from output desc");
+        *samplingRate = outputDesc->samplingRate;
+        gLock.unlock();
+    }
+
+    LOGV("getOutputSamplingRate() streamType %d, output %p, sampling rate %d", streamType, output, *samplingRate);
+
     return NO_ERROR;
 }
 
 status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType)
 {
-    int output = getOutput(streamType);
+    OutputDescriptor *outputDesc;
+    audio_io_handle_t output;
 
-    if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+    if (streamType == DEFAULT) {
+        streamType = MUSIC;
+    }
 
-    // gOutFrameCount[] is updated by getOutput() which calls get_audio_flinger()
-    LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]);
+    output = getOutput((stream_type)streamType);
+    if (output == 0) {
+        return PERMISSION_DENIED;
+    }
 
-    *frameCount = gOutFrameCount[output];
-    
+    gLock.lock();
+    outputDesc = AudioSystem::gOutputs.valueFor(output);
+    if (outputDesc == 0) {
+        gLock.unlock();
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        *frameCount = af->frameCount(output);
+    } else {
+        *frameCount = outputDesc->frameCount;
+        gLock.unlock();
+    }
+
+    LOGV("getOutputFrameCount() streamType %d, output %p, frameCount %d", streamType, output, *frameCount);
+
     return NO_ERROR;
 }
 
 status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType)
 {
-    int output = getOutput(streamType);
+    OutputDescriptor *outputDesc;
+    audio_io_handle_t output;
 
-    if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+    if (streamType == DEFAULT) {
+        streamType = MUSIC;
+    }
 
-    // gOutLatency[] is updated by getOutput() which calls get_audio_flinger()
-    LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]);
+    output = getOutput((stream_type)streamType);
+    if (output == 0) {
+        return PERMISSION_DENIED;
+    }
 
-    *latency = gOutLatency[output];
-    
+    gLock.lock();
+    outputDesc = AudioSystem::gOutputs.valueFor(output);
+    if (outputDesc == 0) {
+        gLock.unlock();
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        *latency = af->latency(output);
+    } else {
+        *latency = outputDesc->latency;
+        gLock.unlock();
+    }
+
+    LOGV("getOutputLatency() streamType %d, output %p, latency %d", streamType, output, *latency);
+
     return NO_ERROR;
 }
 
-status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount, 
+status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
     size_t* buffSize)
 {
     // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
-    if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) 
+    if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
         || (channelCount != gPrevInChannelCount)) {
         // save the request params
         gPrevInSamplingRate = sampleRate;
-        gPrevInFormat = format; 
+        gPrevInFormat = format;
         gPrevInChannelCount = channelCount;
 
         gInBuffSize = 0;
@@ -314,24 +329,18 @@
             return PERMISSION_DENIED;
         }
         gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount);
-    } 
+    }
     *buffSize = gInBuffSize;
-    
+
     return NO_ERROR;
 }
 
 // ---------------------------------------------------------------------------
 
-void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {   
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
     Mutex::Autolock _l(AudioSystem::gLock);
-    AudioSystem::gAudioFlinger.clear();
 
-    for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
-        gOutFrameCount[output] = 0;
-        gOutSamplingRate[output] = 0;
-        gOutLatency[output] = 0;
-    }
-    AudioSystem::gInBuffSize = 0;
+    AudioSystem::gAudioFlinger.clear();
 
     if (gAudioErrorCallback) {
         gAudioErrorCallback(DEAD_OBJECT);
@@ -339,33 +348,83 @@
     LOGW("AudioFlinger server died!");
 }
 
-void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) {
-    gA2dpEnabled = enabled;        
-    LOGV("AudioFlinger A2DP enabled status changed! %d", enabled);
+void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, void *param1, void *param2) {
+    LOGV("ioConfigChanged() event %d", event);
+    audio_io_handle_t ioHandle = (audio_io_handle_t)param1;
+    OutputDescriptor *desc;
+    uint32_t stream;
+
+    if (param1 == 0) return;
+
+    Mutex::Autolock _l(AudioSystem::gLock);
+
+    switch (event) {
+    case STREAM_CONFIG_CHANGED:
+        if (param2 == 0) break;
+        stream = *(uint32_t *)param2;
+        LOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %p", stream, ioHandle);
+        if (gStreamOutputMap.indexOfKey(stream) >= 0) {
+            gStreamOutputMap.replaceValueFor(stream, ioHandle);
+        }
+        break;
+    case OUTPUT_OPENED: {
+        if (gOutputs.indexOfKey(ioHandle) >= 0) {
+            LOGV("ioConfigChanged() opening already existing output! %p", ioHandle);
+            break;
+        }
+        if (param2 == 0) break;
+        desc = (OutputDescriptor *)param2;
+
+        OutputDescriptor *outputDesc =  new OutputDescriptor(*desc);
+        gOutputs.add(ioHandle, outputDesc);
+        LOGV("ioConfigChanged() new output samplingRate %d, format %d channels %d frameCount %d latency %d",
+                outputDesc->samplingRate, outputDesc->format, outputDesc->channels, outputDesc->frameCount, outputDesc->latency);
+        } break;
+    case OUTPUT_CLOSED: {
+        if (gOutputs.indexOfKey(ioHandle) < 0) {
+            LOGW("ioConfigChanged() closing unknow output! %p", ioHandle);
+            break;
+        }
+        LOGV("ioConfigChanged() output %p closed", ioHandle);
+
+        gOutputs.removeItem(ioHandle);
+        for (int i = gStreamOutputMap.size() - 1; i >= 0 ; i--) {
+            if (gStreamOutputMap.valueAt(i) == ioHandle) {
+                gStreamOutputMap.removeItemsAt(i);
+            }
+        }
+        } break;
+
+    case OUTPUT_CONFIG_CHANGED: {
+        int index = gOutputs.indexOfKey(ioHandle);
+        if (index < 0) {
+            LOGW("ioConfigChanged() modifying unknow output! %p", ioHandle);
+            break;
+        }
+        if (param2 == 0) break;
+        desc = (OutputDescriptor *)param2;
+
+        LOGV("ioConfigChanged() new config for output %p samplingRate %d, format %d channels %d frameCount %d latency %d",
+                ioHandle, desc->samplingRate, desc->format,
+                desc->channels, desc->frameCount, desc->latency);
+        OutputDescriptor *outputDesc = gOutputs.valueAt(index);
+        delete outputDesc;
+        outputDesc =  new OutputDescriptor(*desc);
+        gOutputs.replaceValueFor(ioHandle, outputDesc);
+    } break;
+    case INPUT_OPENED:
+    case INPUT_CLOSED:
+    case INPUT_CONFIG_CHANGED:
+        break;
+
+    }
 }
 
 void AudioSystem::setErrorCallback(audio_error_callback cb) {
-    Mutex::Autolock _l(AudioSystem::gLock);
+    Mutex::Autolock _l(gLock);
     gAudioErrorCallback = cb;
 }
 
-int AudioSystem::getOutput(int streamType)
-{   
-    // make sure that gA2dpEnabled is valid by calling get_audio_flinger() which in turn 
-    // will call gAudioFlinger->isA2dpEnabled()
-    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-    if (af == 0) return NUM_AUDIO_OUTPUT_TYPES;
-
-    if (streamType == DEFAULT) {
-        streamType = MUSIC;
-    }
-    if (gA2dpEnabled && routedToA2dpOutput(streamType)) {
-        return AUDIO_OUTPUT_A2DP;
-    } else {
-        return AUDIO_OUTPUT_HARDWARE;
-    }
-}
-
 bool AudioSystem::routedToA2dpOutput(int streamType) {
     switch(streamType) {
     case MUSIC:
@@ -379,6 +438,451 @@
 }
 
 
+// client singleton for AudioPolicyService binder interface
+sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
+sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient;
+
+
+// establish binder interface to AudioFlinger service
+const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service()
+{
+    gLock.lock();
+    if (gAudioPolicyService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.audio_policy"));
+            if (binder != 0)
+                break;
+            LOGW("AudioPolicyService not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while(true);
+        if (gAudioPolicyServiceClient == NULL) {
+            gAudioPolicyServiceClient = new AudioPolicyServiceClient();
+        }
+        binder->linkToDeath(gAudioPolicyServiceClient);
+        gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
+        gLock.unlock();
+    } else {
+        gLock.unlock();
+    }
+    return gAudioPolicyService;
+}
+
+status_t AudioSystem::setDeviceConnectionState(audio_devices device,
+                                                  device_connection_state state,
+                                                  const char *device_address)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    return aps->setDeviceConnectionState(device, state, device_address);
+}
+
+AudioSystem::device_connection_state AudioSystem::getDeviceConnectionState(audio_devices device,
+                                                  const char *device_address)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return DEVICE_STATE_UNAVAILABLE;
+
+    return aps->getDeviceConnectionState(device, device_address);
+}
+
+status_t AudioSystem::setPhoneState(int state)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    return aps->setPhoneState(state);
+}
+
+status_t AudioSystem::setRingerMode(uint32_t mode, uint32_t mask)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setRingerMode(mode, mask);
+}
+
+status_t AudioSystem::setForceUse(force_use usage, forced_config config)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setForceUse(usage, config);
+}
+
+AudioSystem::forced_config AudioSystem::getForceUse(force_use usage)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return FORCE_NONE;
+    return aps->getForceUse(usage);
+}
+
+
+audio_io_handle_t AudioSystem::getOutput(stream_type stream,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channels,
+                                    output_flags flags)
+{
+    audio_io_handle_t output = NULL;
+    if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
+        Mutex::Autolock _l(gLock);
+        output = AudioSystem::gStreamOutputMap.valueFor(stream);
+        LOGV_IF((output != NULL), "getOutput() read %p from cache for stream %d", output, stream);
+    }
+    if (output == NULL) {
+        const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+        if (aps == 0) return NULL;
+        output = aps->getOutput(stream, samplingRate, format, channels, flags);
+        if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
+            Mutex::Autolock _l(gLock);
+            AudioSystem::gStreamOutputMap.add(stream, output);
+        }
+    }
+    return output;
+}
+
+status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->startOutput(output, stream);
+}
+
+status_t AudioSystem::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->stopOutput(output, stream);
+}
+
+void AudioSystem::releaseOutput(audio_io_handle_t output)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return;
+    aps->releaseOutput(output);
+}
+
+audio_io_handle_t AudioSystem::getInput(int inputSource,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channels,
+                                    audio_in_acoustics acoustics)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return NULL;
+    return aps->getInput(inputSource, samplingRate, format, channels, acoustics);
+}
+
+status_t AudioSystem::startInput(audio_io_handle_t input)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->startInput(input);
+}
+
+status_t AudioSystem::stopInput(audio_io_handle_t input)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->stopInput(input);
+}
+
+void AudioSystem::releaseInput(audio_io_handle_t input)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return;
+    aps->releaseInput(input);
+}
+
+status_t AudioSystem::initStreamVolume(stream_type stream,
+                                    int indexMin,
+                                    int indexMax)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->initStreamVolume(stream, indexMin, indexMax);
+}
+
+status_t AudioSystem::setStreamVolumeIndex(stream_type stream, int index)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setStreamVolumeIndex(stream, index);
+}
+
+status_t AudioSystem::getStreamVolumeIndex(stream_type stream, int *index)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getStreamVolumeIndex(stream, index);
+}
+
+// ---------------------------------------------------------------------------
+
+void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock _l(AudioSystem::gLock);
+    AudioSystem::gAudioPolicyService.clear();
+
+    LOGW("AudioPolicyService server died!");
+}
+
+// ---------------------------------------------------------------------------
+
+
+// use emulated popcount optimization
+// http://www.df.lth.se/~john_e/gems/gem002d.html
+uint32_t AudioSystem::popCount(uint32_t u)
+{
+    u = ((u&0x55555555) + ((u>>1)&0x55555555));
+    u = ((u&0x33333333) + ((u>>2)&0x33333333));
+    u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
+    u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
+    u = ( u&0x0000ffff) + (u>>16);
+    return u;
+}
+
+bool AudioSystem::isOutputDevice(audio_devices device)
+{
+    if ((popCount(device) == 1 ) &&
+        ((device & ~AudioSystem::DEVICE_OUT_ALL) == 0)) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool AudioSystem::isInputDevice(audio_devices device)
+{
+    if ((popCount(device) == 1 ) &&
+        ((device & ~AudioSystem::DEVICE_IN_ALL) == 0)) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool AudioSystem::isA2dpDevice(audio_devices device)
+{
+    if ((popCount(device) == 1 ) &&
+        (device & (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
+                   AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                   AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER))) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool AudioSystem::isBluetoothScoDevice(audio_devices device)
+{
+    if ((popCount(device) == 1 ) &&
+        (device & (AudioSystem::DEVICE_OUT_BLUETOOTH_SCO |
+                   AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+                   AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT))) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool AudioSystem::isLowVisibility(stream_type stream)
+{
+    if (stream == AudioSystem::SYSTEM || stream == AudioSystem::NOTIFICATION) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool AudioSystem::isInputChannel(uint32_t channel)
+{
+    if ((channel & ~AudioSystem::CHANNEL_IN_ALL) == 0) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool AudioSystem::isOutputChannel(uint32_t channel)
+{
+    if ((channel & ~AudioSystem::CHANNEL_OUT_ALL) == 0) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool AudioSystem::isValidFormat(uint32_t format)
+{
+    switch (format & MAIN_FORMAT_MASK) {
+    case         PCM:
+    case         MP3:
+    case         AMR_NB:
+    case         AMR_WB:
+    case         AAC:
+    case         HE_AAC_V1:
+    case         HE_AAC_V2:
+    case         VORBIS:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool AudioSystem::isLinearPCM(uint32_t format)
+{
+    switch (format) {
+    case         PCM_16_BIT:
+    case         PCM_8_BIT:
+        return true;
+    default:
+        return false;
+    }
+}
+
+//------------------------- AudioParameter class implementation ---------------
+
+const char *AudioParameter::keyRouting = "routing";
+const char *AudioParameter::keySamplingRate = "sampling_rate";
+const char *AudioParameter::keyFormat = "format";
+const char *AudioParameter::keyChannels = "channels";
+const char *AudioParameter::keyFrameCount = "frame_count";
+
+AudioParameter::AudioParameter(const String8& keyValuePairs)
+{
+    char *str = new char[keyValuePairs.length()+1];
+    mKeyValuePairs = keyValuePairs;
+
+    strcpy(str, keyValuePairs.string());
+    char *pair = strtok(str, ";");
+    while (pair != NULL) {
+        if (strlen(pair) != 0) {
+            size_t eqIdx = strcspn(pair, "=");
+            String8 key = String8(pair, eqIdx);
+            String8 value;
+            if (eqIdx == strlen(pair)) {
+                value = String8("");
+            } else {
+                value = String8(pair + eqIdx + 1);
+            }
+            if (mParameters.indexOfKey(key) < 0) {
+                mParameters.add(key, value);
+            } else {
+                mParameters.replaceValueFor(key, value);
+            }
+        } else {
+            LOGV("AudioParameter() cstor empty key value pair");
+        }
+        pair = strtok(NULL, ";");
+    }
+
+    delete[] str;
+}
+
+AudioParameter::~AudioParameter()
+{
+    mParameters.clear();
+}
+
+String8 AudioParameter::toString()
+{
+    String8 str = String8("");
+
+    size_t size = mParameters.size();
+    for (size_t i = 0; i < size; i++) {
+        str += mParameters.keyAt(i);
+        str += "=";
+        str += mParameters.valueAt(i);
+        if (i < (size - 1)) str += ";";
+    }
+    return str;
+}
+
+status_t AudioParameter::add(const String8& key, const String8& value)
+{
+    if (mParameters.indexOfKey(key) < 0) {
+        mParameters.add(key, value);
+        return NO_ERROR;
+    } else {
+        mParameters.replaceValueFor(key, value);
+        return ALREADY_EXISTS;
+    }
+}
+
+status_t AudioParameter::addInt(const String8& key, const int value)
+{
+    char str[12];
+    if (snprintf(str, 12, "%d", value) > 0) {
+        String8 str8 = String8(str);
+        return add(key, str8);
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::addFloat(const String8& key, const float value)
+{
+    char str[23];
+    if (snprintf(str, 23, "%.10f", value) > 0) {
+        String8 str8 = String8(str);
+        return add(key, str8);
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::remove(const String8& key)
+{
+    if (mParameters.indexOfKey(key) >= 0) {
+        mParameters.removeItem(key);
+        return NO_ERROR;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::get(const String8& key, String8& value)
+{
+    if (mParameters.indexOfKey(key) >= 0) {
+        value = mParameters.valueFor(key);
+        return NO_ERROR;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioParameter::getInt(const String8& key, int& value)
+{
+    String8 str8;
+    status_t result = get(key, str8);
+    value = 0;
+    if (result == NO_ERROR) {
+        int val;
+        if (sscanf(str8.string(), "%d", &val) == 1) {
+            value = val;
+        } else {
+            result = INVALID_OPERATION;
+        }
+    }
+    return result;
+}
+
+status_t AudioParameter::getFloat(const String8& key, float& value)
+{
+    String8 str8;
+    status_t result = get(key, str8);
+    value = 0;
+    if (result == NO_ERROR) {
+        float val;
+        if (sscanf(str8.string(), "%f", &val) == 1) {
+            value = val;
+        } else {
+            result = INVALID_OPERATION;
+        }
+    }
+    return result;
+}
 
 }; // namespace android
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index b2c067b..b147d25 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -32,9 +32,9 @@
 #include <media/AudioTrack.h>
 
 #include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/MemoryDealer.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
 #include <utils/Timers.h>
 #include <cutils/atomic.h>
 
@@ -54,7 +54,7 @@
         int streamType,
         uint32_t sampleRate,
         int format,
-        int channelCount,
+        int channels,
         int frameCount,
         uint32_t flags,
         callback_t cbf,
@@ -62,7 +62,7 @@
         int notificationFrames)
     : mStatus(NO_INIT)
 {
-    mStatus = set(streamType, sampleRate, format, channelCount,
+    mStatus = set(streamType, sampleRate, format, channels,
             frameCount, flags, cbf, user, notificationFrames, 0);
 }
 
@@ -70,7 +70,7 @@
         int streamType,
         uint32_t sampleRate,
         int format,
-        int channelCount,
+        int channels,
         const sp<IMemory>& sharedBuffer,
         uint32_t flags,
         callback_t cbf,
@@ -78,7 +78,7 @@
         int notificationFrames)
     : mStatus(NO_INIT)
 {
-    mStatus = set(streamType, sampleRate, format, channelCount,
+    mStatus = set(streamType, sampleRate, format, channels,
             0, flags, cbf, user, notificationFrames, sharedBuffer);
 }
 
@@ -97,6 +97,7 @@
         }
         mAudioTrack.clear();
         IPCThreadState::self()->flushCommands();
+        AudioSystem::releaseOutput(getOutput());
     }
 }
 
@@ -104,7 +105,7 @@
         int streamType,
         uint32_t sampleRate,
         int format,
-        int channelCount,
+        int channels,
         int frameCount,
         uint32_t flags,
         callback_t cbf,
@@ -150,63 +151,84 @@
     if (format == 0) {
         format = AudioSystem::PCM_16_BIT;
     }
-    if (channelCount == 0) {
-        channelCount = 2;
+    if (channels == 0) {
+        channels = AudioSystem::CHANNEL_OUT_STEREO;
     }
 
     // validate parameters
-    if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
-        (format != AudioSystem::PCM_16_BIT)) {
+    if (!AudioSystem::isValidFormat(format)) {
         LOGE("Invalid format");
         return BAD_VALUE;
     }
-    if (channelCount != 1 && channelCount != 2) {
-        LOGE("Invalid channel number");
+
+    // force direct flag if format is not linear PCM
+    if (!AudioSystem::isLinearPCM(format)) {
+        flags |= AudioSystem::OUTPUT_FLAG_DIRECT;
+    }
+
+    if (!AudioSystem::isOutputChannel(channels)) {
+        LOGE("Invalid channel mask");
+        return BAD_VALUE;
+    }
+    uint32_t channelCount = AudioSystem::popCount(channels);
+
+    audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType,
+            sampleRate, format, channels, (AudioSystem::output_flags)flags);
+
+    if (output == 0) {
+        LOGE("Could not get audio output for stream type %d", streamType);
         return BAD_VALUE;
     }
 
-    // Ensure that buffer depth covers at least audio hardware latency
-    uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
-    if (minBufCount < 2) minBufCount = 2;
-
-    // When playing from shared buffer, playback will start even if last audioflinger
-    // block is partly filled.
-    if (sharedBuffer != 0 && minBufCount > 1) {
-        minBufCount--;
-    }
-
-    int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
-
-    if (sharedBuffer == 0) {
-        if (frameCount == 0) {
-            frameCount = minFrameCount;
-        }
-        if (notificationFrames == 0) {
-            notificationFrames = frameCount/2;
-        }
-        // Make sure that application is notified with sufficient margin
-        // before underrun
-        if (notificationFrames > frameCount/2) {
-            notificationFrames = frameCount/2;
+    if (!AudioSystem::isLinearPCM(format)) {
+        if (sharedBuffer != 0) {
+            frameCount = sharedBuffer->size();
         }
     } else {
-        // Ensure that buffer alignment matches channelcount
-        if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
-            LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
-            return BAD_VALUE;
-        }
-        frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
-    }
+        // Ensure that buffer depth covers at least audio hardware latency
+        uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+        if (minBufCount < 2) minBufCount = 2;
 
-    if (frameCount < minFrameCount) {
-      LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
-      return BAD_VALUE;
+        int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+
+        if (sharedBuffer == 0) {
+            if (frameCount == 0) {
+                frameCount = minFrameCount;
+            }
+            if (notificationFrames == 0) {
+                notificationFrames = frameCount/2;
+            }
+            // Make sure that application is notified with sufficient margin
+            // before underrun
+            if (notificationFrames > frameCount/2) {
+                notificationFrames = frameCount/2;
+            }
+            if (frameCount < minFrameCount) {
+              LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
+              return BAD_VALUE;
+            }
+        } else {
+            // Ensure that buffer alignment matches channelcount
+            if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
+                LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
+                return BAD_VALUE;
+            }
+            frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
+        }
     }
 
     // create the track
     status_t status;
     sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
-                streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
+                                                      streamType,
+                                                      sampleRate,
+                                                      format,
+                                                      channelCount,
+                                                      frameCount,
+                                                      ((uint16_t)flags) << 16,
+                                                      sharedBuffer,
+                                                      output,
+                                                      &status);
 
     if (track == 0) {
         LOGE("AudioFlinger could not create track, status: %d", status);
@@ -245,6 +267,7 @@
     mVolume[RIGHT] = 1.0f;
     mStreamType = streamType;
     mFormat = format;
+    mChannels = channels;
     mChannelCount = channelCount;
     mSharedBuffer = sharedBuffer;
     mMuted = false;
@@ -259,6 +282,7 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
+    mFlags = flags;
 
     return NO_ERROR;
 }
@@ -297,7 +321,11 @@
 
 int AudioTrack::frameSize() const
 {
-    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+    if (AudioSystem::isLinearPCM(mFormat)) {
+        return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+    } else {
+        return sizeof(uint8_t);
+    }
 }
 
 sp<IMemory>& AudioTrack::sharedBuffer()
@@ -323,6 +351,7 @@
      }
 
     if (android_atomic_or(1, &mActive) == 0) {
+        AudioSystem::startOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
         mNewPosition = mCblk->server + mUpdatePeriod;
         mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
         mCblk->waitTimeMs = 0;
@@ -367,6 +396,7 @@
         } else {
             setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
         }
+        AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
     }
 
     if (t != 0) {
@@ -382,12 +412,12 @@
 void AudioTrack::flush()
 {
     LOGV("flush");
-    
+
     // clear playback marker and periodic update counter
     mMarkerPosition = 0;
     mMarkerReached = false;
     mUpdatePeriod = 0;
-    
+
 
     if (!mActive) {
         mAudioTrack->flush();
@@ -403,6 +433,7 @@
     if (android_atomic_and(~1, &mActive) == 1) {
         mActive = 0;
         mAudioTrack->pause();
+        AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
     }
 }
 
@@ -455,7 +486,6 @@
 {
     audio_track_cblk_t* cblk = mCblk;
 
-
     Mutex::Autolock _l(cblk->lock);
 
     if (loopCount == 0) {
@@ -476,7 +506,7 @@
         LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
             loopStart, loopEnd, mFrameCount);
         return BAD_VALUE;
-    }   
+    }
 
     cblk->loopStart = loopStart;
     cblk->loopEnd = loopEnd;
@@ -555,7 +585,7 @@
 
     mCblk->server = position;
     mCblk->forceReady = 1;
-    
+
     return NO_ERROR;
 }
 
@@ -571,7 +601,7 @@
 status_t AudioTrack::reload()
 {
     if (!stopped()) return INVALID_OPERATION;
-    
+
     flush();
 
     mCblk->stepUser(mFrameCount);
@@ -579,6 +609,12 @@
     return NO_ERROR;
 }
 
+audio_io_handle_t AudioTrack::getOutput()
+{
+    return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
+            mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
+}
+
 // -------------------------------------------------------------------------
 
 status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -608,7 +644,7 @@
                 return WOULD_BLOCK;
             timeout = 0;
             result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
-            if (__builtin_expect(result!=NO_ERROR, false)) { 
+            if (__builtin_expect(result!=NO_ERROR, false)) {
                 cblk->waitTimeMs += waitTimeMs;
                 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
                     // timing out when a loop has been set and we have already written upto loop end
@@ -616,7 +652,7 @@
                     if (cblk->user < cblk->loopEnd) {
                         LOGW(   "obtainBuffer timed out (is the CPU pegged?) %p "
                                 "user=%08x, server=%08x", this, cblk->user, cblk->server);
-                        //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) 
+                        //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
                         cblk->lock.unlock();
                         mAudioTrack->start();
                         cblk->lock.lock();
@@ -624,7 +660,7 @@
                     }
                     cblk->waitTimeMs = 0;
                 }
-                
+
                 if (--waitCount == 0) {
                     return TIMED_OUT;
                 }
@@ -636,7 +672,7 @@
     }
 
     cblk->waitTimeMs = 0;
-    
+
     if (framesReq > framesAvail) {
         framesReq = framesAvail;
     }
@@ -653,12 +689,16 @@
         "but didn't need to be locked. We recovered, but "
         "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
 
-    audioBuffer->flags       = mMuted ? Buffer::MUTE : 0;
-    audioBuffer->channelCount= mChannelCount;
-    audioBuffer->format      = AudioSystem::PCM_16_BIT;
-    audioBuffer->frameCount  = framesReq;
-    audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
-    audioBuffer->raw         = (int8_t *)cblk->buffer(u);
+    audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
+    audioBuffer->channelCount = mChannelCount;
+    audioBuffer->frameCount = framesReq;
+    audioBuffer->size = framesReq * cblk->frameSize;
+    if (AudioSystem::isLinearPCM(mFormat)) {
+        audioBuffer->format = AudioSystem::PCM_16_BIT;
+    } else {
+        audioBuffer->format = mFormat;
+    }
+    audioBuffer->raw = (int8_t *)cblk->buffer(u);
     active = mActive;
     return active ? status_t(NO_ERROR) : status_t(STOPPED);
 }
@@ -690,10 +730,8 @@
     Buffer audioBuffer;
 
     do {
-        audioBuffer.frameCount = userSize/mChannelCount;
-        if (mFormat == AudioSystem::PCM_16_BIT) {
-            audioBuffer.frameCount >>= 1;
-        }
+        audioBuffer.frameCount = userSize/frameSize();
+
         // Calling obtainBuffer() with a negative wait count causes
         // an (almost) infinite wait time.
         status_t err = obtainBuffer(&audioBuffer, -1);
@@ -705,6 +743,7 @@
         }
 
         size_t toWrite;
+
         if (mFormat == AudioSystem::PCM_8_BIT) {
             // Divide capacity by 2 to take expansion into account
             toWrite = audioBuffer.size>>1;
@@ -742,13 +781,13 @@
         if (mCblk->flowControlFlag == 0) {
             mCbf(EVENT_UNDERRUN, mUserData, 0);
             if (mCblk->server == mCblk->frameCount) {
-                mCbf(EVENT_BUFFER_END, mUserData, 0);                
+                mCbf(EVENT_BUFFER_END, mUserData, 0);
             }
             mCblk->flowControlFlag = 1;
             if (mSharedBuffer != 0) return false;
         }
     }
-    
+
     // Manage loop end callback
     while (mLoopCount > mCblk->loopCount) {
         int loopCount = -1;
@@ -767,7 +806,7 @@
     }
 
     // Manage new position callback
-    if(mUpdatePeriod > 0) {
+    if (mUpdatePeriod > 0) {
         while (mCblk->server >= mNewPosition) {
             mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
             mNewPosition += mUpdatePeriod;
@@ -784,10 +823,10 @@
     do {
 
         audioBuffer.frameCount = frames;
-        
-        // Calling obtainBuffer() with a wait count of 1 
-        // limits wait time to WAIT_PERIOD_MS. This prevents from being 
-        // stuck here not being able to handle timed events (position, markers, loops). 
+
+        // Calling obtainBuffer() with a wait count of 1
+        // limits wait time to WAIT_PERIOD_MS. This prevents from being
+        // stuck here not being able to handle timed events (position, markers, loops).
         status_t err = obtainBuffer(&audioBuffer, 1);
         if (err < NO_ERROR) {
             if (err != TIMED_OUT) {
@@ -832,7 +871,11 @@
         }
 
         audioBuffer.size = writtenSize;
-        audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
+        // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for
+        // 8 bit PCM data: in this case,  mCblk->frameSize is based on a sampel size of
+        // 16 bit.
+        audioBuffer.frameCount = writtenSize/mCblk->frameSize;
+
         frames -= audioBuffer.frameCount;
 
         releaseBuffer(&audioBuffer);
@@ -891,7 +934,7 @@
 // =========================================================================
 
 audio_track_cblk_t::audio_track_cblk_t()
-    : user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
+    : lock(Mutex::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
     loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
 {
 }
@@ -949,7 +992,7 @@
         // we switch to normal obtainBuffer() timeout period
         if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
             bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
-        }        
+        }
         // It is possible that we receive a flush()
         // while the mixer is processing a block: in this case,
         // stepServer() is called After the flush() has reset u & s and
@@ -981,7 +1024,7 @@
 
 void* audio_track_cblk_t::buffer(uint32_t offset) const
 {
-    return (int16_t *)this->buffers + (offset-userBase)*this->channels;
+    return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
 }
 
 uint32_t audio_track_cblk_t::framesAvailable()
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index eeaa54f..9385367 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -16,12 +16,13 @@
 */
 
 #define LOG_TAG "IAudioFlinger"
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
 
 #include <media/IAudioFlinger.h>
 
@@ -44,17 +45,21 @@
     STREAM_VOLUME,
     STREAM_MUTE,
     SET_MODE,
-    GET_MODE,
-    SET_ROUTING,
-    GET_ROUTING,
     SET_MIC_MUTE,
     GET_MIC_MUTE,
     IS_MUSIC_ACTIVE,
-    SET_PARAMETER,
+    SET_PARAMETERS,
+    GET_PARAMETERS,
     REGISTER_CLIENT,
     GET_INPUTBUFFERSIZE,
-    WAKE_UP,
-    IS_A2DP_ENABLED
+    OPEN_OUTPUT,
+    OPEN_DUPLICATE_OUTPUT,
+    CLOSE_OUTPUT,
+    SUSPEND_OUTPUT,
+    RESTORE_OUTPUT,
+    OPEN_INPUT,
+    CLOSE_INPUT,
+    SET_STREAM_OUTPUT
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -74,6 +79,7 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
+                                void *output,
                                 status_t *status)
     {
         Parcel data, reply;
@@ -86,6 +92,7 @@
         data.writeInt32(frameCount);
         data.writeInt32(flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
+        data.write(&output, sizeof(void *));
         status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
         if (lStatus != NO_ERROR) {
             LOGE("createTrack error: %s", strerror(-lStatus));
@@ -99,7 +106,7 @@
 
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                int inputSource,
+                                void *input,
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
@@ -110,7 +117,7 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(pid);
-        data.writeInt32(inputSource);
+        data.write(&input, sizeof(void *));
         data.writeInt32(sampleRate);
         data.writeInt32(format);
         data.writeInt32(channelCount);
@@ -124,47 +131,47 @@
         return interface_cast<IAudioRecord>(reply.readStrongBinder());
     }
 
-    virtual uint32_t sampleRate(int output) const
+    virtual uint32_t sampleRate(void *output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.write(&output, sizeof(void *));
         remote()->transact(SAMPLE_RATE, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int channelCount(int output) const
+    virtual int channelCount(void *output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.write(&output, sizeof(void *));
         remote()->transact(CHANNEL_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int format(int output) const
+    virtual int format(void *output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.write(&output, sizeof(void *));
         remote()->transact(FORMAT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual size_t frameCount(int output) const
+    virtual size_t frameCount(void *output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.write(&output, sizeof(void *));
         remote()->transact(FRAME_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual uint32_t latency(int output) const
+    virtual uint32_t latency(void *output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.write(&output, sizeof(void *));
         remote()->transact(LATENCY, data, &reply);
         return reply.readInt32();
     }
@@ -203,12 +210,13 @@
         return reply.readInt32();
     }
 
-    virtual status_t setStreamVolume(int stream, float value)
+    virtual status_t setStreamVolume(int stream, float value, void *output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(stream);
         data.writeFloat(value);
+        data.write(&output, sizeof(void *));
         remote()->transact(SET_STREAM_VOLUME, data, &reply);
         return reply.readInt32();
     }
@@ -223,11 +231,12 @@
         return reply.readInt32();
     }
 
-    virtual float streamVolume(int stream) const
+    virtual float streamVolume(int stream, void *output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(stream);
+        data.write(&output, sizeof(void *));
         remote()->transact(STREAM_VOLUME, data, &reply);
         return reply.readFloat();
     }
@@ -241,26 +250,6 @@
         return reply.readInt32();
     }
 
-    virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(mode);
-        data.writeInt32(routes);
-        data.writeInt32(mask);
-        remote()->transact(SET_ROUTING, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual uint32_t getRouting(int mode) const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(mode);
-        remote()->transact(GET_ROUTING, data, &reply);
-        return reply.readInt32();
-    }
-
     virtual status_t setMode(int mode)
     {
         Parcel data, reply;
@@ -270,14 +259,6 @@
         return reply.readInt32();
     }
 
-    virtual int getMode() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        remote()->transact(GET_MODE, data, &reply);
-        return reply.readInt32();
-    }
-
     virtual status_t setMicMute(bool state)
     {
         Parcel data, reply;
@@ -303,16 +284,26 @@
         return reply.readInt32();
     }
 
-    virtual status_t setParameter(const char* key, const char* value)
+    virtual status_t setParameters(void *ioHandle, const String8& keyValuePairs)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeCString(key);
-        data.writeCString(value);
-        remote()->transact(SET_PARAMETER, data, &reply);
+        data.write(&ioHandle, sizeof(void *));
+        data.writeString8(keyValuePairs);
+        remote()->transact(SET_PARAMETERS, data, &reply);
         return reply.readInt32();
     }
-    
+
+    virtual String8 getParameters(void *ioHandle, const String8& keys)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(&ioHandle, sizeof(void *));
+        data.writeString8(keys);
+        remote()->transact(GET_PARAMETERS, data, &reply);
+        return reply.readString8();
+    }
+
     virtual void registerClient(const sp<IAudioFlingerClient>& client)
     {
         Parcel data, reply;
@@ -320,7 +311,7 @@
         data.writeStrongBinder(client->asBinder());
         remote()->transact(REGISTER_CLIENT, data, &reply);
     }
-    
+
     virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
     {
         Parcel data, reply;
@@ -331,21 +322,133 @@
         remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
         return reply.readInt32();
     }
-    
-    virtual void wakeUp()
+
+    virtual void *openOutput(uint32_t *pDevices,
+                            uint32_t *pSamplingRate,
+                            uint32_t *pFormat,
+                            uint32_t *pChannels,
+                            uint32_t *pLatencyMs,
+                            uint32_t flags)
     {
         Parcel data, reply;
+        uint32_t devices = pDevices ? *pDevices : 0;
+        uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+        uint32_t format = pFormat ? *pFormat : 0;
+        uint32_t channels = pChannels ? *pChannels : 0;
+        uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
+
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        remote()->transact(WAKE_UP, data, &reply, IBinder::FLAG_ONEWAY);
-        return;
+        data.writeInt32(devices);
+        data.writeInt32(samplingRate);
+        data.writeInt32(format);
+        data.writeInt32(channels);
+        data.writeInt32(latency);
+        data.writeInt32(flags);
+        remote()->transact(OPEN_OUTPUT, data, &reply);
+        void *output;
+        reply.read(&output, sizeof(void *));
+        LOGV("openOutput() returned output, %p", output);
+        devices = reply.readInt32();
+        if (pDevices) *pDevices = devices;
+        samplingRate = reply.readInt32();
+        if (pSamplingRate) *pSamplingRate = samplingRate;
+        format = reply.readInt32();
+        if (pFormat) *pFormat = format;
+        channels = reply.readInt32();
+        if (pChannels) *pChannels = channels;
+        latency = reply.readInt32();
+        if (pLatencyMs) *pLatencyMs = latency;
+        return output;
     }
 
-    virtual bool isA2dpEnabled() const
+    virtual void *openDuplicateOutput(void *output1, void *output2)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        remote()->transact(IS_A2DP_ENABLED, data, &reply);
-        return (bool)reply.readInt32();
+        data.write(&output1, sizeof(void *));
+        data.write(&output2, sizeof(void *));
+        remote()->transact(OPEN_DUPLICATE_OUTPUT, data, &reply);
+        void *output;
+        reply.read(&output, sizeof(void *));
+        return output;
+    }
+
+    virtual status_t closeOutput(void *output)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(&output, sizeof(void *));
+        remote()->transact(CLOSE_OUTPUT, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t suspendOutput(void *output)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(&output, sizeof(void *));
+        remote()->transact(SUSPEND_OUTPUT, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t restoreOutput(void *output)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(&output, sizeof(void *));
+        remote()->transact(RESTORE_OUTPUT, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual void *openInput(uint32_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        uint32_t *pFormat,
+                                        uint32_t *pChannels,
+                                        uint32_t acoustics)
+    {
+        Parcel data, reply;
+        uint32_t devices = pDevices ? *pDevices : 0;
+        uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+        uint32_t format = pFormat ? *pFormat : 0;
+        uint32_t channels = pChannels ? *pChannels : 0;
+
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(devices);
+        data.writeInt32(samplingRate);
+        data.writeInt32(format);
+        data.writeInt32(channels);
+        data.writeInt32(acoustics);
+        remote()->transact(OPEN_INPUT, data, &reply);
+        void *input;
+        reply.read(&input, sizeof(void *));
+        devices = reply.readInt32();
+        if (pDevices) *pDevices = devices;
+        samplingRate = reply.readInt32();
+        if (pSamplingRate) *pSamplingRate = samplingRate;
+        format = reply.readInt32();
+        if (pFormat) *pFormat = format;
+        channels = reply.readInt32();
+        if (pChannels) *pChannels = channels;
+        return input;
+    }
+
+    virtual status_t closeInput(void *input)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(&input, sizeof(void *));
+        remote()->transact(CLOSE_INPUT, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setStreamOutput(uint32_t stream, void *output)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(stream);
+        data.write(&output, sizeof(void *));
+        remote()->transact(SET_STREAM_OUTPUT, data, &reply);
+        return reply.readInt32();
     }
 };
 
@@ -353,12 +456,6 @@
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnAudioFlinger::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -373,10 +470,12 @@
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
+            void *output;
+            data.read(&output, sizeof(void *));
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     streamType, sampleRate, format,
-                    channelCount, bufferCount, flags, buffer, &status);
+                    channelCount, bufferCount, flags, buffer, output, &status);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
@@ -384,14 +483,15 @@
         case OPEN_RECORD: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             pid_t pid = data.readInt32();
-            int inputSource = data.readInt32();
+            void *input;
+            data.read(&input, sizeof(void *));
             uint32_t sampleRate = data.readInt32();
             int format = data.readInt32();
             int channelCount = data.readInt32();
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
             status_t status;
-            sp<IAudioRecord> record = openRecord(pid, inputSource,
+            sp<IAudioRecord> record = openRecord(pid, input,
                     sampleRate, format, channelCount, bufferCount, flags, &status);
             reply->writeInt32(status);
             reply->writeStrongBinder(record->asBinder());
@@ -399,31 +499,36 @@
         } break;
         case SAMPLE_RATE: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int output = data.readInt32();
+            void *output;
+            data.read(&output, sizeof(void *));
             reply->writeInt32( sampleRate(output) );
             return NO_ERROR;
         } break;
         case CHANNEL_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int output = data.readInt32();
+            void *output;
+            data.read(&output, sizeof(void *));
             reply->writeInt32( channelCount(output) );
             return NO_ERROR;
         } break;
         case FORMAT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int output = data.readInt32();
+            void *output;
+            data.read(&output, sizeof(void *));
             reply->writeInt32( format(output) );
             return NO_ERROR;
         } break;
         case FRAME_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int output = data.readInt32();
+            void *output;
+            data.read(&output, sizeof(void *));
             reply->writeInt32( frameCount(output) );
             return NO_ERROR;
         } break;
         case LATENCY: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int output = data.readInt32();
+            void *output;
+            data.read(&output, sizeof(void *));
             reply->writeInt32( latency(output) );
             return NO_ERROR;
         } break;
@@ -450,7 +555,10 @@
         case SET_STREAM_VOLUME: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int stream = data.readInt32();
-            reply->writeInt32( setStreamVolume(stream, data.readFloat()) );
+            float volume = data.readFloat();
+            void *output;
+            data.read(&output, sizeof(void *));
+            reply->writeInt32( setStreamVolume(stream, volume, output) );
             return NO_ERROR;
         } break;
         case SET_STREAM_MUTE: {
@@ -462,7 +570,9 @@
         case STREAM_VOLUME: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int stream = data.readInt32();
-            reply->writeFloat( streamVolume(stream) );
+            void *output;
+            data.read(&output, sizeof(void *));
+            reply->writeFloat( streamVolume(stream, output) );
             return NO_ERROR;
         } break;
         case STREAM_MUTE: {
@@ -471,31 +581,12 @@
             reply->writeInt32( streamMute(stream) );
             return NO_ERROR;
         } break;
-        case SET_ROUTING: {
-            CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int mode = data.readInt32();
-            uint32_t routes = data.readInt32();
-            uint32_t mask = data.readInt32();
-            reply->writeInt32( setRouting(mode, routes, mask) );
-            return NO_ERROR;
-        } break;
-        case GET_ROUTING: {
-            CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int mode = data.readInt32();
-            reply->writeInt32( getRouting(mode) );
-            return NO_ERROR;
-        } break;
         case SET_MODE: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int mode = data.readInt32();
             reply->writeInt32( setMode(mode) );
             return NO_ERROR;
         } break;
-        case GET_MODE: {
-            CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( getMode() );
-            return NO_ERROR;
-        } break;
         case SET_MIC_MUTE: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int state = data.readInt32();
@@ -512,13 +603,23 @@
             reply->writeInt32( isMusicActive() );
             return NO_ERROR;
         } break;
-        case SET_PARAMETER: {
+        case SET_PARAMETERS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            const char *key = data.readCString();
-            const char *value = data.readCString();
-            reply->writeInt32( setParameter(key, value) );
+            void *ioHandle;
+            data.read(&ioHandle, sizeof(void *));
+            String8 keyValuePairs(data.readString8());
+            reply->writeInt32(setParameters(ioHandle, keyValuePairs));
             return NO_ERROR;
-        } break;
+         } break;
+        case GET_PARAMETERS: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            void *ioHandle;
+            data.read(&ioHandle, sizeof(void *));
+            String8 keys(data.readString8());
+            reply->writeString8(getParameters(ioHandle, keys));
+            return NO_ERROR;
+         } break;
+
         case REGISTER_CLIENT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder());
@@ -533,14 +634,93 @@
             reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) );
             return NO_ERROR;
         } break;
-        case WAKE_UP: {
+        case OPEN_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            wakeUp();
+            uint32_t devices = data.readInt32();
+            uint32_t samplingRate = data.readInt32();
+            uint32_t format = data.readInt32();
+            uint32_t channels = data.readInt32();
+            uint32_t latency = data.readInt32();
+            uint32_t flags = data.readInt32();
+            void *output = openOutput(&devices,
+                                     &samplingRate,
+                                     &format,
+                                     &channels,
+                                     &latency,
+                                     flags);
+            LOGV("OPEN_OUTPUT output, %p", output);
+            reply->write(&output, sizeof(void *));
+            reply->writeInt32(devices);
+            reply->writeInt32(samplingRate);
+            reply->writeInt32(format);
+            reply->writeInt32(channels);
+            reply->writeInt32(latency);
             return NO_ERROR;
         } break;
-        case IS_A2DP_ENABLED: {
+        case OPEN_DUPLICATE_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( (int)isA2dpEnabled() );
+            void *output1;
+            void *output2;
+            data.read(&output1, sizeof(void *));
+            data.read(&output2, sizeof(void *));
+            void *output = openDuplicateOutput(output1, output2);
+            reply->write(&output, sizeof(void *));
+            return NO_ERROR;
+        } break;
+        case CLOSE_OUTPUT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            void *output;
+            data.read(&output, sizeof(void *));
+            reply->writeInt32(closeOutput(output));
+            return NO_ERROR;
+        } break;
+        case SUSPEND_OUTPUT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            void *output;
+            data.read(&output, sizeof(void *));
+            reply->writeInt32(suspendOutput(output));
+            return NO_ERROR;
+        } break;
+        case RESTORE_OUTPUT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            void *output;
+            data.read(&output, sizeof(void *));
+            reply->writeInt32(restoreOutput(output));
+            return NO_ERROR;
+        } break;
+        case OPEN_INPUT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            uint32_t devices = data.readInt32();
+            uint32_t samplingRate = data.readInt32();
+            uint32_t format = data.readInt32();
+            uint32_t channels = data.readInt32();
+            uint32_t acoutics = data.readInt32();
+
+            void *input = openInput(&devices,
+                                     &samplingRate,
+                                     &format,
+                                     &channels,
+                                     acoutics);
+            reply->write(&input, sizeof(void *));
+            reply->writeInt32(devices);
+            reply->writeInt32(samplingRate);
+            reply->writeInt32(format);
+            reply->writeInt32(channels);
+            return NO_ERROR;
+        } break;
+        case CLOSE_INPUT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            void *input;
+            data.read(&input, sizeof(void *));
+            reply->writeInt32(closeInput(input));
+            return NO_ERROR;
+        } break;
+        case SET_STREAM_OUTPUT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            void *output;
+            uint32_t stream = data.readInt32();
+            data.read(&output, sizeof(void *));
+            reply->writeInt32(setStreamOutput(stream, output));
             return NO_ERROR;
         } break;
         default:
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 9d00aef..eaae977 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -20,14 +20,15 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
 
 #include <media/IAudioFlingerClient.h>
+#include <media/AudioSystem.h>
 
 namespace android {
 
 enum {
-    AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION
+    IO_CONFIG_CHANGED = IBinder::FIRST_CALL_TRANSACTION
 };
 
 class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient>
@@ -38,12 +39,25 @@
     {
     }
 
-    void a2dpEnabledChanged(bool enabled)
+    void ioConfigChanged(int event, void *param1, void *param2)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
-        data.writeInt32((int)enabled);
-        remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+        data.writeInt32(event);
+        data.write(&param1, sizeof(void *));
+        if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
+            uint32_t stream = *(uint32_t *)param2;
+            LOGV("ioConfigChanged stream %d", stream);
+            data.writeInt32(stream);
+        } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
+            AudioSystem::OutputDescriptor *desc = (AudioSystem::OutputDescriptor *)param2;
+            data.writeInt32(desc->samplingRate);
+            data.writeInt32(desc->format);
+            data.writeInt32(desc->channels);
+            data.writeInt32(desc->frameCount);
+            data.writeInt32(desc->latency);
+        }
+        remote()->transact(IO_CONFIG_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
 
@@ -51,20 +65,31 @@
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnAudioFlingerClient::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     switch(code) {
-        case AUDIO_OUTPUT_CHANGED: {
+    case IO_CONFIG_CHANGED: {
             CHECK_INTERFACE(IAudioFlingerClient, data, reply);
-            bool enabled = (bool)data.readInt32();
-            a2dpEnabledChanged(enabled);
+            int event = data.readInt32();
+            void *param1;
+            void *param2 = 0;
+            AudioSystem::OutputDescriptor desc;
+            uint32_t stream;
+            data.read(&param1, sizeof(void *));
+            if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
+                stream = data.readInt32();
+                param2 = &stream;
+                LOGV("STREAM_CONFIG_CHANGED stream %d", stream);
+            } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
+                desc.samplingRate = data.readInt32();
+                desc.format = data.readInt32();
+                desc.channels = data.readInt32();
+                desc.frameCount = data.readInt32();
+                desc.latency = data.readInt32();
+                param2 = &desc;
+            }
+            ioConfigChanged(event, param1, param2);
             return NO_ERROR;
         } break;
         default:
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
new file mode 100644
index 0000000..0d8a329
--- /dev/null
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -0,0 +1,423 @@
+/*
+**
+** 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_TAG "IAudioPolicyService"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <media/IAudioPolicyService.h>
+
+namespace android {
+
+enum {
+    SET_DEVICE_CONNECTION_STATE = IBinder::FIRST_CALL_TRANSACTION,
+    GET_DEVICE_CONNECTION_STATE,
+    SET_PHONE_STATE,
+    SET_RINGER_MODE,
+    SET_FORCE_USE,
+    GET_FORCE_USE,
+    GET_OUTPUT,
+    START_OUTPUT,
+    STOP_OUTPUT,
+    RELEASE_OUTPUT,
+    GET_INPUT,
+    START_INPUT,
+    STOP_INPUT,
+    RELEASE_INPUT,
+    INIT_STREAM_VOLUME,
+    SET_STREAM_VOLUME,
+    GET_STREAM_VOLUME
+};
+
+class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
+{
+public:
+    BpAudioPolicyService(const sp<IBinder>& impl)
+        : BpInterface<IAudioPolicyService>(impl)
+    {
+    }
+
+    virtual status_t setDeviceConnectionState(
+                                    AudioSystem::audio_devices device,
+                                    AudioSystem::device_connection_state state,
+                                    const char *device_address)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(device));
+        data.writeInt32(static_cast <uint32_t>(state));
+        data.writeCString(device_address);
+        remote()->transact(SET_DEVICE_CONNECTION_STATE, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual AudioSystem::device_connection_state getDeviceConnectionState(
+                                    AudioSystem::audio_devices device,
+                                    const char *device_address)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(device));
+        data.writeCString(device_address);
+        remote()->transact(GET_DEVICE_CONNECTION_STATE, data, &reply);
+        return static_cast <AudioSystem::device_connection_state>(reply.readInt32());
+    }
+
+    virtual status_t setPhoneState(int state)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(state);
+        remote()->transact(SET_PHONE_STATE, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t setRingerMode(uint32_t mode, uint32_t mask)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        data.writeInt32(mask);
+        remote()->transact(SET_RINGER_MODE, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(usage));
+        data.writeInt32(static_cast <uint32_t>(config));
+        remote()->transact(SET_FORCE_USE, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(usage));
+        remote()->transact(GET_FORCE_USE, data, &reply);
+        return static_cast <AudioSystem::forced_config> (reply.readInt32());
+    }
+
+    virtual audio_io_handle_t getOutput(
+                                        AudioSystem::stream_type stream,
+                                        uint32_t samplingRate,
+                                        uint32_t format,
+                                        uint32_t channels,
+                                        AudioSystem::output_flags flags)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(stream));
+        data.writeInt32(samplingRate);
+        data.writeInt32(static_cast <uint32_t>(format));
+        data.writeInt32(channels);
+        data.writeInt32(static_cast <uint32_t>(flags));
+        remote()->transact(GET_OUTPUT, data, &reply);
+        audio_io_handle_t output;
+        reply.read(&output, sizeof(audio_io_handle_t));
+        return output;
+    }
+
+    virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&output, sizeof(audio_io_handle_t));
+        data.writeInt32(stream);
+        remote()->transact(START_OUTPUT, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&output, sizeof(audio_io_handle_t));
+        data.writeInt32(stream);
+        remote()->transact(STOP_OUTPUT, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual void releaseOutput(audio_io_handle_t output)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&output, sizeof(audio_io_handle_t));
+        remote()->transact(RELEASE_OUTPUT, data, &reply);
+    }
+
+    virtual audio_io_handle_t getInput(
+                                    int inputSource,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channels,
+                                    AudioSystem::audio_in_acoustics acoustics)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(inputSource);
+        data.writeInt32(samplingRate);
+        data.writeInt32(static_cast <uint32_t>(format));
+        data.writeInt32(channels);
+        data.writeInt32(static_cast <uint32_t>(acoustics));
+        remote()->transact(GET_INPUT, data, &reply);
+        audio_io_handle_t input;
+        reply.read(&input, sizeof(audio_io_handle_t));
+        return input;
+    }
+
+    virtual status_t startInput(audio_io_handle_t input)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&input, sizeof(audio_io_handle_t));
+        remote()->transact(START_INPUT, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t stopInput(audio_io_handle_t input)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&input, sizeof(audio_io_handle_t));
+        remote()->transact(STOP_INPUT, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual void releaseInput(audio_io_handle_t input)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(&input, sizeof(audio_io_handle_t));
+        remote()->transact(RELEASE_INPUT, data, &reply);
+    }
+
+    virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+                                    int indexMin,
+                                    int indexMax)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(stream));
+        data.writeInt32(indexMin);
+        data.writeInt32(indexMax);
+        remote()->transact(INIT_STREAM_VOLUME, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(stream));
+        data.writeInt32(index);
+        remote()->transact(SET_STREAM_VOLUME, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(stream));
+        remote()->transact(GET_STREAM_VOLUME, data, &reply);
+        int lIndex = reply.readInt32();
+        if (index) *index = lIndex;
+        return static_cast <status_t> (reply.readInt32());
+    }
+};
+
+IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
+
+// ----------------------------------------------------------------------
+
+
+status_t BnAudioPolicyService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case SET_DEVICE_CONNECTION_STATE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
+            AudioSystem::device_connection_state state = static_cast <AudioSystem::device_connection_state>(data.readInt32());
+            const char *device_address = data.readCString();
+            reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address)));
+            return NO_ERROR;
+        } break;
+
+        case GET_DEVICE_CONNECTION_STATE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
+            const char *device_address = data.readCString();
+            reply->writeInt32(static_cast <uint32_t>(getDeviceConnectionState(device, device_address)));
+            return NO_ERROR;
+        } break;
+
+        case SET_PHONE_STATE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            reply->writeInt32(static_cast <uint32_t>(setPhoneState(data.readInt32())));
+            return NO_ERROR;
+        } break;
+
+        case SET_RINGER_MODE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            uint32_t mode = data.readInt32();
+            uint32_t mask = data.readInt32();
+            reply->writeInt32(static_cast <uint32_t>(setRingerMode(mode, mask)));
+            return NO_ERROR;
+        } break;
+
+        case SET_FORCE_USE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
+            AudioSystem::forced_config config = static_cast <AudioSystem::forced_config>(data.readInt32());
+            reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config)));
+            return NO_ERROR;
+        } break;
+
+        case GET_FORCE_USE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
+            reply->writeInt32(static_cast <uint32_t>(getForceUse(usage)));
+            return NO_ERROR;
+        } break;
+
+        case GET_OUTPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            uint32_t samplingRate = data.readInt32();
+            uint32_t format = data.readInt32();
+            uint32_t channels = data.readInt32();
+            AudioSystem::output_flags flags = static_cast <AudioSystem::output_flags>(data.readInt32());
+
+            audio_io_handle_t output = getOutput(stream,
+                                                 samplingRate,
+                                                 format,
+                                                 channels,
+                                                 flags);
+            reply->write(&output, sizeof(audio_io_handle_t));
+            return NO_ERROR;
+        } break;
+
+        case START_OUTPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_io_handle_t output;
+            data.read(&output, sizeof(audio_io_handle_t));
+            uint32_t stream = data.readInt32();
+            reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream)));
+            return NO_ERROR;
+        } break;
+
+        case STOP_OUTPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_io_handle_t output;
+            data.read(&output, sizeof(audio_io_handle_t));
+            uint32_t stream = data.readInt32();
+            reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream)));
+            return NO_ERROR;
+        } break;
+
+        case RELEASE_OUTPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_io_handle_t output;
+            data.read(&output, sizeof(audio_io_handle_t));
+            releaseOutput(output);
+            return NO_ERROR;
+        } break;
+
+        case GET_INPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            int inputSource = data.readInt32();
+            uint32_t samplingRate = data.readInt32();
+            uint32_t format = data.readInt32();
+            uint32_t channels = data.readInt32();
+            AudioSystem::audio_in_acoustics acoustics = static_cast <AudioSystem::audio_in_acoustics>(data.readInt32());
+            audio_io_handle_t input = getInput(inputSource,
+                                               samplingRate,
+                                               format,
+                                               channels,
+                                               acoustics);
+            reply->write(&input, sizeof(audio_io_handle_t));
+            return NO_ERROR;
+        } break;
+
+        case START_INPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_io_handle_t input;
+            data.read(&input, sizeof(audio_io_handle_t));
+            reply->writeInt32(static_cast <uint32_t>(startInput(input)));
+            return NO_ERROR;
+        } break;
+
+        case STOP_INPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_io_handle_t input;
+            data.read(&input, sizeof(audio_io_handle_t));
+            reply->writeInt32(static_cast <uint32_t>(stopInput(input)));
+            return NO_ERROR;
+        } break;
+
+        case RELEASE_INPUT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_io_handle_t input;
+            data.read(&input, sizeof(audio_io_handle_t));
+            releaseInput(input);
+            return NO_ERROR;
+        } break;
+
+        case INIT_STREAM_VOLUME: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            int indexMin = data.readInt32();
+            int indexMax = data.readInt32();
+            reply->writeInt32(static_cast <uint32_t>(initStreamVolume(stream, indexMin,indexMax)));
+            return NO_ERROR;
+        } break;
+
+        case SET_STREAM_VOLUME: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            int index = data.readInt32();
+            reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index)));
+            return NO_ERROR;
+        } break;
+
+        case GET_STREAM_VOLUME: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            int index;
+            status_t status = getStreamVolumeIndex(stream, &index);
+            reply->writeInt32(index);
+            reply->writeInt32(static_cast <uint32_t>(status));
+            return NO_ERROR;
+        } break;
+
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 6e42dac..8fb5d3d 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -18,7 +18,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
 
 #include <media/IAudioRecord.h>
 
@@ -66,12 +66,6 @@
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnAudioRecord::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index abc202d..75b861b 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -18,7 +18,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
 
 #include <media/IAudioTrack.h>
 
@@ -91,12 +91,6 @@
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnAudioTrack::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 85b5944..397a55b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -17,7 +17,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
 #include <SkBitmap.h>
 #include <media/IMediaMetadataRetriever.h>
 
@@ -126,16 +126,10 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadataRetriever");
+IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnMediaMetadataRetriever::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -215,4 +209,3 @@
 // ----------------------------------------------------------------------------
 
 }; // namespace android
-
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index f18765a..5d9db10 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -18,7 +18,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
 
 #include <media/IMediaPlayer.h>
 #include <ui/ISurface.h>
@@ -39,7 +39,10 @@
     RESET,
     SET_AUDIO_STREAM_TYPE,
     SET_LOOPING,
-    SET_VOLUME
+    SET_VOLUME,
+    INVOKE,
+    SET_METADATA_FILTER,
+    GET_METADATA,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -170,18 +173,38 @@
         remote()->transact(SET_VOLUME, data, &reply);
         return reply.readInt32();
     }
+
+    status_t invoke(const Parcel& request, Parcel *reply)
+    { // Avoid doing any extra copy. The interface descriptor should
+      // have been set by MediaPlayer.java.
+        return remote()->transact(INVOKE, request, reply);
+    }
+
+    status_t setMetadataFilter(const Parcel& request)
+    {
+        Parcel reply;
+        // Avoid doing any extra copy of the request. The interface
+        // descriptor should have been set by MediaPlayer.java.
+        remote()->transact(SET_METADATA_FILTER, request, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
+    {
+        Parcel request;
+        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
+        request.writeInt32(update_only);
+        request.writeInt32(apply_filter);
+        remote()->transact(GET_METADATA, request, reply);
+        return reply->readInt32();
+    }
 };
 
-IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
+IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnMediaPlayer::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -266,6 +289,24 @@
             reply->writeInt32(setVolume(data.readFloat(), data.readFloat()));
             return NO_ERROR;
         } break;
+        case INVOKE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            invoke(data, reply);
+            return NO_ERROR;
+        } break;
+        case SET_METADATA_FILTER: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(setMetadataFilter(data));
+            return NO_ERROR;
+        } break;
+        case GET_METADATA: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply);
+            reply->setDataPosition(0);
+            reply->writeInt32(retcode);
+            reply->setDataPosition(0);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
@@ -274,4 +315,3 @@
 // ----------------------------------------------------------------------------
 
 }; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index 65022cd..bf51829 100644
--- a/media/libmedia/IMediaPlayerClient.cpp
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -16,8 +16,8 @@
 */
 
 #include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
 
 #include <media/IMediaPlayerClient.h>
 
@@ -46,16 +46,10 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
+IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.media.IMediaPlayerClient");
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnMediaPlayerClient::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -74,4 +68,3 @@
 }
 
 }; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 01cdb6c..8d2c360 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -17,11 +17,14 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#include <utils/Parcel.h>
 
-#include <utils/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
 #include <media/IMediaPlayerService.h>
 #include <media/IMediaRecorder.h>
+#include <media/IOMX.h>
+
+#include <utils/Errors.h>  // for status_t
 
 namespace android {
 
@@ -32,6 +35,7 @@
     DECODE_FD,
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
+    CREATE_OMX,
 };
 
 class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -109,18 +113,19 @@
         *pFormat = reply.readInt32();
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
+
+    virtual sp<IOMX> createOMX() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        remote()->transact(CREATE_OMX, data, &reply);
+        return interface_cast<IOMX>(reply.readStrongBinder());
+    }
 };
 
-IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
+IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-            LOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
 status_t BnMediaPlayerService::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -187,6 +192,12 @@
             reply->writeStrongBinder(retriever->asBinder());
             return NO_ERROR;
         } break;
+        case CREATE_OMX: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            sp<IOMX> omx = createOMX();
+            reply->writeStrongBinder(omx->asBinder());
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 84d08c4..df7d301 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -18,7 +18,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "IMediaRecorder"
 #include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
 #include <ui/ISurface.h>
 #include <ui/ICamera.h>
 #include <media/IMediaPlayerClient.h>
@@ -264,16 +264,10 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
+IMPLEMENT_META_INTERFACE(MediaRecorder, "android.media.IMediaRecorder");
 
 // ----------------------------------------------------------------------
 
-#define CHECK_INTERFACE(interface, data, reply) \
-    do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
-        LOGW("Call incorrectly routed to " #interface); \
-        return PERMISSION_DENIED; \
-    } } while (0)
-
 status_t BnMediaRecorder::onTransact(
                                      uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
new file mode 100644
index 0000000..f2a657a
--- /dev/null
+++ b/media/libmedia/IOMX.cpp
@@ -0,0 +1,561 @@
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IOMX"
+#include <utils/Log.h>
+
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IOMX.h>
+
+namespace android {
+
+enum {
+    CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    LIST_NODES,
+    ALLOCATE_NODE,
+    FREE_NODE,
+    SEND_COMMAND,
+    GET_PARAMETER,
+    SET_PARAMETER,
+    USE_BUFFER,
+    ALLOC_BUFFER,
+    ALLOC_BUFFER_WITH_BACKUP,
+    FREE_BUFFER,
+    OBSERVE_NODE,
+    FILL_BUFFER,
+    EMPTY_BUFFER,
+    OBSERVER_ON_MSG,
+};
+
+static void *readVoidStar(const Parcel *parcel) {
+    // FIX if sizeof(void *) != sizeof(int32)
+    return (void *)parcel->readInt32();
+}
+
+static void writeVoidStar(void *x, Parcel *parcel) {
+    // FIX if sizeof(void *) != sizeof(int32)
+    parcel->writeInt32((int32_t)x);
+}
+
+class BpOMX : public BpInterface<IOMX> {
+public:
+    BpOMX(const sp<IBinder> &impl)
+        : BpInterface<IOMX>(impl) {
+    }
+
+#if IOMX_USES_SOCKETS
+    virtual status_t connect(int *sd) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        remote()->transact(CONNECT, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err == OK) {
+            *sd = dup(reply.readFileDescriptor());
+        } else {
+            *sd = -1;
+        }
+
+        return reply.readInt32();
+    }
+#endif
+
+    virtual status_t list_nodes(List<String8> *list) {
+        list->clear();
+
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        remote()->transact(LIST_NODES, data, &reply);
+
+        int32_t n = reply.readInt32();
+        for (int32_t i = 0; i < n; ++i) {
+            String8 s = reply.readString8();
+
+            list->push_back(s);
+        }
+
+        return OK;
+    }
+
+    virtual status_t allocate_node(const char *name, node_id *node) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        data.writeCString(name);
+        remote()->transact(ALLOCATE_NODE, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err == OK) {
+            *node = readVoidStar(&reply);
+        } else {
+            *node = 0;
+        }
+
+        return err;
+    }
+
+    virtual status_t free_node(node_id node) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        remote()->transact(FREE_NODE, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual status_t send_command(
+            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(cmd);
+        data.writeInt32(param);
+        remote()->transact(SEND_COMMAND, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual status_t get_parameter(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(index);
+        data.writeInt32(size);
+        data.write(params, size);
+        remote()->transact(GET_PARAMETER, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err != OK) {
+            return err;
+        }
+
+        reply.read(params, size);
+
+        return OK;
+    }
+
+    virtual status_t set_parameter(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(index);
+        data.writeInt32(size);
+        data.write(params, size);
+        remote()->transact(SET_PARAMETER, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual status_t use_buffer(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(port_index);
+        data.writeStrongBinder(params->asBinder());
+        remote()->transact(USE_BUFFER, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err != OK) {
+            *buffer = 0;
+
+            return err;
+        }
+
+        *buffer = readVoidStar(&reply);
+
+        return err;
+    }
+
+    virtual status_t allocate_buffer(
+            node_id node, OMX_U32 port_index, size_t size,
+            buffer_id *buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(port_index);
+        data.writeInt32(size);
+        remote()->transact(ALLOC_BUFFER, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err != OK) {
+            *buffer = 0;
+
+            return err;
+        }
+
+        *buffer = readVoidStar(&reply);
+
+        return err;
+    }
+
+    virtual status_t allocate_buffer_with_backup(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(port_index);
+        data.writeStrongBinder(params->asBinder());
+        remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (err != OK) {
+            *buffer = 0;
+
+            return err;
+        }
+
+        *buffer = readVoidStar(&reply);
+
+        return err;
+    }
+
+    virtual status_t free_buffer(
+            node_id node, OMX_U32 port_index, buffer_id buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeInt32(port_index);
+        writeVoidStar(buffer, &data);
+        remote()->transact(FREE_BUFFER, data, &reply);
+
+        return reply.readInt32();
+    }
+
+#if !IOMX_USES_SOCKETS
+    virtual status_t observe_node(
+            node_id node, const sp<IOMXObserver> &observer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        data.writeStrongBinder(observer->asBinder());
+        remote()->transact(OBSERVE_NODE, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual void fill_buffer(node_id node, buffer_id buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        writeVoidStar(buffer, &data);
+        remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void empty_buffer(
+            node_id node,
+            buffer_id buffer,
+            OMX_U32 range_offset, OMX_U32 range_length,
+            OMX_U32 flags, OMX_TICKS timestamp) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        writeVoidStar(node, &data);
+        writeVoidStar(buffer, &data);
+        data.writeInt32(range_offset);
+        data.writeInt32(range_length);
+        data.writeInt32(flags);
+        data.writeInt64(timestamp);
+        remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+#endif
+};
+
+IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnOMX::onTransact(
+    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+    switch (code) {
+#if IOMX_USES_SOCKETS
+        case CONNECT:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            int s;
+            status_t err = connect(&s);
+            
+            reply->writeInt32(err);
+            if (err == OK) {
+                assert(s >= 0);
+                reply->writeDupFileDescriptor(s);
+                close(s);
+                s = -1;
+            } else {
+                assert(s == -1);
+            }
+
+            return NO_ERROR;
+        }
+#endif
+
+        case LIST_NODES:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            List<String8> list;
+            list_nodes(&list);
+
+            reply->writeInt32(list.size());
+            for (List<String8>::iterator it = list.begin();
+                 it != list.end(); ++it) {
+                reply->writeString8(*it);
+            }
+
+            return NO_ERROR;
+        }
+
+        case ALLOCATE_NODE:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node;
+            status_t err = allocate_node(data.readCString(), &node);
+            reply->writeInt32(err);
+            if (err == OK) {
+                writeVoidStar(node, reply);
+            }
+                
+            return NO_ERROR;
+        }
+
+        case FREE_NODE:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+
+            reply->writeInt32(free_node(node));
+                
+            return NO_ERROR;
+        }
+
+        case SEND_COMMAND:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+
+            OMX_COMMANDTYPE cmd =
+                static_cast<OMX_COMMANDTYPE>(data.readInt32());
+
+            OMX_S32 param = data.readInt32();
+            reply->writeInt32(send_command(node, cmd, param));
+
+            return NO_ERROR;
+        }
+
+        case GET_PARAMETER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+            size_t size = data.readInt32();
+
+            // XXX I am not happy with this but Parcel::readInplace didn't work.
+            void *params = malloc(size);
+            data.read(params, size);
+
+            status_t err = get_parameter(node, index, params, size);
+
+            reply->writeInt32(err);
+
+            if (err == OK) {
+                reply->write(params, size);
+            }
+
+            free(params);
+            params = NULL;
+
+            return NO_ERROR;
+        }
+
+        case SET_PARAMETER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+            size_t size = data.readInt32();
+            void *params = const_cast<void *>(data.readInplace(size));
+
+            reply->writeInt32(set_parameter(node, index, params, size));
+
+            return NO_ERROR;
+        }
+
+        case USE_BUFFER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_U32 port_index = data.readInt32();
+            sp<IMemory> params =
+                interface_cast<IMemory>(data.readStrongBinder());
+
+            buffer_id buffer;
+            status_t err = use_buffer(node, port_index, params, &buffer);
+            reply->writeInt32(err);
+
+            if (err == OK) {
+                writeVoidStar(buffer, reply);
+            }
+
+            return NO_ERROR;
+        }
+
+        case ALLOC_BUFFER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_U32 port_index = data.readInt32();
+            size_t size = data.readInt32();
+
+            buffer_id buffer;
+            status_t err = allocate_buffer(node, port_index, size, &buffer);
+            reply->writeInt32(err);
+
+            if (err == OK) {
+                writeVoidStar(buffer, reply);
+            }
+
+            return NO_ERROR;
+        }
+
+        case ALLOC_BUFFER_WITH_BACKUP:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_U32 port_index = data.readInt32();
+            sp<IMemory> params =
+                interface_cast<IMemory>(data.readStrongBinder());
+
+            buffer_id buffer;
+            status_t err = allocate_buffer_with_backup(
+                    node, port_index, params, &buffer);
+
+            reply->writeInt32(err);
+
+            if (err == OK) {
+                writeVoidStar(buffer, reply);
+            }
+
+            return NO_ERROR;
+        }
+
+        case FREE_BUFFER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            OMX_U32 port_index = data.readInt32();
+            buffer_id buffer = readVoidStar(&data);
+            reply->writeInt32(free_buffer(node, port_index, buffer));
+
+            return NO_ERROR;
+        }
+
+#if !IOMX_USES_SOCKETS
+        case OBSERVE_NODE:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            sp<IOMXObserver> observer =
+                interface_cast<IOMXObserver>(data.readStrongBinder());
+            reply->writeInt32(observe_node(node, observer));
+
+            return NO_ERROR;
+        }
+
+        case FILL_BUFFER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            buffer_id buffer = readVoidStar(&data);
+            fill_buffer(node, buffer);
+
+            return NO_ERROR;
+        }
+
+        case EMPTY_BUFFER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = readVoidStar(&data);
+            buffer_id buffer = readVoidStar(&data);
+            OMX_U32 range_offset = data.readInt32();
+            OMX_U32 range_length = data.readInt32();
+            OMX_U32 flags = data.readInt32();
+            OMX_TICKS timestamp = data.readInt64();
+
+            empty_buffer(
+                    node, buffer, range_offset, range_length,
+                    flags, timestamp);
+
+            return NO_ERROR;
+        }
+#endif
+
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BpOMXObserver : public BpInterface<IOMXObserver> {
+public:
+    BpOMXObserver(const sp<IBinder> &impl)
+        : BpInterface<IOMXObserver>(impl) {
+    }
+
+    virtual void on_message(const omx_message &msg) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
+        data.write(&msg, sizeof(msg));
+
+        remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver");
+
+status_t BnOMXObserver::onTransact(
+    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+    switch (code) {
+        case OBSERVER_ON_MSG:
+        {
+            CHECK_INTERFACE(IOMXObserver, data, reply);
+
+            omx_message msg;
+            data.read(&msg, sizeof(msg));
+
+            // XXX Could use readInplace maybe?
+            on_message(msg);
+
+            return NO_ERROR;
+        }
+
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}  // namespace android
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 586aacb..ee9e1d8 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -99,7 +99,7 @@
     mAudioTrack->set(AudioSystem::MUSIC,  //TODO parametrize this
             pLibConfig->sampleRate,
             1, // format = PCM 16bits per sample,
-            pLibConfig->numChannels,
+            (pLibConfig->numChannels == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
             mTrackBufferSize,
             0);
 
diff --git a/media/libmedia/Metadata.cpp b/media/libmedia/Metadata.cpp
new file mode 100644
index 0000000..35ec6b3
--- /dev/null
+++ b/media/libmedia/Metadata.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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 "Metadata"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <media/Metadata.h>
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// This file contains code to serialize Metadata triples (key, type,
+// value) into a parcel. The Parcel is destinated to be decoded by the
+// Metadata.java class.
+
+namespace {
+// All these constants below must be kept in sync with Metadata.java.
+enum MetadataId {
+    FIRST_SYSTEM_ID = 1,
+    LAST_SYSTEM_ID = 31,
+    FIRST_CUSTOM_ID = 8192
+};
+
+// Types
+enum Types {
+    STRING_VAL = 1,
+    INTEGER_VAL,
+    BOOLEAN_VAL,
+    LONG_VAL,
+    DOUBLE_VAL,
+    TIMED_TEXT_VAL,
+    DATE_VAL,
+    BYTE_ARRAY_VAL,
+};
+
+const size_t kRecordHeaderSize = 3 * sizeof(int32_t);
+const int32_t kMetaMarker = 0x4d455441;  // 'M' 'E' 'T' 'A'
+
+}  // anonymous namespace
+
+namespace android {
+namespace media {
+
+Metadata::Metadata(Parcel *p)
+    :mData(p),
+     mBegin(p->dataPosition()) { }
+
+Metadata::~Metadata() { }
+
+void Metadata::resetParcel()
+{
+    mData->setDataPosition(mBegin);
+}
+
+// Update the 4 bytes int at the beginning of the parcel which holds
+// the number of bytes written so far.
+void Metadata::updateLength()
+{
+    const size_t end = mData->dataPosition();
+
+    mData->setDataPosition(mBegin);
+    mData->writeInt32(end - mBegin);
+    mData->setDataPosition(end);
+}
+
+// Write the header. The java layer will look for the marker.
+bool Metadata::appendHeader()
+{
+    bool ok = true;
+
+    // Placeholder for the length of the metadata
+    ok = ok && mData->writeInt32(-1) == OK;
+    ok = ok && mData->writeInt32(kMetaMarker) == OK;
+    return ok;
+}
+
+bool Metadata::appendBool(int key, bool val)
+{
+    if (!checkKey(key)) {
+        return false;
+    }
+
+    const size_t begin = mData->dataPosition();
+    bool ok = true;
+
+    // 4 int32s: size, key, type, value.
+    ok = ok && mData->writeInt32(4 * sizeof(int32_t)) == OK;
+    ok = ok && mData->writeInt32(key) == OK;
+    ok = ok && mData->writeInt32(BOOLEAN_VAL) == OK;
+    ok = ok && mData->writeInt32(val ? 1 : 0) == OK;
+    if (!ok) {
+        mData->setDataPosition(begin);
+    }
+    return ok;
+}
+
+bool Metadata::appendInt32(int key, int32_t val)
+{
+    if (!checkKey(key)) {
+        return false;
+    }
+
+    const size_t begin = mData->dataPosition();
+    bool ok = true;
+
+    // 4 int32s: size, key, type, value.
+    ok = ok && mData->writeInt32(4 * sizeof(int32_t)) == OK;
+    ok = ok && mData->writeInt32(key) == OK;
+    ok = ok && mData->writeInt32(INTEGER_VAL) == OK;
+    ok = ok && mData->writeInt32(val) == OK;
+    if (!ok) {
+        mData->setDataPosition(begin);
+    }
+    return ok;
+}
+
+// Check the key (i.e metadata id) is valid if it is a system one.
+// Loop over all the exiting ones in the Parcel to check for duplicate
+// (not allowed).
+bool Metadata::checkKey(int key)
+{
+    if (key < FIRST_SYSTEM_ID ||
+        (LAST_SYSTEM_ID < key && key < FIRST_CUSTOM_ID)) {
+        LOGE("Bad key %d", key);
+        return false;
+    }
+    size_t curr = mData->dataPosition();
+    // Loop over the keys to check if it has been used already.
+    mData->setDataPosition(mBegin);
+
+    bool error = false;
+    size_t left = curr - mBegin;
+    while (left > 0) {
+        size_t pos = mData->dataPosition();
+        size_t size = mData->readInt32();
+        if (size < kRecordHeaderSize || size > left) {
+            error = true;
+            break;
+        }
+        if (mData->readInt32() == key) {
+            LOGE("Key exists already %d", key);
+            error = true;
+            break;
+        }
+        mData->setDataPosition(pos + size);
+        left -= size;
+    }
+    mData->setDataPosition(curr);
+    return !error;
+}
+
+}  // namespace android::media
+}  // namespace android
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 5435da7..3ea64ae 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -1001,7 +1001,7 @@
 
    // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
     mpAudioTrack
-            = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0);
+            = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, AudioSystem::CHANNEL_OUT_MONO, 0, 0, audioCallback, this, 0);
 
     if (mpAudioTrack == 0) {
         LOGE("AudioTrack allocation failed");
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 09afc6c..d34a8ed 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -18,8 +18,8 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaMetadataRetriever"
 
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
 #include <media/mediametadataretriever.h>
 #include <media/IMediaPlayerService.h>
 #include <utils/Log.h>
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 24e3e6f..aeb43c5 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -24,13 +24,13 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
 
 #include <media/mediaplayer.h>
 #include <media/AudioTrack.h>
 
-#include <utils/MemoryBase.h>
+#include <binder/MemoryBase.h>
 
 namespace android {
 
@@ -196,12 +196,47 @@
     return err;
 }
 
+status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
+{
+    Mutex::Autolock _l(mLock);
+    if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED ))
+    {
+         LOGV("invoke %d", request.dataSize());
+         return  mPlayer->invoke(request, reply);
+    }
+    LOGE("invoke failed: wrong state %X", mCurrentState);
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
+{
+    LOGD("setMetadataFilter");
+    Mutex::Autolock lock(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+    return mPlayer->setMetadataFilter(filter);
+}
+
+status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
+{
+    LOGD("getMetadata");
+    Mutex::Autolock lock(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+    return mPlayer->getMetadata(update_only, apply_filter, metadata);
+}
+
 status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
 {
     LOGV("setVideoSurface");
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return NO_INIT;
-    return  mPlayer->setVideoSurface(surface->getISurface());
+    if (surface != NULL)
+        return  mPlayer->setVideoSurface(surface->getISurface());
+    else
+        return  mPlayer->setVideoSurface(NULL);
 }
 
 // must call with lock held
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 5093f0e..6b63931 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -20,7 +20,7 @@
 #include <utils/Log.h>
 #include <ui/Surface.h>
 #include <media/mediarecorder.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
 #include <utils/String8.h>
 #include <media/IMediaPlayerService.h>
 #include <media/IMediaRecorder.h>
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f7f2490..f74ef3a 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -10,6 +10,7 @@
     MediaRecorderClient.cpp \
     MediaPlayerService.cpp \
     MetadataRetrieverClient.cpp \
+    TestPlayerStub.cpp \
     VorbisPlayer.cpp \
     MidiFile.cpp
 
@@ -20,6 +21,7 @@
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libutils \
+	libbinder \
     libvorbisidec \
     libsonivox \
     libopencore_player \
@@ -27,10 +29,27 @@
     libmedia \
     libandroid_runtime
 
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
 LOCAL_C_INCLUDES := external/tremor/Tremor \
-    $(call include-path-for, graphics corecg)
+	$(call include-path-for, graphics corecg) \
+	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
 
 LOCAL_MODULE:= libmediaplayerservice
 
+ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
+    LOCAL_SRC_FILES += StagefrightPlayer.cpp
+
+    LOCAL_SHARED_LIBRARIES += \
+	libstagefright        \
+	libstagefright_omx
+
+    LOCAL_C_INCLUDES += $(TOP)/frameworks/base/media/libstagefright/omx
+
+    LOCAL_CFLAGS += -DBUILD_WITH_STAGEFRIGHT -DUSE_STAGEFRIGHT
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 31eecac..95d61cd 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -27,18 +27,27 @@
 #include <unistd.h>
 
 #include <string.h>
+
 #include <cutils/atomic.h>
+#include <cutils/properties.h> // for property_get
+
+#include <utils/misc.h>
 
 #include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <utils/Errors.h>  // for status_t
+#include <utils/String8.h>
+#include <utils/Vector.h>
 #include <cutils/properties.h>
 
 #include <media/MediaPlayerInterface.h>
 #include <media/mediarecorder.h>
 #include <media/MediaMetadataRetrieverInterface.h>
+#include <media/Metadata.h>
 #include <media/AudioTrack.h>
 
 #include "MediaRecorderClient.h"
@@ -48,6 +57,21 @@
 #include "MidiFile.h"
 #include "VorbisPlayer.h"
 #include <media/PVPlayer.h>
+#include "TestPlayerStub.h"
+
+//#undef USE_STAGEFRIGHT
+
+#if USE_STAGEFRIGHT
+#include "StagefrightPlayer.h"
+#endif
+
+#ifdef BUILD_WITH_STAGEFRIGHT
+#include <OMX.h>
+#else
+#include <media/IOMX.h>
+#endif
+
+
 
 /* desktop Linux needs a little help with gettid() */
 #if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
@@ -61,6 +85,111 @@
 #undef __KERNEL__
 #endif
 
+namespace {
+using android::media::Metadata;
+using android::status_t;
+using android::OK;
+using android::BAD_VALUE;
+using android::NOT_ENOUGH_DATA;
+using android::Parcel;
+
+// Max number of entries in the filter.
+const int kMaxFilterSize = 64;  // I pulled that out of thin air.
+
+// FIXME: Move all the metadata related function in the Metadata.cpp
+
+
+// Unmarshall a filter from a Parcel.
+// Filter format in a parcel:
+//
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       number of entries (n)                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 1                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 2                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type n                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that should start with a filter.
+// @param[out] filter On exit contains the list of metadata type to be
+//                    filtered.
+// @param[out] status On exit contains the status code to be returned.
+// @return true if the parcel starts with a valid filter.
+bool unmarshallFilter(const Parcel& p,
+                      Metadata::Filter *filter,
+                      status_t *status)
+{
+    int32_t val;
+    if (p.readInt32(&val) != OK)
+    {
+        LOGE("Failed to read filter's length");
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    if( val > kMaxFilterSize || val < 0)
+    {
+        LOGE("Invalid filter len %d", val);
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    const size_t num = val;
+
+    filter->clear();
+    filter->setCapacity(num);
+
+    size_t size = num * sizeof(Metadata::Type);
+
+
+    if (p.dataAvail() < size)
+    {
+        LOGE("Filter too short expected %d but got %d", size, p.dataAvail());
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    const Metadata::Type *data =
+            static_cast<const Metadata::Type*>(p.readInplace(size));
+
+    if (NULL == data)
+    {
+        LOGE("Filter had no data");
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    // TODO: The stl impl of vector would be more efficient here
+    // because it degenerates into a memcpy on pod types. Try to
+    // replace later or use stl::set.
+    for (size_t i = 0; i < num; ++i)
+    {
+        filter->add(*data);
+        ++data;
+    }
+    *status = OK;
+    return true;
+}
+
+// @param filter Of metadata type.
+// @param val To be searched.
+// @return true if a match was found.
+bool findMetadata(const Metadata::Filter& filter, const int32_t val)
+{
+    // Deal with empty and ANY right away
+    if (filter.isEmpty()) return false;
+    if (filter[0] == Metadata::kAny) return true;
+
+    return filter.indexOf(val) >= 0;
+}
+
+}  // anonymous namespace
+
 
 namespace android {
 
@@ -70,6 +199,10 @@
     const player_type playertype;
 } extmap;
 extmap FILE_EXTS [] =  {
+#if USE_STAGEFRIGHT
+        {".mp4", STAGEFRIGHT_PLAYER},
+        {".3gp", STAGEFRIGHT_PLAYER},
+#endif
         {".mid", SONIVOX_PLAYER},
         {".midi", SONIVOX_PLAYER},
         {".smf", SONIVOX_PLAYER},
@@ -105,7 +238,11 @@
 
 sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
 {
+#ifndef NO_OPENCORE
     sp<MediaRecorderClient> recorder = new MediaRecorderClient(pid);
+#else
+    sp<MediaRecorderClient> recorder = NULL;
+#endif
     LOGV("Create new media recorder client from pid %d", pid);
     return recorder;
 }
@@ -151,6 +288,14 @@
     return c;
 }
 
+sp<IOMX> MediaPlayerService::createOMX() {
+#ifdef BUILD_WITH_STAGEFRIGHT
+    return new OMX;
+#else
+    return NULL;
+#endif
+}
+
 status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
 {
     const size_t SIZE = 256;
@@ -457,6 +602,7 @@
         p = mPlayer;
     }
     mClient.clear();
+
     mPlayer.clear();
 
     // clear the notification to prevent callbacks to dead client
@@ -504,12 +650,19 @@
         EAS_Shutdown(easdata);
     }
 
+#if USE_STAGEFRIGHT
+    return STAGEFRIGHT_PLAYER;
+#endif
+
     // Fall through to PV
     return PV_PLAYER;
 }
 
 static player_type getPlayerType(const char* url)
 {
+    if (TestPlayerStub::canBeUsed(url)) {
+        return TEST_PLAYER;
+    }
 
     // use MidiFile for MIDI extensions
     int lenURL = strlen(url);
@@ -523,6 +676,10 @@
         }
     }
 
+#if USE_STAGEFRIGHT
+    return STAGEFRIGHT_PLAYER;
+#endif
+
     // Fall through to PV
     return PV_PLAYER;
 }
@@ -532,10 +689,12 @@
 {
     sp<MediaPlayerBase> p;
     switch (playerType) {
+#ifndef NO_OPENCORE
         case PV_PLAYER:
             LOGV(" create PVPlayer");
             p = new PVPlayer();
             break;
+#endif
         case SONIVOX_PLAYER:
             LOGV(" create MidiFile");
             p = new MidiFile();
@@ -544,6 +703,21 @@
             LOGV(" create VorbisPlayer");
             p = new VorbisPlayer();
             break;
+#if USE_STAGEFRIGHT
+        case STAGEFRIGHT_PLAYER:
+            LOGV(" create StagefrightPlayer");
+            p = new StagefrightPlayer;
+            break;
+#else
+        case STAGEFRIGHT_PLAYER:
+            LOG_ALWAYS_FATAL(
+                    "Should not be here, stagefright player not enabled.");
+            break;
+#endif
+        case TEST_PLAYER:
+            LOGV("Create Test Player stub");
+            p = new TestPlayerStub();
+            break;
     }
     if (p != NULL) {
         if (p->initCheck() == NO_ERROR) {
@@ -608,7 +782,11 @@
         // now set data source
         LOGV(" setDataSource");
         mStatus = p->setDataSource(url);
-        if (mStatus == NO_ERROR) mPlayer = p;
+        if (mStatus == NO_ERROR) {
+            mPlayer = p;
+        } else {
+            LOGE("  error: %d", mStatus);
+        }
         return mStatus;
     }
 }
@@ -665,6 +843,73 @@
     return p->setVideoSurface(surface);
 }
 
+status_t MediaPlayerService::Client::invoke(const Parcel& request,
+                                            Parcel *reply)
+{
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == NULL) return UNKNOWN_ERROR;
+    return p->invoke(request, reply);
+}
+
+// This call doesn't need to access the native player.
+status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
+{
+    status_t status;
+    media::Metadata::Filter allow, drop;
+
+    if (unmarshallFilter(filter, &allow, &status) &&
+        unmarshallFilter(filter, &drop, &status)) {
+        Mutex::Autolock lock(mLock);
+
+        mMetadataAllow = allow;
+        mMetadataDrop = drop;
+    }
+    return status;
+}
+
+status_t MediaPlayerService::Client::getMetadata(
+        bool update_only, bool apply_filter, Parcel *reply)
+{
+    sp<MediaPlayerBase> player = getPlayer();
+    if (player == 0) return UNKNOWN_ERROR;
+
+    status_t status;
+    // Placeholder for the return code, updated by the caller.
+    reply->writeInt32(-1);
+
+    media::Metadata::Filter ids;
+
+    // We don't block notifications while we fetch the data. We clear
+    // mMetadataUpdated first so we don't lose notifications happening
+    // during the rest of this call.
+    {
+        Mutex::Autolock lock(mLock);
+        if (update_only) {
+            ids = mMetadataUpdated;
+        }
+        mMetadataUpdated.clear();
+    }
+
+    media::Metadata metadata(reply);
+
+    metadata.appendHeader();
+    status = player->getMetadata(ids, reply);
+
+    if (status != OK) {
+        metadata.resetParcel();
+        LOGE("getMetadata failed %d", status);
+        return status;
+    }
+
+    // FIXME: Implement filtering on the result. Not critical since
+    // filtering takes place on the update notifications already. This
+    // would be when all the metadata are fetch and a filter is set.
+
+    // Everything is fine, update the metadata length.
+    metadata.updateLength();
+    return OK;
+}
+
 status_t MediaPlayerService::Client::prepareAsync()
 {
     LOGV("[%d] prepareAsync", mConnId);
@@ -784,13 +1029,51 @@
     return NO_ERROR;
 }
 
+
 void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
 {
     Client* client = static_cast<Client*>(cookie);
+
+    if (MEDIA_INFO == msg &&
+        MEDIA_INFO_METADATA_UPDATE == ext1) {
+        const media::Metadata::Type metadata_type = ext2;
+
+        if(client->shouldDropMetadata(metadata_type)) {
+            return;
+        }
+
+        // Update the list of metadata that have changed. getMetadata
+        // also access mMetadataUpdated and clears it.
+        client->addNewMetadataUpdate(metadata_type);
+    }
     LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
     client->mClient->notify(msg, ext1, ext2);
 }
 
+
+bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
+{
+    Mutex::Autolock lock(mLock);
+
+    if (findMetadata(mMetadataDrop, code)) {
+        return true;
+    }
+
+    if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+
+void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
+    Mutex::Autolock lock(mLock);
+    if (mMetadataUpdated.indexOf(metadata_type) < 0) {
+        mMetadataUpdated.add(metadata_type);
+    }
+}
+
 #if CALLBACK_ANTAGONIZER
 const int Antagonizer::interval = 10000; // 10 msecs
 
@@ -927,7 +1210,8 @@
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
 MediaPlayerService::AudioOutput::AudioOutput()
-{
+    : mCallback(NULL),
+      mCallbackCookie(NULL) {
     mTrack = 0;
     mStreamType = AudioSystem::MUSIC;
     mLeftVolume = 1.0;
@@ -997,8 +1281,13 @@
     return mMsecsPerFrame;
 }
 
-status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+status_t MediaPlayerService::AudioOutput::open(
+        uint32_t sampleRate, int channelCount, int format, int bufferCount,
+        AudioCallback cb, void *cookie)
 {
+    mCallback = cb;
+    mCallbackCookie = cookie;
+
     // Check argument "bufferCount" against the mininum buffer count
     if (bufferCount < mMinBufferCount) {
         LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
@@ -1019,7 +1308,27 @@
     }
 
     frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
-    AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount);
+
+    AudioTrack *t;
+    if (mCallback != NULL) {
+        t = new AudioTrack(
+                mStreamType,
+                sampleRate,
+                format,
+                (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
+                frameCount,
+                0 /* flags */,
+                CallbackWrapper,
+                this);
+    } else {
+        t = new AudioTrack(
+                mStreamType,
+                sampleRate,
+                format,
+                (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
+                frameCount);
+    }
+
     if ((t == 0) || (t->initCheck() != NO_ERROR)) {
         LOGE("Unable to create audio track");
         delete t;
@@ -1045,6 +1354,8 @@
 
 ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
 {
+    LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+
     //LOGV("write(%p, %u)", buffer, size);
     if (mTrack) return mTrack->write(buffer, size);
     return NO_INIT;
@@ -1085,6 +1396,20 @@
     }
 }
 
+// static
+void MediaPlayerService::AudioOutput::CallbackWrapper(
+        int event, void *cookie, void *info) {
+    if (event != AudioTrack::EVENT_MORE_DATA) {
+        return;
+    }
+
+    AudioOutput *me = (AudioOutput *)cookie;
+    AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+
+    (*me->mCallback)(
+            me, buffer->raw, buffer->size, me->mCallbackCookie);
+}
+
 #undef LOG_TAG
 #define LOG_TAG "AudioCache"
 MediaPlayerService::AudioCache::AudioCache(const char* name) :
@@ -1105,8 +1430,14 @@
     return mMsecsPerFrame;
 }
 
-status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+status_t MediaPlayerService::AudioCache::open(
+        uint32_t sampleRate, int channelCount, int format, int bufferCount,
+        AudioCallback cb, void *cookie)
 {
+    if (cb != NULL) {
+        return UNKNOWN_ERROR;  // TODO: implement this.
+    }
+
     LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
     if (mHeap->getHeapID() < 0) return NO_INIT;
     mSampleRate = sampleRate;
@@ -1171,4 +1502,4 @@
     p->mSignal.signal();
 }
 
-}; // namespace android
+} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index f138886..a4be414 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -18,17 +18,23 @@
 #ifndef ANDROID_MEDIAPLAYERSERVICE_H
 #define ANDROID_MEDIAPLAYERSERVICE_H
 
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
 #include <utils/KeyedVector.h>
+#include <utils/Vector.h>
 #include <ui/SurfaceComposerClient.h>
 
 #include <media/IMediaPlayerService.h>
 #include <media/MediaPlayerInterface.h>
+#include <media/Metadata.h>
 
 namespace android {
 
 class IMediaRecorder;
 class IMediaMetadataRetriever;
+class IOMX;
 
 #define CALLBACK_ANTAGONIZER 0
 #if CALLBACK_ANTAGONIZER
@@ -69,7 +75,12 @@
         virtual ssize_t         frameSize() const;
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
-        virtual status_t        open(uint32_t sampleRate, int channelCount, int format, int bufferCount=4);
+
+        virtual status_t        open(
+                uint32_t sampleRate, int channelCount,
+                int format, int bufferCount,
+                AudioCallback cb, void *cookie);
+
         virtual void            start();
         virtual ssize_t         write(const void* buffer, size_t size);
         virtual void            stop();
@@ -84,8 +95,12 @@
         static int              getMinBufferCount();
     private:
         static void             setMinBufferCount();
+        static void             CallbackWrapper(
+                int event, void *me, void *info);
 
         AudioTrack*             mTrack;
+        AudioCallback           mCallback;
+        void *                  mCallbackCookie;
         int                     mStreamType;
         float                   mLeftVolume;
         float                   mRightVolume;
@@ -113,7 +128,12 @@
         virtual ssize_t         frameSize() const { return ssize_t(mChannelCount * ((mFormat == AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
-        virtual status_t        open(uint32_t sampleRate, int channelCount, int format, int bufferCount=1);
+
+        virtual status_t        open(
+                uint32_t sampleRate, int channelCount, int format,
+                int bufferCount = 1,
+                AudioCallback cb = NULL, void *cookie = NULL);
+
         virtual void            start() {}
         virtual ssize_t         write(const void* buffer, size_t size);
         virtual void            stop() {}
@@ -140,7 +160,7 @@
         sp<MemoryHeapBase>  mHeap;
         float               mMsecsPerFrame;
         uint16_t            mChannelCount;
-        uint16_t			mFormat;
+        uint16_t            mFormat;
         ssize_t             mFrameCount;
         uint32_t            mSampleRate;
         uint32_t            mSize;
@@ -160,11 +180,13 @@
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+    virtual sp<IOMX>            createOMX();
 
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
             void                removeClient(wp<Client> client);
 
+
 private:
 
     class Client : public BnMediaPlayer {
@@ -184,6 +206,11 @@
         virtual status_t        setAudioStreamType(int type);
         virtual status_t        setLooping(int loop);
         virtual status_t        setVolume(float leftVolume, float rightVolume);
+        virtual status_t        invoke(const Parcel& request, Parcel *reply);
+        virtual status_t        setMetadataFilter(const Parcel& filter);
+        virtual status_t        getMetadata(bool update_only,
+                                            bool apply_filter,
+                                            Parcel *reply);
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
                 status_t        setDataSource(const char *url);
@@ -206,6 +233,18 @@
 
         sp<MediaPlayerBase>     getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
 
+
+
+        // @param type Of the metadata to be tested.
+        // @return true if the metadata should be dropped according to
+        //              the filters.
+        bool shouldDropMetadata(media::Metadata::Type type) const;
+
+        // Add a new element to the set of metadata updated. Noop if
+        // the element exists already.
+        // @param type Of the metadata to be recorded.
+        void addNewMetadataUpdate(media::Metadata::Type type);
+
         mutable     Mutex                       mLock;
                     sp<MediaPlayerBase>         mPlayer;
                     sp<MediaPlayerService>      mService;
@@ -215,6 +254,17 @@
                     status_t                    mStatus;
                     bool                        mLoop;
                     int32_t                     mConnId;
+
+        // Metadata filters.
+        media::Metadata::Filter mMetadataAllow;  // protected by mLock
+        media::Metadata::Filter mMetadataDrop;  // protected by mLock
+
+        // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
+        // notification we try to update mMetadataUpdated which is a
+        // set: no duplicate.
+        // getMetadata clears this set.
+        media::Metadata::Filter mMetadataUpdated;  // protected by mLock
+
 #if CALLBACK_ANTAGONIZER
                     Antagonizer*                mAntagonizer;
 #endif
@@ -235,4 +285,3 @@
 }; // namespace android
 
 #endif // ANDROID_MEDIAPLAYERSERVICE_H
-
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 8bc410c..e54f20d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -25,10 +25,10 @@
 #include <string.h>
 #include <cutils/atomic.h>
 #include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
 #include <media/PVMediaRecorder.h>
 #include <utils/String16.h>
 
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index a320bd5..ba8d9a8 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -26,10 +26,10 @@
 
 #include <string.h>
 #include <cutils/atomic.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
 #include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/PVMetadataRetriever.h>
@@ -49,7 +49,11 @@
     mThumbnail = NULL;
     mAlbumArt = NULL;
 
+#ifndef NO_OPENCORE
     mRetriever = new PVMetadataRetriever();
+#else
+    mRetriever = NULL;
+#endif
     if (mRetriever == NULL) {
         LOGE("failed to initialize the retriever");
     }
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index ce29c98..88d50bf 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -18,9 +18,12 @@
 #ifndef ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
 #define ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
 
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
 #include <utils/KeyedVector.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
 
 #include <media/MediaMetadataRetrieverInterface.h>
 
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 302f1cf..25d4a1b 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -46,6 +46,9 @@
     virtual status_t    reset();
     virtual status_t    setLooping(int loop);
     virtual player_type playerType() { return SONIVOX_PLAYER; }
+    virtual status_t    invoke(const Parcel& request, Parcel *reply) {
+        return INVALID_OPERATION;
+    }
 
 private:
             status_t    createOutputTrack();
@@ -74,4 +77,3 @@
 }; // namespace android
 
 #endif // ANDROID_MIDIFILE_H
-
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
new file mode 100644
index 0000000..9a06d13
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -0,0 +1,208 @@
+//#define LOG_NDEBUG 0
+#define LOG_TAG "StagefrightPlayer"
+#include <utils/Log.h>
+
+#include "StagefrightPlayer.h"
+#include <media/stagefright/MediaPlayerImpl.h>
+
+namespace android {
+
+StagefrightPlayer::StagefrightPlayer()
+    : mPlayer(NULL) {
+    LOGV("StagefrightPlayer");
+}
+
+StagefrightPlayer::~StagefrightPlayer() {
+    LOGV("~StagefrightPlayer");
+    reset();
+    LOGV("~StagefrightPlayer done.");
+}
+
+status_t StagefrightPlayer::initCheck() {
+    LOGV("initCheck");
+    return OK;
+}
+
+status_t StagefrightPlayer::setDataSource(const char *url) {
+    LOGV("setDataSource('%s')", url);
+
+    reset();
+    mPlayer = new MediaPlayerImpl(url);
+
+    status_t err = mPlayer->initCheck();
+    if (err != OK) {
+        delete mPlayer;
+        mPlayer = NULL;
+    } else {
+        mPlayer->setAudioSink(mAudioSink);
+    }
+
+    return err;
+}
+
+status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+
+    reset();
+    mPlayer = new MediaPlayerImpl(fd, offset, length);
+
+    status_t err = mPlayer->initCheck();
+    if (err != OK) {
+        delete mPlayer;
+        mPlayer = NULL;
+    } else {
+        mPlayer->setAudioSink(mAudioSink);
+    }
+
+    return err;
+}
+
+status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) {
+    LOGV("setVideoSurface");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    mPlayer->setISurface(surface);
+
+    return OK;
+}
+
+status_t StagefrightPlayer::prepare() {
+    LOGV("prepare");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    sendEvent(
+            MEDIA_SET_VIDEO_SIZE,
+            mPlayer->getWidth(), mPlayer->getHeight());
+
+    return OK;
+}
+
+status_t StagefrightPlayer::prepareAsync() {
+    LOGV("prepareAsync");
+
+    status_t err = prepare();
+
+    if (err != OK) {
+        return err;
+    }
+
+    sendEvent(MEDIA_PREPARED);
+
+    return OK;
+}
+
+status_t StagefrightPlayer::start() {
+    LOGV("start");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    mPlayer->play();
+
+    return OK;
+}
+
+status_t StagefrightPlayer::stop() {
+    LOGV("stop");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    reset();
+
+    return OK;
+}
+
+status_t StagefrightPlayer::pause() {
+    LOGV("pause");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    mPlayer->pause();
+
+    return OK;
+}
+
+bool StagefrightPlayer::isPlaying() {
+    LOGV("isPlaying");
+    return mPlayer != NULL && mPlayer->isPlaying();
+}
+
+status_t StagefrightPlayer::seekTo(int msec) {
+    LOGV("seekTo");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    status_t err = mPlayer->seekTo((int64_t)msec * 1000);
+
+    sendEvent(MEDIA_SEEK_COMPLETE);
+
+    return err;
+}
+
+status_t StagefrightPlayer::getCurrentPosition(int *msec) {
+    LOGV("getCurrentPosition");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    *msec = mPlayer->getPosition() / 1000;
+    return OK;
+}
+
+status_t StagefrightPlayer::getDuration(int *msec) {
+    LOGV("getDuration");
+
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    *msec = mPlayer->getDuration() / 1000;
+    return OK;
+}
+
+status_t StagefrightPlayer::reset() {
+    LOGV("reset");
+
+    delete mPlayer;
+    mPlayer = NULL;
+
+    return OK;
+}
+
+status_t StagefrightPlayer::setLooping(int loop) {
+    LOGV("setLooping");
+    return UNKNOWN_ERROR;
+}
+
+player_type StagefrightPlayer::playerType() {
+    LOGV("playerType");
+    return STAGEFRIGHT_PLAYER;
+}
+
+status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
+    return INVALID_OPERATION;
+}
+
+void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
+    MediaPlayerInterface::setAudioSink(audioSink);
+
+    if (mPlayer != NULL) {
+        mPlayer->setAudioSink(audioSink);
+    }
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
new file mode 100644
index 0000000..f214872
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -0,0 +1,60 @@
+/*
+**
+** 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 ANDROID_STAGEFRIGHTPLAYER_H
+#define ANDROID_STAGEFRIGHTPLAYER_H
+
+#include <media/MediaPlayerInterface.h>
+
+namespace android {
+
+class MediaPlayerImpl;
+
+class StagefrightPlayer : public MediaPlayerInterface {
+public:
+    StagefrightPlayer();
+    virtual ~StagefrightPlayer();
+
+    virtual status_t initCheck();
+    virtual status_t setDataSource(const char *url);
+    virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+    virtual status_t setVideoSurface(const sp<ISurface> &surface);
+    virtual status_t prepare();
+    virtual status_t prepareAsync();
+    virtual status_t start();
+    virtual status_t stop();
+    virtual status_t pause();
+    virtual bool isPlaying();
+    virtual status_t seekTo(int msec);
+    virtual status_t getCurrentPosition(int *msec);
+    virtual status_t getDuration(int *msec);
+    virtual status_t reset();
+    virtual status_t setLooping(int loop);
+    virtual player_type playerType();
+    virtual status_t invoke(const Parcel &request, Parcel *reply);
+    virtual void setAudioSink(const sp<AudioSink> &audioSink);
+
+private:
+    MediaPlayerImpl *mPlayer;
+
+    StagefrightPlayer(const StagefrightPlayer &);
+    StagefrightPlayer &operator=(const StagefrightPlayer &);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_STAGEFRIGHTPLAYER_H
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
new file mode 100644
index 0000000..8627708
--- /dev/null
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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 "TestPlayerStub"
+#include "utils/Log.h"
+
+#include "TestPlayerStub.h"
+
+#include <dlfcn.h>  // for dlopen/dlclose
+#include <stdlib.h>
+#include <string.h>
+#include <cutils/properties.h>
+#include <utils/Errors.h>  // for status_t
+
+#include "media/MediaPlayerInterface.h"
+
+
+namespace {
+using android::status_t;
+using android::MediaPlayerBase;
+
+const char *kTestUrlScheme = "test:";
+const char *kUrlParam = "url=";
+
+const char *kBuildTypePropName = "ro.build.type";
+const char *kEngBuild = "eng";
+const char *kTestBuild = "test";
+
+// @return true if the current build is 'eng' or 'test'.
+bool isTestBuild()
+{
+    char prop[PROPERTY_VALUE_MAX] = { '\0', };
+
+    property_get(kBuildTypePropName, prop, '\0');
+    return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
+}
+
+// @return true if the url scheme is 'test:'
+bool isTestUrl(const char *url)
+{
+    return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
+}
+
+}  // anonymous namespace
+
+namespace android {
+
+TestPlayerStub::TestPlayerStub()
+    :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
+     mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
+     mPlayer(NULL) { }
+
+TestPlayerStub::~TestPlayerStub()
+{
+    resetInternal();
+}
+
+status_t TestPlayerStub::initCheck()
+{
+    return isTestBuild() ? OK : INVALID_OPERATION;
+}
+
+// Parse mUrl to get:
+// * The library to be dlopened.
+// * The url to be passed to the real setDataSource impl.
+//
+// mUrl is expected to be in following format:
+//
+// test:<name of the .so>?url=<url for setDataSource>
+//
+// The value of the url parameter is treated as a string (no
+// unescaping of illegal charaters).
+status_t TestPlayerStub::parseUrl()
+{
+    if (strlen(mUrl) < strlen(kTestUrlScheme)) {
+        resetInternal();
+        return BAD_VALUE;
+    }
+
+    char *i = mUrl + strlen(kTestUrlScheme);
+
+    mFilename = i;
+
+    while (*i != '\0' && *i != '?') {
+        ++i;
+    }
+
+    if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
+        resetInternal();
+        return BAD_VALUE;
+    }
+    *i = '\0';  // replace '?' to nul-terminate mFilename
+
+    mContentUrl = i + 1 + strlen(kUrlParam);
+    return OK;
+}
+
+// Load the dynamic library.
+// Create the test player.
+// Call setDataSource on the test player with the url in param.
+status_t TestPlayerStub::setDataSource(const char *url)
+{
+    if (!isTestUrl(url) || NULL != mHandle) {
+        return INVALID_OPERATION;
+    }
+
+    mUrl = strdup(url);
+
+    status_t status = parseUrl();
+
+    if (OK != status) {
+        resetInternal();
+        return status;
+    }
+
+    ::dlerror();  // Clears any pending error.
+
+    // Load the test player from the url. dlopen will fail if the lib
+    // is not there. dls are under /system/lib
+    // None of the entry points should be NULL.
+    mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
+    if (!mHandle) {
+        LOGE("dlopen failed: %s", ::dlerror());
+        resetInternal();
+        return UNKNOWN_ERROR;
+    }
+
+    // Load the 2 entry points to create and delete instances.
+    const char *err;
+    mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
+                                                    "newPlayer"));
+    err = ::dlerror();
+    if (err || mNewPlayer == NULL) {
+        // if err is NULL the string <null> is inserted in the logs =>
+        // mNewPlayer was NULL.
+        LOGE("dlsym for newPlayer failed %s", err);
+        resetInternal();
+        return UNKNOWN_ERROR;
+    }
+
+    mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
+                                                          "deletePlayer"));
+    err = ::dlerror();
+    if (err || mDeletePlayer == NULL) {
+        LOGE("dlsym for deletePlayer failed %s", err);
+        resetInternal();
+        return UNKNOWN_ERROR;
+    }
+
+    mPlayer = (*mNewPlayer)();
+    return mPlayer->setDataSource(mContentUrl);
+}
+
+// Internal cleanup.
+status_t TestPlayerStub::resetInternal()
+{
+    if(mUrl) {
+        free(mUrl);
+        mUrl = NULL;
+    }
+    mFilename = NULL;
+    mContentUrl = NULL;
+
+    if (mPlayer) {
+        LOG_ASSERT(mDeletePlayer != NULL);
+        (*mDeletePlayer)(mPlayer);
+        mPlayer = NULL;
+    }
+
+    if (mHandle) {
+        ::dlclose(mHandle);
+        mHandle = NULL;
+    }
+    return OK;
+}
+
+/* static */ bool TestPlayerStub::canBeUsed(const char *url)
+{
+    return isTestBuild() && isTestUrl(url);
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
new file mode 100644
index 0000000..80d53a8
--- /dev/null
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -0,0 +1,119 @@
+/*
+ * 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 ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
+#define ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
+
+#include <media/MediaPlayerInterface.h>
+#include <utils/Errors.h>
+
+namespace android {
+class MediaPlayerBase;  // in media/MediaPlayerInterface.h
+
+// Wrapper around a test media player that gets dynamically loaded.
+//
+// The URL passed to setDataSource has this format:
+//
+//   test:<name of the .so>?url=<url for the real setDataSource impl.>
+//
+// e.g:
+//   test:invoke_test_media_player.so?url=http://youtube.com/
+//   test:invoke_test_media_player.so?url=speedtest
+//
+// TestPlayerStub::setDataSource loads the library in the test url. 2
+// entry points with C linkage are expected. One to create the test
+// player and one to destroy it.
+//
+// extern "C" android::MediaPlayerBase* newPlayer();
+// extern "C" android::status_t deletePlayer(android::MediaPlayerBase *p);
+//
+// Once the test player has been loaded, its setDataSource
+// implementation is called with the value of the 'url' parameter.
+//
+// typical usage in a java test:
+// ============================
+//
+//  MediaPlayer p = new MediaPlayer();
+//  p.setDataSource("test:invoke_mock_media_player.so?url=http://youtube.com");
+//  p.prepare();
+//  ...
+//  p.release();
+
+class TestPlayerStub : public MediaPlayerInterface {
+  public:
+    typedef MediaPlayerBase* (*NEW_PLAYER)();
+    typedef status_t (*DELETE_PLAYER)(MediaPlayerBase *);
+
+    TestPlayerStub();
+    virtual ~TestPlayerStub();
+
+    // Called right after the constructor. Check if the current build
+    // allows test players.
+    virtual status_t initCheck();
+
+    // @param url Should be a test url. See class comment.
+    virtual status_t setDataSource(const char* url);
+
+    // Test player for a file descriptor source is not supported.
+    virtual status_t setDataSource(int, int64_t, int64_t)  {
+        return INVALID_OPERATION;
+    }
+
+
+    // All the methods below wrap the mPlayer instance.
+    virtual status_t setVideoSurface(const android::sp<android::ISurface>& s)  {
+        return mPlayer->setVideoSurface(s);
+    }
+    virtual status_t prepare() {return mPlayer->prepare();}
+    virtual status_t prepareAsync()  {return mPlayer->prepareAsync();}
+    virtual status_t start()  {return mPlayer->start();}
+    virtual status_t stop()  {return mPlayer->stop();}
+    virtual status_t pause()  {return mPlayer->pause();}
+    virtual bool isPlaying() {return mPlayer->isPlaying();}
+    virtual status_t seekTo(int msec) {return mPlayer->seekTo(msec);}
+    virtual status_t getCurrentPosition(int *p)  {
+        return mPlayer->getCurrentPosition(p);
+    }
+    virtual status_t getDuration(int *d)  {return mPlayer->getDuration(d);}
+    virtual status_t reset() {return mPlayer->reset();}
+    virtual status_t setLooping(int b)  {return mPlayer->setLooping(b);}
+    virtual player_type playerType() {return mPlayer->playerType();}
+    virtual status_t invoke(const android::Parcel& in, android::Parcel *out) {
+        return mPlayer->invoke(in, out);
+    }
+
+
+    // @return true if the current build is 'eng' or 'test' and the
+    //              url's scheme is 'test:'
+    static bool canBeUsed(const char *url);
+
+  private:
+    // Release the player, dlclose the library.
+    status_t resetInternal();
+    status_t parseUrl();
+
+    char *mUrl;                // test:foo.so?url=http://bar
+    char *mFilename;           // foo.so
+    char *mContentUrl;         // http://bar
+    void *mHandle;             // returned by dlopen
+    NEW_PLAYER    mNewPlayer;
+    DELETE_PLAYER mDeletePlayer;
+    MediaPlayerBase *mPlayer;  // wrapped player
+};
+
+}  // namespace android
+
+#endif
diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h
index c30dc1b..4024654 100644
--- a/media/libmediaplayerservice/VorbisPlayer.h
+++ b/media/libmediaplayerservice/VorbisPlayer.h
@@ -53,6 +53,7 @@
     virtual status_t    reset();
     virtual status_t    setLooping(int loop);
     virtual player_type playerType() { return VORBIS_PLAYER; }
+    virtual status_t    invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;}
 
 private:
             status_t    setdatasource(const char *path, int fd, int64_t offset, int64_t length);
@@ -88,4 +89,3 @@
 }; // namespace android
 
 #endif // ANDROID_VORBISPLAYER_H
-
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
new file mode 100644
index 0000000..5be9224
--- /dev/null
+++ b/media/libstagefright/Android.mk
@@ -0,0 +1,61 @@
+ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=                 \
+        CachingDataSource.cpp     \
+        DataSource.cpp            \
+        FileSource.cpp            \
+        HTTPDataSource.cpp        \
+        HTTPStream.cpp            \
+        MP3Extractor.cpp          \
+        MPEG4Extractor.cpp        \
+        MPEG4Writer.cpp           \
+        MediaBuffer.cpp           \
+        MediaBufferGroup.cpp      \
+        MediaExtractor.cpp        \
+        MediaPlayerImpl.cpp       \
+        MediaSource.cpp           \
+        MetaData.cpp              \
+        MmapSource.cpp            \
+        QComHardwareRenderer.cpp  \
+        SampleTable.cpp           \
+        ShoutcastSource.cpp       \
+        SoftwareRenderer.cpp      \
+        SurfaceRenderer.cpp       \
+        TimeSource.cpp            \
+        TimedEventQueue.cpp       \
+        TIHardwareRenderer.cpp    \
+        Utils.cpp                 \
+        AudioPlayer.cpp           \
+        ESDS.cpp                  \
+        OMXClient.cpp             \
+        OMXDecoder.cpp            \
+        string.cpp
+
+LOCAL_C_INCLUDES:= \
+        $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+        $(TOP)/external/opencore/android
+
+LOCAL_SHARED_LIBRARIES := \
+        libbinder         \
+        libmedia          \
+        libutils          \
+        libcutils         \
+        libui
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+        LOCAL_LDLIBS += -lpthread
+endif
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_PRELINK_MODULE:= false
+
+LOCAL_MODULE:= libstagefright
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
new file mode 100644
index 0000000..d547556
--- /dev/null
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+#define LOG_TAG "AudioPlayer"
+#include <utils/Log.h>
+
+#include <media/AudioTrack.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
+    : mSource(NULL),
+      mAudioTrack(NULL),
+      mInputBuffer(NULL),
+      mSampleRate(0),
+      mLatencyUs(0),
+      mFrameSize(0),
+      mNumFramesPlayed(0),
+      mPositionTimeMediaUs(-1),
+      mPositionTimeRealUs(-1),
+      mSeeking(false),
+      mStarted(false),
+      mAudioSink(audioSink) {
+}
+
+AudioPlayer::~AudioPlayer() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+void AudioPlayer::setSource(MediaSource *source) {
+    assert(mSource == NULL);
+    mSource = source;
+}
+
+void AudioPlayer::start() {
+    assert(!mStarted);
+    assert(mSource != NULL);
+
+    status_t err = mSource->start();
+    assert(err == OK);
+
+    sp<MetaData> format = mSource->getFormat();
+    const char *mime;
+    bool success = format->findCString(kKeyMIMEType, &mime);
+    assert(success);
+    assert(!strcasecmp(mime, "audio/raw"));
+
+    success = format->findInt32(kKeySampleRate, &mSampleRate);
+    assert(success);
+
+    int32_t numChannels;
+    success = format->findInt32(kKeyChannelCount, &numChannels);
+    assert(success);
+
+    if (mAudioSink.get() != NULL) {
+        status_t err = mAudioSink->open(
+                mSampleRate, numChannels, AudioSystem::PCM_16_BIT,
+                DEFAULT_AUDIOSINK_BUFFERCOUNT,
+                &AudioPlayer::AudioSinkCallback, this);
+        assert(err == OK);
+
+        mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+        mFrameSize = mAudioSink->frameSize();
+
+        mAudioSink->start();
+    } else {
+        mAudioTrack = new AudioTrack(
+                AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
+                (numChannels == 2)
+                    ? AudioSystem::CHANNEL_OUT_STEREO
+                    : AudioSystem::CHANNEL_OUT_MONO,
+                8192, 0, &AudioCallback, this, 0);
+
+        assert(mAudioTrack->initCheck() == OK);
+
+        mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+        mFrameSize = mAudioTrack->frameSize();
+
+        mAudioTrack->start();
+    }
+
+    mStarted = true;
+}
+
+void AudioPlayer::pause() {
+    assert(mStarted);
+
+    if (mAudioSink.get() != NULL) {
+        mAudioSink->pause();
+    } else {
+        mAudioTrack->stop();
+    }
+}
+
+void AudioPlayer::resume() {
+    assert(mStarted);
+
+    if (mAudioSink.get() != NULL) {
+        mAudioSink->start();
+    } else {
+        mAudioTrack->start();
+    }
+}
+
+void AudioPlayer::stop() {
+    assert(mStarted);
+
+    if (mAudioSink.get() != NULL) {
+        mAudioSink->stop();
+    } else {
+        mAudioTrack->stop();
+
+        delete mAudioTrack;
+        mAudioTrack = NULL;
+    }
+    
+    // Make sure to release any buffer we hold onto so that the
+    // source is able to stop().
+    if (mInputBuffer != NULL) {
+        LOGI("AudioPlayer releasing input buffer.");
+
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    mSource->stop();
+    
+    mNumFramesPlayed = 0;
+    mPositionTimeMediaUs = -1;
+    mPositionTimeRealUs = -1;
+    mSeeking = false;
+    mStarted = false;
+}
+
+// static
+void AudioPlayer::AudioCallback(int event, void *user, void *info) {
+    static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
+}
+
+// static
+void AudioPlayer::AudioSinkCallback(
+        MediaPlayerBase::AudioSink *audioSink,
+        void *buffer, size_t size, void *cookie) {
+    AudioPlayer *me = (AudioPlayer *)cookie;
+
+    me->fillBuffer(buffer, size);
+}
+
+void AudioPlayer::AudioCallback(int event, void *info) {
+    if (event != AudioTrack::EVENT_MORE_DATA) {
+        return;
+    }
+
+    AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+    fillBuffer(buffer->raw, buffer->size);
+}
+
+void AudioPlayer::fillBuffer(void *data, size_t size) {
+    if (mNumFramesPlayed == 0) {
+        LOGI("AudioCallback");
+    }
+
+    size_t size_done = 0;
+    size_t size_remaining = size;
+    while (size_remaining > 0) {
+        MediaSource::ReadOptions options;
+
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            if (mSeeking) {
+                options.setSeekTo(mSeekTimeUs);
+
+                if (mInputBuffer != NULL) {
+                    mInputBuffer->release();
+                    mInputBuffer = NULL;
+                }
+                mSeeking = false;
+            }
+        }
+
+        if (mInputBuffer == NULL) {
+            status_t err = mSource->read(&mInputBuffer, &options);
+
+            assert((err == OK && mInputBuffer != NULL)
+                   || (err != OK && mInputBuffer == NULL));
+
+            if (err != OK) {
+                memset((char *)data + size_done, 0, size_remaining);
+                break;
+            }
+
+            int32_t units, scale;
+            bool success =
+                mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+            success = success &&
+                mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+            assert(success);
+
+            Mutex::Autolock autoLock(mLock);
+            mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+
+            mPositionTimeRealUs =
+                ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+                    / mSampleRate;
+        }
+
+        if (mInputBuffer->range_length() == 0) {
+            mInputBuffer->release();
+            mInputBuffer = NULL;
+
+            continue;
+        }
+
+        size_t copy = size_remaining;
+        if (copy > mInputBuffer->range_length()) {
+            copy = mInputBuffer->range_length();
+        }
+
+        memcpy((char *)data + size_done,
+               (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+               copy);
+
+        mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+                                mInputBuffer->range_length() - copy);
+                    
+        size_done += copy;
+        size_remaining -= copy;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    mNumFramesPlayed += size / mFrameSize;
+}
+
+int64_t AudioPlayer::getRealTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+    return getRealTimeUsLocked();
+}
+
+int64_t AudioPlayer::getRealTimeUsLocked() const {
+    return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
+}
+
+int64_t AudioPlayer::getMediaTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+
+    return mPositionTimeMediaUs + (getRealTimeUsLocked() - mPositionTimeRealUs);
+}
+
+bool AudioPlayer::getMediaTimeMapping(
+        int64_t *realtime_us, int64_t *mediatime_us) {
+    Mutex::Autolock autoLock(mLock);
+
+    *realtime_us = mPositionTimeRealUs;
+    *mediatime_us = mPositionTimeMediaUs;
+
+    return mPositionTimeRealUs != -1 || mPositionTimeMediaUs != -1;
+}
+
+status_t AudioPlayer::seekTo(int64_t time_us) {
+    Mutex::Autolock autoLock(mLock);
+
+    mSeeking = true;
+    mSeekTimeUs = time_us;
+
+    return OK;
+}
+
+}
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
new file mode 100644
index 0000000..0fd71d5
--- /dev/null
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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/CachingDataSource.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+CachingDataSource::CachingDataSource(
+        DataSource *source, size_t pageSize, int numPages)
+    : mSource(source),
+      mData(malloc(pageSize * numPages)),
+      mPageSize(pageSize),
+      mFirst(NULL),
+      mLast(NULL) {
+    for (int i = 0; i < numPages; ++i) {
+        Page *page = new Page;
+        page->mPrev = mLast;
+        page->mNext = NULL;
+
+        if (mLast == NULL) {
+            mFirst = page;
+        } else {
+            mLast->mNext = page;
+        }
+
+        mLast = page;
+
+        page->mOffset = -1;
+        page->mLength = 0;
+        page->mData = (char *)mData + mPageSize * i;
+    }
+}
+
+CachingDataSource::~CachingDataSource() {
+    Page *page = mFirst;
+    while (page != NULL) {
+        Page *next = page->mNext;
+        delete page;
+        page = next;
+    }
+    mFirst = mLast = NULL;
+
+    free(mData);
+    mData = NULL;
+
+    delete mSource;
+    mSource = NULL;
+}
+
+status_t CachingDataSource::InitCheck() const {
+    return OK;
+}
+
+ssize_t CachingDataSource::read_at(off_t offset, void *data, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    size_t total = 0;
+    while (size > 0) {
+        Page *page = mFirst;
+        while (page != NULL) {
+            if (page->mOffset >= 0 && offset >= page->mOffset
+                && offset < page->mOffset + page->mLength) {
+                break;
+            }
+            page = page->mNext;
+        }
+
+        if (page == NULL) {
+            page = allocate_page();
+            page->mOffset = offset - offset % mPageSize;
+            ssize_t n = mSource->read_at(page->mOffset, page->mData, mPageSize);
+            if (n < 0) {
+                page->mLength = 0;
+            } else {
+                page->mLength = (size_t)n;
+            }
+            mFirst->mPrev = page;
+            page->mNext = mFirst;
+            page->mPrev = NULL;
+            mFirst = page;
+
+            if (n < 0) {
+                return n;
+            }
+
+            if (offset >= page->mOffset + page->mLength) {
+                break;
+            }
+        } else {
+            // Move "page" to the front in LRU order.
+            if (page->mNext != NULL) {
+                page->mNext->mPrev = page->mPrev;
+            } else {
+                mLast = page->mPrev;
+            }
+
+            if (page->mPrev != NULL) {
+                page->mPrev->mNext = page->mNext;
+            } else {
+                mFirst = page->mNext;
+            }
+
+            mFirst->mPrev = page;
+            page->mNext = mFirst;
+            page->mPrev = NULL;
+            mFirst = page;
+        }
+
+        size_t copy = page->mLength - (offset - page->mOffset);
+        if (copy > size) {
+            copy = size;
+        }
+        memcpy(data,(const char *)page->mData + (offset - page->mOffset),
+               copy);
+
+        total += copy;
+
+        if (page->mLength < mPageSize) {
+            // This was the final page. There is no more data beyond it.
+            break;
+        }
+
+        offset += copy;
+        size -= copy;
+        data = (char *)data + copy;
+    }
+
+    return total;
+}
+
+CachingDataSource::Page *CachingDataSource::allocate_page() {
+    // The last page is the least recently used, i.e. oldest.
+
+    Page *page = mLast;
+
+    page->mPrev->mNext = NULL;
+    mLast = page->mPrev;
+    page->mPrev = NULL;
+
+    return page;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
new file mode 100644
index 0000000..ee12873
--- /dev/null
+++ b/media/libstagefright/CameraSource.cpp
@@ -0,0 +1,226 @@
+/*
+ * 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 <sys/time.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <OMX_Component.h>
+
+#include <binder/IServiceManager.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <ui/ICameraClient.h>
+#include <ui/ICameraService.h>
+#include <ui/Overlay.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class CameraBuffer : public MediaBuffer {
+public:
+    CameraBuffer(const sp<IMemory> &frame)
+        : MediaBuffer(frame->pointer(), frame->size()),
+          mFrame(frame) {
+    }
+
+    sp<IMemory> releaseFrame() {
+        sp<IMemory> frame = mFrame;
+        mFrame.clear();
+        return frame;
+    }
+
+private:
+    sp<IMemory> mFrame;
+};
+
+class CameraSourceClient : public BnCameraClient {
+public:
+    CameraSourceClient()
+        : mSource(NULL) {
+    }
+
+    virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
+        assert(mSource != NULL);
+        mSource->notifyCallback(msgType, ext1, ext2);
+    }
+
+    virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {
+        assert(mSource != NULL);
+        mSource->dataCallback(msgType, data);
+    }
+
+    void setCameraSource(CameraSource *source) {
+        mSource = source;
+    }
+
+private:
+    CameraSource *mSource;
+};
+
+class DummySurface : public BnSurface {
+public:
+    DummySurface() {}
+
+    virtual status_t registerBuffers(const BufferHeap &buffers) {
+        return OK;
+    }
+
+    virtual void postBuffer(ssize_t offset) {
+    }
+
+    virtual void unregisterBuffers() {
+    }
+    
+    virtual sp<OverlayRef> createOverlay(
+            uint32_t w, uint32_t h, int32_t format) {
+        return NULL;
+    }
+};
+
+// static
+CameraSource *CameraSource::Create() {
+    sp<IServiceManager> sm = defaultServiceManager();
+
+    sp<ICameraService> service =
+        interface_cast<ICameraService>(
+                sm->getService(String16("media.camera")));
+
+    sp<CameraSourceClient> client = new CameraSourceClient;
+    sp<ICamera> camera = service->connect(client);
+
+    CameraSource *source = new CameraSource(camera, client);
+    client->setCameraSource(source);
+
+    return source;
+}
+
+CameraSource::CameraSource(
+        const sp<ICamera> &camera, const sp<ICameraClient> &client)
+    : mCamera(camera),
+      mCameraClient(client),
+      mNumFrames(0),
+      mStarted(false) {
+    printf("params: \"%s\"\n", mCamera->getParameters().string());
+}
+
+CameraSource::~CameraSource() {
+    if (mStarted) {
+        stop();
+    }
+
+    mCamera->disconnect();
+}
+
+status_t CameraSource::start(MetaData *) {
+    assert(!mStarted);
+
+    status_t err = mCamera->lock();
+    assert(err == OK);
+
+    err = mCamera->setPreviewDisplay(new DummySurface);
+    assert(err == OK);
+    mCamera->setPreviewCallbackFlag(1);
+    mCamera->startPreview();
+    assert(err == OK);
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t CameraSource::stop() {
+    assert(mStarted);
+
+    mCamera->stopPreview();
+    mCamera->unlock();
+
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> CameraSource::getFormat() {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, "video/raw");
+    meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
+    meta->setInt32(kKeyWidth, 480);
+    meta->setInt32(kKeyHeight, 320);
+
+    return meta;
+}
+
+status_t CameraSource::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    assert(mStarted);
+
+    *buffer = NULL;
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    sp<IMemory> frame;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+        while (mFrames.empty()) {
+            mFrameAvailableCondition.wait(mLock);
+        }
+
+        frame = *mFrames.begin();
+        mFrames.erase(mFrames.begin());
+    }
+
+    int count = mNumFrames++;
+
+    *buffer = new CameraBuffer(frame);
+
+    (*buffer)->meta_data()->clear();
+    (*buffer)->meta_data()->setInt32(kKeyTimeScale, 15);
+    (*buffer)->meta_data()->setInt32(kKeyTimeUnits, count);
+
+    (*buffer)->add_ref();
+    (*buffer)->setObserver(this);
+
+    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);
+
+    mFrames.push_back(data);
+    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
new file mode 100644
index 0000000..6e6b43d
--- /dev/null
+++ b/media/libstagefright/DataSource.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <utils/String8.h>
+
+namespace android {
+
+status_t DataSource::getSize(off_t *size) {
+    *size = 0;
+
+    return ERROR_UNSUPPORTED;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Mutex DataSource::gSnifferMutex;
+List<DataSource::SnifferFunc> DataSource::gSniffers;
+
+bool DataSource::sniff(String8 *mimeType, float *confidence) {
+    *mimeType = "";
+    *confidence = 0.0f;
+
+    Mutex::Autolock autoLock(gSnifferMutex);
+    for (List<SnifferFunc>::iterator it = gSniffers.begin();
+         it != gSniffers.end(); ++it) {
+        String8 newMimeType;
+        float newConfidence;
+        if ((*it)(this, &newMimeType, &newConfidence)) {
+            if (newConfidence > *confidence) {
+                *mimeType = newMimeType;
+                *confidence = newConfidence;
+            }
+        }
+    }
+
+    return *confidence > 0.0;
+}
+
+// static
+void DataSource::RegisterSniffer(SnifferFunc func) {
+    Mutex::Autolock autoLock(gSnifferMutex);
+
+    for (List<SnifferFunc>::iterator it = gSniffers.begin();
+         it != gSniffers.end(); ++it) {
+        if (*it == func) {
+            return;
+        }
+    }
+
+    gSniffers.push_back(func);
+}
+
+// static
+void DataSource::RegisterDefaultSniffers() {
+    RegisterSniffer(SniffMP3);
+    RegisterSniffer(SniffMPEG4);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
new file mode 100644
index 0000000..53b92a0
--- /dev/null
+++ b/media/libstagefright/ESDS.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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/ESDS.h>
+
+#include <string.h>
+
+namespace android {
+
+ESDS::ESDS(const void *data, size_t size)
+    : mData(new uint8_t[size]),
+      mSize(size),
+      mInitCheck(NO_INIT),
+      mDecoderSpecificOffset(0),
+      mDecoderSpecificLength(0) {
+    memcpy(mData, data, size);
+
+    mInitCheck = parse();
+}
+
+ESDS::~ESDS() {
+    delete[] mData;
+    mData = NULL;
+}
+
+status_t ESDS::InitCheck() const {
+    return mInitCheck;
+}
+
+status_t ESDS::getCodecSpecificInfo(const void **data, size_t *size) const {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    *data = &mData[mDecoderSpecificOffset];
+    *size = mDecoderSpecificLength;
+
+    return OK;
+}
+
+status_t ESDS::skipDescriptorHeader(
+        size_t offset, size_t size,
+        uint8_t *tag, size_t *data_offset, size_t *data_size) const {
+    if (size == 0) {
+        return ERROR_MALFORMED;
+    }
+
+    *tag = mData[offset++];
+    --size;
+
+    *data_size = 0;
+    bool more;
+    do {
+        if (size == 0) {
+            return ERROR_MALFORMED;
+        }
+
+        uint8_t x = mData[offset++];
+        --size;
+
+        *data_size = (*data_size << 7) | (x & 0x7f);
+        more = (x & 0x80) != 0;
+    }
+    while (more);
+
+    if (*data_size > size) {
+        return ERROR_MALFORMED;
+    }
+
+    *data_offset = offset;
+
+    return OK;
+}
+
+status_t ESDS::parse() {
+    uint8_t tag;
+    size_t data_offset;
+    size_t data_size;
+    status_t err =
+        skipDescriptorHeader(0, mSize, &tag, &data_offset, &data_size);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (tag != kTag_ESDescriptor) {
+        return ERROR_MALFORMED;
+    }
+
+    return parseESDescriptor(data_offset, data_size);
+}
+
+status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
+    if (size < 3) {
+        return ERROR_MALFORMED;
+    }
+
+    offset += 2;  // skip ES_ID
+    size -= 2;
+
+    unsigned streamDependenceFlag = mData[offset] & 0x80;
+    unsigned URL_Flag = mData[offset] & 0x40;
+    unsigned OCRstreamFlag = mData[offset] & 0x20;
+
+    ++offset;
+    --size;
+
+    if (streamDependenceFlag) {
+        offset += 2;
+        size -= 2;
+    }
+
+    if (URL_Flag) {
+        if (offset >= size) {
+            return ERROR_MALFORMED;
+        }
+        unsigned URLlength = mData[offset];
+        offset += URLlength + 1;
+        size -= URLlength + 1;
+    }
+
+    if (OCRstreamFlag) {
+        offset += 2;
+        size -= 2;
+    }
+    
+    if (offset >= size) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t tag;
+    size_t sub_offset, sub_size;
+    status_t err = skipDescriptorHeader(
+            offset, size, &tag, &sub_offset, &sub_size);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (tag != kTag_DecoderConfigDescriptor) {
+        return ERROR_MALFORMED;
+    }
+
+    err = parseDecoderConfigDescriptor(sub_offset, sub_size);
+
+    return err;
+}
+
+status_t ESDS::parseDecoderConfigDescriptor(size_t offset, size_t size) {
+    if (size < 13) {
+        return ERROR_MALFORMED;
+    }
+
+    offset += 13;
+    size -= 13;
+
+    if (size == 0) {
+        mDecoderSpecificOffset = 0;
+        mDecoderSpecificLength = 0;
+        return OK;
+    }
+
+    uint8_t tag;
+    size_t sub_offset, sub_size;
+    status_t err = skipDescriptorHeader(
+            offset, size, &tag, &sub_offset, &sub_size);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (tag != kTag_DecoderSpecificInfo) {
+        return ERROR_MALFORMED;
+    }
+
+    mDecoderSpecificOffset = sub_offset;
+    mDecoderSpecificLength = sub_size;
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
new file mode 100644
index 0000000..c26d0a0
--- /dev/null
+++ b/media/libstagefright/FileSource.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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/FileSource.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+namespace android {
+
+FileSource::FileSource(const char *filename)
+    : mFile(fopen(filename, "rb")) {
+}
+
+FileSource::~FileSource() {
+    if (mFile != NULL) {
+        fclose(mFile);
+        mFile = NULL;
+    }
+}
+
+status_t FileSource::InitCheck() const {
+    return mFile != NULL ? OK : NO_INIT;
+}
+
+ssize_t FileSource::read_at(off_t offset, void *data, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    int err = fseeko(mFile, offset, SEEK_SET);
+    assert(err != -1);
+
+    ssize_t result = fread(data, 1, size, mFile);
+
+    return result;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
new file mode 100644
index 0000000..d1f8cd4
--- /dev/null
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <stdlib.h>
+
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/string.h>
+
+namespace android {
+
+HTTPDataSource::HTTPDataSource(const char *uri)
+    : mHost(NULL),
+      mPort(0),
+      mPath(NULL),
+      mBuffer(malloc(kBufferSize)),
+      mBufferLength(0),
+      mBufferOffset(0) {
+    assert(!strncasecmp("http://", uri, 7));
+
+    string host;
+    string path;
+    int port;
+
+    char *slash = strchr(uri + 7, '/');
+    if (slash == NULL) {
+        host = uri + 7;
+        path = "/";
+    } else {
+        host = string(uri + 7, slash - (uri + 7));
+        path = slash;
+    }
+
+    char *colon = strchr(host.c_str(), ':');
+    if (colon == NULL) {
+        port = 80;
+    } else {
+        char *end;
+        long tmp = strtol(colon + 1, &end, 10);
+        assert(end > colon + 1);
+        assert(tmp > 0 && tmp < 65536);
+        port = tmp;
+
+        host = string(host, 0, colon - host.c_str());
+    }
+
+    LOGI("Connecting to host '%s', port %d, path '%s'",
+         host.c_str(), port, path.c_str());
+
+    mHost = strdup(host.c_str());
+    mPort = port;
+    mPath = strdup(path.c_str());
+
+    status_t err = mHttp.connect(mHost, mPort);
+    assert(err == OK);
+}
+
+HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
+    : mHost(strdup(host)),
+      mPort(port),
+      mPath(strdup(path)),
+      mBuffer(malloc(kBufferSize)),
+      mBufferLength(0),
+      mBufferOffset(0) {
+    status_t err = mHttp.connect(mHost, mPort);
+    assert(err == OK);
+}
+
+HTTPDataSource::~HTTPDataSource() {
+    mHttp.disconnect();
+
+    free(mBuffer);
+    mBuffer = NULL;
+
+    free(mPath);
+    mPath = NULL;
+}
+
+ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
+    if (offset >= mBufferOffset && offset < mBufferOffset + mBufferLength) {
+        size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
+
+        size_t copy = num_bytes_available;
+        if (copy > size) {
+            copy = size;
+        }
+
+        memcpy(data, (const char *)mBuffer + (offset - mBufferOffset), copy);
+
+        return copy;
+    }
+
+    mBufferOffset = offset;
+    mBufferLength = 0;
+
+    char host[128];
+    sprintf(host, "Host: %s\r\n", mHost);
+
+    char range[128];
+    sprintf(range, "Range: bytes=%ld-%ld\r\n\r\n",
+            mBufferOffset, mBufferOffset + kBufferSize - 1);
+
+    int http_status;
+
+    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 (attempt == 3) {
+                return err;
+            }
+
+            mHttp.connect(mHost, mPort);
+            ++attempt;
+        } else {
+            break;
+        }
+    }
+
+    if ((http_status / 100) != 2) {
+        return UNKNOWN_ERROR;
+    }
+
+    string 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);
+
+    if (num_bytes_received <= 0) {
+        return num_bytes_received;
+    }
+
+    mBufferLength = (size_t)num_bytes_received;
+
+    size_t copy = mBufferLength;
+    if (copy > size) {
+        copy = size;
+    }
+
+    memcpy(data, mBuffer, copy);
+
+    return copy;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
new file mode 100644
index 0000000..29e6f72
--- /dev/null
+++ b/media/libstagefright/HTTPStream.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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 <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <media/stagefright/HTTPStream.h>
+
+namespace android {
+
+// static
+const char *HTTPStream::kStatusKey = ":status:";
+
+HTTPStream::HTTPStream()
+    : mState(READY),
+      mSocket(-1) {
+}
+
+HTTPStream::~HTTPStream() {
+    disconnect();
+}
+
+status_t HTTPStream::connect(const char *server, int port) {
+    status_t err = OK;
+
+    if (mState == CONNECTED) {
+        return ERROR_ALREADY_CONNECTED;
+    }
+
+    assert(mSocket == -1);
+    mSocket = socket(AF_INET, SOCK_STREAM, 0);
+    
+    if (mSocket < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    struct hostent *ent = gethostbyname(server);
+    if (ent == NULL) {
+        err = ERROR_UNKNOWN_HOST;
+        goto exit1;
+    }
+
+    struct sockaddr_in addr;
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
+    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+
+    if (::connect(mSocket, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        err = ERROR_CANNOT_CONNECT;
+        goto exit1;
+    }
+
+    mState = CONNECTED;
+
+    return OK;
+
+exit1:
+    close(mSocket);
+    mSocket = -1;
+
+    return err;
+}
+
+status_t HTTPStream::disconnect() {
+    if (mState != CONNECTED) {
+        return ERROR_NOT_CONNECTED;
+    }
+
+    assert(mSocket >= 0);
+    close(mSocket);
+    mSocket = -1;
+
+    mState = READY;
+
+    return OK;
+}
+
+status_t HTTPStream::send(const char *data, size_t size) {
+    if (mState != CONNECTED) {
+        return ERROR_NOT_CONNECTED;
+    }
+
+    while (size > 0) {
+        ssize_t n = ::send(mSocket, data, size, 0);
+
+        if (n < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+
+            disconnect();
+
+            return ERROR_IO;
+        } else if (n == 0) {
+            disconnect();
+
+            return ERROR_CONNECTION_LOST;
+        }
+
+        size -= (size_t)n;
+        data += (size_t)n;
+    }
+
+    return OK;
+}
+
+status_t HTTPStream::send(const char *data) {
+    return send(data, strlen(data));
+}
+
+status_t HTTPStream::receive_line(char *line, size_t size) {
+    if (mState != CONNECTED) {
+        return ERROR_NOT_CONNECTED;
+    }
+
+    bool saw_CR = false;
+    size_t length = 0;
+
+    for (;;) {
+        char c;
+        ssize_t n = recv(mSocket, &c, 1, 0);
+        if (n < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+
+            disconnect();
+
+            return ERROR_IO;
+        } else if (n == 0) {
+            disconnect();
+
+            return ERROR_CONNECTION_LOST;
+        }
+
+        if (saw_CR && c == '\n') {
+            // We have a complete line.
+
+            line[length - 1] = '\0';
+            return OK;
+        }
+
+        saw_CR = (c == '\r');
+
+        assert(length + 1 < size);
+        line[length++] = c;
+    }
+}
+
+status_t HTTPStream::receive_header(int *http_status) {
+    *http_status = -1;
+    mHeaders.clear();
+
+    char line[256];
+    status_t err = receive_line(line, sizeof(line));
+    if (err != OK) {
+        return err;
+    }
+
+    mHeaders.add(string(kStatusKey), string(line));
+
+    char *spacePos = strchr(line, ' ');
+    if (spacePos == NULL) {
+        // Malformed response?
+        return UNKNOWN_ERROR;
+    }
+
+    char *status_start = spacePos + 1;
+    char *status_end = status_start;
+    while (isdigit(*status_end)) {
+        ++status_end;
+    }
+
+    if (status_end == status_start) {
+        // Malformed response, status missing?
+        return UNKNOWN_ERROR;
+    }
+
+    memmove(line, status_start, status_end - status_start);
+    line[status_end - status_start] = '\0';
+
+    long tmp = strtol(line, NULL, 10);
+    if (tmp < 0 || tmp > 999) {
+        return UNKNOWN_ERROR;
+    }
+
+    *http_status = (int)tmp;
+
+    for (;;) {
+        err = receive_line(line, sizeof(line));
+        if (err != OK) {
+            return err;
+        }
+
+        if (*line == '\0') {
+            // Empty line signals the end of the header.
+            break;
+        }
+
+        // puts(line);
+
+        char *colonPos = strchr(line, ':');
+        if (colonPos == NULL) {
+            mHeaders.add(string(line), string());
+        } else {
+            char *end_of_key = colonPos;
+            while (end_of_key > line && isspace(end_of_key[-1])) {
+                --end_of_key;
+            }
+
+            char *start_of_value = colonPos + 1;
+            while (isspace(*start_of_value)) {
+                ++start_of_value;
+            }
+
+            *end_of_key = '\0';
+
+            mHeaders.add(string(line), string(start_of_value));
+        }
+    }
+
+    return OK;
+}
+
+ssize_t HTTPStream::receive(void *data, size_t size) {
+    size_t total = 0;
+    while (total < size) {
+        ssize_t n = recv(mSocket, (char *)data + total, size - total, 0);
+
+        if (n < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+
+            disconnect();
+            return ERROR_IO;
+        } else if (n == 0) {
+            disconnect();
+
+            return ERROR_CONNECTION_LOST;
+        }
+
+        total += (size_t)n;
+    }
+
+    return (ssize_t)total;
+}
+
+bool HTTPStream::find_header_value(const string &key, string *value) const {
+    ssize_t index = mHeaders.indexOfKey(key);
+    if (index < 0) {
+        value->clear();
+        return false;
+    }
+
+    *value = mHeaders.valueAt(index);
+
+    return true;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
new file mode 100644
index 0000000..01cb2d9
--- /dev/null
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -0,0 +1,525 @@
+/*
+ * 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 "MP3Extractor"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+static bool get_mp3_frame_size(
+        uint32_t header, size_t *frame_size,
+        int *out_sampling_rate = NULL, int *out_channels = NULL,
+        int *out_bitrate = NULL) {
+    *frame_size = 0;
+
+    if (out_sampling_rate) {
+        *out_sampling_rate = 0;
+    }
+
+    if (out_channels) {
+        *out_channels = 0;
+    }
+
+    if (out_bitrate) {
+        *out_bitrate = 0;
+    }
+
+    if ((header & 0xffe00000) != 0xffe00000) {
+        return false;
+    }
+
+    unsigned version = (header >> 19) & 3;
+
+    if (version == 0x01) {
+        return false;
+    }
+    
+    unsigned layer = (header >> 17) & 3;
+
+    if (layer == 0x00) {
+        return false;
+    }
+
+    unsigned protection = (header >> 16) & 1;
+
+    unsigned bitrate_index = (header >> 12) & 0x0f;
+
+    if (bitrate_index == 0 || bitrate_index == 0x0f) {
+        // Disallow "free" bitrate.
+        return false;
+    }
+
+    unsigned sampling_rate_index = (header >> 10) & 3;
+
+    if (sampling_rate_index == 3) {
+        return false;
+    }
+
+    static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+    int sampling_rate = kSamplingRateV1[sampling_rate_index];
+    if (version == 2 /* V2 */) {
+        sampling_rate /= 2;
+    } else if (version == 0 /* V2.5 */) {
+        sampling_rate /= 4;
+    }
+
+    unsigned padding = (header >> 9) & 1;
+
+    if (layer == 3) {
+        // layer I
+
+        static const int kBitrateV1[] = {
+            32, 64, 96, 128, 160, 192, 224, 256,
+            288, 320, 352, 384, 416, 448
+        };
+
+        static const int kBitrateV2[] = {
+            32, 48, 56, 64, 80, 96, 112, 128,
+            144, 160, 176, 192, 224, 256
+        };
+
+        int bitrate =
+            (version == 3 /* V1 */)
+                ? kBitrateV1[bitrate_index - 1]
+                : kBitrateV2[bitrate_index - 1];
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+
+        *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+    } else {
+        // layer II or III
+
+        static const int kBitrateV1L2[] = {
+            32, 48, 56, 64, 80, 96, 112, 128,
+            160, 192, 224, 256, 320, 384
+        };
+
+        static const int kBitrateV1L3[] = {
+            32, 40, 48, 56, 64, 80, 96, 112,
+            128, 160, 192, 224, 256, 320
+        };
+
+        static const int kBitrateV2[] = {
+            8, 16, 24, 32, 40, 48, 56, 64,
+            80, 96, 112, 128, 144, 160
+        };
+
+        int bitrate;
+        if (version == 3 /* V1 */) {
+            bitrate = (layer == 2 /* L2 */)
+                ? kBitrateV1L2[bitrate_index - 1]
+                : kBitrateV1L3[bitrate_index - 1];
+        } else {
+            // V2 (or 2.5)
+
+            bitrate = kBitrateV2[bitrate_index - 1];
+        }
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+
+        *frame_size = 144000 * bitrate / sampling_rate + padding;
+    }
+
+    if (out_sampling_rate) {
+        *out_sampling_rate = sampling_rate;
+    }
+
+    if (out_channels) {
+        int channel_mode = (header >> 6) & 3;
+
+        *out_channels = (channel_mode == 3) ? 1 : 2;
+    }
+
+    return true;
+}
+
+static bool Resync(
+        DataSource *source, uint32_t match_header,
+        off_t *inout_pos, uint32_t *out_header) {
+    // Everything must match except for
+    // protection, bitrate, padding, private bits and mode extension.
+    const uint32_t kMask = 0xfffe0ccf;
+
+    const size_t kMaxFrameSize = 4096;
+    uint8_t *buffer = new uint8_t[kMaxFrameSize];
+    
+    off_t pos = *inout_pos - kMaxFrameSize;
+    size_t buffer_offset = kMaxFrameSize;
+    size_t buffer_length = kMaxFrameSize;
+    bool valid = false;
+    do {
+        if (buffer_offset + 3 >= buffer_length) {
+            if (buffer_length < kMaxFrameSize) {
+                break;
+            }
+
+            pos += buffer_offset;
+
+            if (pos >= *inout_pos + 128 * 1024) {
+                // Don't scan forever.
+                LOGV("giving up at offset %ld", pos);
+                break;
+            }
+
+            memmove(buffer, &buffer[buffer_offset], buffer_length - buffer_offset);
+            buffer_length = buffer_length - buffer_offset;
+            buffer_offset = 0;
+
+            ssize_t n = source->read_at(
+                    pos, &buffer[buffer_length], kMaxFrameSize - buffer_length);
+
+            if (n <= 0) {
+                break;
+            }
+
+            buffer_length += (size_t)n;
+
+            continue;
+        }
+
+        uint32_t header = U32_AT(&buffer[buffer_offset]);
+
+        if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+            ++buffer_offset;
+            continue;
+        }
+
+        size_t frame_size;
+        int sample_rate, num_channels, bitrate;
+        if (!get_mp3_frame_size(header, &frame_size,
+                               &sample_rate, &num_channels, &bitrate)) {
+            ++buffer_offset;
+            continue;
+        }
+
+        LOGV("found possible 1st frame at %ld", pos + buffer_offset);
+
+        // We found what looks like a valid frame,
+        // now find its successors.
+
+        off_t test_pos = pos + buffer_offset + frame_size;
+
+        valid = true;
+        for (int j = 0; j < 3; ++j) {
+            uint8_t tmp[4];
+            if (source->read_at(test_pos, tmp, 4) < 4) {
+                valid = false;
+                break;
+            }
+            
+            uint32_t test_header = U32_AT(tmp);
+
+            LOGV("subsequent header is %08x", test_header);
+
+            if ((test_header & kMask) != (header & kMask)) {
+                valid = false;
+                break;
+            }
+
+            size_t test_frame_size;
+            if (!get_mp3_frame_size(test_header, &test_frame_size)) {
+                valid = false;
+                break;
+            }
+
+            LOGV("found subsequent frame #%d at %ld", j + 2, test_pos);
+
+            test_pos += test_frame_size;
+        }
+
+        if (valid) {
+            *inout_pos = pos + buffer_offset;
+
+            if (out_header != NULL) {
+                *out_header = header;
+            }
+        } else {
+            LOGV("no dice, no valid sequence of frames found.");
+        }
+
+        ++buffer_offset;
+
+    } while (!valid);
+
+    delete[] buffer;
+    buffer = NULL;
+
+    return valid;
+}
+
+class MP3Source : public MediaSource {
+public:
+    MP3Source(
+            const sp<MetaData> &meta, DataSource *source,
+            off_t first_frame_pos, uint32_t fixed_header);
+
+    virtual ~MP3Source();
+
+    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);
+
+private:
+    sp<MetaData> mMeta;
+    DataSource *mDataSource;
+    off_t mFirstFramePos;
+    uint32_t mFixedHeader;
+    off_t mCurrentPos;
+    int64_t mCurrentTimeUs;
+    bool mStarted;
+
+    MediaBufferGroup *mGroup;
+
+    MP3Source(const MP3Source &);
+    MP3Source &operator=(const MP3Source &);
+};
+
+MP3Extractor::MP3Extractor(DataSource *source)
+    : mDataSource(source),
+      mFirstFramePos(-1),
+      mFixedHeader(0) {
+    off_t pos = 0;
+    uint32_t header;
+    bool success = Resync(mDataSource, 0, &pos, &header);
+    assert(success);
+
+    if (success) {
+        mFirstFramePos = pos;
+        mFixedHeader = header;
+
+        size_t frame_size;
+        int sample_rate;
+        int num_channels;
+        int bitrate;
+        get_mp3_frame_size(
+                header, &frame_size, &sample_rate, &num_channels, &bitrate);
+
+        mMeta = new MetaData;
+
+        mMeta->setCString(kKeyMIMEType, "audio/mpeg");
+        mMeta->setInt32(kKeySampleRate, sample_rate);
+        mMeta->setInt32(kKeyBitRate, bitrate);
+        mMeta->setInt32(kKeyChannelCount, num_channels);
+
+        off_t fileSize;
+        if (mDataSource->getSize(&fileSize) == OK) {
+            mMeta->setInt32(
+                    kKeyDuration,
+                    8 * (fileSize - mFirstFramePos) / bitrate);
+            mMeta->setInt32(kKeyTimeScale, 1000);
+        }
+    }
+}
+
+MP3Extractor::~MP3Extractor() {
+    delete mDataSource;
+    mDataSource = NULL;
+}
+
+status_t MP3Extractor::countTracks(int *num_tracks) {
+    *num_tracks = mFirstFramePos < 0 ? 0 : 1;
+
+    return OK;
+}
+
+status_t MP3Extractor::getTrack(int index, MediaSource **source) {
+    if (mFirstFramePos < 0 || index != 0) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    *source = new MP3Source(
+            mMeta, mDataSource, mFirstFramePos, mFixedHeader);
+
+    return OK;
+}
+
+sp<MetaData> MP3Extractor::getTrackMetaData(int index) {
+    if (mFirstFramePos < 0 || index != 0) {
+        return NULL;
+    }
+
+    return mMeta;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MP3Source::MP3Source(
+        const sp<MetaData> &meta, DataSource *source,
+        off_t first_frame_pos, uint32_t fixed_header)
+    : mMeta(meta),
+      mDataSource(source),
+      mFirstFramePos(first_frame_pos),
+      mFixedHeader(fixed_header),
+      mCurrentPos(0),
+      mCurrentTimeUs(0),
+      mStarted(false),
+      mGroup(NULL) {
+}
+
+MP3Source::~MP3Source() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t MP3Source::start(MetaData *) {
+    assert(!mStarted);
+
+    mGroup = new MediaBufferGroup;
+
+    const size_t kMaxFrameSize = 32768;
+    mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+
+    mCurrentPos = mFirstFramePos;
+    mCurrentTimeUs = 0;
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t MP3Source::stop() {
+    assert(mStarted);
+
+    delete mGroup;
+    mGroup = NULL;
+
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> MP3Source::getFormat() {
+    return mMeta;
+}
+
+status_t MP3Source::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+        int32_t bitrate;
+        if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
+            // bitrate is in kbits/sec.
+            LOGI("no bitrate");
+
+            return ERROR_UNSUPPORTED;
+        }
+
+        mCurrentTimeUs = seekTimeUs;
+        mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 1000000 * 125;
+    }
+
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+    if (err != OK) {
+        return err;
+    }
+
+    size_t frame_size;
+    for (;;) {
+        ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), 4);
+        if (n < 4) {
+            buffer->release();
+            buffer = NULL;
+
+            return ERROR_END_OF_STREAM;
+        }
+
+        uint32_t header = U32_AT((const uint8_t *)buffer->data());
+        
+        if (get_mp3_frame_size(header, &frame_size)) {
+            break;
+        }
+
+        // Lost sync.
+        LOGW("lost sync!\n");
+
+        off_t pos = mCurrentPos;
+        if (!Resync(mDataSource, mFixedHeader, &pos, NULL)) {
+            LOGE("Unable to resync. Signalling end of stream.");
+
+            buffer->release();
+            buffer = NULL;
+
+            return ERROR_END_OF_STREAM;
+        }
+
+        mCurrentPos = pos;
+
+        // Try again with the new position.
+    }
+
+    assert(frame_size <= buffer->size());
+
+    ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), frame_size);
+    if (n < (ssize_t)frame_size) {
+        buffer->release();
+        buffer = NULL;
+
+        return ERROR_END_OF_STREAM;
+    }
+
+    buffer->set_range(0, frame_size);
+
+    buffer->meta_data()->setInt32(kKeyTimeUnits, mCurrentTimeUs / 1000);
+    buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+
+    mCurrentPos += frame_size;
+    mCurrentTimeUs += 1152 * 1000000 / 44100;
+
+    *out = buffer;
+
+    return OK;
+}
+
+bool SniffMP3(DataSource *source, String8 *mimeType, float *confidence) {
+    off_t pos = 0;
+    uint32_t header;
+    if (!Resync(source, 0, &pos, &header)) {
+        return false;
+    }
+
+    *mimeType = "audio/mpeg";
+    *confidence = 0.3f;
+
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
new file mode 100644
index 0000000..4c883c6
--- /dev/null
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -0,0 +1,958 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MPEG4Extractor"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+#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/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/SampleTable.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class MPEG4Source : public MediaSource {
+public:
+    // Caller retains ownership of both "dataSource" and "sampleTable".
+    MPEG4Source(const sp<MetaData> &format, DataSource *dataSource,
+                SampleTable *sampleTable);
+
+    virtual ~MPEG4Source();
+
+    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);
+
+private:
+    sp<MetaData> mFormat;
+    DataSource *mDataSource;
+    int32_t mTimescale;
+    SampleTable *mSampleTable;
+    uint32_t mCurrentSampleIndex;
+
+    bool mIsAVC;
+    bool mStarted;
+
+    MediaBufferGroup *mGroup;
+
+    MediaBuffer *mBuffer;
+    size_t mBufferOffset;
+    size_t mBufferSizeRemaining;
+
+    bool mNeedsNALFraming;
+
+    uint8_t *mSrcBuffer;
+
+    MPEG4Source(const MPEG4Source &);
+    MPEG4Source &operator=(const MPEG4Source &);
+};
+
+static void hexdump(const void *_data, size_t size) {
+    const uint8_t *data = (const uint8_t *)_data;
+    size_t offset = 0;
+    while (offset < size) {
+        printf("0x%04x  ", offset);
+
+        size_t n = size - offset;
+        if (n > 16) {
+            n = 16;
+        }
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (i == 8) {
+                printf(" ");
+            }
+
+            if (offset + i < size) {
+                printf("%02x ", data[offset + i]);
+            } else {
+                printf("   ");
+            }
+        }
+
+        printf(" ");
+
+        for (size_t i = 0; i < n; ++i) {
+            if (isprint(data[offset + i])) {
+                printf("%c", data[offset + i]);
+            } else {
+                printf(".");
+            }
+        }
+
+        printf("\n");
+
+        offset += 16;
+    }
+}
+
+static const char *const FourCC2MIME(uint32_t fourcc) {
+    switch (fourcc) {
+        case FOURCC('m', 'p', '4', 'a'):
+            return "audio/mp4a-latm";
+
+        case FOURCC('s', 'a', 'm', 'r'):
+            return "audio/3gpp";
+
+        case FOURCC('m', 'p', '4', 'v'):
+            return "video/mp4v-es";
+
+        case FOURCC('s', '2', '6', '3'):
+            return "video/3gpp";
+
+        case FOURCC('a', 'v', 'c', '1'):
+            return "video/avc";
+
+        default:
+            assert(!"should not be here.");
+            return NULL;
+    }
+}
+
+MPEG4Extractor::MPEG4Extractor(DataSource *source)
+    : mDataSource(source),
+      mHaveMetadata(false),
+      mFirstTrack(NULL),
+      mLastTrack(NULL) {
+}
+
+MPEG4Extractor::~MPEG4Extractor() {
+    Track *track = mFirstTrack;
+    while (track) {
+        Track *next = track->next;
+
+        delete track->sampleTable;
+        track->sampleTable = NULL;
+
+        delete track;
+        track = next;
+    }
+    mFirstTrack = mLastTrack = NULL;
+
+    delete mDataSource;
+    mDataSource = NULL;
+}
+
+status_t MPEG4Extractor::countTracks(int *num_tracks) {
+    status_t err;
+    if ((err = readMetaData()) != OK) {
+        return err;
+    }
+
+    *num_tracks = 0;
+    Track *track = mFirstTrack;
+    while (track) {
+        ++*num_tracks;
+        track = track->next;
+    }
+
+    return OK;
+}
+
+sp<MetaData> MPEG4Extractor::getTrackMetaData(int index) {
+    if (index < 0) {
+        return NULL;
+    }
+
+    status_t err;
+    if ((err = readMetaData()) != OK) {
+        return NULL;
+    }
+
+    Track *track = mFirstTrack;
+    while (index > 0) {
+        if (track == NULL) {
+            return NULL;
+        }
+
+        track = track->next;
+        --index;
+    }
+
+    return track->meta;
+}
+
+status_t MPEG4Extractor::readMetaData() {
+    if (mHaveMetadata) {
+        return OK;
+    }
+
+    off_t offset = 0;
+    status_t err;
+    while ((err = parseChunk(&offset, 0)) == OK) {
+    }
+    
+    if (mHaveMetadata) {
+        return OK;
+    }
+
+    return err;
+}
+
+static void MakeFourCCString(uint32_t x, char *s) {
+    s[0] = x >> 24;
+    s[1] = (x >> 16) & 0xff;
+    s[2] = (x >> 8) & 0xff;
+    s[3] = x & 0xff;
+    s[4] = '\0';
+}
+
+status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
+    uint32_t hdr[2];
+    if (mDataSource->read_at(*offset, hdr, 8) < 8) {
+        return ERROR_IO;
+    }
+    uint64_t chunk_size = ntohl(hdr[0]);
+    uint32_t chunk_type = ntohl(hdr[1]);
+    off_t data_offset = *offset + 8;
+
+    if (chunk_size == 1) {
+        if (mDataSource->read_at(*offset + 8, &chunk_size, 8) < 8) {
+            return ERROR_IO;
+        }
+        chunk_size = ntoh64(chunk_size);
+        data_offset += 8;
+    }
+
+    char chunk[5];
+    MakeFourCCString(chunk_type, chunk);
+
+#if 0
+    static const char kWhitespace[] = "                                        ";
+    const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth];
+    printf("%sfound chunk '%s' of size %lld\n", indent, chunk, chunk_size);
+
+    char buffer[256];
+    if (chunk_size <= sizeof(buffer)) {
+        if (mDataSource->read_at(*offset, buffer, chunk_size) < chunk_size) {
+            return ERROR_IO;
+        }
+
+        hexdump(buffer, chunk_size);
+    }
+#endif
+
+    off_t chunk_data_size = *offset + chunk_size - data_offset;
+
+    switch(chunk_type) {
+        case FOURCC('m', 'o', 'o', 'v'):
+        case FOURCC('t', 'r', 'a', 'k'):
+        case FOURCC('m', 'd', 'i', 'a'):
+        case FOURCC('m', 'i', 'n', 'f'):
+        case FOURCC('d', 'i', 'n', 'f'):
+        case FOURCC('s', 't', 'b', 'l'):
+        case FOURCC('m', 'v', 'e', 'x'):
+        case FOURCC('m', 'o', 'o', 'f'):
+        case FOURCC('t', 'r', 'a', 'f'):
+        case FOURCC('m', 'f', 'r', 'a'):
+        case FOURCC('s', 'k', 'i' ,'p'):
+        {
+            off_t stop_offset = *offset + chunk_size;
+            *offset = data_offset;
+            while (*offset < stop_offset) {
+                status_t err = parseChunk(offset, depth + 1);
+                if (err != OK) {
+                    return err;
+                }
+            }
+            assert(*offset == stop_offset);
+
+            if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
+                mHaveMetadata = true;
+
+                return UNKNOWN_ERROR;  // Return a dummy error.
+            }
+            break;
+        }
+
+        case FOURCC('t', 'k', 'h', 'd'):
+        {
+            assert(chunk_data_size >= 4);
+
+            uint8_t version;
+            if (mDataSource->read_at(data_offset, &version, 1) < 1) {
+                return ERROR_IO;
+            }
+
+            uint64_t ctime, mtime, duration;
+            int32_t id;
+            uint32_t width, height;
+
+            if (version == 1) {
+                if (chunk_data_size != 36 + 60) {
+                    return ERROR_MALFORMED;
+                }
+
+                uint8_t buffer[36 + 60];
+                if (mDataSource->read_at(
+                            data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+                    return ERROR_IO;
+                }
+
+                ctime = U64_AT(&buffer[4]);
+                mtime = U64_AT(&buffer[12]);
+                id = U32_AT(&buffer[20]);
+                duration = U64_AT(&buffer[28]);
+                width = U32_AT(&buffer[88]);
+                height = U32_AT(&buffer[92]);
+            } else if (version == 0) {
+                if (chunk_data_size != 24 + 60) {
+                    return ERROR_MALFORMED;
+                }
+
+                uint8_t buffer[24 + 60];
+                if (mDataSource->read_at(
+                            data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+                    return ERROR_IO;
+                }
+                ctime = U32_AT(&buffer[4]);
+                mtime = U32_AT(&buffer[8]);
+                id = U32_AT(&buffer[12]);
+                duration = U32_AT(&buffer[20]);
+                width = U32_AT(&buffer[76]);
+                height = U32_AT(&buffer[80]);
+            }
+
+            Track *track = new Track;
+            track->next = NULL;
+            if (mLastTrack) {
+                mLastTrack->next = track;
+            } else {
+                mFirstTrack = track;
+            }
+            mLastTrack = track;
+
+            track->meta = new MetaData;
+            track->timescale = 0;
+            track->sampleTable = new SampleTable(mDataSource);
+            track->meta->setCString(kKeyMIMEType, "application/octet-stream");
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('m', 'd', 'h', 'd'):
+        {
+            if (chunk_data_size < 4) {
+                return ERROR_MALFORMED;
+            }
+
+            uint8_t version;
+            if (mDataSource->read_at(
+                        data_offset, &version, sizeof(version))
+                    < (ssize_t)sizeof(version)) {
+                return ERROR_IO;
+            }
+
+            off_t timescale_offset;
+
+            if (version == 1) {
+                timescale_offset = data_offset + 4 + 16;
+            } else if (version == 0) {
+                timescale_offset = data_offset + 4 + 8;
+            } else {
+                return ERROR_IO;
+            }
+
+            uint32_t timescale;
+            if (mDataSource->read_at(
+                        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(
+                            timescale_offset + 4, &duration, sizeof(duration))
+                        < (ssize_t)sizeof(duration)) {
+                    return ERROR_IO;
+                }
+                duration = ntoh64(duration);
+            } else {
+                int32_t duration32;
+                if (mDataSource->read_at(
+                            timescale_offset + 4, &duration32, sizeof(duration32))
+                        < (ssize_t)sizeof(duration32)) {
+                    return ERROR_IO;
+                }
+                duration = ntohl(duration32);
+            }
+            mLastTrack->meta->setInt32(kKeyDuration, duration);
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('h', 'd', 'l', 'r'):
+        {
+            if (chunk_data_size < 25) {
+                return ERROR_MALFORMED;
+            }
+
+            uint8_t buffer[24];
+            if (mDataSource->read_at(data_offset, buffer, 24) < 24) {
+                return ERROR_IO;
+            }
+
+            if (U32_AT(buffer) != 0) {
+                // Should be version 0, flags 0.
+                return ERROR_MALFORMED;
+            }
+
+            if (U32_AT(&buffer[4]) != 0) {
+                // pre_defined should be 0.
+                return ERROR_MALFORMED;
+            }
+
+            mHandlerType = U32_AT(&buffer[8]);
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('s', 't', 's', 'd'):
+        {
+            if (chunk_data_size < 8) {
+                return ERROR_MALFORMED;
+            }
+
+            uint8_t buffer[8];
+            assert(chunk_data_size >= (off_t)sizeof(buffer));
+            if (mDataSource->read_at(
+                        data_offset, buffer, 8) < 8) {
+                return ERROR_IO;
+            }
+
+            if (U32_AT(buffer) != 0) {
+                // Should be version 0, flags 0.
+                return ERROR_MALFORMED;
+            }
+
+            uint32_t entry_count = U32_AT(&buffer[4]);
+
+            if (entry_count > 1) {
+                // For now we only support a single type of media per track.
+                return ERROR_UNSUPPORTED;
+            }
+
+            off_t stop_offset = *offset + chunk_size;
+            *offset = data_offset + 8;
+            for (uint32_t i = 0; i < entry_count; ++i) {
+                status_t err = parseChunk(offset, depth + 1);
+                if (err != OK) {
+                    return err;
+                }
+            }
+            assert(*offset == stop_offset);
+            break;
+        }
+
+        case FOURCC('m', 'p', '4', 'a'):
+        case FOURCC('s', 'a', 'm', 'r'):
+        {
+            if (mHandlerType != FOURCC('s', 'o', 'u', 'n')) {
+                return ERROR_MALFORMED;
+            }
+
+            uint8_t buffer[8 + 20];
+            if (chunk_data_size < (ssize_t)sizeof(buffer)) {
+                // Basic AudioSampleEntry size.
+                return ERROR_MALFORMED;
+            }
+
+            if (mDataSource->read_at(
+                        data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+                return ERROR_IO;
+            }
+
+            uint16_t data_ref_index = U16_AT(&buffer[6]);
+            uint16_t num_channels = U16_AT(&buffer[16]);
+
+            if (!strcasecmp("audio/3gpp", FourCC2MIME(chunk_type))) {
+                // AMR audio is always mono.
+                num_channels = 1;
+            }
+
+            uint16_t sample_size = U16_AT(&buffer[18]);
+            uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
+
+            printf("*** coding='%s' %d channels, size %d, rate %d\n",
+                   chunk, num_channels, sample_size, sample_rate);
+
+            mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+            mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
+            mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
+
+            off_t stop_offset = *offset + chunk_size;
+            *offset = data_offset + sizeof(buffer);
+            while (*offset < stop_offset) {
+                status_t err = parseChunk(offset, depth + 1);
+                if (err != OK) {
+                    return err;
+                }
+            }
+            assert(*offset == stop_offset);
+            break;
+        }
+
+        case FOURCC('m', 'p', '4', 'v'):
+        case FOURCC('s', '2', '6', '3'):
+        case FOURCC('a', 'v', 'c', '1'):
+        {
+            if (mHandlerType != FOURCC('v', 'i', 'd', 'e')) {
+                return ERROR_MALFORMED;
+            }
+
+            uint8_t buffer[78];
+            if (chunk_data_size < (ssize_t)sizeof(buffer)) {
+                // Basic VideoSampleEntry size.
+                return ERROR_MALFORMED;
+            }
+
+            if (mDataSource->read_at(
+                        data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+                return ERROR_IO;
+            }
+
+            uint16_t data_ref_index = U16_AT(&buffer[6]);
+            uint16_t width = U16_AT(&buffer[6 + 18]);
+            uint16_t height = U16_AT(&buffer[6 + 20]);
+
+            printf("*** coding='%s' width=%d height=%d\n",
+                   chunk, width, height);
+
+            mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+            mLastTrack->meta->setInt32(kKeyWidth, width);
+            mLastTrack->meta->setInt32(kKeyHeight, height);
+
+            off_t stop_offset = *offset + chunk_size;
+            *offset = data_offset + sizeof(buffer);
+            while (*offset < stop_offset) {
+                status_t err = parseChunk(offset, depth + 1);
+                if (err != OK) {
+                    return err;
+                }
+            }
+            assert(*offset == stop_offset);
+            break;
+        }
+
+        case FOURCC('s', 't', 'c', 'o'):
+        case FOURCC('c', 'o', '6', '4'):
+        {
+            status_t err =
+                mLastTrack->sampleTable->setChunkOffsetParams(
+                        chunk_type, data_offset, chunk_data_size);
+
+            if (err != OK) {
+                return err;
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('s', 't', 's', 'c'):
+        {
+            status_t err =
+                mLastTrack->sampleTable->setSampleToChunkParams(
+                        data_offset, chunk_data_size);
+
+            if (err != OK) {
+                return err;
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('s', 't', 's', 'z'):
+        case FOURCC('s', 't', 'z', '2'):
+        {
+            status_t err =
+                mLastTrack->sampleTable->setSampleSizeParams(
+                        chunk_type, data_offset, chunk_data_size);
+
+            if (err != OK) {
+                return err;
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('s', 't', 't', 's'):
+        {
+            status_t err =
+                mLastTrack->sampleTable->setTimeToSampleParams(
+                        data_offset, chunk_data_size);
+
+            if (err != OK) {
+                return err;
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('s', 't', 's', 's'):
+        {
+            status_t err =
+                mLastTrack->sampleTable->setSyncSampleParams(
+                        data_offset, chunk_data_size);
+
+            if (err != OK) {
+                return err;
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('e', 's', 'd', 's'):
+        {
+            if (chunk_data_size < 4) {
+                return ERROR_MALFORMED;
+            }
+
+            uint8_t buffer[256];
+            if (chunk_data_size > (off_t)sizeof(buffer)) {
+                return ERROR_BUFFER_TOO_SMALL;
+            }
+
+            if (mDataSource->read_at(
+                        data_offset, buffer, chunk_data_size) < chunk_data_size) {
+                return ERROR_IO;
+            }
+
+            if (U32_AT(buffer) != 0) {
+                // Should be version 0, flags 0.
+                return ERROR_MALFORMED;
+            }
+
+            mLastTrack->meta->setData(
+                    kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
+
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('a', 'v', 'c', 'C'):
+        {
+            char buffer[256];
+            if (chunk_data_size > (off_t)sizeof(buffer)) {
+                return ERROR_BUFFER_TOO_SMALL;
+            }
+
+            if (mDataSource->read_at(
+                        data_offset, buffer, chunk_data_size) < chunk_data_size) {
+                return ERROR_IO;
+            }
+
+            mLastTrack->meta->setData(
+                    kKeyAVCC, kTypeAVCC, buffer, chunk_data_size);
+
+            *offset += chunk_size;
+            break;
+        }
+
+        default:
+        {
+            *offset += chunk_size;
+            break;
+        }
+    }
+
+    return OK;
+}
+
+status_t MPEG4Extractor::getTrack(int index, MediaSource **source) {
+    *source = NULL;
+
+    if (index < 0) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    status_t err;
+    if ((err = readMetaData()) != OK) {
+        return err;
+    }
+
+    Track *track = mFirstTrack;
+    while (index > 0) {
+        if (track == NULL) {
+            return ERROR_OUT_OF_RANGE;
+        }
+
+        track = track->next;
+        --index;
+    }
+
+    *source = new MPEG4Source(
+            track->meta, mDataSource, track->sampleTable);
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG4Source::MPEG4Source(
+        const sp<MetaData> &format,
+        DataSource *dataSource, SampleTable *sampleTable)
+    : mFormat(format),
+      mDataSource(dataSource),
+      mTimescale(0),
+      mSampleTable(sampleTable),
+      mCurrentSampleIndex(0),
+      mIsAVC(false),
+      mStarted(false),
+      mGroup(NULL),
+      mBuffer(NULL),
+      mBufferOffset(0),
+      mBufferSizeRemaining(0),
+      mNeedsNALFraming(false),
+      mSrcBuffer(NULL) {
+    const char *mime;
+    bool success = mFormat->findCString(kKeyMIMEType, &mime);
+    assert(success);
+
+    success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
+    assert(success);
+
+    mIsAVC = !strcasecmp(mime, "video/avc");
+}
+
+MPEG4Source::~MPEG4Source() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t MPEG4Source::start(MetaData *params) {
+    assert(!mStarted);
+
+    int32_t val;
+    if (mIsAVC && params && params->findInt32(kKeyNeedsNALFraming, &val)
+        && val != 0) {
+        mNeedsNALFraming = true;
+    } else {
+        mNeedsNALFraming = false;
+    }
+
+    mGroup = new MediaBufferGroup;
+
+    size_t max_size;
+    status_t err = mSampleTable->getMaxSampleSize(&max_size);
+    assert(err == OK);
+
+    // Assume that a given buffer only contains at most 10 fragments,
+    // each fragment originally prefixed with a 2 byte length will
+    // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
+    // and thus will grow by 2 bytes per fragment.
+    mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
+
+    mSrcBuffer = new uint8_t[max_size];
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t MPEG4Source::stop() {
+    assert(mStarted);
+
+    if (mBuffer != NULL) {
+        mBuffer->release();
+        mBuffer = NULL;
+    }
+
+    delete[] mSrcBuffer;
+    mSrcBuffer = NULL;
+
+    delete mGroup;
+    mGroup = NULL;
+
+    mStarted = false;
+    mCurrentSampleIndex = 0;
+
+    return OK;
+}
+
+sp<MetaData> MPEG4Source::getFormat() {
+    return mFormat;
+}
+
+status_t MPEG4Source::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    assert(mStarted);
+
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        uint32_t sampleIndex;
+        status_t err = mSampleTable->findClosestSample(
+                seekTimeUs * mTimescale / 1000000,
+                &sampleIndex, SampleTable::kSyncSample_Flag);
+
+        if (err != OK) {
+            return err;
+        }
+
+        mCurrentSampleIndex = sampleIndex;
+        if (mBuffer != NULL) {
+            mBuffer->release();
+            mBuffer = NULL;
+        }
+
+        // fall through
+    }
+
+    off_t offset;
+    size_t size;
+    status_t err = mSampleTable->getSampleOffsetAndSize(
+            mCurrentSampleIndex, &offset, &size);
+
+    if (err != OK) {
+        return err;
+    }
+
+    uint32_t dts;
+    err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+
+    if (err != OK) {
+        return err;
+    }
+
+    err = mGroup->acquire_buffer(&mBuffer);
+    if (err != OK) {
+        assert(mBuffer == NULL);
+        return err;
+    }
+
+    if (!mIsAVC || !mNeedsNALFraming) {
+        ssize_t num_bytes_read =
+            mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
+
+        if (num_bytes_read < (ssize_t)size) {
+            mBuffer->release();
+            mBuffer = NULL;
+
+            return err;
+        }
+
+        mBuffer->set_range(0, size);
+        mBuffer->meta_data()->clear();
+        mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+        mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+        ++mCurrentSampleIndex;
+
+        *out = mBuffer;
+        mBuffer = NULL;
+
+        return OK;
+    }
+
+    ssize_t num_bytes_read =
+        mDataSource->read_at(offset, mSrcBuffer, size);
+
+    if (num_bytes_read < (ssize_t)size) {
+        mBuffer->release();
+        mBuffer = NULL;
+
+        return err;
+    }
+
+    uint8_t *dstData = (uint8_t *)mBuffer->data();
+    size_t srcOffset = 0;
+    size_t dstOffset = 0;
+    while (srcOffset < size) {
+        assert(srcOffset + 1 < size);
+        size_t nalLength =
+            (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+        assert(srcOffset + 1 + nalLength < size);
+        srcOffset += 2;
+
+        if (nalLength == 0) {
+            continue;
+        }
+
+        assert(dstOffset + 4 <= mBuffer->size());
+
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 1;
+        memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+        srcOffset += nalLength;
+        dstOffset += nalLength;
+    }
+
+    mBuffer->set_range(0, dstOffset);
+    mBuffer->meta_data()->clear();
+    mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+    mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+    ++mCurrentSampleIndex;
+
+    *out = mBuffer;
+    mBuffer = NULL;
+
+    return OK;
+}
+
+bool SniffMPEG4(DataSource *source, String8 *mimeType, float *confidence) {
+    uint8_t header[8];
+
+    ssize_t n = source->read_at(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)) {
+        *mimeType = "video/mp4";
+        *confidence = 0.1;
+
+        return true;
+    }
+
+    return false;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
new file mode 100644
index 0000000..6bdf282
--- /dev/null
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -0,0 +1,641 @@
+/*
+ * 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 <arpa/inet.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <ctype.h>
+#include <pthread.h>
+
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+class MPEG4Writer::Track {
+public:
+    Track(MPEG4Writer *owner, const sp<MetaData> &meta, MediaSource *source);
+    ~Track();
+
+    void start();
+    void stop();
+
+    int64_t getDuration() const;
+    void writeTrackHeader(int32_t trackID);
+
+private:
+    MPEG4Writer *mOwner;
+    sp<MetaData> mMeta;
+    MediaSource *mSource;
+    volatile bool mDone;
+
+    pthread_t mThread;
+
+    struct SampleInfo {
+        size_t size;
+        off_t offset;
+        int64_t timestamp;
+    };
+    List<SampleInfo> mSampleInfos;
+
+    void *mCodecSpecificData;
+    size_t mCodecSpecificDataSize;
+
+    static void *ThreadWrapper(void *me);
+    void threadEntry();
+
+    Track(const Track &);
+    Track &operator=(const Track &);
+};
+
+MPEG4Writer::MPEG4Writer(const char *filename)
+    : mFile(fopen(filename, "wb")),
+      mOffset(0),
+      mMdatOffset(0) {
+    assert(mFile != NULL);
+}
+
+MPEG4Writer::~MPEG4Writer() {
+    stop();
+
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        delete *it;
+    }
+    mTracks.clear();
+}
+
+void MPEG4Writer::addSource(const sp<MetaData> &meta, MediaSource *source) {
+    Track *track = new Track(this, meta, source);
+    mTracks.push_back(track);
+}
+
+void MPEG4Writer::start() {
+    if (mFile == NULL) {
+        return;
+    }
+
+    beginBox("ftyp");
+      writeFourcc("isom");
+      writeInt32(0);
+      writeFourcc("isom");
+    endBox();
+
+    mMdatOffset = mOffset;
+    write("\x00\x00\x00\x01mdat????????", 16);
+
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        (*it)->start();
+    }
+}
+
+void MPEG4Writer::stop() {
+    if (mFile == NULL) {
+        return;
+    }
+
+    int64_t max_duration = 0;
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        (*it)->stop();
+
+        int64_t duration = (*it)->getDuration();
+        if (duration > max_duration) {
+            max_duration = duration;
+        }
+    }
+
+    // Fix up the size of the 'mdat' chunk.
+    fseek(mFile, mMdatOffset + 8, SEEK_SET);
+    int64_t size = mOffset - mMdatOffset;
+    size = hton64(size);
+    fwrite(&size, 1, 8, mFile);
+    fseek(mFile, mOffset, SEEK_SET);
+
+    time_t now = time(NULL);
+
+    beginBox("moov");
+
+      beginBox("mvhd");
+        writeInt32(0);             // version=0, flags=0
+        writeInt32(now);           // creation time
+        writeInt32(now);           // modification time
+        writeInt32(1000);          // timescale
+        writeInt32(max_duration);
+        writeInt32(0x10000);       // rate
+        writeInt16(0x100);         // volume
+        writeInt16(0);             // reserved
+        writeInt32(0);             // reserved
+        writeInt32(0);             // reserved
+        writeInt32(0x10000);       // matrix
+        writeInt32(0);
+        writeInt32(0);
+        writeInt32(0);
+        writeInt32(0x10000);
+        writeInt32(0);
+        writeInt32(0);
+        writeInt32(0);
+        writeInt32(0x40000000);
+        writeInt32(0);             // predefined
+        writeInt32(0);             // predefined
+        writeInt32(0);             // predefined
+        writeInt32(0);             // predefined
+        writeInt32(0);             // predefined
+        writeInt32(0);             // predefined
+        writeInt32(mTracks.size() + 1);  // nextTrackID
+      endBox();  // mvhd
+
+      int32_t id = 1;
+      for (List<Track *>::iterator it = mTracks.begin();
+           it != mTracks.end(); ++it, ++id) {
+          (*it)->writeTrackHeader(id);
+      }
+    endBox();  // moov
+
+    assert(mBoxes.empty());
+
+    fclose(mFile);
+    mFile = NULL;
+}
+
+off_t MPEG4Writer::addSample(MediaBuffer *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    off_t old_offset = mOffset;
+
+    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
+           1, buffer->range_length(), mFile);
+
+    mOffset += buffer->range_length();
+
+    return old_offset;
+}
+
+void MPEG4Writer::beginBox(const char *fourcc) {
+    assert(strlen(fourcc) == 4);
+
+    mBoxes.push_back(mOffset);
+
+    writeInt32(0);
+    writeFourcc(fourcc);
+}
+
+void MPEG4Writer::endBox() {
+    assert(!mBoxes.empty());
+
+    off_t offset = *--mBoxes.end();
+    mBoxes.erase(--mBoxes.end());
+
+    fseek(mFile, offset, SEEK_SET);
+    writeInt32(mOffset - offset);
+    mOffset -= 4;
+    fseek(mFile, mOffset, SEEK_SET);
+}
+
+void MPEG4Writer::writeInt8(int8_t x) {
+    fwrite(&x, 1, 1, mFile);
+    ++mOffset;
+}
+
+void MPEG4Writer::writeInt16(int16_t x) {
+    x = htons(x);
+    fwrite(&x, 1, 2, mFile);
+    mOffset += 2;
+}
+
+void MPEG4Writer::writeInt32(int32_t x) {
+    x = htonl(x);
+    fwrite(&x, 1, 4, mFile);
+    mOffset += 4;
+}
+
+void MPEG4Writer::writeInt64(int64_t x) {
+    x = hton64(x);
+    fwrite(&x, 1, 8, mFile);
+    mOffset += 8;
+}
+
+void MPEG4Writer::writeCString(const char *s) {
+    size_t n = strlen(s);
+
+    fwrite(s, 1, n + 1, mFile);
+    mOffset += n + 1;
+}
+
+void MPEG4Writer::writeFourcc(const char *s) {
+    assert(strlen(s) == 4);
+    fwrite(s, 1, 4, mFile);
+    mOffset += 4;
+}
+
+void MPEG4Writer::write(const void *data, size_t size) {
+    fwrite(data, 1, size, mFile);
+    mOffset += size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG4Writer::Track::Track(
+        MPEG4Writer *owner, const sp<MetaData> &meta, MediaSource *source)
+    : mOwner(owner),
+      mMeta(meta),
+      mSource(source),
+      mDone(false),
+      mCodecSpecificData(NULL),
+      mCodecSpecificDataSize(0) {
+}
+
+MPEG4Writer::Track::~Track() {
+    stop();
+
+    if (mCodecSpecificData != NULL) {
+        free(mCodecSpecificData);
+        mCodecSpecificData = NULL;
+    }
+}
+
+void MPEG4Writer::Track::start() {
+    mSource->start();
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    mDone = false;
+
+    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
+    assert(err == 0);
+
+    pthread_attr_destroy(&attr);
+}
+
+void MPEG4Writer::Track::stop() {
+    if (mDone) {
+        return;
+    }
+
+    mDone = true;
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+
+    mSource->stop();
+}
+
+// static
+void *MPEG4Writer::Track::ThreadWrapper(void *me) {
+    Track *track = static_cast<Track *>(me);
+
+    track->threadEntry();
+
+    return NULL;
+}
+
+void MPEG4Writer::Track::threadEntry() {
+    bool is_mpeg4 = false;
+    sp<MetaData> meta = mSource->getFormat();
+    const char *mime;
+    meta->findCString(kKeyMIMEType, &mime);
+    is_mpeg4 = !strcasecmp(mime, "video/mp4v-es");
+
+    MediaBuffer *buffer;
+    while (!mDone && mSource->read(&buffer) == OK) {
+        if (buffer->range_length() == 0) {
+            buffer->release();
+            buffer = NULL;
+
+            continue;
+        }
+
+        if (mCodecSpecificData == NULL && is_mpeg4) {
+            const uint8_t *data =
+                (const uint8_t *)buffer->data() + buffer->range_offset();
+
+            const size_t size = buffer->range_length();
+
+            size_t offset = 0;
+            while (offset + 3 < size) {
+                if (data[offset] == 0x00 && data[offset + 1] == 0x00
+                    && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
+                    break;
+                }
+
+                ++offset;
+            }
+
+            assert(offset + 3 < size);
+
+            mCodecSpecificDataSize = offset;
+            mCodecSpecificData = malloc(offset);
+            memcpy(mCodecSpecificData, data, offset);
+
+            buffer->set_range(buffer->range_offset() + offset, size - offset);
+        }
+
+        off_t offset = mOwner->addSample(buffer);
+
+        SampleInfo info;
+        info.size = buffer->range_length();
+        info.offset = offset;
+
+        int32_t units, scale;
+        bool success =
+            buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+        assert(success);
+        success =
+            buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+        assert(success);
+
+        info.timestamp = (int64_t)units * 1000 / scale;
+
+        mSampleInfos.push_back(info);
+
+        buffer->release();
+        buffer = NULL;
+    }
+}
+
+int64_t MPEG4Writer::Track::getDuration() const {
+    return 10000;  // XXX
+}
+
+void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
+    const char *mime;
+    bool success = mMeta->findCString(kKeyMIMEType, &mime);
+    assert(success);
+
+    bool is_audio = !strncasecmp(mime, "audio/", 6);
+
+    time_t now = time(NULL);
+
+    mOwner->beginBox("trak");
+
+      mOwner->beginBox("tkhd");
+        mOwner->writeInt32(0);             // version=0, flags=0
+        mOwner->writeInt32(now);           // creation time
+        mOwner->writeInt32(now);           // modification time
+        mOwner->writeInt32(trackID);
+        mOwner->writeInt32(0);             // reserved
+        mOwner->writeInt32(getDuration());
+        mOwner->writeInt32(0);             // reserved
+        mOwner->writeInt32(0);             // reserved
+        mOwner->writeInt16(0);             // layer
+        mOwner->writeInt16(0);             // alternate group
+        mOwner->writeInt16(is_audio ? 0x100 : 0);  // volume
+        mOwner->writeInt16(0);             // reserved
+
+        mOwner->writeInt32(0x10000);       // matrix
+        mOwner->writeInt32(0);
+        mOwner->writeInt32(0);
+        mOwner->writeInt32(0);
+        mOwner->writeInt32(0x10000);
+        mOwner->writeInt32(0);
+        mOwner->writeInt32(0);
+        mOwner->writeInt32(0);
+        mOwner->writeInt32(0x40000000);
+
+        if (is_audio) {
+            mOwner->writeInt32(0);
+            mOwner->writeInt32(0);
+        } else {
+            int32_t width, height;
+            bool success = mMeta->findInt32(kKeyWidth, &width);
+            success = success && mMeta->findInt32(kKeyHeight, &height);
+            assert(success);
+
+            mOwner->writeInt32(width);
+            mOwner->writeInt32(height);
+        }
+      mOwner->endBox();  // tkhd
+
+      mOwner->beginBox("mdia");
+
+        mOwner->beginBox("mdhd");
+          mOwner->writeInt32(0);             // version=0, flags=0
+          mOwner->writeInt32(now);           // creation time
+          mOwner->writeInt32(now);           // modification time
+          mOwner->writeInt32(1000);          // timescale
+          mOwner->writeInt32(getDuration());
+          mOwner->writeInt16(0);             // language code XXX
+          mOwner->writeInt16(0);             // predefined
+        mOwner->endBox();
+
+        mOwner->beginBox("hdlr");
+          mOwner->writeInt32(0);             // version=0, flags=0
+          mOwner->writeInt32(0);             // predefined
+          mOwner->writeFourcc(is_audio ? "soun" : "vide");
+          mOwner->writeInt32(0);             // reserved
+          mOwner->writeInt32(0);             // reserved
+          mOwner->writeInt32(0);             // reserved
+          mOwner->writeCString("");          // name
+        mOwner->endBox();
+
+        mOwner->beginBox("minf");
+
+          mOwner->beginBox("dinf");
+            mOwner->beginBox("dref");
+              mOwner->writeInt32(0);  // version=0, flags=0
+              mOwner->writeInt32(1);
+              mOwner->beginBox("url ");
+                mOwner->writeInt32(1);  // version=0, flags=1
+              mOwner->endBox();  // url
+            mOwner->endBox();  // dref
+          mOwner->endBox();  // dinf
+
+          if (is_audio) {
+              mOwner->beginBox("smhd");
+              mOwner->writeInt32(0);           // version=0, flags=0
+              mOwner->writeInt16(0);           // balance
+              mOwner->writeInt16(0);           // reserved
+              mOwner->endBox();
+          } else {
+              mOwner->beginBox("vmhd");
+              mOwner->writeInt32(0x00000001);  // version=0, flags=1
+              mOwner->writeInt16(0);           // graphics mode
+              mOwner->writeInt16(0);           // opcolor
+              mOwner->writeInt16(0);
+              mOwner->writeInt16(0);
+              mOwner->endBox();
+          }
+        mOwner->endBox();  // minf
+
+        mOwner->beginBox("stbl");
+
+          mOwner->beginBox("stsd");
+            mOwner->writeInt32(0);               // version=0, flags=0
+            mOwner->writeInt32(1);               // entry count
+            if (is_audio) {
+                mOwner->beginBox("xxxx");          // audio format XXX
+                  mOwner->writeInt32(0);           // reserved
+                  mOwner->writeInt16(0);           // reserved
+                  mOwner->writeInt16(0);           // data ref index
+                  mOwner->writeInt32(0);           // reserved
+                  mOwner->writeInt32(0);           // reserved
+                  mOwner->writeInt16(2);           // channel count
+                  mOwner->writeInt16(16);          // sample size
+                  mOwner->writeInt16(0);           // predefined
+                  mOwner->writeInt16(0);           // reserved
+
+                  int32_t samplerate;
+                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
+                  assert(success);
+
+                  mOwner->writeInt32(samplerate << 16);
+                mOwner->endBox();
+            } else {
+                if (!strcasecmp("video/mp4v-es", mime)) {
+                    mOwner->beginBox("mp4v");
+                } else if (!strcasecmp("video/3gpp", mime)) {
+                    mOwner->beginBox("s263");
+                } else {
+                    assert(!"should not be here, unknown mime type.");
+                }
+
+                  mOwner->writeInt32(0);           // reserved
+                  mOwner->writeInt16(0);           // reserved
+                  mOwner->writeInt16(0);           // data ref index
+                  mOwner->writeInt16(0);           // predefined
+                  mOwner->writeInt16(0);           // reserved
+                  mOwner->writeInt32(0);           // predefined
+                  mOwner->writeInt32(0);           // predefined
+                  mOwner->writeInt32(0);           // predefined
+
+                  int32_t width, height;
+                  bool success = mMeta->findInt32(kKeyWidth, &width);
+                  success = success && mMeta->findInt32(kKeyHeight, &height);
+                  assert(success);
+
+                  mOwner->writeInt16(width);
+                  mOwner->writeInt16(height);
+                  mOwner->writeInt32(0x480000);    // horiz resolution
+                  mOwner->writeInt32(0x480000);    // vert resolution
+                  mOwner->writeInt32(0);           // reserved
+                  mOwner->writeInt16(1);           // frame count
+                  mOwner->write("                                ", 32);
+                  mOwner->writeInt16(0x18);        // depth
+                  mOwner->writeInt16(-1);          // predefined
+
+                  assert(23 + mCodecSpecificDataSize < 128);
+
+                  if (!strcasecmp("video/mp4v-es", mime)) {
+                      mOwner->beginBox("esds");
+
+                        mOwner->writeInt32(0);           // version=0, flags=0
+
+                        mOwner->writeInt8(0x03);  // ES_DescrTag
+                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
+                        mOwner->writeInt16(0x0000);  // ES_ID
+                        mOwner->writeInt8(0x1f);
+
+                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
+                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
+                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
+                        mOwner->writeInt8(0x11);  // streamType VisualStream
+
+                        static const uint8_t kData[] = {
+                            0x01, 0x77, 0x00,
+                            0x00, 0x03, 0xe8, 0x00,
+                            0x00, 0x03, 0xe8, 0x00
+                        };
+                        mOwner->write(kData, sizeof(kData));
+                        
+                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
+
+                        mOwner->writeInt8(mCodecSpecificDataSize);
+                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
+
+                        static const uint8_t kData2[] = {
+                            0x06,  // SLConfigDescriptorTag
+                            0x01,
+                            0x02
+                        };
+                        mOwner->write(kData2, sizeof(kData2));
+
+                      mOwner->endBox();  // esds
+                  } else if (!strcasecmp("video/3gpp", mime)) {
+                      mOwner->beginBox("d263");
+
+                          mOwner->writeInt32(0);  // vendor
+                          mOwner->writeInt8(0);   // decoder version
+                          mOwner->writeInt8(10);  // level: 10
+                          mOwner->writeInt8(0);   // profile: 0
+
+                      mOwner->endBox();  // d263
+                  }
+                mOwner->endBox();  // mp4v or s263
+            }
+          mOwner->endBox();  // stsd
+
+          mOwner->beginBox("stts");
+            mOwner->writeInt32(0);  // version=0, flags=0
+            mOwner->writeInt32(mSampleInfos.size() - 1);
+
+            List<SampleInfo>::iterator it = mSampleInfos.begin();
+            int64_t last = (*it).timestamp;
+            ++it;
+            while (it != mSampleInfos.end()) {
+                mOwner->writeInt32(1);
+                mOwner->writeInt32((*it).timestamp - last);
+
+                last = (*it).timestamp;
+
+                ++it;
+            }
+          mOwner->endBox();  // stts
+
+          mOwner->beginBox("stsz");
+            mOwner->writeInt32(0);  // version=0, flags=0
+            mOwner->writeInt32(0);  // default sample size
+            mOwner->writeInt32(mSampleInfos.size());
+            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+                 it != mSampleInfos.end(); ++it) {
+                mOwner->writeInt32((*it).size);
+            }
+          mOwner->endBox();  // stsz
+
+          mOwner->beginBox("stsc");
+            mOwner->writeInt32(0);  // version=0, flags=0
+            mOwner->writeInt32(mSampleInfos.size());
+            int32_t n = 1;
+            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+                 it != mSampleInfos.end(); ++it, ++n) {
+                mOwner->writeInt32(n);
+                mOwner->writeInt32(1);
+                mOwner->writeInt32(1);
+            }
+          mOwner->endBox();  // stsc
+
+          mOwner->beginBox("co64");
+            mOwner->writeInt32(0);  // version=0, flags=0
+            mOwner->writeInt32(mSampleInfos.size());
+            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+                 it != mSampleInfos.end(); ++it, ++n) {
+                mOwner->writeInt64((*it).offset);
+            }
+          mOwner->endBox();  // co64
+
+        mOwner->endBox();  // stbl
+      mOwner->endBox();  // mdia
+    mOwner->endBox();  // trak
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
new file mode 100644
index 0000000..cd78dbd
--- /dev/null
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaBuffer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+// XXX make this truly atomic.
+static int atomic_add(int *value, int delta) {
+    int prev_value = *value;
+    *value += delta;
+
+    return prev_value;
+}
+
+MediaBuffer::MediaBuffer(void *data, size_t size)
+    : mObserver(NULL),
+      mNextBuffer(NULL),
+      mRefCount(0),
+      mData(data),
+      mSize(size),
+      mRangeOffset(0),
+      mRangeLength(size),
+      mOwnsData(false),
+      mMetaData(new MetaData),
+      mOriginal(NULL) {
+}
+
+MediaBuffer::MediaBuffer(size_t size)
+    : mObserver(NULL),
+      mNextBuffer(NULL),
+      mRefCount(0),
+      mData(malloc(size)),
+      mSize(size),
+      mRangeOffset(0),
+      mRangeLength(size),
+      mOwnsData(true),
+      mMetaData(new MetaData),
+      mOriginal(NULL) {
+}
+
+void MediaBuffer::release() {
+    if (mObserver == NULL) {
+        assert(mRefCount == 0);
+        delete this;
+        return;
+    }
+
+    int prevCount = atomic_add(&mRefCount, -1);
+    if (prevCount == 1) {
+        if (mObserver == NULL) {
+            delete this;
+            return;
+        }
+
+        mObserver->signalBufferReturned(this);
+    }
+    assert(prevCount > 0);
+}
+
+void MediaBuffer::claim() {
+    assert(mObserver != NULL);
+    assert(mRefCount == 1);
+
+    mRefCount = 0;
+}
+
+void MediaBuffer::add_ref() {
+    atomic_add(&mRefCount, 1);
+}
+
+void *MediaBuffer::data() const {
+    return mData;
+}
+
+size_t MediaBuffer::size() const {
+    return mSize;
+}
+
+size_t MediaBuffer::range_offset() const {
+    return mRangeOffset;
+}
+
+size_t MediaBuffer::range_length() const {
+    return mRangeLength;
+}
+
+void MediaBuffer::set_range(size_t offset, size_t length) {
+    if (offset < 0 || offset + length > mSize) {
+        LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
+    }
+    assert(offset >= 0 && offset + length <= mSize);
+
+    mRangeOffset = offset;
+    mRangeLength = length;
+}
+
+sp<MetaData> MediaBuffer::meta_data() {
+    return mMetaData;
+}
+
+void MediaBuffer::reset() {
+    mMetaData->clear();
+    set_range(0, mSize);
+}
+
+MediaBuffer::~MediaBuffer() {
+    assert(mObserver == NULL);
+
+    if (mOwnsData && mData != NULL) {
+        free(mData);
+        mData = NULL;
+    }
+
+    if (mOriginal != NULL) {
+        mOriginal->release();
+        mOriginal = NULL;
+    }
+}
+
+void MediaBuffer::setObserver(MediaBufferObserver *observer) {
+    assert(observer == NULL || mObserver == NULL);
+    mObserver = observer;
+}
+
+void MediaBuffer::setNextBuffer(MediaBuffer *buffer) {
+    mNextBuffer = buffer;
+}
+
+MediaBuffer *MediaBuffer::nextBuffer() {
+    return mNextBuffer;
+}
+
+int MediaBuffer::refcount() const {
+    return mRefCount;
+}
+
+MediaBuffer *MediaBuffer::clone() {
+    MediaBuffer *buffer = new MediaBuffer(mData, mSize);
+    buffer->set_range(mRangeOffset, mRangeLength);
+    buffer->mMetaData = new MetaData(*mMetaData.get());
+
+    add_ref();
+    buffer->mOriginal = this;
+
+    return buffer;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
new file mode 100644
index 0000000..aec7722
--- /dev/null
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaBufferGroup"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+
+namespace android {
+
+MediaBufferGroup::MediaBufferGroup()
+    : mFirstBuffer(NULL),
+      mLastBuffer(NULL) {
+}
+
+MediaBufferGroup::~MediaBufferGroup() {
+    MediaBuffer *next;
+    for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
+         buffer = next) {
+        next = buffer->nextBuffer();
+
+        assert(buffer->refcount() == 0);
+
+        buffer->setObserver(NULL);
+        buffer->release();
+    }
+}
+
+void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    buffer->setObserver(this);
+
+    if (mLastBuffer) {
+        mLastBuffer->setNextBuffer(buffer);
+    } else {
+        mFirstBuffer = buffer;
+    }
+
+    mLastBuffer = buffer;
+}
+
+status_t MediaBufferGroup::acquire_buffer(MediaBuffer **out) {
+    Mutex::Autolock autoLock(mLock);
+
+    for (;;) {
+        for (MediaBuffer *buffer = mFirstBuffer;
+             buffer != NULL; buffer = buffer->nextBuffer()) {
+            if (buffer->refcount() == 0) {
+                buffer->add_ref();
+                buffer->reset();
+
+                *out = buffer;
+                goto exit;
+            }
+        }
+
+        // All buffers are in use. Block until one of them is returned to us.
+        mCondition.wait(mLock);
+    }
+
+exit:
+    return OK;
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
+    Mutex::Autolock autoLock(mLock);
+    mCondition.signal();
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
new file mode 100644
index 0000000..bc66794
--- /dev/null
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "MediaExtractor"
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+MediaExtractor *MediaExtractor::Create(DataSource *source, const char *mime) {
+    String8 tmp;
+    if (mime == NULL) {
+        float confidence;
+        if (!source->sniff(&tmp, &confidence)) {
+            LOGE("FAILED to autodetect media content.");
+
+            return NULL;
+        }
+
+        mime = tmp.string();
+        LOGI("Autodetected media content as '%s' with confidence %.2f",
+             mime, confidence);
+    }
+
+    if (!strcasecmp(mime, "video/mp4") || !strcasecmp(mime, "audio/mp4")) {
+        return new MPEG4Extractor(source);
+    } else if (!strcasecmp(mime, "audio/mpeg")) {
+        return new MP3Extractor(source);
+    }
+
+    return NULL;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
new file mode 100644
index 0000000..04c9a11
--- /dev/null
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -0,0 +1,710 @@
+/*
+ * 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 "MediaPlayerImpl"
+#include "utils/Log.h"
+
+#undef NDEBUG
+#include <assert.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/MediaExtractor.h>
+#include <media/stagefright/MediaPlayerImpl.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXDecoder.h>
+#include <media/stagefright/QComHardwareRenderer.h>
+#include <media/stagefright/ShoutcastSource.h>
+#include <media/stagefright/SoftwareRenderer.h>
+#include <media/stagefright/SurfaceRenderer.h>
+#include <media/stagefright/TimeSource.h>
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <ui/PixelFormat.h>
+#include <ui/Surface.h>
+
+namespace android {
+
+MediaPlayerImpl::MediaPlayerImpl(const char *uri)
+    : mInitCheck(NO_INIT),
+      mExtractor(NULL), 
+      mTimeSource(NULL),
+      mAudioSource(NULL),
+      mAudioDecoder(NULL),
+      mAudioPlayer(NULL),
+      mVideoSource(NULL),
+      mVideoDecoder(NULL),
+      mVideoWidth(0),
+      mVideoHeight(0),
+      mVideoPosition(0),
+      mDuration(0),
+      mPlaying(false),
+      mPaused(false),
+      mRenderer(NULL),
+      mSeeking(false),
+      mFrameSize(0),
+      mUseSoftwareColorConversion(false) {
+    LOGI("MediaPlayerImpl(%s)", uri);
+    DataSource::RegisterDefaultSniffers();
+
+    status_t err = mClient.connect();
+    if (err != OK) {
+        LOGE("Failed to connect to OMXClient.");
+        return;
+    }
+
+    if (!strncasecmp("shoutcast://", uri, 12)) {
+        setAudioSource(makeShoutcastSource(uri));
+#if 0
+    } else if (!strncasecmp("camera:", uri, 7)) {
+        mVideoWidth = 480;
+        mVideoHeight = 320;
+        mVideoDecoder = CameraSource::Create();
+#endif
+    } else {
+        DataSource *source = NULL;
+        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);
+
+        if (mExtractor == NULL) {
+            return;
+        }
+    }
+
+    init();
+
+    mInitCheck = OK;
+}
+
+MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
+    : mInitCheck(NO_INIT),
+      mExtractor(NULL), 
+      mTimeSource(NULL),
+      mAudioSource(NULL),
+      mAudioDecoder(NULL),
+      mAudioPlayer(NULL),
+      mVideoSource(NULL),
+      mVideoDecoder(NULL),
+      mVideoWidth(0),
+      mVideoHeight(0),
+      mVideoPosition(0),
+      mDuration(0),
+      mPlaying(false),
+      mPaused(false),
+      mRenderer(NULL),
+      mSeeking(false),
+      mFrameSize(0),
+      mUseSoftwareColorConversion(false) {
+    LOGI("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
+    DataSource::RegisterDefaultSniffers();
+
+    status_t err = mClient.connect();
+    if (err != OK) {
+        LOGE("Failed to connect to OMXClient.");
+        return;
+    }
+
+    mExtractor = MediaExtractor::Create(
+            new MmapSource(fd, offset, length));
+
+    if (mExtractor == NULL) {
+        return;
+    }
+
+    init();
+
+    mInitCheck = OK;
+}
+
+status_t MediaPlayerImpl::initCheck() const {
+    return mInitCheck;
+}
+
+MediaPlayerImpl::~MediaPlayerImpl() {
+    stop();
+    setSurface(NULL);
+
+    LOGV("Shutting down audio.");
+    delete mAudioDecoder;
+    mAudioDecoder = NULL;
+
+    delete mAudioSource;
+    mAudioSource = NULL;
+
+    LOGV("Shutting down video.");
+    delete mVideoDecoder;
+    mVideoDecoder = NULL;
+
+    delete mVideoSource;
+    mVideoSource = NULL;
+
+    delete mExtractor;
+    mExtractor = NULL;
+
+    if (mInitCheck == OK) {
+        mClient.disconnect();
+    }
+
+    LOGV("~MediaPlayerImpl done.");
+}
+
+void MediaPlayerImpl::play() {
+    LOGI("play");
+
+    if (mPlaying) {
+        if (mPaused) {
+            if (mAudioSource != NULL) {
+                mAudioPlayer->resume();
+            }
+            mPaused = false;
+        }
+        return;
+    }
+
+    mPlaying = true;
+
+    if (mAudioSource != NULL) {
+        mAudioPlayer = new AudioPlayer(mAudioSink);
+        mAudioPlayer->setSource(mAudioDecoder);
+        mAudioPlayer->start();
+        mTimeSource = mAudioPlayer;
+    } else {
+        mTimeSource = new SystemTimeSource;
+    }
+
+    if (mVideoDecoder != NULL) {
+        pthread_attr_t attr;
+        pthread_attr_init(&attr);
+        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+        pthread_create(&mVideoThread, &attr, VideoWrapper, this);
+
+        pthread_attr_destroy(&attr);
+    }
+}
+
+void MediaPlayerImpl::pause() {
+    if (!mPlaying || mPaused) {
+        return;
+    }
+
+    if (mAudioSource != NULL) {
+        mAudioPlayer->pause();
+    }
+
+    mPaused = true;
+}
+
+void MediaPlayerImpl::stop() {
+    if (!mPlaying) {
+        return;
+    }
+
+    mPlaying = false;
+
+    if (mVideoDecoder != NULL) {
+        void *dummy;
+        pthread_join(mVideoThread, &dummy);
+    }
+
+    if (mAudioSource != NULL) {
+        mAudioPlayer->stop();
+
+        delete mAudioPlayer;
+        mAudioPlayer = NULL;
+    } else {
+        delete mTimeSource;
+    }
+
+    mTimeSource = NULL;
+}
+
+// static
+void *MediaPlayerImpl::VideoWrapper(void *me) {
+    ((MediaPlayerImpl *)me)->videoEntry();
+
+    return NULL;
+}
+
+void MediaPlayerImpl::videoEntry() {
+    bool firstFrame = true;
+    bool eof = false;
+
+    status_t err = mVideoDecoder->start();
+    assert(err == OK);
+
+    while (mPlaying) {
+        MediaBuffer *buffer;
+
+        MediaSource::ReadOptions options;
+        bool seeking = false;
+
+        {
+            Mutex::Autolock autoLock(mLock);
+            if (mSeeking) {
+                LOGI("seek-options to %lld", mSeekTimeUs);
+                options.setSeekTo(mSeekTimeUs);
+
+                mSeeking = false;
+                seeking = true;
+                eof = false;
+            }
+        }
+
+        if (eof || mPaused) {
+            usleep(100000);
+            continue;
+        }
+
+        status_t err = mVideoDecoder->read(&buffer, &options);
+        assert((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
+
+        if (err == ERROR_END_OF_STREAM || err != OK) {
+            eof = true;
+            continue;
+        }
+
+        if (buffer->range_length() == 0) {
+            // The final buffer is empty.
+            buffer->release();
+            continue;
+        }
+
+        int32_t units, scale;
+        bool success =
+            buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+        assert(success);
+        success =
+            buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+        assert(success);
+
+        int64_t pts_us = (int64_t)units * 1000000 / scale;
+        {
+            Mutex::Autolock autoLock(mLock);
+            mVideoPosition = pts_us;
+
+            LOGV("now_video = %.2f secs (%lld ms)",
+                 pts_us / 1E6, (pts_us + 500) / 1000);
+        }
+
+        if (seeking && mAudioPlayer != NULL) {
+            // Now that we know where exactly video seeked (taking sync-samples
+            // into account), we will seek the audio track to the same time.
+            mAudioPlayer->seekTo(pts_us);
+        }
+
+        if (firstFrame || seeking) {
+            mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - pts_us;
+            firstFrame = false;
+        }
+
+        displayOrDiscardFrame(buffer, pts_us);
+    }
+
+    mVideoDecoder->stop();
+}
+
+void MediaPlayerImpl::displayOrDiscardFrame(
+        MediaBuffer *buffer, int64_t pts_us) {
+    for (;;) {
+        if (!mPlaying || mPaused) {
+            buffer->release();
+            buffer = NULL;
+
+            return;
+        }
+
+        int64_t realtime_us, mediatime_us;
+        if (mAudioPlayer != NULL
+            && mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
+            mTimeSourceDeltaUs = realtime_us - mediatime_us;
+            LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
+        }
+
+        int64_t now_us = mTimeSource->getRealTimeUs();
+        now_us -= mTimeSourceDeltaUs;
+
+        int64_t delay_us = pts_us - now_us;
+
+        if (delay_us < -15000) {
+            // We're late.
+
+            LOGI("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",
+                 delay_us / 1000);
+            usleep(100000);
+            continue;
+        } else if (delay_us > 0) {
+            usleep(delay_us);
+        }
+
+        break;
+    }
+
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mRenderer != NULL) {
+            sendFrameToISurface(buffer);
+        }
+    }
+
+    buffer->release();
+    buffer = NULL;
+}
+
+void MediaPlayerImpl::init() {
+    if (mExtractor != NULL) {
+        int num_tracks;
+        assert(mExtractor->countTracks(&num_tracks) == OK);
+
+        mDuration = 0;
+
+        for (int i = 0; i < num_tracks; ++i) {
+            const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+            assert(meta != NULL);
+
+            const char *mime;
+            if (!meta->findCString(kKeyMIMEType, &mime)) {
+                continue;
+            }
+
+            bool is_audio = false;
+            bool is_acceptable = false;
+            if (!strncasecmp(mime, "audio/", 6)) {
+                is_audio = true;
+                is_acceptable = (mAudioSource == NULL);
+            } else if (!strncasecmp(mime, "video/", 6)) {
+                is_acceptable = (mVideoSource == NULL);
+            }
+
+            if (!is_acceptable) {
+                continue;
+            }
+
+            MediaSource *source;
+            if (mExtractor->getTrack(i, &source) != OK) {
+                continue;
+            }
+
+            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;
+                }
+            }
+
+            if (is_audio) {
+                setAudioSource(source);
+            } else {
+                setVideoSource(source);
+            }
+        }
+    }
+}
+
+void MediaPlayerImpl::setAudioSource(MediaSource *source) {
+    LOGI("setAudioSource");
+    mAudioSource = source;
+
+    sp<MetaData> meta = source->getFormat();
+
+    mAudioDecoder = OMXDecoder::Create(&mClient, meta);
+    mAudioDecoder->setSource(source);
+}
+
+void MediaPlayerImpl::setVideoSource(MediaSource *source) {
+    LOGI("setVideoSource");
+    mVideoSource = source;
+
+    sp<MetaData> meta = source->getFormat();
+
+    bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
+    assert(success);
+
+    success = meta->findInt32(kKeyHeight, &mVideoHeight);
+    assert(success);
+
+    mVideoDecoder = OMXDecoder::Create(&mClient, meta);
+    ((OMXDecoder *)mVideoDecoder)->setSource(source);
+
+    if (mISurface.get() != NULL || mSurface.get() != NULL) {
+        depopulateISurface();
+        populateISurface();
+    }
+}
+
+void MediaPlayerImpl::setSurface(const sp<Surface> &surface) {
+    LOGI("setSurface %p", surface.get());
+    Mutex::Autolock autoLock(mLock);
+
+    depopulateISurface();
+
+    mSurface = surface;
+    mISurface = NULL;
+
+    if (mSurface.get() != NULL) {
+        populateISurface();
+    }
+}
+
+void MediaPlayerImpl::setISurface(const sp<ISurface> &isurface) {
+    LOGI("setISurface %p", isurface.get());
+    Mutex::Autolock autoLock(mLock);
+
+    depopulateISurface();
+
+    mSurface = NULL;
+    mISurface = isurface;
+
+    if (mISurface.get() != NULL) {
+        populateISurface();
+    }
+}
+
+MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) {
+    if (strncasecmp(uri, "shoutcast://", 12)) {
+        return NULL;
+    }
+
+    string host;
+    string path;
+    int port;
+
+    char *slash = strchr(uri + 12, '/');
+    if (slash == NULL) {
+        host = uri + 12;
+        path = "/";
+    } else {
+        host = string(uri + 12, slash - (uri + 12));
+        path = slash;
+    }
+
+    char *colon = strchr(host.c_str(), ':');
+    if (colon == NULL) {
+        port = 80;
+    } else {
+        char *end;
+        long tmp = strtol(colon + 1, &end, 10);
+        assert(end > colon + 1);
+        assert(tmp > 0 && tmp < 65536);
+        port = tmp;
+
+        host = string(host, 0, colon - host.c_str());
+    }
+
+    LOGI("Connecting to host '%s', port %d, path '%s'",
+         host.c_str(), port, path.c_str());
+
+    HTTPStream *http = new HTTPStream;
+    int http_status;
+
+    for (;;) {
+        status_t err = http->connect(host.c_str(), port);
+        assert(err == OK);
+
+        err = http->send("GET ");
+        err = http->send(path.c_str());
+        err = http->send(" HTTP/1.1\r\n");
+        err = http->send("Host: ");
+        err = http->send(host.c_str());
+        err = http->send("\r\n");
+        err = http->send("Icy-MetaData: 1\r\n\r\n");
+
+        assert(OK == http->receive_header(&http_status));
+
+        if (http_status == 301 || http_status == 302) {
+            string location;
+            assert(http->find_header_value("Location", &location));
+
+            assert(string(location, 0, 7) == "http://");
+            location.erase(0, 7);
+            string::size_type slashPos = location.find('/');
+            if (slashPos == string::npos) {
+                slashPos = location.size();
+                location += '/';
+            }
+
+            http->disconnect();
+
+            LOGI("Redirecting to %s\n", location.c_str());
+
+            host = string(location, 0, slashPos);
+
+            string::size_type colonPos = host.find(':');
+            if (colonPos != string::npos) {
+                const char *start = host.c_str() + colonPos + 1;
+                char *end;
+                long tmp = strtol(start, &end, 10);
+                assert(end > start && *end == '\0');
+
+                port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
+            } else {
+                port = 80;
+            }
+
+            path = string(location, slashPos);
+
+            continue;
+        }
+
+        break;
+    }
+
+    if (http_status != 200) {
+        LOGE("Connection failed: http_status = %d", http_status);
+        return NULL;
+    }
+
+    MediaSource *source = new ShoutcastSource(http);
+
+    return source;
+}
+
+bool MediaPlayerImpl::isPlaying() const {
+    return mPlaying && !mPaused;
+}
+
+int64_t MediaPlayerImpl::getDuration() {
+    return mDuration;
+}
+
+int64_t MediaPlayerImpl::getPosition() {
+    int64_t position = 0;
+    if (mVideoSource != NULL) {
+        Mutex::Autolock autoLock(mLock);
+        position = mVideoPosition;
+    } else if (mAudioPlayer != NULL) {
+        position = mAudioPlayer->getMediaTimeUs();
+    }
+
+    return position;
+}
+
+status_t MediaPlayerImpl::seekTo(int64_t time) {
+    LOGI("seekTo %lld", time);
+
+    if (mPaused) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (mVideoSource == NULL && mAudioPlayer != NULL) {
+        mAudioPlayer->seekTo(time);
+    } else {
+        Mutex::Autolock autoLock(mLock);
+        mSeekTimeUs = time;
+        mSeeking = true;
+    }
+
+    return OK;
+}
+
+void MediaPlayerImpl::populateISurface() {
+    if (mVideoSource == NULL) {
+        return;
+    }
+
+    sp<MetaData> meta = mVideoDecoder->getFormat();
+
+    int32_t format;
+    const char *component;
+    int32_t decodedWidth, decodedHeight;
+    bool success = meta->findInt32(kKeyColorFormat, &format);
+    success = success && meta->findCString(kKeyDecoderComponent, &component);
+    success = success && meta->findInt32(kKeyWidth, &decodedWidth);
+    success = success && meta->findInt32(kKeyHeight, &decodedHeight);
+    assert(success);
+
+    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+    if (mSurface.get() != NULL) {
+        LOGW("Using SurfaceRenderer.");
+        mRenderer =
+            new SurfaceRenderer(
+                    mSurface, mVideoWidth, mVideoHeight,
+                    decodedWidth, decodedHeight);
+    } else if (format == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+        && !strncmp(component, "OMX.qcom.video.decoder.", 23)) {
+        LOGW("Using QComHardwareRenderer.");
+        mRenderer =
+            new QComHardwareRenderer(
+                    mISurface, mVideoWidth, mVideoHeight,
+                    decodedWidth, decodedHeight);
+    } else if (format == OMX_COLOR_FormatCbYCrY
+            && !strcmp(component, "OMX.TI.Video.Decoder")) {
+        LOGW("Using TIHardwareRenderer.");
+        mRenderer =
+            new TIHardwareRenderer(
+                    mISurface, mVideoWidth, mVideoHeight,
+                    decodedWidth, decodedHeight);
+    } else {
+        LOGW("Using software renderer.");
+        mRenderer = new SoftwareRenderer(
+                mISurface, mVideoWidth, mVideoHeight,
+                decodedWidth, decodedHeight);
+    }
+}
+
+void MediaPlayerImpl::depopulateISurface() {
+    delete mRenderer;
+    mRenderer = NULL;
+}
+
+void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) {
+    void *platformPrivate;
+    if (!buffer->meta_data()->findPointer(
+                kKeyPlatformPrivate, &platformPrivate)) {
+        platformPrivate = NULL;
+    }
+
+    mRenderer->render(
+        (const uint8_t *)buffer->data() + buffer->range_offset(),
+        buffer->range_length(),
+        platformPrivate);
+}
+
+void MediaPlayerImpl::setAudioSink(
+        const sp<MediaPlayerBase::AudioSink> &audioSink) {
+    LOGI("setAudioSink %p", audioSink.get());
+    mAudioSink = audioSink;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
new file mode 100644
index 0000000..ec89b74
--- /dev/null
+++ b/media/libstagefright/MediaSource.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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/MediaSource.h>
+
+namespace android {
+
+MediaSource::MediaSource() {}
+
+MediaSource::~MediaSource() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MediaSource::ReadOptions::ReadOptions() {
+    reset();
+}
+
+void MediaSource::ReadOptions::reset() {
+    mOptions = 0;
+    mSeekTimeUs = 0;
+    mLatenessUs = 0;
+}
+
+void MediaSource::ReadOptions::setSeekTo(int64_t time_us) {
+    mOptions |= kSeekTo_Option;
+    mSeekTimeUs = time_us;
+}
+
+void MediaSource::ReadOptions::clearSeekTo() {
+    mOptions &= ~kSeekTo_Option;
+    mSeekTimeUs = 0;
+}
+
+bool MediaSource::ReadOptions::getSeekTo(int64_t *time_us) const {
+    *time_us = mSeekTimeUs;
+    return (mOptions & kSeekTo_Option) != 0;
+}
+
+void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+    mLatenessUs = lateness_us;
+}
+
+int64_t MediaSource::ReadOptions::getLateBy() const {
+    return mLatenessUs;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
new file mode 100644
index 0000000..5d23732
--- /dev/null
+++ b/media/libstagefright/MetaData.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+MetaData::MetaData() {
+}
+
+MetaData::MetaData(const MetaData &from)
+    : RefBase(),
+      mItems(from.mItems) {
+}
+
+MetaData::~MetaData() {
+    clear();
+}
+
+void MetaData::clear() {
+    mItems.clear();
+}
+
+bool MetaData::remove(uint32_t key) {
+    ssize_t i = mItems.indexOfKey(key);
+
+    if (i < 0) {
+        return false;
+    }
+
+    mItems.removeItemsAt(i);
+
+    return true;
+}
+
+bool MetaData::setCString(uint32_t key, const char *value) {
+    return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
+}
+
+bool MetaData::setInt32(uint32_t key, int32_t value) {
+    return setData(key, TYPE_INT32, &value, sizeof(value));
+}
+
+bool MetaData::setFloat(uint32_t key, float value) {
+    return setData(key, TYPE_FLOAT, &value, sizeof(value));
+}
+
+bool MetaData::setPointer(uint32_t key, void *value) {
+    return setData(key, TYPE_POINTER, &value, sizeof(value));
+}
+
+bool MetaData::findCString(uint32_t key, const char **value) {
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
+        return false;
+    }
+
+    *value = (const char *)data;
+
+    return true;
+}
+
+bool MetaData::findInt32(uint32_t key, int32_t *value) {
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
+        return false;
+    }
+
+    assert(size == sizeof(*value));
+
+    *value = *(int32_t *)data;
+
+    return true;
+}
+
+bool MetaData::findFloat(uint32_t key, float *value) {
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
+        return false;
+    }
+
+    assert(size == sizeof(*value));
+
+    *value = *(float *)data;
+
+    return true;
+}
+
+bool MetaData::findPointer(uint32_t key, void **value) {
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
+        return false;
+    }
+
+    assert(size == sizeof(*value));
+
+    *value = *(void **)data;
+
+    return true;
+}
+
+bool MetaData::setData(
+        uint32_t key, uint32_t type, const void *data, size_t size) {
+    bool overwrote_existing = true;
+
+    ssize_t i = mItems.indexOfKey(key);
+    if (i < 0) {
+        typed_data item;
+        i = mItems.add(key, item);
+
+        overwrote_existing = false;
+    }
+
+    typed_data &item = mItems.editValueAt(i);
+
+    item.setData(type, data, size);
+
+    return overwrote_existing;
+}
+
+bool MetaData::findData(uint32_t key, uint32_t *type,
+                        const void **data, size_t *size) const {
+    ssize_t i = mItems.indexOfKey(key);
+
+    if (i < 0) {
+        return false;
+    }
+
+    const typed_data &item = mItems.valueAt(i);
+
+    item.getData(type, data, size);
+
+    return true;
+}
+
+MetaData::typed_data::typed_data()
+    : mType(0),
+      mSize(0) {
+}
+
+MetaData::typed_data::~typed_data() {
+    clear();
+}
+
+MetaData::typed_data::typed_data(const typed_data &from)
+    : mType(from.mType),
+      mSize(0) {
+    allocateStorage(from.mSize);
+    memcpy(storage(), from.storage(), mSize);
+}
+
+MetaData::typed_data &MetaData::typed_data::operator=(
+        const MetaData::typed_data &from) {
+    if (this != &from) {
+        clear();
+        mType = from.mType;
+        allocateStorage(from.mSize);
+        memcpy(storage(), from.storage(), mSize);
+    }
+
+    return *this;
+}
+
+void MetaData::typed_data::clear() {
+    freeStorage();
+
+    mType = 0;
+}
+
+void MetaData::typed_data::setData(
+        uint32_t type, const void *data, size_t size) {
+    clear();
+
+    mType = type;
+    allocateStorage(size);
+    memcpy(storage(), data, size);
+}
+
+void MetaData::typed_data::getData(
+        uint32_t *type, const void **data, size_t *size) const {
+    *type = mType;
+    *size = mSize;
+    *data = storage();
+}
+
+void MetaData::typed_data::allocateStorage(size_t size) {
+    mSize = size;
+
+    if (usesReservoir()) {
+        return;
+    }
+
+    u.ext_data = malloc(mSize);
+}
+
+void MetaData::typed_data::freeStorage() {
+    if (!usesReservoir()) {
+        if (u.ext_data) {
+            free(u.ext_data);
+        }
+    }
+
+    mSize = 0;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp
new file mode 100644
index 0000000..7cb861c
--- /dev/null
+++ b/media/libstagefright/MmapSource.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "MmapSource"
+#include <utils/Log.h>
+
+#include <sys/mman.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <media/stagefright/MmapSource.h>
+
+namespace android {
+
+MmapSource::MmapSource(const char *filename)
+    : mFd(open(filename, O_RDONLY)),
+      mBase(NULL),
+      mSize(0) {
+    LOGV("MmapSource '%s'", filename);
+    assert(mFd >= 0);
+
+    off_t size = lseek(mFd, 0, SEEK_END);
+    mSize = (size_t)size;
+
+    mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, 0);
+
+    if (mBase == (void *)-1) {
+        mBase = NULL;
+
+        close(mFd);
+        mFd = -1;
+    }
+}
+
+MmapSource::MmapSource(int fd, int64_t offset, int64_t length)
+    : mFd(fd),
+      mBase(NULL),
+      mSize(length) {
+    LOGV("MmapSource fd:%d offset:%lld length:%lld", fd, offset, length);
+    assert(fd >= 0);
+
+    mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, offset);
+
+    if (mBase == (void *)-1) {
+        mBase = NULL;
+
+        close(mFd);
+        mFd = -1;
+    }
+
+}
+
+MmapSource::~MmapSource() {
+    if (mFd != -1) {
+        munmap(mBase, mSize);
+        mBase = NULL;
+        mSize = 0;
+
+        close(mFd);
+        mFd = -1;
+    }
+}
+
+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);
+    assert(offset >= 0);
+
+    size_t avail = 0;
+    if (offset >= 0 && offset < (off_t)mSize) {
+        avail = mSize - offset;
+    }
+
+    if (size > avail) {
+        size = avail;
+    }
+
+    memcpy(data, (const uint8_t *)mBase + offset, size);
+
+    return (ssize_t)size;
+}
+
+status_t MmapSource::getSize(off_t *size) {
+    *size = mSize;
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
new file mode 100644
index 0000000..1bc8a44
--- /dev/null
+++ b/media/libstagefright/OMXClient.cpp
@@ -0,0 +1,369 @@
+/*
+ * 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 "OMXClient"
+#include <utils/Log.h>
+
+#include <sys/socket.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IOMX.h>
+#include <media/stagefright/OMXClient.h>
+
+namespace android {
+
+OMXClient::OMXClient()
+    : mSock(-1) {
+}
+
+OMXClient::~OMXClient() {
+    disconnect();
+}
+
+status_t OMXClient::connect() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mSock >= 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.player"));
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+    assert(service.get() != NULL);
+
+    mOMX = service->createOMX();
+    assert(mOMX.get() != NULL);
+
+#if IOMX_USES_SOCKETS
+    status_t result = mOMX->connect(&mSock);
+    if (result != OK) {
+        mSock = -1;
+
+        mOMX = NULL;
+        return result;
+    }
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
+    assert(err == 0);
+
+    pthread_attr_destroy(&attr);
+#else
+    mReflector = new OMXClientReflector(this);
+#endif
+
+    return OK;
+}
+
+void OMXClient::disconnect() {
+    {
+        Mutex::Autolock autoLock(mLock);
+
+        if (mSock < 0) {
+            return;
+        }
+
+        assert(mObservers.isEmpty());
+    }
+
+#if IOMX_USES_SOCKETS
+    omx_message msg;
+    msg.type = omx_message::DISCONNECT;
+    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+#else
+    mReflector->reset();
+    mReflector.clear();
+#endif
+}
+
+#if IOMX_USES_SOCKETS
+// static
+void *OMXClient::ThreadWrapper(void *me) {
+    ((OMXClient *)me)->threadEntry();
+
+    return NULL;
+}
+
+void OMXClient::threadEntry() {
+    bool done = false;
+    while (!done) {
+        omx_message msg;
+        ssize_t n = recv(mSock, &msg, sizeof(msg), 0);
+
+        if (n <= 0) {
+            break;
+        }
+
+        done = onOMXMessage(msg);
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    close(mSock);
+    mSock = -1;
+}
+#endif
+
+status_t OMXClient::fillBuffer(IOMX::node_id node, IOMX::buffer_id buffer) {
+#if !IOMX_USES_SOCKETS
+    mOMX->fill_buffer(node, buffer);
+#else
+    if (mSock < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    omx_message msg;
+    msg.type = omx_message::FILL_BUFFER;
+    msg.u.buffer_data.node = node;
+    msg.u.buffer_data.buffer = buffer;
+
+    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+#endif
+
+    return OK;
+}
+
+status_t OMXClient::emptyBuffer(
+        IOMX::node_id node, IOMX::buffer_id buffer,
+        OMX_U32 range_offset, OMX_U32 range_length,
+        OMX_U32 flags, OMX_TICKS timestamp) {
+#if !IOMX_USES_SOCKETS
+    mOMX->empty_buffer(
+            node, buffer, range_offset, range_length, flags, timestamp);
+#else
+    if (mSock < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    // XXX I don't like all this copying...
+
+    omx_message msg;
+    msg.type = omx_message::EMPTY_BUFFER;
+    msg.u.extended_buffer_data.node = node;
+    msg.u.extended_buffer_data.buffer = buffer;
+    msg.u.extended_buffer_data.range_offset = range_offset;
+    msg.u.extended_buffer_data.range_length = range_length;
+    msg.u.extended_buffer_data.flags = flags;
+    msg.u.extended_buffer_data.timestamp = timestamp;
+
+    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+#endif
+
+    return OK;
+}
+
+status_t OMXClient::send_command(
+        IOMX::node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+#if !IOMX_USES_SOCKETS
+    return mOMX->send_command(node, cmd, param);
+#else
+    if (mSock < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    omx_message msg;
+    msg.type = omx_message::SEND_COMMAND;
+    msg.u.send_command_data.node = node;
+    msg.u.send_command_data.cmd = cmd;
+    msg.u.send_command_data.param = param;
+
+    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+#endif
+
+    return OK;
+}
+
+status_t OMXClient::registerObserver(
+        IOMX::node_id node, OMXObserver *observer) {
+    Mutex::Autolock autoLock(&mLock);
+
+    ssize_t index = mObservers.indexOfKey(node);
+    if (index >= 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    mObservers.add(node, observer);
+    observer->start();
+
+#if !IOMX_USES_SOCKETS
+    mOMX->observe_node(node, mReflector);
+#endif
+
+    return OK;
+}
+
+void OMXClient::unregisterObserver(IOMX::node_id node) {
+    Mutex::Autolock autoLock(mLock);
+
+    ssize_t index = mObservers.indexOfKey(node);
+    assert(index >= 0);
+
+    if (index < 0) {
+        return;
+    }
+
+    OMXObserver *observer = mObservers.valueAt(index);
+    observer->stop();
+    mObservers.removeItemsAt(index);
+}
+
+bool OMXClient::onOMXMessage(const omx_message &msg) {
+    bool done = false;
+
+    switch (msg.type) {
+        case omx_message::EVENT:
+        {
+            LOGV("OnEvent node:%p event:%d data1:%ld data2:%ld",
+                 msg.u.event_data.node,
+                 msg.u.event_data.event,
+                 msg.u.event_data.data1,
+                 msg.u.event_data.data2);
+
+            break;
+        }
+
+        case omx_message::FILL_BUFFER_DONE:
+        {
+            LOGV("FillBufferDone %p", msg.u.extended_buffer_data.buffer);
+            break;
+        }
+
+        case omx_message::EMPTY_BUFFER_DONE:
+        {
+            LOGV("EmptyBufferDone %p", msg.u.buffer_data.buffer);
+            break;
+        }
+
+#if IOMX_USES_SOCKETS
+        case omx_message::DISCONNECTED:
+        {
+            LOGV("Disconnected");
+            done = true;
+            break;
+        }
+#endif
+
+        default:
+            LOGE("received unknown omx_message type %d", msg.type);
+            break;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    ssize_t index = mObservers.indexOfKey(msg.u.buffer_data.node);
+
+    if (index >= 0) {
+        mObservers.editValueAt(index)->postMessage(msg);
+    }
+
+    return done;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+OMXObserver::OMXObserver() {
+}
+
+OMXObserver::~OMXObserver() {
+}
+
+void OMXObserver::start() {
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
+    assert(err == 0);
+
+    pthread_attr_destroy(&attr);
+}
+
+void OMXObserver::stop() {
+    omx_message msg;
+    msg.type = omx_message::QUIT_OBSERVER;
+    postMessage(msg);
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+}
+
+void OMXObserver::postMessage(const omx_message &msg) {
+    Mutex::Autolock autoLock(mLock);
+    mQueue.push_back(msg);
+    mQueueNotEmpty.signal();
+}
+
+// static
+void *OMXObserver::ThreadWrapper(void *me) {
+    static_cast<OMXObserver *>(me)->threadEntry();
+
+    return NULL;
+}
+
+void OMXObserver::threadEntry() {
+    for (;;) {
+        omx_message msg;
+
+        {
+            Mutex::Autolock autoLock(mLock);
+            while (mQueue.empty()) {
+                mQueueNotEmpty.wait(mLock);
+            }
+
+            msg = *mQueue.begin();
+            mQueue.erase(mQueue.begin());
+        }
+
+        if (msg.type == omx_message::QUIT_OBSERVER) {
+            break;
+        }
+
+        onOMXMessage(msg);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+OMXClientReflector::OMXClientReflector(OMXClient *client)
+    : mClient(client) {
+}
+
+void OMXClientReflector::on_message(const omx_message &msg) {
+    if (mClient != NULL) {
+        mClient->onOMXMessage(msg);
+    }
+}
+
+void OMXClientReflector::reset() {
+    mClient = NULL;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
new file mode 100644
index 0000000..5e44999
--- /dev/null
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -0,0 +1,1715 @@
+/*
+ * 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 "OMXDecoder"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+#include <ctype.h>
+
+#include <OMX_Component.h>
+
+#include <media/stagefright/ESDS.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXDecoder.h>
+
+namespace android {
+
+class OMXMediaBuffer : public MediaBuffer {
+public:
+    OMXMediaBuffer(IOMX::buffer_id buffer_id, const sp<IMemory> &mem)
+        : MediaBuffer(mem->pointer(),
+                      mem->size()),
+          mBufferID(buffer_id),
+          mMem(mem) {
+    }
+
+    IOMX::buffer_id buffer_id() const { return mBufferID; }
+
+private:
+    IOMX::buffer_id mBufferID;
+    sp<IMemory> mMem;
+
+    OMXMediaBuffer(const OMXMediaBuffer &);
+    OMXMediaBuffer &operator=(const OMXMediaBuffer &);
+};
+
+struct CodecInfo {
+    const char *mime;
+    const char *codec;
+};
+
+static const CodecInfo kDecoderInfo[] = {
+    { "audio/mpeg", "OMX.TI.MP3.decode" },
+    { "audio/mpeg", "OMX.PV.mp3dec" },
+    { "audio/3gpp", "OMX.TI.AMR.decode" },
+    { "audio/3gpp", "OMX.PV.amrdec" },
+    { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
+    { "audio/mp4a-latm", "OMX.PV.aacdec" },
+    { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
+    { "video/mp4v-es", "OMX.TI.Video.Decoder" },
+    { "video/mp4v-es", "OMX.PV.mpeg4dec" },
+    { "video/3gpp", "OMX.qcom.video.decoder.h263" },
+    { "video/3gpp", "OMX.TI.Video.Decoder" },
+    { "video/3gpp", "OMX.PV.h263dec" },
+    { "video/avc", "OMX.qcom.video.decoder.avc" },
+    { "video/avc", "OMX.TI.Video.Decoder" },
+    { "video/avc", "OMX.PV.avcdec" },
+};
+
+static const CodecInfo kEncoderInfo[] = {
+    { "audio/3gpp", "OMX.PV.amrencnb" },
+    { "audio/mp4a-latm", "OMX.PV.aacenc" },
+    { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
+    { "video/mp4v-es", "OMX.PV.mpeg4enc" },
+    { "video/3gpp", "OMX.qcom.video.encoder.h263" },
+    { "video/3gpp", "OMX.PV.h263enc" },
+    { "video/avc", "OMX.PV.avcenc" },
+};
+
+static const char *GetCodec(const CodecInfo *info, size_t numInfos,
+                            const char *mime, int index) {
+    assert(index >= 0);
+    for(size_t i = 0; i < numInfos; ++i) {
+        if (!strcasecmp(mime, info[i].mime)) {
+            if (index == 0) {
+                return info[i].codec;
+            }
+
+            --index;
+        }
+    }
+
+    return NULL;
+}
+
+// static
+OMXDecoder *OMXDecoder::Create(
+        OMXClient *client, const sp<MetaData> &meta,
+        bool createEncoder) {
+    const char *mime;
+    bool success = meta->findCString(kKeyMIMEType, &mime);
+    assert(success);
+
+    sp<IOMX> omx = client->interface();
+
+    const char *codec = NULL;
+    IOMX::node_id node = 0;
+    for (int index = 0;; ++index) {
+        if (createEncoder) {
+            codec = GetCodec(
+                    kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+                    mime, index);
+        } else {
+            codec = GetCodec(
+                    kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+                    mime, index);
+        }
+
+        if (!codec) {
+            return NULL;
+        }
+
+        LOGI("Attempting to allocate OMX node '%s'", codec);
+
+        status_t err = omx->allocate_node(codec, &node);
+        if (err == OK) {
+            break;
+        }
+    }
+
+    uint32_t quirks = 0;
+    if (!strcmp(codec, "OMX.PV.avcdec")) {
+        quirks |= kWantsRawNALFrames;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")
+        || !strcmp(codec, "OMX.TI.MP3.decode")) {
+        quirks |= kDoesntReturnBuffersOnDisable;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")) {
+        quirks |= kDoesntFlushOnExecutingToIdle;
+        quirks |= kDoesntProperlyFlushAllPortsAtOnce;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.encoder.", 23)) {
+        quirks |= kRequiresAllocateBufferOnInputPorts;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.decoder.", 23)) {
+        quirks |= kRequiresAllocateBufferOnOutputPorts;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.", 15)) {
+        quirks |= kRequiresLoadedToIdleAfterAllocation;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")
+        || !strcmp(codec, "OMX.TI.MP3.decode")) {
+        quirks |= kMeasuresTimeInMilliseconds;
+    }
+
+    OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks);
+
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (meta->findData(kKeyESDS, &type, &data, &size)) {
+        ESDS esds((const char *)data, size);
+        assert(esds.InitCheck() == OK);
+        
+        const void *codec_specific_data;
+        size_t codec_specific_data_size;
+        esds.getCodecSpecificInfo(
+                &codec_specific_data, &codec_specific_data_size);
+
+        printf("found codec specific data of size %d\n",
+               codec_specific_data_size);
+
+        decoder->addCodecSpecificData(
+                codec_specific_data, codec_specific_data_size);
+    } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+        printf("found avcc of size %d\n", size);
+
+        const uint8_t *ptr = (const uint8_t *)data + 6;
+        size -= 6;
+        while (size >= 2) {
+            size_t length = ptr[0] << 8 | ptr[1];
+
+            ptr += 2;
+            size -= 2;
+
+            // printf("length = %d, size = %d\n", length, size);
+
+            assert(size >= length);
+
+            decoder->addCodecSpecificData(ptr, length);
+
+            ptr += length;
+            size -= length;
+
+            if (size <= 1) {
+                break;
+            }
+
+            ptr++;  // XXX skip trailing 0x01 byte???
+            --size;
+        }
+    }
+
+    return decoder;
+}
+
+OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
+                       const char *mime, const char *codec,
+                       uint32_t quirks)
+    : mClient(client),
+      mOMX(mClient->interface()),
+      mNode(node),
+      mComponentName(strdup(codec)),
+      mIsMP3(!strcasecmp(mime, "audio/mpeg")),
+      mIsAVC(!strcasecmp(mime, "video/avc")),
+      mQuirks(quirks),
+      mSource(NULL),
+      mCodecSpecificDataIterator(mCodecSpecificData.begin()),
+      mState(OMX_StateLoaded),
+      mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
+      mShutdownInitiated(false),
+      mDealer(new MemoryDealer(5 * 1024 * 1024)),
+      mSeeking(false),
+      mStarted(false),
+      mErrorCondition(OK),
+      mReachedEndOfInput(false) {
+    mClient->registerObserver(mNode, this);
+
+    mBuffers.push();  // input buffers
+    mBuffers.push();  // output buffers
+}
+
+OMXDecoder::~OMXDecoder() {
+    if (mStarted) {
+        stop();
+    }
+
+    for (List<CodecSpecificData>::iterator it = mCodecSpecificData.begin();
+         it != mCodecSpecificData.end(); ++it) {
+        free((*it).data);
+    }
+    mCodecSpecificData.clear();
+
+    mClient->unregisterObserver(mNode);
+
+    status_t err = mOMX->free_node(mNode);
+    assert(err == OK);
+    mNode = 0;
+
+    free(mComponentName);
+    mComponentName = NULL;
+}
+
+void OMXDecoder::setSource(MediaSource *source) {
+    Mutex::Autolock autoLock(mLock);
+
+    assert(mSource == NULL);
+
+    mSource = source;
+    setup();
+}
+
+status_t OMXDecoder::start(MetaData *) {
+    assert(!mStarted);
+
+    // mDealer->dump("Decoder Dealer");
+
+    sp<MetaData> params = new MetaData;
+    if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
+        params->setInt32(kKeyNeedsNALFraming, true);
+    }
+
+    status_t err = mSource->start(params.get());
+
+    if (err != OK) {
+        return err;
+    }
+
+    postStart();
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t OMXDecoder::stop() {
+    assert(mStarted);
+
+    LOGI("Initiating OMX Node shutdown, busy polling.");
+    initiateShutdown();
+
+    // Important: initiateShutdown must be called first, _then_ release
+    // buffers we're holding onto.
+    while (!mOutputBuffers.empty()) {
+        MediaBuffer *buffer = *mOutputBuffers.begin();
+        mOutputBuffers.erase(mOutputBuffers.begin());
+
+        LOGV("releasing buffer %p.", buffer->data());
+
+        buffer->release();
+        buffer = NULL;
+    }
+
+    int attempt = 1;
+    while (mState != OMX_StateLoaded && attempt < 20) {
+        usleep(100000);
+
+        ++attempt;
+    }
+
+    if (mState != OMX_StateLoaded) {
+        LOGE("!!! OMX Node '%s' did NOT shutdown cleanly !!!", mComponentName);
+    } else {
+        LOGI("OMX Node '%s' has shutdown cleanly.", mComponentName);
+    }
+
+    mSource->stop();
+
+    mCodecSpecificDataIterator = mCodecSpecificData.begin();
+    mShutdownInitiated = false;
+    mSeeking = false;
+    mStarted = false;
+    mErrorCondition = OK;
+    mReachedEndOfInput = false;
+
+    return OK;
+}
+
+sp<MetaData> OMXDecoder::getFormat() {
+    return mOutputFormat;
+}
+
+status_t OMXDecoder::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    assert(mStarted);
+
+    *out = NULL;
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mErrorCondition != OK && mErrorCondition != ERROR_END_OF_STREAM) {
+        // Errors are sticky.
+        return mErrorCondition;
+    }
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        LOGI("[%s] seeking to %lld us", mComponentName, seekTimeUs);
+
+        mErrorCondition = OK;
+        mReachedEndOfInput = false;
+
+        setPortStatus(kPortIndexInput, kPortStatusFlushing);
+        setPortStatus(kPortIndexOutput, kPortStatusFlushing);
+
+        mSeeking = true;
+        mSeekTimeUs = seekTimeUs;
+
+        while (!mOutputBuffers.empty()) {
+            OMXMediaBuffer *buffer =
+                static_cast<OMXMediaBuffer *>(*mOutputBuffers.begin());
+
+            // We could have used buffer->release() instead, but we're
+            // holding the lock and signalBufferReturned attempts to acquire
+            // the lock.
+            buffer->claim();
+            mBuffers.editItemAt(
+                    kPortIndexOutput).push_back(buffer->buffer_id());
+            buffer = NULL;
+
+            mOutputBuffers.erase(mOutputBuffers.begin());
+        }
+
+        // XXX One of TI's decoders appears to ignore a flush if it doesn't
+        // currently hold on to any buffers on the port in question and
+        // never sends the completion event... FIXME
+
+        status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+        assert(err == OK);
+
+        // Once flushing is completed buffers will again be scheduled to be
+        // filled/emptied.
+    }
+
+    while (mErrorCondition == OK && mOutputBuffers.empty()) {
+        mOutputBufferAvailable.wait(mLock);
+    }
+
+    if (!mOutputBuffers.empty()) {
+        MediaBuffer *buffer = *mOutputBuffers.begin();
+        mOutputBuffers.erase(mOutputBuffers.begin());
+
+        *out = buffer;
+
+        return OK;
+    } else {
+        assert(mErrorCondition != OK);
+        return mErrorCondition;
+    }
+}
+
+void OMXDecoder::addCodecSpecificData(const void *data, size_t size) {
+    CodecSpecificData specific;
+    specific.data = malloc(size);
+    memcpy(specific.data, data, size);
+    specific.size = size;
+
+    mCodecSpecificData.push_back(specific);
+    mCodecSpecificDataIterator = mCodecSpecificData.begin();
+}
+
+void OMXDecoder::onOMXMessage(const omx_message &msg) {
+    Mutex::Autolock autoLock(mLock);
+
+    switch (msg.type) {
+        case omx_message::START:
+        {
+            onStart();
+            break;
+        }
+
+        case omx_message::EVENT:
+        {
+            onEvent(msg.u.event_data.event, msg.u.event_data.data1,
+                    msg.u.event_data.data2);
+            break;
+        }
+
+        case omx_message::EMPTY_BUFFER_DONE:
+        {
+            onEmptyBufferDone(msg.u.buffer_data.buffer);
+            break;
+        }
+
+        case omx_message::FILL_BUFFER_DONE:
+        case omx_message::INITIAL_FILL_BUFFER:
+        {
+            onFillBufferDone(msg);
+            break;
+        }
+
+        default:
+            LOGE("received unknown omx_message type %d", msg.type);
+            break;
+    }
+}
+
+void OMXDecoder::setAMRFormat() {
+    OMX_AUDIO_PARAM_AMRTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexInput;
+
+    status_t err =
+        mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+
+    assert(err == NO_ERROR);
+
+    def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+    def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
+
+    err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+    assert(err == NO_ERROR);
+}
+
+void OMXDecoder::setAACFormat() {
+    OMX_AUDIO_PARAM_AACPROFILETYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexInput;
+
+    status_t err =
+        mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+    assert(err == NO_ERROR);
+
+    def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+    err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+    assert(err == NO_ERROR);
+}
+
+status_t OMXDecoder::setVideoPortFormatType(
+        OMX_U32 portIndex,
+        OMX_VIDEO_CODINGTYPE compressionFormat,
+        OMX_COLOR_FORMATTYPE colorFormat) {
+    OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+    format.nSize = sizeof(format);
+    format.nVersion.s.nVersionMajor = 1;
+    format.nVersion.s.nVersionMinor = 1;
+    format.nPortIndex = portIndex;
+    format.nIndex = 0;
+    bool found = false;
+
+    OMX_U32 index = 0;
+    for (;;) {
+        format.nIndex = index;
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+
+        if (err != OK) {
+            return err;
+        }
+
+        // The following assertion is violated by TI's video decoder.
+        // assert(format.nIndex == index);
+
+        if (format.eCompressionFormat == compressionFormat
+            && format.eColorFormat == colorFormat) {
+            found = true;
+            break;
+        }
+
+        ++index;
+    }
+
+    if (!found) {
+        return UNKNOWN_ERROR;
+    }
+
+    status_t err = mOMX->set_parameter(
+            mNode, OMX_IndexParamVideoPortFormat,
+            &format, sizeof(format));
+
+    return err;
+}
+
+#if 1
+void OMXDecoder::setVideoOutputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
+    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+#if 1
+    // Enabling this code appears to be the right thing(tm), but,...
+    // the TI decoder then loses the ability to output YUV420 and only outputs
+    // YCbYCr (16bit)
+    if (!strcasecmp("video/avc", mime)) {
+        OMX_PARAM_COMPONENTROLETYPE role;
+        role.nSize = sizeof(role);
+        role.nVersion.s.nVersionMajor = 1;
+        role.nVersion.s.nVersionMinor = 1;
+        strncpy((char *)role.cRole, "video_decoder.avc",
+                OMX_MAX_STRINGNAME_SIZE - 1);
+        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = mOMX->set_parameter(
+                mNode, OMX_IndexParamStandardComponentRole,
+                &role, sizeof(role));
+        assert(err == OK);
+    }
+#endif
+
+    OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+    if (!strcasecmp("video/avc", mime)) {
+        compressionFormat = OMX_VIDEO_CodingAVC;
+    } else if (!strcasecmp("video/mp4v-es", mime)) {
+        compressionFormat = OMX_VIDEO_CodingMPEG4;
+    } else if (!strcasecmp("video/3gpp", mime)) {
+        compressionFormat = OMX_VIDEO_CodingH263;
+    } else {
+        assert(!"Should not be here. Not a supported video mime type.");
+    }
+
+    setVideoPortFormatType(
+            kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
+
+#if 1
+    {
+        OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+        format.nSize = sizeof(format);
+        format.nVersion.s.nVersionMajor = 1;
+        format.nVersion.s.nVersionMinor = 1;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+
+        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+
+        static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+               || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+    }
+#endif
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+    bool is_encoder = strstr(mComponentName, ".encoder.") != NULL;  // XXX
+
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = is_encoder ? kPortIndexOutput : kPortIndexInput;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    assert(err == NO_ERROR);
+
+#if 1
+    // XXX Need a (much) better heuristic to compute input buffer sizes.
+    const size_t X = 64 * 1024;
+    if (def.nBufferSize < X) {
+        def.nBufferSize = X;
+    }
+#endif
+
+    assert(def.eDomain == OMX_PortDomainVideo);
+    
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    video_def->eColorFormat = OMX_COLOR_FormatUnused;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == NO_ERROR);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = is_encoder ? kPortIndexInput : kPortIndexOutput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == NO_ERROR);
+
+    assert(def.eDomain == OMX_PortDomainVideo);
+    
+#if 0
+    def.nBufferSize =
+        (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2;  // YUV420
+#endif
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == NO_ERROR);
+}
+
+#else
+static void hexdump(const void *_data, size_t size) {
+    char line[256];
+    char tmp[16];
+
+    const uint8_t *data = (const uint8_t *)_data;
+    size_t offset = 0;
+    while (offset < size) {
+        sprintf(line, "0x%04x  ", offset);
+
+        size_t n = size - offset;
+        if (n > 16) {
+            n = 16;
+        }
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (i == 8) {
+                strcat(line, " ");
+            }
+
+            if (offset + i < size) {
+                sprintf(tmp, "%02x ", data[offset + i]);
+                strcat(line, tmp);
+            } else {
+                strcat(line, "   ");
+            }
+        }
+
+        strcat(line, " ");
+
+        for (size_t i = 0; i < n; ++i) {
+            if (isprint(data[offset + i])) {
+                sprintf(tmp, "%c", data[offset + i]);
+                strcat(line, tmp);
+            } else {
+                strcat(line, ".");
+            }
+        }
+
+        LOGI(line);
+
+        offset += 16;
+    }
+}
+
+static void DumpPortDefinitionType(const void *_param) {
+    OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param;
+
+    LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output",
+        param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize);
+
+    if (param->eDomain == OMX_PortDomainVideo) {
+        OMX_VIDEO_PORTDEFINITIONTYPE *video = &param->format.video;
+        LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d",
+            video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat);
+    } else {
+        hexdump(param, param->nSize);
+    }
+}
+
+void OMXDecoder::setVideoOutputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
+    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+#if 0
+    // Enabling this code appears to be the right thing(tm), but,...
+    // the decoder then loses the ability to output YUV420 and only outputs
+    // YCbYCr (16bit)
+    {
+        OMX_PARAM_COMPONENTROLETYPE role;
+        role.nSize = sizeof(role);
+        role.nVersion.s.nVersionMajor = 1;
+        role.nVersion.s.nVersionMinor = 1;
+        strncpy((char *)role.cRole, "video_decoder.avc",
+                OMX_MAX_STRINGNAME_SIZE - 1);
+        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = mOMX->set_parameter(
+                mNode, OMX_IndexParamStandardComponentRole,
+                &role, sizeof(role));
+        assert(err == OK);
+    }
+#endif
+
+    setVideoPortFormatType(
+            kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused);
+
+#if 1
+    {
+        OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+        format.nSize = sizeof(format);
+        format.nVersion.s.nVersionMajor = 1;
+        format.nVersion.s.nVersionMinor = 1;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+
+        LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat");
+        hexdump(&format, format.nSize);
+
+        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+               || format.eColorFormat == OMX_COLOR_FormatCbYCrY);
+
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+    }
+#endif
+
+    OMX_PORT_PARAM_TYPE ptype;
+    ptype.nSize = sizeof(ptype);
+    ptype.nVersion.s.nVersionMajor = 1;
+    ptype.nVersion.s.nVersionMinor = 1;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit");
+    hexdump(&ptype, ptype.nSize);
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexInput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+    DumpPortDefinitionType(&def);
+
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    def.nPortIndex = kPortIndexOutput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+    DumpPortDefinitionType(&def);
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+}
+
+#endif
+
+void OMXDecoder::setup() {
+    const sp<MetaData> &meta = mSource->getFormat();
+
+    const char *mime;
+    bool success = meta->findCString(kKeyMIMEType, &mime);
+    assert(success);
+
+    if (!strcasecmp(mime, "audio/3gpp")) {
+        setAMRFormat();
+    } else if (!strcasecmp(mime, "audio/mp4a-latm")) {
+        setAACFormat();
+    } else if (!strncasecmp(mime, "video/", 6)) {
+        int32_t width, height;
+        bool success = meta->findInt32(kKeyWidth, &width);
+        success = success && meta->findInt32(kKeyHeight, &height);
+        assert(success);
+
+        setVideoOutputFormat(mime, width, height);
+    }
+
+    // dumpPortDefinition(0);
+    // dumpPortDefinition(1);
+
+    mOutputFormat = new MetaData;
+    mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == NO_ERROR);
+
+    switch (def.eDomain) {
+        case OMX_PortDomainAudio:
+        {
+            OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
+
+            assert(audio_def->eEncoding == OMX_AUDIO_CodingPCM);
+
+            OMX_AUDIO_PARAM_PCMMODETYPE params;
+            params.nSize = sizeof(params);
+            params.nVersion.s.nVersionMajor = 1;
+            params.nVersion.s.nVersionMinor = 1;
+            params.nPortIndex = kPortIndexOutput;
+
+            err = mOMX->get_parameter(
+                    mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
+            assert(err == OK);
+
+            assert(params.eNumData == OMX_NumericalDataSigned);
+            assert(params.nBitPerSample == 16);
+            assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear);
+
+            int32_t numChannels, sampleRate;
+            meta->findInt32(kKeyChannelCount, &numChannels);
+            meta->findInt32(kKeySampleRate, &sampleRate);
+
+            mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
+            mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+            mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+            break;
+        }
+
+        case OMX_PortDomainVideo:
+        {
+            OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+            if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/raw");
+            } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
+            } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
+            } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
+                mOutputFormat->setCString(kKeyMIMEType, "video/avc");
+            } else {
+                assert(!"Unknown compression format.");
+            }
+
+            if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
+                // This component appears to be lying to me.
+                mOutputFormat->setInt32(
+                        kKeyWidth, (video_def->nFrameWidth + 15) & -16);
+                mOutputFormat->setInt32(
+                        kKeyHeight, (video_def->nFrameHeight + 15) & -16);
+            } else {
+                mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
+                mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
+            }
+
+            mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
+            break;
+        }
+
+        default:
+        {
+            assert(!"should not be here, neither audio nor video.");
+            break;
+        }
+    }
+}
+
+void OMXDecoder::onStart() {
+    if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
+        status_t err =
+            mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+        assert(err == NO_ERROR);
+    }
+
+    allocateBuffers(kPortIndexInput);
+    allocateBuffers(kPortIndexOutput);
+
+    if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
+        // XXX this should happen before AllocateBuffers, but qcom's
+        // h264 vdec disagrees.
+        status_t err =
+            mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+        assert(err == NO_ERROR);
+    }
+}
+
+void OMXDecoder::allocateBuffers(OMX_U32 port_index) {
+    assert(mBuffers[port_index].empty());
+
+    OMX_U32 num_buffers;
+    OMX_U32 buffer_size;
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nVersion.s.nRevision = 0;
+    def.nVersion.s.nStep = 0;
+    def.nPortIndex = port_index;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == NO_ERROR);
+
+    num_buffers = def.nBufferCountActual;
+    buffer_size = def.nBufferSize;
+
+    LOGV("[%s] port %ld: allocating %ld buffers of size %ld each\n",
+           mComponentName, port_index, num_buffers, buffer_size);
+
+    for (OMX_U32 i = 0; i < num_buffers; ++i) {
+        sp<IMemory> mem = mDealer->allocate(buffer_size);
+        if (mem.get() == NULL) {
+            LOGE("[%s] allocating IMemory of size %ld FAILED.",
+                 mComponentName, buffer_size);
+        }
+        assert(mem.get() != NULL);
+
+        IOMX::buffer_id buffer;
+        status_t err;
+
+        if (port_index == kPortIndexInput
+                && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+            // qcom's H.263 encoder appears to want to allocate its own input
+            // buffers.
+            err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
+            if (err != OK) {
+                LOGE("[%s] allocate_buffer_with_backup failed with error %d",
+                     mComponentName, err);
+            }
+        } else if (port_index == kPortIndexOutput
+                && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
+#if 1
+            err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
+#else
+            // XXX This is fine as long as we are either running the player
+            // inside the media server process or we are using the
+            // QComHardwareRenderer to output the frames.
+            err = mOMX->allocate_buffer(mNode, port_index, buffer_size, &buffer);
+#endif
+            if (err != OK) {
+                LOGE("[%s] allocate_buffer_with_backup failed with error %d",
+                     mComponentName, err);
+            }
+        } else {
+            err = mOMX->use_buffer(mNode, port_index, mem, &buffer);
+            if (err != OK) {
+                LOGE("[%s] use_buffer failed with error %d",
+                     mComponentName, err);
+            }
+        }
+        assert(err == OK);
+
+        LOGV("allocated %s buffer %p.",
+             port_index == kPortIndexInput ? "INPUT" : "OUTPUT",
+             buffer);
+
+        mBuffers.editItemAt(port_index).push_back(buffer);
+        mBufferMap.add(buffer, mem);
+
+        if (port_index == kPortIndexOutput) {
+            OMXMediaBuffer *media_buffer = new OMXMediaBuffer(buffer, mem);
+            media_buffer->setObserver(this);
+
+            mMediaBufferMap.add(buffer, media_buffer);
+        }
+    }
+
+    LOGV("allocate %s buffers done.",
+         port_index == kPortIndexInput ? "INPUT" : "OUTPUT");
+}
+
+void OMXDecoder::onEvent(
+        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+    LOGV("[%s] onEvent event=%d, data1=%ld, data2=%ld",
+         mComponentName, event, data1, data2);
+
+    switch (event) {
+        case OMX_EventCmdComplete: {
+            onEventCmdComplete(
+                    static_cast<OMX_COMMANDTYPE>(data1), data2);
+
+            break;
+        }
+
+        case OMX_EventPortSettingsChanged: {
+            onEventPortSettingsChanged(data1);
+            break;
+        }
+
+        case OMX_EventBufferFlag: {
+            // initiateShutdown();
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) {
+    switch (type) {
+        case OMX_CommandStateSet: {
+            OMX_STATETYPE state = static_cast<OMX_STATETYPE>(data);
+            onStateChanged(state);
+            break;
+        }
+
+        case OMX_CommandPortDisable: {
+            OMX_U32 port_index = data;
+            assert(getPortStatus(port_index) == kPortStatusDisabled);
+
+            status_t err =
+                mOMX->send_command(mNode, OMX_CommandPortEnable, port_index);
+
+            allocateBuffers(port_index);
+
+            break;
+        }
+
+        case OMX_CommandPortEnable: {
+            OMX_U32 port_index = data;
+            assert(getPortStatus(port_index) ==kPortStatusDisabled);
+            setPortStatus(port_index, kPortStatusActive);
+
+            assert(port_index == kPortIndexOutput);
+
+            BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
+            while (!obuffers->empty()) {
+                IOMX::buffer_id buffer = *obuffers->begin();
+                obuffers->erase(obuffers->begin());
+
+                status_t err = mClient->fillBuffer(mNode, buffer);
+                assert(err == NO_ERROR);
+            }
+
+            break;
+        }
+
+        case OMX_CommandFlush: {
+            OMX_U32 port_index = data;
+            LOGV("Port %ld flush complete.", port_index);
+
+            PortStatus status = getPortStatus(port_index);
+
+            assert(status == kPortStatusFlushing
+                    || status == kPortStatusFlushingToDisabled
+                    || status == kPortStatusFlushingToShutdown);
+
+            switch (status) {
+                case kPortStatusFlushing:
+                {
+                    // This happens when we're flushing before a seek.
+                    setPortStatus(port_index, kPortStatusActive);
+                    BufferList *buffers = &mBuffers.editItemAt(port_index);
+                    while (!buffers->empty()) {
+                        IOMX::buffer_id buffer = *buffers->begin();
+                        buffers->erase(buffers->begin());
+
+                        if (port_index == kPortIndexInput) {
+                            postEmptyBufferDone(buffer);
+                        } else {
+                            postInitialFillBuffer(buffer);
+                        }
+                    }
+                    break;
+                }
+
+                case kPortStatusFlushingToDisabled:
+                {
+                    // Port settings have changed and the (buggy) OMX component
+                    // does not properly return buffers on disabling, we need to
+                    // do a flush first and _then_ disable the port in question.
+
+                    setPortStatus(port_index, kPortStatusDisabled);
+                    status_t err = mOMX->send_command(
+                            mNode, OMX_CommandPortDisable, port_index);
+                    assert(err == OK);
+
+                    freePortBuffers(port_index);
+                    break;
+                }
+
+                default:
+                {
+                    assert(status == kPortStatusFlushingToShutdown);
+
+                    setPortStatus(port_index, kPortStatusShutdown);
+                    if (getPortStatus(kPortIndexInput) == kPortStatusShutdown
+                        && getPortStatus(kPortIndexOutput) == kPortStatusShutdown) {
+                        status_t err = mOMX->send_command(
+                                mNode, OMX_CommandStateSet, OMX_StateIdle);
+                        assert(err == OK);
+                    }
+                    break;
+                }
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
+    assert(getPortStatus(port_index) == kPortStatusActive);
+
+    status_t err;
+
+    if (mQuirks & kDoesntReturnBuffersOnDisable) {
+        // Decoder does not properly return our buffers when disabled...
+        // Need to flush port instead and _then_ disable.
+
+        setPortStatus(port_index, kPortStatusFlushingToDisabled);
+
+        err = mOMX->send_command(mNode, OMX_CommandFlush, port_index);
+    } else {
+        setPortStatus(port_index, kPortStatusDisabled);
+
+        err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+    }
+
+    assert(err == NO_ERROR);
+}
+
+void OMXDecoder::onStateChanged(OMX_STATETYPE to) {
+    if (mState == OMX_StateLoaded) {
+        assert(to == OMX_StateIdle);
+
+        mState = to;
+
+        status_t err =
+            mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateExecuting);
+        assert(err == NO_ERROR);
+    } else if (mState == OMX_StateIdle) {
+        if (to == OMX_StateExecuting) {
+            mState = to;
+
+            BufferList *ibuffers = &mBuffers.editItemAt(kPortIndexInput);
+            while (!ibuffers->empty()) {
+                IOMX::buffer_id buffer = *ibuffers->begin();
+                ibuffers->erase(ibuffers->begin());
+
+                postEmptyBufferDone(buffer);
+            }
+
+            BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
+            while (!obuffers->empty()) {
+                IOMX::buffer_id buffer = *obuffers->begin();
+                obuffers->erase(obuffers->begin());
+
+                postInitialFillBuffer(buffer);
+            }
+        } else {
+            assert(to == OMX_StateLoaded);
+
+            mState = to;
+
+            setPortStatus(kPortIndexInput, kPortStatusActive);
+            setPortStatus(kPortIndexOutput, kPortStatusActive);
+        }
+    } else if (mState == OMX_StateExecuting) {
+        assert(to == OMX_StateIdle);
+
+        mState = to;
+
+        LOGV("Executing->Idle complete, initiating Idle->Loaded");
+        status_t err =
+            mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
+        assert(err == NO_ERROR);
+
+        freePortBuffers(kPortIndexInput);
+        freePortBuffers(kPortIndexOutput);
+    }
+}
+
+void OMXDecoder::initiateShutdown() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mShutdownInitiated) {
+        return;
+    }
+    
+    if (mState == OMX_StateLoaded) {
+        return;
+    }
+
+    assert(mState == OMX_StateExecuting);
+
+    mShutdownInitiated = true;
+
+    status_t err;
+    if (mQuirks & kDoesntFlushOnExecutingToIdle) {
+        if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
+            err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
+            assert(err == OK);
+
+            err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
+        } else {
+            err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+        }
+
+        setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
+        setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
+    } else {
+        err = mClient->send_command(
+                mNode, OMX_CommandStateSet, OMX_StateIdle);
+
+        setPortStatus(kPortIndexInput, kPortStatusShutdown);
+        setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+    }
+    assert(err == OK);
+}
+
+void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
+    int shift = 3 * port_index;
+
+    mPortStatusMask &= ~(7 << shift);
+    mPortStatusMask |= status << shift;
+}
+
+OMXDecoder::PortStatus OMXDecoder::getPortStatus(
+        OMX_U32 port_index) const {
+    int shift = 3 * port_index;
+
+    return static_cast<PortStatus>((mPortStatusMask >> shift) & 7);
+}
+
+void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
+    LOGV("[%s] onEmptyBufferDone (%p)", mComponentName, buffer);
+
+    status_t err;
+    switch (getPortStatus(kPortIndexInput)) {
+        case kPortStatusDisabled:
+            freeInputBuffer(buffer);
+            err = NO_ERROR;
+            break;
+
+        case kPortStatusShutdown:
+            LOGV("We're shutting down, enqueue INPUT buffer %p.", buffer);
+            mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
+            err = NO_ERROR;
+            break;
+
+        case kPortStatusFlushing:
+        case kPortStatusFlushingToDisabled:
+        case kPortStatusFlushingToShutdown:
+            LOGV("We're currently flushing, enqueue INPUT buffer %p.", buffer);
+            mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
+            err = NO_ERROR;
+            break;
+
+        default:
+            onRealEmptyBufferDone(buffer);
+            err = NO_ERROR;
+            break;
+    }
+    assert(err == NO_ERROR);
+}
+
+void OMXDecoder::onFillBufferDone(const omx_message &msg) {
+    IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+
+    LOGV("[%s] on%sFillBufferDone (%p, size:%ld)", mComponentName,
+         msg.type == omx_message::INITIAL_FILL_BUFFER ? "Initial" : "",
+         buffer, msg.u.extended_buffer_data.range_length);
+
+    status_t err;
+    switch (getPortStatus(kPortIndexOutput)) {
+        case kPortStatusDisabled:
+            freeOutputBuffer(buffer);
+            err = NO_ERROR;
+            break;
+        case kPortStatusShutdown:
+            LOGV("We're shutting down, enqueue OUTPUT buffer %p.", buffer);
+            mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
+            err = NO_ERROR;
+            break;
+
+        case kPortStatusFlushing:
+        case kPortStatusFlushingToDisabled:
+        case kPortStatusFlushingToShutdown:
+            LOGV("We're currently flushing, enqueue OUTPUT buffer %p.", buffer);
+            mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
+            err = NO_ERROR;
+            break;
+
+        default:
+        {
+            if (msg.type == omx_message::INITIAL_FILL_BUFFER) {
+                err = mClient->fillBuffer(mNode, buffer);
+            } else {
+                LOGV("[%s] Filled OUTPUT buffer %p, flags=0x%08lx.",
+                     mComponentName, buffer, msg.u.extended_buffer_data.flags);
+
+                onRealFillBufferDone(msg);
+                err = NO_ERROR;
+            }
+            break;
+        }
+    }
+    assert(err == NO_ERROR);
+}
+
+void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) {
+    if (mReachedEndOfInput) {
+        // We already sent the EOS notification.
+
+        mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
+        return;
+    }
+
+    const sp<IMemory> mem = mBufferMap.valueFor(buffer);
+    assert(mem.get() != NULL);
+
+    static const uint8_t kNALStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
+
+    if (mCodecSpecificDataIterator != mCodecSpecificData.end()) {
+        List<CodecSpecificData>::iterator it = mCodecSpecificDataIterator;
+
+        size_t range_length = 0;
+
+        if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
+            assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
+
+            memcpy(mem->pointer(), kNALStartCode, 4);
+
+            memcpy((uint8_t *)mem->pointer() + 4, (*it).data, (*it).size);
+            range_length = (*it).size + 4;
+        } else {
+            assert((*mCodecSpecificDataIterator).size <= mem->size());
+
+            memcpy((uint8_t *)mem->pointer(), (*it).data, (*it).size);
+            range_length = (*it).size;
+        }
+
+        ++mCodecSpecificDataIterator;
+
+        status_t err = mClient->emptyBuffer(
+                mNode, buffer, 0, range_length, 
+                OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
+                0);
+
+        assert(err == NO_ERROR);
+
+        return;
+    }
+
+    LOGV("[%s] waiting for input data", mComponentName);
+
+    MediaBuffer *input_buffer;
+    for (;;) {
+        status_t err;
+
+        if (mSeeking) {
+            MediaSource::ReadOptions options;
+            options.setSeekTo(mSeekTimeUs);
+
+            mSeeking = false;
+
+            err = mSource->read(&input_buffer, &options);
+        } else {
+            err = mSource->read(&input_buffer);
+        }
+        assert((err == OK && input_buffer != NULL)
+               || (err != OK && input_buffer == NULL));
+
+        if (err == ERROR_END_OF_STREAM) {
+            LOGE("[%s] Reached end of stream.", mComponentName);
+            mReachedEndOfInput = true;
+        } else {
+            LOGV("[%s] got input data", mComponentName);
+        }
+
+        if (err != OK) {
+            status_t err2 = mClient->emptyBuffer(
+                    mNode, buffer, 0, 0, OMX_BUFFERFLAG_EOS, 0);
+
+            assert(err2 == NO_ERROR);
+            return;
+        }
+
+        if (mSeeking) {
+            input_buffer->release();
+            input_buffer = NULL;
+
+            continue;
+        }
+
+        break;
+    }
+
+    const uint8_t *src_data =
+        (const uint8_t *)input_buffer->data() + input_buffer->range_offset();
+
+    size_t src_length = input_buffer->range_length();
+    if (src_length == 195840) {
+        // When feeding the output of the AVC decoder into the H263 encoder,
+        // buffer sizes mismatch if width % 16 != 0 || height % 16 != 0.
+        src_length = 194400;  // XXX HACK
+    } else if (src_length == 115200) {
+        src_length = 114240;  // XXX HACK
+    }
+
+    if (src_length > mem->size()) {
+        LOGE("src_length=%d > mem->size() = %d\n",
+             src_length, mem->size());
+    }
+
+    assert(src_length <= mem->size());
+    memcpy(mem->pointer(), src_data, src_length);
+
+    OMX_U32 flags = 0;
+    if (!mIsMP3) {
+        // Only mp3 audio data may be streamed, all other data is assumed
+        // to be fed into the decoder at frame boundaries.
+        flags |= OMX_BUFFERFLAG_ENDOFFRAME;
+    }
+
+    int32_t units, scale;
+    bool success =
+        input_buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+
+    success = success &&
+        input_buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+
+    OMX_TICKS timestamp = 0;
+
+    if (success) {
+        if (mQuirks & kMeasuresTimeInMilliseconds) {
+            timestamp = ((OMX_S64)units * 1000) / scale;
+        } else {
+            timestamp = ((OMX_S64)units * 1000000) / scale;
+        }
+    }
+
+    input_buffer->release();
+    input_buffer = NULL;
+
+    LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
+         mComponentName, buffer, src_length, flags);
+
+    status_t err2 = mClient->emptyBuffer(
+            mNode, buffer, 0, src_length, flags, timestamp);
+    assert(err2 == OK);
+}
+
+void OMXDecoder::onRealFillBufferDone(const omx_message &msg) {
+    OMXMediaBuffer *media_buffer =
+        mMediaBufferMap.valueFor(msg.u.extended_buffer_data.buffer);
+
+    media_buffer->set_range(
+            msg.u.extended_buffer_data.range_offset,
+            msg.u.extended_buffer_data.range_length);
+
+    media_buffer->add_ref();
+
+    media_buffer->meta_data()->clear();
+
+    if (mQuirks & kMeasuresTimeInMilliseconds) {
+        media_buffer->meta_data()->setInt32(
+                kKeyTimeUnits,
+                msg.u.extended_buffer_data.timestamp);
+    } else {
+        media_buffer->meta_data()->setInt32(
+                kKeyTimeUnits,
+                (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+    }
+
+    media_buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+
+    if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
+        media_buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
+    }
+
+    media_buffer->meta_data()->setPointer(
+            kKeyPlatformPrivate,
+            msg.u.extended_buffer_data.platform_private);
+
+    if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) {
+        mErrorCondition = ERROR_END_OF_STREAM;
+    }
+
+    mOutputBuffers.push_back(media_buffer);
+    mOutputBufferAvailable.signal();
+}
+
+void OMXDecoder::signalBufferReturned(MediaBuffer *_buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMXMediaBuffer *media_buffer = static_cast<OMXMediaBuffer *>(_buffer);
+
+    IOMX::buffer_id buffer = media_buffer->buffer_id();
+
+    PortStatus outputStatus = getPortStatus(kPortIndexOutput);
+    if (outputStatus == kPortStatusShutdown
+            || outputStatus == kPortStatusFlushing
+            || outputStatus == kPortStatusFlushingToDisabled
+            || outputStatus == kPortStatusFlushingToShutdown) {
+        mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
+    } else {
+        LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
+
+        status_t err = mClient->fillBuffer(mNode, buffer);
+        assert(err == NO_ERROR);
+    }
+}
+
+void OMXDecoder::freeInputBuffer(IOMX::buffer_id buffer) {
+    LOGV("freeInputBuffer %p", buffer);
+
+    status_t err = mOMX->free_buffer(mNode, kPortIndexInput, buffer);
+    assert(err == NO_ERROR);
+    mBufferMap.removeItem(buffer);
+
+    LOGV("freeInputBuffer %p done", buffer);
+}
+
+void OMXDecoder::freeOutputBuffer(IOMX::buffer_id buffer) {
+    LOGV("freeOutputBuffer %p", buffer);
+
+    status_t err = mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
+    assert(err == NO_ERROR);
+    mBufferMap.removeItem(buffer);
+
+    ssize_t index = mMediaBufferMap.indexOfKey(buffer);
+    assert(index >= 0);
+    MediaBuffer *mbuffer = mMediaBufferMap.editValueAt(index);
+    mMediaBufferMap.removeItemsAt(index);
+    mbuffer->setObserver(NULL);
+    mbuffer->release();
+    mbuffer = NULL;
+
+    LOGV("freeOutputBuffer %p done", buffer);
+}
+
+void OMXDecoder::dumpPortDefinition(OMX_U32 port_index) {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = port_index;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == NO_ERROR);
+
+    LOGI("DumpPortDefinition on port %ld", port_index);
+    LOGI("nBufferCountActual = %ld, nBufferCountMin = %ld, nBufferSize = %ld",
+         def.nBufferCountActual, def.nBufferCountMin, def.nBufferSize);
+    switch (def.eDomain) {
+        case OMX_PortDomainAudio:
+        {
+            LOGI("eDomain = AUDIO");
+
+            if (port_index == kPortIndexOutput) {
+                OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
+                assert(audio_def->eEncoding == OMX_AUDIO_CodingPCM);
+
+                OMX_AUDIO_PARAM_PCMMODETYPE params;
+                params.nSize = sizeof(params);
+                params.nVersion.s.nVersionMajor = 1;
+                params.nVersion.s.nVersionMinor = 1;
+                params.nPortIndex = port_index;
+
+                err = mOMX->get_parameter(
+                        mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
+                assert(err == OK);
+
+                assert(params.nChannels == 1 || params.bInterleaved);
+                assert(params.eNumData == OMX_NumericalDataSigned);
+                assert(params.nBitPerSample == 16);
+                assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear);
+
+                LOGI("nChannels = %ld, nSamplingRate = %ld",
+                     params.nChannels, params.nSamplingRate);
+            }
+
+            break;
+        }
+
+        case OMX_PortDomainVideo:
+        {
+            LOGI("eDomain = VIDEO");
+
+            OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+            LOGI("nFrameWidth = %ld, nFrameHeight = %ld, nStride = %ld, "
+                 "nSliceHeight = %ld",
+                 video_def->nFrameWidth, video_def->nFrameHeight,
+                 video_def->nStride, video_def->nSliceHeight);
+            LOGI("nBitrate = %ld, xFrameRate = %.2f",
+                 video_def->nBitrate, video_def->xFramerate / 65536.0f);
+            LOGI("eCompressionFormat = %d, eColorFormat = %d",
+                 video_def->eCompressionFormat, video_def->eColorFormat);
+
+            break;
+        }
+
+        default:
+            LOGI("eDomain = UNKNOWN");
+            break;
+    }
+}
+
+void OMXDecoder::postStart() {
+    omx_message msg;
+    msg.type = omx_message::START;
+    postMessage(msg);
+}
+
+void OMXDecoder::postEmptyBufferDone(IOMX::buffer_id buffer) {
+    omx_message msg;
+    msg.type = omx_message::EMPTY_BUFFER_DONE;
+    msg.u.buffer_data.node = mNode;
+    msg.u.buffer_data.buffer = buffer;
+    postMessage(msg);
+}
+
+void OMXDecoder::postInitialFillBuffer(IOMX::buffer_id buffer) {
+    omx_message msg;
+    msg.type = omx_message::INITIAL_FILL_BUFFER;
+    msg.u.buffer_data.node = mNode;
+    msg.u.buffer_data.buffer = buffer;
+    postMessage(msg);
+}
+
+void OMXDecoder::freePortBuffers(OMX_U32 port_index) {
+    BufferList *buffers = &mBuffers.editItemAt(port_index);
+    while (!buffers->empty()) {
+        IOMX::buffer_id buffer = *buffers->begin();
+        buffers->erase(buffers->begin());
+
+        if (port_index == kPortIndexInput) {
+            freeInputBuffer(buffer);
+        } else {
+            freeOutputBuffer(buffer);
+        }
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/QComHardwareRenderer.cpp b/media/libstagefright/QComHardwareRenderer.cpp
new file mode 100644
index 0000000..5a23792
--- /dev/null
+++ b/media/libstagefright/QComHardwareRenderer.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <media/stagefright/QComHardwareRenderer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+typedef struct PLATFORM_PRIVATE_ENTRY
+{
+    /* Entry type */
+    uint32_t type;
+
+    /* Pointer to platform specific entry */
+    void *entry;
+
+} PLATFORM_PRIVATE_ENTRY;
+
+typedef struct PLATFORM_PRIVATE_LIST
+{
+    /* Number of entries */
+    uint32_t nEntries;
+
+    /* Pointer to array of platform specific entries *
+     * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */
+    PLATFORM_PRIVATE_ENTRY *entryList;
+
+} PLATFORM_PRIVATE_LIST;
+
+// data structures for tunneling buffers
+typedef struct PLATFORM_PRIVATE_PMEM_INFO
+{
+    /* pmem file descriptor */
+    uint32_t pmem_fd;
+    uint32_t offset;
+
+} PLATFORM_PRIVATE_PMEM_INFO;
+
+#define PLATFORM_PRIVATE_PMEM   1
+
+QComHardwareRenderer::QComHardwareRenderer(
+        const sp<ISurface> &surface,
+        size_t displayWidth, size_t displayHeight,
+        size_t decodedWidth, size_t decodedHeight)
+    : mISurface(surface),
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mDecodedWidth(decodedWidth),
+      mDecodedHeight(decodedHeight),
+      mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+    assert(mISurface.get() != NULL);
+    assert(mDecodedWidth > 0);
+    assert(mDecodedHeight > 0);
+}
+
+QComHardwareRenderer::~QComHardwareRenderer() {
+    mISurface->unregisterBuffers();
+}
+
+void QComHardwareRenderer::render(
+        const void *data, size_t size, void *platformPrivate) {
+    size_t offset;
+    if (!getOffset(platformPrivate, &offset)) {
+        return;
+    }
+
+    mISurface->postBuffer(offset);
+}
+
+bool QComHardwareRenderer::getOffset(void *platformPrivate, size_t *offset) {
+    *offset = 0;
+
+    PLATFORM_PRIVATE_LIST *list = (PLATFORM_PRIVATE_LIST *)platformPrivate;
+    for (uint32_t i = 0; i < list->nEntries; ++i) {
+        if (list->entryList[i].type != PLATFORM_PRIVATE_PMEM) {
+            continue;
+        }
+
+        PLATFORM_PRIVATE_PMEM_INFO *info =
+            (PLATFORM_PRIVATE_PMEM_INFO *)list->entryList[i].entry;
+
+        if (info != NULL) {
+            if (mMemoryHeap.get() == NULL) {
+                publishBuffers(info->pmem_fd);
+            }
+
+            if (mMemoryHeap.get() == NULL) {
+                return false;
+            }
+
+            *offset = info->offset;
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void QComHardwareRenderer::publishBuffers(uint32_t pmem_fd) {
+    sp<MemoryHeapBase> master =
+        reinterpret_cast<MemoryHeapBase *>(pmem_fd);
+
+    master->setDevice("/dev/pmem");
+
+    mMemoryHeap = new MemoryHeapPmem(master, 0);
+    mMemoryHeap->slap();
+
+    ISurface::BufferHeap bufferHeap(
+            mDisplayWidth, mDisplayHeight,
+            mDecodedWidth, mDecodedHeight,
+            PIXEL_FORMAT_YCbCr_420_SP,
+            mMemoryHeap);
+
+    status_t err = mISurface->registerBuffers(bufferHeap);
+    assert(err == OK);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
new file mode 100644
index 0000000..8f1fa67
--- /dev/null
+++ b/media/libstagefright/SampleTable.cpp
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SampleTable"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/SampleTable.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
+static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
+static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
+static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
+
+SampleTable::SampleTable(DataSource *source)
+    : mDataSource(source),
+      mChunkOffsetOffset(-1),
+      mChunkOffsetType(0),
+      mNumChunkOffsets(0),
+      mSampleToChunkOffset(-1),
+      mNumSampleToChunkOffsets(0),
+      mSampleSizeOffset(-1),
+      mSampleSizeFieldSize(0),
+      mDefaultSampleSize(0),
+      mNumSampleSizes(0),
+      mTimeToSampleCount(0),
+      mTimeToSample(NULL),
+      mSyncSampleOffset(-1),
+      mNumSyncSamples(0) {
+}
+
+SampleTable::~SampleTable() {
+    delete[] mTimeToSample;
+    mTimeToSample = NULL;
+}
+
+status_t SampleTable::setChunkOffsetParams(
+        uint32_t type, off_t data_offset, off_t data_size) {
+    if (mChunkOffsetOffset >= 0) {
+        return ERROR_MALFORMED;
+    }
+
+    assert(type == kChunkOffsetType32 || type == kChunkOffsetType64);
+
+    mChunkOffsetOffset = data_offset;
+    mChunkOffsetType = type;
+
+    if (data_size < 8) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t header[8];
+    if (mDataSource->read_at(
+                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return ERROR_IO;
+    }
+
+    if (U32_AT(header) != 0) {
+        // Expected version = 0, flags = 0.
+        return ERROR_MALFORMED;
+    }
+
+    mNumChunkOffsets = U32_AT(&header[4]);
+
+    if (mChunkOffsetType == kChunkOffsetType32) {
+        if (data_size < 8 + mNumChunkOffsets * 4) {
+            return ERROR_MALFORMED;
+        }
+    } else {
+        if (data_size < 8 + mNumChunkOffsets * 8) {
+            return ERROR_MALFORMED;
+        }
+    }
+
+    return OK;
+}
+
+status_t SampleTable::setSampleToChunkParams(
+        off_t data_offset, off_t data_size) {
+    if (mSampleToChunkOffset >= 0) {
+        return ERROR_MALFORMED;
+    }
+
+    mSampleToChunkOffset = data_offset;
+
+    if (data_size < 8) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t header[8];
+    if (mDataSource->read_at(
+                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return ERROR_IO;
+    }
+
+    if (U32_AT(header) != 0) {
+        // Expected version = 0, flags = 0.
+        return ERROR_MALFORMED;
+    }
+
+    mNumSampleToChunkOffsets = U32_AT(&header[4]);
+
+    if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
+        return ERROR_MALFORMED;
+    }
+
+    return OK;
+}
+
+status_t SampleTable::setSampleSizeParams(
+        uint32_t type, off_t data_offset, off_t data_size) {
+    if (mSampleSizeOffset >= 0) {
+        return ERROR_MALFORMED;
+    }
+
+    assert(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
+
+    mSampleSizeOffset = data_offset;
+
+    if (data_size < 12) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t header[12];
+    if (mDataSource->read_at(
+                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return ERROR_IO;
+    }
+
+    if (U32_AT(header) != 0) {
+        // Expected version = 0, flags = 0.
+        return ERROR_MALFORMED;
+    }
+
+    mDefaultSampleSize = U32_AT(&header[4]);
+    mNumSampleSizes = U32_AT(&header[8]);
+
+    if (type == kSampleSizeType32) {
+        mSampleSizeFieldSize = 32;
+
+        if (mDefaultSampleSize != 0) {
+            return OK;
+        }
+
+        if (data_size < 12 + mNumSampleSizes * 4) {
+            return ERROR_MALFORMED;
+        }
+    } else {
+        if ((mDefaultSampleSize & 0xffffff00) != 0) {
+            // The high 24 bits are reserved and must be 0.
+            return ERROR_MALFORMED;
+        }
+
+        mSampleSizeFieldSize = mDefaultSampleSize & 0xf;
+        mDefaultSampleSize = 0;
+
+        if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
+            && mSampleSizeFieldSize != 16) {
+            return ERROR_MALFORMED;
+        }
+
+        if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
+            return ERROR_MALFORMED;
+        }
+    }
+
+    return OK;
+}
+
+status_t SampleTable::setTimeToSampleParams(
+        off_t data_offset, off_t data_size) {
+    if (mTimeToSample != NULL || data_size < 8) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t header[8];
+    if (mDataSource->read_at(
+                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return ERROR_IO;
+    }
+
+    if (U32_AT(header) != 0) {
+        // Expected version = 0, flags = 0.
+        return ERROR_MALFORMED;
+    }
+
+    mTimeToSampleCount = U32_AT(&header[4]);
+    mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
+
+    size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
+    if (mDataSource->read_at(
+                data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
+        return ERROR_IO;
+    }
+
+    for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
+        mTimeToSample[i] = ntohl(mTimeToSample[i]);
+    }
+
+    return OK;
+}
+
+status_t SampleTable::setSyncSampleParams(off_t data_offset, off_t data_size) {
+    if (mSyncSampleOffset >= 0 || data_size < 8) {
+        return ERROR_MALFORMED;
+    }
+
+    mSyncSampleOffset = data_offset;
+
+    uint8_t header[8];
+    if (mDataSource->read_at(
+                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        return ERROR_IO;
+    }
+
+    if (U32_AT(header) != 0) {
+        // Expected version = 0, flags = 0.
+        return ERROR_MALFORMED;
+    }
+
+    mNumSyncSamples = U32_AT(&header[4]);
+
+    if (mNumSyncSamples < 2) {
+        LOGW("Table of sync samples is empty or has only a single entry!");
+    }
+    return OK;
+}
+
+uint32_t SampleTable::countChunkOffsets() const {
+    return mNumChunkOffsets;
+}
+
+status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
+    *offset = 0;
+
+    if (mChunkOffsetOffset < 0) {
+        return ERROR_MALFORMED;
+    }
+
+    if (chunk_index >= mNumChunkOffsets) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    if (mChunkOffsetType == kChunkOffsetType32) {
+        uint32_t offset32;
+
+        if (mDataSource->read_at(
+                    mChunkOffsetOffset + 8 + 4 * chunk_index,
+                    &offset32,
+                    sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
+            return ERROR_IO;
+        }
+
+        *offset = ntohl(offset32);
+    } else {
+        assert(mChunkOffsetOffset == kChunkOffsetType64);
+
+        uint64_t offset64;
+        if (mDataSource->read_at(
+                    mChunkOffsetOffset + 8 + 8 * chunk_index,
+                    &offset64,
+                    sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
+            return ERROR_IO;
+        }
+
+        *offset = ntoh64(offset64);
+    }
+
+    return OK;
+}
+
+status_t SampleTable::getChunkForSample(
+        uint32_t sample_index,
+        uint32_t *chunk_index, 
+        uint32_t *chunk_relative_sample_index,
+        uint32_t *desc_index) {
+    *chunk_index = 0;
+    *chunk_relative_sample_index = 0;
+    *desc_index = 0;
+
+    if (mSampleToChunkOffset < 0) {
+        return ERROR_MALFORMED;
+    }
+
+    if (sample_index >= countSamples()) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    uint32_t first_chunk = 0;
+    uint32_t samples_per_chunk = 0;
+    uint32_t chunk_desc_index = 0;
+
+    uint32_t index = 0;
+    while (index < mNumSampleToChunkOffsets) {
+        uint8_t buffer[12];
+        if (mDataSource->read_at(mSampleToChunkOffset + 8 + index * 12,
+                                 buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+            return ERROR_IO;
+        }
+
+        uint32_t stop_chunk = U32_AT(buffer);
+        if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) {
+            break;
+        }
+
+        sample_index -= (stop_chunk - first_chunk) * samples_per_chunk;
+        first_chunk = stop_chunk;
+        samples_per_chunk = U32_AT(&buffer[4]);
+        chunk_desc_index = U32_AT(&buffer[8]);
+
+        ++index;
+    }
+
+    *chunk_index = sample_index / samples_per_chunk + first_chunk - 1;
+    *chunk_relative_sample_index = sample_index % samples_per_chunk;
+    *desc_index = chunk_desc_index;
+
+    return OK;
+}
+
+uint32_t SampleTable::countSamples() const {
+    return mNumSampleSizes;
+}
+
+status_t SampleTable::getSampleSize(
+        uint32_t sample_index, size_t *sample_size) {
+    *sample_size = 0;
+
+    if (mSampleSizeOffset < 0) {
+        return ERROR_MALFORMED;
+    }
+
+    if (sample_index >= mNumSampleSizes) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    if (mDefaultSampleSize > 0) {
+        *sample_size = mDefaultSampleSize;
+        return OK;
+    }
+
+    switch (mSampleSizeFieldSize) {
+        case 32:
+        {
+            if (mDataSource->read_at(
+                        mSampleSizeOffset + 12 + 4 * sample_index,
+                        sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
+                return ERROR_IO;
+            }
+
+            *sample_size = ntohl(*sample_size);
+            break;
+        }
+
+        case 16:
+        {
+            uint16_t x;
+            if (mDataSource->read_at(
+                        mSampleSizeOffset + 12 + 2 * sample_index,
+                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+                return ERROR_IO;
+            }
+
+            *sample_size = ntohs(x);
+            break;
+        }
+
+        case 8:
+        {
+            uint8_t x;
+            if (mDataSource->read_at(
+                        mSampleSizeOffset + 12 + sample_index,
+                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+                return ERROR_IO;
+            }
+
+            *sample_size = x;
+            break;
+        }
+
+        default:
+        {
+            assert(mSampleSizeFieldSize == 4);
+
+            uint8_t x;
+            if (mDataSource->read_at(
+                        mSampleSizeOffset + 12 + sample_index / 2,
+                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+                return ERROR_IO;
+            }
+
+            *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4;
+            break;
+        }
+    }
+
+    return OK;
+}
+
+status_t SampleTable::getSampleOffsetAndSize(
+        uint32_t sample_index, off_t *offset, size_t *size) {
+    Mutex::Autolock autoLock(mLock);
+
+    *offset = 0;
+    *size = 0;
+
+    uint32_t chunk_index;
+    uint32_t chunk_relative_sample_index;
+    uint32_t desc_index;
+    status_t err = getChunkForSample(
+            sample_index, &chunk_index, &chunk_relative_sample_index,
+            &desc_index);
+
+    if (err != OK) {
+        return err;
+    }
+
+    err = getChunkOffset(chunk_index, offset);
+
+    if (err != OK) {
+        return err;
+    }
+
+    for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) {
+        size_t sample_size;
+        err = getSampleSize(sample_index - j - 1, &sample_size);
+
+        if (err != OK) {
+            return err;
+        }
+
+        *offset += sample_size;
+    }
+
+    err = getSampleSize(sample_index, size);
+
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
+status_t SampleTable::getMaxSampleSize(size_t *max_size) {
+    Mutex::Autolock autoLock(mLock);
+
+    *max_size = 0;
+
+    for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
+        size_t sample_size;
+        status_t err = getSampleSize(i, &sample_size);
+        
+        if (err != OK) {
+            return err;
+        }
+
+        if (sample_size > *max_size) {
+            *max_size = sample_size;
+        }
+    }
+
+    return OK;
+}
+
+status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) {
+    // XXX FIXME idiotic (for the common use-case) O(n) algorithm below...
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (sample_index >= mNumSampleSizes) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    uint32_t cur_sample = 0;
+    *time = 0;
+    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
+        uint32_t n = mTimeToSample[2 * i];
+        uint32_t delta = mTimeToSample[2 * i + 1];
+
+        if (sample_index < cur_sample + n) {
+            *time += delta * (sample_index - cur_sample);
+
+            return OK;
+        }
+        
+        *time += delta * n;
+        cur_sample += n;
+    }
+
+    return ERROR_OUT_OF_RANGE;
+}
+
+status_t SampleTable::findClosestSample(
+        uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+    Mutex::Autolock autoLock(mLock);
+
+    uint32_t cur_sample = 0;
+    uint32_t time = 0;
+    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
+        uint32_t n = mTimeToSample[2 * i];
+        uint32_t delta = mTimeToSample[2 * i + 1];
+
+        if (req_time < time + n * delta) {
+            int j = (req_time - time) / delta;
+
+            *sample_index = cur_sample + j;
+
+            if (flags & kSyncSample_Flag) {
+                return findClosestSyncSample(*sample_index, sample_index);
+            }
+
+            return OK;
+        }
+
+        time += delta * n;
+        cur_sample += n;
+    }
+
+    return ERROR_OUT_OF_RANGE;
+}
+
+status_t SampleTable::findClosestSyncSample(
+        uint32_t start_sample_index, uint32_t *sample_index) {
+    *sample_index = 0;
+
+    if (mSyncSampleOffset < 0) {
+        // All samples are sync-samples.
+        *sample_index = start_sample_index;
+        return OK;
+    }
+
+    uint32_t x;
+    uint32_t left = 0;
+    uint32_t right = mNumSyncSamples;
+    while (left < right) {
+        uint32_t mid = (left + right) / 2;
+        if (mDataSource->read_at(
+                    mSyncSampleOffset + 8 + (mid - 1) * 4, &x, 4) != 4) {
+            return ERROR_IO;
+        }
+
+        x = ntohl(x);
+
+        if (x < (start_sample_index + 1)) {
+            left = mid + 1;
+        } else if (x > (start_sample_index + 1)) {
+            right = mid;
+        } else {
+            break;
+        }
+    }
+
+#if 1
+    // Make sure we return a sample at or _after_ the requested one.
+    // Seeking to a particular time in a media source containing audio and
+    // video will most likely be able to sync fairly close to the requested
+    // time in the audio track but may only be able to seek a fair distance
+    // from the requested time in the video track.
+    // If we seek the video track to a time earlier than the audio track,
+    // we'll cause the video track to be late for quite a while, the decoder
+    // trying to catch up.
+    // If we seek the video track to a time later than the audio track,
+    // audio will start playing fine while no video will be output for a
+    // while, the video decoder will not stress the system.
+    if (mDataSource->read_at(
+                mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) {
+        return ERROR_IO;
+    }
+    x = ntohl(x);
+    assert((x - 1) >= start_sample_index);
+#endif
+
+    *sample_index = x - 1;
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
new file mode 100644
index 0000000..17b626e
--- /dev/null
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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 <stdlib.h>
+
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/ShoutcastSource.h>
+#include <media/stagefright/string.h>
+
+namespace android {
+
+ShoutcastSource::ShoutcastSource(HTTPStream *http)
+    : mHttp(http),
+      mMetaDataOffset(0),
+      mBytesUntilMetaData(0),
+      mGroup(NULL),
+      mStarted(false) {
+    string metaint;
+    if (mHttp->find_header_value("icy-metaint", &metaint)) {
+        char *end;
+        const char *start = metaint.c_str();
+        mMetaDataOffset = strtol(start, &end, 10);
+        assert(end > start && *end == '\0');
+        assert(mMetaDataOffset > 0);
+
+        mBytesUntilMetaData = mMetaDataOffset;
+    }
+}
+
+ShoutcastSource::~ShoutcastSource() {
+    if (mStarted) {
+        stop();
+    }
+
+    delete mHttp;
+    mHttp = NULL;
+}
+
+status_t ShoutcastSource::start(MetaData *) {
+    assert(!mStarted);
+
+    mGroup = new MediaBufferGroup;
+    mGroup->add_buffer(new MediaBuffer(4096));  // XXX
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t ShoutcastSource::stop() {
+    assert(mStarted);
+
+    delete mGroup;
+    mGroup = NULL;
+
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> ShoutcastSource::getFormat() {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, "audio/mpeg");
+    meta->setInt32(kKeySampleRate, 44100);
+    meta->setInt32(kKeyChannelCount, 2);  // XXX
+
+    return meta;
+}
+
+status_t ShoutcastSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    assert(mStarted);
+
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+    if (err != OK) {
+        return err;
+    }
+
+    *out = buffer;
+
+    size_t num_bytes = buffer->size();
+    if (mMetaDataOffset > 0 && num_bytes > mBytesUntilMetaData) {
+        num_bytes = mBytesUntilMetaData;
+    }
+
+    ssize_t n = mHttp->receive(buffer->data(), num_bytes);
+
+    if (n <= 0) {
+        return (status_t)n;
+    }
+
+    buffer->set_range(0, n);
+
+    mBytesUntilMetaData -= (size_t)n;
+
+    if (mBytesUntilMetaData == 0) {
+        unsigned char num_16_byte_blocks = 0;
+        n = mHttp->receive((char *)&num_16_byte_blocks, 1);
+        assert(n == 1);
+
+        char meta[255 * 16];
+        size_t meta_size = num_16_byte_blocks * 16;
+        size_t meta_length = 0;
+        while (meta_length < meta_size) {
+            n = mHttp->receive(&meta[meta_length], meta_size - meta_length);
+            if (n <= 0) {
+                return (status_t)n;
+            }
+
+            meta_length += (size_t) n;
+        }
+
+        while (meta_length > 0 && meta[meta_length - 1] == '\0') {
+            --meta_length;
+        }
+
+        if (meta_length > 0) {
+            // Technically we should probably attach this meta data to the
+            // next buffer. XXX
+            buffer->meta_data()->setData('shou', 'shou', meta, meta_length);
+        }
+
+        mBytesUntilMetaData = mMetaDataOffset;
+    }
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/SoftwareRenderer.cpp b/media/libstagefright/SoftwareRenderer.cpp
new file mode 100644
index 0000000..66b6b07
--- /dev/null
+++ b/media/libstagefright/SoftwareRenderer.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoftwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/MemoryHeapBase.h>
+#include <media/stagefright/SoftwareRenderer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+#define QCOM_YUV        0
+
+SoftwareRenderer::SoftwareRenderer(
+        const sp<ISurface> &surface,
+        size_t displayWidth, size_t displayHeight,
+        size_t decodedWidth, size_t decodedHeight)
+    : mISurface(surface),
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mDecodedWidth(decodedWidth),
+      mDecodedHeight(decodedHeight),
+      mFrameSize(mDecodedWidth * mDecodedHeight * 2),  // RGB565
+      mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
+      mIndex(0) {
+    assert(mISurface.get() != NULL);
+    assert(mDecodedWidth > 0);
+    assert(mDecodedHeight > 0);
+    assert(mMemoryHeap->heapID() >= 0);
+
+    ISurface::BufferHeap bufferHeap(
+            mDisplayWidth, mDisplayHeight,
+            mDecodedWidth, mDecodedHeight,
+            PIXEL_FORMAT_RGB_565,
+            mMemoryHeap);
+
+    status_t err = mISurface->registerBuffers(bufferHeap);
+    assert(err == OK);
+}
+
+SoftwareRenderer::~SoftwareRenderer() {
+    mISurface->unregisterBuffers();
+}
+
+void SoftwareRenderer::render(
+        const void *data, size_t size, void *platformPrivate) {
+    assert(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
+
+    static const signed kClipMin = -278;
+    static const signed kClipMax = 535;
+    static uint8_t kClip[kClipMax - kClipMin + 1];
+    static uint8_t *kAdjustedClip = &kClip[-kClipMin];
+
+    static bool clipInitialized = false;
+
+    if (!clipInitialized) {
+        for (signed i = kClipMin; i <= kClipMax; ++i) {
+            kClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
+        }
+        clipInitialized = true;
+    }
+
+    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;
+    }
+
+    mISurface->postBuffer(offset);
+    mIndex = 1 - mIndex;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/SurfaceRenderer.cpp b/media/libstagefright/SurfaceRenderer.cpp
new file mode 100644
index 0000000..e54288d
--- /dev/null
+++ b/media/libstagefright/SurfaceRenderer.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/SurfaceRenderer.h>
+#include <ui/Surface.h>
+
+namespace android {
+
+SurfaceRenderer::SurfaceRenderer(
+        const sp<Surface> &surface,
+        size_t displayWidth, size_t displayHeight,
+        size_t decodedWidth, size_t decodedHeight)
+    : mSurface(surface),
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mDecodedWidth(decodedWidth),
+      mDecodedHeight(decodedHeight) {
+}
+
+SurfaceRenderer::~SurfaceRenderer() {
+}
+
+void SurfaceRenderer::render(
+        const void *data, size_t size, void *platformPrivate) {
+    Surface::SurfaceInfo info;
+    status_t err = mSurface->lock(&info);
+    if (err != OK) {
+        return;
+    }
+
+    const uint8_t *src = (const uint8_t *)data;
+    uint8_t *dst = (uint8_t *)info.bits;
+
+    for (size_t i = 0; i < mDisplayHeight; ++i) {
+        memcpy(dst, src, mDisplayWidth);
+        src += mDecodedWidth;
+        dst += mDisplayWidth;
+    }
+    src += (mDecodedHeight - mDisplayHeight) * mDecodedWidth;
+    
+    for (size_t i = 0; i < (mDisplayHeight + 1) / 2; ++i) {
+        memcpy(dst, src, (mDisplayWidth + 1) & ~1);
+        src += (mDecodedWidth + 1) & ~1;
+        dst += (mDisplayWidth + 1) & ~1;
+    }
+
+    mSurface->unlockAndPost();
+}
+
+}  // namespace android
diff --git a/media/libstagefright/TIHardwareRenderer.cpp b/media/libstagefright/TIHardwareRenderer.cpp
new file mode 100644
index 0000000..ba42ef4
--- /dev/null
+++ b/media/libstagefright/TIHardwareRenderer.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TIHardwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TIHardwareRenderer::TIHardwareRenderer(
+        const sp<ISurface> &surface,
+        size_t displayWidth, size_t displayHeight,
+        size_t decodedWidth, size_t decodedHeight)
+    : mISurface(surface),
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mDecodedWidth(decodedWidth),
+      mDecodedHeight(decodedHeight),
+      mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+    assert(mISurface.get() != NULL);
+    assert(mDecodedWidth > 0);
+    assert(mDecodedHeight > 0);
+
+    sp<OverlayRef> ref = mISurface->createOverlay(
+            mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
+
+    if (ref.get() == NULL) {
+        LOGE("Unable to create the overlay!");
+        return;
+    }
+
+    mOverlay = new Overlay(ref);
+
+    for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) {
+        mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i));
+    }
+    mIndex = mOverlayAddresses.size() - 1;
+}
+
+TIHardwareRenderer::~TIHardwareRenderer() {
+    if (mOverlay.get() != NULL) {
+        mOverlay->destroy();
+        mOverlay.clear();
+
+        // XXX apparently destroying an overlay is an asynchronous process...
+        sleep(1);
+    }
+}
+
+void TIHardwareRenderer::render(
+        const void *data, size_t size, void *platformPrivate) {
+    // assert(size == mFrameSize);
+
+    if (mOverlay.get() == NULL) {
+        return;
+    }
+
+#if 0
+    overlay_buffer_t buffer;
+    if (mOverlay->dequeueBuffer(&buffer) == OK) {
+        void *addr = mOverlay->getBufferAddress(buffer);
+
+        memcpy(addr, data, size);
+
+        mOverlay->queueBuffer(buffer);
+    }
+#else
+    memcpy(mOverlayAddresses[mIndex], data, size);
+    mOverlay->queueBuffer((void *)mIndex);
+
+    if (mIndex-- == 0) {
+        mIndex = mOverlayAddresses.size() - 1;
+    }
+#endif
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/TimeSource.cpp b/media/libstagefright/TimeSource.cpp
new file mode 100644
index 0000000..d987fbf
--- /dev/null
+++ b/media/libstagefright/TimeSource.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 <stddef.h>
+#include <sys/time.h>
+
+#include <media/stagefright/TimeSource.h>
+
+namespace android {
+
+SystemTimeSource::SystemTimeSource()
+    : mStartTimeUs(GetSystemTimeUs()) {
+}
+
+int64_t SystemTimeSource::getRealTimeUs() {
+    return GetSystemTimeUs() - mStartTimeUs;
+}
+
+// static
+int64_t SystemTimeSource::GetSystemTimeUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
new file mode 100644
index 0000000..2f8a19f
--- /dev/null
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#define LOG_TAG "TimedEventQueue"
+#include <utils/Log.h>
+
+#include <sys/time.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TimedEventQueue.h>
+
+namespace android {
+
+TimedEventQueue::TimedEventQueue()
+    : mRunning(false),
+      mStopped(false) {
+}
+
+TimedEventQueue::~TimedEventQueue() {
+    stop();
+}
+
+void TimedEventQueue::start() {
+    if (mRunning) {
+        return;
+    }
+
+    mStopped = false;
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    pthread_create(&mThread, &attr, ThreadWrapper, this);
+
+    pthread_attr_destroy(&attr);
+
+    mRunning = true;
+}
+
+void TimedEventQueue::stop(bool flush) {
+    if (!mRunning) {
+        return;
+    }
+
+    if (flush) {
+        postEventToBack(new StopEvent);
+    } else {
+        postTimedEvent(new StopEvent, INT64_MIN);
+    }
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+
+    mQueue.clear();
+
+    mRunning = false;
+}
+
+void TimedEventQueue::postEvent(const sp<Event> &event) {
+    // Reserve an earlier timeslot an INT64_MIN to be able to post
+    // the StopEvent to the absolute head of the queue.
+    postTimedEvent(event, INT64_MIN + 1);
+}
+
+void TimedEventQueue::postEventToBack(const sp<Event> &event) {
+    postTimedEvent(event, INT64_MAX);
+}
+
+void TimedEventQueue::postEventWithDelay(
+        const sp<Event> &event, int64_t delay_us) {
+    assert(delay_us >= 0);
+    postTimedEvent(event, getRealTimeUs() + delay_us);
+}
+
+void TimedEventQueue::postTimedEvent(
+        const sp<Event> &event, int64_t realtime_us) {
+    Mutex::Autolock autoLock(mLock);
+
+    List<QueueItem>::iterator it = mQueue.begin();
+    while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
+        ++it;
+    }
+
+    QueueItem item;
+    item.event = event;
+    item.realtime_us = realtime_us;
+
+    if (it == mQueue.begin()) {
+        mQueueHeadChangedCondition.signal();
+    }
+
+    mQueue.insert(it, item);
+
+    mQueueNotEmptyCondition.signal();
+}
+
+bool TimedEventQueue::cancelEvent(const sp<Event> &event) {
+    Mutex::Autolock autoLock(mLock);
+
+    List<QueueItem>::iterator it = mQueue.begin();
+    while (it != mQueue.end() && (*it).event != event) {
+        ++it;
+    }
+
+    if (it == mQueue.end()) {
+        return false;
+    }
+
+    if (it == mQueue.begin()) {
+        mQueueHeadChangedCondition.signal();
+    }
+
+    mQueue.erase(it);
+
+    return true;
+}
+
+// static
+int64_t TimedEventQueue::getRealTimeUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+// static
+void *TimedEventQueue::ThreadWrapper(void *me) {
+    static_cast<TimedEventQueue *>(me)->threadEntry();
+
+    return NULL;
+}
+
+void TimedEventQueue::threadEntry() {
+    for (;;) {
+        int64_t now_us;
+        sp<Event> event;
+
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            if (mStopped) {
+                break;
+            }
+
+            while (mQueue.empty()) {
+                mQueueNotEmptyCondition.wait(mLock);
+            }
+
+            List<QueueItem>::iterator it;
+            for (;;) {
+                it = mQueue.begin();
+
+                now_us = getRealTimeUs();
+                int64_t when_us = (*it).realtime_us;
+
+                int64_t delay_us;
+                if (when_us < 0 || when_us == INT64_MAX) {
+                    delay_us = 0;
+                } else {
+                    delay_us = when_us - now_us;
+                }
+
+                if (delay_us <= 0) {
+                    break;
+                }
+
+                status_t err = mQueueHeadChangedCondition.waitRelative(
+                        mLock, delay_us * 1000);
+
+                if (err == -ETIMEDOUT) {
+                    now_us = getRealTimeUs();
+                    break;
+                }
+            }
+
+            event = (*it).event;
+            mQueue.erase(it);
+        }
+
+        // Fire event with the lock NOT held.
+        event->fire(this, now_us);
+    }
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
new file mode 100644
index 0000000..2720f93
--- /dev/null
+++ b/media/libstagefright/Utils.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 <arpa/inet.h>
+
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+uint16_t U16_AT(const uint8_t *ptr) {
+    return ptr[0] << 8 | ptr[1];
+}
+
+uint32_t U32_AT(const uint8_t *ptr) {
+    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+uint64_t U64_AT(const uint8_t *ptr) {
+    return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
+}
+
+// XXX warning: these won't work on big-endian host.
+uint64_t ntoh64(uint64_t x) {
+    return ((uint64_t)ntohl(x & 0xffffffff) << 32) | ntohl(x >> 32);
+}
+
+uint64_t hton64(uint64_t x) {
+    return ((uint64_t)htonl(x & 0xffffffff) << 32) | htonl(x >> 32);
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
new file mode 100644
index 0000000..9c6d475
--- /dev/null
+++ b/media/libstagefright/omx/Android.mk
@@ -0,0 +1,27 @@
+ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# Set up the OpenCore variables.
+include external/opencore/Config.mk
+LOCAL_C_INCLUDES := $(PV_INCLUDES)
+LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
+
+LOCAL_SRC_FILES:=                 \
+	OMX.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+        libbinder         \
+        libmedia          \
+	libutils          \
+        libui             \
+        libopencore_common
+
+LOCAL_PRELINK_MODULE:= false
+
+LOCAL_MODULE:= libstagefright_omx
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
new file mode 100644
index 0000000..daaa741
--- /dev/null
+++ b/media/libstagefright/omx/OMX.cpp
@@ -0,0 +1,623 @@
+/*
+ * 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 "OMX"
+#include <utils/Log.h>
+
+#include <sys/socket.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include "OMX.h"
+#include "pv_omxcore.h"
+
+#include <binder/IMemory.h>
+
+#include <OMX_Component.h>
+
+namespace android {
+
+class NodeMeta {
+public:
+    NodeMeta(OMX *owner)
+        : mOwner(owner),
+          mHandle(NULL) {
+    }
+
+    OMX *owner() const {
+        return mOwner;
+    }
+
+    void setHandle(OMX_HANDLETYPE handle) {
+        assert(mHandle == NULL);
+        mHandle = handle;
+    }
+
+    OMX_HANDLETYPE handle() const {
+        return mHandle;
+    }
+
+    void setObserver(const sp<IOMXObserver> &observer) {
+        mObserver = observer;
+    }
+
+    sp<IOMXObserver> observer() {
+        return mObserver;
+    }
+
+private:
+    OMX *mOwner;
+    OMX_HANDLETYPE mHandle;
+    sp<IOMXObserver> mObserver;
+
+    NodeMeta(const NodeMeta &);
+    NodeMeta &operator=(const NodeMeta &);
+};
+
+class BufferMeta {
+public:
+    BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
+        : mOwner(owner),
+          mMem(mem),
+          mIsBackup(is_backup) {
+    }
+
+    BufferMeta(OMX *owner, size_t size)
+        : mOwner(owner),
+          mSize(size),
+          mIsBackup(false) {
+    }
+
+    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
+        if (!mIsBackup) {
+            return;
+        }
+
+        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
+               header->pBuffer + header->nOffset,
+               header->nFilledLen);
+    }
+
+    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
+        if (!mIsBackup) {
+            return;
+        }
+
+        memcpy(header->pBuffer + header->nOffset,
+               (const OMX_U8 *)mMem->pointer() + header->nOffset,
+               header->nFilledLen);
+    }
+
+private:
+    OMX *mOwner;
+    sp<IMemory> mMem;
+    size_t mSize;
+    bool mIsBackup;
+
+    BufferMeta(const BufferMeta &);
+    BufferMeta &operator=(const BufferMeta &);
+};
+
+// static
+OMX_CALLBACKTYPE OMX::kCallbacks = {
+    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
+};
+
+// static
+OMX_ERRORTYPE OMX::OnEvent(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_EVENTTYPE eEvent,
+        OMX_IN OMX_U32 nData1,
+        OMX_IN OMX_U32 nData2,
+        OMX_IN OMX_PTR pEventData) {
+    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+    return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData);
+}
+
+// static
+OMX_ERRORTYPE OMX::OnEmptyBufferDone(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+    return meta->owner()->OnEmptyBufferDone(meta, pBuffer);
+}
+
+// static
+OMX_ERRORTYPE OMX::OnFillBufferDone(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+    return meta->owner()->OnFillBufferDone(meta, pBuffer);
+}
+
+OMX::OMX()
+#if IOMX_USES_SOCKETS
+    : mSock(-1)
+#endif
+{
+}
+
+OMX::~OMX() {
+#if IOMX_USES_SOCKETS
+    assert(mSock < 0);
+#endif
+}
+
+#if IOMX_USES_SOCKETS
+status_t OMX::connect(int *sd) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mSock >= 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    int sockets[2];
+    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    mSock = sockets[0];
+    *sd = sockets[1];
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
+    assert(err == 0);
+
+    pthread_attr_destroy(&attr);
+
+    return OK;
+}
+
+// static
+void *OMX::ThreadWrapper(void *me) {
+    ((OMX *)me)->threadEntry();
+
+    return NULL;
+}
+
+void OMX::threadEntry() {
+    bool done = false;
+    while (!done) {
+        omx_message msg;
+        ssize_t n = recv(mSock, &msg, sizeof(msg), 0);
+
+        if (n <= 0) {
+            break;
+        }
+
+        Mutex::Autolock autoLock(mLock);
+
+        switch (msg.type) {
+            case omx_message::FILL_BUFFER:
+            {
+                OMX_BUFFERHEADERTYPE *header =
+                    static_cast<OMX_BUFFERHEADERTYPE *>(
+                            msg.u.buffer_data.buffer);
+
+                header->nFilledLen = 0;
+                header->nOffset = 0;
+                header->hMarkTargetComponent = NULL;
+                header->nFlags = 0;
+
+                NodeMeta *node_meta = static_cast<NodeMeta *>(
+                        msg.u.buffer_data.node);
+                
+                LOGV("FillThisBuffer buffer=%p", header);
+
+                OMX_ERRORTYPE err =
+                    OMX_FillThisBuffer(node_meta->handle(), header);
+                assert(err == OMX_ErrorNone);
+                break;
+            }
+
+            case omx_message::EMPTY_BUFFER:
+            {
+                OMX_BUFFERHEADERTYPE *header =
+                    static_cast<OMX_BUFFERHEADERTYPE *>(
+                            msg.u.extended_buffer_data.buffer);
+
+                header->nFilledLen = msg.u.extended_buffer_data.range_length;
+                header->nOffset = msg.u.extended_buffer_data.range_offset;
+                header->hMarkTargetComponent = NULL;
+                header->nFlags = msg.u.extended_buffer_data.flags;
+                header->nTimeStamp = msg.u.extended_buffer_data.timestamp;
+
+                BufferMeta *buffer_meta =
+                    static_cast<BufferMeta *>(header->pAppPrivate);
+                buffer_meta->CopyToOMX(header);
+
+                NodeMeta *node_meta = static_cast<NodeMeta *>(
+                        msg.u.extended_buffer_data.node);
+
+                LOGV("EmptyThisBuffer buffer=%p", header);
+
+                OMX_ERRORTYPE err =
+                    OMX_EmptyThisBuffer(node_meta->handle(), header);
+                assert(err == OMX_ErrorNone);
+                break;
+            }
+
+            case omx_message::SEND_COMMAND:
+            {
+                NodeMeta *node_meta = static_cast<NodeMeta *>(
+                        msg.u.send_command_data.node);
+
+                OMX_ERRORTYPE err =
+                    OMX_SendCommand(
+                            node_meta->handle(), msg.u.send_command_data.cmd,
+                            msg.u.send_command_data.param, NULL);
+                assert(err == OMX_ErrorNone);
+                break;
+            }
+
+            case omx_message::DISCONNECT:
+            {
+                omx_message msg;
+                msg.type = omx_message::DISCONNECTED;
+                ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+                assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+                done = true;
+                break;
+            }
+
+            default:
+                LOGE("received unknown omx_message type %d", msg.type);
+                break;
+        }
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    close(mSock);
+    mSock = -1;
+}
+#endif
+
+status_t OMX::list_nodes(List<String8> *list) {
+    OMX_MasterInit();  // XXX Put this somewhere else.
+
+    list->clear();
+
+    OMX_U32 index = 0;
+    char componentName[256];
+    while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
+               == OMX_ErrorNone) {
+        list->push_back(String8(componentName));
+
+        ++index;
+    }
+
+    return OK;
+}
+
+status_t OMX::allocate_node(const char *name, node_id *node) {
+    Mutex::Autolock autoLock(mLock);
+
+    *node = 0;
+
+    OMX_MasterInit();  // XXX Put this somewhere else.
+
+    NodeMeta *meta = new NodeMeta(this);
+
+    OMX_HANDLETYPE handle;
+    OMX_ERRORTYPE err = OMX_MasterGetHandle(
+            &handle, const_cast<char *>(name), meta, &kCallbacks);
+
+    if (err != OMX_ErrorNone) {
+        LOGE("FAILED to allocate omx component '%s'", name);
+
+        delete meta;
+        meta = NULL;
+
+        return UNKNOWN_ERROR;
+    }
+
+    meta->setHandle(handle);
+
+    *node = meta;
+
+    return OK;
+}
+
+status_t OMX::free_node(node_id node) {
+    Mutex::Autolock autoLock(mLock);
+
+    NodeMeta *meta = static_cast<NodeMeta *>(node);
+
+    OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
+
+    delete meta;
+    meta = NULL;
+
+    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::send_command(
+        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    Mutex::Autolock autoLock(mLock);
+
+#if IOMX_USES_SOCKETS
+    if (mSock < 0) {
+        return UNKNOWN_ERROR;
+    }
+#endif
+
+    NodeMeta *meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
+
+    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::get_parameter(
+        node_id node, OMX_INDEXTYPE index,
+        void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    NodeMeta *meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params);
+
+    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::set_parameter(
+        node_id node, OMX_INDEXTYPE index,
+        const void *params, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    NodeMeta *meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err =
+        OMX_SetParameter(meta->handle(), index, const_cast<void *>(params));
+
+    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::use_buffer(
+        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+        buffer_id *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    BufferMeta *buffer_meta = new BufferMeta(this, params);
+
+    OMX_BUFFERHEADERTYPE *header;
+
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err =
+        OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
+                      params->size(), static_cast<OMX_U8 *>(params->pointer()));
+
+    if (err != OMX_ErrorNone) {
+        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
+
+        delete buffer_meta;
+        buffer_meta = NULL;
+
+        *buffer = 0;
+        return UNKNOWN_ERROR;
+    }
+
+    *buffer = header;
+
+    return OK;
+}
+
+status_t OMX::allocate_buffer(
+        node_id node, OMX_U32 port_index, size_t size,
+        buffer_id *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    BufferMeta *buffer_meta = new BufferMeta(this, size);
+
+    OMX_BUFFERHEADERTYPE *header;
+
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err =
+        OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
+                           buffer_meta, size);
+
+    if (err != OMX_ErrorNone) {
+        delete buffer_meta;
+        buffer_meta = NULL;
+
+        *buffer = 0;
+        return UNKNOWN_ERROR;
+    }
+
+    *buffer = header;
+
+    return OK;
+}
+
+status_t OMX::allocate_buffer_with_backup(
+        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+        buffer_id *buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    BufferMeta *buffer_meta = new BufferMeta(this, params, true);
+
+    OMX_BUFFERHEADERTYPE *header;
+
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err =
+        OMX_AllocateBuffer(
+                node_meta->handle(), &header, port_index, buffer_meta,
+                params->size());
+
+    if (err != OMX_ErrorNone) {
+        delete buffer_meta;
+        buffer_meta = NULL;
+
+        *buffer = 0;
+        return UNKNOWN_ERROR;
+    }
+
+    *buffer = header;
+
+    return OK;
+}
+
+status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
+    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
+
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+    OMX_ERRORTYPE err =
+        OMX_FreeBuffer(node_meta->handle(), port_index, header);
+
+    delete buffer_meta;
+    buffer_meta = NULL;
+
+    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+OMX_ERRORTYPE OMX::OnEvent(
+        NodeMeta *meta,
+        OMX_IN OMX_EVENTTYPE eEvent,
+        OMX_IN OMX_U32 nData1,
+        OMX_IN OMX_U32 nData2,
+        OMX_IN OMX_PTR pEventData) {
+    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
+
+    omx_message msg;
+    msg.type = omx_message::EVENT;
+    msg.u.event_data.node = meta;
+    msg.u.event_data.event = eEvent;
+    msg.u.event_data.data1 = nData1;
+    msg.u.event_data.data2 = nData2;
+
+#if !IOMX_USES_SOCKETS
+    sp<IOMXObserver> observer = meta->observer();
+    if (observer.get() != NULL) {
+        observer->on_message(msg);
+    }
+#else
+    assert(mSock >= 0);
+
+    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+#endif
+
+    return OMX_ErrorNone;
+}
+    
+OMX_ERRORTYPE OMX::OnEmptyBufferDone(
+        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
+
+    omx_message msg;
+    msg.type = omx_message::EMPTY_BUFFER_DONE;
+    msg.u.buffer_data.node = meta;
+    msg.u.buffer_data.buffer = pBuffer;
+
+#if !IOMX_USES_SOCKETS
+    sp<IOMXObserver> observer = meta->observer();
+    if (observer.get() != NULL) {
+        observer->on_message(msg);
+    }
+#else
+    assert(mSock >= 0);
+    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+#endif
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE OMX::OnFillBufferDone(
+        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+    LOGV("OnFillBufferDone buffer=%p", pBuffer);
+    BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
+    buffer_meta->CopyFromOMX(pBuffer);
+
+    omx_message msg;
+    msg.type = omx_message::FILL_BUFFER_DONE;
+    msg.u.extended_buffer_data.node = meta;
+    msg.u.extended_buffer_data.buffer = pBuffer;
+    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
+    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
+    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
+    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
+    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
+
+#if !IOMX_USES_SOCKETS
+    sp<IOMXObserver> observer = meta->observer();
+    if (observer.get() != NULL) {
+        observer->on_message(msg);
+    }
+#else
+    assert(mSock >= 0);
+
+    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
+    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
+#endif
+
+    return OMX_ErrorNone;
+}
+
+#if !IOMX_USES_SOCKETS
+status_t OMX::observe_node(
+        node_id node, const sp<IOMXObserver> &observer) {
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+    node_meta->setObserver(observer);
+
+    return OK;
+}
+
+void OMX::fill_buffer(node_id node, buffer_id buffer) {
+    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    header->nFilledLen = 0;
+    header->nOffset = 0;
+    header->nFlags = 0;
+
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+    OMX_ERRORTYPE err =
+        OMX_FillThisBuffer(node_meta->handle(), header);
+    assert(err == OMX_ErrorNone);
+}
+
+void OMX::empty_buffer(
+        node_id node,
+        buffer_id buffer,
+        OMX_U32 range_offset, OMX_U32 range_length,
+        OMX_U32 flags, OMX_TICKS timestamp) {
+    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    header->nFilledLen = range_length;
+    header->nOffset = range_offset;
+    header->nFlags = flags;
+    header->nTimeStamp = timestamp;
+
+    BufferMeta *buffer_meta =
+        static_cast<BufferMeta *>(header->pAppPrivate);
+    buffer_meta->CopyToOMX(header);
+
+    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+    OMX_ERRORTYPE err =
+        OMX_EmptyThisBuffer(node_meta->handle(), header);
+    assert(err == OMX_ErrorNone);
+}
+#endif
+
+}  // namespace android
+
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h
new file mode 100644
index 0000000..ed4e5dd
--- /dev/null
+++ b/media/libstagefright/omx/OMX.h
@@ -0,0 +1,132 @@
+/*
+ * 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 ANDROID_OMX_H_
+#define ANDROID_OMX_H_
+
+#include <pthread.h>
+
+#include <media/IOMX.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class NodeMeta;
+
+class OMX : public BnOMX {
+public:
+    OMX();
+    virtual ~OMX();
+
+#if IOMX_USES_SOCKETS
+    virtual status_t connect(int *sd);
+#endif
+
+    virtual status_t list_nodes(List<String8> *list);
+
+    virtual status_t allocate_node(const char *name, node_id *node);
+    virtual status_t free_node(node_id node);
+
+    virtual status_t send_command(
+            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
+
+    virtual status_t get_parameter(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size);
+
+    virtual status_t set_parameter(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size);
+
+    virtual status_t use_buffer(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer);
+
+    virtual status_t allocate_buffer(
+            node_id node, OMX_U32 port_index, size_t size,
+            buffer_id *buffer);
+
+    virtual status_t allocate_buffer_with_backup(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer);
+
+    virtual status_t free_buffer(
+            node_id node, OMX_U32 port_index, buffer_id buffer);
+
+#if !IOMX_USES_SOCKETS
+    virtual status_t observe_node(
+            node_id node, const sp<IOMXObserver> &observer);
+
+    virtual void fill_buffer(node_id node, buffer_id buffer);
+
+    virtual void empty_buffer(
+            node_id node,
+            buffer_id buffer,
+            OMX_U32 range_offset, OMX_U32 range_length,
+            OMX_U32 flags, OMX_TICKS timestamp);
+#endif
+
+private:
+    static OMX_CALLBACKTYPE kCallbacks;
+
+#if IOMX_USES_SOCKETS
+    int mSock;
+    pthread_t mThread;
+
+    static void *ThreadWrapper(void *me);
+    void threadEntry();
+#endif
+
+    Mutex mLock;
+
+    static OMX_ERRORTYPE OnEvent(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_IN OMX_PTR pAppData,
+            OMX_IN OMX_EVENTTYPE eEvent,
+            OMX_IN OMX_U32 nData1,
+            OMX_IN OMX_U32 nData2,
+            OMX_IN OMX_PTR pEventData);
+
+    static OMX_ERRORTYPE OnEmptyBufferDone(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_IN OMX_PTR pAppData,
+            OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+    static OMX_ERRORTYPE OnFillBufferDone(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_IN OMX_PTR pAppData,
+            OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+    OMX_ERRORTYPE OnEvent(
+            NodeMeta *meta,
+            OMX_IN OMX_EVENTTYPE eEvent,
+            OMX_IN OMX_U32 nData1,
+            OMX_IN OMX_U32 nData2,
+            OMX_IN OMX_PTR pEventData);
+        
+    OMX_ERRORTYPE OnEmptyBufferDone(
+            NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+    OMX_ERRORTYPE OnFillBufferDone(
+            NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+    OMX(const OMX &);
+    OMX &operator=(const OMX &);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_OMX_H_
diff --git a/media/libstagefright/string.cpp b/media/libstagefright/string.cpp
new file mode 100644
index 0000000..5b16784
--- /dev/null
+++ b/media/libstagefright/string.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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/string.h>
+
+namespace android {
+
+// static
+string::size_type string::npos = (string::size_type)-1;
+
+string::string() {
+}
+
+string::string(const char *s, size_t length)
+    : mString(s, length) {
+}
+
+string::string(const string &from, size_type start, size_type length)
+    : mString(from.c_str() + start, length) {
+}
+
+string::string(const char *s)
+    : mString(s) {
+}
+
+const char *string::c_str() const {
+    return mString.string();
+}
+
+string::size_type string::size() const {
+    return mString.length();
+}
+
+void string::clear() {
+    mString = String8();
+}
+
+string::size_type string::find(char c) const {
+    char s[2];
+    s[0] = c;
+    s[1] = '\0';
+
+    ssize_t index = mString.find(s);
+
+    return index < 0 ? npos : (size_type)index;
+}
+
+bool string::operator<(const string &other) const {
+    return mString < other.mString;
+}
+
+bool string::operator==(const string &other) const {
+    return mString == other.mString;
+}
+
+string &string::operator+=(char c) {
+    mString.append(&c, 1);
+
+    return *this;
+}
+
+void string::erase(size_t from, size_t length) {
+    String8 s(mString.string(), from);
+    s.append(mString.string() + from + length);
+    
+    mString = s;
+}
+
+}  // namespace android
+
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index c681698..a92cea8 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -8,7 +8,8 @@
 	libaudioflinger \
 	libcameraservice \
 	libmediaplayerservice \
-	libutils
+	libutils \
+	libbinder
 
 base := $(LOCAL_PATH)/../..
 
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 6954b63..7094cfa 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -20,14 +20,15 @@
 #include <unistd.h>
 #include <grp.h>
 
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
 #include <utils/Log.h>
 
 #include <AudioFlinger.h>
 #include <CameraService.h>
 #include <MediaPlayerService.h>
+#include <AudioPolicyService.h>
 #include <private/android_filesystem_config.h>
 
 using namespace android;
@@ -40,6 +41,7 @@
     AudioFlinger::instantiate();
     MediaPlayerService::instantiate();
     CameraService::instantiate();
+    AudioPolicyService::instantiate();
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
 }