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