Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f29f1f2b authored by Pawin Vongmasa's avatar Pawin Vongmasa
Browse files

Start Codec2.0 Implementation

Test: Builds

Bug: 64121714
Change-Id: I038fe8cdd4c29b61a71f1a93de57735f2526e18b
parent 885f29b8
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
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",
    ],
}
+245 −0
Original line number Diff line number Diff line
/*
 * 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
+212 −0
Original line number Diff line number Diff line
/*
 * 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
+167 −0
Original line number Diff line number Diff line
/*
 * 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
+85 −0
Original line number Diff line number Diff line
#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
Loading