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