1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //#define LOG_NDEBUG 0
6 #define LOG_TAG "V4L2ComponentStore"
7
8 #include <v4l2_codec2/store/V4L2ComponentStore.h>
9
10 #include <dlfcn.h>
11 #include <stdint.h>
12
13 #include <memory>
14 #include <mutex>
15
16 #include <C2.h>
17 #include <C2Config.h>
18 #include <log/log.h>
19
20 #include <v4l2_codec2/common/V4L2ComponentCommon.h>
21
22 namespace android {
23 namespace {
24 const char* kLibPath = "libv4l2_codec2_components.so";
25 const char* kCreateFactoryFuncName = "CreateCodec2Factory";
26 const char* kDestroyFactoryFuncName = "DestroyCodec2Factory";
27
28 const uint32_t kComponentRank = 0x80;
29 } // namespace
30
31 // static
Create()32 std::shared_ptr<C2ComponentStore> V4L2ComponentStore::Create() {
33 ALOGV("%s()", __func__);
34
35 static std::mutex mutex;
36 static std::weak_ptr<C2ComponentStore> platformStore;
37
38 std::lock_guard<std::mutex> lock(mutex);
39 std::shared_ptr<C2ComponentStore> store = platformStore.lock();
40 if (store != nullptr) return store;
41
42 void* libHandle = dlopen(kLibPath, RTLD_NOW | RTLD_NODELETE);
43 if (!libHandle) {
44 ALOGE("Failed to load library: %s", kLibPath);
45 return nullptr;
46 }
47
48 auto createFactoryFunc = (CreateV4L2FactoryFunc)dlsym(libHandle, kCreateFactoryFuncName);
49 auto destroyFactoryFunc = (DestroyV4L2FactoryFunc)dlsym(libHandle, kDestroyFactoryFuncName);
50 if (!createFactoryFunc || !destroyFactoryFunc) {
51 ALOGE("Failed to load functions: %s, %s", kCreateFactoryFuncName, kDestroyFactoryFuncName);
52 dlclose(libHandle);
53 return nullptr;
54 }
55
56 store = std::shared_ptr<C2ComponentStore>(
57 new V4L2ComponentStore(libHandle, createFactoryFunc, destroyFactoryFunc));
58 platformStore = store;
59 return store;
60 }
61
V4L2ComponentStore(void * libHandle,CreateV4L2FactoryFunc createFactoryFunc,DestroyV4L2FactoryFunc destroyFactoryFunc)62 V4L2ComponentStore::V4L2ComponentStore(void* libHandle, CreateV4L2FactoryFunc createFactoryFunc,
63 DestroyV4L2FactoryFunc destroyFactoryFunc)
64 : mLibHandle(libHandle),
65 mCreateFactoryFunc(createFactoryFunc),
66 mDestroyFactoryFunc(destroyFactoryFunc),
67 mReflector(std::make_shared<C2ReflectorHelper>()) {
68 ALOGV("%s()", __func__);
69 }
70
~V4L2ComponentStore()71 V4L2ComponentStore::~V4L2ComponentStore() {
72 ALOGV("%s()", __func__);
73
74 std::lock_guard<std::mutex> lock(mCachedFactoriesLock);
75 for (const auto& kv : mCachedFactories) mDestroyFactoryFunc(kv.second);
76 mCachedFactories.clear();
77
78 dlclose(mLibHandle);
79 }
80
getName() const81 C2String V4L2ComponentStore::getName() const {
82 return "android.componentStore.v4l2";
83 }
84
createComponent(C2String name,std::shared_ptr<C2Component> * const component)85 c2_status_t V4L2ComponentStore::createComponent(C2String name,
86 std::shared_ptr<C2Component>* const component) {
87 ALOGV("%s(%s)", __func__, name.c_str());
88
89 auto factory = GetFactory(name);
90 if (factory == nullptr) return C2_CORRUPTED;
91
92 component->reset();
93 return factory->createComponent(0, component);
94 }
95
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)96 c2_status_t V4L2ComponentStore::createInterface(
97 C2String name, std::shared_ptr<C2ComponentInterface>* const interface) {
98 ALOGV("%s(%s)", __func__, name.c_str());
99
100 auto factory = GetFactory(name);
101 if (factory == nullptr) return C2_CORRUPTED;
102
103 interface->reset();
104 return factory->createInterface(0, interface);
105 }
106
listComponents()107 std::vector<std::shared_ptr<const C2Component::Traits>> V4L2ComponentStore::listComponents() {
108 ALOGV("%s()", __func__);
109
110 std::vector<std::shared_ptr<const C2Component::Traits>> ret;
111 ret.push_back(GetTraits(V4L2ComponentName::kH264Encoder));
112 ret.push_back(GetTraits(V4L2ComponentName::kH264Decoder));
113 ret.push_back(GetTraits(V4L2ComponentName::kH264SecureDecoder));
114 ret.push_back(GetTraits(V4L2ComponentName::kVP8Decoder));
115 ret.push_back(GetTraits(V4L2ComponentName::kVP8SecureDecoder));
116 ret.push_back(GetTraits(V4L2ComponentName::kVP9Decoder));
117 ret.push_back(GetTraits(V4L2ComponentName::kVP9SecureDecoder));
118 return ret;
119 }
120
getParamReflector() const121 std::shared_ptr<C2ParamReflector> V4L2ComponentStore::getParamReflector() const {
122 return mReflector;
123 }
124
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)125 c2_status_t V4L2ComponentStore::copyBuffer(std::shared_ptr<C2GraphicBuffer> /* src */,
126 std::shared_ptr<C2GraphicBuffer> /* dst */) {
127 return C2_OMITTED;
128 }
129
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const) const130 c2_status_t V4L2ComponentStore::querySupportedParams_nb(
131 std::vector<std::shared_ptr<C2ParamDescriptor>>* const /* params */) const {
132 return C2_OK;
133 }
134
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const) const135 c2_status_t V4L2ComponentStore::query_sm(
136 const std::vector<C2Param*>& stackParams,
137 const std::vector<C2Param::Index>& heapParamIndices,
138 std::vector<std::unique_ptr<C2Param>>* const /* heapParams */) const {
139 // There are no supported config params.
140 return stackParams.empty() && heapParamIndices.empty() ? C2_OK : C2_BAD_INDEX;
141 }
142
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const)143 c2_status_t V4L2ComponentStore::config_sm(
144 const std::vector<C2Param*>& params,
145 std::vector<std::unique_ptr<C2SettingResult>>* const /* failures */) {
146 // There are no supported config params.
147 return params.empty() ? C2_OK : C2_BAD_INDEX;
148 }
149
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const150 c2_status_t V4L2ComponentStore::querySupportedValues_sm(
151 std::vector<C2FieldSupportedValuesQuery>& fields) const {
152 // There are no supported config params.
153 return fields.empty() ? C2_OK : C2_BAD_INDEX;
154 }
155
GetFactory(const C2String & name)156 ::C2ComponentFactory* V4L2ComponentStore::GetFactory(const C2String& name) {
157 ALOGV("%s(%s)", __func__, name.c_str());
158
159 if (!V4L2ComponentName::isValid(name.c_str())) {
160 ALOGE("Invalid component name: %s", name.c_str());
161 return nullptr;
162 }
163
164 std::lock_guard<std::mutex> lock(mCachedFactoriesLock);
165 const auto it = mCachedFactories.find(name);
166 if (it != mCachedFactories.end()) return it->second;
167
168 ::C2ComponentFactory* factory = mCreateFactoryFunc(name.c_str());
169 if (factory == nullptr) {
170 ALOGE("Failed to create factory for %s", name.c_str());
171 return nullptr;
172 }
173
174 mCachedFactories.emplace(name, factory);
175 return factory;
176 }
177
GetTraits(const C2String & name)178 std::shared_ptr<const C2Component::Traits> V4L2ComponentStore::GetTraits(const C2String& name) {
179 ALOGV("%s(%s)", __func__, name.c_str());
180
181 if (!V4L2ComponentName::isValid(name.c_str())) {
182 ALOGE("Invalid component name: %s", name.c_str());
183 return nullptr;
184 }
185
186 std::lock_guard<std::mutex> lock(mCachedTraitsLock);
187 auto it = mCachedTraits.find(name);
188 if (it != mCachedTraits.end()) return it->second;
189
190 std::shared_ptr<C2ComponentInterface> intf;
191 auto res = createInterface(name, &intf);
192 if (res != C2_OK) {
193 ALOGE("failed to create interface for %s: %d", name.c_str(), res);
194 return nullptr;
195 }
196
197 bool isEncoder = V4L2ComponentName::isEncoder(name.c_str());
198 uint32_t mediaTypeIndex = isEncoder ? C2PortMediaTypeSetting::output::PARAM_TYPE
199 : C2PortMediaTypeSetting::input::PARAM_TYPE;
200 std::vector<std::unique_ptr<C2Param>> params;
201 res = intf->query_vb({}, {mediaTypeIndex}, C2_MAY_BLOCK, ¶ms);
202 if (res != C2_OK) {
203 ALOGE("failed to query interface: %d", res);
204 return nullptr;
205 }
206 if (params.size() != 1u) {
207 ALOGE("failed to query interface: unexpected vector size: %zu", params.size());
208 return nullptr;
209 }
210
211 C2PortMediaTypeSetting* mediaTypeConfig = (C2PortMediaTypeSetting*)(params[0].get());
212 if (mediaTypeConfig == nullptr) {
213 ALOGE("failed to query media type");
214 return nullptr;
215 }
216
217 auto traits = std::make_shared<C2Component::Traits>();
218 traits->name = intf->getName();
219 traits->domain = C2Component::DOMAIN_VIDEO;
220 traits->kind = isEncoder ? C2Component::KIND_ENCODER : C2Component::KIND_DECODER;
221 traits->mediaType = mediaTypeConfig->m.value;
222 traits->rank = kComponentRank;
223
224 mCachedTraits.emplace(name, traits);
225 return traits;
226 }
227
228 } // namespace android
229