Move Codec2-related code from hardware/google/av

Test: None
Bug: 112362730
Change-Id: Ie2f8ff431d65c40333f267ab9877d47089adeea4
diff --git a/media/codec2/components/vpx/Android.bp b/media/codec2/components/vpx/Android.bp
new file mode 100644
index 0000000..c09f365
--- /dev/null
+++ b/media/codec2/components/vpx/Android.bp
@@ -0,0 +1,60 @@
+cc_library_shared {
+    name: "libstagefright_soft_c2vp9dec",
+    defaults: [
+        "libstagefright_soft_c2-defaults",
+        "libstagefright_soft_c2_sanitize_all-defaults",
+    ],
+
+    srcs: ["C2SoftVpxDec.cpp"],
+
+    static_libs: ["libvpx"],
+
+    cflags: [
+        "-DVP9",
+    ],
+}
+
+cc_library_shared {
+    name: "libstagefright_soft_c2vp8dec",
+    defaults: [
+        "libstagefright_soft_c2-defaults",
+        "libstagefright_soft_c2_sanitize_all-defaults",
+    ],
+
+    srcs: ["C2SoftVpxDec.cpp"],
+
+    static_libs: ["libvpx"],
+}
+
+cc_library_shared {
+    name: "libstagefright_soft_c2vp9enc",
+    defaults: [
+        "libstagefright_soft_c2-defaults",
+        "libstagefright_soft_c2_sanitize_all-defaults",
+    ],
+
+    srcs: [
+        "C2SoftVp9Enc.cpp",
+        "C2SoftVpxEnc.cpp",
+    ],
+
+    static_libs: ["libvpx"],
+
+    cflags: ["-DVP9"],
+}
+
+cc_library_shared {
+    name: "libstagefright_soft_c2vp8enc",
+    defaults: [
+        "libstagefright_soft_c2-defaults",
+        "libstagefright_soft_c2_sanitize_all-defaults",
+    ],
+
+    srcs: [
+        "C2SoftVp8Enc.cpp",
+        "C2SoftVpxEnc.cpp",
+    ],
+
+    static_libs: ["libvpx"],
+}
+
diff --git a/media/codec2/components/vpx/C2SoftVp8Enc.cpp b/media/codec2/components/vpx/C2SoftVp8Enc.cpp
new file mode 100644
index 0000000..0ae717a
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVp8Enc.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftVp8Enc"
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "C2SoftVp8Enc.h"
+
+namespace android {
+
+constexpr char COMPONENT_NAME[] = "c2.android.vp8.encoder";
+
+C2SoftVp8Enc::C2SoftVp8Enc(const char* name, c2_node_id_t id,
+                           const std::shared_ptr<IntfImpl>& intfImpl)
+    : C2SoftVpxEnc(name, id, intfImpl), mDCTPartitions(0), mProfile(1) {}
+
+void C2SoftVp8Enc::setCodecSpecificInterface() {
+    mCodecInterface = vpx_codec_vp8_cx();
+}
+
+void C2SoftVp8Enc::setCodecSpecificConfiguration() {
+    switch (mProfile) {
+        case 1:
+            mCodecConfiguration->g_profile = 0;
+            break;
+
+        case 2:
+            mCodecConfiguration->g_profile = 1;
+            break;
+
+        case 4:
+            mCodecConfiguration->g_profile = 2;
+            break;
+
+        case 8:
+            mCodecConfiguration->g_profile = 3;
+            break;
+
+        default:
+            mCodecConfiguration->g_profile = 0;
+    }
+}
+
+vpx_codec_err_t C2SoftVp8Enc::setCodecSpecificControls() {
+    vpx_codec_err_t codec_return = vpx_codec_control(mCodecContext,
+                                                     VP8E_SET_TOKEN_PARTITIONS,
+                                                     mDCTPartitions);
+    if (codec_return != VPX_CODEC_OK) {
+        ALOGE("Error setting dct partitions for vpx encoder.");
+    }
+    return codec_return;
+}
+
+class C2SoftVp8EncFactory : public C2ComponentFactory {
+public:
+    C2SoftVp8EncFactory()
+        : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
+              GetCodec2PlatformComponentStore()->getParamReflector())) {}
+
+    virtual c2_status_t createComponent(
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(
+            new C2SoftVp8Enc(COMPONENT_NAME, id,
+                             std::make_shared<C2SoftVpxEnc::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+            c2_node_id_t id,
+            std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = std::shared_ptr<C2ComponentInterface>(
+            new SimpleInterface<C2SoftVpxEnc::IntfImpl>(
+                COMPONENT_NAME, id,
+                std::make_shared<C2SoftVpxEnc::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual ~C2SoftVp8EncFactory() override = default;
+
+private:
+    std::shared_ptr<C2ReflectorHelper> mHelper;
+};
+
+}  // namespace android
+
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftVp8EncFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
diff --git a/media/codec2/components/vpx/C2SoftVp8Enc.h b/media/codec2/components/vpx/C2SoftVp8Enc.h
new file mode 100644
index 0000000..ed6f356
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVp8Enc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_C2_SOFT_VP8_ENC_H__
+#define ANDROID_C2_SOFT_VP8_ENC_H__
+
+#include "C2SoftVpxEnc.h"
+
+namespace android {
+
+// Exposes vp8 encoder as a c2 Component
+//
+// In addition to the base class settings, Only following encoder settings are
+// available:
+//    - token partitioning
+struct C2SoftVp8Enc : public C2SoftVpxEnc {
+    C2SoftVp8Enc(const char* name, c2_node_id_t id,
+                 const std::shared_ptr<IntfImpl>& intfImpl);
+
+ protected:
+    // Populates |mCodecInterface| with codec specific settings.
+    virtual void setCodecSpecificInterface();
+
+    // Sets codec specific configuration.
+    virtual void setCodecSpecificConfiguration();
+
+    // Initializes codec specific encoder settings.
+    virtual vpx_codec_err_t setCodecSpecificControls();
+
+ private:
+    // Max value supported for DCT partitions
+    static const uint32_t kMaxDCTPartitions = 3;
+
+    // vp8 specific configuration parameter
+    // that enables token partitioning of
+    // the stream into substreams
+    int32_t mDCTPartitions;
+
+    // C2 Profile parameter
+    int32_t mProfile;
+
+    C2_DO_NOT_COPY(C2SoftVp8Enc);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2_SOFT_VP8_ENC_H__
diff --git a/media/codec2/components/vpx/C2SoftVp9Enc.cpp b/media/codec2/components/vpx/C2SoftVp9Enc.cpp
new file mode 100644
index 0000000..b26170f
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVp9Enc.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftVp9Enc"
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "C2SoftVp9Enc.h"
+
+namespace android {
+
+constexpr char COMPONENT_NAME[] = "c2.android.vp9.encoder";
+
+C2SoftVp9Enc::C2SoftVp9Enc(const char* name, c2_node_id_t id,
+                           const std::shared_ptr<IntfImpl>& intfImpl)
+    : C2SoftVpxEnc(name, id, intfImpl),
+      mProfile(1),
+      mLevel(0),
+      mTileColumns(0),
+      mFrameParallelDecoding(false) {
+}
+
+void C2SoftVp9Enc::setCodecSpecificInterface() {
+    mCodecInterface = vpx_codec_vp9_cx();
+}
+
+void C2SoftVp9Enc::setCodecSpecificConfiguration() {
+    switch (mProfile) {
+        case 1:
+            mCodecConfiguration->g_profile = 0;
+            break;
+
+        case 2:
+            mCodecConfiguration->g_profile = 1;
+            break;
+
+        case 4:
+            mCodecConfiguration->g_profile = 2;
+            break;
+
+        case 8:
+            mCodecConfiguration->g_profile = 3;
+            break;
+
+        default:
+            mCodecConfiguration->g_profile = 0;
+    }
+}
+
+vpx_codec_err_t C2SoftVp9Enc::setCodecSpecificControls() {
+    vpx_codec_err_t codecReturn = vpx_codec_control(
+            mCodecContext, VP9E_SET_TILE_COLUMNS, mTileColumns);
+    if (codecReturn != VPX_CODEC_OK) {
+        ALOGE("Error setting VP9E_SET_TILE_COLUMNS to %d. vpx_codec_control() "
+              "returned %d", mTileColumns, codecReturn);
+        return codecReturn;
+    }
+    codecReturn = vpx_codec_control(
+            mCodecContext, VP9E_SET_FRAME_PARALLEL_DECODING,
+            mFrameParallelDecoding);
+    if (codecReturn != VPX_CODEC_OK) {
+        ALOGE("Error setting VP9E_SET_FRAME_PARALLEL_DECODING to %d."
+              "vpx_codec_control() returned %d", mFrameParallelDecoding,
+              codecReturn);
+        return codecReturn;
+    }
+    codecReturn = vpx_codec_control(mCodecContext, VP9E_SET_ROW_MT, 1);
+    if (codecReturn != VPX_CODEC_OK) {
+        ALOGE("Error setting VP9E_SET_ROW_MT to 1. vpx_codec_control() "
+              "returned %d", codecReturn);
+        return codecReturn;
+    }
+
+    // For VP9, we always set CPU_USED to 8 (because the realtime default is 0
+    // which is too slow).
+    codecReturn = vpx_codec_control(mCodecContext, VP8E_SET_CPUUSED, 8);
+    if (codecReturn != VPX_CODEC_OK) {
+        ALOGE("Error setting VP8E_SET_CPUUSED to 8. vpx_codec_control() "
+              "returned %d", codecReturn);
+        return codecReturn;
+    }
+    return codecReturn;
+}
+
+class C2SoftVp9EncFactory : public C2ComponentFactory {
+public:
+    C2SoftVp9EncFactory()
+        : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
+              GetCodec2PlatformComponentStore()->getParamReflector())) {}
+
+    virtual c2_status_t createComponent(
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(
+            new C2SoftVp9Enc(COMPONENT_NAME, id,
+                             std::make_shared<C2SoftVpxEnc::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+            c2_node_id_t id,
+            std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = std::shared_ptr<C2ComponentInterface>(
+            new SimpleInterface<C2SoftVpxEnc::IntfImpl>(
+                COMPONENT_NAME, id,
+                std::make_shared<C2SoftVpxEnc::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual ~C2SoftVp9EncFactory() override = default;
+
+private:
+    std::shared_ptr<C2ReflectorHelper> mHelper;
+};
+
+}  // namespace android
+
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftVp9EncFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
diff --git a/media/codec2/components/vpx/C2SoftVp9Enc.h b/media/codec2/components/vpx/C2SoftVp9Enc.h
new file mode 100644
index 0000000..77ef8fd
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVp9Enc.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_C2_SOFT_VP9_ENC_H__
+#define ANDROID_C2_SOFT_VP9_ENC_H__
+
+#include "C2SoftVpxEnc.h"
+
+namespace android {
+
+// Exposes vp9 encoder as a c2 Component
+//
+// In addition to the base class settings, Only following encoder settings are
+// available:
+//    - tile rows
+//    - tile columns
+//    - frame parallel mode
+struct C2SoftVp9Enc : public C2SoftVpxEnc {
+    C2SoftVp9Enc(const char* name, c2_node_id_t id,
+                 const std::shared_ptr<IntfImpl>& intfImpl);
+
+ protected:
+    // Populates |mCodecInterface| with codec specific settings.
+    virtual void setCodecSpecificInterface();
+
+    // Sets codec specific configuration.
+    virtual void setCodecSpecificConfiguration();
+
+    // Initializes codec specific encoder settings.
+    virtual vpx_codec_err_t setCodecSpecificControls();
+
+ private:
+    // C2 Profile & Level parameter
+    int32_t mProfile;
+    int32_t mLevel __unused;
+
+    int32_t mTileColumns;
+
+    bool mFrameParallelDecoding;
+
+    C2_DO_NOT_COPY(C2SoftVp9Enc);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2_SOFT_VP9_ENC_H__
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
new file mode 100644
index 0000000..01de681
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftVpxDec"
+#include <log/log.h>
+
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+
+#include "C2SoftVpxDec.h"
+
+namespace android {
+
+#ifdef VP9
+constexpr char COMPONENT_NAME[] = "c2.android.vp9.decoder";
+#else
+constexpr char COMPONENT_NAME[] = "c2.android.vp8.decoder";
+#endif
+
+class C2SoftVpxDec::IntfImpl : public SimpleInterface<void>::BaseParams {
+public:
+    explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
+        : SimpleInterface<void>::BaseParams(
+                helper,
+                COMPONENT_NAME,
+                C2Component::KIND_DECODER,
+                C2Component::DOMAIN_VIDEO,
+#ifdef VP9
+                MEDIA_MIMETYPE_VIDEO_VP9
+#else
+                MEDIA_MIMETYPE_VIDEO_VP8
+#endif
+                ) {
+        noPrivateBuffers(); // TODO: account for our buffers here
+        noInputReferences();
+        noOutputReferences();
+        noInputLatency();
+        noTimeStretch();
+
+        // TODO: output latency and reordering
+
+        addParameter(
+                DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
+                .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
+                .build());
+
+        addParameter(
+                DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
+                .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
+                .withFields({
+                    C2F(mSize, width).inRange(2, 2048, 2),
+                    C2F(mSize, height).inRange(2, 2048, 2),
+                })
+                .withSetter(SizeSetter)
+                .build());
+
+#ifdef VP9
+        // TODO: Add C2Config::PROFILE_VP9_2HDR ??
+        addParameter(
+                DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+                .withDefault(new C2StreamProfileLevelInfo::input(0u,
+                        C2Config::PROFILE_VP9_0, C2Config::LEVEL_VP9_5))
+                .withFields({
+                    C2F(mProfileLevel, profile).oneOf({
+                            C2Config::PROFILE_VP9_0,
+                            C2Config::PROFILE_VP9_2}),
+                    C2F(mProfileLevel, level).oneOf({
+                            C2Config::LEVEL_VP9_1,
+                            C2Config::LEVEL_VP9_1_1,
+                            C2Config::LEVEL_VP9_2,
+                            C2Config::LEVEL_VP9_2_1,
+                            C2Config::LEVEL_VP9_3,
+                            C2Config::LEVEL_VP9_3_1,
+                            C2Config::LEVEL_VP9_4,
+                            C2Config::LEVEL_VP9_4_1,
+                            C2Config::LEVEL_VP9_5,
+                    })
+                })
+                .withSetter(ProfileLevelSetter, mSize)
+                .build());
+
+#if 0
+        // sample BT.2020 static info
+        mHdrStaticInfo = std::make_shared<C2StreamHdrStaticInfo::output>();
+        mHdrStaticInfo->mastering = {
+            .red   = { .x = 0.708,  .y = 0.292 },
+            .green = { .x = 0.170,  .y = 0.797 },
+            .blue  = { .x = 0.131,  .y = 0.046 },
+            .white = { .x = 0.3127, .y = 0.3290 },
+            .maxLuminance = 1000,
+            .minLuminance = 0.1,
+        };
+        mHdrStaticInfo->maxCll = 1000;
+        mHdrStaticInfo->maxFall = 120;
+
+        mHdrStaticInfo->maxLuminance = 0; // disable static info
+
+        helper->addStructDescriptors<C2MasteringDisplayColorVolumeStruct, C2ColorXyStruct>();
+        addParameter(
+                DefineParam(mHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
+                .withDefault(mHdrStaticInfo)
+                .withFields({
+                    C2F(mHdrStaticInfo, mastering.red.x).inRange(0, 1),
+                    // TODO
+                })
+                .withSetter(HdrStaticInfoSetter)
+                .build());
+#endif
+#else
+        addParameter(
+                DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+                .withConstValue(new C2StreamProfileLevelInfo::input(0u,
+                        C2Config::PROFILE_UNUSED, C2Config::LEVEL_UNUSED))
+                .build());
+#endif
+
+        addParameter(
+                DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
+                .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
+                .withFields({
+                    C2F(mSize, width).inRange(2, 2048, 2),
+                    C2F(mSize, height).inRange(2, 2048, 2),
+                })
+                .withSetter(MaxPictureSizeSetter, mSize)
+                .build());
+
+        addParameter(
+                DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
+                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+                .withFields({
+                    C2F(mMaxInputSize, value).any(),
+                })
+                .calculatedAs(MaxInputSizeSetter, mMaxSize)
+                .build());
+
+        C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
+        std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
+            C2StreamColorInfo::output::AllocShared(
+                    1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
+        memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
+
+        defaultColorInfo =
+            C2StreamColorInfo::output::AllocShared(
+                    { C2ChromaOffsetStruct::ITU_YUV_420_0() },
+                    0u, 8u /* bitDepth */, C2Color::YUV_420);
+        helper->addStructDescriptors<C2ChromaOffsetStruct>();
+
+        addParameter(
+                DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
+                .withConstValue(defaultColorInfo)
+                .build());
+
+        // TODO: support more formats?
+        addParameter(
+                DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
+                .withConstValue(new C2StreamPixelFormatInfo::output(
+                                     0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
+                .build());
+    }
+
+    static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
+                          C2P<C2VideoSizeStreamInfo::output> &me) {
+        (void)mayBlock;
+        C2R res = C2R::Ok();
+        if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
+            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
+            me.set().width = oldMe.v.width;
+        }
+        if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
+            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
+            me.set().height = oldMe.v.height;
+        }
+        return res;
+    }
+
+    static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
+                                    const C2P<C2StreamPictureSizeInfo::output> &size) {
+        (void)mayBlock;
+        // TODO: get max width/height from the size's field helpers vs. hardcoding
+        me.set().width = c2_min(c2_max(me.v.width, size.v.width), 2048u);
+        me.set().height = c2_min(c2_max(me.v.height, size.v.height), 2048u);
+        return C2R::Ok();
+    }
+
+    static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
+                                  const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
+        (void)mayBlock;
+        // assume compression ratio of 2
+        me.set().value = (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+        return C2R::Ok();
+    }
+
+
+    static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
+                                  const C2P<C2StreamPictureSizeInfo::output> &size) {
+        (void)mayBlock;
+        (void)size;
+        (void)me;  // TODO: validate
+        return C2R::Ok();
+    }
+
+private:
+    std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
+    std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
+    std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
+    std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
+    std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
+    std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
+#ifdef VP9
+#if 0
+    std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
+#endif
+#endif
+};
+
+C2SoftVpxDec::C2SoftVpxDec(
+        const char *name,
+        c2_node_id_t id,
+        const std::shared_ptr<IntfImpl> &intfImpl)
+    : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
+      mIntf(intfImpl),
+      mCodecCtx(nullptr) {
+}
+
+C2SoftVpxDec::~C2SoftVpxDec() {
+    onRelease();
+}
+
+c2_status_t C2SoftVpxDec::onInit() {
+    status_t err = initDecoder();
+    return err == OK ? C2_OK : C2_CORRUPTED;
+}
+
+c2_status_t C2SoftVpxDec::onStop() {
+    mSignalledError = false;
+    mSignalledOutputEos = false;
+
+    return C2_OK;
+}
+
+void C2SoftVpxDec::onReset() {
+    (void)onStop();
+    c2_status_t err = onFlush_sm();
+    if (err != C2_OK)
+    {
+        ALOGW("Failed to flush decoder. Try to hard reset decoder");
+        destroyDecoder();
+        (void)initDecoder();
+    }
+}
+
+void C2SoftVpxDec::onRelease() {
+    destroyDecoder();
+}
+
+c2_status_t C2SoftVpxDec::onFlush_sm() {
+    if (mFrameParallelMode) {
+        // Flush decoder by passing nullptr data ptr and 0 size.
+        // Ideally, this should never fail.
+        if (vpx_codec_decode(mCodecCtx, nullptr, 0, nullptr, 0)) {
+            ALOGE("Failed to flush on2 decoder.");
+            return C2_CORRUPTED;
+        }
+    }
+
+    // Drop all the decoded frames in decoder.
+    vpx_codec_iter_t iter = nullptr;
+    while (vpx_codec_get_frame(mCodecCtx, &iter)) {
+    }
+
+    mSignalledError = false;
+    mSignalledOutputEos = false;
+    return C2_OK;
+}
+
+static int GetCPUCoreCount() {
+    int cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    ALOGV("Number of CPU cores: %d", cpuCoreCount);
+    return cpuCoreCount;
+}
+
+status_t C2SoftVpxDec::initDecoder() {
+#ifdef VP9
+    mMode = MODE_VP9;
+#else
+    mMode = MODE_VP8;
+#endif
+
+    mWidth = 320;
+    mHeight = 240;
+    mFrameParallelMode = false;
+    mSignalledOutputEos = false;
+    mSignalledError = false;
+
+    if (!mCodecCtx) {
+        mCodecCtx = new vpx_codec_ctx_t;
+    }
+    if (!mCodecCtx) {
+        ALOGE("mCodecCtx is null");
+        return NO_MEMORY;
+    }
+
+    vpx_codec_dec_cfg_t cfg;
+    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
+    cfg.threads = GetCPUCoreCount();
+
+    vpx_codec_flags_t flags;
+    memset(&flags, 0, sizeof(vpx_codec_flags_t));
+    if (mFrameParallelMode) flags |= VPX_CODEC_USE_FRAME_THREADING;
+
+    vpx_codec_err_t vpx_err;
+    if ((vpx_err = vpx_codec_dec_init(
+                 mCodecCtx, mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
+                 &cfg, flags))) {
+        ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+status_t C2SoftVpxDec::destroyDecoder() {
+    if  (mCodecCtx) {
+        vpx_codec_destroy(mCodecCtx);
+        delete mCodecCtx;
+        mCodecCtx = nullptr;
+    }
+
+    return OK;
+}
+
+void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
+    uint32_t flags = 0;
+    if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+        flags |= C2FrameData::FLAG_END_OF_STREAM;
+        ALOGV("signalling eos");
+    }
+    work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+    work->worklets.front()->output.buffers.clear();
+    work->worklets.front()->output.ordinal = work->input.ordinal;
+    work->workletsProcessed = 1u;
+}
+
+void C2SoftVpxDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
+                           const std::shared_ptr<C2GraphicBlock> &block) {
+    std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block,
+                                                           C2Rect(mWidth, mHeight));
+    auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
+        uint32_t flags = 0;
+        if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
+                (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
+            flags |= C2FrameData::FLAG_END_OF_STREAM;
+            ALOGV("signalling eos");
+        }
+        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+        work->worklets.front()->output.buffers.clear();
+        work->worklets.front()->output.buffers.push_back(buffer);
+        work->worklets.front()->output.ordinal = work->input.ordinal;
+        work->workletsProcessed = 1u;
+    };
+    if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
+        fillWork(work);
+    } else {
+        finish(index, fillWork);
+    }
+}
+
+void C2SoftVpxDec::process(
+        const std::unique_ptr<C2Work> &work,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
+    work->result = C2_OK;
+    work->workletsProcessed = 0u;
+    work->worklets.front()->output.configUpdate.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+
+    if (mSignalledError || mSignalledOutputEos) {
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+
+    size_t inOffset = 0u;
+    size_t inSize = 0u;
+    C2ReadView rView = mDummyReadView;
+    if (!work->input.buffers.empty()) {
+        rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
+        inSize = rView.capacity();
+        if (inSize && rView.error()) {
+            ALOGE("read view map failed %d", rView.error());
+            work->result = C2_CORRUPTED;
+            return;
+        }
+    }
+
+    bool codecConfig = ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) !=0);
+    bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
+
+    ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
+          inSize, (int)work->input.ordinal.timestamp.peeku(),
+          (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
+
+    // Software VP9 Decoder does not need the Codec Specific Data (CSD)
+    // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
+    // it was passed.
+    if (codecConfig) {
+        // Ignore CSD buffer for VP9.
+        if (mMode == MODE_VP9) {
+            fillEmptyWork(work);
+            return;
+        } else {
+            // Tolerate the CSD buffer for VP8. This is a workaround
+            // for b/28689536. continue
+            ALOGW("WARNING: Got CSD buffer for VP8. Continue");
+        }
+    }
+
+    int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
+
+    if (inSize) {
+        uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
+        vpx_codec_err_t err = vpx_codec_decode(
+                mCodecCtx, bitstream, inSize, &frameIndex, 0);
+        if (err != VPX_CODEC_OK) {
+            ALOGE("on2 decoder failed to decode frame. err: %d", err);
+            mSignalledError = true;
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
+            return;
+        }
+    }
+
+    (void)outputBuffer(pool, work);
+
+    if (eos) {
+        drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
+        mSignalledOutputEos = true;
+    } else if (!inSize) {
+        fillEmptyWork(work);
+    }
+}
+
+static void copyOutputBufferToYV12Frame(uint8_t *dst,
+        const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
+        size_t srcYStride, size_t srcUStride, size_t srcVStride,
+        uint32_t width, uint32_t height, int32_t bpp) {
+    size_t dstYStride = align(width, 16) * bpp ;
+    size_t dstUVStride = align(dstYStride / 2, 16);
+    uint8_t *dstStart = dst;
+
+    for (size_t i = 0; i < height; ++i) {
+         memcpy(dst, srcY, width * bpp);
+         srcY += srcYStride;
+         dst += dstYStride;
+    }
+
+    dst = dstStart + dstYStride * height;
+    for (size_t i = 0; i < height / 2; ++i) {
+         memcpy(dst, srcV, width / 2 * bpp);
+         srcV += srcVStride;
+         dst += dstUVStride;
+    }
+
+    dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
+    for (size_t i = 0; i < height / 2; ++i) {
+         memcpy(dst, srcU, width / 2 * bpp);
+         srcU += srcUStride;
+         dst += dstUVStride;
+    }
+}
+
+bool C2SoftVpxDec::outputBuffer(
+        const std::shared_ptr<C2BlockPool> &pool,
+        const std::unique_ptr<C2Work> &work)
+{
+    if (!(work && pool)) return false;
+
+    vpx_codec_iter_t iter = nullptr;
+    vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
+
+    if (!img) return false;
+
+    if (img->d_w != mWidth || img->d_h != mHeight) {
+        mWidth = img->d_w;
+        mHeight = img->d_h;
+
+        C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
+        std::vector<std::unique_ptr<C2SettingResult>> failures;
+        c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+        if (err == C2_OK) {
+            work->worklets.front()->output.configUpdate.push_back(
+                C2Param::Copy(size));
+        } else {
+            ALOGE("Config update size failed");
+            mSignalledError = true;
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
+            return false;
+        }
+
+    }
+    CHECK(img->fmt == VPX_IMG_FMT_I420 || img->fmt == VPX_IMG_FMT_I42016);
+    int32_t bpp = 1;
+    if (img->fmt == VPX_IMG_FMT_I42016) {
+        bpp = 2;
+    }
+
+    std::shared_ptr<C2GraphicBlock> block;
+    uint32_t format = HAL_PIXEL_FORMAT_YV12;
+    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+    c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16) * bpp, mHeight, format, usage, &block);
+    if (err != C2_OK) {
+        ALOGE("fetchGraphicBlock for Output failed with status %d", err);
+        work->result = err;
+        return false;
+    }
+
+    C2GraphicView wView = block->map().get();
+    if (wView.error()) {
+        ALOGE("graphic view map failed %d", wView.error());
+        work->result = C2_CORRUPTED;
+        return false;
+    }
+
+    ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
+           block->width(), block->height(), mWidth, mHeight, (int)*(int64_t *)img->user_priv);
+
+    uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
+    size_t srcYStride = img->stride[VPX_PLANE_Y];
+    size_t srcUStride = img->stride[VPX_PLANE_U];
+    size_t srcVStride = img->stride[VPX_PLANE_V];
+    const uint8_t *srcY = (const uint8_t *)img->planes[VPX_PLANE_Y];
+    const uint8_t *srcU = (const uint8_t *)img->planes[VPX_PLANE_U];
+    const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
+    copyOutputBufferToYV12Frame(dst, srcY, srcU, srcV,
+                                srcYStride, srcUStride, srcVStride, mWidth, mHeight, bpp);
+
+    finishWork(*(int64_t *)img->user_priv, work, std::move(block));
+    return true;
+}
+
+c2_status_t C2SoftVpxDec::drainInternal(
+        uint32_t drainMode,
+        const std::shared_ptr<C2BlockPool> &pool,
+        const std::unique_ptr<C2Work> &work) {
+    if (drainMode == NO_DRAIN) {
+        ALOGW("drain with NO_DRAIN: no-op");
+        return C2_OK;
+    }
+    if (drainMode == DRAIN_CHAIN) {
+        ALOGW("DRAIN_CHAIN not supported");
+        return C2_OMITTED;
+    }
+
+    while ((outputBuffer(pool, work))) {
+    }
+
+    if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
+            work && work->workletsProcessed == 0u) {
+        fillEmptyWork(work);
+    }
+
+    return C2_OK;
+}
+c2_status_t C2SoftVpxDec::drain(
+        uint32_t drainMode,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    return drainInternal(drainMode, pool, nullptr);
+}
+
+class C2SoftVpxFactory : public C2ComponentFactory {
+public:
+    C2SoftVpxFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
+        GetCodec2PlatformComponentStore()->getParamReflector())) {
+    }
+
+    virtual c2_status_t createComponent(
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(
+            new C2SoftVpxDec(COMPONENT_NAME, id,
+                          std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+            c2_node_id_t id,
+            std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = std::shared_ptr<C2ComponentInterface>(
+            new SimpleInterface<C2SoftVpxDec::IntfImpl>(
+                COMPONENT_NAME, id,
+                std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual ~C2SoftVpxFactory() override = default;
+
+private:
+    std::shared_ptr<C2ReflectorHelper> mHelper;
+};
+
+}  // namespace android
+
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftVpxFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
new file mode 100644
index 0000000..60c8484
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_C2_SOFT_VPX_DEC_H_
+#define ANDROID_C2_SOFT_VPX_DEC_H_
+
+#include <SimpleC2Component.h>
+
+
+#include "vpx/vpx_decoder.h"
+#include "vpx/vp8dx.h"
+
+namespace android {
+
+struct C2SoftVpxDec : public SimpleC2Component {
+    class IntfImpl;
+
+    C2SoftVpxDec(const char* name, c2_node_id_t id,
+              const std::shared_ptr<IntfImpl>& intfImpl);
+    virtual ~C2SoftVpxDec();
+
+    // From SimpleC2Component
+    c2_status_t onInit() override;
+    c2_status_t onStop() override;
+    void onReset() override;
+    void onRelease() override;
+    c2_status_t onFlush_sm() override;
+    void process(
+            const std::unique_ptr<C2Work> &work,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+    c2_status_t drain(
+            uint32_t drainMode,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+ private:
+    enum {
+        MODE_VP8,
+        MODE_VP9,
+    } mMode;
+
+    std::shared_ptr<IntfImpl> mIntf;
+    vpx_codec_ctx_t *mCodecCtx;
+    bool mFrameParallelMode;  // Frame parallel is only supported by VP9 decoder.
+
+    uint32_t mWidth;
+    uint32_t mHeight;
+    bool mSignalledOutputEos;
+    bool mSignalledError;
+
+    status_t initDecoder();
+    status_t destroyDecoder();
+    void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
+                    const std::shared_ptr<C2GraphicBlock> &block);
+    bool outputBuffer(
+            const std::shared_ptr<C2BlockPool> &pool,
+            const std::unique_ptr<C2Work> &work);
+    c2_status_t drainInternal(
+            uint32_t drainMode,
+            const std::shared_ptr<C2BlockPool> &pool,
+            const std::unique_ptr<C2Work> &work);
+
+    C2_DO_NOT_COPY(C2SoftVpxDec);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2_SOFT_VPX_DEC_H_
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
new file mode 100644
index 0000000..155a84f
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -0,0 +1,670 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftVpxEnc"
+#include <log/log.h>
+#include <utils/misc.h>
+
+#include <media/hardware/VideoAPI.h>
+
+#include <Codec2BufferUtils.h>
+#include <C2Debug.h>
+#include "C2SoftVpxEnc.h"
+
+#ifndef INT32_MAX
+#define INT32_MAX   2147483647
+#endif
+
+namespace android {
+
+#if 0
+static size_t getCpuCoreCount() {
+    long cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    ALOGV("Number of CPU cores: %ld", cpuCoreCount);
+    return (size_t)cpuCoreCount;
+}
+#endif
+
+C2SoftVpxEnc::C2SoftVpxEnc(const char* name, c2_node_id_t id,
+                           const std::shared_ptr<IntfImpl>& intfImpl)
+    : SimpleC2Component(
+          std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
+      mIntf(intfImpl),
+      mCodecContext(nullptr),
+      mCodecConfiguration(nullptr),
+      mCodecInterface(nullptr),
+      mStrideAlign(2),
+      mColorFormat(VPX_IMG_FMT_I420),
+      mBitrateControlMode(VPX_VBR),
+      mErrorResilience(false),
+      mMinQuantizer(0),
+      mMaxQuantizer(0),
+      mTemporalLayers(0),
+      mTemporalPatternType(VPXTemporalLayerPatternNone),
+      mTemporalPatternLength(0),
+      mTemporalPatternIdx(0),
+      mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
+      mSignalledOutputEos(false),
+      mSignalledError(false) {
+    memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
+    mTemporalLayerBitrateRatio[0] = 100;
+}
+
+C2SoftVpxEnc::~C2SoftVpxEnc() {
+    onRelease();
+}
+
+c2_status_t C2SoftVpxEnc::onInit() {
+    status_t err = initEncoder();
+    return err == OK ? C2_OK : C2_CORRUPTED;
+}
+
+void C2SoftVpxEnc::onRelease() {
+    if (mCodecContext) {
+        vpx_codec_destroy(mCodecContext);
+        delete mCodecContext;
+        mCodecContext = nullptr;
+    }
+
+    if (mCodecConfiguration) {
+        delete mCodecConfiguration;
+        mCodecConfiguration = nullptr;
+    }
+
+    // this one is not allocated by us
+    mCodecInterface = nullptr;
+}
+
+c2_status_t C2SoftVpxEnc::onStop() {
+    onRelease();
+    mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL;
+    mSignalledOutputEos = false;
+    mSignalledError = false;
+    return C2_OK;
+}
+
+void C2SoftVpxEnc::onReset() {
+    (void)onStop();
+}
+
+c2_status_t C2SoftVpxEnc::onFlush_sm() {
+    return onStop();
+}
+
+status_t C2SoftVpxEnc::initEncoder() {
+    vpx_codec_err_t codec_return;
+    status_t result = UNKNOWN_ERROR;
+    {
+        IntfImpl::Lock lock = mIntf->lock();
+        mSize = mIntf->getSize_l();
+        mBitrate = mIntf->getBitrate_l();
+        mBitrateMode = mIntf->getBitrateMode_l();
+        mFrameRate = mIntf->getFrameRate_l();
+        mIntraRefresh = mIntf->getIntraRefresh_l();
+        mRequestSync = mIntf->getRequestSync_l();
+        mTemporalLayers = mIntf->getTemporalLayers_l()->m.layerCount;
+    }
+
+    switch (mBitrateMode->value) {
+        case C2Config::BITRATE_VARIABLE:
+            mBitrateControlMode = VPX_VBR;
+            break;
+        case C2Config::BITRATE_CONST:
+        default:
+            mBitrateControlMode = VPX_CBR;
+            break;
+        break;
+    }
+
+    setCodecSpecificInterface();
+    if (!mCodecInterface) goto CleanUp;
+
+    ALOGD("VPx: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
+          (uint32_t)mBitrateControlMode, mTemporalLayers, mIntf->getSyncFramePeriod(),
+          mMinQuantizer, mMaxQuantizer);
+
+    mCodecConfiguration = new vpx_codec_enc_cfg_t;
+    if (!mCodecConfiguration) goto CleanUp;
+    codec_return = vpx_codec_enc_config_default(mCodecInterface,
+                                                mCodecConfiguration,
+                                                0);
+    if (codec_return != VPX_CODEC_OK) {
+        ALOGE("Error populating default configuration for vpx encoder.");
+        goto CleanUp;
+    }
+
+    mCodecConfiguration->g_w = mSize->width;
+    mCodecConfiguration->g_h = mSize->height;
+    //mCodecConfiguration->g_threads = getCpuCoreCount();
+    mCodecConfiguration->g_threads = 0;
+    mCodecConfiguration->g_error_resilient = mErrorResilience;
+
+    // timebase unit is microsecond
+    // g_timebase is in seconds (i.e. 1/1000000 seconds)
+    mCodecConfiguration->g_timebase.num = 1;
+    mCodecConfiguration->g_timebase.den = 1000000;
+    // rc_target_bitrate is in kbps, mBitrate in bps
+    mCodecConfiguration->rc_target_bitrate = (mBitrate->value + 500) / 1000;
+    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
+    // Disable frame drop - not allowed in MediaCodec now.
+    mCodecConfiguration->rc_dropframe_thresh = 0;
+    // Disable lagged encoding.
+    mCodecConfiguration->g_lag_in_frames = 0;
+    if (mBitrateControlMode == VPX_CBR) {
+        // Disable spatial resizing.
+        mCodecConfiguration->rc_resize_allowed = 0;
+        // Single-pass mode.
+        mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
+        // Maximum amount of bits that can be subtracted from the target
+        // bitrate - expressed as percentage of the target bitrate.
+        mCodecConfiguration->rc_undershoot_pct = 100;
+        // Maximum amount of bits that can be added to the target
+        // bitrate - expressed as percentage of the target bitrate.
+        mCodecConfiguration->rc_overshoot_pct = 15;
+        // Initial value of the buffer level in ms.
+        mCodecConfiguration->rc_buf_initial_sz = 500;
+        // Amount of data that the encoder should try to maintain in ms.
+        mCodecConfiguration->rc_buf_optimal_sz = 600;
+        // The amount of data that may be buffered by the decoding
+        // application in ms.
+        mCodecConfiguration->rc_buf_sz = 1000;
+        // Enable error resilience - needed for packet loss.
+        mCodecConfiguration->g_error_resilient = 1;
+        // Maximum key frame interval - for CBR boost to 3000
+        mCodecConfiguration->kf_max_dist = 3000;
+        // Encoder determines optimal key frame placement automatically.
+        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
+    }
+
+    // Frames temporal pattern - for now WebRTC like pattern is only supported.
+    switch (mTemporalLayers) {
+        case 0:
+            mTemporalPatternLength = 0;
+            break;
+        case 1:
+            mCodecConfiguration->ts_number_layers = 1;
+            mCodecConfiguration->ts_rate_decimator[0] = 1;
+            mCodecConfiguration->ts_periodicity = 1;
+            mCodecConfiguration->ts_layer_id[0] = 0;
+            mTemporalPattern[0] = kTemporalUpdateLastRefAll;
+            mTemporalPatternLength = 1;
+            break;
+        case 2:
+            mCodecConfiguration->ts_number_layers = 2;
+            mCodecConfiguration->ts_rate_decimator[0] = 2;
+            mCodecConfiguration->ts_rate_decimator[1] = 1;
+            mCodecConfiguration->ts_periodicity = 2;
+            mCodecConfiguration->ts_layer_id[0] = 0;
+            mCodecConfiguration->ts_layer_id[1] = 1;
+            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
+            mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
+            mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
+            mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
+            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
+            mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
+            mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
+            mTemporalPattern[7] = kTemporalUpdateNone;
+            mTemporalPatternLength = 8;
+            break;
+        case 3:
+            mCodecConfiguration->ts_number_layers = 3;
+            mCodecConfiguration->ts_rate_decimator[0] = 4;
+            mCodecConfiguration->ts_rate_decimator[1] = 2;
+            mCodecConfiguration->ts_rate_decimator[2] = 1;
+            mCodecConfiguration->ts_periodicity = 4;
+            mCodecConfiguration->ts_layer_id[0] = 0;
+            mCodecConfiguration->ts_layer_id[1] = 2;
+            mCodecConfiguration->ts_layer_id[2] = 1;
+            mCodecConfiguration->ts_layer_id[3] = 2;
+            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
+            mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
+            mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
+            mTemporalPattern[3] = kTemporalUpdateNone;
+            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
+            mTemporalPattern[5] = kTemporalUpdateNone;
+            mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
+            mTemporalPattern[7] = kTemporalUpdateNone;
+            mTemporalPatternLength = 8;
+            break;
+        default:
+            ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
+            goto CleanUp;
+    }
+    // Set bitrate values for each layer
+    for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
+        mCodecConfiguration->ts_target_bitrate[i] =
+            mCodecConfiguration->rc_target_bitrate *
+            mTemporalLayerBitrateRatio[i] / 100;
+    }
+    if (mIntf->getSyncFramePeriod() >= 0) {
+        mCodecConfiguration->kf_max_dist = mIntf->getSyncFramePeriod();
+        mCodecConfiguration->kf_min_dist = mIntf->getSyncFramePeriod();
+        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
+    }
+    if (mMinQuantizer > 0) {
+        mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
+    }
+    if (mMaxQuantizer > 0) {
+        mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
+    }
+    setCodecSpecificConfiguration();
+    mCodecContext = new vpx_codec_ctx_t;
+    if (!mCodecContext) goto CleanUp;
+    codec_return = vpx_codec_enc_init(mCodecContext,
+                                      mCodecInterface,
+                                      mCodecConfiguration,
+                                      0);  // flags
+    if (codec_return != VPX_CODEC_OK) {
+        ALOGE("Error initializing vpx encoder");
+        goto CleanUp;
+    }
+
+    // Extra CBR settings
+    if (mBitrateControlMode == VPX_CBR) {
+        codec_return = vpx_codec_control(mCodecContext,
+                                         VP8E_SET_STATIC_THRESHOLD,
+                                         1);
+        if (codec_return == VPX_CODEC_OK) {
+            uint32_t rc_max_intra_target =
+                (uint32_t)(mCodecConfiguration->rc_buf_optimal_sz * mFrameRate->value / 20 + 0.5);
+            // Don't go below 3 times per frame bandwidth.
+            if (rc_max_intra_target < 300) {
+                rc_max_intra_target = 300;
+            }
+            codec_return = vpx_codec_control(mCodecContext,
+                                             VP8E_SET_MAX_INTRA_BITRATE_PCT,
+                                             rc_max_intra_target);
+        }
+        if (codec_return == VPX_CODEC_OK) {
+            codec_return = vpx_codec_control(mCodecContext,
+                                             VP8E_SET_CPUUSED,
+                                             -8);
+        }
+        if (codec_return != VPX_CODEC_OK) {
+            ALOGE("Error setting cbr parameters for vpx encoder.");
+            goto CleanUp;
+        }
+    }
+
+    codec_return = setCodecSpecificControls();
+    if (codec_return != VPX_CODEC_OK) goto CleanUp;
+
+    {
+        uint32_t width = mSize->width;
+        uint32_t height = mSize->height;
+        if (((uint64_t)width * height) >
+            ((uint64_t)INT32_MAX / 3)) {
+            ALOGE("b/25812794, Buffer size is too big, width=%u, height=%u.", width, height);
+        } else {
+            uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
+            uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
+            mConversionBuffer = MemoryBlock::Allocate(stride * vstride * 3 / 2);
+            if (!mConversionBuffer.size()) {
+                ALOGE("Allocating conversion buffer failed.");
+            } else {
+                mNumInputFrames = -1;
+                return OK;
+            }
+        }
+    }
+
+CleanUp:
+    onRelease();
+    return result;
+}
+
+vpx_enc_frame_flags_t C2SoftVpxEnc::getEncodeFlags() {
+    vpx_enc_frame_flags_t flags = 0;
+    if (mTemporalPatternLength > 0) {
+      int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
+      mTemporalPatternIdx++;
+      switch (mTemporalPattern[patternIdx]) {
+          case kTemporalUpdateLast:
+              flags |= VP8_EFLAG_NO_UPD_GF;
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_REF_GF;
+              flags |= VP8_EFLAG_NO_REF_ARF;
+              break;
+          case kTemporalUpdateGoldenWithoutDependency:
+              flags |= VP8_EFLAG_NO_REF_GF;
+              [[fallthrough]];
+          case kTemporalUpdateGolden:
+              flags |= VP8_EFLAG_NO_REF_ARF;
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_UPD_LAST;
+              break;
+          case kTemporalUpdateAltrefWithoutDependency:
+              flags |= VP8_EFLAG_NO_REF_ARF;
+              flags |= VP8_EFLAG_NO_REF_GF;
+              [[fallthrough]];
+          case kTemporalUpdateAltref:
+              flags |= VP8_EFLAG_NO_UPD_GF;
+              flags |= VP8_EFLAG_NO_UPD_LAST;
+              break;
+          case kTemporalUpdateNoneNoRefAltref:
+              flags |= VP8_EFLAG_NO_REF_ARF;
+              [[fallthrough]];
+          case kTemporalUpdateNone:
+              flags |= VP8_EFLAG_NO_UPD_GF;
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_UPD_LAST;
+              flags |= VP8_EFLAG_NO_UPD_ENTROPY;
+              break;
+          case kTemporalUpdateNoneNoRefGoldenRefAltRef:
+              flags |= VP8_EFLAG_NO_REF_GF;
+              flags |= VP8_EFLAG_NO_UPD_GF;
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_UPD_LAST;
+              flags |= VP8_EFLAG_NO_UPD_ENTROPY;
+              break;
+          case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
+              flags |= VP8_EFLAG_NO_REF_GF;
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_UPD_LAST;
+              break;
+          case kTemporalUpdateLastRefAltRef:
+              flags |= VP8_EFLAG_NO_UPD_GF;
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_REF_GF;
+              break;
+          case kTemporalUpdateGoldenRefAltRef:
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_UPD_LAST;
+              break;
+          case kTemporalUpdateLastAndGoldenRefAltRef:
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_REF_GF;
+              break;
+          case kTemporalUpdateLastRefAll:
+              flags |= VP8_EFLAG_NO_UPD_ARF;
+              flags |= VP8_EFLAG_NO_UPD_GF;
+              break;
+      }
+    }
+    return flags;
+}
+
+// TODO: add support for YUV input color formats
+// TODO: add support for SVC, ARF. SVC and ARF returns multiple frames
+// (hierarchical / noshow) in one call. These frames should be combined in to
+// a single buffer and sent back to the client
+void C2SoftVpxEnc::process(
+        const std::unique_ptr<C2Work> &work,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    // Initialize output work
+    work->result = C2_OK;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
+    if (mSignalledError || mSignalledOutputEos) {
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+    // Initialize encoder if not already
+    if (!mCodecContext && OK != initEncoder()) {
+        ALOGE("Failed to initialize encoder");
+        mSignalledError = true;
+        work->result = C2_CORRUPTED;
+        return;
+    }
+
+    std::shared_ptr<const C2GraphicView> rView;
+    std::shared_ptr<C2Buffer> inputBuffer;
+    if (!work->input.buffers.empty()) {
+        inputBuffer = work->input.buffers[0];
+        rView = std::make_shared<const C2GraphicView>(
+                    inputBuffer->data().graphicBlocks().front().map().get());
+        if (rView->error() != C2_OK) {
+            ALOGE("graphic view map err = %d", rView->error());
+            work->result = C2_CORRUPTED;
+            return;
+        }
+    } else {
+        ALOGV("Empty input Buffer");
+        uint32_t flags = 0;
+        if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+            flags |= C2FrameData::FLAG_END_OF_STREAM;
+        }
+        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+        work->worklets.front()->output.buffers.clear();
+        work->worklets.front()->output.ordinal = work->input.ordinal;
+        work->workletsProcessed = 1u;
+        return;
+    }
+
+    const C2ConstGraphicBlock inBuffer =
+        inputBuffer->data().graphicBlocks().front();
+    if (inBuffer.width() != mSize->width ||
+        inBuffer.height() != mSize->height) {
+        ALOGE("unexpected Input buffer attributes %d(%d) x %d(%d)",
+              inBuffer.width(), mSize->width, inBuffer.height(),
+              mSize->height);
+        mSignalledError = true;
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+    bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
+    vpx_image_t raw_frame;
+    const C2PlanarLayout &layout = rView->layout();
+    uint32_t width = rView->width();
+    uint32_t height = rView->height();
+    if (width > 0x8000 || height > 0x8000) {
+        ALOGE("Image too big: %u x %u", width, height);
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+    uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
+    uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
+    switch (layout.type) {
+        case C2PlanarLayout::TYPE_RGB:
+        case C2PlanarLayout::TYPE_RGBA: {
+            ConvertRGBToPlanarYUV(mConversionBuffer.data(), stride, vstride,
+                                  mConversionBuffer.size(), *rView.get());
+            vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
+                         mStrideAlign, mConversionBuffer.data());
+            break;
+        }
+        case C2PlanarLayout::TYPE_YUV: {
+            if (!IsYUV420(*rView)) {
+                ALOGE("input is not YUV420");
+                work->result = C2_BAD_VALUE;
+                return;
+            }
+
+            if (layout.planes[layout.PLANE_Y].colInc == 1
+                    && layout.planes[layout.PLANE_U].colInc == 1
+                    && layout.planes[layout.PLANE_V].colInc == 1) {
+                // I420 compatible - though with custom offset and stride
+                vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
+                             mStrideAlign, (uint8_t*)rView->data()[0]);
+                raw_frame.planes[1] = (uint8_t*)rView->data()[1];
+                raw_frame.planes[2] = (uint8_t*)rView->data()[2];
+                raw_frame.stride[0] = layout.planes[layout.PLANE_Y].rowInc;
+                raw_frame.stride[1] = layout.planes[layout.PLANE_U].rowInc;
+                raw_frame.stride[2] = layout.planes[layout.PLANE_V].rowInc;
+            } else {
+                // copy to I420
+                MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, stride, vstride);
+                if (mConversionBuffer.size() >= stride * vstride * 3 / 2) {
+                    status_t err = ImageCopy(mConversionBuffer.data(), &img, *rView);
+                    if (err != OK) {
+                        ALOGE("Buffer conversion failed: %d", err);
+                        work->result = C2_BAD_VALUE;
+                        return;
+                    }
+                    vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
+                                 mStrideAlign, (uint8_t*)rView->data()[0]);
+                    vpx_img_set_rect(&raw_frame, 0, 0, width, height);
+                } else {
+                    ALOGE("Conversion buffer is too small: %u x %u for %zu",
+                            stride, vstride, mConversionBuffer.size());
+                    work->result = C2_BAD_VALUE;
+                    return;
+                }
+            }
+            break;
+        }
+        default:
+            ALOGE("Unrecognized plane type: %d", layout.type);
+            work->result = C2_BAD_VALUE;
+            return;
+    }
+
+    vpx_enc_frame_flags_t flags = getEncodeFlags();
+    // handle dynamic config parameters
+    {
+        IntfImpl::Lock lock = mIntf->lock();
+        std::shared_ptr<C2StreamIntraRefreshTuning::output> intraRefresh = mIntf->getIntraRefresh_l();
+        std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
+        std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
+        lock.unlock();
+
+        if (intraRefresh != mIntraRefresh) {
+            mIntraRefresh = intraRefresh;
+            ALOGV("Got mIntraRefresh request");
+        }
+
+        if (requestSync != mRequestSync) {
+            // we can handle IDR immediately
+            if (requestSync->value) {
+                // unset request
+                C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
+                std::vector<std::unique_ptr<C2SettingResult>> failures;
+                mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
+                ALOGV("Got sync request");
+                flags |= VPX_EFLAG_FORCE_KF;
+            }
+            mRequestSync = requestSync;
+        }
+
+        if (bitrate != mBitrate) {
+            mBitrate = bitrate;
+            mCodecConfiguration->rc_target_bitrate =
+                (mBitrate->value + 500) / 1000;
+            vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
+                                                           mCodecConfiguration);
+            if (res != VPX_CODEC_OK) {
+                ALOGE("vpx encoder failed to update bitrate: %s",
+                      vpx_codec_err_to_string(res));
+                mSignalledError = true;
+                work->result = C2_CORRUPTED;
+                return;
+            }
+        }
+    }
+
+    uint64_t inputTimeStamp = work->input.ordinal.timestamp.peekull();
+    uint32_t frameDuration;
+    if (inputTimeStamp > mLastTimestamp) {
+        frameDuration = (uint32_t)(inputTimeStamp - mLastTimestamp);
+    } else {
+        // Use default of 30 fps in case of 0 frame rate.
+        float frameRate = mFrameRate->value;
+        if (frameRate < 0.001) {
+            frameRate = 30;
+        }
+        frameDuration = (uint32_t)(1000000 / frameRate + 0.5);
+    }
+    mLastTimestamp = inputTimeStamp;
+
+    vpx_codec_err_t codec_return = vpx_codec_encode(mCodecContext, &raw_frame,
+                                                    inputTimeStamp,
+                                                    frameDuration, flags,
+                                                    VPX_DL_REALTIME);
+    if (codec_return != VPX_CODEC_OK) {
+        ALOGE("vpx encoder failed to encode frame");
+        mSignalledError = true;
+        work->result = C2_CORRUPTED;
+        return;
+    }
+
+    bool populated = false;
+    vpx_codec_iter_t encoded_packet_iterator = nullptr;
+    const vpx_codec_cx_pkt_t* encoded_packet;
+    while ((encoded_packet = vpx_codec_get_cx_data(
+                    mCodecContext, &encoded_packet_iterator))) {
+        if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
+            std::shared_ptr<C2LinearBlock> block;
+            C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+            c2_status_t err = pool->fetchLinearBlock(encoded_packet->data.frame.sz, usage, &block);
+            if (err != C2_OK) {
+                ALOGE("fetchLinearBlock for Output failed with status %d", err);
+                work->result = C2_NO_MEMORY;
+                return;
+            }
+            C2WriteView wView = block->map().get();
+            if (wView.error()) {
+                ALOGE("write view map failed %d", wView.error());
+                work->result = C2_CORRUPTED;
+                return;
+            }
+
+            memcpy(wView.data(), encoded_packet->data.frame.buf, encoded_packet->data.frame.sz);
+            ++mNumInputFrames;
+
+            ALOGD("bytes generated %zu", encoded_packet->data.frame.sz);
+            uint32_t flags = 0;
+            if (eos) {
+                flags |= C2FrameData::FLAG_END_OF_STREAM;
+            }
+            work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+            work->worklets.front()->output.buffers.clear();
+            std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block);
+            if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) {
+                buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
+                        0u /* stream id */, C2PictureTypeKeyFrame));
+            }
+            work->worklets.front()->output.buffers.push_back(buffer);
+            work->worklets.front()->output.ordinal = work->input.ordinal;
+            work->worklets.front()->output.ordinal.timestamp = encoded_packet->data.frame.pts;
+            work->workletsProcessed = 1u;
+            populated = true;
+            if (eos) {
+                mSignalledOutputEos = true;
+                ALOGV("signalled EOS");
+            }
+        }
+    }
+    if (!populated) {
+        work->workletsProcessed = 0u;
+    }
+}
+
+c2_status_t C2SoftVpxEnc::drain(
+        uint32_t drainMode,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    (void)pool;
+    if (drainMode == NO_DRAIN) {
+        ALOGW("drain with NO_DRAIN: no-op");
+        return C2_OK;
+    }
+    if (drainMode == DRAIN_CHAIN) {
+        ALOGW("DRAIN_CHAIN not supported");
+        return C2_OMITTED;
+    }
+
+    return C2_OK;
+}
+
+}  // namespace android
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
new file mode 100644
index 0000000..87ed1a9
--- /dev/null
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_C2_SOFT_VPX_ENC_H__
+#define ANDROID_C2_SOFT_VPX_ENC_H__
+
+#include <media/stagefright/foundation/MediaDefs.h>
+
+#include <C2PlatformSupport.h>
+#include <Codec2BufferUtils.h>
+#include <SimpleC2Component.h>
+#include <SimpleC2Interface.h>
+#include <util/C2InterfaceHelper.h>
+
+#include "vpx/vpx_encoder.h"
+#include "vpx/vpx_codec.h"
+#include "vpx/vpx_image.h"
+#include "vpx/vp8cx.h"
+
+namespace android {
+
+// TODO: These defs taken from deprecated OMX_VideoExt.h. Move these definitions
+// to a new header file and include it.
+
+/** Maximum number of temporal layers */
+#define MAXTEMPORALLAYERS 3
+
+/** temporal layer patterns */
+typedef enum TemporalPatternType {
+    VPXTemporalLayerPatternNone = 0,
+    VPXTemporalLayerPatternWebRTC = 1,
+    VPXTemporalLayerPatternMax = 0x7FFFFFFF
+} TemporalPatternType;
+
+// Base class for a VPX Encoder Component
+//
+// Only following encoder settings are available (codec specific settings might
+// be available in the sub-classes):
+//    - video resolution
+//    - target bitrate
+//    - rate control (constant / variable)
+//    - frame rate
+//    - error resilience
+//    - reconstruction & loop filters (g_profile)
+//
+// Only following color formats are recognized
+//    - C2PlanarLayout::TYPE_RGB
+//    - C2PlanarLayout::TYPE_RGBA
+//
+// Following settings are not configurable by the client
+//    - encoding deadline is realtime
+//    - multithreaded encoding utilizes a number of threads equal
+// to online cpu's available
+//    - the algorithm interface for encoder is decided by the sub-class in use
+//    - fractional bits of frame rate is discarded
+//    - timestamps are in microseconds, therefore encoder timebase is fixed
+// to 1/1000000
+
+struct C2SoftVpxEnc : public SimpleC2Component {
+    class IntfImpl;
+
+    C2SoftVpxEnc(const char* name, c2_node_id_t id,
+                 const std::shared_ptr<IntfImpl>& intfImpl);
+
+    // From SimpleC2Component
+    c2_status_t onInit() override final;
+    c2_status_t onStop() override final;
+    void onReset() override final;
+    void onRelease() override final;
+    c2_status_t onFlush_sm() override final;
+
+    void process(
+            const std::unique_ptr<C2Work> &work,
+            const std::shared_ptr<C2BlockPool> &pool) override final;
+    c2_status_t drain(
+            uint32_t drainMode,
+            const std::shared_ptr<C2BlockPool> &pool) override final;
+
+ protected:
+     std::shared_ptr<IntfImpl> mIntf;
+     virtual ~C2SoftVpxEnc();
+
+     // Initializes vpx encoder with available settings.
+     status_t initEncoder();
+
+     // Populates mCodecInterface with codec specific settings.
+     virtual void setCodecSpecificInterface() = 0;
+
+     // Sets codec specific configuration.
+     virtual void setCodecSpecificConfiguration() = 0;
+
+     // Sets codec specific encoder controls.
+     virtual vpx_codec_err_t setCodecSpecificControls() = 0;
+
+     // Get current encode flags.
+     virtual vpx_enc_frame_flags_t getEncodeFlags();
+
+     enum TemporalReferences {
+         // For 1 layer case: reference all (last, golden, and alt ref), but only
+         // update last.
+         kTemporalUpdateLastRefAll = 12,
+         // First base layer frame for 3 temporal layers, which updates last and
+         // golden with alt ref dependency.
+         kTemporalUpdateLastAndGoldenRefAltRef = 11,
+         // First enhancement layer with alt ref dependency.
+         kTemporalUpdateGoldenRefAltRef = 10,
+         // First enhancement layer with alt ref dependency.
+         kTemporalUpdateGoldenWithoutDependencyRefAltRef = 9,
+         // Base layer with alt ref dependency.
+         kTemporalUpdateLastRefAltRef = 8,
+         // Highest enhacement layer without dependency on golden with alt ref
+         // dependency.
+         kTemporalUpdateNoneNoRefGoldenRefAltRef = 7,
+         // Second layer and last frame in cycle, for 2 layers.
+         kTemporalUpdateNoneNoRefAltref = 6,
+         // Highest enhancement layer.
+         kTemporalUpdateNone = 5,
+         // Second enhancement layer.
+         kTemporalUpdateAltref = 4,
+         // Second enhancement layer without dependency on previous frames in
+         // the second enhancement layer.
+         kTemporalUpdateAltrefWithoutDependency = 3,
+         // First enhancement layer.
+         kTemporalUpdateGolden = 2,
+         // First enhancement layer without dependency on previous frames in
+         // the first enhancement layer.
+         kTemporalUpdateGoldenWithoutDependency = 1,
+         // Base layer.
+         kTemporalUpdateLast = 0,
+     };
+     enum {
+         kMaxTemporalPattern = 8
+     };
+
+     // vpx specific opaque data structure that
+     // stores encoder state
+     vpx_codec_ctx_t* mCodecContext;
+
+     // vpx specific data structure that
+     // stores encoder configuration
+     vpx_codec_enc_cfg_t* mCodecConfiguration;
+
+     // vpx specific read-only data structure
+     // that specifies algorithm interface (e.g. vp8)
+     vpx_codec_iface_t* mCodecInterface;
+
+     // align stride to the power of 2
+     int32_t mStrideAlign;
+
+     // Color format for the input port
+     vpx_img_fmt_t mColorFormat;
+
+     // Bitrate control mode, either constant or variable
+     vpx_rc_mode mBitrateControlMode;
+
+     // Parameter that denotes whether error resilience
+     // is enabled in encoder
+     bool mErrorResilience;
+
+     // Minimum (best quality) quantizer
+     uint32_t mMinQuantizer;
+
+     // Maximum (worst quality) quantizer
+     uint32_t mMaxQuantizer;
+
+     // Number of coding temporal layers to be used.
+     size_t mTemporalLayers;
+
+     // Temporal layer bitrare ratio in percentage
+     uint32_t mTemporalLayerBitrateRatio[MAXTEMPORALLAYERS];
+
+     // Temporal pattern type
+     TemporalPatternType mTemporalPatternType;
+
+     // Temporal pattern length
+     size_t mTemporalPatternLength;
+
+     // Temporal pattern current index
+     size_t mTemporalPatternIdx;
+
+     // Frame type temporal pattern
+     TemporalReferences mTemporalPattern[kMaxTemporalPattern];
+
+     // Last input buffer timestamp
+     uint64_t mLastTimestamp;
+
+     // Number of input frames
+     int64_t mNumInputFrames;
+
+     // Conversion buffer is needed to input to
+     // yuv420 planar format.
+     MemoryBlock mConversionBuffer;
+
+     // Signalled EOS
+     bool mSignalledOutputEos;
+
+     // Signalled Error
+     bool mSignalledError;
+
+    // configurations used by component in process
+    // (TODO: keep this in intf but make them internal only)
+    std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
+    std::shared_ptr<C2StreamIntraRefreshTuning::output> mIntraRefresh;
+    std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
+    std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+    std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
+    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
+
+     C2_DO_NOT_COPY(C2SoftVpxEnc);
+};
+
+class C2SoftVpxEnc::IntfImpl : public C2InterfaceHelper {
+   public:
+    explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
+        : C2InterfaceHelper(helper) {
+        setDerivedInstance(this);
+
+        addParameter(
+            DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
+                .withConstValue(
+                    new C2StreamFormatConfig::input(0u, C2FormatVideo))
+                .build());
+
+        addParameter(
+            DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
+                .withConstValue(
+                    new C2StreamFormatConfig::output(0u, C2FormatCompressed))
+                .build());
+
+        addParameter(
+            DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
+                .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
+                    MEDIA_MIMETYPE_VIDEO_RAW))
+                .build());
+
+        addParameter(
+            DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
+                .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
+#ifdef VP9
+                    MEDIA_MIMETYPE_VIDEO_VP9
+#else
+                    MEDIA_MIMETYPE_VIDEO_VP8
+#endif
+                    ))
+                .build());
+
+        addParameter(DefineParam(mUsage, C2_NAME_INPUT_STREAM_USAGE_SETTING)
+                         .withConstValue(new C2StreamUsageTuning::input(
+                             0u, (uint64_t)C2MemoryUsage::CPU_READ))
+                         .build());
+
+        addParameter(
+            DefineParam(mSize, C2_NAME_STREAM_VIDEO_SIZE_SETTING)
+                .withDefault(new C2VideoSizeStreamTuning::input(0u, 320, 240))
+                .withFields({
+                    C2F(mSize, width).inRange(2, 2048, 2),
+                    C2F(mSize, height).inRange(2, 2048, 2),
+                })
+                .withSetter(SizeSetter)
+                .build());
+
+        addParameter(
+            DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
+                .withDefault(new C2StreamBitrateModeTuning::output(
+                        0u, C2Config::BITRATE_CONST))
+                .withFields({
+                    C2F(mBitrateMode, value).oneOf({
+                        C2Config::BITRATE_CONST, C2Config::BITRATE_VARIABLE })
+                })
+                .withSetter(
+                    Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
+                .build());
+
+        addParameter(
+            DefineParam(mFrameRate, C2_NAME_STREAM_FRAME_RATE_SETTING)
+                .withDefault(new C2StreamFrameRateInfo::output(0u, 30.))
+                // TODO: More restriction?
+                .withFields({C2F(mFrameRate, value).greaterThan(0.)})
+                .withSetter(
+                    Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
+                .build());
+
+        addParameter(
+            DefineParam(mLayering, C2_PARAMKEY_TEMPORAL_LAYERING)
+                .withDefault(C2StreamTemporalLayeringTuning::output::AllocShared(0u, 0, 0, 0))
+                .withFields({
+                    C2F(mLayering, m.layerCount).inRange(0, 4),
+                    C2F(mLayering, m.bLayerCount).inRange(0, 0),
+                    C2F(mLayering, m.bitrateRatios).inRange(0., 1.)
+                })
+                .withSetter(LayeringSetter)
+                .build());
+
+        addParameter(
+                DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
+                .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
+                .withFields({C2F(mSyncFramePeriod, value).any()})
+                .withSetter(Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps)
+                .build());
+
+        addParameter(
+            DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
+                .withDefault(new C2BitrateTuning::output(0u, 64000))
+                .withFields({C2F(mBitrate, value).inRange(4096, 40000000)})
+                .withSetter(BitrateSetter)
+                .build());
+
+        addParameter(
+                DefineParam(mIntraRefresh, C2_PARAMKEY_INTRA_REFRESH)
+                .withConstValue(new C2StreamIntraRefreshTuning::output(
+                             0u, C2Config::INTRA_REFRESH_DISABLED, 0.))
+                .build());
+
+        addParameter(
+        DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+        .withDefault(new C2StreamProfileLevelInfo::output(
+                0u, PROFILE_VP9_0, LEVEL_VP9_4_1))
+        .withFields({
+            C2F(mProfileLevel, profile).equalTo(
+                PROFILE_VP9_0
+            ),
+            C2F(mProfileLevel, level).equalTo(
+                LEVEL_VP9_4_1),
+        })
+        .withSetter(ProfileLevelSetter)
+        .build());
+
+        addParameter(
+                DefineParam(mRequestSync, C2_PARAMKEY_REQUEST_SYNC_FRAME)
+                .withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE))
+                .withFields({C2F(mRequestSync, value).oneOf({ C2_FALSE, C2_TRUE }) })
+                .withSetter(Setter<decltype(*mRequestSync)>::NonStrictValueWithNoDeps)
+                .build());
+    }
+
+    static C2R BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) {
+        (void)mayBlock;
+        C2R res = C2R::Ok();
+        if (me.v.value <= 4096) {
+            me.set().value = 4096;
+        }
+        return res;
+    }
+
+    static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe,
+                          C2P<C2StreamPictureSizeInfo::input> &me) {
+        (void)mayBlock;
+        C2R res = C2R::Ok();
+        if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
+            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
+            me.set().width = oldMe.v.width;
+        }
+        if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
+            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
+            me.set().height = oldMe.v.height;
+        }
+        return res;
+    }
+
+    static C2R ProfileLevelSetter(
+            bool mayBlock,
+            C2P<C2StreamProfileLevelInfo::output> &me) {
+        (void)mayBlock;
+        if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
+            me.set().profile = PROFILE_VP9_0;
+        }
+        if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
+            me.set().level = LEVEL_VP9_4_1;
+        }
+        return C2R::Ok();
+    }
+
+    static C2R LayeringSetter(bool mayBlock, C2P<C2StreamTemporalLayeringTuning::output>& me) {
+        (void)mayBlock;
+        C2R res = C2R::Ok();
+        if (me.v.m.layerCount > 4) {
+            me.set().m.layerCount = 4;
+        }
+        me.set().m.bLayerCount = 0;
+        // ensure ratios are monotonic and clamped between 0 and 1
+        for (size_t ix = 0; ix < me.v.flexCount(); ++ix) {
+            me.set().m.bitrateRatios[ix] = c2_clamp(
+                ix > 0 ? me.v.m.bitrateRatios[ix - 1] : 0, me.v.m.bitrateRatios[ix], 1.);
+        }
+        ALOGI("setting temporal layering %u + %u", me.v.m.layerCount, me.v.m.bLayerCount);
+        return res;
+    }
+
+    // unsafe getters
+    std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
+    std::shared_ptr<C2StreamIntraRefreshTuning::output> getIntraRefresh_l() const { return mIntraRefresh; }
+    std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; }
+    std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
+    std::shared_ptr<C2StreamBitrateModeTuning::output> getBitrateMode_l() const { return mBitrateMode; }
+    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const { return mRequestSync; }
+    std::shared_ptr<C2StreamTemporalLayeringTuning::output> getTemporalLayers_l() const { return mLayering; }
+    uint32_t getSyncFramePeriod() const {
+        if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) {
+            return 0;
+        }
+        double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
+        return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
+    }
+
+   private:
+    std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
+    std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
+    std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
+    std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
+    std::shared_ptr<C2StreamUsageTuning::input> mUsage;
+    std::shared_ptr<C2VideoSizeStreamTuning::input> mSize;
+    std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
+    std::shared_ptr<C2StreamTemporalLayeringTuning::output> mLayering;
+    std::shared_ptr<C2StreamIntraRefreshTuning::output> mIntraRefresh;
+    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
+    std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
+    std::shared_ptr<C2BitrateTuning::output> mBitrate;
+    std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
+    std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2_SOFT_VPX_ENC_H__
diff --git a/media/codec2/components/vpx/MODULE_LICENSE_APACHE2 b/media/codec2/components/vpx/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/codec2/components/vpx/MODULE_LICENSE_APACHE2
diff --git a/media/codec2/components/vpx/NOTICE b/media/codec2/components/vpx/NOTICE
new file mode 100644
index 0000000..faed58a
--- /dev/null
+++ b/media/codec2/components/vpx/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2013, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+