1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "Codec2-Component@1.1"
19 #include <android-base/logging.h>
20
21 #include <codec2/hidl/1.1/Component.h>
22 #include <codec2/hidl/1.1/ComponentStore.h>
23 #include <codec2/hidl/1.1/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_1 {
44 namespace utils {
45
46 using namespace ::android;
47
48 // ComponentListener wrapper
49 struct Component::Listener : public C2Component::Listener {
50
Listenerandroid::hardware::media::c2::V1_1::utils::Component::Listener51 Listener(const sp<Component>& component) :
52 mComponent(component),
53 mListener(component->mListener) {
54 }
55
onError_nbandroid::hardware::media::c2::V1_1::utils::Component::Listener56 virtual void onError_nb(
57 std::weak_ptr<C2Component> /* c2component */,
58 uint32_t errorCode) override {
59 sp<IComponentListener> listener = mListener.promote();
60 if (listener) {
61 Return<void> transStatus = listener->onError(Status::OK, errorCode);
62 if (!transStatus.isOk()) {
63 LOG(ERROR) << "Component::Listener::onError_nb -- "
64 << "transaction failed.";
65 }
66 }
67 }
68
onTripped_nbandroid::hardware::media::c2::V1_1::utils::Component::Listener69 virtual void onTripped_nb(
70 std::weak_ptr<C2Component> /* c2component */,
71 std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
72 ) override {
73 sp<IComponentListener> listener = mListener.promote();
74 if (listener) {
75 hidl_vec<SettingResult> settingResults(c2settingResult.size());
76 size_t ix = 0;
77 for (const std::shared_ptr<C2SettingResult> &c2result :
78 c2settingResult) {
79 if (c2result) {
80 if (!objcpy(&settingResults[ix++], *c2result)) {
81 break;
82 }
83 }
84 }
85 settingResults.resize(ix);
86 Return<void> transStatus = listener->onTripped(settingResults);
87 if (!transStatus.isOk()) {
88 LOG(ERROR) << "Component::Listener::onTripped_nb -- "
89 << "transaction failed.";
90 }
91 }
92 }
93
onWorkDone_nbandroid::hardware::media::c2::V1_1::utils::Component::Listener94 virtual void onWorkDone_nb(
95 std::weak_ptr<C2Component> /* c2component */,
96 std::list<std::unique_ptr<C2Work>> c2workItems) override {
97 for (const std::unique_ptr<C2Work>& work : c2workItems) {
98 if (work) {
99 if (work->worklets.empty()
100 || !work->worklets.back()
101 || (work->worklets.back()->output.flags &
102 C2FrameData::FLAG_INCOMPLETE) == 0) {
103 InputBufferManager::
104 unregisterFrameData(mListener, work->input);
105 }
106 }
107 }
108
109 sp<IComponentListener> listener = mListener.promote();
110 if (listener) {
111 WorkBundle workBundle;
112
113 sp<Component> strongComponent = mComponent.promote();
114 beginTransferBufferQueueBlocks(c2workItems, true);
115 if (!objcpy(&workBundle, c2workItems, strongComponent ?
116 &strongComponent->mBufferPoolSender : nullptr)) {
117 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
118 << "received corrupted work items.";
119 endTransferBufferQueueBlocks(c2workItems, false, true);
120 return;
121 }
122 Return<void> transStatus = listener->onWorkDone(workBundle);
123 if (!transStatus.isOk()) {
124 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
125 << "transaction failed.";
126 endTransferBufferQueueBlocks(c2workItems, false, true);
127 return;
128 }
129 endTransferBufferQueueBlocks(c2workItems, true, true);
130 }
131 }
132
133 protected:
134 wp<Component> mComponent;
135 wp<IComponentListener> mListener;
136 };
137
138 // Component::Sink
139 struct Component::Sink : public IInputSink {
140 std::shared_ptr<Component> mComponent;
141 sp<IConfigurable> mConfigurable;
142
queueandroid::hardware::media::c2::V1_1::utils::Component::Sink143 virtual Return<Status> queue(const WorkBundle& workBundle) override {
144 return mComponent->queue(workBundle);
145 }
146
getConfigurableandroid::hardware::media::c2::V1_1::utils::Component::Sink147 virtual Return<sp<IConfigurable>> getConfigurable() override {
148 return mConfigurable;
149 }
150
151 Sink(const std::shared_ptr<Component>& component);
152 virtual ~Sink() override;
153
154 // Process-wide map: Component::Sink -> C2Component.
155 static std::mutex sSink2ComponentMutex;
156 static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
157
158 static std::shared_ptr<C2Component> findLocalComponent(
159 const sp<IInputSink>& sink);
160 };
161
162 std::mutex
163 Component::Sink::sSink2ComponentMutex{};
164 std::map<IInputSink*, std::weak_ptr<C2Component>>
165 Component::Sink::sSink2Component{};
166
Sink(const std::shared_ptr<Component> & component)167 Component::Sink::Sink(const std::shared_ptr<Component>& component)
168 : mComponent{component},
__anon94bf997f0102() 169 mConfigurable{[&component]() -> sp<IConfigurable> {
170 Return<sp<IComponentInterface>> ret1 = component->getInterface();
171 if (!ret1.isOk()) {
172 LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
173 return nullptr;
174 }
175 Return<sp<IConfigurable>> ret2 =
176 static_cast<sp<IComponentInterface>>(ret1)->
177 getConfigurable();
178 if (!ret2.isOk()) {
179 LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
180 return nullptr;
181 }
182 return static_cast<sp<IConfigurable>>(ret2);
183 }()} {
184 std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
185 sSink2Component.emplace(this, component->mComponent);
186 }
187
~Sink()188 Component::Sink::~Sink() {
189 std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
190 sSink2Component.erase(this);
191 }
192
findLocalComponent(const sp<IInputSink> & sink)193 std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
194 const sp<IInputSink>& sink) {
195 std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
196 auto i = sSink2Component.find(sink.get());
197 if (i == sSink2Component.end()) {
198 return nullptr;
199 }
200 return i->second.lock();
201 }
202
203 // 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)204 Component::Component(
205 const std::shared_ptr<C2Component>& component,
206 const sp<IComponentListener>& listener,
207 const sp<ComponentStore>& store,
208 const sp<::android::hardware::media::bufferpool::V2_0::
209 IClientManager>& clientPoolManager)
210 : mComponent{component},
211 mInterface{new ComponentInterface(component->intf(),
212 store->getParameterCache())},
213 mListener{listener},
214 mStore{store},
215 mBufferPoolSender{clientPoolManager} {
216 // Retrieve supported parameters from store
217 // TODO: We could cache this per component/interface type
218 mInit = mInterface->status();
219 }
220
status() const221 c2_status_t Component::status() const {
222 return mInit;
223 }
224
onDeathReceived()225 void Component::onDeathReceived() {
226 {
227 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
228 mClientDied = true;
229 for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
230 if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
231 std::shared_ptr<C2BufferQueueBlockPool> bqPool =
232 std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
233 bqPool->invalidate();
234 }
235 }
236 }
237 release();
238 }
239
240 // Methods from ::android::hardware::media::c2::V1_1::IComponent
queue(const WorkBundle & workBundle)241 Return<Status> Component::queue(const WorkBundle& workBundle) {
242 std::list<std::unique_ptr<C2Work>> c2works;
243
244 if (!objcpy(&c2works, workBundle)) {
245 return Status::CORRUPTED;
246 }
247
248 // Register input buffers.
249 for (const std::unique_ptr<C2Work>& work : c2works) {
250 if (work) {
251 InputBufferManager::
252 registerFrameData(mListener, work->input);
253 }
254 }
255
256 return static_cast<Status>(mComponent->queue_nb(&c2works));
257 }
258
flush(flush_cb _hidl_cb)259 Return<void> Component::flush(flush_cb _hidl_cb) {
260 std::list<std::unique_ptr<C2Work>> c2flushedWorks;
261 c2_status_t c2res = mComponent->flush_sm(
262 C2Component::FLUSH_COMPONENT,
263 &c2flushedWorks);
264
265 // Unregister input buffers.
266 for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
267 if (work) {
268 if (work->worklets.empty()
269 || !work->worklets.back()
270 || (work->worklets.back()->output.flags &
271 C2FrameData::FLAG_INCOMPLETE) == 0) {
272 InputBufferManager::
273 unregisterFrameData(mListener, work->input);
274 }
275 }
276 }
277
278 WorkBundle flushedWorkBundle;
279 Status res = static_cast<Status>(c2res);
280 beginTransferBufferQueueBlocks(c2flushedWorks, true);
281 if (c2res == C2_OK) {
282 if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
283 res = Status::CORRUPTED;
284 }
285 }
286 _hidl_cb(res, flushedWorkBundle);
287 endTransferBufferQueueBlocks(c2flushedWorks, true, true);
288 return Void();
289 }
290
drain(bool withEos)291 Return<Status> Component::drain(bool withEos) {
292 return static_cast<Status>(mComponent->drain_nb(withEos ?
293 C2Component::DRAIN_COMPONENT_WITH_EOS :
294 C2Component::DRAIN_COMPONENT_NO_EOS));
295 }
296
setOutputSurface(uint64_t blockPoolId,const sp<HGraphicBufferProducer2> & surface)297 Return<Status> Component::setOutputSurface(
298 uint64_t blockPoolId,
299 const sp<HGraphicBufferProducer2>& surface) {
300 std::shared_ptr<C2BlockPool> pool;
301 GetCodec2BlockPool(blockPoolId, mComponent, &pool);
302 if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
303 std::shared_ptr<C2BufferQueueBlockPool> bqPool =
304 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
305 C2BufferQueueBlockPool::OnRenderCallback cb =
306 [this](uint64_t producer, int32_t slot, int64_t nsecs) {
307 // TODO: batch this
308 hidl_vec<IComponentListener::RenderedFrame> rendered;
309 rendered.resize(1);
310 rendered[0] = { producer, slot, nsecs };
311 (void)mListener->onFramesRendered(rendered).isOk();
312 };
313 if (bqPool) {
314 bqPool->setRenderCallback(cb);
315 bqPool->configureProducer(surface);
316 }
317 }
318 return Status::OK;
319 }
320
connectToInputSurface(const sp<IInputSurface> & inputSurface,connectToInputSurface_cb _hidl_cb)321 Return<void> Component::connectToInputSurface(
322 const sp<IInputSurface>& inputSurface,
323 connectToInputSurface_cb _hidl_cb) {
324 Status status;
325 sp<IInputSurfaceConnection> connection;
326 auto transStatus = inputSurface->connect(
327 asInputSink(),
328 [&status, &connection](
329 Status s, const sp<IInputSurfaceConnection>& c) {
330 status = s;
331 connection = c;
332 }
333 );
334 _hidl_cb(status, connection);
335 return Void();
336 }
337
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource> & source,connectToOmxInputSurface_cb _hidl_cb)338 Return<void> Component::connectToOmxInputSurface(
339 const sp<HGraphicBufferProducer1>& producer,
340 const sp<::android::hardware::media::omx::V1_0::
341 IGraphicBufferSource>& source,
342 connectToOmxInputSurface_cb _hidl_cb) {
343 (void)producer;
344 (void)source;
345 (void)_hidl_cb;
346 return Void();
347 }
348
disconnectFromInputSurface()349 Return<Status> Component::disconnectFromInputSurface() {
350 // TODO implement
351 return Status::OK;
352 }
353
354 namespace /* unnamed */ {
355
356 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfandroid::hardware::media::c2::V1_1::utils::__anon94bf997f0411::BlockPoolIntf357 BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
358 : ConfigurableC2Intf{
359 "C2BlockPool:" +
360 (pool ? std::to_string(pool->getLocalId()) : "null"),
361 0},
362 mPool{pool} {
363 }
364
configandroid::hardware::media::c2::V1_1::utils::__anon94bf997f0411::BlockPoolIntf365 virtual c2_status_t config(
366 const std::vector<C2Param*>& params,
367 c2_blocking_t mayBlock,
368 std::vector<std::unique_ptr<C2SettingResult>>* const failures
369 ) override {
370 (void)params;
371 (void)mayBlock;
372 (void)failures;
373 return C2_OK;
374 }
375
queryandroid::hardware::media::c2::V1_1::utils::__anon94bf997f0411::BlockPoolIntf376 virtual c2_status_t query(
377 const std::vector<C2Param::Index>& indices,
378 c2_blocking_t mayBlock,
379 std::vector<std::unique_ptr<C2Param>>* const params
380 ) const override {
381 (void)indices;
382 (void)mayBlock;
383 (void)params;
384 return C2_OK;
385 }
386
querySupportedParamsandroid::hardware::media::c2::V1_1::utils::__anon94bf997f0411::BlockPoolIntf387 virtual c2_status_t querySupportedParams(
388 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
389 ) const override {
390 (void)params;
391 return C2_OK;
392 }
393
querySupportedValuesandroid::hardware::media::c2::V1_1::utils::__anon94bf997f0411::BlockPoolIntf394 virtual c2_status_t querySupportedValues(
395 std::vector<C2FieldSupportedValuesQuery>& fields,
396 c2_blocking_t mayBlock) const override {
397 (void)fields;
398 (void)mayBlock;
399 return C2_OK;
400 }
401
402 protected:
403 std::shared_ptr<C2BlockPool> mPool;
404 };
405
406 } // unnamed namespace
407
createBlockPool(uint32_t allocatorId,createBlockPool_cb _hidl_cb)408 Return<void> Component::createBlockPool(
409 uint32_t allocatorId,
410 createBlockPool_cb _hidl_cb) {
411 std::shared_ptr<C2BlockPool> blockPool;
412 #ifdef __ANDROID_APEX__
413 c2_status_t status = CreateCodec2BlockPool(
414 static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
415 mComponent,
416 &blockPool);
417 #else
418 c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool(
419 static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
420 mComponent,
421 &blockPool);
422 #endif
423 if (status != C2_OK) {
424 blockPool = nullptr;
425 }
426 if (blockPool) {
427 bool emplaced = false;
428 {
429 mBlockPoolsMutex.lock();
430 if (!mClientDied) {
431 mBlockPools.emplace(blockPool->getLocalId(), blockPool);
432 emplaced = true;
433 }
434 mBlockPoolsMutex.unlock();
435 }
436 if (!emplaced) {
437 blockPool.reset();
438 status = C2_BAD_STATE;
439 }
440 } else if (status == C2_OK) {
441 status = C2_CORRUPTED;
442 }
443
444 _hidl_cb(static_cast<Status>(status),
445 blockPool ? blockPool->getLocalId() : 0,
446 new CachedConfigurable(
447 std::make_unique<BlockPoolIntf>(blockPool)));
448 return Void();
449 }
450
destroyBlockPool(uint64_t blockPoolId)451 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
452 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
453 return mBlockPools.erase(blockPoolId) == 1 ?
454 Status::OK : Status::CORRUPTED;
455 }
456
start()457 Return<Status> Component::start() {
458 return static_cast<Status>(mComponent->start());
459 }
460
stop()461 Return<Status> Component::stop() {
462 InputBufferManager::unregisterFrameData(mListener);
463 return static_cast<Status>(mComponent->stop());
464 }
465
reset()466 Return<Status> Component::reset() {
467 Status status = static_cast<Status>(mComponent->reset());
468 {
469 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
470 mBlockPools.clear();
471 }
472 InputBufferManager::unregisterFrameData(mListener);
473 return status;
474 }
475
release()476 Return<Status> Component::release() {
477 Status status = static_cast<Status>(mComponent->release());
478 {
479 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
480 mBlockPools.clear();
481 }
482 InputBufferManager::unregisterFrameData(mListener);
483 return status;
484 }
485
getInterface()486 Return<sp<IComponentInterface>> Component::getInterface() {
487 return sp<IComponentInterface>(mInterface);
488 }
489
asInputSink()490 Return<sp<IInputSink>> Component::asInputSink() {
491 std::lock_guard<std::mutex> lock(mSinkMutex);
492 if (!mSink) {
493 mSink = new Sink(shared_from_this());
494 }
495 return {mSink};
496 }
497
configureVideoTunnel(uint32_t avSyncHwId,configureVideoTunnel_cb _hidl_cb)498 Return<void> Component::configureVideoTunnel(
499 uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
500 (void)avSyncHwId;
501 _hidl_cb(Status::OMITTED, hidl_handle{});
502 return Void();
503 }
504
findLocalComponent(const sp<IInputSink> & sink)505 std::shared_ptr<C2Component> Component::findLocalComponent(
506 const sp<IInputSink>& sink) {
507 return Component::Sink::findLocalComponent(sink);
508 }
509
initListener(const sp<Component> & self)510 void Component::initListener(const sp<Component>& self) {
511 std::shared_ptr<C2Component::Listener> c2listener =
512 std::make_shared<Listener>(self);
513 c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
514 if (res != C2_OK) {
515 mInit = res;
516 }
517
518 struct ListenerDeathRecipient : public HwDeathRecipient {
519 ListenerDeathRecipient(const wp<Component>& comp)
520 : component{comp} {
521 }
522
523 virtual void serviceDied(
524 uint64_t /* cookie */,
525 const wp<::android::hidl::base::V1_0::IBase>& /* who */
526 ) override {
527 auto strongComponent = component.promote();
528 if (strongComponent) {
529 LOG(INFO) << "Client died ! notify and release the component !!";
530 strongComponent->onDeathReceived();
531 } else {
532 LOG(ERROR) << "Client died ! no component to release !!";
533 }
534 }
535
536 wp<Component> component;
537 };
538
539 mDeathRecipient = new ListenerDeathRecipient(self);
540 Return<bool> transStatus = mListener->linkToDeath(
541 mDeathRecipient, 0);
542 if (!transStatus.isOk()) {
543 LOG(ERROR) << "Listener linkToDeath() transaction failed.";
544 }
545 if (!static_cast<bool>(transStatus)) {
546 LOG(DEBUG) << "Listener linkToDeath() call failed.";
547 }
548 }
549
~Component()550 Component::~Component() {
551 InputBufferManager::unregisterFrameData(mListener);
552 mStore->reportComponentDeath(this);
553 }
554
555 } // namespace utils
556 } // namespace V1_1
557 } // namespace c2
558 } // namespace media
559 } // namespace hardware
560 } // namespace android
561