goldfish-codecs: render vp8 and vp9 on host

Refactor guest vpx decoder to work with host.

BUG: 150378029
Test: presubmit
Merged-In: Ie1ba9b4d3ae1b41c1fbddb0b56faf51f8ef9d0dc
Change-Id: I62fdc8f93a263075da71327f88b266471a03c1a8
diff --git a/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp b/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
index 47c22a3..7ff9fa4 100644
--- a/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
+++ b/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
@@ -76,10 +76,12 @@
 }
 
 static const GoldfishComponent kComponents[] = {
-    { "OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8" },
-    { "OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9" },
-    { "OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc" },
-    { "OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc" },
+        {"OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
+        {"OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
+        {"OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
+        {"OMX.android.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
+        {"OMX.android.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
+        {"OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
 };
 
 static std::vector<GoldfishComponent> kActiveComponents;
diff --git a/system/codecs/omx/vpxdec/Android.mk b/system/codecs/omx/vpxdec/Android.mk
index 6374ac3..ce2ab89 100644
--- a/system/codecs/omx/vpxdec/Android.mk
+++ b/system/codecs/omx/vpxdec/Android.mk
@@ -34,12 +34,21 @@
 	                      libhidlbase_impl_internal \
 	                      libbase
 
+LOCAL_HEADER_LIBRARIES += libui_headers \
+                          libnativewindow_headers \
+                          libhardware_headers \
+                          libarect_headers \
+                          libarect_headers_for_ndk
+
 LOCAL_SHARED_LIBRARIES :=       \
         libbinder               \
         libutils                \
         liblog                  \
         libcutils               \
+        libui                   \
         android.hardware.media.omx@1.0 \
+        android.hardware.graphics.allocator@3.0 \
+        android.hardware.graphics.mapper@3.0 \
         libstagefright_foundation
 
 $(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
diff --git a/system/codecs/omx/vpxdec/GoldfishVPX.cpp b/system/codecs/omx/vpxdec/GoldfishVPX.cpp
index 5b9fb2d..2e7043f 100644
--- a/system/codecs/omx/vpxdec/GoldfishVPX.cpp
+++ b/system/codecs/omx/vpxdec/GoldfishVPX.cpp
@@ -19,11 +19,29 @@
 #include <utils/misc.h>
 //#include "OMX_VideoExt.h"
 
+#define DEBUG 0
+#if DEBUG
+#define DDD(...) ALOGD(__VA_ARGS__)
+#else
+#define DDD(...) ((void)0)
+#endif
+
 #include "GoldfishVPX.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
+#include <OMX_VideoExt.h>
+#include <inttypes.h>
+
+#include <nativebase/nativebase.h>
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <hidl/LegacySupport.h>
+
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
 
 namespace android {
 
@@ -35,19 +53,26 @@
     { OMX_VIDEO_VP9Profile2HDR10Plus, OMX_VIDEO_VP9Level5 },
 };
 
-GoldfishVPX::GoldfishVPX(
-        const char *name,
-        const char *componentRole,
-        OMX_VIDEO_CODINGTYPE codingType,
-        const OMX_CALLBACKTYPE *callbacks,
-        OMX_PTR appData,
-        OMX_COMPONENTTYPE **component)
+GoldfishVPX::GoldfishVPX(const char* name,
+                         const char* componentRole,
+                         OMX_VIDEO_CODINGTYPE codingType,
+                         const OMX_CALLBACKTYPE* callbacks,
+                         OMX_PTR appData,
+                         OMX_COMPONENTTYPE** component,
+                         RenderMode renderMode)
     : GoldfishVideoDecoderOMXComponent(
-            name, componentRole, codingType,
-            codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
-            codingType == OMX_VIDEO_CodingVP8 ?  0 : NELEM(kVP9ProfileLevels),
-            320 /* width */, 240 /* height */, callbacks, appData, component),
+              name,
+              componentRole,
+              codingType,
+              codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
+              codingType == OMX_VIDEO_CodingVP8 ? 0 : NELEM(kVP9ProfileLevels),
+              320 /* width */,
+              240 /* height */,
+              callbacks,
+              appData,
+              component),
       mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
+      mRenderMode(renderMode),
       mEOSStatus(INPUT_DATA_AVAILABLE),
       mCtx(NULL),
       mFrameParallelMode(false),
@@ -55,17 +80,19 @@
       mImg(NULL) {
     // arbitrary from avc/hevc as vpx does not specify a min compression ratio
     const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4;
-    const char *mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9;
-    const size_t kMaxOutputBufferSize = 2560 * 2560 * 3 / 2;
-    initPorts(
-            kNumBuffers, kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
-            kNumBuffers, mime, kMinCompressionRatio);
-    ALOGE("calling constructor of GoldfishVPX");
-    CHECK_EQ(initDecoder(), (status_t)OK);
+    const char* mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8
+                                         : MEDIA_MIMETYPE_VIDEO_VP9;
+    const size_t kMaxOutputBufferSize = 3840 * 2160 * 3 / 2;  // 4k
+    initPorts(kNumBuffers,
+              kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
+              kNumBuffers, mime, kMinCompressionRatio);
+    ALOGI("calling constructor of GoldfishVPX");
+    // wait till later
+    // CHECK_EQ(initDecoder(), (status_t)OK);
 }
 
 GoldfishVPX::~GoldfishVPX() {
-    ALOGE("calling destructor of GoldfishVPX");
+    ALOGI("calling destructor of GoldfishVPX");
     destroyDecoder();
 }
 
@@ -81,25 +108,33 @@
     mCtx = new vpx_codec_ctx_t;
     mCtx->vpversion = mMode == MODE_VP8 ? 8 : 9;
 
+    mCtx->version = mEnableAndroidNativeBuffers ? 200 : 100;
+
     int vpx_err = 0;
     if ((vpx_err = vpx_codec_dec_init(mCtx))) {
         ALOGE("vpx decoder failed to initialize. (%d)", vpx_err);
         return UNKNOWN_ERROR;
     }
 
+    ALOGI("calling init GoldfishVPX ctx %p", mCtx);
     return OK;
 }
 
 status_t GoldfishVPX::destroyDecoder() {
-    vpx_codec_destroy(mCtx);
-    delete mCtx;
-    mCtx = NULL;
+    if (mCtx) {
+        ALOGI("calling destroying GoldfishVPX ctx %p", mCtx);
+        vpx_codec_destroy(mCtx);
+        delete mCtx;
+        mCtx = NULL;
+    }
     return OK;
 }
 
-void GoldfishVPX::setup_ctx_parameters(vpx_codec_ctx_t* ctx) {
+void GoldfishVPX::setup_ctx_parameters(vpx_codec_ctx_t* ctx,
+                                       int hostColorBufferId) {
     ctx->width = mWidth;
     ctx->height = mHeight;
+    ctx->hostColorBufferId = hostColorBufferId;
     ctx->outputBufferWidth = outputBufferWidth();
     ctx->outputBufferHeight = outputBufferHeight();
     OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
@@ -111,6 +146,7 @@
     List<BufferInfo *> &outQueue = getPortQueue(1);
     BufferInfo *outInfo = NULL;
     OMX_BUFFERHEADERTYPE *outHeader = NULL;
+    DDD("%s %d", __func__, __LINE__);
 
     if (flushDecoder && mFrameParallelMode) {
         // Flush decoder by passing NULL data ptr and 0 size.
@@ -136,8 +172,11 @@
     }
 
     while (!outQueue.empty()) {
+        DDD("%s %d", __func__, __LINE__);
+        outInfo = *outQueue.begin();
+        outHeader = outInfo->mHeader;
         if (mImg == NULL) {
-            setup_ctx_parameters(mCtx);
+            setup_ctx_parameters(mCtx, getHostColorBufferId(outHeader));
             mImg = vpx_codec_get_frame(mCtx);
             if (mImg == NULL) {
                 break;
@@ -145,8 +184,6 @@
         }
         uint32_t width = mImg->d_w;
         uint32_t height = mImg->d_h;
-        outInfo = *outQueue.begin();
-        outHeader = outInfo->mHeader;
         CHECK(mImg->fmt == VPX_IMG_FMT_I420 || mImg->fmt == VPX_IMG_FMT_I42016);
         OMX_COLOR_FORMATTYPE outputColorFormat = OMX_COLOR_FormatYUV420Planar;
         int32_t bpp = 1;
@@ -168,11 +205,12 @@
             queueOutputFrameConfig(privInfo->mHdr10PlusInfo);
         }
 
-        if (outputBufferSafe(outHeader)) {
+        if (outputBufferSafe(outHeader) &&
+            getHostColorBufferId(outHeader) < 0) {
             uint8_t *dst = outHeader->pBuffer;
             memcpy(dst, mCtx->dst, outHeader->nFilledLen);
         } else {
-            outHeader->nFilledLen = 0;
+            // outHeader->nFilledLen = 0;
         }
 
         mImg = NULL;
@@ -202,6 +240,7 @@
 }
 
 bool GoldfishVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
+    DDD("%s %d", __func__, __LINE__);
     uint32_t width = outputBufferWidth();
     uint32_t height = outputBufferHeight();
     uint64_t nFilledLen = width;
@@ -221,10 +260,19 @@
 }
 
 void GoldfishVPX::onQueueFilled(OMX_U32 /* portIndex */) {
+    DDD("%s %d", __func__, __LINE__);
     if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
         return;
     }
 
+    if (mCtx == nullptr) {
+        if (OK != initDecoder()) {
+            ALOGE("Failed to initialize decoder");
+            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
+            return;
+        }
+    }
+
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
     bool EOSseen = false;
@@ -313,6 +361,7 @@
 }
 
 void GoldfishVPX::onPortFlushCompleted(OMX_U32 portIndex) {
+    DDD("%s %d", __func__, __LINE__);
     if (portIndex == kInputPortIndex) {
         bool portWillReset = false;
         if (!outputBuffers(
@@ -326,6 +375,7 @@
 }
 
 void GoldfishVPX::onReset() {
+    DDD("%s %d", __func__, __LINE__);
     bool portWillReset = false;
     if (!outputBuffers(
              true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
@@ -336,21 +386,141 @@
     mEOSStatus = INPUT_DATA_AVAILABLE;
 }
 
+int GoldfishVPX::getHostColorBufferId(void* header) {
+    DDD("%s %d", __func__, __LINE__);
+    if (mNWBuffers.find(header) == mNWBuffers.end()) {
+        DDD("cannot find color buffer for header %p", header);
+        return -1;
+    }
+    sp<ANativeWindowBuffer> nBuf = mNWBuffers[header];
+    cb_handle_t* handle = (cb_handle_t*)nBuf->handle;
+    DDD("found color buffer for header %p --> %d", header, handle->hostHandle);
+    return handle->hostHandle;
+}
+
+OMX_ERRORTYPE GoldfishVPX::internalGetParameter(OMX_INDEXTYPE index,
+                                                OMX_PTR params) {
+    const int32_t indexFull = index;
+    switch (indexFull) {
+        case kGetAndroidNativeBufferUsageIndex: {
+            DDD("calling kGetAndroidNativeBufferUsageIndex");
+            GetAndroidNativeBufferUsageParams* nativeBuffersUsage =
+                    (GetAndroidNativeBufferUsageParams*)params;
+            nativeBuffersUsage->nUsage =
+                    (unsigned int)(BufferUsage::GPU_DATA_BUFFER);
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return GoldfishVideoDecoderOMXComponent::internalGetParameter(
+                    index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishVPX::internalSetParameter(OMX_INDEXTYPE index,
+                                                const OMX_PTR params) {
+    // Include extension index OMX_INDEXEXTTYPE.
+    const int32_t indexFull = index;
+
+    switch (indexFull) {
+        case kEnableAndroidNativeBuffersIndex: {
+            DDD("calling kEnableAndroidNativeBuffersIndex");
+            EnableAndroidNativeBuffersParams* enableNativeBuffers =
+                    (EnableAndroidNativeBuffersParams*)params;
+            if (enableNativeBuffers) {
+                mEnableAndroidNativeBuffers = enableNativeBuffers->enable;
+                if (mEnableAndroidNativeBuffers == false) {
+                    mNWBuffers.clear();
+                    DDD("disabled kEnableAndroidNativeBuffersIndex");
+                } else {
+                    DDD("enabled kEnableAndroidNativeBuffersIndex");
+                }
+            }
+            return OMX_ErrorNone;
+        }
+
+        case kUseAndroidNativeBufferIndex: {
+            if (mEnableAndroidNativeBuffers == false) {
+                ALOGE("Error: not enabled Android Native Buffers");
+                return OMX_ErrorBadParameter;
+            }
+            UseAndroidNativeBufferParams* use_buffer_params =
+                    (UseAndroidNativeBufferParams*)params;
+            if (use_buffer_params) {
+                sp<ANativeWindowBuffer> nBuf = use_buffer_params->nativeBuffer;
+                cb_handle_t* handle = (cb_handle_t*)nBuf->handle;
+                void* dst = NULL;
+                DDD("kUseAndroidNativeBufferIndex with handle %p host color "
+                    "handle %d "
+                    "calling usebuffer",
+                    handle, handle->hostHandle);
+                useBufferCallerLockedAlready(use_buffer_params->bufferHeader,
+                                             use_buffer_params->nPortIndex,
+                                             use_buffer_params->pAppPrivate,
+                                             handle->allocatedSize(),
+                                             (OMX_U8*)dst);
+                mNWBuffers[*(use_buffer_params->bufferHeader)] =
+                        use_buffer_params->nativeBuffer;
+                ;
+            }
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return GoldfishVideoDecoderOMXComponent::internalSetParameter(
+                    index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishVPX::getExtensionIndex(const char* name,
+                                             OMX_INDEXTYPE* index) {
+    if (mRenderMode == RenderMode::RENDER_BY_HOST_GPU) {
+        if (!strcmp(name,
+                    "OMX.google.android.index.enableAndroidNativeBuffers")) {
+            DDD("calling getExtensionIndex for enable ANB");
+            *(int32_t*)index = kEnableAndroidNativeBuffersIndex;
+            return OMX_ErrorNone;
+        } else if (!strcmp(name,
+                           "OMX.google.android.index.useAndroidNativeBuffer")) {
+            *(int32_t*)index = kUseAndroidNativeBufferIndex;
+            return OMX_ErrorNone;
+        } else if (!strcmp(name,
+                           "OMX.google.android.index."
+                           "getAndroidNativeBufferUsage")) {
+            *(int32_t*)index = kGetAndroidNativeBufferUsageIndex;
+            return OMX_ErrorNone;
+        }
+    }
+    return GoldfishVideoDecoderOMXComponent::getExtensionIndex(name, index);
+}
+
 }  // namespace android
 
 android::GoldfishOMXComponent *createGoldfishOMXComponent(
         const char *name, const OMX_CALLBACKTYPE *callbacks,
         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
-    if (!strcmp(name, "OMX.google.goldfish.vp8.decoder")) {
+    DDD("%s %d", __func__, __LINE__);
+    // only support vp9 to use host hardware decoder, for now
+    if (!strncmp("OMX.android.goldfish.vp9.decoder", name, 32)) {
         return new android::GoldfishVPX(
-                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8,
-                callbacks, appData, component);
-    } else if (!strcmp(name, "OMX.google.goldfish.vp9.decoder")) {
-        return new android::GoldfishVPX(
-                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9,
-                callbacks, appData, component);
-    } else {
-        CHECK(!"Unknown component");
+                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9, callbacks,
+                appData, component, RenderMode::RENDER_BY_HOST_GPU);
     }
+    if (!strncmp("OMX.android.goldfish.vp8.decoder", name, 32)) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8, callbacks,
+                appData, component, RenderMode::RENDER_BY_HOST_GPU);
+    }
+    if (!strncmp("OMX.google.goldfish.vp9.decoder", name, 30)) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9, callbacks,
+                appData, component, RenderMode::RENDER_BY_GUEST_CPU);
+    }
+    if (!strncmp("OMX.google.goldfish.vp8.decoder", name, 30)) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8, callbacks,
+                appData, component, RenderMode::RENDER_BY_GUEST_CPU);
+    }
+    { CHECK(!"Unknown component"); }
     return NULL;
 }
diff --git a/system/codecs/omx/vpxdec/GoldfishVPX.h b/system/codecs/omx/vpxdec/GoldfishVPX.h
index 2ba8beb..2eb762c 100644
--- a/system/codecs/omx/vpxdec/GoldfishVPX.h
+++ b/system/codecs/omx/vpxdec/GoldfishVPX.h
@@ -21,17 +21,30 @@
 #include "GoldfishVideoDecoderOMXComponent.h"
 #include "goldfish_vpx_defs.h"
 
+#include <sys/time.h>
+
+#include <map>
+#include <vector>
+
+#include <ui/GraphicBuffer.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include "gralloc_cb.h"
+
 namespace android {
 
 struct ABuffer;
 
 struct GoldfishVPX : public GoldfishVideoDecoderOMXComponent {
-    GoldfishVPX(const char *name,
-            const char *componentRole,
-            OMX_VIDEO_CODINGTYPE codingType,
-            const OMX_CALLBACKTYPE *callbacks,
-            OMX_PTR appData,
-            OMX_COMPONENTTYPE **component);
+    GoldfishVPX(const char* name,
+                const char* componentRole,
+                OMX_VIDEO_CODINGTYPE codingType,
+                const OMX_CALLBACKTYPE* callbacks,
+                OMX_PTR appData,
+                OMX_COMPONENTTYPE** component,
+                RenderMode renderMode);
 
 protected:
     virtual ~GoldfishVPX();
@@ -42,6 +55,15 @@
     virtual bool supportDescribeHdrStaticInfo();
     virtual bool supportDescribeHdr10PlusInfo();
 
+    virtual OMX_ERRORTYPE internalGetParameter(OMX_INDEXTYPE index,
+                                               OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index,
+                                               const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE getExtensionIndex(const char* name,
+                                            OMX_INDEXTYPE* index);
+
 private:
     enum {
         kNumBuffers = 10
@@ -52,6 +74,12 @@
         MODE_VP9
     } mMode;
 
+    RenderMode mRenderMode = RenderMode::RENDER_BY_GUEST_CPU;
+    bool mEnableAndroidNativeBuffers = false;
+    std::map<void*, sp<ANativeWindowBuffer>> mNWBuffers;
+
+    int getHostColorBufferId(void* header);
+
     enum {
         INPUT_DATA_AVAILABLE,  // VPX component is ready to decode data.
         INPUT_EOS_SEEN,        // VPX component saw EOS and is flushing On2 decoder.
@@ -73,7 +101,7 @@
     bool outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset);
     bool outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader);
 
-    void setup_ctx_parameters(vpx_codec_ctx_t*);
+    void setup_ctx_parameters(vpx_codec_ctx_t*, int hostColorBufferId = -1);
 
     DISALLOW_EVIL_CONSTRUCTORS(GoldfishVPX);
 };
diff --git a/system/codecs/omx/vpxdec/goldfish_vpx_defs.h b/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
index 1b1358c..25fecde 100644
--- a/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
+++ b/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
@@ -9,6 +9,11 @@
 
 typedef unsigned char uint8_t;
 
+enum class RenderMode {
+    RENDER_BY_HOST_GPU = 1,
+    RENDER_BY_GUEST_CPU = 2,
+};
+
 enum vpx_img_fmt_t {
   VPX_IMG_FMT_NONE,
   VPX_IMG_FMT_YV12 =
@@ -34,6 +39,11 @@
 
 struct vpx_codec_ctx_t {
     int vpversion; //8: vp8 or 9: vp9
+    int version;   // 100: return decoded frame to guest; 200: render on host
+    int hostColorBufferId;
+    uint64_t id;  // >= 1, unique
+    int memory_slot;
+    uint64_t address_offset = 0;
     size_t outputBufferWidth;
     size_t outputBufferHeight;
     size_t width;
@@ -41,11 +51,12 @@
     size_t bpp;
     uint8_t *data;
     uint8_t *dst;
+    vpx_image_t myImg;
 };
 
 int vpx_codec_destroy(vpx_codec_ctx_t*);
 int vpx_codec_dec_init(vpx_codec_ctx_t*);
-vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t*);
+vpx_image_t* vpx_codec_get_frame(vpx_codec_ctx_t*, int hostColorBufferId = -1);
 int vpx_codec_flush(vpx_codec_ctx_t *ctx);
 int vpx_codec_decode(vpx_codec_ctx_t *ctx, const uint8_t *data,
                                  unsigned int data_sz, void *user_priv,
diff --git a/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp b/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
index 0771176..92dfcfa 100644
--- a/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
+++ b/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
@@ -14,27 +14,73 @@
 #include "goldfish_vpx_defs.h"
 #include "goldfish_media_utils.h"
 
-static vpx_image_t myImg;
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#define DEBUG 0
+#if DEBUG
+#define DDD(...) ALOGD(__VA_ARGS__)
+#else
+#define DDD(...) ((void)0)
+#endif
+
+// static vpx_image_t myImg;
+static uint64_t s_CtxId = 0;
+static std::mutex sCtxidMutex;
+
+static uint64_t applyForOneId() {
+    DDD("%s %d", __func__, __LINE__);
+    std::lock_guard<std::mutex> g{sCtxidMutex};
+    ++s_CtxId;
+    return s_CtxId;
+}
 
 static void sendVpxOperation(vpx_codec_ctx_t* ctx, MediaOperation op) {
+    DDD("%s %d", __func__, __LINE__);
+    if (ctx->memory_slot < 0) {
+        ALOGE("ERROR: Failed %s %d: there is no memory slot", __func__,
+              __LINE__);
+    }
     auto transport = GoldfishMediaTransport::getInstance();
-    transport->sendOperation(
-            ctx->vpversion == 8 ?
-                MediaCodecType::VP8Codec :
-                MediaCodecType::VP9Codec,
-            op);
+    transport->sendOperation(ctx->vpversion == 9 ? MediaCodecType::VP9Codec
+                                                 : MediaCodecType::VP8Codec,
+                             op, ctx->address_offset);
 }
 
 int vpx_codec_destroy(vpx_codec_ctx_t* ctx) {
+    DDD("%s %d", __func__, __LINE__);
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::DestroyContext);
+    transport->returnMemorySlot(ctx->memory_slot);
+    ctx->memory_slot = -1;
     return 0;
 }
 
 int vpx_codec_dec_init(vpx_codec_ctx_t* ctx) {
+    DDD("%s %d", __func__, __LINE__);
     auto transport = GoldfishMediaTransport::getInstance();
+    int slot = transport->getMemorySlot();
+    if (slot < 0) {
+        ALOGE("ERROR: Failed %s %d: cannot get memory slot", __func__,
+              __LINE__);
+        return -1;
+    } else {
+        DDD("got slot %d", slot);
+    }
+    ctx->id = applyForOneId();
+    ctx->memory_slot = slot;
+    ctx->address_offset = static_cast<unsigned int>(slot) * 8 * (1 << 20);
+    DDD("got address offset 0x%x version %d", (int)(ctx->address_offset),
+        ctx->version);
+
     // data and dst are on the host side actually
-    ctx->data = transport->getInputAddr();
-    ctx->dst = transport->getOutputAddr();
+    ctx->data = transport->getInputAddr(ctx->address_offset);
+    ctx->dst = transport->getInputAddr(
+            ctx->address_offset);  // re-use input address
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
+    transport->writeParam(ctx->version, 1, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::InitContext);
     return 0;
 }
@@ -44,7 +90,9 @@
     return *pint;
 }
 
-static void getVpxFrame(uint8_t* ptr) {
+// vpx_image_t myImg;
+static void getVpxFrame(uint8_t* ptr, vpx_image_t& myImg) {
+    DDD("%s %d", __func__, __LINE__);
     uint8_t* imgptr = (ptr + 8);
     myImg.fmt = *(vpx_img_fmt_t*)imgptr;
     imgptr += 8;
@@ -53,31 +101,41 @@
     myImg.d_h = *(unsigned int *)imgptr;
     imgptr += 8;
     myImg.user_priv = (void*)(*(uint64_t*)imgptr);
+    DDD("fmt %d dw %d dh %d userpriv %p", (int)myImg.fmt, (int)myImg.d_w,
+        (int)myImg.d_h, myImg.user_priv);
 }
 
 //TODO: we might not need to do the putting all the time
-vpx_image_t* vpx_codec_get_frame(vpx_codec_ctx_t* ctx) {
+vpx_image_t* vpx_codec_get_frame(vpx_codec_ctx_t* ctx, int hostColorBufferId) {
+    DDD("%s %d %p", __func__, __LINE__);
     auto transport = GoldfishMediaTransport::getInstance();
 
-    transport->writeParam(ctx->outputBufferWidth, 0);
-    transport->writeParam(ctx->outputBufferHeight, 1);
-    transport->writeParam(ctx->width, 2);
-    transport->writeParam(ctx->height, 3);
-    transport->writeParam(ctx->bpp, 4);
-    transport->writeParam(transport->offsetOf((uint64_t)(ctx->dst)), 5);
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
+    transport->writeParam(ctx->outputBufferWidth, 1, ctx->address_offset);
+    transport->writeParam(ctx->outputBufferHeight, 2, ctx->address_offset);
+    transport->writeParam(ctx->width, 3, ctx->address_offset);
+    transport->writeParam(ctx->height, 4, ctx->address_offset);
+    transport->writeParam(ctx->bpp, 5, ctx->address_offset);
+    transport->writeParam(ctx->hostColorBufferId, 6, ctx->address_offset);
+    transport->writeParam(
+            transport->offsetOf((uint64_t)(ctx->dst)) - ctx->address_offset, 7,
+            ctx->address_offset);
 
     sendVpxOperation(ctx, MediaOperation::GetImage);
 
-    auto* retptr = transport->getReturnAddr();
+    auto* retptr = transport->getReturnAddr(ctx->address_offset);
     int ret = getReturnCode(retptr);
     if (ret) {
         return nullptr;
     }
-    getVpxFrame(retptr);
-    return &myImg;
+    getVpxFrame(retptr, ctx->myImg);
+    return &(ctx->myImg);
 }
 
 int vpx_codec_flush(vpx_codec_ctx_t* ctx) {
+    DDD("%s %d", __func__, __LINE__);
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::Flush);
     return 0;
 }
@@ -87,12 +145,17 @@
                      unsigned int data_sz,
                      void* user_priv,
                      long deadline) {
+    DDD("%s %d data size %d userpriv %p", __func__, __LINE__, (int)data_sz,
+        user_priv);
     auto transport = GoldfishMediaTransport::getInstance();
     memcpy(ctx->data, data, data_sz);
 
-    transport->writeParam(transport->offsetOf((uint64_t)(ctx->data)), 0);
-    transport->writeParam((__u64)data_sz, 1);
-    transport->writeParam((__u64)user_priv, 2);
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
+    transport->writeParam(
+            transport->offsetOf((uint64_t)(ctx->data)) - ctx->address_offset, 1,
+            ctx->address_offset);
+    transport->writeParam((__u64)data_sz, 2, ctx->address_offset);
+    transport->writeParam((__u64)user_priv, 3, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::DecodeImage);
     return 0;
 }