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