client.cpp revision 2cc26aada0fc1c80eb2564eb19f1b085380d07b9
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
47namespace android {
48
49using ::android::hardware::hidl_vec;
50using ::android::hardware::hidl_string;
51using ::android::hardware::Return;
52using ::android::hardware::Void;
53using ::android::TWGraphicBufferProducer;
54
55using namespace ::hardware::google::media::c2::V1_0;
56using namespace ::hardware::google::media::c2::V1_0::utils;
57using namespace ::android::hardware::media::bufferpool::V1_0;
58using namespace ::android::hardware::media::bufferpool::V1_0::implementation;
59
60namespace /* unnamed */ {
61
62// c2_status_t value that corresponds to hwbinder transaction failure.
63constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
64
65// List of known IComponentStore services.
66constexpr const char* kClientNames[] = {
67        "default",
68        "software",
69    };
70
71typedef std::array<
72        std::shared_ptr<Codec2Client>,
73        std::extent<decltype(kClientNames)>::value> ClientList;
74
75// Convenience methods to obtain known clients.
76size_t getClientCount() {
77    // TODO: this may not work if there is no default service
78    return std::extent<decltype(kClientNames)>::value;
79}
80
81std::shared_ptr<Codec2Client> getClient(size_t index) {
82    return Codec2Client::CreateFromService(kClientNames[index]);
83}
84
85ClientList 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
97const C2String& Codec2ConfigurableClient::getName() const {
98    return mName;
99}
100
101Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
102    return static_cast<Base*>(mBase.get());
103}
104
105Codec2ConfigurableClient::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
116c2_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
209c2_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
251c2_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
286c2_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
335Codec2Client::Base* Codec2Client::base() const {
336    return static_cast<Base*>(mBase.get());
337}
338
339Codec2Client::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
349c2_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
480c2_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
504c2_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
520const 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
545c2_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
555std::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
602std::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
621c2_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
665std::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
692std::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
718const 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
747Codec2Client::Listener::~Listener() {
748}
749
750// Codec2Client::Component
751
752Codec2Client::Component::Base* Codec2Client::Component::base() const {
753    return static_cast<Base*>(mBase.get());
754}
755
756Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
757    Codec2Client::Configurable(base),
758    mBufferPoolSender(nullptr) {
759}
760
761Codec2Client::Component::~Component() {
762}
763
764c2_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
792c2_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
803void 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
839c2_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
881c2_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
937c2_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
953c2_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
968c2_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
986c2_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
1004c2_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
1022c2_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
1057status_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
1124c2_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
1142c2_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
1157c2_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
1197Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
1198    return static_cast<Base*>(mBase.get());
1199}
1200
1201Codec2Client::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
1208c2_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
1232std::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
1246const sp<IGraphicBufferProducer>&
1247        Codec2Client::InputSurface::getGraphicBufferProducer() const {
1248    return mGraphicBufferProducer;
1249}
1250
1251// Codec2Client::InputSurfaceConnection
1252
1253Codec2Client::InputSurfaceConnection::Base*
1254        Codec2Client::InputSurfaceConnection::base() const {
1255    return static_cast<Base*>(mBase.get());
1256}
1257
1258Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
1259        const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
1260    mBase(base) {
1261}
1262
1263c2_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