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