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, ¶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 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