Merge "Start Codec2.0 Implementation"
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/Android.bp b/media/libstagefright/codec2/hidl/impl/1.0/Android.bp
new file mode 100644
index 0000000..3d930c6
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/Android.bp
@@ -0,0 +1,42 @@
+cc_library {
+    name: "libstagefright_codec2_hidl@1.0",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+
+    defaults: ["hidl_defaults"],
+
+    srcs: [
+        "Component.cpp",
+        "ComponentStore.cpp",
+        "Configurable.cpp",
+        "types.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.media.bufferpool@1.0",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libutils",
+        "vendor.google.media.c2@1.0",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    export_shared_lib_headers: [
+        "libstagefright_codec2",
+    ],
+
+    // Private include directories
+    header_libs: [
+        "libstagefright_codec2_internal",
+    ],
+}
+
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp b/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp
new file mode 100644
index 0000000..bbcd630
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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 "Codec2-Component"
+#include <log/log.h>
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/types.h>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using namespace ::android;
+
+// Implementation of ConfigurableC2Intf based on C2ComponentInterface
+struct CompIntf : public ConfigurableC2Intf {
+    CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
+        ConfigurableC2Intf(intf->getName()),
+        mIntf(intf) {
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*>& params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        return mIntf->config_vb(params, mayBlock, failures);
+    }
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index>& indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params) override {
+        return mIntf->query_vb({}, indices, mayBlock, params);
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        return mIntf->querySupportedParams_nb(params);
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const override {
+        return mIntf->querySupportedValues_vb(fields, mayBlock);
+    }
+
+protected:
+    std::shared_ptr<C2ComponentInterface> mIntf;
+};
+
+// ComponentInterface
+ComponentInterface::ComponentInterface(
+        const std::shared_ptr<C2ComponentInterface>& intf,
+        const sp<ComponentStore>& store) :
+    Configurable(new CachedConfigurable(std::make_unique<CompIntf>(intf))),
+    mInterface(intf) {
+    mInit = init(store.get());
+}
+
+c2_status_t ComponentInterface::status() const {
+    return mInit;
+}
+
+// ComponentListener wrapper
+struct Listener : public C2Component::Listener {
+    Listener(const wp<IComponentListener>& listener) : mListener(listener) {
+        // TODO: Should we track interface errors? We could reuse onError() or
+        // create our own error channel.
+    }
+
+    virtual void onError_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            uint32_t errorCode) override {
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            listener->onError(Status::OK, errorCode);
+        }
+    }
+
+    virtual void onTripped_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+            ) override {
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            hidl_vec<SettingResult> settingResults(c2settingResult.size());
+            size_t ix = 0;
+            for (const std::shared_ptr<C2SettingResult> &c2result :
+                    c2settingResult) {
+                if (c2result) {
+                    objcpy(&settingResults[ix++], *c2result);
+                }
+            }
+            settingResults.resize(ix);
+            listener->onTripped(settingResults);
+        }
+    }
+
+    virtual void onWorkDone_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            std::list<std::unique_ptr<C2Work>> c2workItems) override {
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            WorkBundle workBundle;
+
+            // TODO: Connect with bufferpool API to send Works & Buffers
+            if (objcpy(&workBundle, c2workItems) != Status::OK) {
+                ALOGE("onWorkDone() received corrupted work items.");
+                return;
+            }
+            listener->onWorkDone(workBundle);
+
+            // Finish buffer transfers: nothing else to do
+        }
+    }
+
+protected:
+    wp<IComponentListener> mListener;
+};
+
+// Component
+Component::Component(
+        const std::shared_ptr<C2Component>& component,
+        const sp<IComponentListener>& listener,
+        const sp<ComponentStore>& store) :
+    Configurable(new CachedConfigurable(
+            std::make_unique<CompIntf>(component->intf()))),
+    mComponent(component),
+    mInterface(component->intf()),
+    mListener(listener) /* , // TODO: Do we need store for anything?
+    mStore(store)*/ {
+    std::shared_ptr<C2Component::Listener> c2listener =
+            std::make_shared<Listener>(listener);
+    c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
+    // Retrieve supported parameters from store
+    // TODO: We could cache this per component/interface type
+    mInit = init(store.get());
+    mInit = mInit != C2_OK ? res : mInit;
+}
+
+// Methods from ::android::hardware::media::c2::V1_0::IComponent
+Return<Status> Component::queue(const WorkBundle& workBundle) {
+    std::list<std::unique_ptr<C2Work>> c2works;
+
+    // TODO: Connect with bufferpool API for buffer transfers
+    if (objcpy(&c2works, workBundle) != C2_OK) {
+        return Status::CORRUPTED;
+    }
+    (void)workBundle;
+    return static_cast<Status>(mComponent->queue_nb(&c2works));
+}
+
+Return<void> Component::flush(flush_cb _hidl_cb) {
+    std::list<std::unique_ptr<C2Work>> c2flushedWorks;
+    c2_status_t c2res = mComponent->flush_sm(
+            C2Component::FLUSH_COMPONENT,
+            &c2flushedWorks);
+    WorkBundle flushedWorkBundle;
+
+    Status res = static_cast<Status>(c2res);
+    if (c2res == C2_OK) {
+        // TODO: Connect with bufferpool API for buffer transfers
+        res = objcpy(&flushedWorkBundle, c2flushedWorks);
+    }
+    _hidl_cb(res, flushedWorkBundle);
+    return Void();
+}
+
+Return<Status> Component::drain(bool withEos) {
+    return static_cast<Status>(mComponent->drain_nb(withEos ?
+            C2Component::DRAIN_COMPONENT_WITH_EOS :
+            C2Component::DRAIN_COMPONENT_NO_EOS));
+}
+
+Return<Status> Component::connectToInputSurface(const sp<IInputSurface>& surface) {
+    // TODO implement
+    (void)surface;
+    return Status::OK;
+}
+
+Return<Status> Component::connectToOmxInputSurface(
+        const sp<::android::hardware::graphics::bufferqueue::V1_0::
+        IGraphicBufferProducer>& producer,
+        const sp<::android::hardware::media::omx::V1_0::
+        IGraphicBufferSource>& source) {
+    // TODO implement
+    (void)producer;
+    (void)source;
+    return Status::OK;
+}
+
+Return<Status> Component::disconnectFromInputSurface() {
+    // TODO implement
+    return Status::OK;
+}
+
+Return<void> Component::createBlockPool(uint32_t allocatorId, createBlockPool_cb _hidl_cb) {
+    // TODO implement
+    (void)allocatorId;
+    _hidl_cb(Status::OK, 0 /* blockPoolId */, nullptr /* configurable */);
+    return Void();
+}
+
+Return<Status> Component::start() {
+    return static_cast<Status>(mComponent->start());
+}
+
+Return<Status> Component::stop() {
+    return static_cast<Status>(mComponent->stop());
+}
+
+Return<Status> Component::reset() {
+    return static_cast<Status>(mComponent->reset());
+}
+
+Return<Status> Component::release() {
+    return static_cast<Status>(mComponent->release());
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp b/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp
new file mode 100644
index 0000000..d42d67a
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 "Codec2-ComponentStore"
+#include <log/log.h>
+
+#include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
+#include <codec2/hidl/1.0/types.h>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using namespace ::android;
+
+struct StoreIntf : public ConfigurableC2Intf {
+    StoreIntf(const std::shared_ptr<C2ComponentStore>& store) :
+        ConfigurableC2Intf(store ? store->getName() : ""),
+        mStore(store) {
+    }
+
+    c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>> *const failures
+            ) override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->config_sm(params, failures);
+    }
+
+    c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>> *const params) override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->query_sm({}, indices, params);
+    }
+
+    c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+            ) const override {
+        return mStore->querySupportedParams_nb(params);
+    }
+
+    c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery> &fields,
+            c2_blocking_t mayBlock) const override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->querySupportedValues_sm(fields);
+    }
+
+protected:
+    std::shared_ptr<C2ComponentStore> mStore;
+};
+
+
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store) :
+    Configurable(new CachedConfigurable(std::make_unique<StoreIntf>(store))),
+    mStore(store) {
+    // Retrieve struct descriptors
+    mParamReflector = mStore->getParamReflector();
+
+    // Retrieve supported parameters from store
+    mInit = init(this);
+}
+
+c2_status_t ComponentStore::validateSupportedParams(
+        const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
+    c2_status_t res = C2_OK;
+
+    for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
+        if (!desc) {
+            // All descriptors should be valid
+            res = res ? res : C2_BAD_VALUE;
+            continue;
+        }
+        C2Param::CoreIndex coreIndex = desc->index().coreIndex();
+        auto it = mStructDescriptors.find(coreIndex);
+        if (it == mStructDescriptors.end()) {
+            std::shared_ptr<C2StructDescriptor> structDesc =
+                    mParamReflector->describe(coreIndex);
+            if (!structDesc) {
+                // All supported params must be described
+                res = C2_BAD_INDEX;
+            }
+            mStructDescriptors.insert({ coreIndex, structDesc });
+        }
+    }
+    return res;
+}
+
+// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
+Return<void> ComponentStore::createComponent(
+        const hidl_string& name,
+        const sp<IComponentListener>& listener,
+        // TODO: Return the pool if the component has it.
+        const sp<IClientManager>& /* pool */,
+        createComponent_cb _hidl_cb) {
+    std::shared_ptr<C2Component> c2component;
+    c2_status_t res = mStore->createComponent(name, &c2component);
+    sp<IComponent> component;
+    if (res == C2_OK) {
+        component = new Component(c2component, listener, this);
+    }
+    _hidl_cb((Status)res, component);
+    return Void();
+}
+
+Return<void> ComponentStore::createInterface(
+        const hidl_string& name,
+        createInterface_cb _hidl_cb) {
+    std::shared_ptr<C2ComponentInterface> c2interface;
+    c2_status_t res = mStore->createInterface(name, &c2interface);
+    sp<IComponentInterface> interface;
+    if (res == C2_OK) {
+        interface = new ComponentInterface(c2interface, this);
+    }
+    _hidl_cb((Status)res, interface);
+    return Void();
+}
+
+Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) {
+    std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
+            mStore->listComponents();
+    hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size());
+    size_t ix = 0;
+    for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
+        if (c2trait) {
+            objcpy(&traits[ix++], *c2trait);
+        }
+    }
+    traits.resize(ix);
+    _hidl_cb(traits);
+    return Void();
+}
+
+Return<sp<IInputSurface>> ComponentStore::createInputSurface() {
+    // TODO implement
+    return sp<IInputSurface> {};
+}
+
+Return<void> ComponentStore::getStructDescriptors(
+        const hidl_vec<uint32_t>& indices,
+        getStructDescriptors_cb _hidl_cb) {
+    hidl_vec<StructDescriptor> descriptors(indices.size());
+    size_t dstIx = 0;
+    Status res;
+    for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
+        const auto item = mStructDescriptors.find(
+                C2Param::CoreIndex(indices[srcIx]).coreIndex());
+        if (item == mStructDescriptors.end()) {
+            res = Status::NOT_FOUND;
+        } else if (item->second) {
+            objcpy(&descriptors[dstIx++], *item->second);
+        } else {
+            res = Status::NO_MEMORY;
+        }
+    }
+    descriptors.resize(dstIx);
+    _hidl_cb(res, descriptors);
+    return Void();
+}
+
+Return<sp<IClientManager>> ComponentStore::getPoolClientManager() {
+    // TODO implement
+    return sp<IClientManager> {};
+}
+
+Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
+    // TODO implement
+    (void)src;
+    (void)dst;
+    return Status {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/Configurable.cpp b/media/libstagefright/codec2/hidl/impl/1.0/Configurable.cpp
new file mode 100644
index 0000000..3f041a9
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/Configurable.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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 "Codec2-Configurable"
+#include <log/log.h>
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.0/types.h>
+#include <C2ParamInternal.h>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using namespace ::android;
+
+CachedConfigurable::CachedConfigurable(
+        std::unique_ptr<ConfigurableC2Intf>&& intf) :
+    mIntf(std::move(intf)) {
+}
+
+c2_status_t CachedConfigurable::init(ComponentStore* store) {
+    // Retrieve supported parameters from store
+    c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
+    c2_status_t validate = store->validateSupportedParams(mSupportedParams);
+    return init == C2_OK ? C2_OK : validate;
+}
+
+// Methods from ::android::hardware::media::c2::V1_0::IConfigurable follow.
+Return<void> CachedConfigurable::getName(getName_cb _hidl_cb) {
+    _hidl_cb(mIntf->getName());
+    return Void();
+}
+
+Return<void> CachedConfigurable::query(
+        const hidl_vec<uint32_t>& indices,
+        bool mayBlock,
+        query_cb _hidl_cb) {
+    typedef C2Param::Index Index;
+    std::vector<Index> c2heapParamIndices(
+            (Index*)indices.data(),
+            (Index*)indices.data() + indices.size());
+    std::vector<std::unique_ptr<C2Param>> c2heapParams;
+    c2_status_t c2res = mIntf->query(
+            c2heapParamIndices,
+            mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
+            &c2heapParams);
+
+    hidl_vec<uint8_t> params;
+    createParamsBlob(&params, c2heapParams);
+    _hidl_cb(static_cast<Status>(c2res), params);
+
+    return Void();
+}
+
+Return<void> CachedConfigurable::config(
+        const hidl_vec<uint8_t>& inParams,
+        bool mayBlock,
+        config_cb _hidl_cb) {
+    std::vector<C2Param*> c2params;
+    if (parseParamsBlob(&c2params, inParams) != C2_OK) {
+        _hidl_cb(Status::CORRUPTED,
+                hidl_vec<SettingResult>(),
+                hidl_vec<uint8_t>());
+        return Void();
+    }
+    // TODO: check if blob was invalid
+    std::vector<std::unique_ptr<C2SettingResult>> c2failures;
+    c2_status_t c2res = mIntf->config(
+            c2params,
+            mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
+            &c2failures);
+    hidl_vec<SettingResult> failures(c2failures.size());
+    {
+        size_t ix = 0;
+        for (const std::unique_ptr<C2SettingResult>& c2result : c2failures) {
+            if (c2result) {
+                objcpy(&failures[ix++], *c2result);
+            }
+        }
+        failures.resize(ix);
+    }
+    hidl_vec<uint8_t> outParams;
+    createParamsBlob(&outParams, c2params);
+    _hidl_cb((Status)c2res, failures, outParams);
+    return Void();
+}
+
+Return<void> CachedConfigurable::querySupportedParams(
+        uint32_t start,
+        uint32_t count,
+        querySupportedParams_cb _hidl_cb) {
+    C2LinearRange request = C2LinearCapacity(mSupportedParams.size()).range(
+            start, count);
+    hidl_vec<ParamDescriptor> params(request.size());
+    Status res = Status::OK;
+    size_t dstIx = 0;
+    for (size_t srcIx = request.offset(); srcIx < request.endOffset(); ++srcIx) {
+        if (mSupportedParams[srcIx]) {
+            objcpy(&params[dstIx++], *mSupportedParams[srcIx]);
+        } else {
+            res = Status::CORRUPTED;
+        }
+    }
+    params.resize(dstIx);
+    _hidl_cb(res, params);
+    return Void();
+}
+
+Return<void> CachedConfigurable::querySupportedValues(
+        const hidl_vec<FieldSupportedValuesQuery>& inFields,
+        bool mayBlock,
+        querySupportedValues_cb _hidl_cb) {
+    std::vector<C2FieldSupportedValuesQuery> c2fields;
+    {
+        // C2FieldSupportedValuesQuery objects are restricted in that some
+        // members are const.
+        // C2ParamField - required for its constructor - has no constructors
+        // from fields. Use C2ParamInspector.
+        for (const FieldSupportedValuesQuery &query : inFields) {
+            c2fields.emplace_back(_C2ParamInspector::CreateParamField(
+                    query.field.index,
+                    query.field.fieldId.offset,
+                    query.field.fieldId.size),
+                    query.type == FieldSupportedValuesQuery::Type::POSSIBLE ?
+                    C2FieldSupportedValuesQuery::POSSIBLE :
+                    C2FieldSupportedValuesQuery::CURRENT);
+        }
+    }
+    c2_status_t c2res = mIntf->querySupportedValues(
+            c2fields,
+            mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
+    hidl_vec<FieldSupportedValuesQueryResult> outFields(inFields.size());
+    {
+        size_t ix = 0;
+        for (const C2FieldSupportedValuesQuery &result : c2fields) {
+            objcpy(&outFields[ix++], result);
+        }
+    }
+    _hidl_cb((Status)c2res, outFields);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Component.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Component.h
new file mode 100644
index 0000000..0308fe0
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Component.h
@@ -0,0 +1,85 @@
+#ifndef VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENT_H
+#define VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENT_H
+
+#include <codec2/hidl/1.0/Configurable.h>
+
+#include <vendor/google/media/c2/1.0/IComponentListener.h>
+#include <vendor/google/media/c2/1.0/IComponentStore.h>
+#include <vendor/google/media/c2/1.0/IComponent.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2.h>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+struct ComponentInterface : public Configurable<IComponentInterface> {
+    ComponentInterface(
+            const std::shared_ptr<C2ComponentInterface>& interface,
+            const sp<ComponentStore>& store);
+    c2_status_t status() const;
+
+protected:
+    c2_status_t mInit;
+    std::shared_ptr<C2ComponentInterface> mInterface;
+    // sp<ComponentStore> mStore; // TODO needed?
+};
+
+struct Component : public Configurable<IComponent> {
+    Component(
+            const std::shared_ptr<C2Component>&,
+            const sp<IComponentListener>& listener,
+            const sp<ComponentStore>& store);
+
+    // Methods from gIComponent follow.
+    virtual Return<Status> queue(const WorkBundle& workBundle) override;
+    virtual Return<void> flush(flush_cb _hidl_cb) override;
+    virtual Return<Status> drain(bool withEos) override;
+    virtual Return<Status> connectToInputSurface(
+            const sp<IInputSurface>& surface) override;
+    virtual Return<Status> connectToOmxInputSurface(
+            const sp<::android::hardware::graphics::bufferqueue::V1_0::
+            IGraphicBufferProducer>& producer,
+            const sp<::android::hardware::media::omx::V1_0::
+            IGraphicBufferSource>& source) override;
+    virtual Return<Status> disconnectFromInputSurface() override;
+    virtual Return<void> createBlockPool(
+            uint32_t allocatorId,
+            createBlockPool_cb _hidl_cb) override;
+    virtual Return<Status> start() override;
+    virtual Return<Status> stop() override;
+    virtual Return<Status> reset() override;
+    virtual Return<Status> release() override;
+
+protected:
+    c2_status_t mInit;
+    std::shared_ptr<C2Component> mComponent;
+    std::shared_ptr<C2ComponentInterface> mInterface;
+    sp<IComponentListener> mListener;
+    // sp<ComponentStore> mStore; // TODO needed?
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
+
+#endif  // VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENT_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ComponentStore.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ComponentStore.h
new file mode 100644
index 0000000..c3f92a0
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ComponentStore.h
@@ -0,0 +1,99 @@
+/*
+ * 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 VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENTSTORE_H
+#define VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENTSTORE_H
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/Configurable.h>
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <vendor/google/media/c2/1.0/IComponentStore.h>
+#include <android/hardware/media/bufferpool/1.0/IClientManager.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <vector>
+#include <map>
+#include <memory>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::bufferpool::V1_0::IClientManager;
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore : public Configurable<IComponentStore> {
+    ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
+    virtual ~ComponentStore() = default;
+
+    c2_status_t status() const {
+        return mInit;
+    }
+
+    c2_status_t validateSupportedParams(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
+
+    // Methods from ::android::hardware::media::c2::V1_0::IComponentStore
+    Return<void> createComponent(
+            const hidl_string& name,
+            const sp<IComponentListener>& listener,
+            const sp<IClientManager>& pool,
+            createComponent_cb _hidl_cb) override;
+    Return<void> createInterface(
+            const hidl_string& name,
+            createInterface_cb _hidl_cb) override;
+    Return<void> listComponents(listComponents_cb _hidl_cb) override;
+    Return<sp<IInputSurface>> createInputSurface() override;
+    Return<void> getStructDescriptors(
+            const hidl_vec<uint32_t>& indices,
+            getStructDescriptors_cb _hidl_cb) override;
+    Return<sp<IClientManager>> getPoolClientManager() override;
+    Return<Status> copyBuffer(
+            const Buffer& src,
+            const Buffer& dst) override;
+
+protected:
+    c2_status_t mInit;
+    std::shared_ptr<C2ComponentStore> mStore;
+    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>>
+            mStructDescriptors;
+
+    sp<IClientManager> mPoolManager;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
+
+#endif  // VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENTSTORE_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Configurable.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Configurable.h
new file mode 100644
index 0000000..697d483
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Configurable.h
@@ -0,0 +1,157 @@
+/*
+ * 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 VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLE_H
+#define VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLE_H
+
+#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <vendor/google/media/c2/1.0/IConfigurable.h>
+#include <hidl/Status.h>
+
+#include <memory>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+/**
+ * Implementation of the IConfigurable interface that supports caching of
+ * supported parameters from a supplied ComponentStore.
+ *
+ * This is mainly the same for all of the configurable C2 interfaces though
+ * there are slight differences in the blocking behavior. This is handled in the
+ * ConfigurableC2Intf implementations.
+ */
+struct CachedConfigurable : public IConfigurable {
+    CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
+
+    c2_status_t init(ComponentStore* store);
+
+    // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
+
+    virtual Return<void> getName(getName_cb _hidl_cb) override;
+
+    virtual Return<void> query(
+            const hidl_vec<uint32_t>& indices,
+            bool mayBlock,
+            query_cb _hidl_cb) override;
+
+    virtual Return<void> config(
+            const hidl_vec<uint8_t>& inParams,
+            bool mayBlock,
+            config_cb _hidl_cb) override;
+
+    virtual Return<void> querySupportedParams(
+            uint32_t start,
+            uint32_t count,
+            querySupportedParams_cb _hidl_cb) override;
+
+    virtual Return<void> querySupportedValues(
+            const hidl_vec<FieldSupportedValuesQuery>& inFields,
+            bool mayBlock,
+            querySupportedValues_cb _hidl_cb) override;
+
+protected:
+    // Common Codec2.0 interface wrapper
+    std::unique_ptr<ConfigurableC2Intf> mIntf;
+
+    // Cached supported params
+    std::vector<std::shared_ptr<C2ParamDescriptor>> mSupportedParams;
+};
+
+/**
+ * Template that implements the `IConfigurable` interface for an inherited
+ * interface. Classes that implement a child interface `I` of `IConfigurable`
+ * can derive from `Configurable<I>`.
+ */
+template <typename I>
+struct Configurable : public I {
+    Configurable(const sp<CachedConfigurable>& intf): mIntf(intf) {
+    }
+
+    c2_status_t init(ComponentStore* store) {
+        return mIntf->init(store);
+    }
+
+    // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
+
+    using getName_cb = typename I::getName_cb;
+    virtual Return<void> getName(getName_cb _hidl_cb) override {
+        return mIntf->getName(_hidl_cb);
+    }
+
+    using query_cb = typename I::query_cb;
+    virtual Return<void> query(
+            const hidl_vec<uint32_t>& indices,
+            bool mayBlock,
+            query_cb _hidl_cb) override {
+        return mIntf->query(indices, mayBlock, _hidl_cb);
+    }
+
+    using config_cb = typename I::config_cb;
+    virtual Return<void> config(
+            const hidl_vec<uint8_t>& inParams,
+            bool mayBlock,
+            config_cb _hidl_cb) override {
+        return mIntf->config(inParams, mayBlock, _hidl_cb);
+    }
+
+    using querySupportedParams_cb = typename I::querySupportedParams_cb;
+    virtual Return<void> querySupportedParams(
+            uint32_t start,
+            uint32_t count,
+            querySupportedParams_cb _hidl_cb) override {
+        return mIntf->querySupportedParams(start, count, _hidl_cb);
+    }
+
+    using querySupportedValues_cb = typename I::querySupportedValues_cb;
+    virtual Return<void> querySupportedValues(
+            const hidl_vec<FieldSupportedValuesQuery>& inFields,
+            bool mayBlock,
+            querySupportedValues_cb _hidl_cb) override {
+        return mIntf->querySupportedValues(inFields, mayBlock, _hidl_cb);
+    }
+
+protected:
+    sp<CachedConfigurable> mIntf;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
+
+#endif  // VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLE_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h
new file mode 100644
index 0000000..94d2e6d
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h
@@ -0,0 +1,80 @@
+/*
+ * 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 VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLEC2INTF_H
+#define VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLEC2INTF_H
+
+#include <C2Work.h>
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <hidl/HidlSupport.h>
+#include <utils/StrongPointer.h>
+#include <vector>
+#include <memory>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+/**
+ * Common Codec 2.0 interface wrapper.
+ */
+struct ConfigurableC2Intf {
+    C2String getName() const { return mName; }
+    /** C2ComponentInterface::query_vb sans stack params */
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params) = 0;
+    /** C2ComponentInterface::config_vb */
+    virtual c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+    /** C2ComponentInterface::querySupportedParams_nb */
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
+    /** C2ComponentInterface::querySupportedParams_nb */
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const = 0;
+
+    virtual ~ConfigurableC2Intf() = default;
+
+    ConfigurableC2Intf(const C2String& name) : mName(name) {}
+
+protected:
+    C2String mName; /* cache component name */
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
+
+#endif  // VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLEC2INTF_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h
new file mode 100644
index 0000000..41ee275
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h
@@ -0,0 +1,169 @@
+/*
+ * 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 VENDOR_GOOGLE_MEDIA_C2_V1_0_TYPES_H
+#define VENDOR_GOOGLE_MEDIA_C2_V1_0_TYPES_H
+
+#include <vendor/google/media/c2/1.0/types.h>
+#include <vendor/google/media/c2/1.0/IComponentStore.h>
+
+#include <C2Param.h>
+#include <C2Component.h>
+#include <C2Work.h>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+
+// Types of metadata for Blocks.
+struct C2Hidl_Range {
+    uint32_t offset;
+    uint32_t length; // Do not use "size" because the name collides with C2Info::size().
+};
+typedef C2GlobalParam<C2Info, C2Hidl_Range, 0> C2Hidl_RangeInfo;
+
+struct C2Hidl_Rect {
+    uint32_t left;
+    uint32_t top;
+    uint32_t width;
+    uint32_t height;
+};
+typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
+
+// C2SettingResult -> SettingResult
+Status C2_HIDE objcpy(
+        SettingResult* d,
+        const C2SettingResult& s);
+
+// SettingResult -> C2SettingResult
+c2_status_t C2_HIDE objcpy(
+        C2SettingResult* d,
+        const SettingResult& s);
+
+// C2ParamDescriptor -> ParamDescriptor
+Status C2_HIDE objcpy(
+        ParamDescriptor* d,
+        const C2ParamDescriptor& s);
+
+// ParamDescriptor -> std::unique_ptr<C2ParamDescriptor>
+c2_status_t C2_HIDE objcpy(
+        std::unique_ptr<C2ParamDescriptor>* d,
+        const ParamDescriptor& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+Status C2_HIDE objcpy(
+        FieldSupportedValuesQuery* d,
+        const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+c2_status_t C2_HIDE objcpy(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+Status C2_HIDE objcpy(
+        FieldSupportedValuesQueryResult* d,
+        const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
+c2_status_t C2_HIDE objcpy(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& sq,
+        const FieldSupportedValuesQueryResult& sr);
+
+// C2Component::Traits -> ComponentTraits
+Status C2_HIDE objcpy(
+        IComponentStore::ComponentTraits* d,
+        const C2Component::Traits& s);
+
+// ComponentTraits -> C2Component::Traits
+c2_status_t C2_HIDE objcpy(
+        C2Component::Traits* d,
+        const IComponentStore::ComponentTraits& s);
+
+// C2StructDescriptor -> StructDescriptor
+Status C2_HIDE objcpy(
+        StructDescriptor* d,
+        const C2StructDescriptor& s);
+
+// StructDescriptor -> C2StructDescriptor
+// TODO: This cannot be implemented yet because C2StructDescriptor does not
+// allow dynamic construction/modification.
+c2_status_t C2_HIDE objcpy(
+        C2StructDescriptor* d,
+        const StructDescriptor& s);
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+// TODO: Connect with Bufferpool
+Status C2_HIDE objcpy(
+        WorkBundle* d,
+        const std::list<std::unique_ptr<C2Work>>& s);
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+// TODO: Connect with Bufferpool
+c2_status_t C2_HIDE objcpy(
+        std::list<std::unique_ptr<C2Work>>* d,
+        const WorkBundle& s);
+
+/**
+ * Parses a params blob and returns C2Param pointers to its params.
+ * \param[out] params target vector of C2Param pointers
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed
+ * \retval C2_BAD_VALUE otherwise
+ */
+c2_status_t parseParamsBlob(
+        std::vector<C2Param*> *params,
+        const hidl_vec<uint8_t> &blob);
+
+/**
+ * Concatenates a list of C2Params into a params blob.
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval C2_OK if the blob was successfully created
+ * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
+ *         not const)
+ */
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<C2Param*> &params);
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<std::unique_ptr<C2Param>> &params);
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<std::shared_ptr<const C2Info>> &params);
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<std::unique_ptr<C2Tuning>> &params);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace google
+}  // namespace vendor
+
+#endif  // VENDOR_GOOGLE_MEDIA_C2_V1_0_TYPES_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/types.cpp b/media/libstagefright/codec2/hidl/impl/1.0/types.cpp
new file mode 100644
index 0000000..14ced2e
--- /dev/null
+++ b/media/libstagefright/codec2/hidl/impl/1.0/types.cpp
@@ -0,0 +1,1185 @@
+/*
+ * 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 "Codec2-types"
+#include <log/log.h>
+
+#include <codec2/hidl/1.0/types.h>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2PlatformSupport.h>
+#include <C2BlockInternal.h>
+#include <C2ParamInternal.h>
+#include <C2Param.h>
+#include <C2Buffer.h>
+#include <C2Work.h>
+#include <C2Component.h>
+#include <util/C2ParamUtils.h>
+
+#include <algorithm>
+
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using namespace ::android;
+
+namespace /* unnamed */ {
+
+template <typename Common, typename DstVector, typename SrcVector>
+void copyVector(DstVector* d, const SrcVector& s) {
+    static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
+            "DstVector's component size does not match Common");
+    static_assert(sizeof(Common) == sizeof(decltype(s[0])),
+            "SrcVector's component size does not match Common");
+    d->resize(s.size());
+    std::copy(
+            reinterpret_cast<const Common*>(&s[0]),
+            reinterpret_cast<const Common*>(&s[0] + s.size()),
+            reinterpret_cast<Common*>(&(*d)[0]));
+}
+
+// C2ParamField -> ParamField
+void objcpy(ParamField *d, const C2ParamField &s) {
+    d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
+    d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
+    d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+}
+
+struct C2ParamFieldBuilder : public C2ParamField {
+    C2ParamFieldBuilder() : C2ParamField(
+            static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
+    }
+    // ParamField -> C2ParamField
+    C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
+            static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
+            static_cast<uint32_t>(s.fieldId.offset),
+            static_cast<uint32_t>(s.fieldId.size)) {
+    }
+};
+
+// C2WorkOrdinalStruct -> WorkOrdinal
+void objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+    d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
+    d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
+    d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+}
+
+// WorkOrdinal -> C2WorkOrdinalStruct
+void objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+    d->frameIndex = c2_cntr64_t(s.frameIndex);
+    d->timestamp = c2_cntr64_t(s.timestampUs);
+    d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+}
+
+// C2FieldSupportedValues::range's type -> FieldSupportedValues::Range
+void objcpy(
+        FieldSupportedValues::Range* d,
+        const decltype(C2FieldSupportedValues::range)& s) {
+    d->min = static_cast<PrimitiveValue>(s.min.u64);
+    d->max = static_cast<PrimitiveValue>(s.max.u64);
+    d->step = static_cast<PrimitiveValue>(s.step.u64);
+    d->num = static_cast<PrimitiveValue>(s.num.u64);
+    d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+}
+
+// C2FieldSupportedValues -> FieldSupportedValues
+Status objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+    d->typeOther = static_cast<int32_t>(s.type);
+    switch (s.type) {
+    case C2FieldSupportedValues::EMPTY:
+        d->type = FieldSupportedValues::Type::EMPTY;
+        d->values.resize(0);
+        return Status::OK;
+    case C2FieldSupportedValues::RANGE:
+        d->type = FieldSupportedValues::Type::RANGE;
+        objcpy(&d->range, s.range);
+        d->values.resize(0);
+        return Status::OK;
+    default:
+        switch (s.type) {
+        case C2FieldSupportedValues::VALUES:
+            d->type = FieldSupportedValues::Type::VALUES;
+            break;
+        case C2FieldSupportedValues::FLAGS:
+            d->type = FieldSupportedValues::Type::FLAGS;
+            break;
+        default:
+            d->type = FieldSupportedValues::Type::OTHER;
+            // Copy all fields in this case
+            objcpy(&d->range, s.range);
+        }
+        d->values.resize(s.values.size());
+        copyVector<uint64_t>(&d->values, s.values);
+        return Status::OK;
+    }
+}
+
+// FieldSupportedValues::Range -> C2FieldSupportedValues::range's type
+void objcpy(
+        decltype(C2FieldSupportedValues::range)* d,
+        const FieldSupportedValues::Range& s) {
+    d->min.u64 = static_cast<uint64_t>(s.min);
+    d->max.u64 = static_cast<uint64_t>(s.max);
+    d->step.u64 = static_cast<uint64_t>(s.step);
+    d->num.u64 = static_cast<uint64_t>(s.num);
+    d->denom.u64 = static_cast<uint64_t>(s.denom);
+}
+
+// FieldSupportedValues -> C2FieldSupportedValues
+c2_status_t objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+    switch (s.type) {
+    case FieldSupportedValues::Type::EMPTY:
+        d->type = C2FieldSupportedValues::EMPTY;
+        return C2_OK;
+    case FieldSupportedValues::Type::RANGE:
+        d->type = C2FieldSupportedValues::RANGE;
+        objcpy(&d->range, s.range);
+        d->values.resize(0);
+        return C2_OK;
+    default:
+        switch (s.type) {
+        case FieldSupportedValues::Type::VALUES:
+            d->type = C2FieldSupportedValues::VALUES;
+            break;
+        case FieldSupportedValues::Type::FLAGS:
+            d->type = C2FieldSupportedValues::FLAGS;
+            break;
+        default:
+            d->type = static_cast<C2FieldSupportedValues::type_t>(s.typeOther);
+            // Copy all fields in this case
+            objcpy(&d->range, s.range);
+        }
+        copyVector<uint64_t>(&d->values, s.values);
+        return C2_OK;
+    }
+}
+
+} // unnamed namespace
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+Status objcpy(
+        FieldSupportedValuesQuery* d,
+        const C2FieldSupportedValuesQuery& s) {
+    objcpy(&d->field, s.field());
+    switch (s.type()) {
+    case C2FieldSupportedValuesQuery::POSSIBLE:
+        d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
+        break;
+    case C2FieldSupportedValuesQuery::CURRENT:
+        d->type = FieldSupportedValuesQuery::Type::CURRENT;
+        break;
+    default:
+        ALOGE("Unknown type of C2FieldSupportedValuesQuery: %u",
+                static_cast<unsigned>(s.type()));
+        return Status::BAD_VALUE;
+    }
+    return Status::OK;
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+c2_status_t objcpy(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& s) {
+    C2FieldSupportedValuesQuery::type_t dType;
+    switch (s.type) {
+    case FieldSupportedValuesQuery::Type::POSSIBLE:
+        dType = C2FieldSupportedValuesQuery::POSSIBLE;
+        break;
+    case FieldSupportedValuesQuery::Type::CURRENT:
+        dType = C2FieldSupportedValuesQuery::CURRENT;
+        break;
+    default:
+        ALOGE("Unknown type of FieldSupportedValuesQuery: %u",
+                static_cast<unsigned>(s.type));
+        return C2_BAD_VALUE;
+    }
+    *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
+    return C2_OK;
+}
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+Status objcpy(
+        FieldSupportedValuesQueryResult* d,
+        const C2FieldSupportedValuesQuery& s) {
+    d->status = static_cast<Status>(s.status);
+    return objcpy(&d->values, s.values);
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+c2_status_t objcpy(
+        C2FieldSupportedValuesQuery* d,
+        const FieldSupportedValuesQuery& sq,
+        const FieldSupportedValuesQueryResult& sr) {
+    c2_status_t status = objcpy(d, sq);
+    if (status != C2_OK) {
+        return status;
+    }
+    d->status = static_cast<c2_status_t>(sr.status);
+    return objcpy(&d->values, sr.values);
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+Status objcpy(
+        IComponentStore::ComponentTraits *d,
+        const C2Component::Traits &s) {
+    d->name = s.name;
+
+    // TODO: Currently, we do not have any domain values defined in Codec2.0.
+    d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+    d->domainOther = static_cast<uint32_t>(s.domain);
+
+    // TODO: Currently, we do not have any kind values defined in Codec2.0.
+    d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+    d->kindOther = static_cast<uint32_t>(s.kind);
+
+    d->rank = static_cast<uint32_t>(s.rank);
+
+    d->mediaType = s.mediaType;
+
+    d->aliases.resize(s.aliases.size());
+    for (size_t ix = s.aliases.size(); ix > 0; ) {
+        --ix;
+        d->aliases[ix] = s.aliases[ix];
+    }
+    return Status::OK;
+}
+
+// ComponentTraits -> C2Component::Traits
+c2_status_t objcpy(
+        C2Component::Traits* d,
+        const IComponentStore::ComponentTraits& s) {
+    d->name = s.name;
+
+    // TODO: Currently, we do not have any domain values defined in Codec2.0.
+    d->domain = static_cast<C2Component::domain_t>(s.domainOther);
+
+    // TODO: Currently, we do not have any kind values defined in Codec2.0.
+    d->kind = static_cast<C2Component::kind_t>(s.kindOther);
+
+    d->rank = static_cast<C2Component::rank_t>(s.rank);
+
+    d->mediaType = s.mediaType.c_str();
+
+    // TODO: Currently, aliases are pointers to static strings. This is not
+    // supported by HIDL.
+    d->aliases.clear();
+    return C2_OK;
+}
+
+namespace /* unnamed */ {
+
+// C2ParamFieldValues -> ParamFieldValues
+Status objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+    objcpy(&d->paramOrField, s.paramOrField);
+    if (s.values) {
+        d->values.resize(1);
+        return objcpy(&d->values[0], *s.values);
+    }
+    d->values.resize(0);
+    return Status::OK;
+}
+
+// ParamFieldValues -> C2ParamFieldValues
+c2_status_t objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+    d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
+    if (s.values.size() == 1) {
+        d->values = std::make_unique<C2FieldSupportedValues>();
+        return objcpy(d->values.get(), s.values[0]);
+    } else if (s.values.size() == 0) {
+        d->values.reset();
+        return C2_OK;
+    }
+    ALOGE("Multiple FieldSupportedValues objects. "
+            "(Only one is allowed.)");
+    return C2_BAD_VALUE;
+}
+
+} // unnamed namespace
+
+// C2SettingResult -> SettingResult
+Status objcpy(SettingResult *d, const C2SettingResult &s) {
+    d->failureOther = static_cast<uint32_t>(s.failure);
+    switch (s.failure) {
+    case C2SettingResult::READ_ONLY:
+        d->failure = SettingResult::Failure::READ_ONLY;
+        break;
+    case C2SettingResult::MISMATCH:
+        d->failure = SettingResult::Failure::MISMATCH;
+        break;
+    case C2SettingResult::BAD_VALUE:
+        d->failure = SettingResult::Failure::BAD_VALUE;
+        break;
+    case C2SettingResult::BAD_TYPE:
+        d->failure = SettingResult::Failure::BAD_TYPE;
+        break;
+    case C2SettingResult::BAD_PORT:
+        d->failure = SettingResult::Failure::BAD_PORT;
+        break;
+    case C2SettingResult::BAD_INDEX:
+        d->failure = SettingResult::Failure::BAD_INDEX;
+        break;
+    case C2SettingResult::CONFLICT:
+        d->failure = SettingResult::Failure::CONFLICT;
+        break;
+    case C2SettingResult::UNSUPPORTED:
+        d->failure = SettingResult::Failure::UNSUPPORTED;
+        break;
+    case C2SettingResult::INFO_CONFLICT:
+        d->failure = SettingResult::Failure::INFO_CONFLICT;
+        break;
+    default:
+        d->failure = SettingResult::Failure::OTHER;
+    }
+    Status status = objcpy(&d->field, s.field);
+    if (status != Status::OK) {
+        return status;
+    }
+    d->conflicts.resize(s.conflicts.size());
+    size_t i = 0;
+    for (const C2ParamFieldValues& sConflict : s.conflicts) {
+        ParamFieldValues &dConflict = d->conflicts[i++];
+        status = objcpy(&dConflict, sConflict);
+        if (status != Status::OK) {
+            return status;
+        }
+    }
+    return Status::OK;
+}
+
+// SettingResult -> C2SettingResult
+c2_status_t objcpy(C2SettingResult *d, const SettingResult &s) {
+    switch (s.failure) {
+    case SettingResult::Failure::READ_ONLY:
+        d->failure = C2SettingResult::READ_ONLY;
+        break;
+    case SettingResult::Failure::MISMATCH:
+        d->failure = C2SettingResult::MISMATCH;
+        break;
+    case SettingResult::Failure::BAD_VALUE:
+        d->failure = C2SettingResult::BAD_VALUE;
+        break;
+    case SettingResult::Failure::BAD_TYPE:
+        d->failure = C2SettingResult::BAD_TYPE;
+        break;
+    case SettingResult::Failure::BAD_PORT:
+        d->failure = C2SettingResult::BAD_PORT;
+        break;
+    case SettingResult::Failure::BAD_INDEX:
+        d->failure = C2SettingResult::BAD_INDEX;
+        break;
+    case SettingResult::Failure::CONFLICT:
+        d->failure = C2SettingResult::CONFLICT;
+        break;
+    case SettingResult::Failure::UNSUPPORTED:
+        d->failure = C2SettingResult::UNSUPPORTED;
+        break;
+    case SettingResult::Failure::INFO_CONFLICT:
+        d->failure = C2SettingResult::INFO_CONFLICT;
+        break;
+    default:
+        d->failure = static_cast<C2SettingResult::Failure>(s.failureOther);
+    }
+    c2_status_t status = objcpy(&d->field, s.field);
+    if (status != C2_OK) {
+        return status;
+    }
+    d->conflicts.clear();
+    for (const ParamFieldValues& sConflict : s.conflicts) {
+        d->conflicts.emplace_back(
+                C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
+        status = objcpy(&d->conflicts.back(), sConflict);
+        if (status != C2_OK) {
+            return status;
+        }
+    }
+    return C2_OK;
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+Status objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+    d->index = static_cast<ParamIndex>(s.index());
+    d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
+            _C2ParamInspector::GetAttrib(s));
+    d->name = s.name();
+    copyVector<uint32_t>(&d->dependencies, s.dependencies());
+    return Status::OK;
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+c2_status_t objcpy(std::unique_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+    std::vector<C2Param::Index> dDependencies;
+    dDependencies.reserve(s.dependencies.size());
+    for (const ParamIndex& sDependency : s.dependencies) {
+        dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
+    }
+    *d = std::make_unique<C2ParamDescriptor>(
+            C2Param::Index(static_cast<uint32_t>(s.index)),
+            static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
+            C2String(s.name.c_str()),
+            std::move(dDependencies));
+    return C2_OK;
+}
+
+// C2StructDescriptor -> StructDescriptor
+Status objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+    d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
+    d->fields.resize(s.numFields());
+    size_t i = 0;
+    for (const auto& sField : s) {
+        FieldDescriptor& dField = d->fields[i++];
+        dField.fieldId.offset = static_cast<uint32_t>(
+                _C2ParamInspector::GetOffset(sField));
+        dField.fieldId.size = static_cast<uint32_t>(
+                _C2ParamInspector::GetSize(sField));
+        dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
+                sField.type());
+        dField.length = static_cast<uint32_t>(sField.extent());
+        dField.name = static_cast<hidl_string>(sField.name());
+        const auto& sNamedValues = sField.namedValues();
+        dField.namedValues.resize(sNamedValues.size());
+        size_t j = 0;
+        for (const auto& sNamedValue : sNamedValues) {
+            FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
+            dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
+            dNamedValue.value = static_cast<PrimitiveValue>(
+                    sNamedValue.second.u64);
+        }
+    }
+    return Status::OK;
+}
+
+// StructDescriptor -> C2StructDescriptor
+c2_status_t objcpy(C2StructDescriptor *d, const StructDescriptor &s) {
+    // TODO: Implement this when C2StructDescriptor can be dynamically
+    // constructed.
+    (void)d;
+    (void)s;
+    ALOGE("Conversion StructDescriptor -> C2StructDescriptor "
+            "not implemented.");
+    return C2_OMITTED;
+}
+
+// Finds or adds a hidl BaseBlock object from a given C2Handle* to a list and an
+// associated map.
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+namespace /* unnamed */ {
+
+Status addBaseBlock(uint32_t* index, const C2Handle* handle,
+        std::vector<BaseBlock>* baseBlocks,
+        std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
+    if (handle == nullptr) {
+        return Status::BAD_VALUE;
+    }
+    auto it = baseBlockIndices->find(handle);
+    if (it != baseBlockIndices->end()) {
+        *index = it->second;
+    } else {
+        *index = baseBlocks->size();
+        BaseBlock dBaseBlock;
+        // TODO: Use BufferPool.
+        dBaseBlock.type = BaseBlock::Type::NATIVE;
+        // This does not clone the handle.
+        dBaseBlock.nativeBlock =
+                reinterpret_cast<const native_handle_t*>(handle);
+        baseBlocks->push_back(dBaseBlock);
+        baseBlockIndices->emplace(handle, *index);
+    }
+    return Status::OK;
+}
+
+// C2Fence -> hidl_handle
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+Status objcpy(hidl_handle* d, const C2Fence& s) {
+    (void)s; // TODO: implement s.fd()
+    int fenceFd = -1;
+    d->setTo(nullptr);
+    if (fenceFd >= 0) {
+        native_handle_t *handle = native_handle_create(1, 0);
+        if (!handle) {
+            return Status::NO_MEMORY;
+        }
+        handle->data[0] = fenceFd;
+        d->setTo(handle, true /* owns */);
+    }
+    return Status::OK;
+}
+
+// C2ConstLinearBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+Status objcpy(Block* d, const C2ConstLinearBlock& s,
+        std::vector<BaseBlock>* baseBlocks,
+        std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
+    // Find the BaseBlock index.
+    // TODO: Use BufferPool.
+    Status status = addBaseBlock(
+            &d->index, s.handle(), baseBlocks, baseBlockIndices);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    // Create the metadata.
+    C2Hidl_RangeInfo dRangeInfo;
+    dRangeInfo.offset = static_cast<uint32_t>(s.offset());
+    dRangeInfo.length = static_cast<uint32_t>(s.size());
+    status = createParamsBlob(&d->meta,
+            std::vector<C2Param*>{ &dRangeInfo });
+    if (status != Status::OK) {
+        return Status::BAD_VALUE;
+    }
+
+    // Copy the fence
+    return objcpy(&d->fence, s.fence());
+}
+
+// C2ConstGraphicBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+Status objcpy(Block* d, const C2ConstGraphicBlock& s,
+        std::vector<BaseBlock>* baseBlocks,
+        std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
+    // Find the BaseBlock index.
+    // TODO: Use BufferPool.
+    Status status = addBaseBlock(
+            &d->index, s.handle(), baseBlocks, baseBlockIndices);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    // Create the metadata.
+    C2Hidl_RectInfo dRectInfo;
+    C2Rect sRect = s.crop();
+    dRectInfo.left = static_cast<uint32_t>(sRect.left);
+    dRectInfo.top = static_cast<uint32_t>(sRect.top);
+    dRectInfo.width = static_cast<uint32_t>(sRect.width);
+    dRectInfo.height = static_cast<uint32_t>(sRect.height);
+    status = createParamsBlob(&d->meta,
+            std::vector<C2Param*>{ &dRectInfo });
+    if (status != Status::OK) {
+        return Status::BAD_VALUE;
+    }
+
+    // Copy the fence
+    return objcpy(&d->fence, s.fence());
+}
+
+// C2BufferData -> Buffer
+// This function only fills in d->blocks.
+Status objcpy(Buffer* d, const C2BufferData& s,
+        std::vector<BaseBlock>* baseBlocks,
+        std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
+    Status status;
+    d->blocks.resize(
+            s.linearBlocks().size() +
+            s.graphicBlocks().size());
+    size_t i = 0;
+    for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
+        Block& dBlock = d->blocks[i++];
+        status = objcpy(
+                &dBlock, linearBlock, baseBlocks, baseBlockIndices);
+        if (status != Status::OK) {
+            return status;
+        }
+    }
+    for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
+        Block& dBlock = d->blocks[i++];
+        status = objcpy(
+                &dBlock, graphicBlock, baseBlocks, baseBlockIndices);
+        if (status != Status::OK) {
+            return status;
+        }
+    }
+    return Status::OK;
+}
+
+// C2Buffer -> Buffer
+Status objcpy(Buffer* d, const C2Buffer& s,
+        std::vector<BaseBlock>* baseBlocks,
+        std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
+    Status status = createParamsBlob(&d->info, s.info());
+    if (status != Status::OK) {
+        return status;
+    }
+    return objcpy(d, s.data(), baseBlocks, baseBlockIndices);
+}
+
+// C2InfoBuffer -> InfoBuffer
+Status objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+        std::vector<BaseBlock>* baseBlocks,
+        std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
+    // TODO: C2InfoBuffer is not implemented.
+    (void)d;
+    (void)s;
+    (void)baseBlocks;
+    (void)baseBlockIndices;
+    return Status::OK;
+    /*
+    // Stub implementation that may work in the future.
+    d->index = static_cast<uint32_t>(s.index());
+    d->buffer.info.resize(0);
+    return objcpy(&d->buffer, s.data(), baseBlocks, baseBlockIndices);
+    */
+}
+
+// C2FrameData -> FrameData
+Status objcpy(FrameData* d, const C2FrameData& s,
+        std::vector<BaseBlock>* baseBlocks,
+        std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
+    d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
+    objcpy(&d->ordinal, s.ordinal);
+
+    Status status;
+    d->buffers.resize(s.buffers.size());
+    size_t i = 0;
+    for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
+        Buffer& dBuffer = d->buffers[i++];
+        if (!sBuffer) {
+            ALOGE("Null C2Buffer");
+            return Status::BAD_VALUE;
+        }
+        status = objcpy(&dBuffer, *sBuffer, baseBlocks, baseBlockIndices);
+        if (status != Status::OK) {
+            return status;
+        }
+    }
+
+    status = createParamsBlob(&d->configUpdate, s.configUpdate);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    d->infoBuffers.resize(s.infoBuffers.size());
+    i = 0;
+    for (const std::shared_ptr<C2InfoBuffer>& sInfoBuffer : s.infoBuffers) {
+        InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
+        if (!sInfoBuffer) {
+            ALOGE("Null C2InfoBuffer");
+            return Status::BAD_VALUE;
+        }
+        status = objcpy(&dInfoBuffer, *sInfoBuffer, baseBlocks, baseBlockIndices);
+        if (status != Status::OK) {
+            return status;
+        }
+    }
+
+    return status;
+}
+
+} // unnamed namespace
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+// TODO: Connect with Bufferpool
+Status objcpy(WorkBundle* d, const std::list<std::unique_ptr<C2Work>>& s) {
+    Status status = Status::OK;
+
+    std::vector<BaseBlock> baseBlocks;
+    std::map<const C2Handle*, uint32_t> baseBlockIndices;
+    d->works.resize(s.size());
+    size_t i = 0;
+    for (const std::unique_ptr<C2Work>& sWork : s) {
+        Work &dWork = d->works[i++];
+        if (!sWork) {
+            ALOGW("Null C2Work encountered.");
+            continue;
+        }
+        status = objcpy(&dWork.input, sWork->input,
+                &baseBlocks, &baseBlockIndices);
+        if (status != Status::OK) {
+            return status;
+        }
+        if (sWork->worklets.size() == 0) {
+            ALOGW("Work with no worklets.");
+        } else {
+            if (sWork->worklets.size() > 1) {
+                ALOGW("Work with multiple worklets. "
+                        "Only the first worklet will be marshalled.");
+            }
+            if (!sWork->worklets.front()) {
+                ALOGE("Null worklet encountered.");
+                return Status::BAD_VALUE;
+            }
+
+            // Parcel the first worklet.
+            const C2Worklet &sWorklet = *sWork->worklets.front();
+            Worklet &dWorklet = dWork.worklet;
+
+            dWorklet.tunings.resize(sWorklet.tunings.size());
+            size_t j = 0;
+            for (const std::unique_ptr<C2Tuning>& sTuning : sWorklet.tunings) {
+                status = createParamsBlob(
+                        &dWorklet.tunings[j++],
+                        std::vector<C2Param*>
+                        { reinterpret_cast<C2Param*>(sTuning.get()) });
+                if (status != Status::OK) {
+                    return status;
+                }
+            }
+
+            dWorklet.failures.resize(sWorklet.failures.size());
+            j = 0;
+            for (const std::unique_ptr<C2SettingResult>& sFailure :
+                    sWorklet.failures) {
+                if (!sFailure) {
+                    ALOGE("Null C2SettingResult");
+                    return Status::BAD_VALUE;
+                }
+                status = objcpy(&dWorklet.failures[j++], *sFailure);
+                if (status != Status::OK) {
+                    return status;
+                }
+            }
+
+            status = objcpy(&dWorklet.output, sWorklet.output,
+                    &baseBlocks, &baseBlockIndices);
+            if (status != Status::OK) {
+                return status;
+            }
+        }
+        dWork.workletProcessed = sWork->workletsProcessed > 0;
+        dWork.result = static_cast<Status>(sWork->result);
+    }
+
+    d->baseBlocks = baseBlocks;
+
+    return Status::OK;
+}
+
+namespace /* unnamed */ {
+
+// hidl_handle -> C2Fence
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+c2_status_t objcpy(C2Fence* d, const hidl_handle& s) {
+    // TODO: Implement.
+    (void)s;
+    *d = C2Fence();
+    return C2_OK;
+}
+
+// Buffer -> C2Buffer
+// Note: The native handles will be cloned.
+c2_status_t objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+        const hidl_vec<BaseBlock>& baseBlocks) {
+    c2_status_t status;
+
+    // First, construct C2Buffer with blocks from s.blocks.
+    *d = nullptr;
+
+    // TODO: Only buffers with 1 block are supported.
+    if (s.blocks.size() == 1) {
+        // Obtain the BaseBlock.
+        const Block &sBlock = s.blocks[0];
+        if (sBlock.index >= baseBlocks.size()) {
+            ALOGE("Index into baseBlocks is out of range.");
+            return C2_BAD_VALUE;
+        }
+        const BaseBlock &sBaseBlock = baseBlocks[sBlock.index];
+
+        // Parse meta.
+        std::vector<C2Param*> sBlockMeta;
+        status = parseParamsBlob(&sBlockMeta, sBlock.meta);
+        if (status != C2_OK) {
+            ALOGE("Invalid block params blob.");
+            return C2_BAD_VALUE;
+        }
+
+        // Copy fence.
+        C2Fence dFence;
+        status = objcpy(&dFence, sBlock.fence);
+
+        // Construct a block.
+        switch (sBaseBlock.type) {
+        case BaseBlock::Type::NATIVE: {
+            const native_handle_t* sHandle = sBaseBlock.nativeBlock;
+            if (sHandle == nullptr) {
+                ALOGE("Null native handle in a block.");
+                return C2_BAD_VALUE;
+            }
+            sHandle = native_handle_clone(sHandle);
+            if (sHandle == nullptr) {
+                ALOGE("Cannot clone native handle.");
+                return C2_NO_MEMORY;
+            }
+            const C2Handle *sC2Handle =
+                    reinterpret_cast<const C2Handle*>(sHandle);
+
+            // Currently, there are only 2 types of C2Allocation: ion and
+            // gralloc.
+            if (C2AllocatorIon::isValid(sC2Handle)) {
+                // Check the block meta. It should have exactly 1 C2Info:
+                // C2Hidl_RangeInfo.
+                if ((sBlockMeta.size() != 1) || !sBlockMeta[0]) {
+                    ALOGE("Invalid block metadata for ion block.");
+                    return C2_BAD_VALUE;
+                }
+                if (sBlockMeta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
+                    ALOGE("Invalid block metadata for ion block: range.");
+                    return C2_BAD_VALUE;
+                }
+                C2Hidl_RangeInfo *rangeInfo =
+                        reinterpret_cast<C2Hidl_RangeInfo*>(sBlockMeta[0]);
+
+                std::shared_ptr<C2Allocator> allocator;
+                c2_status_t status = GetCodec2PlatformAllocatorStore(
+                        )->fetchAllocator(
+                        C2PlatformAllocatorStore::ION,
+                        &allocator);
+                if (status != C2_OK) {
+                    ALOGE("Cannot fetch platform linear allocator.");
+                    return status;
+                }
+                std::shared_ptr<C2LinearAllocation> allocation;
+                status = allocator->priorLinearAllocation(
+                        sC2Handle, &allocation);
+                if (status != C2_OK) {
+                    ALOGE("Error constructing linear allocation.");
+                    return status;
+                } else if (!allocation) {
+                    ALOGE("Null linear allocation.");
+                    return C2_BAD_VALUE;
+                }
+                std::shared_ptr<C2LinearBlock> block =
+                        _C2BlockFactory::CreateLinearBlock(allocation);
+                if (!block) {
+                    ALOGE("Cannot create a block.");
+                    return C2_BAD_VALUE;
+                }
+                *d = C2Buffer::CreateLinearBuffer(block->share(
+                        rangeInfo->offset, rangeInfo->length, dFence));
+                if (!(*d)) {
+                    ALOGE("Cannot create a linear buffer.");
+                    return C2_BAD_VALUE;
+                }
+            } else if (C2AllocatorGralloc::isValid(sC2Handle)) {
+                // Check the block meta. It should have exactly 1 C2Info:
+                // C2Hidl_RectInfo.
+                if ((sBlockMeta.size() != 1) || !sBlockMeta[0]) {
+                    ALOGE("Invalid block metadata for graphic block.");
+                    return C2_BAD_VALUE;
+                }
+                if (sBlockMeta[0]->size() != sizeof(C2Hidl_RectInfo)) {
+                    ALOGE("Invalid block metadata for graphic block: crop rect.");
+                    return C2_BAD_VALUE;
+                }
+                C2Hidl_RectInfo *rectInfo =
+                        reinterpret_cast<C2Hidl_RectInfo*>(sBlockMeta[0]);
+
+                std::shared_ptr<C2Allocator> allocator;
+                c2_status_t status = GetCodec2PlatformAllocatorStore(
+                        )->fetchAllocator(
+                        C2PlatformAllocatorStore::GRALLOC,
+                        &allocator);
+                if (status != C2_OK) {
+                    ALOGE("Cannot fetch platform graphic allocator.");
+                    return status;
+                }
+
+                std::shared_ptr<C2GraphicAllocation> allocation;
+                status = allocator->priorGraphicAllocation(
+                        sC2Handle, &allocation);
+                if (status != C2_OK) {
+                    ALOGE("Error constructing graphic allocation.");
+                    return status;
+                } else if (!allocation) {
+                    ALOGE("Null graphic allocation.");
+                    return C2_BAD_VALUE;
+                }
+                std::shared_ptr<C2GraphicBlock> block =
+                        _C2BlockFactory::CreateGraphicBlock(allocation);
+                if (!block) {
+                    ALOGE("Cannot create a block.");
+                    return C2_BAD_VALUE;
+                }
+                *d = C2Buffer::CreateGraphicBuffer(block->share(
+                        C2Rect(rectInfo->width, rectInfo->height,
+                               rectInfo->left, rectInfo->top),
+                        dFence));
+                if (!(*d)) {
+                    ALOGE("Cannot create a graphic buffer.");
+                    return C2_BAD_VALUE;
+                }
+            } else {
+                ALOGE("Unknown handle type.");
+                return C2_BAD_VALUE;
+            }
+            break;
+        }
+        case BaseBlock::Type::POOLED: {
+            // TODO: Implement. Use BufferPool.
+            return C2_OMITTED;
+        }
+        default:
+            ALOGE("Invalid BaseBlock type.");
+            return C2_BAD_VALUE;
+        }
+    } else {
+        ALOGE("Currently a buffer must contain exactly 1 block.");
+        return C2_BAD_VALUE;
+    }
+
+    // Parse info
+    std::vector<C2Param*> params;
+    status = parseParamsBlob(&params, s.info);
+    if (status != C2_OK) {
+        ALOGE("Invalid buffer params blob.");
+        return status;
+    }
+    for (C2Param* param : params) {
+        if (param == nullptr) {
+            ALOGE("Null buffer param encountered.");
+            return C2_BAD_VALUE;
+        }
+        std::shared_ptr<C2Param> c2param(
+                C2Param::Copy(*param).release());
+        if (!c2param) {
+            ALOGE("Invalid buffer param inside a blob.");
+            return C2_BAD_VALUE;
+        }
+        status = (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+        if (status != C2_OK) {
+            ALOGE("C2Buffer::setInfo failed().");
+            return C2_BAD_VALUE;
+        }
+    }
+
+    return C2_OK;
+}
+
+// FrameData -> C2FrameData
+c2_status_t objcpy(C2FrameData* d, const FrameData& s,
+        const hidl_vec<BaseBlock>& baseBlocks) {
+    c2_status_t status;
+    d->flags = static_cast<C2FrameData::flags_t>(s.flags);
+    objcpy(&d->ordinal, s.ordinal);
+    d->buffers.clear();
+    d->buffers.reserve(s.buffers.size());
+    for (const Buffer& sBuffer : s.buffers) {
+        std::shared_ptr<C2Buffer> dBuffer;
+        status = objcpy(&dBuffer, sBuffer, baseBlocks);
+        if (status != C2_OK) {
+            return status;
+        }
+        d->buffers.emplace_back(dBuffer);
+    }
+
+    std::vector<C2Param*> params;
+    status = parseParamsBlob(&params, s.configUpdate);
+    if (status != C2_OK) {
+        ALOGE("Failed to parse frame data params.");
+        return status;
+    }
+    d->configUpdate.clear();
+    for (C2Param* param : params) {
+        d->configUpdate.emplace_back(C2Param::Copy(*param));
+        if (!d->configUpdate.back()) {
+            ALOGE("Unexpected error while parsing frame data params.");
+            return C2_BAD_VALUE;
+        }
+    }
+
+    // TODO: Implement this once C2InfoBuffer has constructors.
+    d->infoBuffers.clear();
+    return C2_OK;
+}
+
+} // unnamed namespace
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+// TODO: Connect with Bufferpool
+c2_status_t objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
+    c2_status_t status;
+    d->clear();
+    for (const Work& sWork : s.works) {
+        d->emplace_back(std::make_unique<C2Work>());
+        C2Work& dWork = *d->back();
+
+        // input
+        status = objcpy(&dWork.input, sWork.input, s.baseBlocks);
+        if (status != C2_OK) {
+            ALOGE("Error constructing C2Work's input.");
+            return C2_BAD_VALUE;
+        }
+
+        // worklet(s)
+        // TODO: Currently, tunneling is not supported.
+        if (sWork.workletProcessed) {
+            dWork.worklets.clear();
+            dWork.workletsProcessed = 1;
+
+            const Worklet &sWorklet = sWork.worklet;
+            std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
+
+            // tunings
+            dWorklet->tunings.clear();
+            dWorklet->tunings.reserve(sWorklet.tunings.size());
+            for (const Params& sTuning : sWorklet.tunings) {
+                std::vector<C2Param*> dParams;
+                status = parseParamsBlob(&dParams, sTuning);
+                if (status != C2_OK) {
+                    ALOGE("Failed to parse C2Tuning in C2Worklet.");
+                    return C2_BAD_VALUE;
+                }
+                for (C2Param* param : dParams) {
+                    std::unique_ptr<C2Param> dParam = C2Param::Copy(*param);
+                    if (!dParam) {
+                        ALOGE("Null C2Tuning encountered while "
+                                "parsing C2Worklet.");
+                        return C2_BAD_VALUE;
+                    }
+                    dWorklet->tunings.emplace_back(
+                            std::unique_ptr<C2Tuning>(
+                            reinterpret_cast<C2Tuning*>(
+                            dParam.release())));
+                }
+            }
+            // failures
+            dWorklet->failures.clear();
+            dWorklet->failures.reserve(sWorklet.failures.size());
+            for (const SettingResult& sFailure : sWorklet.failures) {
+                std::unique_ptr<C2SettingResult> dFailure(
+                        new C2SettingResult { .field = C2ParamFieldValues {
+                        C2ParamFieldBuilder(), nullptr } });
+                status = objcpy(dFailure.get(), sFailure);
+                if (status != C2_OK) {
+                    ALOGE("Failed to create C2SettingResult in C2Worklet.");
+                    return C2_BAD_VALUE;
+                }
+                dWorklet->failures.emplace_back(std::move(dFailure));
+            }
+            // output
+            status = objcpy(&dWorklet->output, sWorklet.output, s.baseBlocks);
+            if (status != C2_OK) {
+                ALOGE("Failed to create output C2FrameData.");
+                return C2_BAD_VALUE;
+            }
+            dWork.worklets.emplace_back(std::move(dWorklet));
+        } else {
+            dWork.worklets.clear();
+            dWork.workletsProcessed = 0;
+        }
+
+        // result
+        dWork.result = static_cast<c2_status_t>(sWork.result);
+    }
+
+    return C2_OK;
+}
+
+// Params -> std::vector<C2Param*>
+c2_status_t parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+    // assuming blob is const here
+    size_t size = blob.size();
+    const uint8_t *data = blob.data();
+    C2Param *p = nullptr;
+
+    do {
+        p = C2ParamUtils::ParseFirst(data, size);
+        if (p) {
+            params->emplace_back(p);
+            size -= p->size();
+            data += p->size();
+        }
+    } while (p);
+
+    return size == 0 ? C2_OK : C2_BAD_VALUE;
+}
+
+namespace /* unnamed */ {
+
+/**
+ * Concatenates a list of C2Params into a params blob.
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval C2_OK if the blob was successfully created
+ * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
+ *         not const)
+ */
+template<typename T>
+Status _createParamsBlob(hidl_vec<uint8_t> *blob, const T &params) {
+    // assuming the parameter values are const
+    size_t size = 0;
+    for (const auto &p : params) {
+        size += p->size();
+    }
+    blob->resize(size);
+    size_t ix = 0;
+    for (const auto &p : params) {
+        // NEVER overwrite even if param values (e.g. size) changed
+        size_t paramSize = std::min(p->size(), size - ix);
+//        memcpy(&blob[ix], &*p, paramSize);
+        std::copy(
+                reinterpret_cast<const uint8_t*>(&*p),
+                reinterpret_cast<const uint8_t*>(&*p) + paramSize,
+                &blob[ix]);
+        ix += paramSize;
+    }
+    blob->resize(ix);
+    return ix == size ? Status::OK : Status::CORRUPTED;
+}
+
+} // unnamed namespace
+
+// std::vector<const C2Param*> -> Params
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<const C2Param*> &params) {
+    return _createParamsBlob(blob, params);
+}
+
+// std::vector<C2Param*> -> Params
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<C2Param*> &params) {
+    return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Param>> -> Params
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<std::unique_ptr<C2Param>> &params) {
+    return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Tuning>> -> Params
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<std::unique_ptr<C2Tuning>> &params) {
+    return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::shared_ptr<const C2Info>> -> Params
+Status createParamsBlob(
+        hidl_vec<uint8_t> *blob,
+        const std::vector<std::shared_ptr<const C2Info>> &params) {
+    return _createParamsBlob(blob, params);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index d7709a0..47afd42 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -6,6 +6,9 @@
     ],
 
     vendor_available: false,
+    vndk: {
+        enabled: true,
+    },
 }
 
 cc_library_shared {
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index 3d7fc8d..a90e094 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -646,4 +646,8 @@
     return mImpl->status();
 }
 
+bool C2AllocatorGralloc::isValid(const C2Handle* const o) {
+    return C2HandleGralloc::isValid(o);
+}
+
 } // namespace android
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index 6b0cffb..cf7658a 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -466,5 +466,9 @@
     return ret;
 }
 
+bool C2AllocatorIon::isValid(const C2Handle* const o) {
+    return C2HandleIon::isValid(o);
+}
+
 } // namespace android
 
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
index 9dc7152..8d28192 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -65,6 +65,8 @@
 
     virtual ~C2AllocatorGralloc() override;
 
+    static bool isValid(const C2Handle* const o);
+
 private:
     class Impl;
     Impl *mImpl;
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
index 716eae0..8c0992e 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -49,6 +49,8 @@
 
     virtual ~C2AllocatorIon() override;
 
+    static bool isValid(const C2Handle* const o);
+
 private:
     std::shared_ptr<const Traits> mTraits;
     c2_status_t mInit;
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
index 25003cb..ff67788 100644
--- a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
@@ -39,7 +39,7 @@
      *         create this block.
      */
     static
-    std::shared_ptr<C2LinearBlock> C2_HIDE CreateLinearBlock(
+    std::shared_ptr<C2LinearBlock> CreateLinearBlock(
             const std::shared_ptr<C2LinearAllocation> &alloc,
             const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
             size_t offset = 0,
diff --git a/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h b/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
index 34797a9..ba7c5d5 100644
--- a/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
+++ b/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
@@ -20,6 +20,14 @@
 #include <C2Param.h>
 
 struct C2_HIDE _C2ParamInspector {
+    inline static uint32_t GetOffset(const C2FieldDescriptor &fd) {
+        return fd._mFieldId._mOffset;
+    }
+
+    inline static uint32_t GetSize(const C2FieldDescriptor &fd) {
+        return fd._mFieldId._mSize;
+    }
+
     inline static uint32_t GetIndex(const C2ParamField &pf) {
         return pf._mIndex;
     }