// 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 #include #include #include #include #include #include #include #include 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 V4L2ComponentStore::Create() { ALOGV("%s()", __func__); static std::mutex mutex; static std::weak_ptr platformStore; std::lock_guard lock(mutex); std::shared_ptr 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( 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()) { ALOGV("%s()", __func__); } V4L2ComponentStore::~V4L2ComponentStore() { ALOGV("%s()", __func__); std::lock_guard 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* 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* 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> V4L2ComponentStore::listComponents() { ALOGV("%s()", __func__); std::vector> 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 V4L2ComponentStore::getParamReflector() const { return mReflector; } c2_status_t V4L2ComponentStore::copyBuffer(std::shared_ptr /* src */, std::shared_ptr /* dst */) { return C2_OMITTED; } c2_status_t V4L2ComponentStore::querySupportedParams_nb( std::vector>* const /* params */) const { return C2_OK; } c2_status_t V4L2ComponentStore::query_sm( const std::vector& stackParams, const std::vector& heapParamIndices, std::vector>* 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& params, std::vector>* const /* failures */) { // There are no supported config params. return params.empty() ? C2_OK : C2_BAD_INDEX; } c2_status_t V4L2ComponentStore::querySupportedValues_sm( std::vector& 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 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 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 lock(mCachedTraitsLock); auto it = mCachedTraits.find(name); if (it != mCachedTraits.end()) return it->second; std::shared_ptr 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> params; res = intf->query_vb({}, {mediaTypeIndex}, C2_MAY_BLOCK, ¶ms); 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(); 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