Reland "codec2: C2VDAAdaptorProxy Implementation"

This reverts commit 9900faa4256aec6debdcfbd05ba396847694967c.

Reason for revert: This CL doesn't break build now.

Change-Id: I04480777ac9af477ad844917974490c8d5fb8669
diff --git a/Android.mk b/Android.mk
index c9588db..bc712d1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -38,6 +38,24 @@
 
 LOCAL_LDFLAGS := -Wl,-Bsymbolic
 
+# Build C2VDAAdaptorProxy only for ARC++ case.
+ifneq (,$(findstring cheets_,$(TARGET_PRODUCT)))
+
+LOCAL_CFLAGS += -DV4L2_CODEC2_ARC
+LOCAL_SRC_FILES += C2VDAAdaptorProxy.cpp
+LOCAL_SRC_FILES := $(filter-out C2VDAAdaptor.cpp, $(LOCAL_SRC_FILES))
+LOCAL_SHARED_LIBRARIES += libarcbridge \
+                          libarcbridgeservice \
+                          libarcvideobridge \
+                          libmojo \
+
+ANDROID_VERSION := $(word 1, $(subst ., , $(PLATFORM_VERSION)))
+ifeq ($(ANDROID_VERSION),7)  # NYC
+LOCAL_CFLAGS += -DANDROID_VERSION_NYC
+endif
+
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/C2VDAAdaptorProxy.cpp b/C2VDAAdaptorProxy.cpp
new file mode 100644
index 0000000..dcf76f2
--- /dev/null
+++ b/C2VDAAdaptorProxy.cpp
@@ -0,0 +1,427 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "C2VDAAdaptorProxy"
+
+#include <C2VDAAdaptorProxy.h>
+
+#include <videodev2.h>
+
+#include <arc/MojoProcessSupport.h>
+#include <arc/MojoThread.h>
+#include <base/bind.h>
+#include <binder/IServiceManager.h>
+#include <media/arcvideobridge/IArcVideoBridge.h>
+#include <mojo/edk/embedder/embedder.h>
+#include <mojo/public/cpp/system/handle.h>
+#include <utils/Log.h>
+#include <utils/Singleton.h>
+
+namespace mojo {
+// TODO(hiroh): Remove this ifdef workaround
+#ifdef ANDROID_VERSION_NYC
+template <>
+struct TypeConverter<::arc::VideoFramePlane, android::VideoFramePlane> {
+    static ::arc::VideoFramePlane Convert(const android::VideoFramePlane& plane) {
+        return ::arc::VideoFramePlane{static_cast<int32_t>(plane.mOffset),
+                                      static_cast<int32_t>(plane.mStride)};
+    }
+};
+#else
+template <>
+struct TypeConverter<::arc::mojom::VideoFramePlanePtr, android::VideoFramePlane> {
+    static ::arc::mojom::VideoFramePlanePtr Convert(const android::VideoFramePlane& plane) {
+        ::arc::mojom::VideoFramePlanePtr result = ::arc::mojom::VideoFramePlane::New();
+        result->offset = plane.mOffset;
+        result->stride = plane.mStride;
+        return result;
+    }
+};
+#endif
+}  // namespace mojo
+
+namespace android {
+
+// Helper class to create message pipe to the VideoDecodeAccelerator.
+// This class should only be used in the Mojo thread.
+class VideoDecodeAcceleratorFactory : public Singleton<VideoDecodeAcceleratorFactory> {
+public:
+    bool create(::arc::mojom::VideoDecodeAcceleratorRequest request) {
+        if (!mRemoteFactory) {
+            ALOGE("Factory is not ready");
+            return false;
+        }
+        mRemoteFactory->CreateDecodeAccelerator(std::move(request));
+        return true;
+    }
+    int32_t hostVersion() { return mHostVersion; }
+
+private:
+    VideoDecodeAcceleratorFactory() : mHostVersion(0) {
+        sp<IBinder> binder =
+                defaultServiceManager()->getService(String16("android.os.IArcVideoBridge"));
+        mArcVideoBridge = interface_cast<IArcVideoBridge>(binder);
+        mHostVersion = mArcVideoBridge->hostVersion();
+        ALOGV("HostVersion: %d", mHostVersion);
+
+        if (mHostVersion < 4) {
+            ALOGW("HostVersion(%d) is outdated", mHostVersion);
+            return;
+        }
+        ::arc::MojoBootstrapResult bootstrapResult =
+                mArcVideoBridge->bootstrapVideoAcceleratorFactory();
+        if (!bootstrapResult.is_valid()) {
+            ALOGE("bootstrapVideoAcceleratorFactory returns invalid result");
+            return;
+        }
+        mojo::edk::ScopedPlatformHandle handle(
+                mojo::edk::PlatformHandle(bootstrapResult.releaseFd().release()));
+        ALOGV("SetParentPipeHandle(fd=%d)", handle.get().handle);
+        mojo::edk::SetParentPipeHandle(std::move(handle));
+        mojo::ScopedMessagePipeHandle server_pipe =
+                mojo::edk::CreateChildMessagePipe(bootstrapResult.releaseToken());
+        // TODO(hiroh): query the latest version of VideoAcceleratorFactory on Chrome via mojo,
+        //              instead of putting fixed number.
+        mRemoteFactory.Bind(mojo::InterfacePtrInfo<::arc::mojom::VideoAcceleratorFactory>(
+                std::move(server_pipe), 2u));
+    }
+
+    uint32_t mHostVersion;
+    ::arc::mojom::VideoAcceleratorFactoryPtr mRemoteFactory;
+    sp<IArcVideoBridge> mArcVideoBridge;
+    friend class Singleton<VideoDecodeAcceleratorFactory>;
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(VideoDecodeAcceleratorFactory)
+
+namespace arc {
+constexpr SupportedPixelFormat kSupportedPixelFormats[] = {
+        // {mCrcb, mSemiplanar, mPixelFormat}
+        {false, true, HalPixelFormat::NV12},
+        {true, false, HalPixelFormat::YV12},
+        // Add more buffer formats when needed
+};
+
+C2VDAAdaptorProxy::C2VDAAdaptorProxy()
+      : C2VDAAdaptorProxy(::arc::MojoProcessSupport::getLeakyInstance()) {}
+
+C2VDAAdaptorProxy::C2VDAAdaptorProxy(::arc::MojoProcessSupport* mojoProcessSupport)
+      : mClient(nullptr),
+        mMojoTaskRunner(mojoProcessSupport->mojo_thread().getTaskRunner()),
+        mBinding(this),
+        mRelay(new ::arc::CancellationRelay()) {}
+
+C2VDAAdaptorProxy::~C2VDAAdaptorProxy() {}
+
+void C2VDAAdaptorProxy::onConnectionError(const std::string& pipeName) {
+    ALOGE("onConnectionError (%s)", pipeName.c_str());
+    mRelay->cancel();
+    NotifyError(::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE);
+}
+
+bool C2VDAAdaptorProxy::establishChannel() {
+    ALOGV("establishChannel");
+    ::arc::Future<bool> future(mRelay);
+    mMojoTaskRunner->PostTask(FROM_HERE,
+                              base::Bind(&C2VDAAdaptorProxy::establishChannelOnMojoThread,
+                                         base::Unretained(this), base::Unretained(&future)));
+    return future.wait() && future.get();
+}
+
+void C2VDAAdaptorProxy::establishChannelOnMojoThread(::arc::Future<bool>* future) {
+    VideoDecodeAcceleratorFactory& factory = VideoDecodeAcceleratorFactory::getInstance();
+
+    if (!factory.create(mojo::MakeRequest(&mVDAPtr))) {
+        future->set(false);
+        return;
+    }
+    mVDAPtr.set_connection_error_handler(base::Bind(&C2VDAAdaptorProxy::onConnectionError,
+                                                    base::Unretained(this),
+                                                    std::string("mVDAPtr (vda pipe)")));
+    mVDAPtr.QueryVersion(base::Bind(&C2VDAAdaptorProxy::onVersionReady, base::Unretained(this),
+                                    base::Unretained(future)));
+}
+
+void C2VDAAdaptorProxy::onVersionReady(::arc::Future<bool>* future, uint32_t version) {
+    ALOGI("VideoDecodeAccelerator ready (version=%d)", version);
+
+    future->set(true);
+}
+
+void C2VDAAdaptorProxy::ProvidePictureBuffers(::arc::mojom::PictureBufferFormatPtr format) {
+    ALOGV("ProvidePictureBuffers");
+    // TODO(hiroh): Remove this ifdef workaround
+    mClient->providePictureBuffers(
+            format->min_num_buffers,
+#ifdef ANDROID_VERSION_NYC
+            media::Size(format->coded_size.width(), format->coded_size.height()));
+#else
+            media::Size(format->coded_size->width, format->coded_size->height));
+#endif
+}
+void C2VDAAdaptorProxy::PictureReady(::arc::mojom::PicturePtr picture) {
+    ALOGV("PictureReady");
+    const auto& rect = picture->crop_rect;
+    // TODO(hiroh): Remove this ifdef workaround
+    mClient->pictureReady(picture->picture_buffer_id, picture->bitstream_id,
+#ifdef ANDROID_VERSION_NYC
+                          media::Rect(rect.x(), rect.y(), rect.right(), rect.bottom()));
+#else
+                          media::Rect(rect->left, rect->top, rect->right, rect->bottom));
+#endif
+}
+
+static VideoDecodeAcceleratorAdaptor::Result convertErrorCode(
+        ::arc::mojom::VideoDecodeAccelerator::Result error) {
+    switch (error) {
+    case ::arc::mojom::VideoDecodeAccelerator::Result::ILLEGAL_STATE:
+        return VideoDecodeAcceleratorAdaptor::ILLEGAL_STATE;
+    case ::arc::mojom::VideoDecodeAccelerator::Result::INVALID_ARGUMENT:
+        return VideoDecodeAcceleratorAdaptor::INVALID_ARGUMENT;
+    case ::arc::mojom::VideoDecodeAccelerator::Result::UNREADABLE_INPUT:
+        return VideoDecodeAcceleratorAdaptor::UNREADABLE_INPUT;
+    case ::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE:
+        return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE;
+    case ::arc::mojom::VideoDecodeAccelerator::Result::INSUFFICIENT_RESOURCES:
+        return VideoDecodeAcceleratorAdaptor::INSUFFICIENT_RESOURCES;
+
+    default:
+        ALOGE("Unknown error code: %d", static_cast<int>(error));
+        return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE;
+    }
+}
+
+void C2VDAAdaptorProxy::NotifyError(::arc::mojom::VideoDecodeAccelerator::Result error) {
+    ALOGE("NotifyError %d", static_cast<int>(error));
+    mClient->notifyError(convertErrorCode(error));
+}
+
+void C2VDAAdaptorProxy::NotifyEndOfBitstreamBuffer(int32_t bitstream_id) {
+    ALOGV("NotifyEndOfBitstreamBuffer");
+    mClient->notifyEndOfBitstreamBuffer(bitstream_id);
+}
+
+void C2VDAAdaptorProxy::NotifyResetDone(::arc::mojom::VideoDecodeAccelerator::Result result) {
+    ALOGV("NotifyResetDone");
+    if (result != ::arc::mojom::VideoDecodeAccelerator::Result::SUCCESS) {
+        ALOGE("Reset is done incorrectly.");
+        NotifyError(result);
+        return;
+    }
+    mClient->notifyResetDone();
+}
+
+void C2VDAAdaptorProxy::NotifyFlushDone(::arc::mojom::VideoDecodeAccelerator::Result result) {
+    ALOGV("NotifyFlushDone");
+    if (result == ::arc::mojom::VideoDecodeAccelerator::Result::CANCELLED) {
+        // Flush is cancelled by a succeeding Reset(). A client expects this behavior.
+        ALOGE("Flush is canceled.");
+        return;
+    }
+    if (result != ::arc::mojom::VideoDecodeAccelerator::Result::SUCCESS) {
+        ALOGE("Flush is done incorrectly.");
+        NotifyError(result);
+        return;
+    }
+    mClient->notifyFlushDone();
+}
+
+//static
+media::VideoDecodeAccelerator::SupportedProfiles C2VDAAdaptorProxy::GetSupportedProfiles(
+        uint32_t inputFormatFourcc) {
+    media::VideoDecodeAccelerator::SupportedProfiles profiles(1);
+    profiles[0].min_resolution = media::Size(16, 16);
+    profiles[0].max_resolution = media::Size(4096, 4096);
+    switch (inputFormatFourcc) {
+    case V4L2_PIX_FMT_H264:
+    case V4L2_PIX_FMT_H264_SLICE:
+        profiles[0].profile = media::H264PROFILE_MAIN;
+        break;
+    case V4L2_PIX_FMT_VP8:
+    case V4L2_PIX_FMT_VP8_FRAME:
+        profiles[0].profile = media::VP8PROFILE_ANY;
+        break;
+    case V4L2_PIX_FMT_VP9:
+    case V4L2_PIX_FMT_VP9_FRAME:
+        profiles[0].profile = media::VP9PROFILE_PROFILE0;
+        break;
+    default:
+        ALOGE("Unknown formatfourcc: %d", inputFormatFourcc);
+        return {};
+    }
+    return profiles;
+}
+
+//static
+HalPixelFormat C2VDAAdaptorProxy::ResolveBufferFormat(bool crcb, bool semiplanar) {
+    auto value = std::find_if(std::begin(kSupportedPixelFormats), std::end(kSupportedPixelFormats),
+                              [crcb, semiplanar](const struct SupportedPixelFormat& f) {
+                                  return f.mCrcb == crcb && f.mSemiplanar == semiplanar;
+                              });
+    LOG_ALWAYS_FATAL_IF(value == std::end(kSupportedPixelFormats),
+                        "Unsupported pixel format: (crcb=%d, semiplanar=%d)", crcb, semiplanar);
+    return value->mPixelFormat;
+}
+
+VideoDecodeAcceleratorAdaptor::Result C2VDAAdaptorProxy::initialize(
+        media::VideoCodecProfile profile, bool secureMode,
+        VideoDecodeAcceleratorAdaptor::Client* client) {
+    ALOGV("initialize(profile=%d, secureMode=%d)", static_cast<int>(profile),
+          static_cast<int>(secureMode));
+    DCHECK(client);
+    DCHECK(!mClient);
+    mClient = client;
+
+    if (!establishChannel()) {
+        ALOGE("establishChannel failed");
+        return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE;
+    }
+
+    ::arc::Future<::arc::mojom::VideoDecodeAccelerator::Result> future(mRelay);
+    mMojoTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAAdaptorProxy::initializeOnMojoThread,
+                                                    base::Unretained(this), profile, secureMode,
+                                                    ::arc::FutureCallback(&future)));
+
+    if (!future.wait()) {
+        ALOGE("Connection lost");
+        return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE;
+    }
+    return static_cast<VideoDecodeAcceleratorAdaptor::Result>(future.get());
+}
+
+void C2VDAAdaptorProxy::initializeOnMojoThread(
+        const media::VideoCodecProfile profile, const bool secureMode,
+        const ::arc::mojom::VideoDecodeAccelerator::InitializeCallback& cb) {
+    // base::Unretained is safe because we own |mBinding|.
+    auto client = mBinding.CreateInterfacePtrAndBind();
+    mBinding.set_connection_error_handler(base::Bind(&C2VDAAdaptorProxy::onConnectionError,
+                                                     base::Unretained(this),
+                                                     std::string("mBinding (client pipe)")));
+
+    ::arc::mojom::VideoDecodeAcceleratorConfigPtr arcConfig =
+            ::arc::mojom::VideoDecodeAcceleratorConfig::New();
+    arcConfig->secure_mode = secureMode;
+    arcConfig->profile = static_cast<::arc::mojom::VideoCodecProfile>(profile);
+    mVDAPtr->Initialize(std::move(arcConfig), std::move(client), cb);
+}
+
+void C2VDAAdaptorProxy::decode(int32_t bitstreamId, int handleFd, off_t offset, uint32_t size) {
+    ALOGV("decode");
+    mMojoTaskRunner->PostTask(
+            FROM_HERE, base::Bind(&C2VDAAdaptorProxy::decodeOnMojoThread, base::Unretained(this),
+                                  bitstreamId, handleFd, offset, size));
+}
+
+void C2VDAAdaptorProxy::decodeOnMojoThread(int32_t bitstreamId, int handleFd, off_t offset,
+                                           uint32_t size) {
+    MojoHandle wrappedHandle;
+    MojoResult wrapResult = mojo::edk::CreatePlatformHandleWrapper(
+            mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(handleFd)), &wrappedHandle);
+    if (wrapResult != MOJO_RESULT_OK) {
+        ALOGE("failed to wrap handle: %d", static_cast<int>(wrapResult));
+        NotifyError(::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE);
+        return;
+    }
+    auto bufferPtr = ::arc::mojom::BitstreamBuffer::New();
+    bufferPtr->bitstream_id = bitstreamId;
+    bufferPtr->handle_fd = mojo::ScopedHandle(mojo::Handle(wrappedHandle));
+    bufferPtr->offset = offset;
+    bufferPtr->bytes_used = size;
+    mVDAPtr->Decode(std::move(bufferPtr));
+}
+
+void C2VDAAdaptorProxy::assignPictureBuffers(uint32_t numOutputBuffers) {
+    ALOGV("assignPictureBuffers: %d", numOutputBuffers);
+    mMojoTaskRunner->PostTask(FROM_HERE,
+                              base::Bind(&C2VDAAdaptorProxy::assignPictureBuffersOnMojoThread,
+                                         base::Unretained(this), numOutputBuffers));
+}
+
+void C2VDAAdaptorProxy::assignPictureBuffersOnMojoThread(uint32_t numOutputBuffers) {
+    mVDAPtr->AssignPictureBuffers(numOutputBuffers);
+}
+
+void C2VDAAdaptorProxy::importBufferForPicture(int32_t pictureBufferId, HalPixelFormat format,
+                                               int handleFd,
+                                               const std::vector<VideoFramePlane>& planes) {
+    ALOGV("importBufferForPicture");
+    mMojoTaskRunner->PostTask(
+            FROM_HERE,
+            base::Bind(&C2VDAAdaptorProxy::importBufferForPictureOnMojoThread,
+                       base::Unretained(this), pictureBufferId, format, handleFd, planes));
+}
+
+void C2VDAAdaptorProxy::importBufferForPictureOnMojoThread(
+        int32_t pictureBufferId, HalPixelFormat format, int handleFd,
+        const std::vector<VideoFramePlane>& planes) {
+    MojoHandle wrappedHandle;
+    MojoResult wrapResult = mojo::edk::CreatePlatformHandleWrapper(
+            mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(handleFd)), &wrappedHandle);
+    if (wrapResult != MOJO_RESULT_OK) {
+        ALOGE("failed to wrap handle: %d", static_cast<int>(wrapResult));
+        NotifyError(::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE);
+        return;
+    }
+
+    // TODO(hiroh): Remove this ifdef workaround
+    mVDAPtr->ImportBufferForPicture(pictureBufferId,
+                                    static_cast<::arc::mojom::HalPixelFormat>(format),
+                                    mojo::ScopedHandle(mojo::Handle(wrappedHandle)),
+#ifdef ANDROID_VERSION_NYC
+                                    mojo::ConvertTo<std::vector<::arc::VideoFramePlane>>(planes));
+#else
+                                    mojo::ConvertTo<std::vector<::arc::mojom::VideoFramePlanePtr>>(
+                                            planes));
+#endif
+}
+
+void C2VDAAdaptorProxy::reusePictureBuffer(int32_t pictureBufferId) {
+    ALOGV("reusePictureBuffer: %d", pictureBufferId);
+    mMojoTaskRunner->PostTask(FROM_HERE,
+                              base::Bind(&C2VDAAdaptorProxy::reusePictureBufferOnMojoThread,
+                                         base::Unretained(this), pictureBufferId));
+}
+
+void C2VDAAdaptorProxy::reusePictureBufferOnMojoThread(int32_t pictureBufferId) {
+    mVDAPtr->ReusePictureBuffer(pictureBufferId);
+}
+
+void C2VDAAdaptorProxy::flush() {
+    ALOGV("flush");
+    mMojoTaskRunner->PostTask(
+            FROM_HERE, base::Bind(&C2VDAAdaptorProxy::flushOnMojoThread, base::Unretained(this)));
+}
+
+void C2VDAAdaptorProxy::flushOnMojoThread() {
+    mVDAPtr->Flush(base::Bind(&C2VDAAdaptorProxy::NotifyFlushDone, base::Unretained(this)));
+}
+
+void C2VDAAdaptorProxy::reset() {
+    ALOGV("reset");
+    mMojoTaskRunner->PostTask(
+            FROM_HERE, base::Bind(&C2VDAAdaptorProxy::resetOnMojoThread, base::Unretained(this)));
+}
+
+void C2VDAAdaptorProxy::resetOnMojoThread() {
+    mVDAPtr->Reset(base::Bind(&C2VDAAdaptorProxy::NotifyResetDone, base::Unretained(this)));
+}
+
+void C2VDAAdaptorProxy::destroy() {
+    ALOGV("destroy");
+    ::arc::Future<void> future;
+    ::arc::PostTaskAndSetFutureWithResult(
+            mMojoTaskRunner.get(), FROM_HERE,
+            base::Bind(&C2VDAAdaptorProxy::closeChannelOnMojoThread, base::Unretained(this)),
+            &future);
+    future.get();
+}
+
+void C2VDAAdaptorProxy::closeChannelOnMojoThread() {
+    if (mBinding.is_bound()) mBinding.Close();
+    mVDAPtr.reset();
+}
+
+}  // namespace arc
+}  // namespace android
diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp
index 0db1d79..c39dd01 100644
--- a/C2VDAComponent.cpp
+++ b/C2VDAComponent.cpp
@@ -5,7 +5,12 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2VDAComponent"
 
+#ifdef V4L2_CODEC2_ARC
+#include <C2VDAAdaptorProxy.h>
+#else
 #include <C2VDAAdaptor.h>
+#endif
+
 #define __C2_GENERATE_GLOBAL_VARS__
 #include <C2VDAComponent.h>
 #include <C2VDASupport.h>
@@ -134,7 +139,11 @@
     // Get supported profiles from VDA.
     // TODO: re-think the suitable method of getting supported profiles for both pure Android and
     //       ARC++.
+#ifdef V4L2_CODEC2_ARC
+    mSupportedProfiles = arc::C2VDAAdaptorProxy::GetSupportedProfiles(inputFormatFourcc);
+#else
     mSupportedProfiles = C2VDAAdaptor::GetSupportedProfiles(inputFormatFourcc);
+#endif
     if (mSupportedProfiles.empty()) {
         ALOGE("No supported profile from input format: %u", inputFormatFourcc);
         mInitStatus = C2_BAD_VALUE;
@@ -505,7 +514,11 @@
 void C2VDAComponent::onCreate() {
     DCHECK(mTaskRunner->BelongsToCurrentThread());
     ALOGV("onCreate");
+#ifdef V4L2_CODEC2_ARC
+    mVDAAdaptor.reset(new arc::C2VDAAdaptorProxy());
+#else
     mVDAAdaptor.reset(new C2VDAAdaptor());
+#endif
 }
 
 void C2VDAComponent::onDestroy() {
@@ -993,8 +1006,11 @@
     for (uint32_t i = 0; i < passedNumPlanes; ++i) {
         ALOGV("plane %u: stride: %d, offset: %u", i, layout.planes[i].rowInc, offsets[i]);
     }
-
+#ifdef V4L2_CODEC2_ARC
+    info.mPixelFormat = arc::C2VDAAdaptorProxy::ResolveBufferFormat(crcb, semiplanar);
+#else
     info.mPixelFormat = C2VDAAdaptor::ResolveBufferFormat(crcb, semiplanar);
+#endif
     ALOGV("HAL pixel format: 0x%x", static_cast<uint32_t>(info.mPixelFormat));
 
     base::ScopedFD passedHandle(dup(info.mGraphicBlock->handle()->data[0]));
diff --git a/include/C2VDAAdaptorProxy.h b/include/C2VDAAdaptorProxy.h
new file mode 100644
index 0000000..3a854dc
--- /dev/null
+++ b/include/C2VDAAdaptorProxy.h
@@ -0,0 +1,108 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ANDROID_C2_VDA_ADAPTOR_PROXY_H
+#define ANDROID_C2_VDA_ADAPTOR_PROXY_H
+
+#include <VideoDecodeAcceleratorAdaptor.h>
+
+#include <video_decode_accelerator.h>
+
+#include <arc/Future.h>
+#include <mojo/public/cpp/bindings/binding.h>
+#include <utils/Singleton.h>
+
+// TODO(hiroh): Remove this ifdef workaround
+#ifdef ANDROID_VERSION_NYC
+#include <components/arc/common/video.mojom.h>
+#include <components/arc/common/video_decode_accelerator.mojom.h>
+#else
+#include <video.mojom.h>
+#include <video_decode_accelerator.mojom.h>
+#endif
+
+namespace arc {
+class MojoProcessSupport;
+}  // namespace arc
+
+namespace android {
+namespace arc {
+class C2VDAAdaptorProxy : public VideoDecodeAcceleratorAdaptor,
+                          public ::arc::mojom::VideoDecodeClient {
+public:
+    C2VDAAdaptorProxy();
+    explicit C2VDAAdaptorProxy(::arc::MojoProcessSupport* MojomProcessSupport);
+    ~C2VDAAdaptorProxy() override;
+
+    // Establishes ipc channel for video acceleration. Returns true if channel
+    // connected successfully.
+    // This must be called before all other methods.
+    bool establishChannel();
+
+    // Implementation of the VideoDecodeAcceleratorAdaptor interface.
+    Result initialize(media::VideoCodecProfile profile, bool secureMode,
+                      VideoDecodeAcceleratorAdaptor::Client* client) override;
+    void decode(int32_t bitstreamId, int handleFd, off_t offset, uint32_t size) override;
+    void assignPictureBuffers(uint32_t numOutputBuffers) override;
+    void importBufferForPicture(int32_t pictureBufferId, HalPixelFormat format, int handleFd,
+                                const std::vector<VideoFramePlane>& planes) override;
+    void reusePictureBuffer(int32_t pictureBufferId) override;
+    void flush() override;
+    void reset() override;
+    void destroy() override;
+
+    // ::arc::mojom::VideoDecodeClient implementations.
+    void ProvidePictureBuffers(::arc::mojom::PictureBufferFormatPtr format) override;
+    void PictureReady(::arc::mojom::PicturePtr picture) override;
+    void NotifyEndOfBitstreamBuffer(int32_t bitstream_id) override;
+    void NotifyError(::arc::mojom::VideoDecodeAccelerator::Result error) override;
+
+    // The following functions are called as callbacks.
+    void NotifyResetDone(::arc::mojom::VideoDecodeAccelerator::Result result);
+    void NotifyFlushDone(::arc::mojom::VideoDecodeAccelerator::Result result);
+
+    static media::VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(
+            uint32_t inputFormatFourcc);
+    static HalPixelFormat ResolveBufferFormat(bool crcb, bool semiplanar);
+
+private:
+    void onConnectionError(const std::string& pipeName);
+    void establishChannelOnMojoThread(::arc::Future<bool>* future);
+    void onVersionReady(::arc::Future<bool>* future, uint32_t version);
+
+    // Closes ipc channel for video acceleration.
+    // This must be called before deleting this object.
+    void closeChannelOnMojoThread();
+
+    // mojo thread corresponding part of C2VDAAdaptorProxy implementations.
+    void initializeOnMojoThread(const media::VideoCodecProfile profile, const bool mSecureMode,
+                                const ::arc::mojom::VideoDecodeAccelerator::InitializeCallback& cb);
+    void decodeOnMojoThread(int32_t bitstreamId, int ashmemFd, off_t offset, uint32_t bytesUsed);
+    void assignPictureBuffersOnMojoThread(uint32_t numOutputBuffers);
+
+    void importBufferForPictureOnMojoThread(int32_t pictureBufferId, HalPixelFormat format,
+                                            int handleFd,
+                                            const std::vector<VideoFramePlane>& planes);
+    void reusePictureBufferOnMojoThread(int32_t pictureBufferId);
+    void flushOnMojoThread();
+    void resetOnMojoThread();
+
+    VideoDecodeAcceleratorAdaptor::Client* mClient;
+
+    // Task runner for mojom functions.
+    const scoped_refptr<base::SingleThreadTaskRunner> mMojoTaskRunner;
+
+    // |mVDAPtr| and |mBinding| should only be called on |mMojoTaskRunner| after bound.
+    ::arc::mojom::VideoDecodeAcceleratorPtr mVDAPtr;
+    mojo::Binding<::arc::mojom::VideoDecodeClient> mBinding;
+
+    // Used to cancel the wait on arc::Future.
+    sp<::arc::CancellationRelay> mRelay;
+
+    DISALLOW_COPY_AND_ASSIGN(C2VDAAdaptorProxy);
+};
+}  // namespace arc
+}  // namespace android
+
+#endif  // ANDROID_C2_VDA_ADAPTOR_PROXY_H