1 // Copyright 2018 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 "C2VDAComponentStore"
7 #include <C2Component.h>
8 #include <C2ComponentFactory.h>
9 #include <C2Config.h>
10 #include <C2V4l2Support.h>
11
12 #include <utils/Log.h>
13
14 #include <dlfcn.h>
15
16 #include <map>
17 #include <memory>
18 #include <mutex>
19
20 #define UNUSED(expr) \
21 do { \
22 (void)(expr); \
23 } while (0)
24
25 namespace android {
26 class C2VDAComponentStore : public C2ComponentStore {
27 public:
28 C2VDAComponentStore();
29 ~C2VDAComponentStore() override = default;
30
31 // The implementation of C2ComponentStore.
32 C2String getName() const override;
33 c2_status_t createComponent(C2String name,
34 std::shared_ptr<C2Component>* const component) override;
35 c2_status_t createInterface(C2String name,
36 std::shared_ptr<C2ComponentInterface>* const interface) override;
37 std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
38 c2_status_t copyBuffer(std::shared_ptr<C2GraphicBuffer> src,
39 std::shared_ptr<C2GraphicBuffer> dst) override;
40 c2_status_t query_sm(const std::vector<C2Param*>& stackParams,
41 const std::vector<C2Param::Index>& heapParamIndices,
42 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
43 c2_status_t config_sm(const std::vector<C2Param*>& params,
44 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
45 std::shared_ptr<C2ParamReflector> getParamReflector() const override;
46 c2_status_t querySupportedParams_nb(
47 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override;
48 c2_status_t querySupportedValues_sm(
49 std::vector<C2FieldSupportedValuesQuery>& fields) const override;
50
51 private:
52 enum class C2VDACodec {
53 UNKNOWN,
54 H264,
55 VP8,
56 VP9,
57 };
58
59 /**
60 * An object encapsulating a loaded component module.
61 *
62 * \todo provide a way to add traits to known components here to avoid loading the .so-s
63 * for listComponents
64 */
65 class ComponentModule : public C2ComponentFactory {
66 public:
ComponentModule()67 ComponentModule()
68 : mInit(C2_NO_INIT),
69 mLibHandle(nullptr),
70 createFactory(nullptr),
71 destroyFactory(nullptr),
72 mComponentFactory(nullptr) {
73 }
74
75 ~ComponentModule() override;
76 c2_status_t init(std::string libPath, C2VDACodec codec);
77
78 // Return the traits of the component in this module.
79 std::shared_ptr<const C2Component::Traits> getTraits();
80
81 // The implementation of C2ComponentFactory.
82 c2_status_t createComponent(
83 c2_node_id_t id, std::shared_ptr<C2Component>* component,
84 ComponentDeleter deleter = std::default_delete<C2Component>()) override;
85 c2_status_t createInterface(
86 c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* interface,
87 InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;
88
89 protected:
90 std::recursive_mutex mLock; ///< lock protecting mTraits
91 std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
92
93 c2_status_t mInit; ///< initialization result
94
95 void* mLibHandle; ///< loaded library handle
96 C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
97 C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
98 C2ComponentFactory* mComponentFactory; ///< loaded/created component factory
99 };
100
101 /**
102 * An object encapsulating a loadable component module.
103 *
104 * \todo make this also work for enumerations
105 */
106 class ComponentLoader {
107 public:
ComponentLoader(std::string libPath,C2VDACodec codec)108 ComponentLoader(std::string libPath, C2VDACodec codec) : mLibPath(libPath), mCodec(codec) {}
109
110 /**
111 * Load the component module.
112 *
113 * This method simply returns the component module if it is already currently loaded, or
114 * attempts to load it if it is not.
115 *
116 * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
117 * This will be nullptr on error.
118 *
119 * \retval C2_OK the component module has been successfully loaded
120 * \retval C2_NO_MEMORY not enough memory to loading the component module
121 * \retval C2_NOT_FOUND could not locate the component module
122 * \retval C2_CORRUPTED the component module could not be loaded
123 * \retval C2_REFUSED permission denied to load the component module
124 */
125 c2_status_t fetchModule(std::shared_ptr<ComponentModule>* module);
126
127 private:
128 std::mutex mMutex; ///< mutex guarding the module
129 std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
130 std::string mLibPath; ///< library path (or name)
131 C2VDACodec mCodec = C2VDACodec::UNKNOWN;
132 };
133
134 c2_status_t findComponent(C2String name, ComponentLoader** loader);
135
136 std::map<C2String, ComponentLoader> mComponents; ///< list of components
137 };
138
~ComponentModule()139 C2VDAComponentStore::ComponentModule::~ComponentModule() {
140 ALOGV("in %s", __func__);
141 if (destroyFactory && mComponentFactory) {
142 destroyFactory(mComponentFactory);
143 }
144 if (mLibHandle) {
145 ALOGV("unloading dll");
146 dlclose(mLibHandle);
147 }
148 }
149
init(std::string libPath,C2VDACodec codec)150 c2_status_t C2VDAComponentStore::ComponentModule::init(std::string libPath, C2VDACodec codec) {
151 ALOGV("in %s", __func__);
152 ALOGV("loading dll");
153 mLibHandle = dlopen(libPath.c_str(), RTLD_NOW | RTLD_NODELETE);
154 if (mLibHandle == nullptr) {
155 ALOGD("could not dlopen %s: %s", libPath.c_str(), dlerror());
156 mInit = C2_CORRUPTED;
157 } else {
158 std::string createFactoryName;
159 std::string destroyFactoryName;
160 switch (codec) {
161 case C2VDACodec::H264:
162 createFactoryName = "CreateC2VDAH264Factory";
163 destroyFactoryName = "DestroyC2VDAH264Factory";
164 break;
165 case C2VDACodec::VP8:
166 createFactoryName = "CreateC2VDAVP8Factory";
167 destroyFactoryName = "DestroyC2VDAVP8Factory";
168 break;
169 case C2VDACodec::VP9:
170 createFactoryName = "CreateC2VDAVP9Factory";
171 destroyFactoryName = "DestroyC2VDAVP9Factory";
172 break;
173 default:
174 ALOGE("Unknown ");
175 return C2_CORRUPTED;
176 }
177 createFactory = (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(
178 mLibHandle, createFactoryName.c_str());
179 destroyFactory = (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(
180 mLibHandle, destroyFactoryName.c_str());
181
182 mComponentFactory = createFactory();
183 if (mComponentFactory == nullptr) {
184 ALOGD("could not create factory in %s", libPath.c_str());
185 mInit = C2_NO_MEMORY;
186 } else {
187 mInit = C2_OK;
188 }
189 }
190 return mInit;
191 }
192
getTraits()193 std::shared_ptr<const C2Component::Traits> C2VDAComponentStore::ComponentModule::getTraits() {
194 std::unique_lock<std::recursive_mutex> lock(mLock);
195 if (!mTraits) {
196 std::shared_ptr<C2ComponentInterface> intf;
197 auto res = createInterface(0, &intf);
198 if (res != C2_OK) {
199 ALOGE("failed to create interface: %d", res);
200 return nullptr;
201 }
202
203 std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
204 if (traits) {
205 traits->name = intf->getName();
206 // TODO: get this from interface properly.
207 bool encoder = (traits->name.find("encoder") != std::string::npos);
208 uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
209 : C2PortMimeConfig::input::PARAM_TYPE;
210 std::vector<std::unique_ptr<C2Param>> params;
211 res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, ¶ms);
212 if (res != C2_OK) {
213 ALOGE("failed to query interface: %d", res);
214 return nullptr;
215 }
216 if (params.size() != 1u) {
217 ALOGE("failed to query interface: unexpected vector size: %zu", params.size());
218 return nullptr;
219 }
220 C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
221 if (mediaTypeConfig == nullptr) {
222 ALOGE("failed to query media type");
223 return nullptr;
224 }
225 traits->mediaType = mediaTypeConfig->m.value;
226 // TODO: get this properly.
227 // Set the rank prior to c2.android.* (=0x200) and after OMX.google.* (=0x100) by now.
228 // In the future this should be prior to OMX.google.* as well so that ARC HW codec
229 // would be the first priority.
230 traits->rank = 0x180;
231 }
232 mTraits = traits;
233 }
234 return mTraits;
235 }
236
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * component,std::function<void (::C2Component *)> deleter)237 c2_status_t C2VDAComponentStore::ComponentModule::createComponent(
238 c2_node_id_t id, std::shared_ptr<C2Component>* component,
239 std::function<void(::C2Component*)> deleter) {
240 UNUSED(deleter);
241 component->reset();
242 if (mInit != C2_OK) {
243 return mInit;
244 }
245 return mComponentFactory->createComponent(id, component,
246 C2ComponentFactory::ComponentDeleter());
247 }
248
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * interface,std::function<void (::C2ComponentInterface *)> deleter)249 c2_status_t C2VDAComponentStore::ComponentModule::createInterface(
250 c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* interface,
251 std::function<void(::C2ComponentInterface*)> deleter) {
252 UNUSED(deleter);
253 interface->reset();
254 if (mInit != C2_OK) {
255 return mInit;
256 }
257 return mComponentFactory->createInterface(id, interface,
258 C2ComponentFactory::InterfaceDeleter());
259 }
260
fetchModule(std::shared_ptr<ComponentModule> * module)261 c2_status_t C2VDAComponentStore::ComponentLoader::fetchModule(
262 std::shared_ptr<ComponentModule>* module) {
263 c2_status_t res = C2_OK;
264 std::lock_guard<std::mutex> lock(mMutex);
265 std::shared_ptr<ComponentModule> localModule = mModule.lock();
266 if (localModule == nullptr) {
267 localModule = std::make_shared<ComponentModule>();
268 res = localModule->init(mLibPath, mCodec);
269 if (res == C2_OK) {
270 mModule = localModule;
271 }
272 }
273 *module = localModule;
274 return res;
275 }
276
C2VDAComponentStore()277 C2VDAComponentStore::C2VDAComponentStore() {
278 // TODO: move this also into a .so so it can be updated
279 mComponents.emplace(std::piecewise_construct, std::forward_as_tuple("c2.vda.avc.decoder"),
280 std::forward_as_tuple("libv4l2_codec2.so", C2VDACodec::H264));
281 mComponents.emplace(std::piecewise_construct, std::forward_as_tuple("c2.vda.vp8.decoder"),
282 std::forward_as_tuple("libv4l2_codec2.so", C2VDACodec::VP8));
283 mComponents.emplace(std::piecewise_construct, std::forward_as_tuple("c2.vda.vp9.decoder"),
284 std::forward_as_tuple("libv4l2_codec2.so", C2VDACodec::VP9));
285 }
286
getName() const287 C2String C2VDAComponentStore::getName() const {
288 return "android.componentStore.vda";
289 }
290
listComponents()291 std::vector<std::shared_ptr<const C2Component::Traits>> C2VDAComponentStore::listComponents() {
292 // This method SHALL return within 500ms.
293 std::vector<std::shared_ptr<const C2Component::Traits>> list;
294 for (auto& it : mComponents) {
295 ComponentLoader& loader = it.second;
296 std::shared_ptr<ComponentModule> module;
297 c2_status_t res = loader.fetchModule(&module);
298 if (res == C2_OK) {
299 std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
300 if (traits) {
301 list.push_back(traits);
302 }
303 }
304 }
305 return list;
306 }
307
findComponent(C2String name,ComponentLoader ** loader)308 c2_status_t C2VDAComponentStore::findComponent(C2String name, ComponentLoader** loader) {
309 *loader = nullptr;
310 auto pos = mComponents.find(name);
311 // TODO: check aliases
312 if (pos == mComponents.end()) {
313 return C2_NOT_FOUND;
314 }
315 *loader = &pos->second;
316 return C2_OK;
317 }
318
createComponent(C2String name,std::shared_ptr<C2Component> * const component)319 c2_status_t C2VDAComponentStore::createComponent(C2String name,
320 std::shared_ptr<C2Component>* const component) {
321 // This method SHALL return within 100ms.
322 component->reset();
323 ComponentLoader* loader;
324 c2_status_t res = findComponent(name, &loader);
325 if (res == C2_OK) {
326 std::shared_ptr<ComponentModule> module;
327 res = loader->fetchModule(&module);
328 if (res == C2_OK) {
329 // TODO: get a unique node ID
330 res = module->createComponent(0, component);
331 }
332 }
333 return res;
334 }
335
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)336 c2_status_t C2VDAComponentStore::createInterface(
337 C2String name, std::shared_ptr<C2ComponentInterface>* const interface) {
338 // This method SHALL return within 100ms.
339 interface->reset();
340 ComponentLoader* loader;
341 c2_status_t res = findComponent(name, &loader);
342 if (res == C2_OK) {
343 std::shared_ptr<ComponentModule> module;
344 res = loader->fetchModule(&module);
345 if (res == C2_OK) {
346 // TODO: get a unique node ID
347 res = module->createInterface(0, interface);
348 }
349 }
350 return res;
351 }
352
copyBuffer(std::shared_ptr<C2GraphicBuffer> src,std::shared_ptr<C2GraphicBuffer> dst)353 c2_status_t C2VDAComponentStore::copyBuffer(std::shared_ptr<C2GraphicBuffer> src,
354 std::shared_ptr<C2GraphicBuffer> dst) {
355 UNUSED(src);
356 UNUSED(dst);
357 return C2_OMITTED;
358 }
359
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const360 c2_status_t C2VDAComponentStore::query_sm(
361 const std::vector<C2Param*>& stackParams,
362 const std::vector<C2Param::Index>& heapParamIndices,
363 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
364 // there are no supported configs
365 UNUSED(heapParams);
366 return stackParams.empty() && heapParamIndices.empty() ? C2_OK : C2_BAD_INDEX;
367 }
368
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)369 c2_status_t C2VDAComponentStore::config_sm(
370 const std::vector<C2Param*>& params,
371 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
372 // there are no supported configs
373 UNUSED(failures);
374 return params.empty() ? C2_OK : C2_BAD_INDEX;
375 }
376
getParamReflector() const377 std::shared_ptr<C2ParamReflector> C2VDAComponentStore::getParamReflector() const {
378 // TODO
379 return nullptr;
380 }
381
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const382 c2_status_t C2VDAComponentStore::querySupportedParams_nb(
383 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
384 // there are no supported config params
385 UNUSED(params);
386 return C2_OK;
387 }
388
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const389 c2_status_t C2VDAComponentStore::querySupportedValues_sm(
390 std::vector<C2FieldSupportedValuesQuery>& fields) const {
391 // there are no supported config params
392 return fields.empty() ? C2_OK : C2_BAD_INDEX;
393 }
394
GetCodec2VDAComponentStore()395 std::shared_ptr<C2ComponentStore> GetCodec2VDAComponentStore() {
396 static std::mutex mutex;
397 static std::weak_ptr<C2ComponentStore> platformStore;
398 std::lock_guard<std::mutex> lock(mutex);
399 std::shared_ptr<C2ComponentStore> store = platformStore.lock();
400 if (store == nullptr) {
401 store = std::make_shared<C2VDAComponentStore>();
402 platformStore = store;
403 }
404 return store;
405 }
406
407 } // namespace android
408