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 <log/log.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 
28 #include <C2BqBufferPriv.h>
29 #include <C2PlatformSupport.h>
30 
31 namespace hardware {
32 namespace google {
33 namespace media {
34 namespace c2 {
35 namespace V1_0 {
36 namespace utils {
37 
38 using namespace ::android;
39 
40 namespace /* unnamed */ {
41 
42 // Implementation of ConfigurableC2Intf based on C2ComponentInterface
43 struct CompIntf : public ConfigurableC2Intf {
CompIntfhardware::google::media::c2::V1_0::utils::__anonac6205bf0111::CompIntf44     CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
45         ConfigurableC2Intf(intf->getName()),
46         mIntf(intf) {
47     }
48 
confighardware::google::media::c2::V1_0::utils::__anonac6205bf0111::CompIntf49     virtual c2_status_t config(
50             const std::vector<C2Param*>& params,
51             c2_blocking_t mayBlock,
52             std::vector<std::unique_ptr<C2SettingResult>>* const failures
53             ) override {
54         ALOGV("config");
55         return mIntf->config_vb(params, mayBlock, failures);
56     }
57 
queryhardware::google::media::c2::V1_0::utils::__anonac6205bf0111::CompIntf58     virtual c2_status_t query(
59             const std::vector<C2Param::Index>& indices,
60             c2_blocking_t mayBlock,
61             std::vector<std::unique_ptr<C2Param>>* const params
62             ) const override {
63         ALOGV("query");
64         return mIntf->query_vb({}, indices, mayBlock, params);
65     }
66 
querySupportedParamshardware::google::media::c2::V1_0::utils::__anonac6205bf0111::CompIntf67     virtual c2_status_t querySupportedParams(
68             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
69             ) const override {
70         ALOGV("querySupportedParams");
71         return mIntf->querySupportedParams_nb(params);
72     }
73 
querySupportedValueshardware::google::media::c2::V1_0::utils::__anonac6205bf0111::CompIntf74     virtual c2_status_t querySupportedValues(
75             std::vector<C2FieldSupportedValuesQuery>& fields,
76             c2_blocking_t mayBlock) const override {
77         ALOGV("querySupportedValues");
78         return mIntf->querySupportedValues_vb(fields, mayBlock);
79     }
80 
81 protected:
82     std::shared_ptr<C2ComponentInterface> mIntf;
83 };
84 
85 } // unnamed namespace
86 
87 // ComponentInterface
ComponentInterface(const std::shared_ptr<C2ComponentInterface> & intf,const sp<ComponentStore> & store)88 ComponentInterface::ComponentInterface(
89         const std::shared_ptr<C2ComponentInterface>& intf,
90         const sp<ComponentStore>& store) :
91     Configurable(new CachedConfigurable(std::make_unique<CompIntf>(intf))),
92     mInterface(intf) {
93     mInit = init(store.get());
94 }
95 
status() const96 c2_status_t ComponentInterface::status() const {
97     return mInit;
98 }
99 
100 // ComponentListener wrapper
101 struct Component::Listener : public C2Component::Listener {
102 
Listenerhardware::google::media::c2::V1_0::utils::Component::Listener103     Listener(const sp<Component>& component) :
104         mComponent(component),
105         mListener(component->mListener) {
106     }
107 
onError_nbhardware::google::media::c2::V1_0::utils::Component::Listener108     virtual void onError_nb(
109             std::weak_ptr<C2Component> /* c2component */,
110             uint32_t errorCode) override {
111         ALOGV("onError");
112         sp<IComponentListener> listener = mListener.promote();
113         if (listener) {
114             Return<void> transStatus = listener->onError(Status::OK, errorCode);
115             if (!transStatus.isOk()) {
116                 ALOGE("onError -- transaction failed.");
117             }
118         }
119     }
120 
onTripped_nbhardware::google::media::c2::V1_0::utils::Component::Listener121     virtual void onTripped_nb(
122             std::weak_ptr<C2Component> /* c2component */,
123             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
124             ) override {
125         ALOGV("onTripped");
126         sp<IComponentListener> listener = mListener.promote();
127         if (listener) {
128             hidl_vec<SettingResult> settingResults(c2settingResult.size());
129             size_t ix = 0;
130             for (const std::shared_ptr<C2SettingResult> &c2result :
131                     c2settingResult) {
132                 if (c2result) {
133                     if (objcpy(&settingResults[ix++], *c2result) !=
134                             Status::OK) {
135                         break;
136                     }
137                 }
138             }
139             settingResults.resize(ix);
140             Return<void> transStatus = listener->onTripped(settingResults);
141             if (!transStatus.isOk()) {
142                 ALOGE("onTripped -- transaction failed.");
143             }
144         }
145     }
146 
onWorkDone_nbhardware::google::media::c2::V1_0::utils::Component::Listener147     virtual void onWorkDone_nb(
148             std::weak_ptr<C2Component> /* c2component */,
149             std::list<std::unique_ptr<C2Work>> c2workItems) override {
150         ALOGV("onWorkDone");
151         sp<IComponentListener> listener = mListener.promote();
152         if (listener) {
153             WorkBundle workBundle;
154 
155             sp<Component> strongComponent = mComponent.promote();
156             if (objcpy(&workBundle, c2workItems, strongComponent ?
157                     &strongComponent->mBufferPoolSender : nullptr)
158                     != Status::OK) {
159                 ALOGE("onWorkDone() received corrupted work items.");
160                 return;
161             }
162             Return<void> transStatus = listener->onWorkDone(workBundle);
163             if (!transStatus.isOk()) {
164                 ALOGE("onWorkDone -- transaction failed.");
165                 return;
166             }
167             yieldBufferQueueBlocks(c2workItems, true);
168         }
169     }
170 
171 protected:
172     wp<Component> mComponent;
173     wp<IComponentListener> mListener;
174 };
175 
176 // 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)177 Component::Component(
178         const std::shared_ptr<C2Component>& component,
179         const sp<IComponentListener>& listener,
180         const sp<ComponentStore>& store,
181         const sp<::android::hardware::media::bufferpool::V1_0::
182         IClientManager>& clientPoolManager) :
183     Configurable(new CachedConfigurable(
184             std::make_unique<CompIntf>(component->intf()))),
185     mComponent(component),
186     mInterface(component->intf()),
187     mListener(listener),
188     mStore(store),
189     mBufferPoolSender(clientPoolManager) {
190     // Retrieve supported parameters from store
191     // TODO: We could cache this per component/interface type
192     mInit = init(store.get());
193 }
194 
status() const195 c2_status_t Component::status() const {
196     return mInit;
197 }
198 
199 // Methods from ::android::hardware::media::c2::V1_0::IComponent
queue(const WorkBundle & workBundle)200 Return<Status> Component::queue(const WorkBundle& workBundle) {
201     ALOGV("queue -- converting input");
202     std::list<std::unique_ptr<C2Work>> c2works;
203 
204     // TODO: Connect with bufferpool API for buffer transfers
205     if (objcpy(&c2works, workBundle) != C2_OK) {
206         ALOGV("queue -- corrupted");
207         return Status::CORRUPTED;
208     }
209     ALOGV("queue -- calling");
210     return static_cast<Status>(mComponent->queue_nb(&c2works));
211 }
212 
flush(flush_cb _hidl_cb)213 Return<void> Component::flush(flush_cb _hidl_cb) {
214     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
215     ALOGV("flush -- calling");
216     c2_status_t c2res = mComponent->flush_sm(
217             C2Component::FLUSH_COMPONENT,
218             &c2flushedWorks);
219     WorkBundle flushedWorkBundle;
220 
221     Status res = static_cast<Status>(c2res);
222     if (c2res == C2_OK) {
223         ALOGV("flush -- converting output");
224         res = objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender);
225     }
226     _hidl_cb(res, flushedWorkBundle);
227     yieldBufferQueueBlocks(c2flushedWorks, true);
228     return Void();
229 }
230 
drain(bool withEos)231 Return<Status> Component::drain(bool withEos) {
232     ALOGV("drain");
233     return static_cast<Status>(mComponent->drain_nb(withEos ?
234             C2Component::DRAIN_COMPONENT_WITH_EOS :
235             C2Component::DRAIN_COMPONENT_NO_EOS));
236 }
237 
setOutputSurface(uint64_t blockPoolId,const sp<HGraphicBufferProducer> & surface)238 Return<Status> Component::setOutputSurface(
239         uint64_t blockPoolId,
240         const sp<HGraphicBufferProducer>& surface) {
241     std::shared_ptr<C2BlockPool> pool;
242     GetCodec2BlockPool(blockPoolId, mComponent, &pool);
243     if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
244         std::shared_ptr<C2BufferQueueBlockPool> bqPool =
245                 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
246         C2BufferQueueBlockPool::OnRenderCallback cb =
247             [this](uint64_t producer, int32_t slot, int64_t nsecs) {
248                 // TODO: batch this
249                 hidl_vec<IComponentListener::RenderedFrame> rendered;
250                 rendered.resize(1);
251                 rendered[0] = { producer, slot, nsecs };
252                 mListener->onFramesRendered(rendered);
253         };
254         if (bqPool) {
255             bqPool->setRenderCallback(cb);
256             bqPool->configureProducer(surface);
257         }
258     }
259     return Status::OK;
260 }
261 
connectToOmxInputSurface(const sp<HGraphicBufferProducer> & producer,const sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource> & source)262 Return<Status> Component::connectToOmxInputSurface(
263         const sp<HGraphicBufferProducer>& producer,
264         const sp<::android::hardware::media::omx::V1_0::
265         IGraphicBufferSource>& source) {
266     // TODO implement
267     (void)producer;
268     (void)source;
269     return Status::OMITTED;
270 }
271 
disconnectFromInputSurface()272 Return<Status> Component::disconnectFromInputSurface() {
273     // TODO implement
274     return Status::OK;
275 }
276 
277 namespace /* unnamed */ {
278 
279 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfhardware::google::media::c2::V1_0::utils::__anonac6205bf0311::BlockPoolIntf280     BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool) :
281         ConfigurableC2Intf("C2BlockPool:" + std::to_string(pool->getLocalId())),
282         mPool(pool) {
283     }
284 
confighardware::google::media::c2::V1_0::utils::__anonac6205bf0311::BlockPoolIntf285     virtual c2_status_t config(
286             const std::vector<C2Param*>& params,
287             c2_blocking_t mayBlock,
288             std::vector<std::unique_ptr<C2SettingResult>>* const failures
289             ) override {
290         (void)params;
291         (void)mayBlock;
292         (void)failures;
293         return C2_OK;
294     }
295 
queryhardware::google::media::c2::V1_0::utils::__anonac6205bf0311::BlockPoolIntf296     virtual c2_status_t query(
297             const std::vector<C2Param::Index>& indices,
298             c2_blocking_t mayBlock,
299             std::vector<std::unique_ptr<C2Param>>* const params
300             ) const override {
301         (void)indices;
302         (void)mayBlock;
303         (void)params;
304         return C2_OK;
305     }
306 
querySupportedParamshardware::google::media::c2::V1_0::utils::__anonac6205bf0311::BlockPoolIntf307     virtual c2_status_t querySupportedParams(
308             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
309             ) const override {
310         (void)params;
311         return C2_OK;
312     }
313 
querySupportedValueshardware::google::media::c2::V1_0::utils::__anonac6205bf0311::BlockPoolIntf314     virtual c2_status_t querySupportedValues(
315             std::vector<C2FieldSupportedValuesQuery>& fields,
316             c2_blocking_t mayBlock) const override {
317         (void)fields;
318         (void)mayBlock;
319         return C2_OK;
320     }
321 
322 protected:
323     std::shared_ptr<C2BlockPool> mPool;
324 };
325 
326 } // unnamed namespace
327 
createBlockPool(uint32_t allocatorId,createBlockPool_cb _hidl_cb)328 Return<void> Component::createBlockPool(
329         uint32_t allocatorId,
330         createBlockPool_cb _hidl_cb) {
331     std::shared_ptr<C2BlockPool> blockPool;
332     c2_status_t status = CreateCodec2BlockPool(
333             static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
334             mComponent,
335             &blockPool);
336     if (status != C2_OK) {
337         blockPool = nullptr;
338     }
339     if (blockPool) {
340         mBlockPoolsMutex.lock();
341         mBlockPools.emplace(blockPool->getLocalId(), blockPool);
342         mBlockPoolsMutex.unlock();
343     } else if (status == C2_OK) {
344         status = C2_CORRUPTED;
345     }
346 
347     _hidl_cb(static_cast<Status>(status),
348             blockPool ? blockPool->getLocalId() : 0,
349             new CachedConfigurable(
350             std::make_unique<BlockPoolIntf>(blockPool)));
351     return Void();
352 }
353 
destroyBlockPool(uint64_t blockPoolId)354 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
355     std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
356     return mBlockPools.erase(blockPoolId) == 1 ?
357             Status::OK : Status::CORRUPTED;
358 }
359 
start()360 Return<Status> Component::start() {
361     ALOGV("start");
362     return static_cast<Status>(mComponent->start());
363 }
364 
stop()365 Return<Status> Component::stop() {
366     ALOGV("stop");
367     return static_cast<Status>(mComponent->stop());
368 }
369 
reset()370 Return<Status> Component::reset() {
371     ALOGV("reset");
372     Status status = static_cast<Status>(mComponent->reset());
373     {
374         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
375         mBlockPools.clear();
376     }
377     return status;
378 }
379 
release()380 Return<Status> Component::release() {
381     ALOGV("release");
382     Status status = static_cast<Status>(mComponent->release());
383     {
384         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
385         mBlockPools.clear();
386     }
387     return status;
388 }
389 
setLocalId(const Component::LocalId & localId)390 void Component::setLocalId(const Component::LocalId& localId) {
391     mLocalId = localId;
392 }
393 
initListener(const sp<Component> & self)394 void Component::initListener(const sp<Component>& self) {
395     std::shared_ptr<C2Component::Listener> c2listener =
396             std::make_shared<Listener>(self);
397     c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
398     if (res != C2_OK) {
399         mInit = res;
400     }
401 }
402 
~Component()403 Component::~Component() {
404     mStore->reportComponentDeath(mLocalId);
405 }
406 
InterfaceKey(const sp<IComponent> & component)407 Component::InterfaceKey::InterfaceKey(const sp<IComponent>& component) {
408     isRemote = component->isRemote();
409     if (isRemote) {
410         remote = ::android::hardware::toBinder(component);
411     } else {
412         local = component;
413     }
414 }
415 
416 }  // namespace utils
417 }  // namespace V1_0
418 }  // namespace c2
419 }  // namespace media
420 }  // namespace google
421 }  // namespace hardware
422