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