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