blob: 03810e9d604be3c8b546510903ff745694e9a8d6 [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "C2Store"
18#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
Pin-chih Linaa18ea52019-11-19 18:48:50 +080021#include <C2AllocatorBlob.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080022#include <C2AllocatorGralloc.h>
23#include <C2AllocatorIon.h>
24#include <C2BufferPriv.h>
25#include <C2BqBufferPriv.h>
26#include <C2Component.h>
27#include <C2Config.h>
28#include <C2PlatformStorePluginLoader.h>
29#include <C2PlatformSupport.h>
Pin-chih Linaa18ea52019-11-19 18:48:50 +080030#include <cutils/properties.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080031#include <util/C2InterfaceHelper.h>
32
33#include <dlfcn.h>
34#include <unistd.h> // getpagesize
35
36#include <map>
37#include <memory>
38#include <mutex>
39
40namespace android {
41
42/**
43 * Returns the preferred component store in this process to access its interface.
44 */
45std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore();
46
47/**
48 * The platform allocator store provides basic allocator-types for the framework based on ion and
49 * gralloc. Allocators are not meant to be updatable.
50 *
51 * \todo Provide allocator based on ashmem
52 * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
53 * \todo Make this allocator store extendable
54 */
55class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
56public:
57 C2PlatformAllocatorStoreImpl();
58
59 virtual c2_status_t fetchAllocator(
60 id_t id, std::shared_ptr<C2Allocator> *const allocator) override;
61
62 virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb()
63 const override {
64 return std::vector<std::shared_ptr<const C2Allocator::Traits>>(); /// \todo
65 }
66
67 virtual C2String getName() const override {
68 return "android.allocator-store";
69 }
70
71 void setComponentStore(std::shared_ptr<C2ComponentStore> store);
72
73 ~C2PlatformAllocatorStoreImpl() override = default;
74
75private:
Pin-chih Linaa18ea52019-11-19 18:48:50 +080076 /// returns a shared-singleton blob allocator (gralloc-backed)
77 std::shared_ptr<C2Allocator> fetchBlobAllocator();
78
Pawin Vongmasa36653902018-11-15 00:10:25 -080079 /// returns a shared-singleton ion allocator
80 std::shared_ptr<C2Allocator> fetchIonAllocator();
81
82 /// returns a shared-singleton gralloc allocator
83 std::shared_ptr<C2Allocator> fetchGrallocAllocator();
84
85 /// returns a shared-singleton bufferqueue supporting gralloc allocator
86 std::shared_ptr<C2Allocator> fetchBufferQueueAllocator();
87
88 /// component store to use
89 std::mutex _mComponentStoreSetLock; // protects the entire updating _mComponentStore and its
90 // dependencies
91 std::mutex _mComponentStoreReadLock; // must protect only read/write of _mComponentStore
92 std::shared_ptr<C2ComponentStore> _mComponentStore;
93};
94
95C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
96}
97
98c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
99 id_t id, std::shared_ptr<C2Allocator> *const allocator) {
100 allocator->reset();
Pin-chih Linaa18ea52019-11-19 18:48:50 +0800101 if (id == C2AllocatorStore::DEFAULT_LINEAR) {
102 id = GetPreferredLinearAllocatorId(GetCodec2PoolMask());
103 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800104 switch (id) {
105 // TODO: should we implement a generic registry for all, and use that?
106 case C2PlatformAllocatorStore::ION:
Pawin Vongmasa36653902018-11-15 00:10:25 -0800107 *allocator = fetchIonAllocator();
108 break;
109
110 case C2PlatformAllocatorStore::GRALLOC:
111 case C2AllocatorStore::DEFAULT_GRAPHIC:
112 *allocator = fetchGrallocAllocator();
113 break;
114
115 case C2PlatformAllocatorStore::BUFFERQUEUE:
116 *allocator = fetchBufferQueueAllocator();
117 break;
118
Pin-chih Linaa18ea52019-11-19 18:48:50 +0800119 case C2PlatformAllocatorStore::BLOB:
120 *allocator = fetchBlobAllocator();
121 break;
122
Pawin Vongmasa36653902018-11-15 00:10:25 -0800123 default:
124 // Try to create allocator from platform store plugins.
125 c2_status_t res =
126 C2PlatformStorePluginLoader::GetInstance()->createAllocator(id, allocator);
127 if (res != C2_OK) {
128 return res;
129 }
130 break;
131 }
132 if (*allocator == nullptr) {
133 return C2_NO_MEMORY;
134 }
135 return C2_OK;
136}
137
138namespace {
139
140std::mutex gIonAllocatorMutex;
141std::weak_ptr<C2AllocatorIon> gIonAllocator;
142
143void UseComponentStoreForIonAllocator(
144 const std::shared_ptr<C2AllocatorIon> allocator,
145 std::shared_ptr<C2ComponentStore> store) {
146 C2AllocatorIon::UsageMapperFn mapper;
147 uint64_t minUsage = 0;
148 uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected;
149 size_t blockSize = getpagesize();
150
151 // query min and max usage as well as block size via supported values
152 C2StoreIonUsageInfo usageInfo;
153 std::vector<C2FieldSupportedValuesQuery> query = {
154 C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.usage)),
155 C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.capacity)),
156 };
157 c2_status_t res = store->querySupportedValues_sm(query);
158 if (res == C2_OK) {
159 if (query[0].status == C2_OK) {
160 const C2FieldSupportedValues &fsv = query[0].values;
161 if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) {
162 minUsage = fsv.values[0].u64;
163 maxUsage = 0;
164 for (C2Value::Primitive v : fsv.values) {
165 maxUsage |= v.u64;
166 }
167 }
168 }
169 if (query[1].status == C2_OK) {
170 const C2FieldSupportedValues &fsv = query[1].values;
171 if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) {
172 blockSize = fsv.range.step.u32;
173 }
174 }
175
176 mapper = [store](C2MemoryUsage usage, size_t capacity,
177 size_t *align, unsigned *heapMask, unsigned *flags) -> c2_status_t {
178 if (capacity > UINT32_MAX) {
179 return C2_BAD_VALUE;
180 }
181 C2StoreIonUsageInfo usageInfo = { usage.expected, capacity };
182 std::vector<std::unique_ptr<C2SettingResult>> failures; // TODO: remove
183 c2_status_t res = store->config_sm({&usageInfo}, &failures);
184 if (res == C2_OK) {
185 *align = usageInfo.minAlignment;
186 *heapMask = usageInfo.heapMask;
187 *flags = usageInfo.allocFlags;
188 }
189 return res;
190 };
191 }
192
193 allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize);
194}
195
196}
197
198void C2PlatformAllocatorStoreImpl::setComponentStore(std::shared_ptr<C2ComponentStore> store) {
199 // technically this set lock is not needed, but is here for safety in case we add more
200 // getter orders
201 std::lock_guard<std::mutex> lock(_mComponentStoreSetLock);
202 {
203 std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
204 _mComponentStore = store;
205 }
206 std::shared_ptr<C2AllocatorIon> allocator;
207 {
208 std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
209 allocator = gIonAllocator.lock();
210 }
211 if (allocator) {
212 UseComponentStoreForIonAllocator(allocator, store);
213 }
214}
215
216std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
217 std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
218 std::shared_ptr<C2AllocatorIon> allocator = gIonAllocator.lock();
219 if (allocator == nullptr) {
220 std::shared_ptr<C2ComponentStore> componentStore;
221 {
222 std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
223 componentStore = _mComponentStore;
224 }
225 allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
226 UseComponentStoreForIonAllocator(allocator, componentStore);
227 gIonAllocator = allocator;
228 }
229 return allocator;
230}
231
Pin-chih Linaa18ea52019-11-19 18:48:50 +0800232std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBlobAllocator() {
233 static std::mutex mutex;
234 static std::weak_ptr<C2Allocator> blobAllocator;
235 std::lock_guard<std::mutex> lock(mutex);
236 std::shared_ptr<C2Allocator> allocator = blobAllocator.lock();
237 if (allocator == nullptr) {
238 allocator = std::make_shared<C2AllocatorBlob>(C2PlatformAllocatorStore::BLOB);
239 blobAllocator = allocator;
240 }
241 return allocator;
242}
243
Pawin Vongmasa36653902018-11-15 00:10:25 -0800244std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
245 static std::mutex mutex;
246 static std::weak_ptr<C2Allocator> grallocAllocator;
247 std::lock_guard<std::mutex> lock(mutex);
248 std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
249 if (allocator == nullptr) {
250 allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
251 grallocAllocator = allocator;
252 }
253 return allocator;
254}
255
256std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBufferQueueAllocator() {
257 static std::mutex mutex;
258 static std::weak_ptr<C2Allocator> grallocAllocator;
259 std::lock_guard<std::mutex> lock(mutex);
260 std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
261 if (allocator == nullptr) {
262 allocator = std::make_shared<C2AllocatorGralloc>(
263 C2PlatformAllocatorStore::BUFFERQUEUE, true);
264 grallocAllocator = allocator;
265 }
266 return allocator;
267}
268
269namespace {
270 std::mutex gPreferredComponentStoreMutex;
271 std::shared_ptr<C2ComponentStore> gPreferredComponentStore;
272
273 std::mutex gPlatformAllocatorStoreMutex;
274 std::weak_ptr<C2PlatformAllocatorStoreImpl> gPlatformAllocatorStore;
275}
276
277std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
278 std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
279 std::shared_ptr<C2PlatformAllocatorStoreImpl> store = gPlatformAllocatorStore.lock();
280 if (store == nullptr) {
281 store = std::make_shared<C2PlatformAllocatorStoreImpl>();
282 store->setComponentStore(GetPreferredCodec2ComponentStore());
283 gPlatformAllocatorStore = store;
284 }
285 return store;
286}
287
288void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore) {
289 static std::mutex mutex;
290 std::lock_guard<std::mutex> lock(mutex); // don't interleve set-s
291
292 // update preferred store
293 {
294 std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
295 gPreferredComponentStore = componentStore;
296 }
297
298 // update platform allocator's store as well if it is alive
299 std::shared_ptr<C2PlatformAllocatorStoreImpl> allocatorStore;
300 {
301 std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
302 allocatorStore = gPlatformAllocatorStore.lock();
303 }
304 if (allocatorStore) {
305 allocatorStore->setComponentStore(componentStore);
306 }
307}
308
309std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore() {
310 std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
311 return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore();
312}
313
Pin-chih Linaa18ea52019-11-19 18:48:50 +0800314int GetCodec2PoolMask() {
315 return property_get_int32(
316 "debug.stagefright.c2-poolmask",
317 1 << C2PlatformAllocatorStore::ION |
318 1 << C2PlatformAllocatorStore::BUFFERQUEUE);
319}
320
321C2PlatformAllocatorStore::id_t GetPreferredLinearAllocatorId(int poolMask) {
322 return ((poolMask >> C2PlatformAllocatorStore::BLOB) & 1) ? C2PlatformAllocatorStore::BLOB
323 : C2PlatformAllocatorStore::ION;
324}
325
Pawin Vongmasa36653902018-11-15 00:10:25 -0800326namespace {
327
328class _C2BlockPoolCache {
329public:
330 _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
331
332 c2_status_t _createBlockPool(
333 C2PlatformAllocatorStore::id_t allocatorId,
334 std::shared_ptr<const C2Component> component,
335 C2BlockPool::local_id_t poolId,
336 std::shared_ptr<C2BlockPool> *pool) {
337 std::shared_ptr<C2AllocatorStore> allocatorStore =
338 GetCodec2PlatformAllocatorStore();
339 std::shared_ptr<C2Allocator> allocator;
340 c2_status_t res = C2_NOT_FOUND;
341
Pin-chih Linaa18ea52019-11-19 18:48:50 +0800342 if (allocatorId == C2AllocatorStore::DEFAULT_LINEAR) {
343 allocatorId = GetPreferredLinearAllocatorId(GetCodec2PoolMask());
344 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800345 switch(allocatorId) {
346 case C2PlatformAllocatorStore::ION:
Pawin Vongmasa36653902018-11-15 00:10:25 -0800347 res = allocatorStore->fetchAllocator(
Pin-chih Linaa18ea52019-11-19 18:48:50 +0800348 C2PlatformAllocatorStore::ION, &allocator);
349 if (res == C2_OK) {
350 std::shared_ptr<C2BlockPool> ptr =
351 std::make_shared<C2PooledBlockPool>(
352 allocator, poolId);
353 *pool = ptr;
354 mBlockPools[poolId] = ptr;
355 mComponents[poolId] = component;
356 }
357 break;
358 case C2PlatformAllocatorStore::BLOB:
359 res = allocatorStore->fetchAllocator(
360 C2PlatformAllocatorStore::BLOB, &allocator);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800361 if (res == C2_OK) {
362 std::shared_ptr<C2BlockPool> ptr =
363 std::make_shared<C2PooledBlockPool>(
364 allocator, poolId);
365 *pool = ptr;
366 mBlockPools[poolId] = ptr;
367 mComponents[poolId] = component;
368 }
369 break;
370 case C2PlatformAllocatorStore::GRALLOC:
371 case C2AllocatorStore::DEFAULT_GRAPHIC:
372 res = allocatorStore->fetchAllocator(
373 C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
374 if (res == C2_OK) {
375 std::shared_ptr<C2BlockPool> ptr =
376 std::make_shared<C2PooledBlockPool>(allocator, poolId);
377 *pool = ptr;
378 mBlockPools[poolId] = ptr;
379 mComponents[poolId] = component;
380 }
381 break;
382 case C2PlatformAllocatorStore::BUFFERQUEUE:
383 res = allocatorStore->fetchAllocator(
384 C2PlatformAllocatorStore::BUFFERQUEUE, &allocator);
385 if (res == C2_OK) {
386 std::shared_ptr<C2BlockPool> ptr =
387 std::make_shared<C2BufferQueueBlockPool>(
388 allocator, poolId);
389 *pool = ptr;
390 mBlockPools[poolId] = ptr;
391 mComponents[poolId] = component;
392 }
393 break;
394 default:
395 // Try to create block pool from platform store plugins.
396 std::shared_ptr<C2BlockPool> ptr;
397 res = C2PlatformStorePluginLoader::GetInstance()->createBlockPool(
398 allocatorId, poolId, &ptr);
399 if (res == C2_OK) {
400 *pool = ptr;
401 mBlockPools[poolId] = ptr;
402 mComponents[poolId] = component;
403 }
404 break;
405 }
406 return res;
407 }
408
409 c2_status_t createBlockPool(
410 C2PlatformAllocatorStore::id_t allocatorId,
411 std::shared_ptr<const C2Component> component,
412 std::shared_ptr<C2BlockPool> *pool) {
413 return _createBlockPool(allocatorId, component, mBlockPoolSeqId++, pool);
414 }
415
416 bool getBlockPool(
417 C2BlockPool::local_id_t blockPoolId,
418 std::shared_ptr<const C2Component> component,
419 std::shared_ptr<C2BlockPool> *pool) {
420 // TODO: use one iterator for multiple blockpool type scalability.
421 std::shared_ptr<C2BlockPool> ptr;
422 auto it = mBlockPools.find(blockPoolId);
423 if (it != mBlockPools.end()) {
424 ptr = it->second.lock();
425 if (!ptr) {
426 mBlockPools.erase(it);
427 mComponents.erase(blockPoolId);
428 } else {
429 auto found = mComponents.find(blockPoolId);
430 if (component == found->second.lock()) {
431 *pool = ptr;
432 return true;
433 }
434 }
435 }
436 return false;
437 }
438
439private:
440 C2BlockPool::local_id_t mBlockPoolSeqId;
441
442 std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
443 std::map<C2BlockPool::local_id_t, std::weak_ptr<const C2Component>> mComponents;
444};
445
446static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
447 std::make_unique<_C2BlockPoolCache>();
448static std::mutex sBlockPoolCacheMutex;
449
450} // anynymous namespace
451
452c2_status_t GetCodec2BlockPool(
453 C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
454 std::shared_ptr<C2BlockPool> *pool) {
455 pool->reset();
456 std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
457 std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
458 std::shared_ptr<C2Allocator> allocator;
459 c2_status_t res = C2_NOT_FOUND;
460
461 if (id >= C2BlockPool::PLATFORM_START) {
462 if (sBlockPoolCache->getBlockPool(id, component, pool)) {
463 return C2_OK;
464 }
465 }
466
467 switch (id) {
468 case C2BlockPool::BASIC_LINEAR:
469 res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
470 if (res == C2_OK) {
471 *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
472 }
473 break;
474 case C2BlockPool::BASIC_GRAPHIC:
475 res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
476 if (res == C2_OK) {
477 *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
478 }
479 break;
480 // TODO: remove this. this is temporary
481 case C2BlockPool::PLATFORM_START:
482 res = sBlockPoolCache->_createBlockPool(
483 C2PlatformAllocatorStore::BUFFERQUEUE, component, id, pool);
484 break;
485 default:
486 break;
487 }
488 return res;
489}
490
491c2_status_t CreateCodec2BlockPool(
492 C2PlatformAllocatorStore::id_t allocatorId,
493 std::shared_ptr<const C2Component> component,
494 std::shared_ptr<C2BlockPool> *pool) {
495 pool->reset();
496
497 std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
498 return sBlockPoolCache->createBlockPool(allocatorId, component, pool);
499}
500
501class C2PlatformComponentStore : public C2ComponentStore {
502public:
503 virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
504 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
505 virtual C2String getName() const override;
506 virtual c2_status_t querySupportedValues_sm(
507 std::vector<C2FieldSupportedValuesQuery> &fields) const override;
508 virtual c2_status_t querySupportedParams_nb(
509 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override;
510 virtual c2_status_t query_sm(
511 const std::vector<C2Param*> &stackParams,
512 const std::vector<C2Param::Index> &heapParamIndices,
513 std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
514 virtual c2_status_t createInterface(
515 C2String name, std::shared_ptr<C2ComponentInterface> *const interface) override;
516 virtual c2_status_t createComponent(
517 C2String name, std::shared_ptr<C2Component> *const component) override;
518 virtual c2_status_t copyBuffer(
519 std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) override;
520 virtual c2_status_t config_sm(
521 const std::vector<C2Param*> &params,
522 std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
523 C2PlatformComponentStore();
524
525 virtual ~C2PlatformComponentStore() override = default;
526
527private:
528
529 /**
530 * An object encapsulating a loaded component module.
531 *
532 * \todo provide a way to add traits to known components here to avoid loading the .so-s
533 * for listComponents
534 */
535 struct ComponentModule : public C2ComponentFactory,
536 public std::enable_shared_from_this<ComponentModule> {
537 virtual c2_status_t createComponent(
538 c2_node_id_t id, std::shared_ptr<C2Component> *component,
539 ComponentDeleter deleter = std::default_delete<C2Component>()) override;
540 virtual c2_status_t createInterface(
541 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
542 InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;
543
544 /**
545 * \returns the traits of the component in this module.
546 */
547 std::shared_ptr<const C2Component::Traits> getTraits();
548
549 /**
550 * Creates an uninitialized component module.
551 *
552 * \param name[in] component name.
553 *
554 * \note Only used by ComponentLoader.
555 */
556 ComponentModule()
557 : mInit(C2_NO_INIT),
558 mLibHandle(nullptr),
559 createFactory(nullptr),
560 destroyFactory(nullptr),
561 mComponentFactory(nullptr) {
562 }
563
564 /**
565 * Initializes a component module with a given library path. Must be called exactly once.
566 *
567 * \note Only used by ComponentLoader.
568 *
Pawin Vongmasa36653902018-11-15 00:10:25 -0800569 * \param libPath[in] library path
570 *
571 * \retval C2_OK the component module has been successfully loaded
572 * \retval C2_NO_MEMORY not enough memory to loading the component module
573 * \retval C2_NOT_FOUND could not locate the component module
574 * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
575 * \retval C2_REFUSED permission denied to load the component module (unexpected)
576 * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
577 */
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800578 c2_status_t init(std::string libPath);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800579
580 virtual ~ComponentModule() override;
581
582 protected:
583 std::recursive_mutex mLock; ///< lock protecting mTraits
584 std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
585
586 c2_status_t mInit; ///< initialization result
587
588 void *mLibHandle; ///< loaded library handle
589 C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
590 C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
591 C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
592 };
593
594 /**
595 * An object encapsulating a loadable component module.
596 *
597 * \todo make this also work for enumerations
598 */
599 struct ComponentLoader {
600 /**
601 * Load the component module.
602 *
603 * This method simply returns the component module if it is already currently loaded, or
604 * attempts to load it if it is not.
605 *
606 * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
607 * This will be nullptr on error.
608 *
609 * \retval C2_OK the component module has been successfully loaded
610 * \retval C2_NO_MEMORY not enough memory to loading the component module
611 * \retval C2_NOT_FOUND could not locate the component module
612 * \retval C2_CORRUPTED the component module could not be loaded
613 * \retval C2_REFUSED permission denied to load the component module
614 */
615 c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
616 c2_status_t res = C2_OK;
617 std::lock_guard<std::mutex> lock(mMutex);
618 std::shared_ptr<ComponentModule> localModule = mModule.lock();
619 if (localModule == nullptr) {
620 localModule = std::make_shared<ComponentModule>();
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800621 res = localModule->init(mLibPath);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800622 if (res == C2_OK) {
623 mModule = localModule;
624 }
625 }
626 *module = localModule;
627 return res;
628 }
629
630 /**
631 * Creates a component loader for a specific library path (or name).
632 */
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800633 ComponentLoader(std::string libPath)
634 : mLibPath(libPath) {}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800635
636 private:
637 std::mutex mMutex; ///< mutex guarding the module
638 std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
Pawin Vongmasa36653902018-11-15 00:10:25 -0800639 std::string mLibPath; ///< library path
640 };
641
642 struct Interface : public C2InterfaceHelper {
643 std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
644
645 Interface(std::shared_ptr<C2ReflectorHelper> reflector)
646 : C2InterfaceHelper(reflector) {
647 setDerivedInstance(this);
648
649 struct Setter {
650 static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
651 me.set().heapMask = ~0;
652 me.set().allocFlags = 0;
653 me.set().minAlignment = 0;
654 return C2R::Ok();
655 }
656 };
657
658 addParameter(
659 DefineParam(mIonUsageInfo, "ion-usage")
660 .withDefault(new C2StoreIonUsageInfo())
661 .withFields({
662 C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
663 C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
664 C2F(mIonUsageInfo, heapMask).any(),
665 C2F(mIonUsageInfo, allocFlags).flags({}),
666 C2F(mIonUsageInfo, minAlignment).equalTo(0)
667 })
668 .withSetter(Setter::setIonUsage)
669 .build());
670 }
671 };
672
673 /**
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800674 * Retrieves the component module for a component.
Pawin Vongmasa36653902018-11-15 00:10:25 -0800675 *
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800676 * \param module pointer to a shared_pointer where the component module will be stored on
677 * success.
Pawin Vongmasa36653902018-11-15 00:10:25 -0800678 *
679 * \retval C2_OK the component loader has been successfully retrieved
680 * \retval C2_NO_MEMORY not enough memory to locate the component loader
681 * \retval C2_NOT_FOUND could not locate the component to be loaded
682 * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
683 * corrupted (this can happen if the name does not refer to an already
684 * identified component but some components could not be loaded due to
685 * bad library)
686 * \retval C2_REFUSED permission denied to find the component loader for the named component
687 * (this can happen if the name does not refer to an already identified
688 * component but some components could not be loaded due to lack of
689 * permissions)
690 */
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800691 c2_status_t findComponent(C2String name, std::shared_ptr<ComponentModule> *module);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800692
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800693 /**
694 * Loads each component module and discover its contents.
695 */
696 void visitComponents();
697
698 std::mutex mMutex; ///< mutex guarding the component lists during construction
699 bool mVisited; ///< component modules visited
700 std::map<C2String, ComponentLoader> mComponents; ///< path -> component module
701 std::map<C2String, C2String> mComponentNameToPath; ///< name -> path
702 std::vector<std::shared_ptr<const C2Component::Traits>> mComponentList;
703
Pawin Vongmasa36653902018-11-15 00:10:25 -0800704 std::shared_ptr<C2ReflectorHelper> mReflector;
705 Interface mInterface;
706};
707
708c2_status_t C2PlatformComponentStore::ComponentModule::init(
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800709 std::string libPath) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800710 ALOGV("in %s", __func__);
711 ALOGV("loading dll");
712 mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
Dongwon Kang673236b2019-05-08 09:02:21 -0700713 LOG_ALWAYS_FATAL_IF(mLibHandle == nullptr,
714 "could not dlopen %s: %s", libPath.c_str(), dlerror());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800715
Chong Zhangf5c7ca82019-04-23 17:06:21 -0700716 createFactory =
717 (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
Dongwon Kang673236b2019-05-08 09:02:21 -0700718 LOG_ALWAYS_FATAL_IF(createFactory == nullptr,
719 "createFactory is null in %s", libPath.c_str());
Chong Zhangf5c7ca82019-04-23 17:06:21 -0700720
721 destroyFactory =
722 (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
Dongwon Kang673236b2019-05-08 09:02:21 -0700723 LOG_ALWAYS_FATAL_IF(destroyFactory == nullptr,
724 "destroyFactory is null in %s", libPath.c_str());
Chong Zhangf5c7ca82019-04-23 17:06:21 -0700725
726 mComponentFactory = createFactory();
727 if (mComponentFactory == nullptr) {
728 ALOGD("could not create factory in %s", libPath.c_str());
729 mInit = C2_NO_MEMORY;
Dongwon Kang673236b2019-05-08 09:02:21 -0700730 } else {
731 mInit = C2_OK;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800732 }
733
Dongwon Kang673236b2019-05-08 09:02:21 -0700734 if (mInit != C2_OK) {
735 return mInit;
736 }
Dongwon Kange55d13c2019-04-24 11:01:49 -0700737
Pawin Vongmasa36653902018-11-15 00:10:25 -0800738 std::shared_ptr<C2ComponentInterface> intf;
739 c2_status_t res = createInterface(0, &intf);
740 if (res != C2_OK) {
741 ALOGD("failed to create interface: %d", res);
742 return mInit;
743 }
744
745 std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
746 if (traits) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800747 traits->name = intf->getName();
Lajos Molnar62d62d62019-01-31 16:26:46 -0800748
749 C2ComponentKindSetting kind;
750 C2ComponentDomainSetting domain;
751 res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
752 bool fixDomain = res != C2_OK;
753 if (res == C2_OK) {
754 traits->kind = kind.value;
755 traits->domain = domain.value;
756 } else {
757 // TODO: remove this fall-back
758 ALOGD("failed to query interface for kind and domain: %d", res);
759
760 traits->kind =
761 (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
762 (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
763 C2Component::KIND_OTHER;
764 }
765
766 uint32_t mediaTypeIndex =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800767 traits->kind == C2Component::KIND_ENCODER ? C2PortMediaTypeSetting::output::PARAM_TYPE
768 : C2PortMediaTypeSetting::input::PARAM_TYPE;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800769 std::vector<std::unique_ptr<C2Param>> params;
770 res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
771 if (res != C2_OK) {
772 ALOGD("failed to query interface: %d", res);
773 return mInit;
774 }
775 if (params.size() != 1u) {
776 ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
777 return mInit;
778 }
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800779 C2PortMediaTypeSetting *mediaTypeConfig = C2PortMediaTypeSetting::From(params[0].get());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800780 if (mediaTypeConfig == nullptr) {
781 ALOGD("failed to query media type");
782 return mInit;
783 }
Lajos Molnar62d62d62019-01-31 16:26:46 -0800784 traits->mediaType =
785 std::string(mediaTypeConfig->m.value,
786 strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800787
Lajos Molnar62d62d62019-01-31 16:26:46 -0800788 if (fixDomain) {
789 if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
790 traits->domain = C2Component::DOMAIN_AUDIO;
791 } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
792 traits->domain = C2Component::DOMAIN_VIDEO;
793 } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
794 traits->domain = C2Component::DOMAIN_IMAGE;
795 } else {
796 traits->domain = C2Component::DOMAIN_OTHER;
797 }
798 }
799
800 // TODO: get this properly from the store during emplace
801 switch (traits->domain) {
802 case C2Component::DOMAIN_AUDIO:
803 traits->rank = 8;
804 break;
805 default:
806 traits->rank = 512;
807 }
808
809 params.clear();
810 res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, &params);
811 if (res == C2_OK && params.size() == 1u) {
812 C2ComponentAliasesSetting *aliasesSetting =
813 C2ComponentAliasesSetting::From(params[0].get());
814 if (aliasesSetting) {
815 // Split aliases on ','
816 // This looks simpler in plain C and even std::string would still make a copy.
817 char *aliases = ::strndup(aliasesSetting->m.value, aliasesSetting->flexCount());
818 ALOGD("'%s' has aliases: '%s'", intf->getName().c_str(), aliases);
819
820 for (char *tok, *ptr, *str = aliases; (tok = ::strtok_r(str, ",", &ptr));
821 str = nullptr) {
822 traits->aliases.push_back(tok);
823 ALOGD("adding alias: '%s'", tok);
824 }
825 free(aliases);
826 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800827 }
828 }
829 mTraits = traits;
830
831 return mInit;
832}
833
834C2PlatformComponentStore::ComponentModule::~ComponentModule() {
835 ALOGV("in %s", __func__);
836 if (destroyFactory && mComponentFactory) {
837 destroyFactory(mComponentFactory);
838 }
839 if (mLibHandle) {
840 ALOGV("unloading dll");
841 dlclose(mLibHandle);
842 }
843}
844
845c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
846 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
847 std::function<void(::C2ComponentInterface*)> deleter) {
848 interface->reset();
849 if (mInit != C2_OK) {
850 return mInit;
851 }
852 std::shared_ptr<ComponentModule> module = shared_from_this();
853 c2_status_t res = mComponentFactory->createInterface(
854 id, interface, [module, deleter](C2ComponentInterface *p) mutable {
855 // capture module so that we ensure we still have it while deleting interface
856 deleter(p); // delete interface first
857 module.reset(); // remove module ref (not technically needed)
858 });
859 return res;
860}
861
862c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
863 c2_node_id_t id, std::shared_ptr<C2Component> *component,
864 std::function<void(::C2Component*)> deleter) {
865 component->reset();
866 if (mInit != C2_OK) {
867 return mInit;
868 }
869 std::shared_ptr<ComponentModule> module = shared_from_this();
870 c2_status_t res = mComponentFactory->createComponent(
871 id, component, [module, deleter](C2Component *p) mutable {
872 // capture module so that we ensure we still have it while deleting component
873 deleter(p); // delete component first
874 module.reset(); // remove module ref (not technically needed)
875 });
876 return res;
877}
878
879std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
880 std::unique_lock<std::recursive_mutex> lock(mLock);
881 return mTraits;
882}
883
884C2PlatformComponentStore::C2PlatformComponentStore()
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800885 : mVisited(false),
886 mReflector(std::make_shared<C2ReflectorHelper>()),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800887 mInterface(mReflector) {
888
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800889 auto emplace = [this](const char *libPath) {
890 mComponents.emplace(libPath, libPath);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800891 };
Pawin Vongmasa36653902018-11-15 00:10:25 -0800892
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800893 // TODO: move this also into a .so so it can be updated
894 emplace("libcodec2_soft_aacdec.so");
895 emplace("libcodec2_soft_aacenc.so");
896 emplace("libcodec2_soft_amrnbdec.so");
897 emplace("libcodec2_soft_amrnbenc.so");
898 emplace("libcodec2_soft_amrwbdec.so");
899 emplace("libcodec2_soft_amrwbenc.so");
Ray Essickc2cc4372019-08-21 14:02:28 -0700900 //emplace("libcodec2_soft_av1dec_aom.so"); // deprecated for the gav1 implementation
901 emplace("libcodec2_soft_av1dec_gav1.so");
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800902 emplace("libcodec2_soft_avcdec.so");
903 emplace("libcodec2_soft_avcenc.so");
904 emplace("libcodec2_soft_flacdec.so");
905 emplace("libcodec2_soft_flacenc.so");
906 emplace("libcodec2_soft_g711alawdec.so");
907 emplace("libcodec2_soft_g711mlawdec.so");
908 emplace("libcodec2_soft_gsmdec.so");
909 emplace("libcodec2_soft_h263dec.so");
910 emplace("libcodec2_soft_h263enc.so");
911 emplace("libcodec2_soft_hevcdec.so");
Roma Kauldfe650a2018-08-02 17:48:51 +0530912 emplace("libcodec2_soft_hevcenc.so");
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800913 emplace("libcodec2_soft_mp3dec.so");
914 emplace("libcodec2_soft_mpeg2dec.so");
915 emplace("libcodec2_soft_mpeg4dec.so");
916 emplace("libcodec2_soft_mpeg4enc.so");
917 emplace("libcodec2_soft_opusdec.so");
918 emplace("libcodec2_soft_opusenc.so");
919 emplace("libcodec2_soft_rawdec.so");
920 emplace("libcodec2_soft_vorbisdec.so");
921 emplace("libcodec2_soft_vp8dec.so");
922 emplace("libcodec2_soft_vp8enc.so");
923 emplace("libcodec2_soft_vp9dec.so");
924 emplace("libcodec2_soft_vp9enc.so");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800925}
926
927c2_status_t C2PlatformComponentStore::copyBuffer(
928 std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
929 (void)src;
930 (void)dst;
931 return C2_OMITTED;
932}
933
934c2_status_t C2PlatformComponentStore::query_sm(
935 const std::vector<C2Param*> &stackParams,
936 const std::vector<C2Param::Index> &heapParamIndices,
937 std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
938 return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
939}
940
941c2_status_t C2PlatformComponentStore::config_sm(
942 const std::vector<C2Param*> &params,
943 std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
944 return mInterface.config(params, C2_MAY_BLOCK, failures);
945}
946
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800947void C2PlatformComponentStore::visitComponents() {
948 std::lock_guard<std::mutex> lock(mMutex);
949 if (mVisited) {
950 return;
951 }
952 for (auto &pathAndLoader : mComponents) {
953 const C2String &path = pathAndLoader.first;
954 ComponentLoader &loader = pathAndLoader.second;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800955 std::shared_ptr<ComponentModule> module;
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800956 if (loader.fetchModule(&module) == C2_OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800957 std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
958 if (traits) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800959 mComponentList.push_back(traits);
960 mComponentNameToPath.emplace(traits->name, path);
961 for (const C2String &alias : traits->aliases) {
962 mComponentNameToPath.emplace(alias, path);
963 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800964 }
965 }
966 }
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800967 mVisited = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800968}
969
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800970std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
971 // This method SHALL return within 500ms.
972 visitComponents();
973 return mComponentList;
974}
975
976c2_status_t C2PlatformComponentStore::findComponent(
977 C2String name, std::shared_ptr<ComponentModule> *module) {
978 (*module).reset();
979 visitComponents();
980
981 auto pos = mComponentNameToPath.find(name);
982 if (pos != mComponentNameToPath.end()) {
983 return mComponents.at(pos->second).fetchModule(module);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800984 }
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800985 return C2_NOT_FOUND;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800986}
987
988c2_status_t C2PlatformComponentStore::createComponent(
989 C2String name, std::shared_ptr<C2Component> *const component) {
990 // This method SHALL return within 100ms.
991 component->reset();
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800992 std::shared_ptr<ComponentModule> module;
993 c2_status_t res = findComponent(name, &module);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800994 if (res == C2_OK) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800995 // TODO: get a unique node ID
996 res = module->createComponent(0, component);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800997 }
998 return res;
999}
1000
1001c2_status_t C2PlatformComponentStore::createInterface(
1002 C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
1003 // This method SHALL return within 100ms.
1004 interface->reset();
Lajos Molnarc9b4ca02019-01-31 16:24:45 -08001005 std::shared_ptr<ComponentModule> module;
1006 c2_status_t res = findComponent(name, &module);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001007 if (res == C2_OK) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -08001008 // TODO: get a unique node ID
1009 res = module->createInterface(0, interface);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001010 }
1011 return res;
1012}
1013
1014c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
1015 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
1016 return mInterface.querySupportedParams(params);
1017}
1018
1019c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
1020 std::vector<C2FieldSupportedValuesQuery> &fields) const {
1021 return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
1022}
1023
1024C2String C2PlatformComponentStore::getName() const {
1025 return "android.componentStore.platform";
1026}
1027
1028std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
1029 return mReflector;
1030}
1031
1032std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
1033 static std::mutex mutex;
1034 static std::weak_ptr<C2ComponentStore> platformStore;
1035 std::lock_guard<std::mutex> lock(mutex);
1036 std::shared_ptr<C2ComponentStore> store = platformStore.lock();
1037 if (store == nullptr) {
1038 store = std::make_shared<C2PlatformComponentStore>();
1039 platformStore = store;
1040 }
1041 return store;
1042}
1043
1044} // namespace android