Merge "Experimental support for enabling the use of "surface input" mode"
diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk
index a92d376..4060a0a 100644
--- a/media/libstagefright/codecs/on2/enc/Android.mk
+++ b/media/libstagefright/codecs/on2/enc/Android.mk
@@ -12,11 +12,16 @@
         frameworks/av/media/libstagefright/include \
         frameworks/native/include/media/openmax \
 
+ifeq ($(TARGET_DEVICE), manta)
+    LOCAL_CFLAGS += -DSURFACE_IS_BGR32
+endif
+
 LOCAL_STATIC_LIBRARIES := \
         libvpx
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog \
+        libhardware \
 
 LOCAL_MODULE := libstagefright_soft_vpxenc
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 74d6df5..d8456fe 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -20,6 +20,8 @@
 
 #include <utils/Log.h>
 
+#include <media/hardware/HardwareAPI.h>
+#include <media/hardware/MetadataBufferType.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
@@ -81,6 +83,52 @@
     }
 }
 
+static void ConvertRGB32ToPlanar(
+        const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) {
+    CHECK((width & 1) == 0);
+    CHECK((height & 1) == 0);
+
+    uint8_t *dstU = dstY + width * height;
+    uint8_t *dstV = dstU + (width / 2) * (height / 2);
+
+    for (int32_t y = 0; y < height; ++y) {
+        for (int32_t x = 0; x < width; ++x) {
+#ifdef SURFACE_IS_BGR32
+            unsigned blue = src[4 * x];
+            unsigned green = src[4 * x + 1];
+            unsigned red= src[4 * x + 2];
+#else
+            unsigned red= src[4 * x];
+            unsigned green = src[4 * x + 1];
+            unsigned blue = src[4 * x + 2];
+#endif
+
+            unsigned luma =
+                ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
+
+            dstY[x] = luma;
+
+            if ((x & 1) == 0 && (y & 1) == 0) {
+                unsigned U =
+                    ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
+
+                unsigned V =
+                    ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
+
+                dstU[x / 2] = U;
+                dstV[x / 2] = V;
+            }
+        }
+
+        if ((y & 1) == 0) {
+            dstU += width / 2;
+            dstV += width / 2;
+        }
+
+        src += 4 * width;
+        dstY += width;
+    }
+}
 
 SoftVPXEncoder::SoftVPXEncoder(const char *name,
                                const OMX_CALLBACKTYPE *callbacks,
@@ -99,8 +147,9 @@
       mErrorResilience(OMX_FALSE),
       mColorFormat(OMX_COLOR_FormatYUV420Planar),
       mLevel(OMX_VIDEO_VP8Level_Version0),
-      mConversionBuffer(NULL) {
-
+      mConversionBuffer(NULL),
+      mInputDataIsMeta(false),
+      mGrallocModule(NULL) {
     initPorts();
 }
 
@@ -247,7 +296,7 @@
         return UNKNOWN_ERROR;
     }
 
-    if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
+    if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) {
         if (mConversionBuffer == NULL) {
             mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
             if (mConversionBuffer == NULL) {
@@ -427,9 +476,17 @@
                 (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
 
         case OMX_IndexParamPortDefinition:
-            return internalSetPortParams(
+        {
+            OMX_ERRORTYPE err = internalSetPortParams(
                 (const OMX_PARAM_PORTDEFINITIONTYPE *)param);
 
+            if (err != OMX_ErrorNone) {
+                return err;
+            }
+
+            return SimpleSoftOMXComponent::internalSetParameter(index, param);
+        }
+
         case OMX_IndexParamVideoPortFormat:
             return internalSetFormatParams(
                 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param);
@@ -442,6 +499,21 @@
             return internalSetProfileLevel(
                 (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);
 
+        case OMX_IndexVendorStartUnused:
+        {
+            // storeMetaDataInBuffers
+            const StoreMetaDataInBuffersParams *storeParam =
+                (const StoreMetaDataInBuffersParams *)param;
+
+            if (storeParam->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, param);
     }
@@ -507,6 +579,10 @@
             format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
             format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
             mColorFormat = format->eColorFormat;
+
+            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
+            def->format.video.eColorFormat = mColorFormat;
+
             return OMX_ErrorNone;
         } else {
             ALOGE("Unsupported color format %i", format->eColorFormat);
@@ -552,11 +628,17 @@
         if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
             port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
             port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
-                mColorFormat = port->format.video.eColorFormat;
+            mColorFormat = port->format.video.eColorFormat;
         } else {
             return OMX_ErrorUnsupportedSetting;
         }
 
+        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
+        def->format.video.nFrameWidth = mWidth;
+        def->format.video.nFrameHeight = mHeight;
+        def->format.video.xFramerate = port->format.video.xFramerate;
+        def->format.video.eColorFormat = mColorFormat;
+
         return OMX_ErrorNone;
     } else if (port->nPortIndex == kOutputPortIndex) {
         mBitrate = port->format.video.nBitrate;
@@ -625,24 +707,56 @@
             return;
         }
 
-        uint8_t* source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
+        uint8_t *source =
+            inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
 
-        // NOTE: As much as nothing is known about color format
-        // when it is denoted as AndroidOpaque, it is at least
-        // assumed to be planar.
-        if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
-            ConvertSemiPlanarToPlanar(source, mConversionBuffer, mWidth, mHeight);
+        if (mInputDataIsMeta) {
+            CHECK_GE(inputBufferHeader->nFilledLen,
+                     4 + sizeof(buffer_handle_t));
+
+            uint32_t bufferType = *(uint32_t *)source;
+            CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource);
+
+            if (mGrallocModule == NULL) {
+                CHECK_EQ(0, hw_get_module(
+                            GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
+            }
+
+            const gralloc_module_t *grmodule =
+                (const gralloc_module_t *)mGrallocModule;
+
+            buffer_handle_t handle = *(buffer_handle_t *)(source + 4);
+
+            void *bits;
+            CHECK_EQ(0,
+                     grmodule->lock(
+                         grmodule, handle,
+                         GRALLOC_USAGE_SW_READ_OFTEN
+                            | GRALLOC_USAGE_SW_WRITE_NEVER,
+                         0, 0, mWidth, mHeight, &bits));
+
+            ConvertRGB32ToPlanar(
+                    (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight);
+
+            source = mConversionBuffer;
+
+            CHECK_EQ(0, grmodule->unlock(grmodule, handle));
+        } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
+            ConvertSemiPlanarToPlanar(
+                    source, mConversionBuffer, mWidth, mHeight);
+
             source = mConversionBuffer;
         }
         vpx_image_t raw_frame;
         vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
                      kInputBufferAlignment, source);
-        codec_return = vpx_codec_encode(mCodecContext,
-                                        &raw_frame,
-                                        inputBufferHeader->nTimeStamp,  // in timebase units
-                                        mFrameDurationUs,  // frame duration in timebase units
-                                        0,  // frame flags
-                                        VPX_DL_REALTIME);  // encoding deadline
+        codec_return = vpx_codec_encode(
+                mCodecContext,
+                &raw_frame,
+                inputBufferHeader->nTimeStamp,  // in timebase units
+                mFrameDurationUs,  // frame duration in timebase units
+                0,  // frame flags
+                VPX_DL_REALTIME);  // encoding deadline
         if (codec_return != VPX_CODEC_OK) {
             ALOGE("vpx encoder failed to encode frame");
             notify(OMX_EventError,
@@ -676,6 +790,17 @@
         notifyEmptyBufferDone(inputBufferHeader);
     }
 }
+
+OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex(
+        const char *name, OMX_INDEXTYPE *index) {
+    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
+        *index = OMX_IndexVendorStartUnused;
+        return OMX_ErrorNone;
+    }
+
+    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
+}
+
 }  // namespace android
 
 
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index a0a8ee6..d570154 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -23,6 +23,8 @@
 #include <OMX_VideoExt.h>
 #include <OMX_IndexExt.h>
 
+#include <hardware/gralloc.h>
+
 #include "vpx/vpx_encoder.h"
 #include "vpx/vpx_codec.h"
 #include "vpx/vp8cx.h"
@@ -57,14 +59,13 @@
 //    - OMX timestamps are in microseconds, therefore
 // encoder timebase is fixed to 1/1000000
 
-class SoftVPXEncoder : public SimpleSoftOMXComponent {
- public:
+struct SoftVPXEncoder : public SimpleSoftOMXComponent {
     SoftVPXEncoder(const char *name,
                    const OMX_CALLBACKTYPE *callbacks,
                    OMX_PTR appData,
                    OMX_COMPONENTTYPE **component);
 
- protected:
+protected:
     virtual ~SoftVPXEncoder();
 
     // Returns current values for requested OMX
@@ -83,7 +84,10 @@
     // encoding of the frame
     virtual void onQueueFilled(OMX_U32 portIndex);
 
- private:
+    virtual OMX_ERRORTYPE getExtensionIndex(
+            const char *name, OMX_INDEXTYPE *index);
+
+private:
     // number of buffers allocated per port
     static const uint32_t kNumBuffers = 4;
 
@@ -156,6 +160,9 @@
     // indeed YUV420SemiPlanar.
     uint8_t* mConversionBuffer;
 
+    bool mInputDataIsMeta;
+    const hw_module_t *mGrallocModule;
+
     // Initializes input and output OMX ports with sensible
     // default values.
     void initPorts();