• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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"
19 #include <android-base/logging.h>
20 
21 #include <C2PlatformSupport.h>
22 #include <codec2/hidl/1.0/Component.h>
23 #include <codec2/hidl/1.0/ComponentStore.h>
24 #include <codec2/hidl/1.0/types.h>
25 
26 #include <hidl/HidlBinderSupport.h>
27 #include <utils/Timers.h>
28 
29 #include <C2BqBufferPriv.h>
30 #include <C2Debug.h>
31 #include <C2PlatformSupport.h>
32 
33 #include <chrono>
34 #include <thread>
35 
36 namespace hardware {
37 namespace google {
38 namespace media {
39 namespace c2 {
40 namespace V1_0 {
41 namespace utils {
42 
43 using namespace ::android;
44 
45 namespace /* unnamed */ {
46 
47 // Implementation of ConfigurableC2Intf based on C2ComponentInterface
48 struct CompIntf : public ConfigurableC2Intf {
CompIntfhardware::google::media::c2::V1_0::utils::__anon914485c80111::CompIntf49     CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
50         ConfigurableC2Intf(intf->getName()),
51         mIntf(intf) {
52     }
53 
confighardware::google::media::c2::V1_0::utils::__anon914485c80111::CompIntf54     virtual c2_status_t config(
55             const std::vector<C2Param*>& params,
56             c2_blocking_t mayBlock,
57             std::vector<std::unique_ptr<C2SettingResult>>* const failures
58             ) override {
59         ALOGV("config");
60         return mIntf->config_vb(params, mayBlock, failures);
61     }
62 
queryhardware::google::media::c2::V1_0::utils::__anon914485c80111::CompIntf63     virtual c2_status_t query(
64             const std::vector<C2Param::Index>& indices,
65             c2_blocking_t mayBlock,
66             std::vector<std::unique_ptr<C2Param>>* const params
67             ) const override {
68         ALOGV("query");
69         return mIntf->query_vb({}, indices, mayBlock, params);
70     }
71 
querySupportedParamshardware::google::media::c2::V1_0::utils::__anon914485c80111::CompIntf72     virtual c2_status_t querySupportedParams(
73             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
74             ) const override {
75         ALOGV("querySupportedParams");
76         return mIntf->querySupportedParams_nb(params);
77     }
78 
querySupportedValueshardware::google::media::c2::V1_0::utils::__anon914485c80111::CompIntf79     virtual c2_status_t querySupportedValues(
80             std::vector<C2FieldSupportedValuesQuery>& fields,
81             c2_blocking_t mayBlock) const override {
82         ALOGV("querySupportedValues");
83         return mIntf->querySupportedValues_vb(fields, mayBlock);
84     }
85 
86 protected:
87     std::shared_ptr<C2ComponentInterface> mIntf;
88 };
89 
90 } // unnamed namespace
91 
92 // InputBufferManager
93 // ==================
94 //
95 // InputBufferManager presents a way to track and untrack input buffers in this
96 // (codec) process and send a notification to a listener, possibly in a
97 // different process, when a tracked buffer no longer has any references in this
98 // process. (In fact, this class would work for listeners in the same process
99 // too, but the optimization discussed below will not be beneficial.)
100 //
101 // InputBufferManager holds a collection of records representing tracked buffers
102 // and their callback listeners. Conceptually, one record is a triple (listener,
103 // frameIndex, bufferIndex) where
104 //
105 // - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
106 // - listener is of type IComponentListener. Its onFramesRendered() function
107 //   will be called after the associated buffer dies. The argument of
108 //   onFramesRendered() is a list of RenderedFrame objects, each of which has
109 //   the following members:
110 //
111 //     uint64_t bufferQueueId
112 //     int32_t  slotId
113 //     int64_t  timestampNs
114 //
115 // When a tracked buffer associated to the triple (listener, frameIndex,
116 // bufferIndex) goes out of scope, listener->onFramesRendered() will be called
117 // with a RenderedFrame object whose members are set as follows:
118 //
119 //     bufferQueueId = frameIndex
120 //     slotId        = ~bufferIndex
121 //     timestampNs   = systemTime() at the time of notification
122 //
123 // The reason for the bitwise negation of bufferIndex is that onFramesRendered()
124 // may be used for a different purpose when slotId is non-negative (which is a
125 // more general use case).
126 //
127 // IPC Optimization
128 // ----------------
129 //
130 // Since onFramesRendered() generally is an IPC call, InputBufferManager tries
131 // not to call it too often. There is a mechanism to guarantee that any two
132 // calls to the same listener are at least kNotificationPeriodNs nanoseconds
133 // apart.
134 //
135 struct InputBufferManager {
136     // The minimum time period between IPC calls to notify the client about the
137     // destruction of input buffers.
138     static constexpr nsecs_t kNotificationPeriodNs = 1000000;
139 
140     // Track all buffers in a C2FrameData object.
141     //
142     // input (C2FrameData) has the following two members that are of interest:
143     //
144     //   C2WorkOrdinal                ordinal
145     //   vector<shared_ptr<C2Buffer>> buffers
146     //
147     // Calling registerFrameData(listener, input) will register multiple
148     // triples (, frameIndex, bufferIndex) where frameIndex is equal to
149     // input.ordinal.frameIndex and bufferIndex runs through the indices of
150     // input.buffers such that input.buffers[bufferIndex] is not null.
151     //
152     // This should be called from queue().
153     static void registerFrameData(
154             const sp<IComponentListener>& listener,
155             const C2FrameData& input);
156 
157     // Untrack all buffers in a C2FrameData object.
158     //
159     // Calling unregisterFrameData(listener, input) will unregister and remove
160     // pending notifications for all triples (l, fi, bufferIndex) such that
161     // l = listener and fi = input.ordinal.frameIndex.
162     //
163     // This should be called from onWorkDone() and flush().
164     static void unregisterFrameData(
165             const wp<IComponentListener>& listener,
166             const C2FrameData& input);
167 
168     // Untrack all buffers associated to a given listener.
169     //
170     // Calling unregisterFrameData(listener) will unregister and remove
171     // pending notifications for all triples (l, frameIndex, bufferIndex) such
172     // that l = listener.
173     //
174     // This should be called when the component cleans up all input buffers,
175     // i.e., when reset(), release(), stop() or ~Component() is called.
176     static void unregisterFrameData(
177             const wp<IComponentListener>& listener);
178 
179 private:
180     void _registerFrameData(
181             const sp<IComponentListener>& listener,
182             const C2FrameData& input);
183     void _unregisterFrameData(
184             const wp<IComponentListener>& listener,
185             const C2FrameData& input);
186     void _unregisterFrameData(
187             const wp<IComponentListener>& listener);
188 
189     // The callback function tied to C2Buffer objects.
190     //
191     // Note: This function assumes that sInstance is the only instance of this
192     //       class.
193     static void onBufferDestroyed(const C2Buffer* buf, void* arg);
194     void _onBufferDestroyed(const C2Buffer* buf, void* arg);
195 
196     // Comparison operator for weak pointers.
197     struct CompareWeakComponentListener {
operator ()hardware::google::media::c2::V1_0::utils::InputBufferManager::CompareWeakComponentListener198         constexpr bool operator()(
199                 const wp<IComponentListener>& x,
200                 const wp<IComponentListener>& y) const {
201             return x.get_refs() < y.get_refs();
202         }
203     };
204 
205     // Persistent data to be passed as "arg" in onBufferDestroyed().
206     // This is essentially the triple (listener, frameIndex, bufferIndex) plus a
207     // weak pointer to the C2Buffer object.
208     //
209     // Note that the "key" is bufferIndex according to operator<(). This is
210     // designed to work with TrackedBuffersMap defined below.
211     struct TrackedBuffer {
212         wp<IComponentListener> listener;
213         uint64_t frameIndex;
214         size_t bufferIndex;
215         std::weak_ptr<C2Buffer> buffer;
TrackedBufferhardware::google::media::c2::V1_0::utils::InputBufferManager::TrackedBuffer216         TrackedBuffer(const wp<IComponentListener>& listener,
217                       uint64_t frameIndex,
218                       size_t bufferIndex,
219                       const std::shared_ptr<C2Buffer>& buffer)
220               : listener(listener),
221                 frameIndex(frameIndex),
222                 bufferIndex(bufferIndex),
223                 buffer(buffer) {}
224         TrackedBuffer(const TrackedBuffer&) = default;
operator <hardware::google::media::c2::V1_0::utils::InputBufferManager::TrackedBuffer225         bool operator<(const TrackedBuffer& other) const {
226             return bufferIndex < other.bufferIndex;
227         }
228     };
229 
230     // Map: listener -> frameIndex -> set<TrackedBuffer>.
231     // Essentially, this is used to store triples (listener, frameIndex,
232     // bufferIndex) that's searchable by listener and (listener, frameIndex).
233     // However, the value of the innermost map is TrackedBuffer, which also
234     // contains an extra copy of listener and frameIndex. This is needed
235     // because onBufferDestroyed() needs to know listener and frameIndex too.
236     typedef std::map<wp<IComponentListener>,
237                      std::map<uint64_t,
238                               std::set<TrackedBuffer>>,
239                      CompareWeakComponentListener> TrackedBuffersMap;
240 
241     // Storage for pending (unsent) death notifications for one listener.
242     // Each pair in member named "indices" are (frameIndex, bufferIndex) from
243     // the (listener, frameIndex, bufferIndex) triple.
244     struct DeathNotifications {
245 
246         // The number of pending notifications for this listener.
247         // count may be 0, in which case the DeathNotifications object will
248         // remain valid for only a small period (kNotificationPeriodNs
249         // nanoseconds).
250         size_t count;
251 
252         // The timestamp of the most recent callback on this listener. This is
253         // used to guarantee that callbacks do not occur too frequently, and
254         // also to trigger expiration of a DeathNotifications object that has
255         // count = 0.
256         nsecs_t lastSentNs;
257 
258         // Map: frameIndex -> vector of bufferIndices
259         // This is essentially a collection of (framdeIndex, bufferIndex).
260         std::map<uint64_t, std::vector<size_t>> indices;
261 
DeathNotificationshardware::google::media::c2::V1_0::utils::InputBufferManager::DeathNotifications262         DeathNotifications()
263               : count(0),
264                 lastSentNs(systemTime() - kNotificationPeriodNs),
265                 indices() {}
266     };
267 
268     // Mutex for the management of all input buffers.
269     std::mutex mMutex;
270 
271     // Tracked input buffers.
272     TrackedBuffersMap mTrackedBuffersMap;
273 
274     // Death notifications to be sent.
275     //
276     // A DeathNotifications object is associated to each listener. An entry in
277     // this map will be removed if its associated DeathNotifications has count =
278     // 0 and lastSentNs < systemTime() - kNotificationPeriodNs.
279     std::map<wp<IComponentListener>, DeathNotifications> mDeathNotifications;
280 
281     // Condition variable signaled when an entry is added to mDeathNotifications.
282     std::condition_variable mOnBufferDestroyed;
283 
284     // Notify the clients about buffer destructions.
285     // Return false if all destructions have been notified.
286     // Return true and set timeToRetry to the duration to wait for before
287     // retrying if some destructions have not been notified.
288     bool processNotifications(nsecs_t* timeToRetryNs);
289 
290     // Main function for the input buffer manager thread.
291     void main();
292 
293     // The thread that manages notifications.
294     //
295     // Note: This variable is declared last so its initialization will happen
296     // after all other member variables have been initialized.
297     std::thread mMainThread;
298 
299     // Private constructor.
300     InputBufferManager();
301 
302     // The only instance of this class.
303     static InputBufferManager& getInstance();
304 
305 };
306 
307 // ComponentInterface
ComponentInterface(const std::shared_ptr<C2ComponentInterface> & intf,const sp<ComponentStore> & store)308 ComponentInterface::ComponentInterface(
309         const std::shared_ptr<C2ComponentInterface>& intf,
310         const sp<ComponentStore>& store) :
311     Configurable(new CachedConfigurable(std::make_unique<CompIntf>(intf))),
312     mInterface(intf) {
313     mInit = init(store.get());
314 }
315 
status() const316 c2_status_t ComponentInterface::status() const {
317     return mInit;
318 }
319 
320 // ComponentListener wrapper
321 struct Component::Listener : public C2Component::Listener {
322 
Listenerhardware::google::media::c2::V1_0::utils::Component::Listener323     Listener(const sp<Component>& component) :
324         mComponent(component),
325         mListener(component->mListener) {
326     }
327 
onError_nbhardware::google::media::c2::V1_0::utils::Component::Listener328     virtual void onError_nb(
329             std::weak_ptr<C2Component> /* c2component */,
330             uint32_t errorCode) override {
331         ALOGV("onError");
332         sp<IComponentListener> listener = mListener.promote();
333         if (listener) {
334             Return<void> transStatus = listener->onError(Status::OK, errorCode);
335             if (!transStatus.isOk()) {
336                 ALOGE("onError -- transaction failed.");
337             }
338         }
339     }
340 
onTripped_nbhardware::google::media::c2::V1_0::utils::Component::Listener341     virtual void onTripped_nb(
342             std::weak_ptr<C2Component> /* c2component */,
343             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
344             ) override {
345         ALOGV("onTripped");
346         sp<IComponentListener> listener = mListener.promote();
347         if (listener) {
348             hidl_vec<SettingResult> settingResults(c2settingResult.size());
349             size_t ix = 0;
350             for (const std::shared_ptr<C2SettingResult> &c2result :
351                     c2settingResult) {
352                 if (c2result) {
353                     if (objcpy(&settingResults[ix++], *c2result) !=
354                             Status::OK) {
355                         break;
356                     }
357                 }
358             }
359             settingResults.resize(ix);
360             Return<void> transStatus = listener->onTripped(settingResults);
361             if (!transStatus.isOk()) {
362                 ALOGE("onTripped -- transaction failed.");
363             }
364         }
365     }
366 
onWorkDone_nbhardware::google::media::c2::V1_0::utils::Component::Listener367     virtual void onWorkDone_nb(
368             std::weak_ptr<C2Component> /* c2component */,
369             std::list<std::unique_ptr<C2Work>> c2workItems) override {
370         ALOGV("onWorkDone");
371         for (const std::unique_ptr<C2Work>& work : c2workItems) {
372             if (work) {
373                 if (work->worklets.empty()
374                         || !work->worklets.back()
375                         || (work->worklets.back()->output.flags &
376                             C2FrameData::FLAG_INCOMPLETE) == 0) {
377                     InputBufferManager::
378                             unregisterFrameData(mListener, work->input);
379                 }
380             }
381         }
382 
383         sp<IComponentListener> listener = mListener.promote();
384         if (listener) {
385             WorkBundle workBundle;
386 
387             sp<Component> strongComponent = mComponent.promote();
388             if (objcpy(&workBundle, c2workItems, strongComponent ?
389                     &strongComponent->mBufferPoolSender : nullptr)
390                     != Status::OK) {
391                 ALOGE("onWorkDone() received corrupted work items.");
392                 return;
393             }
394             Return<void> transStatus = listener->onWorkDone(workBundle);
395             if (!transStatus.isOk()) {
396                 ALOGE("onWorkDone -- transaction failed.");
397                 return;
398             }
399             yieldBufferQueueBlocks(c2workItems, true);
400         }
401     }
402 
403 protected:
404     wp<Component> mComponent;
405     wp<IComponentListener> mListener;
406 };
407 
408 // Component
Component(const std::shared_ptr<C2Component> & component,const sp<IComponentListener> & listener,const sp<ComponentStore> & store,const sp<::android::hardware::media::bufferpool::V1_0::IClientManager> & clientPoolManager)409 Component::Component(
410         const std::shared_ptr<C2Component>& component,
411         const sp<IComponentListener>& listener,
412         const sp<ComponentStore>& store,
413         const sp<::android::hardware::media::bufferpool::V1_0::
414         IClientManager>& clientPoolManager) :
415     Configurable(new CachedConfigurable(
416             std::make_unique<CompIntf>(component->intf()))),
417     mComponent(component),
418     mInterface(component->intf()),
419     mListener(listener),
420     mStore(store),
421     mBufferPoolSender(clientPoolManager) {
422     // Retrieve supported parameters from store
423     // TODO: We could cache this per component/interface type
424     mInit = init(store.get());
425 }
426 
status() const427 c2_status_t Component::status() const {
428     return mInit;
429 }
430 
431 // Methods from ::android::hardware::media::c2::V1_0::IComponent
queue(const WorkBundle & workBundle)432 Return<Status> Component::queue(const WorkBundle& workBundle) {
433     ALOGV("queue -- converting input");
434     std::list<std::unique_ptr<C2Work>> c2works;
435 
436     if (objcpy(&c2works, workBundle) != C2_OK) {
437         ALOGV("queue -- corrupted");
438         return Status::CORRUPTED;
439     }
440 
441     // Register input buffers.
442     for (const std::unique_ptr<C2Work>& work : c2works) {
443         if (work) {
444             InputBufferManager::
445                     registerFrameData(mListener, work->input);
446         }
447     }
448 
449     ALOGV("queue -- calling");
450     return static_cast<Status>(mComponent->queue_nb(&c2works));
451 }
452 
flush(flush_cb _hidl_cb)453 Return<void> Component::flush(flush_cb _hidl_cb) {
454     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
455     ALOGV("flush -- calling");
456     c2_status_t c2res = mComponent->flush_sm(
457             C2Component::FLUSH_COMPONENT,
458             &c2flushedWorks);
459 
460     // Unregister input buffers.
461     for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
462         if (work) {
463             if (work->worklets.empty()
464                     || !work->worklets.back()
465                     || (work->worklets.back()->output.flags &
466                         C2FrameData::FLAG_INCOMPLETE) == 0) {
467                 InputBufferManager::
468                         unregisterFrameData(mListener, work->input);
469             }
470         }
471     }
472 
473     WorkBundle flushedWorkBundle;
474     Status res = static_cast<Status>(c2res);
475     if (c2res == C2_OK) {
476         ALOGV("flush -- converting output");
477         res = objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender);
478     }
479     _hidl_cb(res, flushedWorkBundle);
480     yieldBufferQueueBlocks(c2flushedWorks, true);
481     return Void();
482 }
483 
drain(bool withEos)484 Return<Status> Component::drain(bool withEos) {
485     ALOGV("drain");
486     return static_cast<Status>(mComponent->drain_nb(withEos ?
487             C2Component::DRAIN_COMPONENT_WITH_EOS :
488             C2Component::DRAIN_COMPONENT_NO_EOS));
489 }
490 
setOutputSurface(uint64_t blockPoolId,const sp<HGraphicBufferProducer> & surface)491 Return<Status> Component::setOutputSurface(
492         uint64_t blockPoolId,
493         const sp<HGraphicBufferProducer>& surface) {
494     std::shared_ptr<C2BlockPool> pool;
495     GetCodec2BlockPool(blockPoolId, mComponent, &pool);
496     if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
497         std::shared_ptr<C2BufferQueueBlockPool> bqPool =
498                 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
499         C2BufferQueueBlockPool::OnRenderCallback cb =
500             [this](uint64_t producer, int32_t slot, int64_t nsecs) {
501                 // TODO: batch this
502                 hidl_vec<IComponentListener::RenderedFrame> rendered;
503                 rendered.resize(1);
504                 rendered[0] = { producer, slot, nsecs };
505                 (void)mListener->onFramesRendered(rendered).isOk();
506         };
507         if (bqPool) {
508             bqPool->setRenderCallback(cb);
509             bqPool->configureProducer(surface);
510         }
511     }
512     return Status::OK;
513 }
514 
connectToOmxInputSurface(const sp<HGraphicBufferProducer> & producer,const sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource> & source)515 Return<Status> Component::connectToOmxInputSurface(
516         const sp<HGraphicBufferProducer>& producer,
517         const sp<::android::hardware::media::omx::V1_0::
518         IGraphicBufferSource>& source) {
519     // TODO implement
520     (void)producer;
521     (void)source;
522     return Status::OMITTED;
523 }
524 
disconnectFromInputSurface()525 Return<Status> Component::disconnectFromInputSurface() {
526     // TODO implement
527     return Status::OK;
528 }
529 
530 namespace /* unnamed */ {
531 
532 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfhardware::google::media::c2::V1_0::utils::__anon914485c80311::BlockPoolIntf533     BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool) :
534         ConfigurableC2Intf("C2BlockPool:" +
535                            (pool ? std::to_string(pool->getLocalId()) :
536                            "null")),
537         mPool(pool) {
538     }
539 
confighardware::google::media::c2::V1_0::utils::__anon914485c80311::BlockPoolIntf540     virtual c2_status_t config(
541             const std::vector<C2Param*>& params,
542             c2_blocking_t mayBlock,
543             std::vector<std::unique_ptr<C2SettingResult>>* const failures
544             ) override {
545         (void)params;
546         (void)mayBlock;
547         (void)failures;
548         return C2_OK;
549     }
550 
queryhardware::google::media::c2::V1_0::utils::__anon914485c80311::BlockPoolIntf551     virtual c2_status_t query(
552             const std::vector<C2Param::Index>& indices,
553             c2_blocking_t mayBlock,
554             std::vector<std::unique_ptr<C2Param>>* const params
555             ) const override {
556         (void)indices;
557         (void)mayBlock;
558         (void)params;
559         return C2_OK;
560     }
561 
querySupportedParamshardware::google::media::c2::V1_0::utils::__anon914485c80311::BlockPoolIntf562     virtual c2_status_t querySupportedParams(
563             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
564             ) const override {
565         (void)params;
566         return C2_OK;
567     }
568 
querySupportedValueshardware::google::media::c2::V1_0::utils::__anon914485c80311::BlockPoolIntf569     virtual c2_status_t querySupportedValues(
570             std::vector<C2FieldSupportedValuesQuery>& fields,
571             c2_blocking_t mayBlock) const override {
572         (void)fields;
573         (void)mayBlock;
574         return C2_OK;
575     }
576 
577 protected:
578     std::shared_ptr<C2BlockPool> mPool;
579 };
580 
581 } // unnamed namespace
582 
createBlockPool(uint32_t allocatorId,createBlockPool_cb _hidl_cb)583 Return<void> Component::createBlockPool(
584         uint32_t allocatorId,
585         createBlockPool_cb _hidl_cb) {
586     std::shared_ptr<C2BlockPool> blockPool;
587     c2_status_t status = CreateCodec2BlockPool(
588             static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
589             mComponent,
590             &blockPool);
591     if (status != C2_OK) {
592         blockPool = nullptr;
593     }
594     if (blockPool) {
595         mBlockPoolsMutex.lock();
596         mBlockPools.emplace(blockPool->getLocalId(), blockPool);
597         mBlockPoolsMutex.unlock();
598     } else if (status == C2_OK) {
599         status = C2_CORRUPTED;
600     }
601 
602     _hidl_cb(static_cast<Status>(status),
603             blockPool ? blockPool->getLocalId() : 0,
604             new CachedConfigurable(
605             std::make_unique<BlockPoolIntf>(blockPool)));
606     return Void();
607 }
608 
destroyBlockPool(uint64_t blockPoolId)609 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
610     std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
611     return mBlockPools.erase(blockPoolId) == 1 ?
612             Status::OK : Status::CORRUPTED;
613 }
614 
start()615 Return<Status> Component::start() {
616     ALOGV("start");
617     return static_cast<Status>(mComponent->start());
618 }
619 
stop()620 Return<Status> Component::stop() {
621     ALOGV("stop");
622     InputBufferManager::unregisterFrameData(mListener);
623     return static_cast<Status>(mComponent->stop());
624 }
625 
reset()626 Return<Status> Component::reset() {
627     ALOGV("reset");
628     Status status = static_cast<Status>(mComponent->reset());
629     {
630         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
631         mBlockPools.clear();
632     }
633     InputBufferManager::unregisterFrameData(mListener);
634     return status;
635 }
636 
release()637 Return<Status> Component::release() {
638     ALOGV("release");
639     Status status = static_cast<Status>(mComponent->release());
640     {
641         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
642         mBlockPools.clear();
643     }
644     InputBufferManager::unregisterFrameData(mListener);
645     return status;
646 }
647 
setLocalId(const Component::LocalId & localId)648 void Component::setLocalId(const Component::LocalId& localId) {
649     mLocalId = localId;
650 }
651 
initListener(const sp<Component> & self)652 void Component::initListener(const sp<Component>& self) {
653     std::shared_ptr<C2Component::Listener> c2listener =
654             std::make_shared<Listener>(self);
655     c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
656     if (res != C2_OK) {
657         mInit = res;
658     }
659 }
660 
~Component()661 Component::~Component() {
662     InputBufferManager::unregisterFrameData(mListener);
663     mStore->reportComponentDeath(mLocalId);
664 }
665 
InterfaceKey(const sp<IComponent> & component)666 Component::InterfaceKey::InterfaceKey(const sp<IComponent>& component) {
667     isRemote = component->isRemote();
668     if (isRemote) {
669         remote = ::android::hardware::toBinder(component);
670     } else {
671         local = component;
672     }
673 }
674 
675 // InputBufferManager implementation
676 
677 constexpr nsecs_t InputBufferManager::kNotificationPeriodNs;
678 
registerFrameData(const sp<IComponentListener> & listener,const C2FrameData & input)679 void InputBufferManager::registerFrameData(
680         const sp<IComponentListener>& listener,
681         const C2FrameData& input) {
682     getInstance()._registerFrameData(listener, input);
683 }
684 
unregisterFrameData(const wp<IComponentListener> & listener,const C2FrameData & input)685 void InputBufferManager::unregisterFrameData(
686         const wp<IComponentListener>& listener,
687         const C2FrameData& input) {
688     getInstance()._unregisterFrameData(listener, input);
689 }
690 
unregisterFrameData(const wp<IComponentListener> & listener)691 void InputBufferManager::unregisterFrameData(
692         const wp<IComponentListener>& listener) {
693     getInstance()._unregisterFrameData(listener);
694 }
695 
_registerFrameData(const sp<IComponentListener> & listener,const C2FrameData & input)696 void InputBufferManager::_registerFrameData(
697         const sp<IComponentListener>& listener,
698         const C2FrameData& input) {
699     uint64_t frameIndex = input.ordinal.frameIndex.peeku();
700     ALOGV("InputBufferManager::_registerFrameData called "
701           "(listener @ %p, frameIndex = %llu)",
702           listener.get(),
703           static_cast<long long unsigned>(frameIndex));
704     std::lock_guard<std::mutex> lock(mMutex);
705 
706     std::set<TrackedBuffer> &bufferIds =
707             mTrackedBuffersMap[listener][frameIndex];
708 
709     for (size_t i = 0; i < input.buffers.size(); ++i) {
710         if (!input.buffers[i]) {
711             ALOGV("InputBufferManager::_registerFrameData: "
712                   "Input buffer at index %zu is null", i);
713             continue;
714         }
715         const TrackedBuffer &bufferId =
716                 *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
717                 first;
718 
719         c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
720                 onBufferDestroyed,
721                 const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
722         if (status != C2_OK) {
723             ALOGD("InputBufferManager: registerOnDestroyNotify failed "
724                   "(listener @ %p, frameIndex = %llu, bufferIndex = %zu) "
725                   "=> %s (%d)",
726                   listener.get(),
727                   static_cast<unsigned long long>(frameIndex),
728                   i,
729                   asString(status), static_cast<int>(status));
730         }
731     }
732 
733     mDeathNotifications.emplace(listener, DeathNotifications());
734 }
735 
736 // Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
737 // mDeathNotifications. This implies all bufferIndices are removed.
738 //
739 // This is called from onWorkDone() and flush().
_unregisterFrameData(const wp<IComponentListener> & listener,const C2FrameData & input)740 void InputBufferManager::_unregisterFrameData(
741         const wp<IComponentListener>& listener,
742         const C2FrameData& input) {
743     uint64_t frameIndex = input.ordinal.frameIndex.peeku();
744     ALOGV("InputBufferManager::_unregisterFrameData called "
745           "(listener @ %p, frameIndex = %llu)",
746           listener.unsafe_get(),
747           static_cast<long long unsigned>(frameIndex));
748     std::lock_guard<std::mutex> lock(mMutex);
749 
750     auto findListener = mTrackedBuffersMap.find(listener);
751     if (findListener != mTrackedBuffersMap.end()) {
752         std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
753                 = findListener->second;
754         auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
755         if (findFrameIndex != frameIndex2BufferIds.end()) {
756             std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
757             for (const TrackedBuffer& bufferId : bufferIds) {
758                 std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
759                 if (buffer) {
760                     c2_status_t status = buffer->unregisterOnDestroyNotify(
761                             onBufferDestroyed,
762                             const_cast<void*>(
763                             reinterpret_cast<const void*>(&bufferId)));
764                     if (status != C2_OK) {
765                         ALOGD("InputBufferManager: "
766                               "unregisterOnDestroyNotify failed "
767                               "(listener @ %p, "
768                               "frameIndex = %llu, "
769                               "bufferIndex = %zu) "
770                               "=> %s (%d)",
771                               bufferId.listener.unsafe_get(),
772                               static_cast<unsigned long long>(
773                                   bufferId.frameIndex),
774                               bufferId.bufferIndex,
775                               asString(status), static_cast<int>(status));
776                     }
777                 }
778             }
779 
780             frameIndex2BufferIds.erase(findFrameIndex);
781             if (frameIndex2BufferIds.empty()) {
782                 mTrackedBuffersMap.erase(findListener);
783             }
784         }
785     }
786 
787     auto findListenerD = mDeathNotifications.find(listener);
788     if (findListenerD != mDeathNotifications.end()) {
789         DeathNotifications &deathNotifications = findListenerD->second;
790         auto findFrameIndex = deathNotifications.indices.find(frameIndex);
791         if (findFrameIndex != deathNotifications.indices.end()) {
792             std::vector<size_t> &bufferIndices = findFrameIndex->second;
793             deathNotifications.count -= bufferIndices.size();
794             deathNotifications.indices.erase(findFrameIndex);
795         }
796     }
797 }
798 
799 // Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
800 // all frameIndices and bufferIndices are removed.
801 //
802 // This is called when the component cleans up all input buffers, i.e., when
803 // reset(), release(), stop() or ~Component() is called.
_unregisterFrameData(const wp<IComponentListener> & listener)804 void InputBufferManager::_unregisterFrameData(
805         const wp<IComponentListener>& listener) {
806     ALOGV("InputBufferManager::_unregisterFrameData called (listener @ %p)",
807             listener.unsafe_get());
808     std::lock_guard<std::mutex> lock(mMutex);
809 
810     auto findListener = mTrackedBuffersMap.find(listener);
811     if (findListener != mTrackedBuffersMap.end()) {
812         std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds =
813                 findListener->second;
814         for (auto findFrameIndex = frameIndex2BufferIds.begin();
815                 findFrameIndex != frameIndex2BufferIds.end();
816                 ++findFrameIndex) {
817             std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
818             for (const TrackedBuffer& bufferId : bufferIds) {
819                 std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
820                 if (buffer) {
821                     c2_status_t status = buffer->unregisterOnDestroyNotify(
822                             onBufferDestroyed,
823                             const_cast<void*>(
824                             reinterpret_cast<const void*>(&bufferId)));
825                     if (status != C2_OK) {
826                         ALOGD("InputBufferManager: "
827                               "unregisterOnDestroyNotify failed "
828                               "(listener @ %p, "
829                               "frameIndex = %llu, "
830                               "bufferIndex = %zu) "
831                               "=> %s (%d)",
832                               bufferId.listener.unsafe_get(),
833                               static_cast<unsigned long long>(bufferId.frameIndex),
834                               bufferId.bufferIndex,
835                               asString(status), static_cast<int>(status));
836                     }
837                 }
838             }
839         }
840         mTrackedBuffersMap.erase(findListener);
841     }
842 
843     mDeathNotifications.erase(listener);
844 }
845 
846 // Move a buffer from mTrackedBuffersMap to mDeathNotifications.
847 // This is called when a registered C2Buffer object is destroyed.
onBufferDestroyed(const C2Buffer * buf,void * arg)848 void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
849     getInstance()._onBufferDestroyed(buf, arg);
850 }
851 
_onBufferDestroyed(const C2Buffer * buf,void * arg)852 void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
853     if (!buf || !arg) {
854         ALOGW("InputBufferManager::_onBufferDestroyed called "
855               "with null argument(s) (buf @ %p, arg @ %p)",
856               buf, arg);
857         return;
858     }
859     TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
860     ALOGV("InputBufferManager::_onBufferDestroyed called "
861           "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
862           id.listener.unsafe_get(),
863           static_cast<unsigned long long>(id.frameIndex),
864           id.bufferIndex);
865 
866     std::lock_guard<std::mutex> lock(mMutex);
867 
868     auto findListener = mTrackedBuffersMap.find(id.listener);
869     if (findListener == mTrackedBuffersMap.end()) {
870         ALOGD("InputBufferManager::_onBufferDestroyed received "
871               "invalid listener "
872               "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
873               id.listener.unsafe_get(),
874               static_cast<unsigned long long>(id.frameIndex),
875               id.bufferIndex);
876         return;
877     }
878 
879     std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
880             = findListener->second;
881     auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
882     if (findFrameIndex == frameIndex2BufferIds.end()) {
883         ALOGD("InputBufferManager::_onBufferDestroyed received "
884               "invalid frame index "
885               "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
886               id.listener.unsafe_get(),
887               static_cast<unsigned long long>(id.frameIndex),
888               id.bufferIndex);
889         return;
890     }
891 
892     std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
893     auto findBufferId = bufferIds.find(id);
894     if (findBufferId == bufferIds.end()) {
895         ALOGD("InputBufferManager::_onBufferDestroyed received "
896               "invalid buffer index: "
897               "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
898               id.listener.unsafe_get(),
899               static_cast<unsigned long long>(id.frameIndex),
900               id.bufferIndex);
901     }
902 
903     bufferIds.erase(findBufferId);
904     if (bufferIds.empty()) {
905         frameIndex2BufferIds.erase(findFrameIndex);
906         if (frameIndex2BufferIds.empty()) {
907             mTrackedBuffersMap.erase(findListener);
908         }
909     }
910 
911     DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
912     deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
913     ++deathNotifications.count;
914     mOnBufferDestroyed.notify_one();
915 }
916 
917 // Notify the clients about buffer destructions.
918 // Return false if all destructions have been notified.
919 // Return true and set timeToRetry to the time point to wait for before
920 // retrying if some destructions have not been notified.
processNotifications(nsecs_t * timeToRetryNs)921 bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
922 
923     struct Notification {
924         sp<IComponentListener> listener;
925         hidl_vec<IComponentListener::RenderedFrame> renderedFrames;
926         Notification(const sp<IComponentListener>& l, size_t s)
927               : listener(l), renderedFrames(s) {}
928     };
929     std::list<Notification> notifications;
930 
931     bool retry = false;
932     {
933         std::lock_guard<std::mutex> lock(mMutex);
934         *timeToRetryNs = kNotificationPeriodNs;
935         nsecs_t timeNowNs = systemTime();
936         for (auto it = mDeathNotifications.begin();
937                 it != mDeathNotifications.end(); ) {
938             sp<IComponentListener> listener = it->first.promote();
939             if (!listener) {
940                 ++it;
941                 continue;
942             }
943             DeathNotifications &deathNotifications = it->second;
944 
945             nsecs_t timeSinceLastNotifiedNs =
946                     timeNowNs - deathNotifications.lastSentNs;
947             // If not enough time has passed since the last callback, leave the
948             // notifications for this listener untouched for now and retry
949             // later.
950             if (timeSinceLastNotifiedNs < kNotificationPeriodNs) {
951                 retry = true;
952                 *timeToRetryNs = std::min(*timeToRetryNs,
953                         kNotificationPeriodNs - timeSinceLastNotifiedNs);
954                 ALOGV("InputBufferManager: Notifications for "
955                       "listener @ %p will be postponed.",
956                       listener.get());
957                 ++it;
958                 continue;
959             }
960 
961             // If enough time has passed since the last notification to this
962             // listener but there are currently no pending notifications, the
963             // listener can be removed from mDeathNotifications---there is no
964             // need to keep track of the last notification time anymore.
965             if (deathNotifications.count == 0) {
966                 it = mDeathNotifications.erase(it);
967                 continue;
968             }
969 
970             // Create the argument for the callback.
971             notifications.emplace_back(listener, deathNotifications.count);
972             hidl_vec<IComponentListener::RenderedFrame>& renderedFrames =
973                     notifications.back().renderedFrames;
974             size_t i = 0;
975             for (std::pair<const uint64_t, std::vector<size_t>>& p :
976                     deathNotifications.indices) {
977                 uint64_t frameIndex = p.first;
978                 const std::vector<size_t> &bufferIndices = p.second;
979                 for (const size_t& bufferIndex : bufferIndices) {
980                     IComponentListener::RenderedFrame &renderedFrame
981                             = renderedFrames[i++];
982                     renderedFrame.slotId = ~bufferIndex;
983                     renderedFrame.bufferQueueId = frameIndex;
984                     renderedFrame.timestampNs = timeNowNs;
985                     ALOGV("InputBufferManager: "
986                           "Sending death notification (listener @ %p, "
987                           "frameIndex = %llu, bufferIndex = %zu)",
988                           listener.get(),
989                           static_cast<long long unsigned>(frameIndex),
990                           bufferIndex);
991                 }
992             }
993 
994             // Clear deathNotifications for this listener and set retry to true
995             // so processNotifications will be called again. This will
996             // guarantee that a listener with no pending notifications will
997             // eventually be removed from mDeathNotifications after
998             // kNotificationPeriodNs nanoseconds has passed.
999             retry = true;
1000             deathNotifications.indices.clear();
1001             deathNotifications.count = 0;
1002             deathNotifications.lastSentNs = timeNowNs;
1003             ++it;
1004         }
1005     }
1006 
1007     // Call onFramesRendered outside the lock to avoid deadlock.
1008     for (const Notification& notification : notifications) {
1009         if (!notification.listener->onFramesRendered(
1010                 notification.renderedFrames).isOk()) {
1011             // This may trigger if the client has died.
1012             ALOGD("InputBufferManager: onFramesRendered transaction failed "
1013                   "(listener @ %p)",
1014                   notification.listener.get());
1015         }
1016     }
1017     if (retry) {
1018         ALOGV("InputBufferManager: Pending death notifications"
1019               "will be sent in %lldns.",
1020               static_cast<long long>(*timeToRetryNs));
1021     }
1022     return retry;
1023 }
1024 
main()1025 void InputBufferManager::main() {
1026     ALOGV("InputBufferManager: Starting main thread");
1027     nsecs_t timeToRetryNs;
1028     while (true) {
1029         std::unique_lock<std::mutex> lock(mMutex);
1030         while (mDeathNotifications.empty()) {
1031             ALOGV("InputBufferManager: Waiting for buffer deaths");
1032             mOnBufferDestroyed.wait(lock);
1033         }
1034         lock.unlock();
1035         ALOGV("InputBufferManager: Sending buffer death notifications");
1036         while (processNotifications(&timeToRetryNs)) {
1037             std::this_thread::sleep_for(
1038                     std::chrono::nanoseconds(timeToRetryNs));
1039             ALOGV("InputBufferManager: Sending pending death notifications");
1040         }
1041         ALOGV("InputBufferManager: No pending death notifications");
1042     }
1043 }
1044 
InputBufferManager()1045 InputBufferManager::InputBufferManager()
1046       : mMainThread(&InputBufferManager::main, this) {
1047 }
1048 
getInstance()1049 InputBufferManager& InputBufferManager::getInstance() {
1050     static InputBufferManager instance{};
1051     return instance;
1052 }
1053 
1054 }  // namespace utils
1055 }  // namespace V1_0
1056 }  // namespace c2
1057 }  // namespace media
1058 }  // namespace google
1059 }  // namespace hardware
1060