diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/Android.bp | 4 | ||||
-rw-r--r-- | components/V4L2ComponentFactory.cpp | 103 | ||||
-rw-r--r-- | components/V4L2ComponentStore.cpp | 203 | ||||
-rw-r--r-- | components/include/v4l2_codec2/components/V4L2ComponentFactory.h | 39 | ||||
-rw-r--r-- | components/include/v4l2_codec2/components/V4L2ComponentStore.h | 61 |
5 files changed, 340 insertions, 70 deletions
diff --git a/components/Android.bp b/components/Android.bp index c683cb0..9b39a22 100644 --- a/components/Android.bp +++ b/components/Android.bp @@ -18,8 +18,9 @@ cc_library { srcs: [ "VideoFrame.cpp", "VideoFramePool.cpp", - "V4L2Decoder.cpp", "V4L2ComponentFactory.cpp", + "V4L2ComponentStore.cpp", + "V4L2Decoder.cpp", "V4L2DecodeComponent.cpp", "V4L2DecodeInterface.cpp", "V4L2EncodeComponent.cpp", @@ -43,7 +44,6 @@ cc_library { "libsfplugin_ccodec_utils", "libstagefright_bufferqueue_helper", "libstagefright_foundation", - "libv4l2_codec2_store", "libui", ], static_libs: [ diff --git a/components/V4L2ComponentFactory.cpp b/components/V4L2ComponentFactory.cpp index 049edce..a3f8837 100644 --- a/components/V4L2ComponentFactory.cpp +++ b/components/V4L2ComponentFactory.cpp @@ -5,71 +5,57 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "V4L2ComponentFactory" -#include <string> +#include <v4l2_codec2/components/V4L2ComponentFactory.h> -#include <C2ComponentFactory.h> -#include <SimpleC2Interface.h> #include <codec2/hidl/1.0/InputBufferManager.h> #include <log/log.h> -#include <util/C2InterfaceHelper.h> #include <v4l2_codec2/common/V4L2ComponentCommon.h> #include <v4l2_codec2/components/V4L2DecodeComponent.h> #include <v4l2_codec2/components/V4L2DecodeInterface.h> #include <v4l2_codec2/components/V4L2EncodeComponent.h> #include <v4l2_codec2/components/V4L2EncodeInterface.h> -#include <v4l2_codec2/store/V4L2ComponentStore.h> namespace android { -class V4L2ComponentFactory : public C2ComponentFactory { -public: - V4L2ComponentFactory(const char* componentName, bool isEncoder); - ~V4L2ComponentFactory() override; - - // Implementation of C2ComponentFactory. - c2_status_t createComponent(c2_node_id_t id, std::shared_ptr<C2Component>* const component, - ComponentDeleter deleter) override; - c2_status_t createInterface(c2_node_id_t id, - std::shared_ptr<C2ComponentInterface>* const interface, - InterfaceDeleter deleter) override; - -private: - const std::string mComponentName; - const bool mIsEncoder; - std::shared_ptr<C2ReflectorHelper> mReflector; -}; - -V4L2ComponentFactory::V4L2ComponentFactory(const char* componentName, bool isEncoder) - : mComponentName(componentName), mIsEncoder(isEncoder) { - auto componentStore = V4L2ComponentStore::Create(); - if (componentStore == nullptr) { - ALOGE("Could not create V4L2ComponentStore."); - return; +// static +std::unique_ptr<V4L2ComponentFactory> V4L2ComponentFactory::create( + const std::string& componentName, std::shared_ptr<C2ReflectorHelper> reflector) { + ALOGV("%s(%s)", __func__, componentName.c_str()); + + if (!android::V4L2ComponentName::isValid(componentName.c_str())) { + ALOGE("Invalid component name: %s", componentName.c_str()); + return nullptr; } - mReflector = std::static_pointer_cast<C2ReflectorHelper>(componentStore->getParamReflector()); - - { - using namespace ::android::hardware::media::c2::V1_0; - // To minimize IPC, we generally want the codec2 framework to release and - // recycle input buffers when the corresponding work item is done. However, - // sometimes it is necessary to provide more input to unblock a decoder. - // - // Optimally we would configure this on a per-context basis. However, the - // InputBufferManager is a process-wide singleton, so we need to configure it - // pessimistically. Basing the interval on frame timing can be suboptimal if - // the decoded output isn't being displayed, but that's not a primary use case - // and few videos will actually rely on this behavior. - constexpr nsecs_t kMinFrameIntervalNs = 1000000000ull / 60; - uint32_t delayCount = 0; - for (auto c : kAllCodecs) { - delayCount = std::max(delayCount, V4L2DecodeInterface::getOutputDelay(c)); - } - utils::InputBufferManager::setNotificationInterval(delayCount * kMinFrameIntervalNs / 2); + if (reflector == nullptr) { + ALOGE("reflector is null"); + return nullptr; } + + bool isEncoder = android::V4L2ComponentName::isEncoder(componentName.c_str()); + return std::make_unique<V4L2ComponentFactory>(componentName, isEncoder, std::move(reflector)); } -V4L2ComponentFactory::~V4L2ComponentFactory() = default; +V4L2ComponentFactory::V4L2ComponentFactory(const std::string& componentName, bool isEncoder, + std::shared_ptr<C2ReflectorHelper> reflector) + : mComponentName(componentName), mIsEncoder(isEncoder), mReflector(std::move(reflector)) { + using namespace ::android::hardware::media::c2::V1_0; + // To minimize IPC, we generally want the codec2 framework to release and + // recycle input buffers when the corresponding work item is done. However, + // sometimes it is necessary to provide more input to unblock a decoder. + // + // Optimally we would configure this on a per-context basis. However, the + // InputBufferManager is a process-wide singleton, so we need to configure it + // pessimistically. Basing the interval on frame timing can be suboptimal if + // the decoded output isn't being displayed, but that's not a primary use case + // and few videos will actually rely on this behavior. + constexpr nsecs_t kMinFrameIntervalNs = 1000000000ull / 60; + uint32_t delayCount = 0; + for (auto c : kAllCodecs) { + delayCount = std::max(delayCount, V4L2DecodeInterface::getOutputDelay(c)); + } + utils::InputBufferManager::setNotificationInterval(delayCount * kMinFrameIntervalNs / 2); +} c2_status_t V4L2ComponentFactory::createComponent(c2_node_id_t id, std::shared_ptr<C2Component>* const component, @@ -118,22 +104,3 @@ c2_status_t V4L2ComponentFactory::createInterface( } } // namespace android - -__attribute__((cfi_canonical_jump_table)) extern "C" ::C2ComponentFactory* CreateCodec2Factory( - const char* componentName) { - ALOGV("%s(%s)", __func__, componentName); - - if (!android::V4L2ComponentName::isValid(componentName)) { - ALOGE("Invalid component name: %s", componentName); - return nullptr; - } - - bool isEncoder = android::V4L2ComponentName::isEncoder(componentName); - return new android::V4L2ComponentFactory(componentName, isEncoder); -} - -__attribute__((cfi_canonical_jump_table)) extern "C" void DestroyCodec2Factory( - ::C2ComponentFactory* factory) { - ALOGV("%s()", __func__); - delete factory; -} diff --git a/components/V4L2ComponentStore.cpp b/components/V4L2ComponentStore.cpp new file mode 100644 index 0000000..4004ce5 --- /dev/null +++ b/components/V4L2ComponentStore.cpp @@ -0,0 +1,203 @@ +// 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/components/V4L2ComponentStore.h> + +#include <stdint.h> + +#include <memory> +#include <mutex> + +#include <C2.h> +#include <C2Config.h> +#include <log/log.h> +#include <media/stagefright/foundation/MediaDefs.h> + +#include <v4l2_codec2/common/V4L2ComponentCommon.h> +#include <v4l2_codec2/components/V4L2ComponentFactory.h> + +namespace android { +namespace { +const uint32_t kComponentRank = 0x80; + +std::string getMediaTypeFromComponentName(const std::string& name) { + if (name == V4L2ComponentName::kH264Decoder || name == V4L2ComponentName::kH264SecureDecoder || + name == V4L2ComponentName::kH264Encoder) { + return MEDIA_MIMETYPE_VIDEO_AVC; + } + if (name == V4L2ComponentName::kVP8Decoder || name == V4L2ComponentName::kVP8SecureDecoder || + name == V4L2ComponentName::kVP8Encoder) { + return MEDIA_MIMETYPE_VIDEO_VP8; + } + if (name == V4L2ComponentName::kVP9Decoder || name == V4L2ComponentName::kVP9SecureDecoder || + name == V4L2ComponentName::kVP9Encoder) { + return MEDIA_MIMETYPE_VIDEO_VP9; + } + return ""; +} + +} // 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; + + store = std::shared_ptr<C2ComponentStore>(new V4L2ComponentStore()); + platformStore = store; + return store; +} + +V4L2ComponentStore::V4L2ComponentStore() : mReflector(std::make_shared<C2ReflectorHelper>()) { + ALOGV("%s()", __func__); +} + +V4L2ComponentStore::~V4L2ComponentStore() { + ALOGV("%s()", __func__); + + std::lock_guard<std::mutex> lock(mCachedFactoriesLock); + mCachedFactories.clear(); +} + +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()); + + if (!V4L2ComponentName::isValid(name.c_str())) { + ALOGI("%s(): Invalid component name: %s", __func__, name.c_str()); + return C2_NOT_FOUND; + } + + 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()); + + if (!V4L2ComponentName::isValid(name.c_str())) { + ALOGI("%s(): Invalid component name: %s", __func__, name.c_str()); + return C2_NOT_FOUND; + } + + 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::kVP8Encoder)); + ret.push_back(GetTraits(V4L2ComponentName::kVP8Decoder)); + ret.push_back(GetTraits(V4L2ComponentName::kVP8SecureDecoder)); + ret.push_back(GetTraits(V4L2ComponentName::kVP9Encoder)); + 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()); + ALOG_ASSERT(V4L2ComponentName::isValid(name.c_str())); + + std::lock_guard<std::mutex> lock(mCachedFactoriesLock); + const auto it = mCachedFactories.find(name); + if (it != mCachedFactories.end()) return it->second.get(); + + std::unique_ptr<::C2ComponentFactory> factory = V4L2ComponentFactory::create( + name, std::static_pointer_cast<C2ReflectorHelper>(getParamReflector())); + if (factory == nullptr) { + ALOGE("Failed to create factory for %s", name.c_str()); + return nullptr; + } + + auto ret = factory.get(); + mCachedFactories.emplace(name, std::move(factory)); + return ret; +} + +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; + + auto traits = std::make_shared<C2Component::Traits>(); + traits->name = name; + traits->domain = C2Component::DOMAIN_VIDEO; + traits->rank = kComponentRank; + traits->mediaType = getMediaTypeFromComponentName(name); + traits->kind = V4L2ComponentName::isEncoder(name.c_str()) ? C2Component::KIND_ENCODER + : C2Component::KIND_DECODER; + + mCachedTraits.emplace(name, traits); + return traits; +} + +} // namespace android diff --git a/components/include/v4l2_codec2/components/V4L2ComponentFactory.h b/components/include/v4l2_codec2/components/V4L2ComponentFactory.h new file mode 100644 index 0000000..fc6abea --- /dev/null +++ b/components/include/v4l2_codec2/components/V4L2ComponentFactory.h @@ -0,0 +1,39 @@ +// Copyright 2021 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_COMPONENTS_V4L2_COMPONENT_FACTORY_H +#define ANDROID_V4L2_CODEC2_COMPONENTS_V4L2_COMPONENT_FACTORY_H + +#include <memory> +#include <string> + +#include <C2ComponentFactory.h> +#include <util/C2InterfaceHelper.h> + +namespace android { + +class V4L2ComponentFactory : public C2ComponentFactory { +public: + static std::unique_ptr<V4L2ComponentFactory> create( + const std::string& componentName, std::shared_ptr<C2ReflectorHelper> reflector); + V4L2ComponentFactory(const std::string& componentName, bool isEncoder, + std::shared_ptr<C2ReflectorHelper> reflector); + ~V4L2ComponentFactory() override = default; + + // Implementation of C2ComponentFactory. + c2_status_t createComponent(c2_node_id_t id, std::shared_ptr<C2Component>* const component, + ComponentDeleter deleter) override; + c2_status_t createInterface(c2_node_id_t id, + std::shared_ptr<C2ComponentInterface>* const interface, + InterfaceDeleter deleter) override; + +private: + const std::string mComponentName; + const bool mIsEncoder; + std::shared_ptr<C2ReflectorHelper> mReflector; +}; + +} // namespace android + +#endif // ANDROID_V4L2_CODEC2_COMPONENTS_V4L2_COMPONENT_FACTORY_H diff --git a/components/include/v4l2_codec2/components/V4L2ComponentStore.h b/components/include/v4l2_codec2/components/V4L2ComponentStore.h new file mode 100644 index 0000000..bfec407 --- /dev/null +++ b/components/include/v4l2_codec2/components/V4L2ComponentStore.h @@ -0,0 +1,61 @@ +// 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_COMPONENTS_V4L2_COMPONENT_STORE_H +#define ANDROID_V4L2_CODEC2_COMPONENTS_V4L2_COMPONENT_STORE_H + +#include <map> +#include <mutex> + +#include <C2Component.h> +#include <C2ComponentFactory.h> +#include <android-base/thread_annotations.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: + V4L2ComponentStore(); + + ::C2ComponentFactory* GetFactory(const C2String& name); + std::shared_ptr<const C2Component::Traits> GetTraits(const C2String& name); + + std::shared_ptr<C2ReflectorHelper> mReflector; + + std::mutex mCachedFactoriesLock; + std::map<C2String, std::unique_ptr<::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_COMPONENTS_V4L2_COMPONENT_STORE_H |