1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "Codec2-Component@1.1"
19 #include <android-base/logging.h>
20
21 #include <codec2/hidl/1.1/Component.h>
22 #include <codec2/hidl/1.1/ComponentStore.h>
23 #include <codec2/hidl/1.1/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_1 {
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_1::utils::Component::Listener47 Listener(const sp<Component>& component) :
48 mComponent(component),
49 mListener(component->mListener) {
50 }
51
onError_nbandroid::hardware::media::c2::V1_1::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_1::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_1::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_1::utils::Component::Sink139 virtual Return<Status> queue(const WorkBundle& workBundle) override {
140 return mComponent->queue(workBundle);
141 }
142
getConfigurableandroid::hardware::media::c2::V1_1::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},
__anonea117c760102() 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(),
208 store->getParameterCache())},
209 mListener{listener},
210 mStore{store},
211 mBufferPoolSender{clientPoolManager} {
212 // Retrieve supported parameters from store
213 // TODO: We could cache this per component/interface type
214 mInit = mInterface->status();
215 }
216
status() const217 c2_status_t Component::status() const {
218 return mInit;
219 }
220
221 // Methods from ::android::hardware::media::c2::V1_1::IComponent
queue(const WorkBundle & workBundle)222 Return<Status> Component::queue(const WorkBundle& workBundle) {
223 std::list<std::unique_ptr<C2Work>> c2works;
224
225 if (!objcpy(&c2works, workBundle)) {
226 return Status::CORRUPTED;
227 }
228
229 // Register input buffers.
230 for (const std::unique_ptr<C2Work>& work : c2works) {
231 if (work) {
232 InputBufferManager::
233 registerFrameData(mListener, work->input);
234 }
235 }
236
237 return static_cast<Status>(mComponent->queue_nb(&c2works));
238 }
239
flush(flush_cb _hidl_cb)240 Return<void> Component::flush(flush_cb _hidl_cb) {
241 std::list<std::unique_ptr<C2Work>> c2flushedWorks;
242 c2_status_t c2res = mComponent->flush_sm(
243 C2Component::FLUSH_COMPONENT,
244 &c2flushedWorks);
245
246 // Unregister input buffers.
247 for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
248 if (work) {
249 if (work->worklets.empty()
250 || !work->worklets.back()
251 || (work->worklets.back()->output.flags &
252 C2FrameData::FLAG_INCOMPLETE) == 0) {
253 InputBufferManager::
254 unregisterFrameData(mListener, work->input);
255 }
256 }
257 }
258
259 WorkBundle flushedWorkBundle;
260 Status res = static_cast<Status>(c2res);
261 beginTransferBufferQueueBlocks(c2flushedWorks, true);
262 if (c2res == C2_OK) {
263 if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
264 res = Status::CORRUPTED;
265 }
266 }
267 _hidl_cb(res, flushedWorkBundle);
268 endTransferBufferQueueBlocks(c2flushedWorks, true, true);
269 return Void();
270 }
271
drain(bool withEos)272 Return<Status> Component::drain(bool withEos) {
273 return static_cast<Status>(mComponent->drain_nb(withEos ?
274 C2Component::DRAIN_COMPONENT_WITH_EOS :
275 C2Component::DRAIN_COMPONENT_NO_EOS));
276 }
277
setOutputSurface(uint64_t blockPoolId,const sp<HGraphicBufferProducer2> & surface)278 Return<Status> Component::setOutputSurface(
279 uint64_t blockPoolId,
280 const sp<HGraphicBufferProducer2>& surface) {
281 std::shared_ptr<C2BlockPool> pool;
282 GetCodec2BlockPool(blockPoolId, mComponent, &pool);
283 if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
284 std::shared_ptr<C2BufferQueueBlockPool> bqPool =
285 std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
286 C2BufferQueueBlockPool::OnRenderCallback cb =
287 [this](uint64_t producer, int32_t slot, int64_t nsecs) {
288 // TODO: batch this
289 hidl_vec<IComponentListener::RenderedFrame> rendered;
290 rendered.resize(1);
291 rendered[0] = { producer, slot, nsecs };
292 (void)mListener->onFramesRendered(rendered).isOk();
293 };
294 if (bqPool) {
295 bqPool->setRenderCallback(cb);
296 bqPool->configureProducer(surface);
297 }
298 }
299 return Status::OK;
300 }
301
connectToInputSurface(const sp<IInputSurface> & inputSurface,connectToInputSurface_cb _hidl_cb)302 Return<void> Component::connectToInputSurface(
303 const sp<IInputSurface>& inputSurface,
304 connectToInputSurface_cb _hidl_cb) {
305 Status status;
306 sp<IInputSurfaceConnection> connection;
307 auto transStatus = inputSurface->connect(
308 asInputSink(),
309 [&status, &connection](
310 Status s, const sp<IInputSurfaceConnection>& c) {
311 status = s;
312 connection = c;
313 }
314 );
315 _hidl_cb(status, connection);
316 return Void();
317 }
318
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource> & source,connectToOmxInputSurface_cb _hidl_cb)319 Return<void> Component::connectToOmxInputSurface(
320 const sp<HGraphicBufferProducer1>& producer,
321 const sp<::android::hardware::media::omx::V1_0::
322 IGraphicBufferSource>& source,
323 connectToOmxInputSurface_cb _hidl_cb) {
324 (void)producer;
325 (void)source;
326 (void)_hidl_cb;
327 return Void();
328 }
329
disconnectFromInputSurface()330 Return<Status> Component::disconnectFromInputSurface() {
331 // TODO implement
332 return Status::OK;
333 }
334
335 namespace /* unnamed */ {
336
337 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfandroid::hardware::media::c2::V1_1::utils::__anonea117c760411::BlockPoolIntf338 BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
339 : ConfigurableC2Intf{
340 "C2BlockPool:" +
341 (pool ? std::to_string(pool->getLocalId()) : "null"),
342 0},
343 mPool{pool} {
344 }
345
configandroid::hardware::media::c2::V1_1::utils::__anonea117c760411::BlockPoolIntf346 virtual c2_status_t config(
347 const std::vector<C2Param*>& params,
348 c2_blocking_t mayBlock,
349 std::vector<std::unique_ptr<C2SettingResult>>* const failures
350 ) override {
351 (void)params;
352 (void)mayBlock;
353 (void)failures;
354 return C2_OK;
355 }
356
queryandroid::hardware::media::c2::V1_1::utils::__anonea117c760411::BlockPoolIntf357 virtual c2_status_t query(
358 const std::vector<C2Param::Index>& indices,
359 c2_blocking_t mayBlock,
360 std::vector<std::unique_ptr<C2Param>>* const params
361 ) const override {
362 (void)indices;
363 (void)mayBlock;
364 (void)params;
365 return C2_OK;
366 }
367
querySupportedParamsandroid::hardware::media::c2::V1_1::utils::__anonea117c760411::BlockPoolIntf368 virtual c2_status_t querySupportedParams(
369 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
370 ) const override {
371 (void)params;
372 return C2_OK;
373 }
374
querySupportedValuesandroid::hardware::media::c2::V1_1::utils::__anonea117c760411::BlockPoolIntf375 virtual c2_status_t querySupportedValues(
376 std::vector<C2FieldSupportedValuesQuery>& fields,
377 c2_blocking_t mayBlock) const override {
378 (void)fields;
379 (void)mayBlock;
380 return C2_OK;
381 }
382
383 protected:
384 std::shared_ptr<C2BlockPool> mPool;
385 };
386
387 } // unnamed namespace
388
createBlockPool(uint32_t allocatorId,createBlockPool_cb _hidl_cb)389 Return<void> Component::createBlockPool(
390 uint32_t allocatorId,
391 createBlockPool_cb _hidl_cb) {
392 std::shared_ptr<C2BlockPool> blockPool;
393 c2_status_t status = CreateCodec2BlockPool(
394 static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
395 mComponent,
396 &blockPool);
397 if (status != C2_OK) {
398 blockPool = nullptr;
399 }
400 if (blockPool) {
401 mBlockPoolsMutex.lock();
402 mBlockPools.emplace(blockPool->getLocalId(), blockPool);
403 mBlockPoolsMutex.unlock();
404 } else if (status == C2_OK) {
405 status = C2_CORRUPTED;
406 }
407
408 _hidl_cb(static_cast<Status>(status),
409 blockPool ? blockPool->getLocalId() : 0,
410 new CachedConfigurable(
411 std::make_unique<BlockPoolIntf>(blockPool)));
412 return Void();
413 }
414
destroyBlockPool(uint64_t blockPoolId)415 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
416 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
417 return mBlockPools.erase(blockPoolId) == 1 ?
418 Status::OK : Status::CORRUPTED;
419 }
420
start()421 Return<Status> Component::start() {
422 return static_cast<Status>(mComponent->start());
423 }
424
stop()425 Return<Status> Component::stop() {
426 InputBufferManager::unregisterFrameData(mListener);
427 return static_cast<Status>(mComponent->stop());
428 }
429
reset()430 Return<Status> Component::reset() {
431 Status status = static_cast<Status>(mComponent->reset());
432 {
433 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
434 mBlockPools.clear();
435 }
436 InputBufferManager::unregisterFrameData(mListener);
437 return status;
438 }
439
release()440 Return<Status> Component::release() {
441 Status status = static_cast<Status>(mComponent->release());
442 {
443 std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
444 mBlockPools.clear();
445 }
446 InputBufferManager::unregisterFrameData(mListener);
447 return status;
448 }
449
getInterface()450 Return<sp<IComponentInterface>> Component::getInterface() {
451 return sp<IComponentInterface>(mInterface);
452 }
453
asInputSink()454 Return<sp<IInputSink>> Component::asInputSink() {
455 std::lock_guard<std::mutex> lock(mSinkMutex);
456 if (!mSink) {
457 mSink = new Sink(shared_from_this());
458 }
459 return {mSink};
460 }
461
configureVideoTunnel(uint32_t avSyncHwId,configureVideoTunnel_cb _hidl_cb)462 Return<void> Component::configureVideoTunnel(
463 uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
464 (void)avSyncHwId;
465 _hidl_cb(Status::OMITTED, hidl_handle{});
466 return Void();
467 }
468
findLocalComponent(const sp<IInputSink> & sink)469 std::shared_ptr<C2Component> Component::findLocalComponent(
470 const sp<IInputSink>& sink) {
471 return Component::Sink::findLocalComponent(sink);
472 }
473
initListener(const sp<Component> & self)474 void Component::initListener(const sp<Component>& self) {
475 std::shared_ptr<C2Component::Listener> c2listener =
476 std::make_shared<Listener>(self);
477 c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
478 if (res != C2_OK) {
479 mInit = res;
480 }
481 }
482
~Component()483 Component::~Component() {
484 InputBufferManager::unregisterFrameData(mListener);
485 mStore->reportComponentDeath(this);
486 }
487
488 } // namespace utils
489 } // namespace V1_1
490 } // namespace c2
491 } // namespace media
492 } // namespace hardware
493 } // namespace android
494