Added Tunneled video playback support to ACodec

Bug:16132368
Change-Id: I88d2d66b8548fc203f4a2c4797196af15e56ff38
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index dd13fea..627f23b 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -87,6 +87,10 @@
             node_id node, OMX_U32 portIndex, OMX_BOOL enable,
             OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) = 0;
 
+   virtual status_t configureVideoTunnelMode(
+            node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle) = 0;
+
     virtual status_t enableGraphicBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
 
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 3a6bb9e..eb31c77 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -234,6 +234,9 @@
     status_t setComponentRole(bool isEncoder, const char *mime);
     status_t configureCodec(const char *mime, const sp<AMessage> &msg);
 
+    status_t configureTunneledVideoPlayback(int64_t audioHwSync,
+            const sp<ANativeWindow> &nativeWindow);
+
     status_t setVideoPortFormatType(
             OMX_U32 portIndex,
             OMX_VIDEO_CODINGTYPE compressionFormat,
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 5df232f..c583d32 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -54,6 +54,7 @@
     GET_GRAPHIC_BUFFER_USAGE,
     SET_INTERNAL_OPTION,
     UPDATE_GRAPHIC_BUFFER_IN_META,
+    CONFIGURE_VIDEO_TUNNEL_MODE,
 };
 
 class BpOMX : public BpInterface<IOMX> {
@@ -368,6 +369,25 @@
         return err;
     }
 
+    virtual status_t configureVideoTunnelMode(
+            node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle ) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        data.writeInt32((int32_t)node);
+        data.writeInt32(portIndex);
+        data.writeInt32((int32_t)tunneled);
+        data.writeInt32(audioHwSync);
+        remote()->transact(CONFIGURE_VIDEO_TUNNEL_MODE, data, &reply);
+
+        status_t err = reply.readInt32();
+        if (sidebandHandle) {
+            *sidebandHandle = (native_handle_t *)reply.readNativeHandle();
+        }
+        return err;
+    }
+
+
     virtual status_t allocateBuffer(
             node_id node, OMX_U32 port_index, size_t size,
             buffer_id *buffer, void **buffer_data) {
@@ -804,6 +824,24 @@
             return NO_ERROR;
         }
 
+        case CONFIGURE_VIDEO_TUNNEL_MODE:
+        {
+            CHECK_OMX_INTERFACE(IOMX, data, reply);
+
+            node_id node = (node_id)data.readInt32();
+            OMX_U32 port_index = data.readInt32();
+            OMX_BOOL tunneled = (OMX_BOOL)data.readInt32();
+            OMX_U32 audio_hw_sync = data.readInt32();
+
+            native_handle_t *sideband_handle;
+            status_t err = configureVideoTunnelMode(
+                    node, port_index, tunneled, audio_hw_sync, &sideband_handle);
+            reply->writeInt32(err);
+            reply->writeNativeHandle(sideband_handle);
+
+            return NO_ERROR;
+        }
+
         case ALLOC_BUFFER:
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 503ce81..ac80da2 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1224,77 +1224,99 @@
         }
     }
 
-    // Always try to enable dynamic output buffers on native surface
     sp<RefBase> obj;
     int32_t haveNativeWindow = msg->findObject("native-window", &obj) &&
-            obj != NULL;
+        obj != NULL;
     mStoreMetaDataInOutputBuffers = false;
     if (video && !encoder) {
         inputFormat->setInt32("adaptive-playback", false);
     }
     if (!encoder && video && haveNativeWindow) {
-        err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
-        if (err != OK) {
-            ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d",
-                  mComponentName.c_str(), err);
+        sp<NativeWindowWrapper> windowWrapper(
+                static_cast<NativeWindowWrapper *>(obj.get()));
+        sp<ANativeWindow> nativeWindow = windowWrapper->getNativeWindow();
 
-            // if adaptive playback has been requested, try JB fallback
-            // NOTE: THIS FALLBACK MECHANISM WILL BE REMOVED DUE TO ITS
-            // LARGE MEMORY REQUIREMENT
+        int32_t tunneled;
+        if (msg->findInt32("feature-tunneled-playback", &tunneled) &&
+            tunneled != 0) {
+            ALOGI("Configuring TUNNELED video playback.");
 
-            // we will not do adaptive playback on software accessed
-            // surfaces as they never had to respond to changes in the
-            // crop window, and we don't trust that they will be able to.
-            int usageBits = 0;
-            bool canDoAdaptivePlayback;
-
-            sp<NativeWindowWrapper> windowWrapper(
-                    static_cast<NativeWindowWrapper *>(obj.get()));
-            sp<ANativeWindow> nativeWindow = windowWrapper->getNativeWindow();
-
-            if (nativeWindow->query(
-                    nativeWindow.get(),
-                    NATIVE_WINDOW_CONSUMER_USAGE_BITS,
-                    &usageBits) != OK) {
-                canDoAdaptivePlayback = false;
-            } else {
-                canDoAdaptivePlayback =
-                    (usageBits &
-                            (GRALLOC_USAGE_SW_READ_MASK |
-                             GRALLOC_USAGE_SW_WRITE_MASK)) == 0;
+            int64_t audioHwSync = 0;
+            if (!msg->findInt64("audio-hw-sync", &audioHwSync)) {
+                ALOGW("No Audio HW Sync provided for video tunnel");
+            }
+            err = configureTunneledVideoPlayback(audioHwSync, nativeWindow);
+            if (err != OK) {
+                ALOGE("configureTunneledVideoPlayback(%" PRId64 ",%p) failed!",
+                        audioHwSync, nativeWindow.get());
+                return err;
             }
 
-            int32_t maxWidth = 0, maxHeight = 0;
-            if (canDoAdaptivePlayback &&
-                msg->findInt32("max-width", &maxWidth) &&
-                msg->findInt32("max-height", &maxHeight)) {
-                ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)",
-                      mComponentName.c_str(), maxWidth, maxHeight);
-
-                err = mOMX->prepareForAdaptivePlayback(
-                        mNode, kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight);
-                ALOGW_IF(err != OK,
-                        "[%s] prepareForAdaptivePlayback failed w/ err %d",
+            inputFormat->setInt32("adaptive-playback", true);
+        } else {
+            // Always try to enable dynamic output buffers on native surface
+            err = mOMX->storeMetaDataInBuffers(
+                    mNode, kPortIndexOutput, OMX_TRUE);
+            if (err != OK) {
+                ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d",
                         mComponentName.c_str(), err);
 
-                if (err == OK) {
-                    inputFormat->setInt32("max-width", maxWidth);
-                    inputFormat->setInt32("max-height", maxHeight);
-                    inputFormat->setInt32("adaptive-playback", true);
-                }
-            }
-            // allow failure
-            err = OK;
-        } else {
-            ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str());
-            mStoreMetaDataInOutputBuffers = true;
-            inputFormat->setInt32("adaptive-playback", true);
-        }
+                // if adaptive playback has been requested, try JB fallback
+                // NOTE: THIS FALLBACK MECHANISM WILL BE REMOVED DUE TO ITS
+                // LARGE MEMORY REQUIREMENT
 
-        int32_t push;
-        if (msg->findInt32("push-blank-buffers-on-shutdown", &push)
-                && push != 0) {
-            mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
+                // we will not do adaptive playback on software accessed
+                // surfaces as they never had to respond to changes in the
+                // crop window, and we don't trust that they will be able to.
+                int usageBits = 0;
+                bool canDoAdaptivePlayback;
+
+                if (nativeWindow->query(
+                        nativeWindow.get(),
+                        NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+                        &usageBits) != OK) {
+                    canDoAdaptivePlayback = false;
+                } else {
+                    canDoAdaptivePlayback =
+                        (usageBits &
+                                (GRALLOC_USAGE_SW_READ_MASK |
+                                 GRALLOC_USAGE_SW_WRITE_MASK)) == 0;
+                }
+
+                int32_t maxWidth = 0, maxHeight = 0;
+                if (canDoAdaptivePlayback &&
+                        msg->findInt32("max-width", &maxWidth) &&
+                        msg->findInt32("max-height", &maxHeight)) {
+                    ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)",
+                            mComponentName.c_str(), maxWidth, maxHeight);
+
+                    err = mOMX->prepareForAdaptivePlayback(
+                            mNode, kPortIndexOutput, OMX_TRUE, maxWidth,
+                            maxHeight);
+                    ALOGW_IF(err != OK,
+                            "[%s] prepareForAdaptivePlayback failed w/ err %d",
+                            mComponentName.c_str(), err);
+
+                    if (err == OK) {
+                        inputFormat->setInt32("max-width", maxWidth);
+                        inputFormat->setInt32("max-height", maxHeight);
+                        inputFormat->setInt32("adaptive-playback", true);
+                    }
+                }
+                // allow failure
+                err = OK;
+            } else {
+                ALOGV("[%s] storeMetaDataInBuffers succeeded",
+                        mComponentName.c_str());
+                mStoreMetaDataInOutputBuffers = true;
+                inputFormat->setInt32("adaptive-playback", true);
+            }
+
+            int32_t push;
+            if (msg->findInt32("push-blank-buffers-on-shutdown", &push)
+                    && push != 0) {
+                mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
+            }
         }
 
         int32_t rotationDegrees;
@@ -1869,6 +1891,27 @@
             mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
 }
 
+status_t ACodec::configureTunneledVideoPlayback(
+        int64_t audioHwSync, const sp<ANativeWindow> &nativeWindow) {
+    native_handle_t* sidebandHandle;
+
+    status_t err = mOMX->configureVideoTunnelMode(
+            mNode, kPortIndexOutput, OMX_TRUE, audioHwSync, &sidebandHandle);
+    if (err != OK) {
+        ALOGE("configureVideoTunnelMode failed! (err %d).", err);
+        return err;
+    }
+
+    err = native_window_set_sideband_stream(nativeWindow.get(), sidebandHandle);
+    if (err != OK) {
+        ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).",
+                sidebandHandle, err);
+        return err;
+    }
+
+    return OK;
+}
+
 status_t ACodec::setVideoPortFormatType(
         OMX_U32 portIndex,
         OMX_VIDEO_CODINGTYPE compressionFormat,
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index aca21cf..ca031aa 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -78,6 +78,10 @@
             node_id node, OMX_U32 port_index, OMX_BOOL enable,
             OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight);
 
+    virtual status_t configureVideoTunnelMode(
+            node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
+
     virtual status_t enableGraphicBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable);
 
@@ -291,6 +295,13 @@
             node, port_index, enable, maxFrameWidth, maxFrameHeight);
 }
 
+status_t MuxOMX::configureVideoTunnelMode(
+        node_id node, OMX_U32 portIndex, OMX_BOOL enable,
+        OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
+    return getOMX(node)->configureVideoTunnelMode(
+            node, portIndex, enable, audioHwSync, sidebandHandle);
+}
+
 status_t MuxOMX::enableGraphicBuffers(
         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
     return getOMX(node)->enableGraphicBuffers(node, port_index, enable);
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index cd51bbf..e8c4970 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -75,6 +75,10 @@
             node_id node, OMX_U32 portIndex, OMX_BOOL enable,
             OMX_U32 max_frame_width, OMX_U32 max_frame_height);
 
+    virtual status_t configureVideoTunnelMode(
+            node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
+
     virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
             buffer_id *buffer);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 3967dc6..dc6d410 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -62,6 +62,10 @@
             OMX_U32 portIndex, OMX_BOOL enable,
             OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight);
 
+    status_t configureVideoTunnelMode(
+            OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
+
     status_t useBuffer(
             OMX_U32 portIndex, const sp<IMemory> &params,
             OMX::buffer_id *buffer);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index cc4770a..41407e4 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -342,6 +342,13 @@
             portIndex, enable, maxFrameWidth, maxFrameHeight);
 }
 
+status_t OMX::configureVideoTunnelMode(
+        node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
+        OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
+    return findInstance(node)->configureVideoTunnelMode(
+            portIndex, tunneled, audioHwSync, sidebandHandle);
+}
+
 status_t OMX::useBuffer(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer) {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index d6ab109..efb27f5 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -460,6 +460,49 @@
     return err;
 }
 
+status_t OMXNodeInstance::configureVideoTunnelMode(
+        OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
+        native_handle_t **sidebandHandle) {
+    Mutex::Autolock autolock(mLock);
+
+    OMX_INDEXTYPE index;
+    OMX_STRING name = const_cast<OMX_STRING>(
+            "OMX.google.android.index.configureVideoTunnelMode");
+
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
+    if (err != OMX_ErrorNone) {
+        ALOGE("configureVideoTunnelMode extension is missing!");
+        return StatusFromOMXError(err);
+    }
+
+    ConfigureVideoTunnelModeParams tunnelParams;
+    tunnelParams.nSize = sizeof(tunnelParams);
+    tunnelParams.nVersion.s.nVersionMajor = 1;
+    tunnelParams.nVersion.s.nVersionMinor = 0;
+    tunnelParams.nVersion.s.nRevision = 0;
+    tunnelParams.nVersion.s.nStep = 0;
+
+    tunnelParams.nPortIndex = portIndex;
+    tunnelParams.bTunneled = tunneled;
+    tunnelParams.nAudioHwSync = audioHwSync;
+    err = OMX_SetParameter(mHandle, index, &tunnelParams);
+    if (err != OMX_ErrorNone) {
+        ALOGE("configureVideoTunnelMode failed! (err %d).", err);
+        return UNKNOWN_ERROR;
+    }
+
+    err = OMX_GetParameter(mHandle, index, &tunnelParams);
+    if (err != OMX_ErrorNone) {
+        ALOGE("GetVideoTunnelWindow failed! (err %d).", err);
+        return UNKNOWN_ERROR;
+    }
+    if (sidebandHandle) {
+        *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;
+    }
+
+    return err;
+}
+
 status_t OMXNodeInstance::useBuffer(
         OMX_U32 portIndex, const sp<IMemory> &params,
         OMX::buffer_id *buffer) {