Avoid copying for input recording frames in CameraSource

This is the part one.

- Let CameraSource be a MediaBufferObserver. It releases the recording frame when the ref count of a MediaBuffer containing
  the recording frame drops to 0.

  This reduces the CPU load from 90+% down to 50-60%.

Part two is related to the avoidance of copying the input video frames to the video encoder.
However, we are not able to use OMX_UseBuffer directly. Still work on the second part.

Change-Id: I906f1d054ae8bdcf82e1617f1fc120152f2eb2eb
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 9d6b01d..0c7bf6f 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -19,7 +19,6 @@
 #define CAMERA_SOURCE_H_
 
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaSource.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
@@ -31,7 +30,7 @@
 class IMemory;
 class Camera;
 
-class CameraSource : public MediaSource {
+class CameraSource : public MediaSource, public MediaBufferObserver {
 public:
     static CameraSource *Create();
     static CameraSource *CreateFromCamera(const sp<Camera> &camera);
@@ -46,6 +45,8 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
+    virtual void signalBufferReturned(MediaBuffer* buffer);
+
 private:
     friend class CameraSourceListener;
 
@@ -53,7 +54,9 @@
 
     Mutex mLock;
     Condition mFrameAvailableCondition;
-    List<sp<IMemory> > mFrames;
+    Condition mFrameCompleteCondition;
+    List<sp<IMemory> > mFramesReceived;
+    List<sp<IMemory> > mFramesBeingEncoded;
     List<int64_t> mFrameTimes;
 
     int mWidth, mHeight;
@@ -62,7 +65,6 @@
     int32_t mNumFramesReceived;
     int32_t mNumFramesEncoded;
     int32_t mNumFramesDropped;
-    MediaBufferGroup *mBufferGroup;
     bool mStarted;
 
     CameraSource(const sp<Camera> &camera);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 476b36d..c8834f8 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -104,7 +104,6 @@
       mNumFramesReceived(0),
       mNumFramesEncoded(0),
       mNumFramesDropped(0),
-      mBufferGroup(NULL),
       mStarted(false) {
     String8 s = mCamera->getParameters();
     printf("params: \"%s\"\n", s.string());
@@ -139,8 +138,12 @@
     mCamera->stopRecording();
 
     releaseQueuedFrames();
-    delete mBufferGroup;
-    mBufferGroup = NULL;
+
+    while (!mFramesBeingEncoded.empty()) {
+        LOGI("Number of outstanding frames is being encoded: %d", mFramesBeingEncoded.size());
+        mFrameCompleteCondition.wait(mLock);
+    }
+
     LOGI("Frames received/encoded/dropped: %d/%d/%d, timestamp (us) last/first: %lld/%lld",
             mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
             mLastFrameTimestampUs, mFirstFrameTimeUs);
@@ -151,10 +154,10 @@
 
 void CameraSource::releaseQueuedFrames() {
     List<sp<IMemory> >::iterator it;
-    while (!mFrames.empty()) {
-        it = mFrames.begin();
+    while (!mFramesReceived.empty()) {
+        it = mFramesReceived.begin();
         mCamera->releaseRecordingFrame(*it);
-        mFrames.erase(it);
+        mFramesReceived.erase(it);
         ++mNumFramesDropped;
     }
 }
@@ -169,6 +172,23 @@
     return meta;
 }
 
+void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
+    LOGV("signalBufferReturned: %p", buffer->data());
+    for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
+         it != mFramesBeingEncoded.end(); ++it) {
+        if ((*it)->pointer() ==  buffer->data()) {
+            mCamera->releaseRecordingFrame((*it));
+            mFramesBeingEncoded.erase(it);
+            ++mNumFramesEncoded;
+            buffer->setObserver(0);
+            buffer->release();
+            mFrameCompleteCondition.signal();
+            return;
+        }
+    }
+    CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+}
+
 status_t CameraSource::read(
         MediaBuffer **buffer, const ReadOptions *options) {
     LOGV("read");
@@ -185,33 +205,24 @@
 
     {
         Mutex::Autolock autoLock(mLock);
-        while (mStarted && mFrames.empty()) {
+        while (mStarted && mFramesReceived.empty()) {
             mFrameAvailableCondition.wait(mLock);
         }
         if (!mStarted) {
             return OK;
         }
-        frame = *mFrames.begin();
-        mFrames.erase(mFrames.begin());
+        frame = *mFramesReceived.begin();
+        mFramesReceived.erase(mFramesReceived.begin());
 
         frameTime = *mFrameTimes.begin();
         mFrameTimes.erase(mFrameTimes.begin());
-        ++mNumFramesEncoded;
+
+        mFramesBeingEncoded.push_back(frame);
+        *buffer = new MediaBuffer(frame->pointer(), frame->size());
+        (*buffer)->setObserver(this);
+        (*buffer)->add_ref();
+        (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
     }
-    if (mBufferGroup == NULL) {
-        mBufferGroup = new MediaBufferGroup();
-        CHECK(mBufferGroup != NULL);
-        mBufferGroup->add_buffer(new MediaBuffer(frame->size()));
-    }
-
-    mBufferGroup->acquire_buffer(buffer);
-    memcpy((*buffer)->data(), frame->pointer(), frame->size());
-    (*buffer)->set_range(0, frame->size());
-    mCamera->releaseRecordingFrame(frame);
-
-    (*buffer)->meta_data()->clear();
-    (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
-
     return OK;
 }
 
@@ -232,7 +243,7 @@
     }
     ++mNumFramesReceived;
 
-    mFrames.push_back(data);
+    mFramesReceived.push_back(data);
     mFrameTimes.push_back(timestampUs - mFirstFrameTimeUs);
     mFrameAvailableCondition.signal();
 }