Home | History | Annotate | Download | only in v4l2store
      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:
     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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    287 C2String C2VDAComponentStore::getName() const {
    288     return "android.componentStore.vda";
    289 }
    290 
    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 
    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 
    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 
    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 
    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 
    360 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 
    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 
    377 std::shared_ptr<C2ParamReflector> C2VDAComponentStore::getParamReflector() const {
    378     // TODO
    379     return nullptr;
    380 }
    381 
    382 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 
    389 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 
    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