1 /*
2 * Copyright 2019 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_NDEBUG 0
18 #define LOG_TAG "Codec2-Component@1.1"
19 #include <android-base/logging.h>
20
21 #include <codec2/common/BqPoolInvalidateHelper.h>
22 #include <codec2/hidl/1.1/Component.h>
23 #include <codec2/hidl/1.1/ComponentStore.h>
24 #include <codec2/hidl/1.1/InputBufferManager.h>
25
26 #ifndef __ANDROID_APEX__
27 #include <FilterWrapper.h>
28 #endif
29
30 #include <hidl/HidlBinderSupport.h>
31 #include <utils/Timers.h>
32
33 #include <codec2/common/MultiAccessUnitHelper.h>
34
35 #include <C2BqBufferPriv.h>
36 #include <C2BqPoolInvalidator.h>
37 #include <C2Debug.h>
38 #include <C2PlatformSupport.h>
39
40 #include <chrono>
41 #include <thread>
42
43 namespace android {
44 namespace hardware {
45 namespace media {
46 namespace c2 {
47 namespace V1_1 {
48 namespace utils {
49
50 using namespace ::android;
51 using ::android::MultiAccessUnitInterface;
52 using ::android::MultiAccessUnitHelper;
53
54 // ComponentListener wrapper
55 struct Component::Listener : public C2Component::Listener {
56
Listenerandroid::hardware::media::c2::V1_1::utils::Component::Listener57 Listener(const sp<Component>& component) :
58 mComponent(component),
59 mListener(component->mListener) {
60 }
61
onError_nbandroid::hardware::media::c2::V1_1::utils::Component::Listener62 virtual void onError_nb(
63 std::weak_ptr<C2Component> /* c2component */,
64 uint32_t errorCode) override {
65 sp<IComponentListener> listener = mListener.promote();
66 if (listener) {
67 Return<void> transStatus = listener->onError(Status::OK, errorCode);
68 if (!transStatus.isOk()) {
69 LOG(ERROR) << "Component::Listener::onError_nb -- "
70 << "transaction failed.";
71 }
72 }
73 }
74
onTripped_nbandroid::hardware::media::c2::V1_1::utils::Component::Listener75 virtual void onTripped_nb(
76 std::weak_ptr<C2Component> /* c2component */,
77 std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
78 ) override {
79 sp<IComponentListener> listener = mListener.promote();
80 if (listener) {
81 hidl_vec<SettingResult> settingResults(c2settingResult.size());
82 size_t ix = 0;
83 for (const std::shared_ptr<C2SettingResult> &c2result :
84 c2settingResult) {
85 if (c2result) {
86 if (!objcpy(&settingResults[ix++], *c2result)) {
87 break;
88 }
89 }
90 }
91 settingResults.resize(ix);
92 Return<void> transStatus = listener->onTripped(settingResults);
93 if (!transStatus.isOk()) {
94 LOG(ERROR) << "Component::Listener::onTripped_nb -- "
95 << "transaction failed.";
96 }
97 }
98 }
99
onWorkDone_nbandroid::hardware::media::c2::V1_1::utils::Component::Listener100 virtual void onWorkDone_nb(
101 std::weak_ptr<C2Component> /* c2component */,
102 std::list<std::unique_ptr<C2Work>> c2workItems) override {
103 for (const std::unique_ptr<C2Work>& work : c2workItems) {
104 if (work) {
105 if (work->worklets.empty()
106 || !work->worklets.back()
107 || (work->worklets.back()->output.flags &
108 C2FrameData::FLAG_INCOMPLETE) == 0) {
109 InputBufferManager::
110 unregisterFrameData(mListener, work->input);
111 }
112 }
113 }
114
115 sp<IComponentListener> listener = mListener.promote();
116 if (listener) {
117 WorkBundle workBundle;
118
119 sp<Component> strongComponent = mComponent.promote();
120 beginTransferBufferQueueBlocks(c2workItems, true);
121 if (!objcpy(&workBundle, c2workItems, strongComponent ?
122 &strongComponent->mBufferPoolSender : nullptr)) {
123 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
124 << "received corrupted work items.";
125 endTransferBufferQueueBlocks(c2workItems, false, true);
126 return;
127 }
128 Return<void> transStatus = listener->onWorkDone(workBundle);
129 if (!transStatus.isOk()) {
130 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
131 << "transaction failed.";
132 endTransferBufferQueueBlocks(c2workItems, false, true);
133 return;
134 }
135 endTransferBufferQueueBlocks(c2workItems, true, true);
136 }
137 }
138
139 protected:
140 wp<Component> mComponent;
141 wp<IComponentListener> mListener;
142 };
143
144 // Component listener for handle multiple access-units
145 struct MultiAccessUnitListener : public Component::Listener {
MultiAccessUnitListenerandroid::hardware::media::c2::V1_1::utils::MultiAccessUnitListener146 MultiAccessUnitListener(const sp<Component> &component,
147 const std::shared_ptr<MultiAccessUnitHelper> &helper):
148 Listener(component), mHelper(helper) {
149 }
150
onError_nbandroid::hardware::media::c2::V1_1::utils::MultiAccessUnitListener151 virtual void onError_nb(
152 std::weak_ptr<C2Component> c2component,
153 uint32_t errorCode) override {
154 if (mHelper) {
155 std::list<std::unique_ptr<C2Work>> worklist;
156 mHelper->error(&worklist);
157 if (!worklist.empty()) {
158 Listener::onWorkDone_nb(c2component, std::move(worklist));
159 }
160 }
161 Listener::onError_nb(c2component, errorCode);
162 }
163
onTripped_nbandroid::hardware::media::c2::V1_1::utils::MultiAccessUnitListener164 virtual void onTripped_nb(
165 std::weak_ptr<C2Component> c2component,
166 std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
167 ) override {
168 Listener::onTripped_nb(c2component,
169 c2settingResult);
170 }
171
onWorkDone_nbandroid::hardware::media::c2::V1_1::utils::MultiAccessUnitListener172 virtual void onWorkDone_nb(
173 std::weak_ptr<C2Component> c2component,
174 std::list<std::unique_ptr<C2Work>> c2workItems) override {
175 if (mHelper) {
176 std::list<std::unique_ptr<C2Work>> processedWork;
177 mHelper->gather(c2workItems, &processedWork);
178 if (!processedWork.empty()) {
179 Listener::onWorkDone_nb(c2component, std::move(processedWork));
180 }
181 } else {
182 Listener::onWorkDone_nb(c2component, std::move(c2workItems));
183 }
184 }
185
186 protected:
187 std::shared_ptr<MultiAccessUnitHelper> mHelper;
188 };
189
190 // Component::Sink
191 struct Component::Sink : public IInputSink {
192 std::shared_ptr<Component> mComponent;
193 sp<IConfigurable> mConfigurable;
194
queueandroid::hardware::media::c2::V1_1::utils::Component::Sink195 virtual Return<Status> queue(const WorkBundle& workBundle) override {
196 return mComponent->queue(workBundle);
197 }
198
getConfigurableandroid::hardware::media::c2::V1_1::utils::Component::Sink199 virtual Return<sp<IConfigurable>> getConfigurable() override {
200 return mConfigurable;
201 }
202
203 Sink(const std::shared_ptr<Component>& component);
204 virtual ~Sink() override;
205
206 // Process-wide map: Component::Sink -> C2Component.
207 static std::mutex sSink2ComponentMutex;
208 static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
209
210 static std::shared_ptr<C2Component> findLocalComponent(
211 const sp<IInputSink>& sink);
212 };
213
214 std::mutex
215 Component::Sink::sSink2ComponentMutex{};
216 std::map<IInputSink*, std::weak_ptr<C2Component>>
217 Component::Sink::sSink2Component{};
218
Sink(const std::shared_ptr<Component> & component)219 Component::Sink::Sink(const std::shared_ptr<Component>& component)
220 : mComponent{component},
__anon896242100102() 221 mConfigurable{[&component]() -> sp<IConfigurable> {
222 Return<sp<IComponentInterface>> ret1 = component->getInterface();
223 if (!ret1.isOk()) {
224 LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
225 return nullptr;
226 }
227 Return<sp<IConfigurable>> ret2 =
228 static_cast<sp<IComponentInterface>>(ret1)->
229 getConfigurable();
230 if (!ret2.isOk()) {
231 LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
232 return nullptr;
233 }
234 return static_cast<sp<IConfigurable>>(ret2);
235 }()} {
236 std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
237 sSink2Component.emplace(this, component->mComponent);
238 }
239
~Sink()240 Component::Sink::~Sink() {
241 std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
242 sSink2Component.erase(this);
243 }
244
findLocalComponent(const sp<IInputSink> & sink)245 std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
246 const sp<IInputSink>& sink) {
247 std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
248 auto i = sSink2Component.find(sink.get());
249 if (i == sSink2Component.end()) {
250 return nullptr;
251 }
252 return i->second.lock();
253 }
254
255 // Component
Component(const std::shared_ptr<C2Component> & component,const sp<IComponentListener> & listener,const sp<ComponentStore> & store,const sp<::android::hardware::media::bufferpool::V2_0::IClientManager> & clientPoolManager)256 Component::Component(
257 const std::shared_ptr<C2Component>& component,
258 const sp<IComponentListener>& listener,
259 const sp<ComponentStore>& store,
260 const sp<::android::hardware::media::bufferpool::V2_0::
261 IClientManager>& clientPoolManager)
262 : mComponent{component},
263 mListener{listener},
264 mStore{store},
265 mBufferPoolSender{clientPoolManager} {
266 // Retrieve supported parameters from store
267 // TODO: We could cache this per component/interface type
268 mMultiAccessUnitIntf = store->tryCreateMultiAccessUnitInterface(component->intf());
269 mInterface = new ComponentInterface(
270 component->intf(), mMultiAccessUnitIntf, store->getParameterCache());
271 mInit = mInterface->status();
272 }
273
status() const274 c2_status_t Component::status() const {
275 return mInit;
276 }
277
onDeathReceived()278 void Component::onDeathReceived() {
279 std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
280 {
281 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
282 mClientDied = true;
283 transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
284 BqPoolFilterFn, BqPoolConvertFn);
285 }
286 if (!bqPools.empty()) {
287 std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
288 std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
289 bqInvalidateItem->invalidate();
290 }
291 release();
292 }
293
294 // Methods from ::android::hardware::media::c2::V1_1::IComponent
queue(const WorkBundle & workBundle)295 Return<Status> Component::queue(const WorkBundle& workBundle) {
296 std::list<std::unique_ptr<C2Work>> c2works;
297
298 if (!objcpy(&c2works, workBundle)) {
299 return Status::CORRUPTED;
300 }
301
302 // Register input buffers.
303 for (const std::unique_ptr<C2Work>& work : c2works) {
304 if (work) {
305 InputBufferManager::
306 registerFrameData(mListener, work->input);
307 }
308 }
309 c2_status_t err = C2_OK;
310 if (mMultiAccessUnitHelper) {
311 std::list<std::list<std::unique_ptr<C2Work>>> c2worklists;
312 mMultiAccessUnitHelper->scatter(c2works, &c2worklists);
313 for (auto &c2worklist : c2worklists) {
314 err = mComponent->queue_nb(&c2worklist);
315 if (err != C2_OK) {
316 LOG(ERROR) << "Error Queuing to component.";
317 break;
318 }
319 }
320 return static_cast<Status>(err);
321 }
322
323 return static_cast<Status>(mComponent->queue_nb(&c2works));
324 }
325
flush(flush_cb _hidl_cb)326 Return<void> Component::flush(flush_cb _hidl_cb) {
327 std::list<std::unique_ptr<C2Work>> c2flushedWorks;
328 c2_status_t c2res = mComponent->flush_sm(
329 C2Component::FLUSH_COMPONENT,
330 &c2flushedWorks);
331 if (mMultiAccessUnitHelper) {
332 c2res = mMultiAccessUnitHelper->flush(&c2flushedWorks);
333 }
334
335 // Unregister input buffers.
336 for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
337 if (work) {
338 if (work->worklets.empty()
339 || !work->worklets.back()
340 || (work->worklets.back()->output.flags &
341 C2FrameData::FLAG_INCOMPLETE) == 0) {
342 InputBufferManager::
343 unregisterFrameData(mListener, work->input);
344 }
345 }
346 }
347
348 WorkBundle flushedWorkBundle;
349 Status res = static_cast<Status>(c2res);
350 beginTransferBufferQueueBlocks(c2flushedWorks, true);
351 if (c2res == C2_OK) {
352 if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
353 res = Status::CORRUPTED;
354 }
355 }
356 _hidl_cb(res, flushedWorkBundle);
357 endTransferBufferQueueBlocks(c2flushedWorks, true, true);
358 return Void();
359 }
360
drain(bool withEos)361 Return<Status> Component::drain(bool withEos) {
362 return static_cast<Status>(mComponent->drain_nb(withEos ?
363 C2Component::DRAIN_COMPONENT_WITH_EOS :
364 C2Component::DRAIN_COMPONENT_NO_EOS));
365 }
366
setOutputSurface(uint64_t blockPoolId,const sp<HGraphicBufferProducer2> & surface)367 Return<Status> Component::setOutputSurface(
368 uint64_t blockPoolId,
369 const sp<HGraphicBufferProducer2>& surface) {
370 std::shared_ptr<C2BlockPool> pool;
371 GetCodec2BlockPool(blockPoolId, mComponent, &pool);
372 if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
373 std::shared_ptr<C2BufferQueueBlockPool> bqPool =
374 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
375 C2BufferQueueBlockPool::OnRenderCallback cb =
376 [this](uint64_t producer, int32_t slot, int64_t nsecs) {
377 // TODO: batch this
378 hidl_vec<IComponentListener::RenderedFrame> rendered;
379 rendered.resize(1);
380 rendered[0] = { producer, slot, nsecs };
381 (void)mListener->onFramesRendered(rendered).isOk();
382 };
383 if (bqPool) {
384 bqPool->setRenderCallback(cb);
385 bqPool->configureProducer(surface);
386 }
387 }
388 return Status::OK;
389 }
390
connectToInputSurface(const sp<IInputSurface> & inputSurface,connectToInputSurface_cb _hidl_cb)391 Return<void> Component::connectToInputSurface(
392 const sp<IInputSurface>& inputSurface,
393 connectToInputSurface_cb _hidl_cb) {
394 Status status;
395 sp<IInputSurfaceConnection> connection;
396 auto transStatus = inputSurface->connect(
397 asInputSink(),
398 [&status, &connection](
399 Status s, const sp<IInputSurfaceConnection>& c) {
400 status = s;
401 connection = c;
402 }
403 );
404 _hidl_cb(status, connection);
405 return Void();
406 }
407
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource> & source,connectToOmxInputSurface_cb _hidl_cb)408 Return<void> Component::connectToOmxInputSurface(
409 const sp<HGraphicBufferProducer1>& producer,
410 const sp<::android::hardware::media::omx::V1_0::
411 IGraphicBufferSource>& source,
412 connectToOmxInputSurface_cb _hidl_cb) {
413 (void)producer;
414 (void)source;
415 (void)_hidl_cb;
416 return Void();
417 }
418
disconnectFromInputSurface()419 Return<Status> Component::disconnectFromInputSurface() {
420 // TODO implement
421 return Status::OK;
422 }
423
424 namespace /* unnamed */ {
425
426 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfandroid::hardware::media::c2::V1_1::utils::__anon896242100411::BlockPoolIntf427 BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
428 : ConfigurableC2Intf{
429 "C2BlockPool:" +
430 (pool ? std::to_string(pool->getLocalId()) : "null"),
431 0},
432 mPool{pool} {
433 }
434
configandroid::hardware::media::c2::V1_1::utils::__anon896242100411::BlockPoolIntf435 virtual c2_status_t config(
436 const std::vector<C2Param*>& params,
437 c2_blocking_t mayBlock,
438 std::vector<std::unique_ptr<C2SettingResult>>* const failures
439 ) override {
440 (void)params;
441 (void)mayBlock;
442 (void)failures;
443 return C2_OK;
444 }
445
queryandroid::hardware::media::c2::V1_1::utils::__anon896242100411::BlockPoolIntf446 virtual c2_status_t query(
447 const std::vector<C2Param::Index>& indices,
448 c2_blocking_t mayBlock,
449 std::vector<std::unique_ptr<C2Param>>* const params
450 ) const override {
451 (void)indices;
452 (void)mayBlock;
453 (void)params;
454 return C2_OK;
455 }
456
querySupportedParamsandroid::hardware::media::c2::V1_1::utils::__anon896242100411::BlockPoolIntf457 virtual c2_status_t querySupportedParams(
458 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
459 ) const override {
460 (void)params;
461 return C2_OK;
462 }
463
querySupportedValuesandroid::hardware::media::c2::V1_1::utils::__anon896242100411::BlockPoolIntf464 virtual c2_status_t querySupportedValues(
465 std::vector<C2FieldSupportedValuesQuery>& fields,
466 c2_blocking_t mayBlock) const override {
467 (void)fields;
468 (void)mayBlock;
469 return C2_OK;
470 }
471
472 protected:
473 std::shared_ptr<C2BlockPool> mPool;
474 };
475
476 } // unnamed namespace
477
createBlockPool(uint32_t allocatorId,createBlockPool_cb _hidl_cb)478 Return<void> Component::createBlockPool(
479 uint32_t allocatorId,
480 createBlockPool_cb _hidl_cb) {
481 std::shared_ptr<C2BlockPool> blockPool;
482 #ifdef __ANDROID_APEX__
483 c2_status_t status = CreateCodec2BlockPool(
484 static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
485 mComponent,
486 &blockPool);
487 #else
488 c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool(
489 static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
490 mComponent,
491 &blockPool);
492 #endif
493 if (status != C2_OK) {
494 blockPool = nullptr;
495 }
496 if (blockPool) {
497 bool emplaced = false;
498 {
499 mBlockPoolsMutex.lock();
500 if (!mClientDied) {
501 mBlockPools.emplace(blockPool->getLocalId(), blockPool);
502 emplaced = true;
503 }
504 mBlockPoolsMutex.unlock();
505 }
506 if (!emplaced) {
507 blockPool.reset();
508 status = C2_BAD_STATE;
509 }
510 } else if (status == C2_OK) {
511 status = C2_CORRUPTED;
512 }
513
514 _hidl_cb(static_cast<Status>(status),
515 blockPool ? blockPool->getLocalId() : 0,
516 new CachedConfigurable(
517 std::make_unique<BlockPoolIntf>(blockPool)));
518 return Void();
519 }
520
destroyBlockPool(uint64_t blockPoolId)521 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
522 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
523 return mBlockPools.erase(blockPoolId) == 1 ?
524 Status::OK : Status::CORRUPTED;
525 }
526
start()527 Return<Status> Component::start() {
528 return static_cast<Status>(mComponent->start());
529 }
530
stop()531 Return<Status> Component::stop() {
532 InputBufferManager::unregisterFrameData(mListener);
533 Status status = static_cast<Status>(mComponent->stop());
534 {
535 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
536 for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
537 if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
538 std::shared_ptr<C2BufferQueueBlockPool> bqPool =
539 std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
540 bqPool->clearDeferredBlocks();
541 }
542 }
543 }
544 return status;
545 }
546
reset()547 Return<Status> Component::reset() {
548 Status status = static_cast<Status>(mComponent->reset());
549 {
550 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
551 mBlockPools.clear();
552 }
553 if (mMultiAccessUnitHelper) {
554 mMultiAccessUnitHelper->reset();
555 }
556 InputBufferManager::unregisterFrameData(mListener);
557 return status;
558 }
559
release()560 Return<Status> Component::release() {
561 std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
562 {
563 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
564 if (!mClientDied) {
565 transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
566 BqPoolFilterFn, BqPoolConvertFn);
567 }
568 }
569 std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem;
570 if (!bqPools.empty()) {
571 // handling rare cases of process death just after release() called.
572 bqInvalidateItem = std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
573 C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
574 }
575 Status status = static_cast<Status>(mComponent->release());
576 if (bqInvalidateItem) {
577 // If release is not blocked,
578 // skip invalidation and finish ASAP.
579 bqInvalidateItem->skip();
580 }
581 {
582 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
583 mBlockPools.clear();
584 }
585 if (mMultiAccessUnitHelper) {
586 mMultiAccessUnitHelper->reset();
587 }
588 InputBufferManager::unregisterFrameData(mListener);
589 return status;
590 }
591
getInterface()592 Return<sp<IComponentInterface>> Component::getInterface() {
593 return sp<IComponentInterface>(mInterface);
594 }
595
asInputSink()596 Return<sp<IInputSink>> Component::asInputSink() {
597 std::lock_guard<std::mutex> lock(mSinkMutex);
598 if (!mSink) {
599 mSink = new Sink(shared_from_this());
600 }
601 return {mSink};
602 }
603
configureVideoTunnel(uint32_t avSyncHwId,configureVideoTunnel_cb _hidl_cb)604 Return<void> Component::configureVideoTunnel(
605 uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
606 (void)avSyncHwId;
607 _hidl_cb(Status::OMITTED, hidl_handle{});
608 return Void();
609 }
610
findLocalComponent(const sp<IInputSink> & sink)611 std::shared_ptr<C2Component> Component::findLocalComponent(
612 const sp<IInputSink>& sink) {
613 return Component::Sink::findLocalComponent(sink);
614 }
615
initListener(const sp<Component> & self)616 void Component::initListener(const sp<Component>& self) {
617 std::shared_ptr<C2Component::Listener> c2listener;
618 if (mMultiAccessUnitIntf) {
619 std::shared_ptr<C2Allocator> allocator;
620 std::shared_ptr<C2BlockPool> linearPool;
621 std::shared_ptr<C2AllocatorStore> store = ::android::GetCodec2PlatformAllocatorStore();
622 if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator) == C2_OK) {
623 ::android::C2PlatformAllocatorDesc desc;
624 desc.allocatorId = allocator->getId();
625 if (C2_OK == CreateCodec2BlockPool(desc, mComponent, &linearPool)) {
626 if (linearPool) {
627 mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(
628 mMultiAccessUnitIntf, linearPool);
629 }
630 }
631 }
632 }
633 c2listener = mMultiAccessUnitHelper ?
634 std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
635 std::make_shared<Listener>(self);
636 c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
637 if (res != C2_OK) {
638 mInit = res;
639 }
640
641 struct ListenerDeathRecipient : public HwDeathRecipient {
642 ListenerDeathRecipient(const wp<Component>& comp)
643 : component{comp} {
644 }
645
646 virtual void serviceDied(
647 uint64_t /* cookie */,
648 const wp<::android::hidl::base::V1_0::IBase>& /* who */
649 ) override {
650 auto strongComponent = component.promote();
651 if (strongComponent) {
652 LOG(INFO) << "Client died ! notify and release the component !!";
653 strongComponent->onDeathReceived();
654 } else {
655 LOG(ERROR) << "Client died ! no component to release !!";
656 }
657 }
658
659 wp<Component> component;
660 };
661
662 mDeathRecipient = new ListenerDeathRecipient(self);
663 Return<bool> transStatus = mListener->linkToDeath(
664 mDeathRecipient, 0);
665 if (!transStatus.isOk()) {
666 LOG(ERROR) << "Listener linkToDeath() transaction failed.";
667 }
668 if (!static_cast<bool>(transStatus)) {
669 LOG(DEBUG) << "Listener linkToDeath() call failed.";
670 }
671 }
672
~Component()673 Component::~Component() {
674 std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
675 {
676 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
677 transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
678 BqPoolFilterFn, BqPoolConvertFn);
679 }
680 if (!bqPools.empty()) {
681 LOG(ERROR) << "blockpools are not cleared yet at dtor";
682 std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
683 std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
684 C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
685 }
686 InputBufferManager::unregisterFrameData(mListener);
687 mStore->reportComponentDeath(this);
688 }
689
690 } // namespace utils
691 } // namespace V1_1
692 } // namespace c2
693 } // namespace media
694 } // namespace hardware
695 } // namespace android
696