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