• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 <codec2/hidl/1.0/Component.h>
22 #include <codec2/hidl/1.0/ComponentStore.h>
23 #include <codec2/hidl/1.0/InputBufferManager.h>
24 
25 #include <hidl/HidlBinderSupport.h>
26 #include <utils/Timers.h>
27 
28 #include <C2BqBufferPriv.h>
29 #include <C2Debug.h>
30 #include <C2PlatformSupport.h>
31 
32 #include <chrono>
33 #include <thread>
34 
35 namespace android {
36 namespace hardware {
37 namespace media {
38 namespace c2 {
39 namespace V1_0 {
40 namespace utils {
41 
42 using namespace ::android;
43 
44 // ComponentListener wrapper
45 struct Component::Listener : public C2Component::Listener {
46 
Listenerandroid::hardware::media::c2::V1_0::utils::Component::Listener47     Listener(const sp<Component>& component) :
48         mComponent(component),
49         mListener(component->mListener) {
50     }
51 
onError_nbandroid::hardware::media::c2::V1_0::utils::Component::Listener52     virtual void onError_nb(
53             std::weak_ptr<C2Component> /* c2component */,
54             uint32_t errorCode) override {
55         sp<IComponentListener> listener = mListener.promote();
56         if (listener) {
57             Return<void> transStatus = listener->onError(Status::OK, errorCode);
58             if (!transStatus.isOk()) {
59                 LOG(ERROR) << "Component::Listener::onError_nb -- "
60                            << "transaction failed.";
61             }
62         }
63     }
64 
onTripped_nbandroid::hardware::media::c2::V1_0::utils::Component::Listener65     virtual void onTripped_nb(
66             std::weak_ptr<C2Component> /* c2component */,
67             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
68             ) override {
69         sp<IComponentListener> listener = mListener.promote();
70         if (listener) {
71             hidl_vec<SettingResult> settingResults(c2settingResult.size());
72             size_t ix = 0;
73             for (const std::shared_ptr<C2SettingResult> &c2result :
74                     c2settingResult) {
75                 if (c2result) {
76                     if (!objcpy(&settingResults[ix++], *c2result)) {
77                         break;
78                     }
79                 }
80             }
81             settingResults.resize(ix);
82             Return<void> transStatus = listener->onTripped(settingResults);
83             if (!transStatus.isOk()) {
84                 LOG(ERROR) << "Component::Listener::onTripped_nb -- "
85                            << "transaction failed.";
86             }
87         }
88     }
89 
onWorkDone_nbandroid::hardware::media::c2::V1_0::utils::Component::Listener90     virtual void onWorkDone_nb(
91             std::weak_ptr<C2Component> /* c2component */,
92             std::list<std::unique_ptr<C2Work>> c2workItems) override {
93         for (const std::unique_ptr<C2Work>& work : c2workItems) {
94             if (work) {
95                 if (work->worklets.empty()
96                         || !work->worklets.back()
97                         || (work->worklets.back()->output.flags &
98                             C2FrameData::FLAG_INCOMPLETE) == 0) {
99                     InputBufferManager::
100                             unregisterFrameData(mListener, work->input);
101                 }
102             }
103         }
104 
105         sp<IComponentListener> listener = mListener.promote();
106         if (listener) {
107             WorkBundle workBundle;
108 
109             sp<Component> strongComponent = mComponent.promote();
110             beginTransferBufferQueueBlocks(c2workItems, true);
111             if (!objcpy(&workBundle, c2workItems, strongComponent ?
112                     &strongComponent->mBufferPoolSender : nullptr)) {
113                 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
114                            << "received corrupted work items.";
115                 endTransferBufferQueueBlocks(c2workItems, false, true);
116                 return;
117             }
118             Return<void> transStatus = listener->onWorkDone(workBundle);
119             if (!transStatus.isOk()) {
120                 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
121                            << "transaction failed.";
122                 endTransferBufferQueueBlocks(c2workItems, false, true);
123                 return;
124             }
125             endTransferBufferQueueBlocks(c2workItems, true, true);
126         }
127     }
128 
129 protected:
130     wp<Component> mComponent;
131     wp<IComponentListener> mListener;
132 };
133 
134 // Component::Sink
135 struct Component::Sink : public IInputSink {
136     std::shared_ptr<Component> mComponent;
137     sp<IConfigurable> mConfigurable;
138 
queueandroid::hardware::media::c2::V1_0::utils::Component::Sink139     virtual Return<Status> queue(const WorkBundle& workBundle) override {
140         return mComponent->queue(workBundle);
141     }
142 
getConfigurableandroid::hardware::media::c2::V1_0::utils::Component::Sink143     virtual Return<sp<IConfigurable>> getConfigurable() override {
144         return mConfigurable;
145     }
146 
147     Sink(const std::shared_ptr<Component>& component);
148     virtual ~Sink() override;
149 
150     // Process-wide map: Component::Sink -> C2Component.
151     static std::mutex sSink2ComponentMutex;
152     static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
153 
154     static std::shared_ptr<C2Component> findLocalComponent(
155             const sp<IInputSink>& sink);
156 };
157 
158 std::mutex
159         Component::Sink::sSink2ComponentMutex{};
160 std::map<IInputSink*, std::weak_ptr<C2Component>>
161         Component::Sink::sSink2Component{};
162 
Sink(const std::shared_ptr<Component> & component)163 Component::Sink::Sink(const std::shared_ptr<Component>& component)
164         : mComponent{component},
__anon1a37031e0102() 165           mConfigurable{[&component]() -> sp<IConfigurable> {
166               Return<sp<IComponentInterface>> ret1 = component->getInterface();
167               if (!ret1.isOk()) {
168                   LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
169                   return nullptr;
170               }
171               Return<sp<IConfigurable>> ret2 =
172                       static_cast<sp<IComponentInterface>>(ret1)->
173                       getConfigurable();
174               if (!ret2.isOk()) {
175                   LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
176                   return nullptr;
177               }
178               return static_cast<sp<IConfigurable>>(ret2);
179           }()} {
180     std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
181     sSink2Component.emplace(this, component->mComponent);
182 }
183 
~Sink()184 Component::Sink::~Sink() {
185     std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
186     sSink2Component.erase(this);
187 }
188 
findLocalComponent(const sp<IInputSink> & sink)189 std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
190         const sp<IInputSink>& sink) {
191     std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
192     auto i = sSink2Component.find(sink.get());
193     if (i == sSink2Component.end()) {
194         return nullptr;
195     }
196     return i->second.lock();
197 }
198 
199 // 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)200 Component::Component(
201         const std::shared_ptr<C2Component>& component,
202         const sp<IComponentListener>& listener,
203         const sp<ComponentStore>& store,
204         const sp<::android::hardware::media::bufferpool::V2_0::
205         IClientManager>& clientPoolManager)
206       : mComponent{component},
207         mInterface{new ComponentInterface(component->intf(), store.get())},
208         mListener{listener},
209         mStore{store},
210         mBufferPoolSender{clientPoolManager} {
211     // Retrieve supported parameters from store
212     // TODO: We could cache this per component/interface type
213     mInit = mInterface->status();
214 }
215 
status() const216 c2_status_t Component::status() const {
217     return mInit;
218 }
219 
220 // Methods from ::android::hardware::media::c2::V1_0::IComponent
queue(const WorkBundle & workBundle)221 Return<Status> Component::queue(const WorkBundle& workBundle) {
222     std::list<std::unique_ptr<C2Work>> c2works;
223 
224     if (!objcpy(&c2works, workBundle)) {
225         return Status::CORRUPTED;
226     }
227 
228     // Register input buffers.
229     for (const std::unique_ptr<C2Work>& work : c2works) {
230         if (work) {
231             InputBufferManager::
232                     registerFrameData(mListener, work->input);
233         }
234     }
235 
236     return static_cast<Status>(mComponent->queue_nb(&c2works));
237 }
238 
flush(flush_cb _hidl_cb)239 Return<void> Component::flush(flush_cb _hidl_cb) {
240     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
241     c2_status_t c2res = mComponent->flush_sm(
242             C2Component::FLUSH_COMPONENT,
243             &c2flushedWorks);
244 
245     // Unregister input buffers.
246     for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
247         if (work) {
248             if (work->worklets.empty()
249                     || !work->worklets.back()
250                     || (work->worklets.back()->output.flags &
251                         C2FrameData::FLAG_INCOMPLETE) == 0) {
252                 InputBufferManager::
253                         unregisterFrameData(mListener, work->input);
254             }
255         }
256     }
257 
258     WorkBundle flushedWorkBundle;
259     Status res = static_cast<Status>(c2res);
260     beginTransferBufferQueueBlocks(c2flushedWorks, true);
261     if (c2res == C2_OK) {
262         if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
263             res = Status::CORRUPTED;
264         }
265     }
266     _hidl_cb(res, flushedWorkBundle);
267     endTransferBufferQueueBlocks(c2flushedWorks, true, true);
268     return Void();
269 }
270 
drain(bool withEos)271 Return<Status> Component::drain(bool withEos) {
272     return static_cast<Status>(mComponent->drain_nb(withEos ?
273             C2Component::DRAIN_COMPONENT_WITH_EOS :
274             C2Component::DRAIN_COMPONENT_NO_EOS));
275 }
276 
setOutputSurface(uint64_t blockPoolId,const sp<HGraphicBufferProducer2> & surface)277 Return<Status> Component::setOutputSurface(
278         uint64_t blockPoolId,
279         const sp<HGraphicBufferProducer2>& surface) {
280     std::shared_ptr<C2BlockPool> pool;
281     GetCodec2BlockPool(blockPoolId, mComponent, &pool);
282     if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
283         std::shared_ptr<C2BufferQueueBlockPool> bqPool =
284                 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
285         C2BufferQueueBlockPool::OnRenderCallback cb =
286             [this](uint64_t producer, int32_t slot, int64_t nsecs) {
287                 // TODO: batch this
288                 hidl_vec<IComponentListener::RenderedFrame> rendered;
289                 rendered.resize(1);
290                 rendered[0] = { producer, slot, nsecs };
291                 (void)mListener->onFramesRendered(rendered).isOk();
292         };
293         if (bqPool) {
294             bqPool->setRenderCallback(cb);
295             bqPool->configureProducer(surface);
296         }
297     }
298     return Status::OK;
299 }
300 
connectToInputSurface(const sp<IInputSurface> & inputSurface,connectToInputSurface_cb _hidl_cb)301 Return<void> Component::connectToInputSurface(
302         const sp<IInputSurface>& inputSurface,
303         connectToInputSurface_cb _hidl_cb) {
304     Status status;
305     sp<IInputSurfaceConnection> connection;
306     auto transStatus = inputSurface->connect(
307             asInputSink(),
308             [&status, &connection](
309                     Status s, const sp<IInputSurfaceConnection>& c) {
310                 status = s;
311                 connection = c;
312             }
313         );
314     _hidl_cb(status, connection);
315     return Void();
316 }
317 
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource> & source,connectToOmxInputSurface_cb _hidl_cb)318 Return<void> Component::connectToOmxInputSurface(
319         const sp<HGraphicBufferProducer1>& producer,
320         const sp<::android::hardware::media::omx::V1_0::
321         IGraphicBufferSource>& source,
322         connectToOmxInputSurface_cb _hidl_cb) {
323     (void)producer;
324     (void)source;
325     (void)_hidl_cb;
326     return Void();
327 }
328 
disconnectFromInputSurface()329 Return<Status> Component::disconnectFromInputSurface() {
330     // TODO implement
331     return Status::OK;
332 }
333 
334 namespace /* unnamed */ {
335 
336 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfandroid::hardware::media::c2::V1_0::utils::__anon1a37031e0411::BlockPoolIntf337     BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
338           : ConfigurableC2Intf{
339                 "C2BlockPool:" +
340                     (pool ? std::to_string(pool->getLocalId()) : "null"),
341                 0},
342             mPool{pool} {
343     }
344 
configandroid::hardware::media::c2::V1_0::utils::__anon1a37031e0411::BlockPoolIntf345     virtual c2_status_t config(
346             const std::vector<C2Param*>& params,
347             c2_blocking_t mayBlock,
348             std::vector<std::unique_ptr<C2SettingResult>>* const failures
349             ) override {
350         (void)params;
351         (void)mayBlock;
352         (void)failures;
353         return C2_OK;
354     }
355 
queryandroid::hardware::media::c2::V1_0::utils::__anon1a37031e0411::BlockPoolIntf356     virtual c2_status_t query(
357             const std::vector<C2Param::Index>& indices,
358             c2_blocking_t mayBlock,
359             std::vector<std::unique_ptr<C2Param>>* const params
360             ) const override {
361         (void)indices;
362         (void)mayBlock;
363         (void)params;
364         return C2_OK;
365     }
366 
querySupportedParamsandroid::hardware::media::c2::V1_0::utils::__anon1a37031e0411::BlockPoolIntf367     virtual c2_status_t querySupportedParams(
368             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
369             ) const override {
370         (void)params;
371         return C2_OK;
372     }
373 
querySupportedValuesandroid::hardware::media::c2::V1_0::utils::__anon1a37031e0411::BlockPoolIntf374     virtual c2_status_t querySupportedValues(
375             std::vector<C2FieldSupportedValuesQuery>& fields,
376             c2_blocking_t mayBlock) const override {
377         (void)fields;
378         (void)mayBlock;
379         return C2_OK;
380     }
381 
382 protected:
383     std::shared_ptr<C2BlockPool> mPool;
384 };
385 
386 } // unnamed namespace
387 
createBlockPool(uint32_t allocatorId,createBlockPool_cb _hidl_cb)388 Return<void> Component::createBlockPool(
389         uint32_t allocatorId,
390         createBlockPool_cb _hidl_cb) {
391     std::shared_ptr<C2BlockPool> blockPool;
392     c2_status_t status = CreateCodec2BlockPool(
393             static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
394             mComponent,
395             &blockPool);
396     if (status != C2_OK) {
397         blockPool = nullptr;
398     }
399     if (blockPool) {
400         mBlockPoolsMutex.lock();
401         mBlockPools.emplace(blockPool->getLocalId(), blockPool);
402         mBlockPoolsMutex.unlock();
403     } else if (status == C2_OK) {
404         status = C2_CORRUPTED;
405     }
406 
407     _hidl_cb(static_cast<Status>(status),
408             blockPool ? blockPool->getLocalId() : 0,
409             new CachedConfigurable(
410             std::make_unique<BlockPoolIntf>(blockPool)));
411     return Void();
412 }
413 
destroyBlockPool(uint64_t blockPoolId)414 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
415     std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
416     return mBlockPools.erase(blockPoolId) == 1 ?
417             Status::OK : Status::CORRUPTED;
418 }
419 
start()420 Return<Status> Component::start() {
421     return static_cast<Status>(mComponent->start());
422 }
423 
stop()424 Return<Status> Component::stop() {
425     InputBufferManager::unregisterFrameData(mListener);
426     return static_cast<Status>(mComponent->stop());
427 }
428 
reset()429 Return<Status> Component::reset() {
430     Status status = static_cast<Status>(mComponent->reset());
431     {
432         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
433         mBlockPools.clear();
434     }
435     InputBufferManager::unregisterFrameData(mListener);
436     return status;
437 }
438 
release()439 Return<Status> Component::release() {
440     Status status = static_cast<Status>(mComponent->release());
441     {
442         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
443         mBlockPools.clear();
444     }
445     InputBufferManager::unregisterFrameData(mListener);
446     return status;
447 }
448 
getInterface()449 Return<sp<IComponentInterface>> Component::getInterface() {
450     return sp<IComponentInterface>(mInterface);
451 }
452 
asInputSink()453 Return<sp<IInputSink>> Component::asInputSink() {
454     std::lock_guard<std::mutex> lock(mSinkMutex);
455     if (!mSink) {
456         mSink = new Sink(shared_from_this());
457     }
458     return {mSink};
459 }
460 
findLocalComponent(const sp<IInputSink> & sink)461 std::shared_ptr<C2Component> Component::findLocalComponent(
462         const sp<IInputSink>& sink) {
463     return Component::Sink::findLocalComponent(sink);
464 }
465 
initListener(const sp<Component> & self)466 void Component::initListener(const sp<Component>& self) {
467     std::shared_ptr<C2Component::Listener> c2listener =
468             std::make_shared<Listener>(self);
469     c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
470     if (res != C2_OK) {
471         mInit = res;
472     }
473 }
474 
~Component()475 Component::~Component() {
476     InputBufferManager::unregisterFrameData(mListener);
477     mStore->reportComponentDeath(this);
478 }
479 
480 }  // namespace utils
481 }  // namespace V1_0
482 }  // namespace c2
483 }  // namespace media
484 }  // namespace hardware
485 }  // namespace android
486 
487