229 lines
7.7 KiB
C++
229 lines
7.7 KiB
C++
// 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, ¶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<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
|