• 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/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 
48 // ComponentListener wrapper
49 struct Component::Listener : public C2Component::Listener {
50 
Listenerandroid::hardware::media::c2::V1_2::utils::Component::Listener51     Listener(const sp<Component>& component) :
52         mComponent(component),
53         mListener(component->mListener) {
54     }
55 
onError_nbandroid::hardware::media::c2::V1_2::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_2::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_2::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_2::utils::Component::Sink143     virtual Return<Status> queue(const WorkBundle& workBundle) override {
144         return mComponent->queue(workBundle);
145     }
146 
getConfigurableandroid::hardware::media::c2::V1_2::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},
__anon7bdb10a30102() 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 
225 // Methods from ::android::hardware::media::c2::V1_1::IComponent
queue(const WorkBundle & workBundle)226 Return<Status> Component::queue(const WorkBundle& workBundle) {
227     std::list<std::unique_ptr<C2Work>> c2works;
228 
229     if (!objcpy(&c2works, workBundle)) {
230         return Status::CORRUPTED;
231     }
232 
233     // Register input buffers.
234     for (const std::unique_ptr<C2Work>& work : c2works) {
235         if (work) {
236             InputBufferManager::
237                     registerFrameData(mListener, work->input);
238         }
239     }
240 
241     return static_cast<Status>(mComponent->queue_nb(&c2works));
242 }
243 
flush(flush_cb _hidl_cb)244 Return<void> Component::flush(flush_cb _hidl_cb) {
245     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
246     c2_status_t c2res = mComponent->flush_sm(
247             C2Component::FLUSH_COMPONENT,
248             &c2flushedWorks);
249 
250     // Unregister input buffers.
251     for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
252         if (work) {
253             if (work->worklets.empty()
254                     || !work->worklets.back()
255                     || (work->worklets.back()->output.flags &
256                         C2FrameData::FLAG_INCOMPLETE) == 0) {
257                 InputBufferManager::
258                         unregisterFrameData(mListener, work->input);
259             }
260         }
261     }
262 
263     WorkBundle flushedWorkBundle;
264     Status res = static_cast<Status>(c2res);
265     beginTransferBufferQueueBlocks(c2flushedWorks, true);
266     if (c2res == C2_OK) {
267         if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
268             res = Status::CORRUPTED;
269         }
270     }
271     _hidl_cb(res, flushedWorkBundle);
272     endTransferBufferQueueBlocks(c2flushedWorks, true, true);
273     return Void();
274 }
275 
drain(bool withEos)276 Return<Status> Component::drain(bool withEos) {
277     return static_cast<Status>(mComponent->drain_nb(withEos ?
278             C2Component::DRAIN_COMPONENT_WITH_EOS :
279             C2Component::DRAIN_COMPONENT_NO_EOS));
280 }
281 
setOutputSurface(uint64_t blockPoolId,const sp<HGraphicBufferProducer2> & surface)282 Return<Status> Component::setOutputSurface(
283         uint64_t blockPoolId,
284         const sp<HGraphicBufferProducer2>& surface) {
285     std::shared_ptr<C2BlockPool> pool;
286     GetCodec2BlockPool(blockPoolId, mComponent, &pool);
287     if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
288         std::shared_ptr<C2BufferQueueBlockPool> bqPool =
289                 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
290         C2BufferQueueBlockPool::OnRenderCallback cb =
291             [this](uint64_t producer, int32_t slot, int64_t nsecs) {
292                 // TODO: batch this
293                 hidl_vec<IComponentListener::RenderedFrame> rendered;
294                 rendered.resize(1);
295                 rendered[0] = { producer, slot, nsecs };
296                 (void)mListener->onFramesRendered(rendered).isOk();
297         };
298         if (bqPool) {
299             bqPool->setRenderCallback(cb);
300             bqPool->configureProducer(surface);
301         }
302     }
303     return Status::OK;
304 }
305 
connectToInputSurface(const sp<IInputSurface> & inputSurface,connectToInputSurface_cb _hidl_cb)306 Return<void> Component::connectToInputSurface(
307         const sp<IInputSurface>& inputSurface,
308         connectToInputSurface_cb _hidl_cb) {
309     Status status;
310     sp<IInputSurfaceConnection> connection;
311     auto transStatus = inputSurface->connect(
312             asInputSink(),
313             [&status, &connection](
314                     Status s, const sp<IInputSurfaceConnection>& c) {
315                 status = s;
316                 connection = c;
317             }
318         );
319     _hidl_cb(status, connection);
320     return Void();
321 }
322 
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource> & source,connectToOmxInputSurface_cb _hidl_cb)323 Return<void> Component::connectToOmxInputSurface(
324         const sp<HGraphicBufferProducer1>& producer,
325         const sp<::android::hardware::media::omx::V1_0::
326         IGraphicBufferSource>& source,
327         connectToOmxInputSurface_cb _hidl_cb) {
328     (void)producer;
329     (void)source;
330     (void)_hidl_cb;
331     return Void();
332 }
333 
disconnectFromInputSurface()334 Return<Status> Component::disconnectFromInputSurface() {
335     // TODO implement
336     return Status::OK;
337 }
338 
339 namespace /* unnamed */ {
340 
341 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfandroid::hardware::media::c2::V1_2::utils::__anon7bdb10a30411::BlockPoolIntf342     BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
343           : ConfigurableC2Intf{
344                 "C2BlockPool:" +
345                     (pool ? std::to_string(pool->getLocalId()) : "null"),
346                 0},
347             mPool{pool} {
348     }
349 
configandroid::hardware::media::c2::V1_2::utils::__anon7bdb10a30411::BlockPoolIntf350     virtual c2_status_t config(
351             const std::vector<C2Param*>& params,
352             c2_blocking_t mayBlock,
353             std::vector<std::unique_ptr<C2SettingResult>>* const failures
354             ) override {
355         (void)params;
356         (void)mayBlock;
357         (void)failures;
358         return C2_OK;
359     }
360 
queryandroid::hardware::media::c2::V1_2::utils::__anon7bdb10a30411::BlockPoolIntf361     virtual c2_status_t query(
362             const std::vector<C2Param::Index>& indices,
363             c2_blocking_t mayBlock,
364             std::vector<std::unique_ptr<C2Param>>* const params
365             ) const override {
366         (void)indices;
367         (void)mayBlock;
368         (void)params;
369         return C2_OK;
370     }
371 
querySupportedParamsandroid::hardware::media::c2::V1_2::utils::__anon7bdb10a30411::BlockPoolIntf372     virtual c2_status_t querySupportedParams(
373             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
374             ) const override {
375         (void)params;
376         return C2_OK;
377     }
378 
querySupportedValuesandroid::hardware::media::c2::V1_2::utils::__anon7bdb10a30411::BlockPoolIntf379     virtual c2_status_t querySupportedValues(
380             std::vector<C2FieldSupportedValuesQuery>& fields,
381             c2_blocking_t mayBlock) const override {
382         (void)fields;
383         (void)mayBlock;
384         return C2_OK;
385     }
386 
387 protected:
388     std::shared_ptr<C2BlockPool> mPool;
389 };
390 
391 } // unnamed namespace
392 
createBlockPool(uint32_t allocatorId,createBlockPool_cb _hidl_cb)393 Return<void> Component::createBlockPool(
394         uint32_t allocatorId,
395         createBlockPool_cb _hidl_cb) {
396     std::shared_ptr<C2BlockPool> blockPool;
397 #ifdef __ANDROID_APEX__
398     c2_status_t status = CreateCodec2BlockPool(
399             static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
400             mComponent,
401             &blockPool);
402 #else
403     c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool(
404             static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
405             mComponent,
406             &blockPool);
407 #endif
408     if (status != C2_OK) {
409         blockPool = nullptr;
410     }
411     if (blockPool) {
412         mBlockPoolsMutex.lock();
413         mBlockPools.emplace(blockPool->getLocalId(), blockPool);
414         mBlockPoolsMutex.unlock();
415     } else if (status == C2_OK) {
416         status = C2_CORRUPTED;
417     }
418 
419     _hidl_cb(static_cast<Status>(status),
420             blockPool ? blockPool->getLocalId() : 0,
421             new CachedConfigurable(
422             std::make_unique<BlockPoolIntf>(blockPool)));
423     return Void();
424 }
425 
destroyBlockPool(uint64_t blockPoolId)426 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
427     std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
428     return mBlockPools.erase(blockPoolId) == 1 ?
429             Status::OK : Status::CORRUPTED;
430 }
431 
start()432 Return<Status> Component::start() {
433     return static_cast<Status>(mComponent->start());
434 }
435 
stop()436 Return<Status> Component::stop() {
437     InputBufferManager::unregisterFrameData(mListener);
438     return static_cast<Status>(mComponent->stop());
439 }
440 
reset()441 Return<Status> Component::reset() {
442     Status status = static_cast<Status>(mComponent->reset());
443     {
444         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
445         mBlockPools.clear();
446     }
447     InputBufferManager::unregisterFrameData(mListener);
448     return status;
449 }
450 
release()451 Return<Status> Component::release() {
452     Status status = static_cast<Status>(mComponent->release());
453     {
454         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
455         mBlockPools.clear();
456     }
457     InputBufferManager::unregisterFrameData(mListener);
458     return status;
459 }
460 
getInterface()461 Return<sp<IComponentInterface>> Component::getInterface() {
462     return sp<IComponentInterface>(mInterface);
463 }
464 
asInputSink()465 Return<sp<IInputSink>> Component::asInputSink() {
466     std::lock_guard<std::mutex> lock(mSinkMutex);
467     if (!mSink) {
468         mSink = new Sink(shared_from_this());
469     }
470     return {mSink};
471 }
472 
configureVideoTunnel(uint32_t avSyncHwId,configureVideoTunnel_cb _hidl_cb)473 Return<void> Component::configureVideoTunnel(
474         uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
475     (void)avSyncHwId;
476     _hidl_cb(Status::OMITTED, hidl_handle{});
477     return Void();
478 }
479 
setOutputSurfaceWithSyncObj(uint64_t blockPoolId,const sp<HGraphicBufferProducer2> & surface,const SurfaceSyncObj & syncObject)480 Return<Status> Component::setOutputSurfaceWithSyncObj(
481         uint64_t blockPoolId, const sp<HGraphicBufferProducer2>& surface,
482         const SurfaceSyncObj& syncObject) {
483     std::shared_ptr<C2BlockPool> pool;
484     GetCodec2BlockPool(blockPoolId, mComponent, &pool);
485     if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
486         std::shared_ptr<C2BufferQueueBlockPool> bqPool =
487                 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
488         C2BufferQueueBlockPool::OnRenderCallback cb =
489             [this](uint64_t producer, int32_t slot, int64_t nsecs) {
490                 // TODO: batch this
491                 hidl_vec<IComponentListener::RenderedFrame> rendered;
492                 rendered.resize(1);
493                 rendered[0] = { producer, slot, nsecs };
494                 (void)mListener->onFramesRendered(rendered).isOk();
495         };
496         if (bqPool) {
497             const native_handle_t *h = syncObject.syncMemory;
498             native_handle_t *syncMemory = h ? native_handle_clone(h) : nullptr;
499             uint64_t bqId = syncObject.bqId;
500             uint32_t generationId = syncObject.generationId;
501             uint64_t consumerUsage = syncObject.consumerUsage;
502 
503             bqPool->setRenderCallback(cb);
504             bqPool->configureProducer(surface, syncMemory, bqId,
505                                       generationId, consumerUsage);
506         }
507     }
508     return Status::OK;
509 }
510 
findLocalComponent(const sp<IInputSink> & sink)511 std::shared_ptr<C2Component> Component::findLocalComponent(
512         const sp<IInputSink>& sink) {
513     return Component::Sink::findLocalComponent(sink);
514 }
515 
initListener(const sp<Component> & self)516 void Component::initListener(const sp<Component>& self) {
517     std::shared_ptr<C2Component::Listener> c2listener =
518             std::make_shared<Listener>(self);
519     c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
520     if (res != C2_OK) {
521         mInit = res;
522     }
523 
524     struct ListenerDeathRecipient : public HwDeathRecipient {
525         ListenerDeathRecipient(const wp<Component>& comp)
526             : component{comp} {
527         }
528 
529         virtual void serviceDied(
530                 uint64_t /* cookie */,
531                 const wp<::android::hidl::base::V1_0::IBase>& /* who */
532                 ) override {
533             auto strongComponent = component.promote();
534             if (strongComponent) {
535                 LOG(INFO) << "Client died ! release the component !!";
536                 strongComponent->release();
537             } else {
538                 LOG(ERROR) << "Client died ! no component to release !!";
539             }
540         }
541 
542         wp<Component> component;
543     };
544 
545     mDeathRecipient = new ListenerDeathRecipient(self);
546     Return<bool> transStatus = mListener->linkToDeath(
547             mDeathRecipient, 0);
548     if (!transStatus.isOk()) {
549         LOG(ERROR) << "Listener linkToDeath() transaction failed.";
550     }
551     if (!static_cast<bool>(transStatus)) {
552         LOG(DEBUG) << "Listener linkToDeath() call failed.";
553     }
554 }
555 
~Component()556 Component::~Component() {
557     InputBufferManager::unregisterFrameData(mListener);
558     mStore->reportComponentDeath(this);
559 }
560 
561 } // namespace utils
562 } // namespace V1_2
563 } // namespace c2
564 } // namespace media
565 } // namespace hardware
566 } // namespace android
567