client.cpp revision ec232287b40b0fca541d57420f5d84472cdde5b0
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 <codec2/hidl/1.0/types.h>
24
25#include <hardware/google/media/c2/1.0/IComponentListener.h>
26#include <hardware/google/media/c2/1.0/IConfigurable.h>
27#include <hardware/google/media/c2/1.0/IComponentInterface.h>
28#include <hardware/google/media/c2/1.0/IComponent.h>
29#include <hardware/google/media/c2/1.0/IComponentStore.h>
30
31#include <C2PlatformSupport.h>
32#include <C2BufferPriv.h>
33#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
34#include <hidl/HidlSupport.h>
35#include <cutils/properties.h>
36
37#include <limits>
38#include <type_traits>
39#include <vector>
40#include <map>
41
42namespace android {
43
44using ::android::hardware::hidl_vec;
45using ::android::hardware::hidl_string;
46using ::android::hardware::Return;
47using ::android::hardware::Void;
48
49using namespace ::hardware::google::media::c2::V1_0;
50using namespace ::hardware::google::media::c2::V1_0::utils;
51
52namespace /* unnamed */ {
53
54// c2_status_t value that corresponds to hwbinder transaction failure.
55constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
56
57// List of known IComponentStore services.
58constexpr const char* kClientNames[] = {
59        "default",
60        "software",
61    };
62
63std::vector<std::shared_ptr<Codec2Client>> gClients;
64
65void prepareClients() {
66    static std::mutex clientsMutex;
67    static bool clientsInitialized = false;
68
69    std::lock_guard<std::mutex> lock(clientsMutex);
70    if (clientsInitialized) {
71        return;
72    }
73    gClients.reserve(std::extent<decltype(kClientNames)>::value);
74    for (const char* clientName : kClientNames) {
75        gClients.emplace_back(Codec2Client::CreateFromService(clientName));
76    }
77    clientsInitialized = true;
78}
79
80} // unnamed namespace
81
82// Codec2ConfigurableClient
83
84const C2String& Codec2ConfigurableClient::getName() const {
85    return mName;
86}
87
88Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
89    return static_cast<Base*>(mBase.get());
90}
91
92Codec2ConfigurableClient::Codec2ConfigurableClient(
93        const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
94    Return<void> transStatus = base->getName(
95            [this](const hidl_string& name) {
96                mName = name.c_str();
97            });
98    if (!transStatus.isOk()) {
99        ALOGE("Cannot obtain name from IConfigurable.");
100    }
101}
102
103c2_status_t Codec2ConfigurableClient::query(
104        const std::vector<C2Param*> &stackParams,
105        const std::vector<C2Param::Index> &heapParamIndices,
106        c2_blocking_t mayBlock,
107        std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
108    hidl_vec<ParamIndex> indices(
109            stackParams.size() + heapParamIndices.size());
110    size_t numIndices = 0;
111    for (C2Param* const& stackParam : stackParams) {
112        if (!stackParam) {
113            ALOGW("query -- null stack param encountered.");
114            continue;
115        }
116        indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
117    }
118    size_t numStackIndices = numIndices;
119    for (const C2Param::Index& index : heapParamIndices) {
120        indices[numIndices++] =
121                static_cast<ParamIndex>(static_cast<uint32_t>(index));
122    }
123    indices.resize(numIndices);
124    if (heapParams) {
125        heapParams->reserve(numIndices);
126        heapParams->clear();
127    }
128    c2_status_t status;
129    Return<void> transStatus = base()->query(
130            indices,
131            mayBlock == C2_MAY_BLOCK,
132            [&status, &numStackIndices, &stackParams, heapParams](
133                    Status s, const Params& p) {
134                status = static_cast<c2_status_t>(s);
135                if (status != C2_OK) {
136                    ALOGE("query -- call failed. "
137                            "Error code = %d", static_cast<int>(status));
138                    return;
139                }
140                std::vector<C2Param*> paramPointers;
141                status = parseParamsBlob(&paramPointers, p);
142                if (status != C2_OK) {
143                    ALOGE("query -- error while parsing params. "
144                            "Error code = %d", static_cast<int>(status));
145                    return;
146                }
147                size_t i = 0;
148                for (C2Param* const& paramPointer : paramPointers) {
149                    if (numStackIndices > 0) {
150                        --numStackIndices;
151                        if (!paramPointer) {
152                            ALOGW("query -- null stack param.");
153                            if (numStackIndices > 0) {
154                                ++i;
155                            }
156                            continue;
157                        }
158                        for (; !stackParams[i]; ++i) {
159                            if (i >= stackParams.size()) {
160                                ALOGE("query -- unexpected error.");
161                                status = C2_CORRUPTED;
162                                return;
163                            }
164                        }
165                        if (!stackParams[i++]->updateFrom(*paramPointer)) {
166                            ALOGW("query -- param update failed. index = %d",
167                                    static_cast<int>(paramPointer->index()));
168                        }
169                    } else {
170                        if (!paramPointer) {
171                            ALOGW("query -- null heap param.");
172                            continue;
173                        }
174                        if (!heapParams) {
175                            ALOGW("query -- extra stack param.");
176                        }
177                        heapParams->emplace_back(C2Param::Copy(*paramPointer));
178                    }
179                }
180            });
181    if (!transStatus.isOk()) {
182        ALOGE("query -- transaction failed.");
183        return C2_TRANSACTION_FAILED;
184    }
185    return status;
186}
187
188c2_status_t Codec2ConfigurableClient::config(
189        const std::vector<C2Param*> &params,
190        c2_blocking_t mayBlock,
191        std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
192    Params hidlParams;
193    Status hidlStatus = createParamsBlob(&hidlParams, params);
194    if (hidlStatus != Status::OK) {
195        ALOGE("config -- bad input.");
196        return C2_TRANSACTION_FAILED;
197    }
198    c2_status_t status;
199    Return<void> transStatus = base()->config(
200            hidlParams,
201            mayBlock == C2_MAY_BLOCK,
202            [&status, &params, failures](
203                    Status s,
204                    const hidl_vec<SettingResult> f,
205                    const Params& o) {
206                status = static_cast<c2_status_t>(s);
207                if (status != C2_OK) {
208                    ALOGE("config -- call failed. "
209                            "Error code = %d", static_cast<int>(status));
210                    return;
211                }
212                failures->clear();
213                failures->resize(f.size());
214                size_t i = 0;
215                for (const SettingResult& sf : f) {
216                    status = objcpy(&(*failures)[i++], sf);
217                    if (status != C2_OK) {
218                        ALOGE("config -- invalid returned SettingResult. "
219                                "Error code = %d", static_cast<int>(status));
220                        return;
221                    }
222                }
223                status = updateParamsFromBlob(params, o);
224            });
225    if (!transStatus.isOk()) {
226        ALOGE("config -- transaction failed.");
227        return C2_TRANSACTION_FAILED;
228    }
229    return status;
230}
231
232c2_status_t Codec2ConfigurableClient::querySupportedParams(
233        std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
234    // TODO: Cache and query properly!
235    c2_status_t status;
236    Return<void> transStatus = base()->querySupportedParams(
237            std::numeric_limits<uint32_t>::min(),
238            std::numeric_limits<uint32_t>::max(),
239            [&status, params](
240                    Status s,
241                    const hidl_vec<ParamDescriptor>& p) {
242                status = static_cast<c2_status_t>(s);
243                if (status != C2_OK) {
244                    ALOGE("querySupportedParams -- call failed. "
245                            "Error code = %d", static_cast<int>(status));
246                    return;
247                }
248                params->resize(p.size());
249                size_t i = 0;
250                for (const ParamDescriptor& sp : p) {
251                    status = objcpy(&(*params)[i++], sp);
252                    if (status != C2_OK) {
253                        ALOGE("querySupportedParams -- "
254                                "invalid returned ParamDescriptor. "
255                                "Error code = %d", static_cast<int>(status));
256                        return;
257                    }
258                }
259            });
260    if (!transStatus.isOk()) {
261        ALOGE("querySupportedParams -- transaction failed.");
262        return C2_TRANSACTION_FAILED;
263    }
264    return status;
265}
266
267c2_status_t Codec2ConfigurableClient::querySupportedValues(
268        std::vector<C2FieldSupportedValuesQuery>& fields,
269        c2_blocking_t mayBlock) const {
270    hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
271    for (size_t i = 0; i < fields.size(); ++i) {
272        Status hidlStatus = objcpy(&inFields[i], fields[i]);
273        if (hidlStatus != Status::OK) {
274            ALOGE("querySupportedValues -- bad input");
275            return C2_TRANSACTION_FAILED;
276        }
277    }
278
279    c2_status_t status;
280    Return<void> transStatus = base()->querySupportedValues(
281            inFields,
282            mayBlock == C2_MAY_BLOCK,
283            [&status, &inFields, &fields](
284                    Status s,
285                    const hidl_vec<FieldSupportedValuesQueryResult>& r) {
286                status = static_cast<c2_status_t>(s);
287                if (status != C2_OK) {
288                    ALOGE("querySupportedValues -- call failed. "
289                            "Error code = %d", static_cast<int>(status));
290                    return;
291                }
292                if (r.size() != fields.size()) {
293                    ALOGE("querySupportedValues -- input and output lists "
294                            "have different sizes.");
295                    status = C2_CORRUPTED;
296                    return;
297                }
298                for (size_t i = 0; i < fields.size(); ++i) {
299                    status = objcpy(&fields[i], inFields[i], r[i]);
300                    if (status != C2_OK) {
301                        ALOGE("querySupportedValues -- invalid returned value. "
302                                "Error code = %d", static_cast<int>(status));
303                        return;
304                    }
305                }
306            });
307    if (!transStatus.isOk()) {
308        ALOGE("querySupportedValues -- transaction failed.");
309        return C2_TRANSACTION_FAILED;
310    }
311    return status;
312}
313
314// Codec2Client
315
316Codec2Client::Base* Codec2Client::base() const {
317    return static_cast<Base*>(mBase.get());
318}
319
320Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base) :
321    Codec2ConfigurableClient(base), mListed(false) {
322}
323
324c2_status_t Codec2Client::createComponent(
325        const C2String& name,
326        const std::shared_ptr<Codec2Client::Listener>& listener,
327        std::shared_ptr<Codec2Client::Component>* const component) {
328
329    // TODO: Add support for Bufferpool
330
331    struct HidlListener : public IComponentListener {
332        std::shared_ptr<Codec2Client::Listener> base;
333        std::weak_ptr<Codec2Client::Component> component;
334
335        virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
336            std::list<std::unique_ptr<C2Work>> workItems;
337            c2_status_t status = objcpy(&workItems, workBundle);
338            if (status != C2_OK) {
339                ALOGE("onWorkDone -- received corrupted WorkBundle. "
340                        "Error code: %d", static_cast<int>(status));
341                return Void();
342            }
343            base->onWorkDone(component, workItems);
344            return Void();
345        }
346
347        virtual Return<void> onTripped(
348                const hidl_vec<SettingResult>& settingResults) override {
349            std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
350                    settingResults.size());
351            c2_status_t status;
352            for (size_t i = 0; i < settingResults.size(); ++i) {
353                std::unique_ptr<C2SettingResult> c2SettingResult;
354                status = objcpy(&c2SettingResult, settingResults[i]);
355                if (status != C2_OK) {
356                    ALOGE("onTripped -- received corrupted SettingResult. "
357                            "Error code: %d", static_cast<int>(status));
358                    return Void();
359                }
360                c2SettingResults[i] = std::move(c2SettingResult);
361            }
362            base->onTripped(component, c2SettingResults);
363            return Void();
364        }
365
366        virtual Return<void> onError(Status s, uint32_t errorCode) override {
367            ALOGE("onError -- status = %d, errorCode = %u. ",
368                    static_cast<int>(s),
369                    static_cast<unsigned>(errorCode));
370            base->onError(component, s == Status::OK ?
371                    errorCode : static_cast<c2_status_t>(s));
372            return Void();
373        }
374    };
375
376    c2_status_t status;
377    sp<HidlListener> hidlListener = new HidlListener();
378    hidlListener->base = listener;
379    Return<void> transStatus = base()->createComponent(
380            name,
381            hidlListener,
382            nullptr,
383            [&status, component, hidlListener](
384                    Status s,
385                    const sp<IComponent>& c) {
386                status = static_cast<c2_status_t>(s);
387                if (status != C2_OK) {
388                    ALOGE("createComponent -- call failed. "
389                            "Error code = %d", static_cast<int>(status));
390                    return;
391                }
392                *component = std::make_shared<Codec2Client::Component>(c);
393                hidlListener->component = *component;
394            });
395    if (!transStatus.isOk()) {
396        ALOGE("createComponent -- failed transaction.");
397        return C2_TRANSACTION_FAILED;
398    }
399    return status;
400}
401
402c2_status_t Codec2Client::createInterface(
403        const C2String& name,
404        std::shared_ptr<Codec2Client::Interface>* const interface) {
405    c2_status_t status;
406    Return<void> transStatus = base()->createInterface(
407            name,
408            [&status, interface](
409                    Status s,
410                    const sp<IComponentInterface>& i) {
411                status = static_cast<c2_status_t>(s);
412                if (status != C2_OK) {
413                    ALOGE("createInterface -- call failed. "
414                            "Error code = %d", static_cast<int>(status));
415                    return;
416                }
417                *interface = std::make_shared<Codec2Client::Interface>(i);
418            });
419    if (!transStatus.isOk()) {
420        ALOGE("createInterface -- failed transaction.");
421        return C2_TRANSACTION_FAILED;
422    }
423    return status;
424}
425
426c2_status_t Codec2Client::createInputSurface(
427        std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) {
428    Return<sp<IInputSurface>> transResult = base()->createInputSurface();
429    if (!transResult.isOk()) {
430        ALOGE("createInputSurface -- failed transaction.");
431        return C2_TRANSACTION_FAILED;
432    }
433    *inputSurface = std::make_shared<InputSurface>(
434            static_cast<sp<IInputSurface>>(transResult));
435    if (!*inputSurface) {
436        ALOGE("createInputSurface -- failed to create client.");
437        return C2_CORRUPTED;
438    }
439    return C2_OK;
440}
441
442const std::vector<C2Component::Traits>& Codec2Client::listComponents() const {
443    std::lock_guard<std::mutex> lock(mMutex);
444    if (mListed) {
445        return mTraitsList;
446    }
447    Return<void> transStatus = base()->listComponents(
448            [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
449                mTraitsList.resize(t.size());
450                mAliasesBuffer.resize(t.size());
451                for (size_t i = 0; i < t.size(); ++i) {
452                    c2_status_t status = objcpy(
453                            &mTraitsList[i], &mAliasesBuffer[i], t[i]);
454                    if (status != C2_OK) {
455                        ALOGE("listComponents -- corrupted output.");
456                        return;
457                    }
458                }
459            });
460    if (!transStatus.isOk()) {
461        ALOGE("listComponents -- failed transaction.");
462    }
463    mListed = true;
464    return mTraitsList;
465}
466
467c2_status_t Codec2Client::copyBuffer(
468        const std::shared_ptr<C2Buffer>& src,
469        const std::shared_ptr<C2Buffer>& dst) {
470    // TODO: Implement?
471    (void)src;
472    (void)dst;
473    ALOGE("copyBuffer not implemented");
474    return C2_OMITTED;
475}
476
477std::shared_ptr<C2ParamReflector>
478        Codec2Client::getParamReflector() {
479    // TODO: Implement this once there is a way to construct C2StructDescriptor
480    // dynamically.
481    ALOGE("getParamReflector -- not implemented.");
482    return nullptr;
483}
484
485std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
486        const char* instanceName, bool waitForService) {
487    if (!instanceName) {
488        return nullptr;
489    }
490    sp<Base> baseStore = waitForService ?
491            Base::getService(instanceName) :
492            Base::tryGetService(instanceName);
493    if (!baseStore) {
494        if (waitForService) {
495            ALOGE("Codec2.0 service inaccessible. Check the device manifest.");
496        } else {
497            ALOGW("Codec2.0 service not available right now. Try again later.");
498        }
499        return nullptr;
500    }
501    return std::make_shared<Codec2Client>(baseStore);
502}
503
504std::shared_ptr<Codec2Client::Component>
505        Codec2Client::CreateComponentByName(
506        const char* componentName,
507        const std::shared_ptr<Listener>& listener,
508        std::shared_ptr<Codec2Client>* owner) {
509    prepareClients();
510
511    c2_status_t status;
512    std::shared_ptr<Component> component;
513
514    // Cache the mapping componentName -> Codec2Client
515    static std::mutex component2ClientMutex;
516    static std::map<std::string, Codec2Client*> component2Client;
517
518    std::unique_lock<std::mutex> lock(component2ClientMutex);
519    std::map<C2String, Codec2Client*>::const_iterator it =
520            component2Client.find(componentName);
521    if (it != component2Client.end()) {
522        Codec2Client *client = it->second;
523        lock.unlock();
524
525        status = client->createComponent(
526                componentName,
527                listener,
528                &component);
529        if (status == C2_OK) {
530            return component;
531        }
532        return nullptr;
533    }
534    for (const std::shared_ptr<Codec2Client>& client : gClients) {
535        if (!client) {
536            continue;
537        }
538        status = client->createComponent(
539                componentName,
540                listener,
541                &component);
542        if (status == C2_OK) {
543            if (owner) {
544                *owner = client;
545            }
546            component2Client.emplace(componentName, client.get());
547            return component;
548        }
549    }
550    return nullptr;
551}
552
553const std::vector<C2Component::Traits>& Codec2Client::ListComponents() {
554    prepareClients();
555
556    static std::vector<C2Component::Traits> traitsList = [](){
557        std::vector<C2Component::Traits> list;
558        size_t listSize = 0;
559        for (const std::shared_ptr<Codec2Client>& client : gClients) {
560            if (!client) {
561                continue;
562            }
563            listSize += client->listComponents().size();
564        }
565        list.reserve(listSize);
566        for (const std::shared_ptr<Codec2Client>& client : gClients) {
567            if (!client) {
568                continue;
569            }
570            list.insert(
571                    list.end(),
572                    client->listComponents().begin(),
573                    client->listComponents().end());
574        }
575        return list;
576    }();
577
578    return traitsList;
579}
580
581// Codec2Client::Listener
582
583Codec2Client::Listener::~Listener() {
584}
585
586// Codec2Client::Component
587
588Codec2Client::Component::Base* Codec2Client::Component::base() const {
589    return static_cast<Base*>(mBase.get());
590}
591
592Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
593    Codec2Client::Configurable(base) {
594}
595
596c2_status_t Codec2Client::Component::createBlockPool(
597        C2Allocator::id_t id,
598        C2BlockPool::local_id_t* localId,
599        std::shared_ptr<Codec2Client::Configurable>* configurable) {
600    c2_status_t status;
601    Return<void> transStatus = base()->createBlockPool(
602            static_cast<uint32_t>(id),
603            [&status, localId, configurable](
604                    Status s,
605                    uint64_t pId,
606                    const sp<IConfigurable>& c) {
607                status = static_cast<c2_status_t>(s);
608                if (status != C2_OK) {
609                    ALOGE("createBlockPool -- call failed. "
610                            "Error code = %d", static_cast<int>(status));
611                    return;
612                }
613                *localId = static_cast<C2BlockPool::local_id_t>(pId);
614                *configurable = std::make_shared<Codec2Client::Configurable>(c);
615            });
616    if (!transStatus.isOk()) {
617        ALOGE("createBlockPool -- transaction failed.");
618        return C2_TRANSACTION_FAILED;
619    }
620    return status;
621}
622
623c2_status_t Codec2Client::Component::queue(
624        std::list<std::unique_ptr<C2Work>>* const items) {
625    WorkBundle workBundle;
626    Status hidlStatus = objcpy(&workBundle, *items);
627    if (hidlStatus != Status::OK) {
628        ALOGE("queue -- bad input.");
629        return C2_TRANSACTION_FAILED;
630    }
631    Return<Status> transStatus = base()->queue(workBundle);
632    if (!transStatus.isOk()) {
633        ALOGE("queue -- transaction failed.");
634        return C2_TRANSACTION_FAILED;
635    }
636    c2_status_t status =
637            static_cast<c2_status_t>(static_cast<Status>(transStatus));
638    if (status != C2_OK) {
639        ALOGE("queue -- call failed. "
640                "Error code = %d", static_cast<int>(status));
641    }
642    return status;
643}
644
645c2_status_t Codec2Client::Component::flush(
646        C2Component::flush_mode_t mode,
647        std::list<std::unique_ptr<C2Work>>* const flushedWork) {
648    (void)mode; // Flush mode isn't supported in HIDL yet.
649    c2_status_t status;
650    Return<void> transStatus = base()->flush(
651            [&status, flushedWork](
652                    Status s, const WorkBundle& wb) {
653                status = static_cast<c2_status_t>(s);
654                if (status != C2_OK) {
655                    ALOGE("flush -- call failed. "
656                            "Error code = %d", static_cast<int>(status));
657                    return;
658                }
659                status = objcpy(flushedWork, wb);
660            });
661    if (!transStatus.isOk()) {
662        ALOGE("flush -- transaction failed.");
663        return C2_TRANSACTION_FAILED;
664    }
665    return status;
666}
667
668c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
669    Return<Status> transStatus = base()->drain(
670            mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
671    if (!transStatus.isOk()) {
672        ALOGE("drain -- transaction failed.");
673        return C2_TRANSACTION_FAILED;
674    }
675    c2_status_t status =
676            static_cast<c2_status_t>(static_cast<Status>(transStatus));
677    if (status != C2_OK) {
678        ALOGE("drain -- call failed. "
679                "Error code = %d", static_cast<int>(status));
680    }
681    return status;
682}
683
684c2_status_t Codec2Client::Component::start() {
685    Return<Status> transStatus = base()->start();
686    if (!transStatus.isOk()) {
687        ALOGE("start -- transaction failed.");
688        return C2_TRANSACTION_FAILED;
689    }
690    c2_status_t status =
691            static_cast<c2_status_t>(static_cast<Status>(transStatus));
692    if (status != C2_OK) {
693        ALOGE("start -- call failed. "
694                "Error code = %d", static_cast<int>(status));
695    }
696    return status;
697}
698
699c2_status_t Codec2Client::Component::stop() {
700    Return<Status> transStatus = base()->stop();
701    if (!transStatus.isOk()) {
702        ALOGE("stop -- transaction failed.");
703        return C2_TRANSACTION_FAILED;
704    }
705    c2_status_t status =
706            static_cast<c2_status_t>(static_cast<Status>(transStatus));
707    if (status != C2_OK) {
708        ALOGE("stop -- call failed. "
709                "Error code = %d", static_cast<int>(status));
710    }
711    return status;
712}
713
714c2_status_t Codec2Client::Component::reset() {
715    Return<Status> transStatus = base()->reset();
716    if (!transStatus.isOk()) {
717        ALOGE("reset -- transaction failed.");
718        return C2_TRANSACTION_FAILED;
719    }
720    c2_status_t status =
721            static_cast<c2_status_t>(static_cast<Status>(transStatus));
722    if (status != C2_OK) {
723        ALOGE("reset -- call failed. "
724                "Error code = %d", static_cast<int>(status));
725    }
726    return status;
727}
728
729c2_status_t Codec2Client::Component::release() {
730    Return<Status> transStatus = base()->release();
731    if (!transStatus.isOk()) {
732        ALOGE("release -- transaction failed.");
733        return C2_TRANSACTION_FAILED;
734    }
735    c2_status_t status =
736            static_cast<c2_status_t>(static_cast<Status>(transStatus));
737    if (status != C2_OK) {
738        ALOGE("release -- call failed. "
739                "Error code = %d", static_cast<int>(status));
740    }
741    return status;
742}
743
744c2_status_t Codec2Client::Component::setOutputSurface(
745        const sp<IGraphicBufferProducer>& surface) {
746    Return<Status> transStatus = base()->setOutputSurface(surface);
747    if (!transStatus.isOk()) {
748        ALOGE("setOutputSurface -- transaction failed.");
749        return C2_TRANSACTION_FAILED;
750    }
751    c2_status_t status =
752            static_cast<c2_status_t>(static_cast<Status>(transStatus));
753    if (status != C2_OK) {
754        ALOGE("setOutputSurface -- call failed. "
755                "Error code = %d", static_cast<int>(status));
756    }
757    return status;
758}
759
760c2_status_t Codec2Client::Component::connectToInputSurface(
761        const std::shared_ptr<InputSurface>& surface) {
762    Return<Status> transStatus = base()->connectToInputSurface(
763            surface->base());
764    if (!transStatus.isOk()) {
765        ALOGE("connectToInputSurface -- transaction failed.");
766        return C2_TRANSACTION_FAILED;
767    }
768    c2_status_t status =
769            static_cast<c2_status_t>(static_cast<Status>(transStatus));
770    if (status != C2_OK) {
771        ALOGE("connectToInputSurface -- call failed. "
772                "Error code = %d", static_cast<int>(status));
773    }
774    return status;
775}
776
777c2_status_t Codec2Client::Component::connectToOmxInputSurface(
778        const sp<IGraphicBufferProducer>& producer,
779        const sp<IGraphicBufferSource>& source) {
780    Return<Status> transStatus = base()->connectToOmxInputSurface(
781            producer, source);
782    if (!transStatus.isOk()) {
783        ALOGE("connectToOmxInputSurface -- transaction failed.");
784        return C2_TRANSACTION_FAILED;
785    }
786    c2_status_t status =
787            static_cast<c2_status_t>(static_cast<Status>(transStatus));
788    if (status != C2_OK) {
789        ALOGE("connectToOmxInputSurface -- call failed. "
790                "Error code = %d", static_cast<int>(status));
791    }
792    return status;
793}
794
795c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
796    Return<Status> transStatus = base()->disconnectFromInputSurface();
797    if (!transStatus.isOk()) {
798        ALOGE("disconnectToInputSurface -- transaction failed.");
799        return C2_TRANSACTION_FAILED;
800    }
801    c2_status_t status =
802            static_cast<c2_status_t>(static_cast<Status>(transStatus));
803    if (status != C2_OK) {
804        ALOGE("disconnectFromInputSurface -- call failed. "
805                "Error code = %d", static_cast<int>(status));
806    }
807    return status;
808}
809
810c2_status_t Codec2Client::Component::getLocalBlockPool(
811        C2BlockPool::local_id_t id,
812        std::shared_ptr<C2BlockPool>* pool) const {
813    pool->reset();
814    if (!mBase) {
815        return C2_BAD_VALUE;
816    }
817    // TODO support pre-registered block pools
818    std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
819    std::shared_ptr<C2Allocator> allocator;
820    c2_status_t res = C2_NOT_FOUND;
821
822    switch (id) {
823    case C2BlockPool::BASIC_LINEAR:
824        res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
825        if (res == C2_OK) {
826            *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
827        }
828        break;
829    case C2BlockPool::BASIC_GRAPHIC:
830        res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
831        if (res == C2_OK) {
832            *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
833        }
834        break;
835    default:
836        break;
837    }
838    if (res != C2_OK) {
839        ALOGE("getLocalBlockPool -- failed to get pool with id %d. "
840                "Error code = %d",
841                static_cast<int>(id),
842                res);
843    }
844    return res;
845}
846
847c2_status_t Codec2Client::Component::createLocalBlockPool(
848        C2PlatformAllocatorStore::id_t allocatorId,
849        std::shared_ptr<C2BlockPool>* pool) const {
850    pool->reset();
851    if (!mBase) {
852        return C2_BAD_VALUE;
853    }
854    // TODO: support caching block pool along with GetCodec2BlockPool.
855    static std::atomic_int sBlockPoolId(C2BlockPool::PLATFORM_START);
856    std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
857    std::shared_ptr<C2Allocator> allocator;
858    c2_status_t res = C2_NOT_FOUND;
859
860    switch (allocatorId) {
861    case C2PlatformAllocatorStore::ION:
862        res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
863        if (res == C2_OK) {
864            *pool = std::make_shared<C2PooledBlockPool>(allocator, sBlockPoolId++);
865            if (!*pool) {
866                res = C2_NO_MEMORY;
867            }
868        }
869        break;
870    case C2PlatformAllocatorStore::GRALLOC:
871        // TODO: support gralloc
872        break;
873    default:
874        break;
875    }
876    if (res != C2_OK) {
877        ALOGE("createLocalBlockPool -- "
878                "failed to create pool with allocator id %d. "
879                "Error code = %d",
880                static_cast<int>(allocatorId),
881                res);
882    }
883    return res;
884}
885
886// Codec2Client::InputSurface
887
888Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
889    return static_cast<Base*>(mBase.get());
890}
891
892Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) :
893    mBase(base),
894    mGraphicBufferProducer(new
895            ::android::hardware::graphics::bufferqueue::V1_0::utils::
896            H2BGraphicBufferProducer(base)) {
897}
898
899c2_status_t Codec2Client::InputSurface::connectToComponent(
900        const std::shared_ptr<Codec2Client::Component>& component,
901        std::shared_ptr<Connection>* connection) {
902    c2_status_t status;
903    Return<void> transStatus = base()->connectToComponent(
904        component->base(),
905        [&status, connection](
906                Status s,
907                const sp<IInputSurfaceConnection>& c) {
908            status = static_cast<c2_status_t>(s);
909            if (status != C2_OK) {
910                ALOGE("connectToComponent -- call failed. "
911                        "Error code = %d", static_cast<int>(status));
912                return;
913            }
914            *connection = std::make_shared<Connection>(c);
915        });
916    if (!transStatus.isOk()) {
917        ALOGE("connect -- transaction failed.");
918        return C2_TRANSACTION_FAILED;
919    }
920    return status;
921}
922
923std::shared_ptr<Codec2Client::Configurable>
924        Codec2Client::InputSurface::getConfigurable() const {
925    Return<sp<IConfigurable>> transResult = base()->getConfigurable();
926    if (!transResult.isOk()) {
927        ALOGW("getConfigurable -- transaction failed.");
928        return nullptr;
929    }
930    if (!static_cast<sp<IConfigurable>>(transResult)) {
931        ALOGW("getConfigurable -- null pointer.");
932        return nullptr;
933    }
934    return std::make_shared<Configurable>(transResult);
935}
936
937const sp<IGraphicBufferProducer>&
938        Codec2Client::InputSurface::getGraphicBufferProducer() const {
939    return mGraphicBufferProducer;
940}
941
942// Codec2Client::InputSurfaceConnection
943
944Codec2Client::InputSurfaceConnection::Base*
945        Codec2Client::InputSurfaceConnection::base() const {
946    return static_cast<Base*>(mBase.get());
947}
948
949Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
950        const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
951    mBase(base) {
952}
953
954c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
955    Return<Status> transResult = base()->disconnect();
956    return static_cast<c2_status_t>(static_cast<Status>(transResult));
957}
958
959}  // namespace android
960
961