Merge "SF transactions are now O(1) wrt IPC instead of O(N)."
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index a17a47e..ee91c29 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -20,6 +20,11 @@
 #include <media/mediaplayer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
 
 #include <binder/IServiceManager.h>
 #include <media/IMediaPlayerService.h>
@@ -31,7 +36,7 @@
 using namespace android;
 
 struct MyStreamSource : public BnStreamSource {
-    // Caller retains ownership of fd.
+    // Object assumes ownership of fd.
     MyStreamSource(int fd);
 
     virtual void setListener(const sp<IStreamListener> &listener);
@@ -64,6 +69,8 @@
 }
 
 MyStreamSource::~MyStreamSource() {
+    close(mFd);
+    mFd = -1;
 }
 
 void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
@@ -99,6 +106,143 @@
         mListener->queueBuffer(index, n);
     }
 }
+////////////////////////////////////////////////////////////////////////////////
+
+struct MyConvertingStreamSource : public BnStreamSource {
+    MyConvertingStreamSource(const char *filename);
+
+    virtual void setListener(const sp<IStreamListener> &listener);
+    virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
+
+    virtual void onBufferAvailable(size_t index);
+
+protected:
+    virtual ~MyConvertingStreamSource();
+
+private:
+    Mutex mLock;
+    Condition mCondition;
+
+    sp<IStreamListener> mListener;
+    Vector<sp<IMemory> > mBuffers;
+
+    sp<MPEG2TSWriter> mWriter;
+
+    ssize_t mCurrentBufferIndex;
+    size_t mCurrentBufferOffset;
+
+    List<size_t> mBufferQueue;
+
+    static ssize_t WriteDataWrapper(void *me, const void *data, size_t size);
+    ssize_t writeData(const void *data, size_t size);
+
+    DISALLOW_EVIL_CONSTRUCTORS(MyConvertingStreamSource);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
+    : mCurrentBufferIndex(-1),
+      mCurrentBufferOffset(0) {
+    sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+    CHECK(dataSource != NULL);
+
+    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+    CHECK(extractor != NULL);
+
+    mWriter = new MPEG2TSWriter(
+            this, &MyConvertingStreamSource::WriteDataWrapper);
+
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        const sp<MetaData> &meta = extractor->getTrackMetaData(i);
+
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+        if (strncasecmp("video/", mime, 6) && strncasecmp("audio/", mime, 6)) {
+            continue;
+        }
+
+        CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK);
+    }
+
+    CHECK_EQ(mWriter->start(), (status_t)OK);
+}
+
+MyConvertingStreamSource::~MyConvertingStreamSource() {
+}
+
+void MyConvertingStreamSource::setListener(
+        const sp<IStreamListener> &listener) {
+    mListener = listener;
+}
+
+void MyConvertingStreamSource::setBuffers(
+        const Vector<sp<IMemory> > &buffers) {
+    mBuffers = buffers;
+}
+
+ssize_t MyConvertingStreamSource::WriteDataWrapper(
+        void *me, const void *data, size_t size) {
+    return static_cast<MyConvertingStreamSource *>(me)->writeData(data, size);
+}
+
+ssize_t MyConvertingStreamSource::writeData(const void *data, size_t size) {
+    size_t totalWritten = 0;
+
+    while (size > 0) {
+        Mutex::Autolock autoLock(mLock);
+
+        if (mCurrentBufferIndex < 0) {
+            while (mBufferQueue.empty()) {
+                mCondition.wait(mLock);
+            }
+
+            mCurrentBufferIndex = *mBufferQueue.begin();
+            mCurrentBufferOffset = 0;
+
+            mBufferQueue.erase(mBufferQueue.begin());
+        }
+
+        sp<IMemory> mem = mBuffers.itemAt(mCurrentBufferIndex);
+
+        size_t copy = size;
+        if (copy + mCurrentBufferOffset > mem->size()) {
+            copy = mem->size() - mCurrentBufferOffset;
+        }
+
+        memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy);
+        mCurrentBufferOffset += copy;
+
+        if (mCurrentBufferOffset == mem->size()) {
+            mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
+            mCurrentBufferIndex = -1;
+        }
+
+        data = (const uint8_t *)data + copy;
+        size -= copy;
+
+        totalWritten += copy;
+    }
+
+    return (ssize_t)totalWritten;
+}
+
+void MyConvertingStreamSource::onBufferAvailable(size_t index) {
+    Mutex::Autolock autoLock(mLock);
+
+    mBufferQueue.push_back(index);
+    mCondition.signal();
+
+    if (mWriter->reachedEOS()) {
+        if (mCurrentBufferIndex >= 0) {
+            mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
+            mCurrentBufferIndex = -1;
+        }
+
+        mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
+    }
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -139,6 +283,8 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
+    DataSource::RegisterDefaultSniffers();
+
     if (argc != 2) {
         fprintf(stderr, "Usage: %s filename\n", argv[0]);
         return 1;
@@ -173,17 +319,28 @@
 
     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<IStreamSource> source;
+
+    size_t len = strlen(argv[1]);
+    if (len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) {
+        int fd = open(argv[1], O_RDONLY);
+
+        if (fd < 0) {
+            fprintf(stderr, "Failed to open file '%s'.", argv[1]);
+            return 1;
+        }
+
+        source = new MyStreamSource(fd);
+    } else {
+        printf("Converting file to transport stream for streaming...\n");
+
+        source = new MyConvertingStreamSource(argv[1]);
+    }
+
     sp<IMediaPlayer> player =
-        service->create(getpid(), client, new MyStreamSource(fd), 0);
+        service->create(getpid(), client, source, 0);
 
     if (player != NULL) {
         player->setVideoSurface(surface);
@@ -196,9 +353,6 @@
         fprintf(stderr, "failed to instantiate player.\n");
     }
 
-    close(fd);
-    fd = -1;
-
     composerClient->dispose();
 
     return 0;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index bdffce9..ed8149a 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -158,9 +158,12 @@
     mVideoSize.width  = -1;
     mVideoSize.height = -1;
 
+    int64_t token = IPCThreadState::self()->clearCallingIdentity();
     mInitCheck = init(camera, proxy, cameraId,
                     videoSize, frameRate,
                     storeMetaDataInVideoBuffers);
+    if (mInitCheck != OK) releaseCamera();
+    IPCThreadState::self()->restoreCallingIdentity(token);
 }
 
 status_t CameraSource::initCheck() const {
@@ -295,7 +298,6 @@
     if (width != -1 && height != -1) {
         if (!isVideoSizeSupported(width, height, sizes)) {
             LOGE("Video dimension (%dx%d) is unsupported", width, height);
-            releaseCamera();
             return BAD_VALUE;
         }
         if (isSetVideoSizeSupportedByCamera) {
@@ -309,7 +311,6 @@
         // If one and only one of the width and height is -1
         // we reject such a request.
         LOGE("Requested video size (%dx%d) is not supported", width, height);
-        releaseCamera();
         return BAD_VALUE;
     } else {  // width == -1 && height == -1
         // Do not configure the camera.
@@ -327,7 +328,6 @@
         if (strstr(supportedFrameRates, buf) == NULL) {
             LOGE("Requested frame rate (%d) is not supported: %s",
                 frameRate, supportedFrameRates);
-            releaseCamera();
             return BAD_VALUE;
         }
 
@@ -463,7 +463,6 @@
         bool storeMetaDataInVideoBuffers) {
 
     status_t err = OK;
-    int64_t token = IPCThreadState::self()->clearCallingIdentity();
 
     if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
         LOGE("Camera connection could not be established.");
@@ -505,8 +504,6 @@
         }
     }
 
-    IPCThreadState::self()->restoreCallingIdentity(token);
-
     int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
     if (glitchDurationUs > mGlitchDurationThresholdUs) {
         mGlitchDurationThresholdUs = glitchDurationUs;
@@ -573,13 +570,21 @@
 
 void CameraSource::releaseCamera() {
     LOGV("releaseCamera");
-    if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
-        LOGV("Camera was cold when we started, stopping preview");
-        mCamera->stopPreview();
+    if (mCamera != 0) {
+        if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
+            LOGV("Camera was cold when we started, stopping preview");
+            mCamera->stopPreview();
+            mCamera->disconnect();
+        } else {
+            // Unlock the camera so the application can lock it back.
+            mCamera->unlock();
+        }
+        mCamera.clear();
     }
-    mCamera.clear();
-    mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
-    mCameraRecordingProxy.clear();
+    if (mCameraRecordingProxy != 0) {
+        mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
+        mCameraRecordingProxy.clear();
+    }
     mCameraFlags = 0;
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index cd97302..e36b01f 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1838,7 +1838,7 @@
         }
     }
 
-    LOGV("native_window_set_usage usage=0x%x", usage);
+    LOGV("native_window_set_usage usage=0x%lx", usage);
     err = native_window_set_usage(
             mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
     if (err != 0) {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index ed6846c..967f126 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -41,6 +41,7 @@
 static Mutex gNetworkThreadLock;
 static base::Thread *gNetworkThread = NULL;
 static scoped_refptr<net::URLRequestContext> gReqContext;
+static scoped_ptr<net::NetworkChangeNotifier> gNetworkChangeNotifier;
 
 static void InitializeNetworkThreadIfNecessary() {
     Mutex::Autolock autoLock(gNetworkThreadLock);
@@ -52,6 +53,8 @@
 
         gReqContext = new SfRequestContext;
 
+        gNetworkChangeNotifier.reset(net::NetworkChangeNotifier::Create());
+
         net::AndroidNetworkLibrary::RegisterSharedInstance(
                 new SfNetworkLibrary);
     }