blob: 26bd96c23f7b8bab304bc9e20ad8987b0ebb316b [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
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 "Codec2Client"
19#include <log/log.h>
20
21#include <codec2/hidl/client.h>
22
23#include <deque>
24#include <limits>
25#include <map>
26#include <type_traits>
27#include <vector>
28
29#include <android-base/properties.h>
30#include <bufferpool/ClientManager.h>
31#include <cutils/native_handle.h>
32#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
33#include <hidl/HidlSupport.h>
34#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
35#undef LOG
36
37#include <android/hardware/media/bufferpool/1.0/IClientManager.h>
Pawin Vongmasad0f0e142018-11-15 03:36:28 -080038#include <android/hardware/media/c2/1.0/IComponent.h>
39#include <android/hardware/media/c2/1.0/IComponentInterface.h>
40#include <android/hardware/media/c2/1.0/IComponentListener.h>
41#include <android/hardware/media/c2/1.0/IComponentStore.h>
42#include <android/hardware/media/c2/1.0/IConfigurable.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080043
44#include <C2Debug.h>
45#include <C2BufferPriv.h>
46#include <C2PlatformSupport.h>
47
48namespace android {
49
50using ::android::hardware::hidl_vec;
51using ::android::hardware::hidl_string;
52using ::android::hardware::Return;
53using ::android::hardware::Void;
54using ::android::TWGraphicBufferProducer;
55
Pawin Vongmasad0f0e142018-11-15 03:36:28 -080056using namespace ::android::hardware::media::c2::V1_0;
57using namespace ::android::hardware::media::c2::V1_0::utils;
Pawin Vongmasa36653902018-11-15 00:10:25 -080058using namespace ::android::hardware::media::bufferpool::V1_0;
59using namespace ::android::hardware::media::bufferpool::V1_0::implementation;
60
61namespace /* unnamed */ {
62
63// c2_status_t value that corresponds to hwbinder transaction failure.
64constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
65
66// List of known IComponentStore services in the decreasing order of preference.
67constexpr const char* kClientNames[] = {
68 "default",
69 "software",
70 };
71
72// Number of known IComponentStore services.
73constexpr size_t kNumClients = std::extent<decltype(kClientNames)>::value;
74
75typedef std::array<std::shared_ptr<Codec2Client>, kNumClients> ClientList;
76
77// Convenience methods to obtain known clients.
78std::shared_ptr<Codec2Client> getClient(size_t index) {
Pawin Vongmasae55ed3f2018-11-28 03:39:57 -080079 uint32_t serviceMask = ::android::base::GetUintProperty(
80 "debug.media.codec2", uint32_t(0));
81 return Codec2Client::CreateFromService(
82 kClientNames[index],
83 (serviceMask & (1 << index)) != 0);
Pawin Vongmasa36653902018-11-15 00:10:25 -080084}
85
86ClientList getClientList() {
87 ClientList list;
88 for (size_t i = 0; i < list.size(); ++i) {
89 list[i] = getClient(i);
90 }
91 return list;
92}
93
94} // unnamed
95
96// Codec2ConfigurableClient
97
98const C2String& Codec2ConfigurableClient::getName() const {
99 return mName;
100}
101
102Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
103 return static_cast<Base*>(mBase.get());
104}
105
106Codec2ConfigurableClient::Codec2ConfigurableClient(
107 const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
108 Return<void> transStatus = base->getName(
109 [this](const hidl_string& name) {
110 mName = name.c_str();
111 });
112 if (!transStatus.isOk()) {
113 ALOGE("Cannot obtain name from IConfigurable.");
114 }
115}
116
117c2_status_t Codec2ConfigurableClient::query(
118 const std::vector<C2Param*> &stackParams,
119 const std::vector<C2Param::Index> &heapParamIndices,
120 c2_blocking_t mayBlock,
121 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
122 hidl_vec<ParamIndex> indices(
123 stackParams.size() + heapParamIndices.size());
124 size_t numIndices = 0;
125 for (C2Param* const& stackParam : stackParams) {
126 if (!stackParam) {
127 ALOGW("query -- null stack param encountered.");
128 continue;
129 }
130 indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
131 }
132 size_t numStackIndices = numIndices;
133 for (const C2Param::Index& index : heapParamIndices) {
134 indices[numIndices++] =
135 static_cast<ParamIndex>(static_cast<uint32_t>(index));
136 }
137 indices.resize(numIndices);
138 if (heapParams) {
139 heapParams->reserve(heapParams->size() + numIndices);
140 }
141 c2_status_t status;
142 Return<void> transStatus = base()->query(
143 indices,
144 mayBlock == C2_MAY_BLOCK,
145 [&status, &numStackIndices, &stackParams, heapParams](
146 Status s, const Params& p) {
147 status = static_cast<c2_status_t>(s);
148 if (status != C2_OK && status != C2_BAD_INDEX) {
149 ALOGE("query -- call failed. "
150 "Error code = %d", static_cast<int>(status));
151 return;
152 }
153 std::vector<C2Param*> paramPointers;
154 c2_status_t parseStatus = parseParamsBlob(&paramPointers, p);
155 if (parseStatus != C2_OK) {
156 ALOGE("query -- error while parsing params. "
157 "Error code = %d", static_cast<int>(status));
158 status = parseStatus;
159 return;
160 }
161 size_t i = 0;
162 for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
163 C2Param* paramPointer = *it;
164 if (numStackIndices > 0) {
165 --numStackIndices;
166 if (!paramPointer) {
167 ALOGW("query -- null stack param.");
168 ++it;
169 continue;
170 }
171 for (; i < stackParams.size() && !stackParams[i]; ) {
172 ++i;
173 }
174 if (i >= stackParams.size()) {
175 ALOGE("query -- unexpected error.");
176 status = C2_CORRUPTED;
177 return;
178 }
179 if (stackParams[i]->index() != paramPointer->index()) {
180 ALOGW("query -- param skipped. index = %d",
181 static_cast<int>(stackParams[i]->index()));
182 stackParams[i++]->invalidate();
183 continue;
184 }
185 if (!stackParams[i++]->updateFrom(*paramPointer)) {
186 ALOGW("query -- param update failed. index = %d",
187 static_cast<int>(paramPointer->index()));
188 }
189 } else {
190 if (!paramPointer) {
191 ALOGW("query -- null heap param.");
192 ++it;
193 continue;
194 }
195 if (!heapParams) {
196 ALOGW("query -- unexpected extra stack param.");
197 } else {
198 heapParams->emplace_back(C2Param::Copy(*paramPointer));
199 }
200 }
201 ++it;
202 }
203 });
204 if (!transStatus.isOk()) {
205 ALOGE("query -- transaction failed.");
206 return C2_TRANSACTION_FAILED;
207 }
208 return status;
209}
210
211c2_status_t Codec2ConfigurableClient::config(
212 const std::vector<C2Param*> &params,
213 c2_blocking_t mayBlock,
214 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
215 Params hidlParams;
216 Status hidlStatus = createParamsBlob(&hidlParams, params);
217 if (hidlStatus != Status::OK) {
218 ALOGE("config -- bad input.");
219 return C2_TRANSACTION_FAILED;
220 }
221 c2_status_t status;
222 Return<void> transStatus = base()->config(
223 hidlParams,
224 mayBlock == C2_MAY_BLOCK,
225 [&status, &params, failures](
226 Status s,
227 const hidl_vec<SettingResult> f,
228 const Params& o) {
229 status = static_cast<c2_status_t>(s);
230 if (status != C2_OK) {
231 ALOGD("config -- call failed. "
232 "Error code = %d", static_cast<int>(status));
233 }
234 size_t i = failures->size();
235 failures->resize(i + f.size());
236 for (const SettingResult& sf : f) {
237 status = objcpy(&(*failures)[i++], sf);
238 if (status != C2_OK) {
239 ALOGE("config -- invalid returned SettingResult. "
240 "Error code = %d", static_cast<int>(status));
241 return;
242 }
243 }
244 status = updateParamsFromBlob(params, o);
245 });
246 if (!transStatus.isOk()) {
247 ALOGE("config -- transaction failed.");
248 return C2_TRANSACTION_FAILED;
249 }
250 return status;
251}
252
253c2_status_t Codec2ConfigurableClient::querySupportedParams(
254 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
255 // TODO: Cache and query properly!
256 c2_status_t status;
257 Return<void> transStatus = base()->querySupportedParams(
258 std::numeric_limits<uint32_t>::min(),
259 std::numeric_limits<uint32_t>::max(),
260 [&status, params](
261 Status s,
262 const hidl_vec<ParamDescriptor>& p) {
263 status = static_cast<c2_status_t>(s);
264 if (status != C2_OK) {
265 ALOGE("querySupportedParams -- call failed. "
266 "Error code = %d", static_cast<int>(status));
267 return;
268 }
269 size_t i = params->size();
270 params->resize(i + p.size());
271 for (const ParamDescriptor& sp : p) {
272 status = objcpy(&(*params)[i++], sp);
273 if (status != C2_OK) {
274 ALOGE("querySupportedParams -- "
275 "invalid returned ParamDescriptor. "
276 "Error code = %d", static_cast<int>(status));
277 return;
278 }
279 }
280 });
281 if (!transStatus.isOk()) {
282 ALOGE("querySupportedParams -- transaction failed.");
283 return C2_TRANSACTION_FAILED;
284 }
285 return status;
286}
287
288c2_status_t Codec2ConfigurableClient::querySupportedValues(
289 std::vector<C2FieldSupportedValuesQuery>& fields,
290 c2_blocking_t mayBlock) const {
291 hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
292 for (size_t i = 0; i < fields.size(); ++i) {
293 Status hidlStatus = objcpy(&inFields[i], fields[i]);
294 if (hidlStatus != Status::OK) {
295 ALOGE("querySupportedValues -- bad input");
296 return C2_TRANSACTION_FAILED;
297 }
298 }
299
300 c2_status_t status;
301 Return<void> transStatus = base()->querySupportedValues(
302 inFields,
303 mayBlock == C2_MAY_BLOCK,
304 [&status, &inFields, &fields](
305 Status s,
306 const hidl_vec<FieldSupportedValuesQueryResult>& r) {
307 status = static_cast<c2_status_t>(s);
308 if (status != C2_OK) {
309 ALOGE("querySupportedValues -- call failed. "
310 "Error code = %d", static_cast<int>(status));
311 return;
312 }
313 if (r.size() != fields.size()) {
314 ALOGE("querySupportedValues -- input and output lists "
315 "have different sizes.");
316 status = C2_CORRUPTED;
317 return;
318 }
319 for (size_t i = 0; i < fields.size(); ++i) {
320 status = objcpy(&fields[i], inFields[i], r[i]);
321 if (status != C2_OK) {
322 ALOGE("querySupportedValues -- invalid returned value. "
323 "Error code = %d", static_cast<int>(status));
324 return;
325 }
326 }
327 });
328 if (!transStatus.isOk()) {
329 ALOGE("querySupportedValues -- transaction failed.");
330 return C2_TRANSACTION_FAILED;
331 }
332 return status;
333}
334
335// Codec2Client::Component::HidlListener
336struct Codec2Client::Component::HidlListener : public IComponentListener {
337 std::weak_ptr<Component> component;
338 std::weak_ptr<Listener> base;
339
340 virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
341 std::list<std::unique_ptr<C2Work>> workItems;
342 c2_status_t status = objcpy(&workItems, workBundle);
343 if (status != C2_OK) {
344 ALOGI("onWorkDone -- received corrupted WorkBundle. "
345 "status = %d.", static_cast<int>(status));
346 return Void();
347 }
348 // release input buffers potentially held by the component from queue
349 size_t numDiscardedInputBuffers = 0;
350 std::shared_ptr<Codec2Client::Component> strongComponent = component.lock();
351 if (strongComponent) {
352 numDiscardedInputBuffers = strongComponent->handleOnWorkDone(workItems);
353 }
354 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
355 listener->onWorkDone(component, workItems, numDiscardedInputBuffers);
356 } else {
357 ALOGD("onWorkDone -- listener died.");
358 }
359 return Void();
360 }
361
362 virtual Return<void> onTripped(
363 const hidl_vec<SettingResult>& settingResults) override {
364 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
365 settingResults.size());
366 c2_status_t status;
367 for (size_t i = 0; i < settingResults.size(); ++i) {
368 std::unique_ptr<C2SettingResult> c2SettingResult;
369 status = objcpy(&c2SettingResult, settingResults[i]);
370 if (status != C2_OK) {
371 ALOGI("onTripped -- received corrupted SettingResult. "
372 "status = %d.", static_cast<int>(status));
373 return Void();
374 }
375 c2SettingResults[i] = std::move(c2SettingResult);
376 }
377 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
378 listener->onTripped(component, c2SettingResults);
379 } else {
380 ALOGD("onTripped -- listener died.");
381 }
382 return Void();
383 }
384
385 virtual Return<void> onError(Status s, uint32_t errorCode) override {
386 ALOGD("onError -- status = %d, errorCode = %u.",
387 static_cast<int>(s),
388 static_cast<unsigned>(errorCode));
389 if (std::shared_ptr<Listener> listener = base.lock()) {
390 listener->onError(component, s == Status::OK ?
391 errorCode : static_cast<c2_status_t>(s));
392 } else {
393 ALOGD("onError -- listener died.");
394 }
395 return Void();
396 }
397
398 virtual Return<void> onFramesRendered(
399 const hidl_vec<RenderedFrame>& renderedFrames) override {
400 std::shared_ptr<Listener> listener = base.lock();
401 std::vector<Codec2Client::Listener::RenderedFrame> rfs;
402 rfs.reserve(renderedFrames.size());
403 for (const RenderedFrame& rf : renderedFrames) {
404 if (rf.slotId >= 0) {
405 if (listener) {
406 rfs.emplace_back(rf.bufferQueueId,
407 rf.slotId,
408 rf.timestampNs);
409 }
410 } else {
411 std::shared_ptr<Codec2Client::Component> strongComponent =
412 component.lock();
413 if (strongComponent) {
414 uint64_t frameIndex = rf.bufferQueueId;
415 size_t bufferIndex = static_cast<size_t>(~rf.slotId);
416 ALOGV("Received death notification of input buffer: "
417 "frameIndex = %llu, bufferIndex = %zu.",
418 static_cast<long long unsigned>(frameIndex),
419 bufferIndex);
420 std::shared_ptr<C2Buffer> buffer =
421 strongComponent->freeInputBuffer(
422 frameIndex, bufferIndex);
423 if (buffer) {
424 listener->onInputBufferDone(buffer);
425 }
426 }
427 }
428 }
429 if (!rfs.empty()) {
430 if (listener) {
431 listener->onFramesRendered(rfs);
432 } else {
433 ALOGD("onFramesRendered -- listener died.");
434 }
435 }
436 return Void();
437 }
438};
439
440// Codec2Client
441Codec2Client::Base* Codec2Client::base() const {
442 return static_cast<Base*>(mBase.get());
443}
444
445Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base, std::string instanceName) :
446 Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) {
447 Return<sp<IClientManager>> transResult = base->getPoolClientManager();
448 if (!transResult.isOk()) {
449 ALOGE("getPoolClientManager -- failed transaction.");
450 } else {
451 mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
452 }
453}
454
455c2_status_t Codec2Client::createComponent(
456 const C2String& name,
457 const std::shared_ptr<Codec2Client::Listener>& listener,
458 std::shared_ptr<Codec2Client::Component>* const component) {
459
460 // TODO: Add support for Bufferpool
461
462
463 c2_status_t status;
464 sp<Component::HidlListener> hidlListener = new Component::HidlListener();
465 hidlListener->base = listener;
466 Return<void> transStatus = base()->createComponent(
467 name,
468 hidlListener,
469 ClientManager::getInstance(),
470 [&status, component, hidlListener](
471 Status s,
472 const sp<IComponent>& c) {
473 status = static_cast<c2_status_t>(s);
474 if (status != C2_OK) {
475 return;
476 }
477 *component = std::make_shared<Codec2Client::Component>(c);
478 hidlListener->component = *component;
479 });
480 if (!transStatus.isOk()) {
481 ALOGE("createComponent -- failed transaction.");
482 return C2_TRANSACTION_FAILED;
483 }
484
485 if (status != C2_OK) {
486 return status;
487 }
488
489 if (!*component) {
490 ALOGE("createComponent -- null component.");
491 return C2_CORRUPTED;
492 }
493
494 status = (*component)->setDeathListener(*component, listener);
495 if (status != C2_OK) {
496 ALOGE("createComponent -- setDeathListener returned error: %d.",
497 static_cast<int>(status));
498 }
499
500 (*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
501 return status;
502}
503
504c2_status_t Codec2Client::createInterface(
505 const C2String& name,
506 std::shared_ptr<Codec2Client::Interface>* const interface) {
507 c2_status_t status;
508 Return<void> transStatus = base()->createInterface(
509 name,
510 [&status, interface](
511 Status s,
512 const sp<IComponentInterface>& i) {
513 status = static_cast<c2_status_t>(s);
514 if (status != C2_OK) {
515 ALOGE("createInterface -- call failed. "
516 "Error code = %d", static_cast<int>(status));
517 return;
518 }
519 *interface = std::make_shared<Codec2Client::Interface>(i);
520 });
521 if (!transStatus.isOk()) {
522 ALOGE("createInterface -- failed transaction.");
523 return C2_TRANSACTION_FAILED;
524 }
525 return status;
526}
527
528c2_status_t Codec2Client::createInputSurface(
529 std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) {
530 Return<sp<IInputSurface>> transResult = base()->createInputSurface();
531 if (!transResult.isOk()) {
532 ALOGE("createInputSurface -- failed transaction.");
533 return C2_TRANSACTION_FAILED;
534 }
535 sp<IInputSurface> result = static_cast<sp<IInputSurface>>(transResult);
536 if (!result) {
537 *inputSurface = nullptr;
538 return C2_OK;
539 }
540 *inputSurface = std::make_shared<InputSurface>(result);
541 if (!*inputSurface) {
542 ALOGE("createInputSurface -- unknown error.");
543 return C2_CORRUPTED;
544 }
545 return C2_OK;
546}
547
548const std::vector<C2Component::Traits>& Codec2Client::listComponents() const {
549 std::lock_guard<std::mutex> lock(mMutex);
550 if (mListed) {
551 return mTraitsList;
552 }
553 Return<void> transStatus = base()->listComponents(
554 [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
555 mTraitsList.resize(t.size());
556 mAliasesBuffer.resize(t.size());
557 for (size_t i = 0; i < t.size(); ++i) {
558 c2_status_t status = objcpy(
559 &mTraitsList[i], &mAliasesBuffer[i], t[i]);
560 if (status != C2_OK) {
561 ALOGE("listComponents -- corrupted output.");
562 return;
563 }
564 }
565 });
566 if (!transStatus.isOk()) {
567 ALOGE("listComponents -- failed transaction.");
568 }
569 mListed = true;
570 return mTraitsList;
571}
572
573c2_status_t Codec2Client::copyBuffer(
574 const std::shared_ptr<C2Buffer>& src,
575 const std::shared_ptr<C2Buffer>& dst) {
576 // TODO: Implement?
577 (void)src;
578 (void)dst;
579 ALOGE("copyBuffer not implemented");
580 return C2_OMITTED;
581}
582
583std::shared_ptr<C2ParamReflector>
584 Codec2Client::getParamReflector() {
585 // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
586 // should reflect the HAL API.
587 struct SimpleParamReflector : public C2ParamReflector {
588 virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const {
589 hidl_vec<ParamIndex> indices(1);
590 indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
591 std::unique_ptr<C2StructDescriptor> descriptor;
592 Return<void> transStatus = mBase->getStructDescriptors(
593 indices,
594 [&descriptor](
595 Status s,
596 const hidl_vec<StructDescriptor>& sd) {
597 c2_status_t status = static_cast<c2_status_t>(s);
598 if (status != C2_OK) {
599 ALOGE("getStructDescriptors -- call failed. "
600 "Error code = %d", static_cast<int>(status));
601 descriptor.reset();
602 return;
603 }
604 if (sd.size() != 1) {
605 ALOGD("getStructDescriptors -- returned vector of size %zu.",
606 sd.size());
607 descriptor.reset();
608 return;
609 }
610 status = objcpy(&descriptor, sd[0]);
611 if (status != C2_OK) {
612 ALOGD("getStructDescriptors -- failed to convert. "
613 "Error code = %d", static_cast<int>(status));
614 descriptor.reset();
615 return;
616 }
617 });
618 return descriptor;
619 }
620
621 SimpleParamReflector(sp<Base> base)
622 : mBase(base) { }
623
624 sp<Base> mBase;
625 };
626
627 return std::make_shared<SimpleParamReflector>(base());
628};
629
630std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
631 const char* instanceName, bool waitForService) {
632 if (!instanceName) {
633 return nullptr;
634 }
635 sp<Base> baseStore = waitForService ?
636 Base::getService(instanceName) :
637 Base::tryGetService(instanceName);
638 if (!baseStore) {
639 if (waitForService) {
Pawin Vongmasae55ed3f2018-11-28 03:39:57 -0800640 ALOGW("Codec2.0 service \"%s\" inaccessible. "
641 "Check the device manifest.",
642 instanceName);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800643 } else {
Pawin Vongmasae55ed3f2018-11-28 03:39:57 -0800644 ALOGD("Codec2.0 service \"%s\" unavailable right now. "
645 "Try again later.",
646 instanceName);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800647 }
648 return nullptr;
649 }
650 return std::make_shared<Codec2Client>(baseStore, instanceName);
651}
652
653c2_status_t Codec2Client::ForAllStores(
654 const std::string &key,
655 std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) {
656 c2_status_t status = C2_NO_INIT; // no IComponentStores present
657
658 // Cache the mapping key -> index of Codec2Client in getClient().
659 static std::mutex key2IndexMutex;
660 static std::map<std::string, size_t> key2Index;
661
662 // By default try all stores. However, try the last known client first. If the last known
663 // client fails, retry once. We do this by pushing the last known client in front of the
664 // list of all clients.
665 std::deque<size_t> indices;
666 for (size_t index = kNumClients; index > 0; ) {
667 indices.push_front(--index);
668 }
669
670 bool wasMapped = false;
671 std::unique_lock<std::mutex> lock(key2IndexMutex);
672 auto it = key2Index.find(key);
673 if (it != key2Index.end()) {
674 indices.push_front(it->second);
675 wasMapped = true;
676 }
677 lock.unlock();
678
679 for (size_t index : indices) {
680 std::shared_ptr<Codec2Client> client = getClient(index);
681 if (client) {
682 status = predicate(client);
683 if (status == C2_OK) {
684 lock.lock();
685 key2Index[key] = index; // update last known client index
686 return status;
687 }
688 }
689 if (wasMapped) {
690 ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str());
691 wasMapped = false;
692 }
693 }
694 return status; // return the last status from a valid client
695}
696
697std::shared_ptr<Codec2Client::Component>
698 Codec2Client::CreateComponentByName(
699 const char* componentName,
700 const std::shared_ptr<Listener>& listener,
701 std::shared_ptr<Codec2Client>* owner) {
702 std::shared_ptr<Component> component;
703 c2_status_t status = ForAllStores(
704 componentName,
705 [owner, &component, componentName, &listener](
706 const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
707 c2_status_t status = client->createComponent(componentName, listener, &component);
708 if (status == C2_OK) {
709 if (owner) {
710 *owner = client;
711 }
712 } else if (status != C2_NOT_FOUND) {
713 ALOGD("IComponentStore(%s)::createComponent('%s') returned %s",
714 client->getInstanceName().c_str(), componentName, asString(status));
715 }
716 return status;
717 });
718 if (status != C2_OK) {
719 ALOGI("Could not create component '%s' (%s)", componentName, asString(status));
720 }
721 return component;
722}
723
724std::shared_ptr<Codec2Client::Interface>
725 Codec2Client::CreateInterfaceByName(
726 const char* interfaceName,
727 std::shared_ptr<Codec2Client>* owner) {
728 std::shared_ptr<Interface> interface;
729 c2_status_t status = ForAllStores(
730 interfaceName,
731 [owner, &interface, interfaceName](
732 const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
733 c2_status_t status = client->createInterface(interfaceName, &interface);
734 if (status == C2_OK) {
735 if (owner) {
736 *owner = client;
737 }
738 } else if (status != C2_NOT_FOUND) {
739 ALOGD("IComponentStore(%s)::createInterface('%s') returned %s",
740 client->getInstanceName().c_str(), interfaceName, asString(status));
741 }
742 return status;
743 });
744 if (status != C2_OK) {
745 ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status));
746 }
747 return interface;
748}
749
750std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface() {
751 uint32_t serviceMask = ::android::base::GetUintProperty(
752 "debug.stagefright.c2inputsurface", uint32_t(0));
753 for (size_t i = 0; i < kNumClients; ++i) {
754 if ((1 << i) & serviceMask) {
755 std::shared_ptr<Codec2Client> client = getClient(i);
756 std::shared_ptr<Codec2Client::InputSurface> inputSurface;
757 if (client &&
758 client->createInputSurface(&inputSurface) == C2_OK &&
759 inputSurface) {
760 return inputSurface;
761 }
762 }
763 }
764 ALOGW("Could not create an input surface from any Codec2.0 services.");
765 return nullptr;
766}
767
768const std::vector<C2Component::Traits>& Codec2Client::ListComponents() {
769 static std::vector<C2Component::Traits> traitsList = [](){
770 std::vector<C2Component::Traits> list;
771 size_t listSize = 0;
772 ClientList clientList = getClientList();
773 for (const std::shared_ptr<Codec2Client>& client : clientList) {
774 if (!client) {
775 continue;
776 }
777 listSize += client->listComponents().size();
778 }
779 list.reserve(listSize);
780 for (const std::shared_ptr<Codec2Client>& client : clientList) {
781 if (!client) {
782 continue;
783 }
784 list.insert(
785 list.end(),
786 client->listComponents().begin(),
787 client->listComponents().end());
788 }
789 return list;
790 }();
791
792 return traitsList;
793}
794
795// Codec2Client::Listener
796
797Codec2Client::Listener::~Listener() {
798}
799
800// Codec2Client::Component
801
802Codec2Client::Component::Base* Codec2Client::Component::base() const {
803 return static_cast<Base*>(mBase.get());
804}
805
806Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
807 Codec2Client::Configurable(base),
808 mBufferPoolSender(nullptr) {
809}
810
811Codec2Client::Component::~Component() {
812}
813
814c2_status_t Codec2Client::Component::createBlockPool(
815 C2Allocator::id_t id,
816 C2BlockPool::local_id_t* blockPoolId,
817 std::shared_ptr<Codec2Client::Configurable>* configurable) {
818 c2_status_t status;
819 Return<void> transStatus = base()->createBlockPool(
820 static_cast<uint32_t>(id),
821 [&status, blockPoolId, configurable](
822 Status s,
823 uint64_t pId,
824 const sp<IConfigurable>& c) {
825 status = static_cast<c2_status_t>(s);
826 configurable->reset();
827 if (status != C2_OK) {
828 ALOGE("createBlockPool -- call failed. "
829 "Error code = %d", static_cast<int>(status));
830 return;
831 }
832 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
833 *configurable = std::make_shared<Codec2Client::Configurable>(c);
834 });
835 if (!transStatus.isOk()) {
836 ALOGE("createBlockPool -- transaction failed.");
837 return C2_TRANSACTION_FAILED;
838 }
839 return status;
840}
841
842c2_status_t Codec2Client::Component::destroyBlockPool(
843 C2BlockPool::local_id_t localId) {
844 Return<Status> transResult = base()->destroyBlockPool(
845 static_cast<uint64_t>(localId));
846 if (!transResult.isOk()) {
847 ALOGE("destroyBlockPool -- transaction failed.");
848 return C2_TRANSACTION_FAILED;
849 }
850 return static_cast<c2_status_t>(static_cast<Status>(transResult));
851}
852
853size_t Codec2Client::Component::handleOnWorkDone(
854 const std::list<std::unique_ptr<C2Work>> &workItems) {
855 // Input buffers' lifetime management
856 std::vector<uint64_t> inputDone;
857 for (const std::unique_ptr<C2Work> &work : workItems) {
858 if (work) {
859 if (work->worklets.empty()
860 || !work->worklets.back()
861 || (work->worklets.back()->output.flags & C2FrameData::FLAG_INCOMPLETE) == 0) {
862 // input is complete
863 inputDone.emplace_back(work->input.ordinal.frameIndex.peeku());
864 }
865 }
866 }
867
868 size_t numDiscardedInputBuffers = 0;
869 {
870 std::lock_guard<std::mutex> lock(mInputBuffersMutex);
871 for (uint64_t inputIndex : inputDone) {
872 auto it = mInputBuffers.find(inputIndex);
873 if (it == mInputBuffers.end()) {
874 ALOGV("onWorkDone -- returned consumed/unknown "
875 "input frame: index %llu",
876 (long long)inputIndex);
877 } else {
878 ALOGV("onWorkDone -- processed input frame: "
879 "index %llu (containing %zu buffers)",
880 (long long)inputIndex, it->second.size());
881 mInputBuffers.erase(it);
882 mInputBufferCount.erase(inputIndex);
883 ++numDiscardedInputBuffers;
884 }
885 }
886 }
887
888 // Output bufferqueue-based blocks' lifetime management
889 mOutputBufferQueueMutex.lock();
890 sp<IGraphicBufferProducer> igbp = mOutputIgbp;
891 uint64_t bqId = mOutputBqId;
892 uint32_t generation = mOutputGeneration;
893 mOutputBufferQueueMutex.unlock();
894
895 if (igbp) {
896 holdBufferQueueBlocks(workItems, igbp, bqId, generation);
897 }
898 return numDiscardedInputBuffers;
899}
900
901std::shared_ptr<C2Buffer> Codec2Client::Component::freeInputBuffer(
902 uint64_t frameIndex,
903 size_t bufferIndex) {
904 std::shared_ptr<C2Buffer> buffer;
905 std::lock_guard<std::mutex> lock(mInputBuffersMutex);
906 auto it = mInputBuffers.find(frameIndex);
907 if (it == mInputBuffers.end()) {
908 ALOGI("freeInputBuffer -- Unrecognized input frame index %llu.",
909 static_cast<long long unsigned>(frameIndex));
910 return nullptr;
911 }
912 if (bufferIndex >= it->second.size()) {
913 ALOGI("freeInputBuffer -- Input buffer no. %zu is invalid in "
914 "input frame index %llu.",
915 bufferIndex, static_cast<long long unsigned>(frameIndex));
916 return nullptr;
917 }
918 buffer = it->second[bufferIndex];
919 if (!buffer) {
920 ALOGI("freeInputBuffer -- Input buffer no. %zu in "
921 "input frame index %llu has already been freed.",
922 bufferIndex, static_cast<long long unsigned>(frameIndex));
923 return nullptr;
924 }
925 it->second[bufferIndex] = nullptr;
926 if (--mInputBufferCount[frameIndex] == 0) {
927 mInputBuffers.erase(it);
928 mInputBufferCount.erase(frameIndex);
929 }
930 return buffer;
931}
932
933c2_status_t Codec2Client::Component::queue(
934 std::list<std::unique_ptr<C2Work>>* const items) {
935 // remember input buffers queued to hold reference to them
936 {
937 std::lock_guard<std::mutex> lock(mInputBuffersMutex);
938 for (const std::unique_ptr<C2Work> &work : *items) {
939 if (!work) {
940 continue;
941 }
942 if (work->input.buffers.size() == 0) {
943 continue;
944 }
945
946 uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
947 auto res = mInputBuffers.emplace(inputIndex, work->input.buffers);
948 if (!res.second) {
949 // TODO: append? - for now we are replacing
950 res.first->second = work->input.buffers;
951 ALOGI("queue -- duplicate input frame: index %llu. "
952 "Discarding the old input frame...",
953 (long long)inputIndex);
954 }
955 mInputBufferCount[inputIndex] = work->input.buffers.size();
956 ALOGV("queue -- queueing input frame: "
957 "index %llu (containing %zu buffers)",
958 (long long)inputIndex, work->input.buffers.size());
959 }
960 }
961
962 WorkBundle workBundle;
963 Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender);
964 if (hidlStatus != Status::OK) {
965 ALOGE("queue -- bad input.");
966 return C2_TRANSACTION_FAILED;
967 }
968 Return<Status> transStatus = base()->queue(workBundle);
969 if (!transStatus.isOk()) {
970 ALOGE("queue -- transaction failed.");
971 return C2_TRANSACTION_FAILED;
972 }
973 c2_status_t status =
974 static_cast<c2_status_t>(static_cast<Status>(transStatus));
975 if (status != C2_OK) {
976 ALOGE("queue -- call failed. "
977 "Error code = %d", static_cast<int>(status));
978 }
979 return status;
980}
981
982c2_status_t Codec2Client::Component::flush(
983 C2Component::flush_mode_t mode,
984 std::list<std::unique_ptr<C2Work>>* const flushedWork) {
985 (void)mode; // Flush mode isn't supported in HIDL yet.
986 c2_status_t status;
987 Return<void> transStatus = base()->flush(
988 [&status, flushedWork](
989 Status s, const WorkBundle& wb) {
990 status = static_cast<c2_status_t>(s);
991 if (status != C2_OK) {
992 ALOGE("flush -- call failed. "
993 "Error code = %d", static_cast<int>(status));
994 return;
995 }
996 status = objcpy(flushedWork, wb);
997 });
998 if (!transStatus.isOk()) {
999 ALOGE("flush -- transaction failed.");
1000 return C2_TRANSACTION_FAILED;
1001 }
1002
1003 // Indices of flushed work items.
1004 std::vector<uint64_t> flushedIndices;
1005 for (const std::unique_ptr<C2Work> &work : *flushedWork) {
1006 if (work) {
1007 if (work->worklets.empty()
1008 || !work->worklets.back()
1009 || (work->worklets.back()->output.flags &
1010 C2FrameData::FLAG_INCOMPLETE) == 0) {
1011 // input is complete
1012 flushedIndices.emplace_back(
1013 work->input.ordinal.frameIndex.peeku());
1014 }
1015 }
1016 }
1017
1018 // Input buffers' lifetime management
1019 for (uint64_t flushedIndex : flushedIndices) {
1020 std::lock_guard<std::mutex> lock(mInputBuffersMutex);
1021 auto it = mInputBuffers.find(flushedIndex);
1022 if (it == mInputBuffers.end()) {
1023 ALOGV("flush -- returned consumed/unknown input frame: "
1024 "index %llu",
1025 (long long)flushedIndex);
1026 } else {
1027 ALOGV("flush -- returned unprocessed input frame: "
1028 "index %llu (containing %zu buffers)",
1029 (long long)flushedIndex, mInputBufferCount[flushedIndex]);
1030 mInputBuffers.erase(it);
1031 mInputBufferCount.erase(flushedIndex);
1032 }
1033 }
1034
1035 // Output bufferqueue-based blocks' lifetime management
1036 mOutputBufferQueueMutex.lock();
1037 sp<IGraphicBufferProducer> igbp = mOutputIgbp;
1038 uint64_t bqId = mOutputBqId;
1039 uint32_t generation = mOutputGeneration;
1040 mOutputBufferQueueMutex.unlock();
1041
1042 if (igbp) {
1043 holdBufferQueueBlocks(*flushedWork, igbp, bqId, generation);
1044 }
1045
1046 return status;
1047}
1048
1049c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
1050 Return<Status> transStatus = base()->drain(
1051 mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
1052 if (!transStatus.isOk()) {
1053 ALOGE("drain -- transaction failed.");
1054 return C2_TRANSACTION_FAILED;
1055 }
1056 c2_status_t status =
1057 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1058 if (status != C2_OK) {
1059 ALOGE("drain -- call failed. "
1060 "Error code = %d", static_cast<int>(status));
1061 }
1062 return status;
1063}
1064
1065c2_status_t Codec2Client::Component::start() {
1066 Return<Status> transStatus = base()->start();
1067 if (!transStatus.isOk()) {
1068 ALOGE("start -- transaction failed.");
1069 return C2_TRANSACTION_FAILED;
1070 }
1071 c2_status_t status =
1072 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1073 if (status != C2_OK) {
1074 ALOGE("start -- call failed. "
1075 "Error code = %d", static_cast<int>(status));
1076 }
1077 return status;
1078}
1079
1080c2_status_t Codec2Client::Component::stop() {
1081 Return<Status> transStatus = base()->stop();
1082 if (!transStatus.isOk()) {
1083 ALOGE("stop -- transaction failed.");
1084 return C2_TRANSACTION_FAILED;
1085 }
1086 c2_status_t status =
1087 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1088 if (status != C2_OK) {
1089 ALOGE("stop -- call failed. "
1090 "Error code = %d", static_cast<int>(status));
1091 }
1092 mInputBuffersMutex.lock();
1093 mInputBuffers.clear();
1094 mInputBufferCount.clear();
1095 mInputBuffersMutex.unlock();
1096 return status;
1097}
1098
1099c2_status_t Codec2Client::Component::reset() {
1100 Return<Status> transStatus = base()->reset();
1101 if (!transStatus.isOk()) {
1102 ALOGE("reset -- transaction failed.");
1103 return C2_TRANSACTION_FAILED;
1104 }
1105 c2_status_t status =
1106 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1107 if (status != C2_OK) {
1108 ALOGE("reset -- call failed. "
1109 "Error code = %d", static_cast<int>(status));
1110 }
1111 mInputBuffersMutex.lock();
1112 mInputBuffers.clear();
1113 mInputBufferCount.clear();
1114 mInputBuffersMutex.unlock();
1115 return status;
1116}
1117
1118c2_status_t Codec2Client::Component::release() {
1119 Return<Status> transStatus = base()->release();
1120 if (!transStatus.isOk()) {
1121 ALOGE("release -- transaction failed.");
1122 return C2_TRANSACTION_FAILED;
1123 }
1124 c2_status_t status =
1125 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1126 if (status != C2_OK) {
1127 ALOGE("release -- call failed. "
1128 "Error code = %d", static_cast<int>(status));
1129 }
1130 mInputBuffersMutex.lock();
1131 mInputBuffers.clear();
1132 mInputBufferCount.clear();
1133 mInputBuffersMutex.unlock();
1134 return status;
1135}
1136
1137c2_status_t Codec2Client::Component::setOutputSurface(
1138 C2BlockPool::local_id_t blockPoolId,
1139 const sp<IGraphicBufferProducer>& surface,
1140 uint32_t generation) {
1141 sp<HGraphicBufferProducer> igbp = surface->getHalInterface();
1142 if (!igbp) {
1143 igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface);
1144 }
1145
1146 Return<Status> transStatus = base()->setOutputSurface(
1147 static_cast<uint64_t>(blockPoolId), igbp);
1148 if (!transStatus.isOk()) {
1149 ALOGE("setOutputSurface -- transaction failed.");
1150 return C2_TRANSACTION_FAILED;
1151 }
1152 c2_status_t status =
1153 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1154 if (status != C2_OK) {
1155 ALOGE("setOutputSurface -- call failed. "
1156 "Error code = %d", static_cast<int>(status));
1157 } else {
1158 std::lock_guard<std::mutex> lock(mOutputBufferQueueMutex);
1159 if (mOutputIgbp != surface) {
1160 mOutputIgbp = surface;
1161 if (!surface) {
1162 mOutputBqId = 0;
1163 } else if (surface->getUniqueId(&mOutputBqId) != OK) {
1164 ALOGE("setOutputSurface -- cannot obtain bufferqueue id.");
1165 }
1166 }
1167 mOutputGeneration = generation;
1168 }
1169 return status;
1170}
1171
1172status_t Codec2Client::Component::queueToOutputSurface(
1173 const C2ConstGraphicBlock& block,
1174 const QueueBufferInput& input,
1175 QueueBufferOutput* output) {
1176 uint32_t generation;
1177 uint64_t bqId;
1178 int32_t bqSlot;
1179 if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
1180 bqId == 0) {
1181 // Block not from bufferqueue -- it must be attached before queuing.
1182
1183 mOutputBufferQueueMutex.lock();
1184 sp<IGraphicBufferProducer> outputIgbp = mOutputIgbp;
1185 uint32_t outputGeneration = mOutputGeneration;
1186 mOutputBufferQueueMutex.unlock();
1187
1188 status_t status = !attachToBufferQueue(block,
1189 outputIgbp,
1190 outputGeneration,
1191 &bqSlot);
1192 if (status != OK) {
1193 ALOGW("queueToOutputSurface -- attaching failed.");
1194 return INVALID_OPERATION;
1195 }
1196
1197 status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
1198 input, output);
1199 if (status != OK) {
1200 ALOGE("queueToOutputSurface -- queueBuffer() failed "
1201 "on non-bufferqueue-based block. "
1202 "Error code = %d.",
1203 static_cast<int>(status));
1204 return status;
1205 }
1206 return OK;
1207 }
1208
1209 mOutputBufferQueueMutex.lock();
1210 sp<IGraphicBufferProducer> outputIgbp = mOutputIgbp;
1211 uint64_t outputBqId = mOutputBqId;
1212 uint32_t outputGeneration = mOutputGeneration;
1213 mOutputBufferQueueMutex.unlock();
1214
1215 if (!outputIgbp) {
1216 ALOGV("queueToOutputSurface -- output surface is null.");
1217 return NO_INIT;
1218 }
1219
1220 if (bqId != outputBqId) {
1221 ALOGV("queueToOutputSurface -- bufferqueue ids mismatch.");
1222 return DEAD_OBJECT;
1223 }
1224
1225 if (generation != outputGeneration) {
1226 ALOGV("queueToOutputSurface -- generation numbers mismatch.");
1227 return DEAD_OBJECT;
1228 }
1229
1230 status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
1231 input, output);
1232 if (status != OK) {
1233 ALOGD("queueToOutputSurface -- queueBuffer() failed "
1234 "on bufferqueue-based block. "
1235 "Error code = %d.",
1236 static_cast<int>(status));
1237 return status;
1238 }
1239 if (!yieldBufferQueueBlock(block)) {
1240 ALOGD("queueToOutputSurface -- cannot yield bufferqueue-based block "
1241 "to the bufferqueue.");
1242 return UNKNOWN_ERROR;
1243 }
1244 return OK;
1245}
1246
1247c2_status_t Codec2Client::Component::connectToOmxInputSurface(
1248 const sp<HGraphicBufferProducer>& producer,
1249 const sp<HGraphicBufferSource>& source) {
1250 Return<Status> transStatus = base()->connectToOmxInputSurface(
1251 producer, source);
1252 if (!transStatus.isOk()) {
1253 ALOGE("connectToOmxInputSurface -- transaction failed.");
1254 return C2_TRANSACTION_FAILED;
1255 }
1256 c2_status_t status =
1257 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1258 if (status != C2_OK) {
1259 ALOGE("connectToOmxInputSurface -- call failed. "
1260 "Error code = %d", static_cast<int>(status));
1261 }
1262 return status;
1263}
1264
1265c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
1266 Return<Status> transStatus = base()->disconnectFromInputSurface();
1267 if (!transStatus.isOk()) {
1268 ALOGE("disconnectToInputSurface -- transaction failed.");
1269 return C2_TRANSACTION_FAILED;
1270 }
1271 c2_status_t status =
1272 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1273 if (status != C2_OK) {
1274 ALOGE("disconnectFromInputSurface -- call failed. "
1275 "Error code = %d", static_cast<int>(status));
1276 }
1277 return status;
1278}
1279
1280c2_status_t Codec2Client::Component::setDeathListener(
1281 const std::shared_ptr<Component>& component,
1282 const std::shared_ptr<Listener>& listener) {
1283
1284 struct HidlDeathRecipient : public hardware::hidl_death_recipient {
1285 std::weak_ptr<Component> component;
1286 std::weak_ptr<Listener> base;
1287
1288 virtual void serviceDied(
1289 uint64_t /* cookie */,
1290 const wp<::android::hidl::base::V1_0::IBase>& /* who */
1291 ) override {
1292 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1293 listener->onDeath(component);
1294 } else {
1295 ALOGW("onDeath -- listener died.");
1296 }
1297 }
1298 };
1299
1300 sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
1301 deathRecipient->base = listener;
1302 deathRecipient->component = component;
1303
1304 component->mDeathRecipient = deathRecipient;
1305 Return<bool> transResult = component->base()->linkToDeath(
1306 component->mDeathRecipient, 0);
1307 if (!transResult.isOk()) {
1308 ALOGE("setDeathListener -- failed transaction: linkToDeath.");
1309 return C2_TRANSACTION_FAILED;
1310 }
1311 if (!static_cast<bool>(transResult)) {
1312 ALOGE("setDeathListener -- linkToDeath call failed.");
1313 return C2_CORRUPTED;
1314 }
1315 return C2_OK;
1316}
1317
1318// Codec2Client::InputSurface
1319
1320Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
1321 return static_cast<Base*>(mBase.get());
1322}
1323
1324Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) :
1325 mBase(base),
1326 mGraphicBufferProducer(new
1327 ::android::hardware::graphics::bufferqueue::V1_0::utils::
1328 H2BGraphicBufferProducer(base)) {
1329}
1330
1331c2_status_t Codec2Client::InputSurface::connectToComponent(
1332 const std::shared_ptr<Codec2Client::Component>& component,
1333 std::shared_ptr<Connection>* connection) {
1334 c2_status_t status;
1335 Return<void> transStatus = base()->connectToComponent(
1336 component->base(),
1337 [&status, connection](
1338 Status s,
1339 const sp<IInputSurfaceConnection>& c) {
1340 status = static_cast<c2_status_t>(s);
1341 if (status != C2_OK) {
1342 ALOGE("connectToComponent -- call failed. "
1343 "Error code = %d", static_cast<int>(status));
1344 return;
1345 }
1346 *connection = std::make_shared<Connection>(c);
1347 });
1348 if (!transStatus.isOk()) {
1349 ALOGE("connect -- transaction failed.");
1350 return C2_TRANSACTION_FAILED;
1351 }
1352 return status;
1353}
1354
1355std::shared_ptr<Codec2Client::Configurable>
1356 Codec2Client::InputSurface::getConfigurable() const {
1357 Return<sp<IConfigurable>> transResult = base()->getConfigurable();
1358 if (!transResult.isOk()) {
1359 ALOGW("getConfigurable -- transaction failed.");
1360 return nullptr;
1361 }
1362 if (!static_cast<sp<IConfigurable>>(transResult)) {
1363 ALOGW("getConfigurable -- null pointer.");
1364 return nullptr;
1365 }
1366 return std::make_shared<Configurable>(transResult);
1367}
1368
1369const sp<IGraphicBufferProducer>&
1370 Codec2Client::InputSurface::getGraphicBufferProducer() const {
1371 return mGraphicBufferProducer;
1372}
1373
1374const sp<IInputSurface>& Codec2Client::InputSurface::getHalInterface() const {
1375 return mBase;
1376}
1377
1378// Codec2Client::InputSurfaceConnection
1379
1380Codec2Client::InputSurfaceConnection::Base*
1381 Codec2Client::InputSurfaceConnection::base() const {
1382 return static_cast<Base*>(mBase.get());
1383}
1384
1385Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
1386 const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
1387 mBase(base) {
1388}
1389
1390c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
1391 Return<Status> transResult = base()->disconnect();
1392 return static_cast<c2_status_t>(static_cast<Status>(transResult));
1393}
1394
1395} // namespace android
1396