• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params);
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