stagefright: support passing GraphicBuffer in metadata buffer

Bug: 17935149
Change-Id: I6bb5dd654e498a7153410afc052c2c8f7f35e44d
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index dc6d410..24d431c 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -182,7 +182,9 @@
             OMX_IN OMX_PTR pAppData,
             OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
 
-    status_t storeMetaDataInBuffers_l(OMX_U32 portIndex, OMX_BOOL enable);
+    status_t storeMetaDataInBuffers_l(
+            OMX_U32 portIndex, OMX_BOOL enable,
+            OMX_BOOL useGraphicBuffer, OMX_BOOL *usingGraphicBufferInMeta);
 
     sp<GraphicBufferSource> getGraphicBufferSource();
     void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index fad6c33..3e70956 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -37,7 +37,8 @@
 
 
 GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance,
-        uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount) :
+        uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount,
+        bool useGraphicBufferInMeta) :
     mInitCheck(UNKNOWN_ERROR),
     mNodeInstance(nodeInstance),
     mExecuting(false),
@@ -59,7 +60,8 @@
     mTimePerCaptureUs(-1ll),
     mTimePerFrameUs(-1ll),
     mPrevCaptureUs(-1ll),
-    mPrevFrameUs(-1ll) {
+    mPrevFrameUs(-1ll),
+    mUseGraphicBufferInMeta(useGraphicBufferInMeta) {
 
     ALOGV("GraphicBufferSource w=%u h=%u c=%u",
             bufferWidth, bufferHeight, bufferCount);
@@ -254,13 +256,25 @@
         // Pull the graphic buffer handle back out of the buffer, and confirm
         // that it matches expectations.
         OMX_U8* data = header->pBuffer;
-        buffer_handle_t bufferHandle;
-        memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t));
-        if (bufferHandle != codecBuffer.mGraphicBuffer->handle) {
-            // should never happen
-            ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p",
-                    bufferHandle, codecBuffer.mGraphicBuffer->handle);
-            CHECK(!"codecBufferEmptied: mismatched buffer");
+        MetadataBufferType type = *(MetadataBufferType *)data;
+        if (type == kMetadataBufferTypeGrallocSource) {
+            buffer_handle_t bufferHandle;
+            memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t));
+            if (bufferHandle != codecBuffer.mGraphicBuffer->handle) {
+                // should never happen
+                ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p",
+                        bufferHandle, codecBuffer.mGraphicBuffer->handle);
+                CHECK(!"codecBufferEmptied: mismatched buffer");
+            }
+        } else if (type == kMetadataBufferTypeGraphicBuffer) {
+            GraphicBuffer *buffer;
+            memcpy(&buffer, data + 4, sizeof(buffer));
+            if (buffer != codecBuffer.mGraphicBuffer.get()) {
+                // should never happen
+                ALOGE("codecBufferEmptied: buffer is %p, expected %p",
+                        buffer, codecBuffer.mGraphicBuffer.get());
+                CHECK(!"codecBufferEmptied: mismatched buffer");
+            }
         }
     }
 
@@ -642,10 +656,22 @@
     OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
     CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t));
     OMX_U8* data = header->pBuffer;
-    const OMX_U32 type = kMetadataBufferTypeGrallocSource;
-    buffer_handle_t handle = codecBuffer.mGraphicBuffer->handle;
-    memcpy(data, &type, 4);
-    memcpy(data + 4, &handle, sizeof(buffer_handle_t));
+    buffer_handle_t handle;
+    if (!mUseGraphicBufferInMeta) {
+        const OMX_U32 type = kMetadataBufferTypeGrallocSource;
+        handle = codecBuffer.mGraphicBuffer->handle;
+        memcpy(data, &type, 4);
+        memcpy(data + 4, &handle, sizeof(buffer_handle_t));
+    } else {
+        // codecBuffer holds a reference to the GraphicBuffer, so
+        // it is valid while it is with the OMX component
+        const OMX_U32 type = kMetadataBufferTypeGraphicBuffer;
+        memcpy(data, &type, 4);
+        // passing a non-reference-counted graphicBuffer
+        GraphicBuffer *buffer = codecBuffer.mGraphicBuffer.get();
+        handle = buffer->handle;
+        memcpy(data + 4, &buffer, sizeof(buffer));
+    }
 
     status_t err = mNodeInstance->emptyDirectBuffer(header, 0,
             4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME,
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index a70cc1a..c0860ab 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -49,7 +49,8 @@
 class GraphicBufferSource : public BufferQueue::ConsumerListener {
 public:
     GraphicBufferSource(OMXNodeInstance* nodeInstance,
-            uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount);
+            uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount,
+            bool useGraphicBufferInMeta = false);
     virtual ~GraphicBufferSource();
 
     // We can't throw an exception if the constructor fails, so we just set
@@ -271,6 +272,8 @@
     int64_t mPrevCaptureUs;
     int64_t mPrevFrameUs;
 
+    bool mUseGraphicBufferInMeta;
+
     void onMessageReceived(const sp<AMessage> &msg);
 
     DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index efb27f5..d07ec14 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -393,20 +393,39 @@
         OMX_U32 portIndex,
         OMX_BOOL enable) {
     Mutex::Autolock autolock(mLock);
-    return storeMetaDataInBuffers_l(portIndex, enable);
+    return storeMetaDataInBuffers_l(
+            portIndex, enable,
+            OMX_FALSE /* useGraphicBuffer */, NULL /* usingGraphicBufferInMetadata */);
 }
 
 status_t OMXNodeInstance::storeMetaDataInBuffers_l(
         OMX_U32 portIndex,
-        OMX_BOOL enable) {
+        OMX_BOOL enable,
+        OMX_BOOL useGraphicBuffer,
+        OMX_BOOL *usingGraphicBufferInMetadata) {
     OMX_INDEXTYPE index;
     OMX_STRING name = const_cast<OMX_STRING>(
             "OMX.google.android.index.storeMetaDataInBuffers");
 
-    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
+    OMX_STRING graphicBufferName = const_cast<OMX_STRING>(
+            "OMX.google.android.index.storeGraphicBufferInMetaData");
+    if (usingGraphicBufferInMetadata == NULL) {
+        usingGraphicBufferInMetadata = &useGraphicBuffer;
+    }
+
+    OMX_ERRORTYPE err =
+        (useGraphicBuffer && portIndex == kPortIndexInput)
+                ? OMX_GetExtensionIndex(mHandle, graphicBufferName, &index)
+                : OMX_ErrorBadParameter;
+    if (err == OMX_ErrorNone) {
+        *usingGraphicBufferInMetadata = OMX_TRUE;
+    } else {
+        *usingGraphicBufferInMetadata = OMX_FALSE;
+        err = OMX_GetExtensionIndex(mHandle, name, &index);
+    }
+
     if (err != OMX_ErrorNone) {
         ALOGE("OMX_GetExtensionIndex %s failed", name);
-
         return StatusFromOMXError(err);
     }
 
@@ -421,6 +440,7 @@
     params.bStoreMetaData = enable;
     if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
         ALOGE("OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x%08x", err);
+        *usingGraphicBufferInMetadata = OMX_FALSE;
         return UNKNOWN_ERROR;
     }
     return err;
@@ -683,7 +703,10 @@
     }
 
     // Input buffers will hold meta-data (gralloc references).
-    err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE);
+    OMX_BOOL usingGraphicBuffer = OMX_FALSE;
+    err = storeMetaDataInBuffers_l(
+            portIndex, OMX_TRUE,
+            OMX_TRUE /* useGraphicBuffer */, &usingGraphicBuffer);
     if (err != OK) {
         return err;
     }
@@ -709,7 +732,7 @@
 
     GraphicBufferSource* bufferSource = new GraphicBufferSource(
             this, def.format.video.nFrameWidth, def.format.video.nFrameHeight,
-            def.nBufferCountActual);
+            def.nBufferCountActual, usingGraphicBuffer);
     if ((err = bufferSource->initCheck()) != OK) {
         delete bufferSource;
         return err;