Merge "stagefright: rework MediaCodecSource" into nyc-dev
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 7d75108..e5fbba0 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -9,7 +9,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia libutils libbinder libstagefright_foundation \
-        libjpeg libgui libcutils liblog libui
+	libjpeg libgui libcutils liblog
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -31,8 +31,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-        SineSource.cpp    \
-        record.cpp
+	SineSource.cpp    \
+	record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
@@ -55,8 +55,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-        SineSource.cpp    \
-        recordvideo.cpp
+	SineSource.cpp    \
+	recordvideo.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
@@ -80,8 +80,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-        SineSource.cpp    \
-        audioloop.cpp
+	SineSource.cpp    \
+	audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
@@ -108,7 +108,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright liblog libutils libbinder libgui \
-        libstagefright_foundation libmedia libcutils
+	libstagefright_foundation libmedia libcutils
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -128,11 +128,11 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-        sf2.cpp    \
+	sf2.cpp    \
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright liblog libutils libbinder libstagefright_foundation \
-        libmedia libgui libcutils libui
+	libmedia libgui libcutils libui
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -152,12 +152,12 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-        codec.cpp               \
-        SimplePlayer.cpp        \
+	codec.cpp               \
+	SimplePlayer.cpp        \
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright liblog libutils libbinder libstagefright_foundation \
-        libmedia libgui libcutils libui
+	libmedia libgui libcutils libui
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -220,11 +220,11 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-        muxer.cpp            \
+	muxer.cpp            \
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright liblog libutils libbinder libstagefright_foundation \
-        libmedia libgui libcutils libui libc
+	libmedia libgui libcutils libui libc
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index db0c12d..ed44b4d 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -23,13 +23,14 @@
 #include <binder/ProcessState.h>
 #include <media/mediarecorder.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/AudioSource.h>
+#include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SimpleDecodingSource.h>
 #include "SineSource.h"
 
 using namespace android;
@@ -79,8 +80,6 @@
     const int32_t kBitRate = outputWBAMR ? 16000 : 8000;
 
     android::ProcessState::self()->startThreadPool();
-    OMXClient client;
-    CHECK_EQ(client.connect(), (status_t)OK);
     sp<MediaSource> source;
 
     if (useMic) {
@@ -95,24 +94,25 @@
         source = new SineSource(kSampleRate, channels);
     }
 
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(
-            kKeyMIMEType,
+    sp<AMessage> meta = new AMessage;
+    meta->setString(
+            "mime",
             outputWBAMR ? MEDIA_MIMETYPE_AUDIO_AMR_WB
                     : MEDIA_MIMETYPE_AUDIO_AMR_NB);
 
-    meta->setInt32(kKeyChannelCount, channels);
-    meta->setInt32(kKeySampleRate, kSampleRate);
-    meta->setInt32(kKeyBitRate, kBitRate);
+    meta->setInt32("channel-count", channels);
+    meta->setInt32("sample-rate", kSampleRate);
+    meta->setInt32("bitrate", kBitRate);
     int32_t maxInputSize;
     if (source->getFormat()->findInt32(kKeyMaxInputSize, &maxInputSize)) {
-        meta->setInt32(kKeyMaxInputSize, maxInputSize);
+        meta->setInt32("max-input-size", maxInputSize);
     }
 
-    sp<IMediaSource> encoder = OMXCodec::Create(
-            client.interface(),
-            meta, true /* createEncoder */,
-            source);
+    sp<ALooper> looper = new ALooper;
+    looper->setName("audioloop");
+    looper->start();
+
+    sp<IMediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
 
     if (fileOut != NULL) {
         // target file specified, write encoded AMR output
@@ -128,17 +128,15 @@
         writer->stop();
     } else {
         // otherwise decode to speaker
-        sp<IMediaSource> decoder = OMXCodec::Create(
-                client.interface(),
-                meta, false /* createEncoder */,
-                encoder);
+        sp<IMediaSource> decoder = SimpleDecodingSource::Create(encoder);
 
         if (playToSpeaker) {
             AudioPlayer *player = new AudioPlayer(NULL);
             player->setSource(decoder);
             player->start();
             sleep(duration);
-            source->stop(); // must stop source otherwise delete player will hang
+
+            decoder.clear(); // must clear |decoder| otherwise delete player will hang.
             delete player; // there is no player->stop()...
         } else {
             CHECK_EQ(decoder->start(), (status_t)OK);
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index cd9c8dc..f8b2f68 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -18,16 +18,18 @@
 
 #include <binder/ProcessState.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SimpleDecodingSource.h>
 #include <media/MediaPlayerInterface.h>
 
 using namespace android;
@@ -182,9 +184,6 @@
         fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n");
         return 1;
     }
-    OMXClient client;
-    CHECK_EQ(client.connect(), (status_t)OK);
-
     status_t err = OK;
 
 #if 0
@@ -197,8 +196,7 @@
 
     sp<MetaData> meta = source->getFormat();
 
-    sp<MediaSource> decoder = OMXCodec::Create(
-            client.interface(), meta, false /* createEncoder */, source);
+    sp<MediaSource> decoder = SimpleDecodingSource::Create(source);
 
     int width, height;
     bool success = meta->findInt32(kKeyWidth, &width);
@@ -210,22 +208,21 @@
     sp<MediaSource> decoder = new DummySource(width, height, colorFormat);
 #endif
 
-    sp<MetaData> enc_meta = new MetaData;
-    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
-    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
-    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-    enc_meta->setInt32(kKeyWidth, width);
-    enc_meta->setInt32(kKeyHeight, height);
-    enc_meta->setInt32(kKeySampleRate, kFramerate);
-    enc_meta->setInt32(kKeyBitRate, kVideoBitRate);
-    enc_meta->setInt32(kKeyStride, width);
-    enc_meta->setInt32(kKeySliceHeight, height);
-    enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec);
-    enc_meta->setInt32(kKeyColorFormat, colorFormat);
+    sp<AMessage> enc_meta = new AMessage;
+    // enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
+    // enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
+    enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
+    enc_meta->setInt32("width", width);
+    enc_meta->setInt32("height", height);
+    enc_meta->setInt32("sample-rate", kFramerate);
+    enc_meta->setInt32("bit-rate", kVideoBitRate);
+    // enc_meta->setInt32("stride", width);
+    // enc_meta->setInt32("slice-height", height);
+    enc_meta->setInt32("i-frame-interval", kIFramesIntervalSec);
+    enc_meta->setInt32("color-format", colorFormat);
 
     sp<MediaSource> encoder =
-        OMXCodec::Create(
-                client.interface(), enc_meta, true /* createEncoder */, decoder);
+        MediaCodecSource::Create(looper, format, decoder);
 
 #if 1
     sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
@@ -260,7 +257,6 @@
 #endif
 
     printf("$\n");
-    client.disconnect();
 #endif
 
 #if 0
@@ -299,9 +295,6 @@
 int main(int /* argc */, char ** /* argv */) {
     android::ProcessState::self()->startThreadPool();
 
-    OMXClient client;
-    CHECK_EQ(client.connect(), (status_t)OK);
-
     const int32_t kSampleRate = 22050;
     const int32_t kNumChannels = 2;
     sp<MediaSource> audioSource = new SineSource(kSampleRate, kNumChannels);
@@ -317,16 +310,20 @@
     player->stop();
 #endif
 
-    sp<MetaData> encMeta = new MetaData;
-    encMeta->setCString(kKeyMIMEType,
+    sp<AMessage> encMeta = new AMessage;
+    encMeta->setString("mime",
             0 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
-    encMeta->setInt32(kKeySampleRate, kSampleRate);
-    encMeta->setInt32(kKeyChannelCount, kNumChannels);
-    encMeta->setInt32(kKeyMaxInputSize, 8192);
-    encMeta->setInt32(kKeyBitRate, kAudioBitRate);
+    encMeta->setInt32("sample-rate", kSampleRate);
+    encMeta->setInt32("channel-count", kNumChannels);
+    encMeta->setInt32("max-input-size", 8192);
+    encMeta->setInt32("bitrate", kAudioBitRate);
+
+    sp<ALooper> looper = new ALooper;
+    looper->setName("record");
+    looper->start();
 
     sp<IMediaSource> encoder =
-        OMXCodec::Create(client.interface(), encMeta, true, audioSource);
+        MediaCodecSource::Create(looper, encMeta, audioSource);
 
     encoder->start();
 
@@ -348,8 +345,6 @@
 
     encoder->stop();
 
-    client.disconnect();
-
     return 0;
 }
 #endif
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index 05b50be..7a3c842 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -23,15 +23,18 @@
 
 #include <binder/ProcessState.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
 #include <media/MediaPlayerInterface.h>
 
+#include <OMX_Video.h>
+
 using namespace android;
 
 // Print usage showing how to use this utility to record videos
@@ -265,44 +268,45 @@
         }
     }
 
-    OMXClient client;
-    CHECK_EQ(client.connect(), (status_t)OK);
-
     status_t err = OK;
     sp<MediaSource> source =
         new DummySource(width, height, nFrames, frameRateFps, colorFormat);
 
-    sp<MetaData> enc_meta = new MetaData;
+    sp<AMessage> enc_meta = new AMessage;
     switch (codec) {
         case 1:
-            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+            enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
             break;
         case 2:
-            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+            enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
             break;
         default:
-            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+            enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
             break;
     }
-    enc_meta->setInt32(kKeyWidth, width);
-    enc_meta->setInt32(kKeyHeight, height);
-    enc_meta->setInt32(kKeyFrameRate, frameRateFps);
-    enc_meta->setInt32(kKeyBitRate, bitRateBps);
-    enc_meta->setInt32(kKeyStride, width);
-    enc_meta->setInt32(kKeySliceHeight, height);
-    enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds);
-    enc_meta->setInt32(kKeyColorFormat, colorFormat);
+    enc_meta->setInt32("width", width);
+    enc_meta->setInt32("height", height);
+    enc_meta->setInt32("frame-rate", frameRateFps);
+    enc_meta->setInt32("bitrate", bitRateBps);
+    enc_meta->setInt32("stride", width);
+    enc_meta->setInt32("slice-height", height);
+    enc_meta->setInt32("i-frame-interval", iFramesIntervalSeconds);
+    enc_meta->setInt32("color-format", colorFormat);
     if (level != -1) {
-        enc_meta->setInt32(kKeyVideoLevel, level);
+        enc_meta->setInt32("level", level);
     }
     if (profile != -1) {
-        enc_meta->setInt32(kKeyVideoProfile, profile);
+        enc_meta->setInt32("profile", profile);
     }
 
+    sp<ALooper> looper = new ALooper;
+    looper->setName("recordvideo");
+    looper->start();
+
     sp<IMediaSource> encoder =
-        OMXCodec::Create(
-                client.interface(), enc_meta, true /* createEncoder */, source,
-                0, preferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
+        MediaCodecSource::Create(
+                looper, enc_meta, source, NULL /* consumer */,
+                preferSoftwareCodec ? MediaCodecSource::FLAG_PREFER_SOFTWARE_CODEC : 0);
 
     int fd = open(fileName, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
     if (fd < 0) {
@@ -321,7 +325,6 @@
     int64_t end = systemTime();
 
     fprintf(stderr, "$\n");
-    client.disconnect();
 
     if (err != OK && err != ERROR_END_OF_STREAM) {
         fprintf(stderr, "record failed: %d\n", err);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 9537daa..eacb32e 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,20 +31,26 @@
 
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
 #include "include/NuCachedSource2.h"
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <media/stagefright/Utils.h>
 #include <media/mediametadataretriever.h>
 
 #include <media/stagefright/foundation/hexdump.h>
@@ -164,7 +170,7 @@
     out = NULL;
 }
 
-static void playSource(OMXClient *client, sp<IMediaSource> &source) {
+static void playSource(sp<IMediaSource> &source) {
     sp<MetaData> meta = source->getFormat();
 
     const char *mime;
@@ -176,20 +182,14 @@
     } else {
         int flags = 0;
         if (gPreferSoftwareCodec) {
-            flags |= OMXCodec::kPreferSoftwareCodecs;
+            flags |= MediaCodecList::kPreferSoftwareCodecs;
         }
         if (gForceToUseHardwareCodec) {
             CHECK(!gPreferSoftwareCodec);
-            flags |= OMXCodec::kHardwareCodecsOnly;
+            flags |= MediaCodecList::kHardwareCodecsOnly;
         }
-        rawSource = OMXCodec::Create(
-            client->interface(), meta, false /* createEncoder */, source,
-            NULL /* matchComponentName */,
-            flags,
-            gSurface);
-
+        rawSource = SimpleDecodingSource::Create(source, flags, gSurface);
         if (rawSource == NULL) {
-            fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
             return;
         }
         displayAVCProfileLevelIfPossible(meta);
@@ -343,12 +343,6 @@
                     printf(".");
                     fflush(stdout);
                 }
-
-                // render buffers from OMXCodec
-                if (buffer->graphicBuffer() != NULL && gSurface != NULL) {
-                    gSurface->queueBuffer(gSurface.get(), buffer->graphicBuffer()->getNativeBuffer(), -1);
-                    buffer->meta_data()->setInt32(kKeyRendered, 1);
-                }
             }
 
             sumDecodeUs += delayDecodeUs;
@@ -628,7 +622,7 @@
     fprintf(stderr, "       -D(ump) output_filename (decoded PCM data to a file)\n");
 }
 
-static void dumpCodecProfiles(const sp<IOMX>& omx, bool queryDecoders) {
+static void dumpCodecProfiles(bool queryDecoders) {
     const char *kMimeTypes[] = {
         MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
         MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
@@ -642,30 +636,36 @@
     const char *codecType = queryDecoders? "decoder" : "encoder";
     printf("%s profiles:\n", codecType);
 
+    sp<IMediaCodecList> list = MediaCodecList::getInstance();
+    size_t numCodecs = list->countCodecs();
+
     for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++k) {
         printf("type '%s':\n", kMimeTypes[k]);
 
-        Vector<CodecCapabilities> results;
-        // will retrieve hardware and software codecs
-        CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
-                             queryDecoders,
-                             &results), (status_t)OK);
-
-        for (size_t i = 0; i < results.size(); ++i) {
+        for (size_t index = 0; index < numCodecs; ++index) {
+            sp<MediaCodecInfo> info = list->getCodecInfo(index);
+            if (info == NULL || info->isEncoder() != !queryDecoders) {
+                continue;
+            }
+            sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(kMimeTypes[k]);
+            if (caps == NULL) {
+                continue;
+            }
             printf("  %s '%s' supports ",
-                       codecType, results[i].mComponentName.string());
+                       codecType, info->getCodecName());
 
-            if (results[i].mProfileLevels.size() == 0) {
-                    printf("NOTHING.\n");
-                    continue;
+            Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+            caps->getSupportedProfileLevels(&profileLevels);
+            if (profileLevels.size() == 0) {
+                printf("NOTHING.\n");
+                continue;
             }
 
-            for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) {
-                const CodecProfileLevel &profileLevel =
-                     results[i].mProfileLevels[j];
+            for (size_t j = 0; j < profileLevels.size(); ++j) {
+                const MediaCodecInfo::ProfileLevel &profileLevel = profileLevels[j];
 
-                printf("%s%" PRIu32 "/%" PRIu32, j > 0 ? ", " : "",
-                    profileLevel.mProfile, profileLevel.mLevel);
+                printf("%s%u/%u", j > 0 ? ", " : "",
+                        profileLevel.mProfile, profileLevel.mLevel);
             }
 
             printf("\n");
@@ -898,17 +898,8 @@
     }
 
     if (dumpProfiles) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder = sm->getService(String16("media.player"));
-        sp<IMediaPlayerService> service =
-            interface_cast<IMediaPlayerService>(binder);
-
-        CHECK(service.get() != NULL);
-
-        sp<IOMX> omx = service->getOMX();
-        CHECK(omx.get() != NULL);
-        dumpCodecProfiles(omx, true /* queryDecoders */);
-        dumpCodecProfiles(omx, false /* queryDecoders */);
+        dumpCodecProfiles(true /* queryDecoders */);
+        dumpCodecProfiles(false /* queryDecoders */);
     }
 
     if (listComponents) {
@@ -971,16 +962,11 @@
                     false /* isControlledByApp */);
             gSurface = new Surface(producer);
         }
-
-        CHECK_EQ((status_t)OK,
-                 native_window_api_connect(
-                     gSurface.get(), NATIVE_WINDOW_API_MEDIA));
     }
 
     DataSource::RegisterDefaultSniffers();
 
-    OMXClient client;
-    status_t err = client.connect();
+    status_t err = OK;
 
     for (int k = 0; k < argc && err == OK; ++k) {
         bool syncInfoPresent = true;
@@ -1120,31 +1106,16 @@
         } else if (dumpStream) {
             dumpSource(mediaSource, dumpStreamFilename);
         } else if (dumpPCMStream) {
-            OMXClient client;
-            CHECK_EQ(client.connect(), (status_t)OK);
-
-            sp<IMediaSource> decSource =
-                OMXCodec::Create(
-                        client.interface(),
-                        mediaSource->getFormat(),
-                        false,
-                        mediaSource,
-                        0,
-                        0);
-
+            sp<IMediaSource> decSource = SimpleDecodingSource::Create(mediaSource);
             dumpSource(decSource, dumpStreamFilename);
         } else if (seekTest) {
             performSeekTest(mediaSource);
         } else {
-            playSource(&client, mediaSource);
+            playSource(mediaSource);
         }
     }
 
     if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) {
-        CHECK_EQ((status_t)OK,
-                 native_window_api_disconnect(
-                     gSurface.get(), NATIVE_WINDOW_API_MEDIA));
-
         gSurface.clear();
 
         if (useSurfaceAlloc) {
@@ -1152,7 +1123,5 @@
         }
     }
 
-    client.disconnect();
-
     return 0;
 }
diff --git a/include/media/stagefright/SimpleDecodingSource.h b/include/media/stagefright/SimpleDecodingSource.h
new file mode 100644
index 0000000..6bd82c4
--- /dev/null
+++ b/include/media/stagefright/SimpleDecodingSource.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016, 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 SIMPLE_DECODING_SOURCE_H_
+#define SIMPLE_DECODING_SOURCE_H_
+
+#include <system/window.h>
+
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/Mutexed.h>
+
+#include <utils/Condition.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct ALooper;
+struct AMessage;
+class MediaBuffer;
+struct MediaCodec;
+class MetaData;
+
+class SimpleDecodingSource : public MediaSource {
+public:
+    // Creates a MediaSource that uses MediaCodec to decode a compressed input |source|.
+    // The selected codec can be influenced using |flags|. This source only supports the
+    // kPreferGoogleCodec and kNonGoogleCodecsOnly |flags| - MediaCodecList.
+    // You can pass in a target |nativeWindow| to render video directly onto a surface. In this
+    // case the source will return empty buffers.
+    // This source cannot be restarted (hence the name "Simple"), all reads are blocking, and
+    // does not support secure input or pausing.
+    static sp<SimpleDecodingSource> Create(
+            const sp<IMediaSource> &source, uint32_t flags = 0,
+            const sp<ANativeWindow> &nativeWindow = NULL);
+
+    virtual ~SimpleDecodingSource();
+
+    // starts this source (and it's underlying source). |params| is ignored.
+    virtual status_t start(MetaData *params = NULL);
+
+    // stops this source (and it's underlying source).
+    virtual status_t stop();
+
+    // returns the output format of this source.
+    virtual sp<MetaData> getFormat();
+
+    // reads from the source. This call always blocks.
+    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options);
+
+    // unsupported methods
+    virtual status_t pause() { return INVALID_OPERATION; }
+    virtual status_t setBuffers(const Vector<MediaBuffer *> &) { return INVALID_OPERATION; }
+
+private:
+    // Construct this using a codec, source and looper.
+    SimpleDecodingSource(
+            const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
+            bool usingSurface, const sp<AMessage> &format);
+
+    sp<MediaCodec> mCodec;
+    sp<IMediaSource> mSource;
+    sp<ALooper> mLooper;
+    bool mUsingSurface;
+    enum State {
+        INIT,
+        STARTED,
+        STOPPING,
+        STOPPED,
+        ERROR,
+    };
+    AString mComponentName;
+
+    struct ProtectedState {
+        ProtectedState(const sp<AMessage> &format);
+        bool mReading;
+        Condition mReadCondition;
+
+        sp<AMessage> mFormat;
+        State mState;
+        bool mQueuedInputEOS;
+        bool mGotOutputEOS;
+    };
+    Mutexed<ProtectedState> mProtectedState;
+
+    // do the actual reading
+    status_t doRead(
+            Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options);
+};
+
+} // namespace android
+
+#endif
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 14a0c66..cac34d0 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -52,6 +52,7 @@
         ProcessInfo.cpp                   \
         SampleIterator.cpp                \
         SampleTable.cpp                   \
+        SimpleDecodingSource.cpp          \
         SkipCutBuffer.cpp                 \
         StagefrightMediaScanner.cpp       \
         StagefrightMetadataRetriever.cpp  \
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
new file mode 100644
index 0000000..04f9a88
--- /dev/null
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2016, 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 <gui/Surface.h>
+
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <media/stagefright/Utils.h>
+
+using namespace android;
+
+const int64_t kTimeoutWaitForOutputUs = 500000; // 0.5 seconds
+
+//static
+sp<SimpleDecodingSource> SimpleDecodingSource::Create(
+        const sp<IMediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow) {
+    sp<Surface> surface = static_cast<Surface*>(nativeWindow.get());
+    const char *mime = NULL;
+    sp<MetaData> meta = source->getFormat();
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    sp<AMessage> format = new AMessage;
+    convertMetaDataToMessage(source->getFormat(), &format);
+
+    Vector<AString> matchingCodecs;
+    MediaCodecList::findMatchingCodecs(
+            mime, false /* encoder */, flags, &matchingCodecs);
+
+    sp<ALooper> looper = new ALooper;
+    looper->setName("stagefright");
+    looper->start();
+
+    sp<MediaCodec> codec;
+
+    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+        const AString &componentName = matchingCodecs[i];
+
+        ALOGV("Attempting to allocate codec '%s'", componentName.c_str());
+
+        codec = MediaCodec::CreateByComponentName(looper, componentName);
+        if (codec != NULL) {
+            ALOGI("Successfully allocated codec '%s'", componentName.c_str());
+
+            status_t err = codec->configure(format, surface, NULL /* crypto */, 0 /* flags */);
+            if (err == OK) {
+                err = codec->getOutputFormat(&format);
+            }
+            if (err == OK) {
+                return new SimpleDecodingSource(codec, source, looper, surface != NULL, format);
+            }
+
+            ALOGD("Failed to configure codec '%s'", componentName.c_str());
+            codec->release();
+            codec = NULL;
+        }
+    }
+
+    looper->stop();
+    ALOGE("No matching decoder! (mime: %s)", mime);
+    return NULL;
+}
+
+SimpleDecodingSource::SimpleDecodingSource(
+        const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
+        bool usingSurface, const sp<AMessage> &format)
+    : mCodec(codec),
+      mSource(source),
+      mLooper(looper),
+      mUsingSurface(usingSurface),
+      mProtectedState(format) {
+    mCodec->getName(&mComponentName);
+}
+
+SimpleDecodingSource::~SimpleDecodingSource() {
+    mCodec->release();
+    mLooper->stop();
+}
+
+status_t SimpleDecodingSource::start(MetaData *params) {
+    (void)params;
+    Mutexed<ProtectedState>::Locked me(mProtectedState);
+    if (me->mState != INIT) {
+        return -EINVAL;
+    }
+    status_t res = mCodec->start();
+    if (res == OK) {
+        res = mSource->start();
+    }
+
+    if (res == OK) {
+        me->mState = STARTED;
+        me->mQueuedInputEOS = false;
+        me->mGotOutputEOS = false;
+    } else {
+        me->mState = ERROR;
+    }
+
+    return res;
+}
+
+status_t SimpleDecodingSource::stop() {
+    Mutexed<ProtectedState>::Locked me(mProtectedState);
+    if (me->mState != STARTED) {
+        return -EINVAL;
+    }
+
+    // wait for any pending reads to complete
+    me->mState = STOPPING;
+    while (me->mReading) {
+        me.waitForCondition(me->mReadCondition);
+    }
+
+    status_t res1 = mCodec->stop();
+    if (res1 != OK) {
+        mCodec->release();
+    }
+    status_t res2 = mSource->stop();
+    if (res1 == OK && res2 == OK) {
+        me->mState = STOPPED;
+    } else {
+        me->mState = ERROR;
+    }
+    return res1 != OK ? res1 : res2;
+}
+
+sp<MetaData> SimpleDecodingSource::getFormat() {
+    Mutexed<ProtectedState>::Locked me(mProtectedState);
+    if (me->mState == STARTED || me->mState == INIT) {
+        sp<MetaData> meta = new MetaData();
+        convertMessageToMetaData(me->mFormat, meta);
+        return meta;
+    }
+    return NULL;
+}
+
+SimpleDecodingSource::ProtectedState::ProtectedState(const sp<AMessage> &format)
+    : mReading(false),
+      mFormat(format),
+      mState(INIT),
+      mQueuedInputEOS(false),
+      mGotOutputEOS(false) {
+}
+
+status_t SimpleDecodingSource::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    *buffer = NULL;
+
+    Mutexed<ProtectedState>::Locked me(mProtectedState);
+    if (me->mState != STARTED) {
+        return ERROR_END_OF_STREAM;
+    }
+    me->mReading = true;
+
+    status_t res = doRead(me, buffer, options);
+
+    me.lock();
+    me->mReading = false;
+    if (me->mState != STARTED) {
+        me->mReadCondition.signal();
+    }
+
+    return res;
+}
+
+status_t SimpleDecodingSource::doRead(
+        Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options) {
+    // |me| is always locked on entry, but is allowed to be unlocked on exit
+    CHECK_EQ(me->mState, STARTED);
+
+    size_t out_ix, in_ix, out_offset, out_size;
+    int64_t out_pts;
+    uint32_t out_flags;
+    status_t res;
+
+    // flush codec on seek
+    IMediaSource::ReadOptions::SeekMode mode;
+    if (options != NULL && options->getSeekTo(&out_pts, &mode)) {
+        me->mQueuedInputEOS = false;
+        me->mGotOutputEOS = false;
+        mCodec->flush();
+    }
+
+    if (me->mGotOutputEOS) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    for (int retries = 1; ++retries; ) {
+        // If we fill all available input buffers, we should expect that
+        // the codec produces at least one output buffer. Also, the codec
+        // should produce an output buffer in at most 1 seconds. Retry a
+        // few times nonetheless.
+        while (!me->mQueuedInputEOS) {
+            res = mCodec->dequeueInputBuffer(&in_ix, 0);
+            if (res == -EAGAIN) {
+                // no available input buffers
+                break;
+            }
+
+            sp<ABuffer> in_buffer;
+            if (res == OK) {
+                res = mCodec->getInputBuffer(in_ix, &in_buffer);
+            }
+
+            if (res != OK || in_buffer == NULL) {
+                ALOGW("[%s] could not get input buffer #%zu",
+                        mComponentName.c_str(), in_ix);
+                me->mState = ERROR;
+                return UNKNOWN_ERROR;
+            }
+
+            MediaBuffer *in_buf;
+            while (true) {
+                in_buf = NULL;
+                me.unlock();
+                res = mSource->read(&in_buf, options);
+                me.lock();
+                if (res != OK || me->mState != STARTED) {
+                    if (in_buf != NULL) {
+                        in_buf->release();
+                        in_buf = NULL;
+                    }
+
+                    // queue EOS
+                    me->mQueuedInputEOS = true;
+                    if (mCodec->queueInputBuffer(
+                                 in_ix, 0 /* offset */, 0 /* size */,
+                                 0 /* pts */, MediaCodec::BUFFER_FLAG_EOS) != OK) {
+                        ALOGI("[%s] failed to queue input EOS", mComponentName.c_str());
+                        me->mState = ERROR;
+                        return UNKNOWN_ERROR;
+                    }
+
+                    // don't stop on EOS, but report error or EOS on stop
+                    if (res != ERROR_END_OF_STREAM) {
+                        me->mState = ERROR;
+                        return res;
+                    }
+                    if (me->mState != STARTED) {
+                        return ERROR_END_OF_STREAM;
+                    }
+                    break;
+                }
+                if (in_buf == NULL) { // should not happen
+                    continue;
+                } else if (in_buf->range_length() != 0) {
+                    break;
+                }
+                in_buf->release();
+            }
+
+            if (in_buf != NULL) {
+                int64_t timestampUs = 0;
+                CHECK(in_buf->meta_data()->findInt64(kKeyTime, &timestampUs));
+                if (in_buf->range_length() > in_buffer->capacity()) {
+                    ALOGW("'%s' received %zu input bytes for buffer of size %zu",
+                            mComponentName.c_str(),
+                            in_buf->range_length(), in_buffer->capacity());
+                }
+                memcpy(in_buffer->base(), (uint8_t *)in_buf->data() + in_buf->range_offset(),
+                       min(in_buf->range_length(), in_buffer->capacity()));
+
+                res = mCodec->queueInputBuffer(
+                        in_ix, 0 /* offset */, in_buf->range_length(),
+                        timestampUs, 0 /* flags */);
+                if (res != OK) {
+                    ALOGI("[%s] failed to queue input buffer #%zu", mComponentName.c_str(), in_ix);
+                    me->mState = ERROR;
+                }
+                in_buf->release();
+            }
+        }
+
+        me.unlock();
+        res = mCodec->dequeueOutputBuffer(
+                &out_ix, &out_offset, &out_size, &out_pts,
+                &out_flags, kTimeoutWaitForOutputUs /* timeoutUs */);
+        me.lock();
+        // abort read on stop
+        if (me->mState != STARTED) {
+            if (res == OK) {
+                mCodec->releaseOutputBuffer(out_ix);
+            }
+            return ERROR_END_OF_STREAM;
+        }
+
+        if (res == -EAGAIN) {
+            ALOGD("[%s] did not produce an output buffer. retry count: %d",
+                  mComponentName.c_str(), retries);
+            continue;
+        } else if (res == INFO_FORMAT_CHANGED) {
+            if (mCodec->getOutputFormat(&me->mFormat) != OK) {
+                me->mState = ERROR;
+                res = UNKNOWN_ERROR;
+            }
+            return res;
+        } else if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
+            ALOGV("output buffers changed");
+            continue;
+        } else if (res != OK) {
+            me->mState = ERROR;
+            return res;
+        }
+
+        sp<ABuffer> out_buffer;
+        res = mCodec->getOutputBuffer(out_ix, &out_buffer);
+        if (res != OK) {
+            ALOGW("[%s] could not get output buffer #%zu",
+                    mComponentName.c_str(), out_ix);
+            me->mState = ERROR;
+            return UNKNOWN_ERROR;
+        }
+        if (out_flags & MediaCodec::BUFFER_FLAG_EOS) {
+            me->mGotOutputEOS = true;
+            // return EOS immediately if last buffer is empty
+            if (out_size == 0) {
+                mCodec->releaseOutputBuffer(out_ix);
+                return ERROR_END_OF_STREAM;
+            }
+        }
+
+        if (mUsingSurface && out_size > 0) {
+            *buffer = new MediaBuffer(0);
+            mCodec->renderOutputBufferAndRelease(out_ix);
+        } else {
+            *buffer = new MediaBuffer(out_size);
+            CHECK_LE(out_buffer->size(), (*buffer)->size());
+            memcpy((*buffer)->data(), out_buffer->data(), out_buffer->size());
+            (*buffer)->meta_data()->setInt64(kKeyTime, out_pts);
+            mCodec->releaseOutputBuffer(out_ix);
+        }
+        return OK;
+    }
+
+    return TIMED_OUT;
+}
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index dfb3d9c..bdda19c 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -43,17 +43,18 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:=         \
-        rtp_test.cpp
+LOCAL_SRC_FILES := \
+	rtp_test.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation
+	libstagefright liblog libutils libbinder libstagefright_foundation libmedia
 
 LOCAL_STATIC_LIBRARIES := \
-        libstagefright_rtsp
+	libstagefright_rtsp
 
-LOCAL_C_INCLUDES:= \
+LOCAL_C_INCLUDES := \
 	frameworks/av/media/libstagefright \
+	frameworks/av/cmds/stagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
diff --git a/media/libstagefright/rtsp/MyTransmitter.h b/media/libstagefright/rtsp/MyTransmitter.h
index 369f276..bf44aff 100644
--- a/media/libstagefright/rtsp/MyTransmitter.h
+++ b/media/libstagefright/rtsp/MyTransmitter.h
@@ -31,9 +31,10 @@
 
 #ifdef ANDROID
 #include "VideoSource.h"
-
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodecSource.h>
 #endif
 
 namespace android {
@@ -109,17 +110,19 @@
 
         sp<MediaSource> source = new VideoSource(width, height);
 
-        sp<MetaData> encMeta = new MetaData;
-        encMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-        encMeta->setInt32(kKeyWidth, width);
-        encMeta->setInt32(kKeyHeight, height);
+        sp<AMessage> encMeta = new AMessage;
+        encMeta->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
+        encMeta->setInt32("width", width);
+        encMeta->setInt32("height", height);
+        encMeta->setInt32("frame-rate", 30);
+        encMeta->setInt32("bitrate", 256000);
+        encMeta->setInt32("i-frame-interval", 10);
 
-        OMXClient client;
-        client.connect();
+        sp<ALooper> encLooper = new ALooper;
+        encLooper->setName("rtsp_transmitter");
+        encLooper->start();
 
-        mEncoder = OMXCodec::Create(
-                client.interface(), encMeta,
-                true /* createEncoder */, source);
+        mEncoder = MediaCodecSource::Create(encLooper, encMeta, source);
 
         mEncoder->start();
 
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index d43cd2a..24f529b 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -20,13 +20,13 @@
 
 #include <binder/ProcessState.h>
 
+#include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/SimpleDecodingSource.h>
 
 #include "ARTPSession.h"
 #include "ASessionDescription.h"
@@ -178,15 +178,8 @@
     CHECK_EQ(session->countTracks(), 1u);
     sp<MediaSource> source = session->trackAt(0);
 
-    OMXClient client;
-    CHECK_EQ(client.connect(), (status_t)OK);
-
-    sp<MediaSource> decoder = OMXCodec::Create(
-            client.interface(),
-            source->getFormat(), false /* createEncoder */,
-            source,
-            NULL,
-            0);  // OMXCodec::kPreferSoftwareCodecs);
+    sp<MediaSource> decoder = SimpleDecodingSource::Create(
+            source, 0 /* flags: ACodec::kPreferSoftwareCodecs */);
     CHECK(decoder != NULL);
 
     CHECK_EQ(decoder->start(), (status_t)OK);
@@ -213,7 +206,7 @@
             int64_t timeUs;
             CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
 
-            printf("decoder returned frame of size %d at time %.2f secs\n",
+            printf("decoder returned frame of size %zu at time %.2f secs\n",
                    buffer->range_length(), timeUs / 1E6);
         }
 #endif