Support streaming data across binder boundaries.

Change-Id: Ifbac61406dcb81343765f99ccba08bd90f9274cc
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 93baefd..f8650eb 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -98,3 +98,27 @@
 LOCAL_MODULE:= audioloop
 
 include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=         \
+        stream.cpp    \
+
+LOCAL_SHARED_LIBRARIES := \
+	libstagefright liblog libutils libbinder libsurfaceflinger_client \
+        libstagefright_foundation libmedia
+
+LOCAL_C_INCLUDES:= \
+	$(JNI_H_INCLUDE) \
+	frameworks/base/media/libstagefright \
+	$(TOP)/frameworks/base/include/media/stagefright/openmax
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= stream
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
new file mode 100644
index 0000000..f2b5638
--- /dev/null
+++ b/cmds/stagefright/stream.cpp
@@ -0,0 +1,168 @@
+#include <binder/ProcessState.h>
+
+#include <media/IStreamSource.h>
+#include <media/mediaplayer.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <fcntl.h>
+
+using namespace android;
+
+struct MyStreamSource : public BnStreamSource {
+    // Caller retains ownership of fd.
+    MyStreamSource(int fd);
+
+    virtual void setListener(const sp<IStreamListener> &listener);
+    virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
+
+    virtual void onBufferAvailable(size_t index);
+
+protected:
+    virtual ~MyStreamSource();
+
+private:
+    int mFd;
+
+    sp<IStreamListener> mListener;
+    Vector<sp<IMemory> > mBuffers;
+
+    DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource);
+};
+
+MyStreamSource::MyStreamSource(int fd)
+    : mFd(fd) {
+    CHECK_GE(fd, 0);
+}
+
+MyStreamSource::~MyStreamSource() {
+}
+
+void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
+    mListener = listener;
+}
+
+void MyStreamSource::setBuffers(const Vector<sp<IMemory> > &buffers) {
+    mBuffers = buffers;
+}
+
+void MyStreamSource::onBufferAvailable(size_t index) {
+    CHECK_LT(index, mBuffers.size());
+    sp<IMemory> mem = mBuffers.itemAt(index);
+
+    ssize_t n = read(mFd, mem->pointer(), mem->size());
+    if (n <= 0) {
+        mListener->queueCommand(IStreamListener::EOS);
+    } else {
+        mListener->queueBuffer(index, n);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct MyClient : public BnMediaPlayerClient {
+    MyClient()
+        : mEOS(false) {
+    }
+
+    virtual void notify(int msg, int ext1, int ext2) {
+        Mutex::Autolock autoLock(mLock);
+
+        if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
+            mEOS = true;
+            mCondition.signal();
+        }
+    }
+
+    void waitForEOS() {
+        Mutex::Autolock autoLock(mLock);
+        while (!mEOS) {
+            mCondition.wait(mLock);
+        }
+    }
+
+protected:
+    virtual ~MyClient() {
+    }
+
+private:
+    Mutex mLock;
+    Condition mCondition;
+
+    bool mEOS;
+
+    DISALLOW_EVIL_CONSTRUCTORS(MyClient);
+};
+
+int main(int argc, char **argv) {
+    android::ProcessState::self()->startThreadPool();
+
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s filename\n", argv[0]);
+        return 1;
+    }
+
+    sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+    CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+    sp<SurfaceControl> control =
+        composerClient->createSurface(
+                getpid(),
+                String8("A Surface"),
+                0,
+                1280,
+                800,
+                PIXEL_FORMAT_RGB_565,
+                0);
+
+    CHECK(control != NULL);
+    CHECK(control->isValid());
+
+    CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+    CHECK_EQ(control->setLayer(30000), (status_t)OK);
+    CHECK_EQ(control->show(), (status_t)OK);
+    CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+
+    sp<Surface> surface = control->getSurface();
+    CHECK(surface != NULL);
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.player"));
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+    CHECK(service.get() != NULL);
+
+    int fd = open(argv[1], O_RDONLY);
+
+    if (fd < 0) {
+        fprintf(stderr, "Failed to open file '%s'.", argv[1]);
+        return 1;
+    }
+
+    sp<MyClient> client = new MyClient;
+
+    sp<IMediaPlayer> player =
+        service->create(getpid(), client, new MyStreamSource(fd), 0);
+
+    if (player != NULL) {
+        player->setVideoSurface(surface);
+        player->start();
+
+        client->waitForEOS();
+
+        player->stop();
+    } else {
+        fprintf(stderr, "failed to instantiate player.\n");
+    }
+
+    close(fd);
+    fd = -1;
+
+    composerClient->dispose();
+
+    return 0;
+}