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