store: add libv4l2_codec2_store library.

This CL adds the libv4l2_codec2_store library, that is used to create
the C2Components implemented in libv4l2_codec2_components

Bug: 152714603
Test: mmm external/v4l2_codec2

Change-Id: If2e978627088ec63746e08a96a90278ebbd73bb2
diff --git a/store/Android.bp b/store/Android.bp
new file mode 100644
index 0000000..6f0a63f
--- /dev/null
+++ b/store/Android.bp
@@ -0,0 +1,29 @@
+cc_library_shared {
+    name: "libv4l2_codec2_store",
+    vendor_available: true,
+
+    defaults: [
+        "libcodec2-impl-defaults",
+    ],
+
+    srcs: [
+        "V4L2ComponentStore.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+    ],
+    static_libs: [
+        "libv4l2_codec2_common",
+    ],
+
+    cflags: [
+      "-Werror",
+      "-Wall",
+    ],
+}
+
diff --git a/store/V4L2ComponentStore.cpp b/store/V4L2ComponentStore.cpp
new file mode 100644
index 0000000..8942866
--- /dev/null
+++ b/store/V4L2ComponentStore.cpp
@@ -0,0 +1,228 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "V4L2ComponentStore"
+
+#include <v4l2_codec2/store/V4L2ComponentStore.h>
+
+#include <dlfcn.h>
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+
+#include <C2.h>
+#include <C2Config.h>
+#include <log/log.h>
+
+#include <v4l2_codec2/common/V4L2ComponentCommon.h>
+
+namespace android {
+namespace {
+const char* kLibPath = "libv4l2_codec2_components.so";
+const char* kCreateFactoryFuncName = "CreateCodec2Factory";
+const char* kDestroyFactoryFuncName = "DestroyCodec2Factory";
+
+const uint32_t kComponentRank = 0x80;
+}  // namespace
+
+// static
+std::shared_ptr<C2ComponentStore> V4L2ComponentStore::Create() {
+    ALOGV("%s()", __func__);
+
+    static std::mutex mutex;
+    static std::weak_ptr<C2ComponentStore> platformStore;
+
+    std::lock_guard<std::mutex> lock(mutex);
+    std::shared_ptr<C2ComponentStore> store = platformStore.lock();
+    if (store != nullptr) return store;
+
+    void* libHandle = dlopen(kLibPath, RTLD_NOW | RTLD_NODELETE);
+    if (!libHandle) {
+        ALOGE("Failed to load library: %s", kLibPath);
+        return nullptr;
+    }
+
+    auto createFactoryFunc = (CreateV4L2FactoryFunc)dlsym(libHandle, kCreateFactoryFuncName);
+    auto destroyFactoryFunc = (DestroyV4L2FactoryFunc)dlsym(libHandle, kDestroyFactoryFuncName);
+    if (!createFactoryFunc || !destroyFactoryFunc) {
+        ALOGE("Failed to load functions: %s, %s", kCreateFactoryFuncName, kDestroyFactoryFuncName);
+        dlclose(libHandle);
+        return nullptr;
+    }
+
+    store = std::shared_ptr<C2ComponentStore>(
+            new V4L2ComponentStore(libHandle, createFactoryFunc, destroyFactoryFunc));
+    platformStore = store;
+    return store;
+}
+
+V4L2ComponentStore::V4L2ComponentStore(void* libHandle, CreateV4L2FactoryFunc createFactoryFunc,
+                                       DestroyV4L2FactoryFunc destroyFactoryFunc)
+      : mLibHandle(libHandle),
+        mCreateFactoryFunc(createFactoryFunc),
+        mDestroyFactoryFunc(destroyFactoryFunc),
+        mReflector(std::make_shared<C2ReflectorHelper>()) {
+    ALOGV("%s()", __func__);
+}
+
+V4L2ComponentStore::~V4L2ComponentStore() {
+    ALOGV("%s()", __func__);
+
+    std::lock_guard<std::mutex> lock(mCachedFactoriesLock);
+    for (const auto& kv : mCachedFactories) mDestroyFactoryFunc(kv.second);
+    mCachedFactories.clear();
+
+    dlclose(mLibHandle);
+}
+
+C2String V4L2ComponentStore::getName() const {
+    return "android.componentStore.v4l2";
+}
+
+c2_status_t V4L2ComponentStore::createComponent(C2String name,
+                                                std::shared_ptr<C2Component>* const component) {
+    ALOGV("%s(%s)", __func__, name.c_str());
+
+    auto factory = GetFactory(name);
+    if (factory == nullptr) return C2_CORRUPTED;
+
+    component->reset();
+    return factory->createComponent(0, component);
+}
+
+c2_status_t V4L2ComponentStore::createInterface(
+        C2String name, std::shared_ptr<C2ComponentInterface>* const interface) {
+    ALOGV("%s(%s)", __func__, name.c_str());
+
+    auto factory = GetFactory(name);
+    if (factory == nullptr) return C2_CORRUPTED;
+
+    interface->reset();
+    return factory->createInterface(0, interface);
+}
+
+std::vector<std::shared_ptr<const C2Component::Traits>> V4L2ComponentStore::listComponents() {
+    ALOGV("%s()", __func__);
+
+    std::vector<std::shared_ptr<const C2Component::Traits>> ret;
+    ret.push_back(GetTraits(V4L2ComponentName::kH264Encoder));
+    ret.push_back(GetTraits(V4L2ComponentName::kH264Decoder));
+    ret.push_back(GetTraits(V4L2ComponentName::kH264SecureDecoder));
+    ret.push_back(GetTraits(V4L2ComponentName::kVP8Decoder));
+    ret.push_back(GetTraits(V4L2ComponentName::kVP8SecureDecoder));
+    ret.push_back(GetTraits(V4L2ComponentName::kVP9Decoder));
+    ret.push_back(GetTraits(V4L2ComponentName::kVP9SecureDecoder));
+    return ret;
+}
+
+std::shared_ptr<C2ParamReflector> V4L2ComponentStore::getParamReflector() const {
+    return mReflector;
+}
+
+c2_status_t V4L2ComponentStore::copyBuffer(std::shared_ptr<C2GraphicBuffer> /* src */,
+                                           std::shared_ptr<C2GraphicBuffer> /* dst */) {
+    return C2_OMITTED;
+}
+
+c2_status_t V4L2ComponentStore::querySupportedParams_nb(
+        std::vector<std::shared_ptr<C2ParamDescriptor>>* const /* params */) const {
+    return C2_OK;
+}
+
+c2_status_t V4L2ComponentStore::query_sm(
+        const std::vector<C2Param*>& stackParams,
+        const std::vector<C2Param::Index>& heapParamIndices,
+        std::vector<std::unique_ptr<C2Param>>* const /* heapParams */) const {
+    // There are no supported config params.
+    return stackParams.empty() && heapParamIndices.empty() ? C2_OK : C2_BAD_INDEX;
+}
+
+c2_status_t V4L2ComponentStore::config_sm(
+        const std::vector<C2Param*>& params,
+        std::vector<std::unique_ptr<C2SettingResult>>* const /* failures */) {
+    // There are no supported config params.
+    return params.empty() ? C2_OK : C2_BAD_INDEX;
+}
+
+c2_status_t V4L2ComponentStore::querySupportedValues_sm(
+        std::vector<C2FieldSupportedValuesQuery>& fields) const {
+    // There are no supported config params.
+    return fields.empty() ? C2_OK : C2_BAD_INDEX;
+}
+
+::C2ComponentFactory* V4L2ComponentStore::GetFactory(const C2String& name) {
+    ALOGV("%s(%s)", __func__, name.c_str());
+
+    if (!V4L2ComponentName::isValid(name.c_str())) {
+        ALOGE("Invalid component name: %s", name.c_str());
+        return nullptr;
+    }
+
+    std::lock_guard<std::mutex> lock(mCachedFactoriesLock);
+    const auto it = mCachedFactories.find(name);
+    if (it != mCachedFactories.end()) return it->second;
+
+    ::C2ComponentFactory* factory = mCreateFactoryFunc(name.c_str());
+    if (factory == nullptr) {
+        ALOGE("Failed to create factory for %s", name.c_str());
+        return nullptr;
+    }
+
+    mCachedFactories.emplace(name, factory);
+    return factory;
+}
+
+std::shared_ptr<const C2Component::Traits> V4L2ComponentStore::GetTraits(const C2String& name) {
+    ALOGV("%s(%s)", __func__, name.c_str());
+
+    if (!V4L2ComponentName::isValid(name.c_str())) {
+        ALOGE("Invalid component name: %s", name.c_str());
+        return nullptr;
+    }
+
+    std::lock_guard<std::mutex> lock(mCachedTraitsLock);
+    auto it = mCachedTraits.find(name);
+    if (it != mCachedTraits.end()) return it->second;
+
+    std::shared_ptr<C2ComponentInterface> intf;
+    auto res = createInterface(name, &intf);
+    if (res != C2_OK) {
+        ALOGE("failed to create interface for %s: %d", name.c_str(), res);
+        return nullptr;
+    }
+
+    bool isEncoder = V4L2ComponentName::isEncoder(name.c_str());
+    uint32_t mediaTypeIndex = isEncoder ? C2PortMediaTypeSetting::output::PARAM_TYPE
+                                        : C2PortMediaTypeSetting::input::PARAM_TYPE;
+    std::vector<std::unique_ptr<C2Param>> params;
+    res = intf->query_vb({}, {mediaTypeIndex}, C2_MAY_BLOCK, &params);
+    if (res != C2_OK) {
+        ALOGE("failed to query interface: %d", res);
+        return nullptr;
+    }
+    if (params.size() != 1u) {
+        ALOGE("failed to query interface: unexpected vector size: %zu", params.size());
+        return nullptr;
+    }
+
+    C2PortMediaTypeSetting* mediaTypeConfig = (C2PortMediaTypeSetting*)(params[0].get());
+    if (mediaTypeConfig == nullptr) {
+        ALOGE("failed to query media type");
+        return nullptr;
+    }
+
+    auto traits = std::make_shared<C2Component::Traits>();
+    traits->name = intf->getName();
+    traits->domain = C2Component::DOMAIN_VIDEO;
+    traits->kind = isEncoder ? C2Component::KIND_ENCODER : C2Component::KIND_DECODER;
+    traits->mediaType = mediaTypeConfig->m.value;
+    traits->rank = kComponentRank;
+
+    mCachedTraits.emplace(name, traits);
+    return traits;
+}
+
+}  // namespace android
diff --git a/store/include/v4l2_codec2/store/V4L2ComponentStore.h b/store/include/v4l2_codec2/store/V4L2ComponentStore.h
new file mode 100644
index 0000000..8013f55
--- /dev/null
+++ b/store/include/v4l2_codec2/store/V4L2ComponentStore.h
@@ -0,0 +1,67 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ANDROID_V4L2_CODEC2_STORE_V4L2_COMPONENT_STORE_H
+#define ANDROID_V4L2_CODEC2_STORE_V4L2_COMPONENT_STORE_H
+
+#include <map>
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
+#include <C2Component.h>
+#include <C2ComponentFactory.h>
+#include <util/C2InterfaceHelper.h>
+
+namespace android {
+
+class V4L2ComponentStore : public C2ComponentStore {
+public:
+    static std::shared_ptr<C2ComponentStore> Create();
+    ~V4L2ComponentStore();
+
+    // C2ComponentStore implementation.
+    C2String getName() const override;
+    c2_status_t createComponent(C2String name,
+                                std::shared_ptr<C2Component>* const component) override;
+    c2_status_t createInterface(C2String name,
+                                std::shared_ptr<C2ComponentInterface>* const interface) override;
+    std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
+    std::shared_ptr<C2ParamReflector> getParamReflector() const override;
+    c2_status_t copyBuffer(std::shared_ptr<C2GraphicBuffer> src,
+                           std::shared_ptr<C2GraphicBuffer> dst) override;
+    c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override;
+    c2_status_t query_sm(const std::vector<C2Param*>& stackParams,
+                         const std::vector<C2Param::Index>& heapParamIndices,
+                         std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
+    c2_status_t config_sm(const std::vector<C2Param*>& params,
+                          std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
+    c2_status_t querySupportedValues_sm(
+            std::vector<C2FieldSupportedValuesQuery>& fields) const override;
+
+private:
+    using CreateV4L2FactoryFunc = ::C2ComponentFactory* (*)(const char* /* componentName */);
+    using DestroyV4L2FactoryFunc = void (*)(::C2ComponentFactory*);
+
+    V4L2ComponentStore(void* libHandle, CreateV4L2FactoryFunc createFactoryFunc,
+                       DestroyV4L2FactoryFunc destroyFactoryFunc);
+
+    ::C2ComponentFactory* GetFactory(const C2String& name);
+    std::shared_ptr<const C2Component::Traits> GetTraits(const C2String& name);
+
+    void* mLibHandle;
+    CreateV4L2FactoryFunc mCreateFactoryFunc;
+    DestroyV4L2FactoryFunc mDestroyFactoryFunc;
+
+    std::shared_ptr<C2ReflectorHelper> mReflector;
+
+    std::mutex mCachedFactoriesLock;
+    std::map<C2String, ::C2ComponentFactory*> mCachedFactories GUARDED_BY(mCachedFactoriesLock);
+    std::mutex mCachedTraitsLock;
+    std::map<C2String, std::shared_ptr<const C2Component::Traits>> mCachedTraits GUARDED_BY(mCachedTraitsLock);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_V4L2_CODEC2_STORE_V4L2_COMPONENT_STORE_H