Home | History | Annotate | Download | only in client
      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.
     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 
     81 std::shared_ptr<Codec2Client> getClient(size_t index) {
     82     return Codec2Client::CreateFromService(kClientNames[index]);
     83 }
     84 
     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 
     97 const C2String& Codec2ConfigurableClient::getName() const {
     98     return mName;
     99 }
    100 
    101 Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
    102     return static_cast<Base*>(mBase.get());
    103 }
    104 
    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 
    116 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 
    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 
    251 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 
    286 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 
    335 Codec2Client::Base* Codec2Client::base() const {
    336     return static_cast<Base*>(mBase.get());
    337 }
    338 
    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 
    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 
    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 
    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 
    520 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 
    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>
    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 
    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 
    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>
    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>
    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 
    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 
    747 Codec2Client::Listener::~Listener() {
    748 }
    749 
    750 // Codec2Client::Component
    751 
    752 Codec2Client::Component::Base* Codec2Client::Component::base() const {
    753     return static_cast<Base*>(mBase.get());
    754 }
    755 
    756 Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
    757     Codec2Client::Configurable(base),
    758     mBufferPoolSender(nullptr) {
    759 }
    760 
    761 Codec2Client::Component::~Component() {
    762 }
    763 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   1197 Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
   1198     return static_cast<Base*>(mBase.get());
   1199 }
   1200 
   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 
   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>
   1233         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>&
   1247         Codec2Client::InputSurface::getGraphicBufferProducer() const {
   1248     return mGraphicBufferProducer;
   1249 }
   1250 
   1251 // Codec2Client::InputSurfaceConnection
   1252 
   1253 Codec2Client::InputSurfaceConnection::Base*
   1254         Codec2Client::InputSurfaceConnection::base() const {
   1255     return static_cast<Base*>(mBase.get());
   1256 }
   1257 
   1258 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
   1259         const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
   1260     mBase(base) {
   1261 }
   1262 
   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