1/*
2 * Copyright (C) 2017 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 "CCodec"
19#include <utils/Log.h>
20
21#include <sstream>
22#include <thread>
23
24#include <C2Config.h>
25#include <C2Debug.h>
26#include <C2ParamInternal.h>
27#include <C2PlatformSupport.h>
28#include <C2V4l2Support.h>
29
30#include <android/IOMXBufferSource.h>
31#include <android/IGraphicBufferSource.h>
32#include <cutils/properties.h>
33#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
34#include <gui/IGraphicBufferProducer.h>
35#include <gui/Surface.h>
36#include <media/omx/1.0/WOmx.h>
37#include <media/stagefright/codec2/1.0/InputSurface.h>
38#include <media/stagefright/BufferProducerWrapper.h>
39#include <media/stagefright/MediaCodecConstants.h>
40#include <media/stagefright/PersistentSurface.h>
41
42#include "C2OMXNode.h"
43#include "CCodec.h"
44#include "CCodecBufferChannel.h"
45#include "InputSurfaceWrapper.h"
46
47namespace android {
48
49using namespace std::chrono_literals;
50using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
51using BGraphicBufferSource = ::android::IGraphicBufferSource;
52
53namespace {
54
55class CCodecWatchdog : public AHandler {
56private:
57    enum {
58        kWhatRegister,
59        kWhatWatch,
60    };
61    constexpr static int64_t kWatchIntervalUs = 3000000;  // 3 secs
62
63public:
64    static sp<CCodecWatchdog> getInstance() {
65        Mutexed<sp<CCodecWatchdog>>::Locked instance(sInstance);
66        if (*instance == nullptr) {
67            *instance = new CCodecWatchdog;
68            (*instance)->init();
69        }
70        return *instance;
71    }
72
73    ~CCodecWatchdog() = default;
74
75    void registerCodec(CCodec *codec) {
76        sp<AMessage> msg = new AMessage(kWhatRegister, this);
77        msg->setPointer("codec", codec);
78        msg->post();
79    }
80
81protected:
82    void onMessageReceived(const sp<AMessage> &msg) {
83        switch (msg->what()) {
84            case kWhatRegister: {
85                void *ptr = nullptr;
86                CHECK(msg->findPointer("codec", &ptr));
87                Mutexed<std::list<wp<CCodec>>>::Locked codecs(mCodecs);
88                codecs->emplace_back((CCodec *)ptr);
89                break;
90            }
91
92            case kWhatWatch: {
93                Mutexed<std::list<wp<CCodec>>>::Locked codecs(mCodecs);
94                for (auto it = codecs->begin(); it != codecs->end(); ) {
95                    sp<CCodec> codec = it->promote();
96                    if (codec == nullptr) {
97                        it = codecs->erase(it);
98                        continue;
99                    }
100                    codec->initiateReleaseIfStuck();
101                    ++it;
102                }
103                msg->post(kWatchIntervalUs);
104                break;
105            }
106
107            default: {
108                TRESPASS("CCodecWatchdog: unrecognized message");
109            }
110        }
111    }
112
113private:
114    CCodecWatchdog() : mLooper(new ALooper) {}
115
116    void init() {
117        mLooper->setName("CCodecWatchdog");
118        mLooper->registerHandler(this);
119        mLooper->start();
120        (new AMessage(kWhatWatch, this))->post(kWatchIntervalUs);
121    }
122
123    static Mutexed<sp<CCodecWatchdog>> sInstance;
124
125    sp<ALooper> mLooper;
126    Mutexed<std::list<wp<CCodec>>> mCodecs;
127};
128
129Mutexed<sp<CCodecWatchdog>> CCodecWatchdog::sInstance;
130
131class C2InputSurfaceWrapper : public InputSurfaceWrapper {
132public:
133    explicit C2InputSurfaceWrapper(
134            const std::shared_ptr<Codec2Client::InputSurface> &surface) :
135        mSurface(surface) {
136    }
137
138    ~C2InputSurfaceWrapper() override = default;
139
140    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
141        if (mConnection != nullptr) {
142            return ALREADY_EXISTS;
143        }
144        return static_cast<status_t>(
145                mSurface->connectToComponent(comp, &mConnection));
146    }
147
148    void disconnect() override {
149        if (mConnection != nullptr) {
150            mConnection->disconnect();
151            mConnection = nullptr;
152        }
153    }
154
155    status_t signalEndOfInputStream() override {
156        C2InputSurfaceEosTuning eos(true);
157        std::vector<std::unique_ptr<C2SettingResult>> failures;
158        c2_status_t err = mSurface->getConfigurable()->config({&eos}, C2_MAY_BLOCK, &failures);
159        if (err != C2_OK) {
160            return UNKNOWN_ERROR;
161        }
162        return OK;
163    }
164
165    status_t configure(Config &config __unused) {
166        // TODO
167        return OK;
168    }
169
170private:
171    std::shared_ptr<Codec2Client::InputSurface> mSurface;
172    std::shared_ptr<Codec2Client::InputSurfaceConnection> mConnection;
173};
174
175class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
176public:
177//    explicit GraphicBufferSourceWrapper(const sp<BGraphicBufferSource> &source) : mSource(source) {}
178    GraphicBufferSourceWrapper(
179            const sp<BGraphicBufferSource> &source,
180            uint32_t width,
181            uint32_t height)
182        : mSource(source), mWidth(width), mHeight(height) {}
183    ~GraphicBufferSourceWrapper() override = default;
184
185    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
186        // TODO: proper color aspect & dataspace
187        android_dataspace dataSpace = HAL_DATASPACE_BT709;
188
189        mNode = new C2OMXNode(comp);
190        mNode->setFrameSize(mWidth, mHeight);
191        mSource->configure(mNode, dataSpace);
192
193        // TODO: configure according to intf().
194        // TODO: initial color aspects (dataspace)
195
196        sp<IOMXBufferSource> source = mNode->getSource();
197        if (source == nullptr) {
198            return NO_INIT;
199        }
200        constexpr size_t kNumSlots = 16;
201        for (size_t i = 0; i < kNumSlots; ++i) {
202            source->onInputBufferAdded(i);
203        }
204        source->onOmxExecuting();
205        return OK;
206    }
207
208    void disconnect() override {
209        if (mNode == nullptr) {
210            return;
211        }
212        sp<IOMXBufferSource> source = mNode->getSource();
213        if (source == nullptr) {
214            ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
215            return;
216        }
217        source->onOmxIdle();
218        source->onOmxLoaded();
219        mNode.clear();
220    }
221
222    status_t GetStatus(const binder::Status &status) {
223        status_t err = OK;
224        if (!status.isOk()) {
225            err = status.serviceSpecificErrorCode();
226            if (err == OK) {
227                err = status.transactionError();
228                if (err == OK) {
229                    // binder status failed, but there is no servie or transaction error
230                    err = UNKNOWN_ERROR;
231                }
232            }
233        }
234        return err;
235    }
236
237    status_t signalEndOfInputStream() override {
238        return GetStatus(mSource->signalEndOfInputStream());
239    }
240
241    status_t configure(Config &config) {
242        std::stringstream status;
243        status_t err = OK;
244
245        // handle each configuration granually, in case we need to handle part of the configuration
246        // elsewhere
247
248        // TRICKY: we do not unset frame delay repeating
249        if (config.mMinFps > 0 && config.mMinFps != mConfig.mMinFps) {
250            int64_t us = 1e6 / config.mMinFps + 0.5;
251            status_t res = GetStatus(mSource->setRepeatPreviousFrameDelayUs(us));
252            status << " minFps=" << config.mMinFps << " => repeatDelayUs=" << us;
253            if (res != OK) {
254                status << " (=> " << asString(res) << ")";
255                err = res;
256            }
257            mConfig.mMinFps = config.mMinFps;
258        }
259
260        // TODO: pts gap
261
262        // max fps
263        // TRICKY: we do not unset max fps to 0 unless using fixed fps
264        if ((config.mMaxFps > 0 || (config.mFixedAdjustedFps > 0 && config.mMaxFps == 0))
265                && config.mMaxFps != mConfig.mMaxFps) {
266            status_t res = GetStatus(mSource->setMaxFps(config.mMaxFps));
267            status << " maxFps=" << config.mMaxFps;
268            if (res != OK) {
269                status << " (=> " << asString(res) << ")";
270                err = res;
271            }
272            mConfig.mMaxFps = config.mMaxFps;
273        }
274
275        if (config.mTimeOffsetUs != mConfig.mTimeOffsetUs) {
276            status_t res = GetStatus(mSource->setTimeOffsetUs(config.mTimeOffsetUs));
277            status << " timeOffset " << config.mTimeOffsetUs << "us";
278            if (res != OK) {
279                status << " (=> " << asString(res) << ")";
280                err = res;
281            }
282            mConfig.mTimeOffsetUs = config.mTimeOffsetUs;
283        }
284
285        // TODO: time lapse config
286
287        if (config.mStartAtUs != mConfig.mStartAtUs
288                || (config.mStopped != mConfig.mStopped && !config.mStopped)) {
289            status_t res = GetStatus(mSource->setStartTimeUs(config.mStartAtUs));
290            status << " start at " << config.mStartAtUs << "us";
291            if (res != OK) {
292                status << " (=> " << asString(res) << ")";
293                err = res;
294            }
295            mConfig.mStartAtUs = config.mStartAtUs;
296            mConfig.mStopped = config.mStopped;
297        }
298
299        // suspend-resume
300        if (config.mSuspended != mConfig.mSuspended) {
301            status_t res = GetStatus(mSource->setSuspend(config.mSuspended, config.mSuspendAtUs));
302            status << " " << (config.mSuspended ? "suspend" : "resume")
303                    << " at " << config.mSuspendAtUs << "us";
304            if (res != OK) {
305                status << " (=> " << asString(res) << ")";
306                err = res;
307            }
308            mConfig.mSuspended = config.mSuspended;
309            mConfig.mSuspendAtUs = config.mSuspendAtUs;
310        }
311
312        if (config.mStopped != mConfig.mStopped && config.mStopped) {
313            status_t res = GetStatus(mSource->setStopTimeUs(config.mStopAtUs));
314            status << " stop at " << config.mStopAtUs << "us";
315            if (res != OK) {
316                status << " (=> " << asString(res) << ")";
317                err = res;
318            } else {
319                status << " delayUs";
320                res = GetStatus(mSource->getStopTimeOffsetUs(&config.mInputDelayUs));
321                if (res != OK) {
322                    status << " (=> " << asString(res) << ")";
323                } else {
324                    status << "=" << config.mInputDelayUs << "us";
325                }
326                mConfig.mInputDelayUs = config.mInputDelayUs;
327            }
328            mConfig.mStopAtUs = config.mStopAtUs;
329            mConfig.mStopped = config.mStopped;
330        }
331
332        // color aspects (android._color-aspects)
333
334        // consumer usage
335        ALOGD("ISConfig%s", status.str().c_str());
336        return err;
337    }
338
339private:
340    sp<BGraphicBufferSource> mSource;
341    sp<C2OMXNode> mNode;
342    uint32_t mWidth;
343    uint32_t mHeight;
344    Config mConfig;
345};
346
347class Codec2ClientInterfaceWrapper : public C2ComponentStore {
348    std::shared_ptr<Codec2Client> mClient;
349
350public:
351    Codec2ClientInterfaceWrapper(std::shared_ptr<Codec2Client> client)
352        : mClient(client) { }
353
354    virtual ~Codec2ClientInterfaceWrapper() = default;
355
356    virtual c2_status_t config_sm(
357            const std::vector<C2Param *> &params,
358            std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
359        return mClient->config(params, C2_MAY_BLOCK, failures);
360    };
361
362    virtual c2_status_t copyBuffer(
363            std::shared_ptr<C2GraphicBuffer>,
364            std::shared_ptr<C2GraphicBuffer>) {
365        return C2_OMITTED;
366    }
367
368    virtual c2_status_t createComponent(
369            C2String, std::shared_ptr<C2Component> *const component) {
370        component->reset();
371        return C2_OMITTED;
372    }
373
374    virtual c2_status_t createInterface(
375            C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
376        interface->reset();
377        return C2_OMITTED;
378    }
379
380    virtual c2_status_t query_sm(
381            const std::vector<C2Param *> &stackParams,
382            const std::vector<C2Param::Index> &heapParamIndices,
383            std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
384        return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
385    }
386
387    virtual c2_status_t querySupportedParams_nb(
388            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
389        return mClient->querySupportedParams(params);
390    }
391
392    virtual c2_status_t querySupportedValues_sm(
393            std::vector<C2FieldSupportedValuesQuery> &fields) const {
394        return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
395    }
396
397    virtual C2String getName() const {
398        return mClient->getName();
399    }
400
401    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
402        return mClient->getParamReflector();
403    }
404
405    virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() {
406        return std::vector<std::shared_ptr<const C2Component::Traits>>();
407    }
408};
409
410}  // namespace
411
412// CCodec::ClientListener
413
414struct CCodec::ClientListener : public Codec2Client::Listener {
415
416    explicit ClientListener(const wp<CCodec> &codec) : mCodec(codec) {}
417
418    virtual void onWorkDone(
419            const std::weak_ptr<Codec2Client::Component>& component,
420            std::list<std::unique_ptr<C2Work>>& workItems) override {
421        (void)component;
422        sp<CCodec> codec(mCodec.promote());
423        if (!codec) {
424            return;
425        }
426        codec->onWorkDone(workItems);
427    }
428
429    virtual void onTripped(
430            const std::weak_ptr<Codec2Client::Component>& component,
431            const std::vector<std::shared_ptr<C2SettingResult>>& settingResult
432            ) override {
433        // TODO
434        (void)component;
435        (void)settingResult;
436    }
437
438    virtual void onError(
439            const std::weak_ptr<Codec2Client::Component>& component,
440            uint32_t errorCode) override {
441        // TODO
442        (void)component;
443        (void)errorCode;
444    }
445
446    virtual void onDeath(
447            const std::weak_ptr<Codec2Client::Component>& component) override {
448        { // Log the death of the component.
449            std::shared_ptr<Codec2Client::Component> comp = component.lock();
450            if (!comp) {
451                ALOGE("Codec2 component died.");
452            } else {
453                ALOGE("Codec2 component \"%s\" died.", comp->getName().c_str());
454            }
455        }
456
457        // Report to MediaCodec.
458        sp<CCodec> codec(mCodec.promote());
459        if (!codec || !codec->mCallback) {
460            return;
461        }
462        codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL);
463    }
464
465    virtual void onFramesRendered(
466            const std::vector<RenderedFrame>& renderedFrames) override {
467        // TODO
468        (void)renderedFrames;
469    }
470
471private:
472    wp<CCodec> mCodec;
473};
474
475// CCodecCallbackImpl
476
477class CCodecCallbackImpl : public CCodecCallback {
478public:
479    explicit CCodecCallbackImpl(CCodec *codec) : mCodec(codec) {}
480    ~CCodecCallbackImpl() override = default;
481
482    void onError(status_t err, enum ActionCode actionCode) override {
483        mCodec->mCallback->onError(err, actionCode);
484    }
485
486    void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override {
487        mCodec->mCallback->onOutputFramesRendered(
488                {RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
489    }
490
491private:
492    CCodec *mCodec;
493};
494
495// CCodec
496
497CCodec::CCodec()
498    : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))) {
499    CCodecWatchdog::getInstance()->registerCodec(this);
500}
501
502CCodec::~CCodec() {
503}
504
505std::shared_ptr<BufferChannelBase> CCodec::getBufferChannel() {
506    return mChannel;
507}
508
509status_t CCodec::tryAndReportOnError(std::function<status_t()> job) {
510    status_t err = job();
511    if (err != C2_OK) {
512        mCallback->onError(err, ACTION_CODE_FATAL);
513    }
514    return err;
515}
516
517void CCodec::initiateAllocateComponent(const sp<AMessage> &msg) {
518    auto setAllocating = [this] {
519        Mutexed<State>::Locked state(mState);
520        if (state->get() != RELEASED) {
521            return INVALID_OPERATION;
522        }
523        state->set(ALLOCATING);
524        return OK;
525    };
526    if (tryAndReportOnError(setAllocating) != OK) {
527        return;
528    }
529
530    sp<RefBase> codecInfo;
531    CHECK(msg->findObject("codecInfo", &codecInfo));
532    // For Codec 2.0 components, componentName == codecInfo->getCodecName().
533
534    sp<AMessage> allocMsg(new AMessage(kWhatAllocate, this));
535    allocMsg->setObject("codecInfo", codecInfo);
536    allocMsg->post();
537}
538
539void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) {
540    if (codecInfo == nullptr) {
541        mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
542        return;
543    }
544    ALOGV("allocate(%s)", codecInfo->getCodecName());
545    mClientListener.reset(new ClientListener(this));
546
547    AString componentName = codecInfo->getCodecName();
548    std::shared_ptr<Codec2Client> client;
549
550    // set up preferred component store to access vendor store parameters
551    client = Codec2Client::CreateFromService("default", false);
552    if (client) {
553        ALOGI("setting up '%s' as default (vendor) store", client->getInstanceName().c_str());
554        SetPreferredCodec2ComponentStore(
555                std::make_shared<Codec2ClientInterfaceWrapper>(client));
556    }
557
558    std::shared_ptr<Codec2Client::Component> comp =
559            Codec2Client::CreateComponentByName(
560            componentName.c_str(),
561            mClientListener,
562            &client);
563    if (!comp) {
564        ALOGE("Failed Create component: %s", componentName.c_str());
565        Mutexed<State>::Locked state(mState);
566        state->set(RELEASED);
567        state.unlock();
568        mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
569        state.lock();
570        return;
571    }
572    ALOGI("Created component [%s]", componentName.c_str());
573    mChannel->setComponent(comp);
574    auto setAllocated = [this, comp, client] {
575        Mutexed<State>::Locked state(mState);
576        if (state->get() != ALLOCATING) {
577            state->set(RELEASED);
578            return UNKNOWN_ERROR;
579        }
580        state->set(ALLOCATED);
581        state->comp = comp;
582        mClient = client;
583        return OK;
584    };
585    if (tryAndReportOnError(setAllocated) != OK) {
586        return;
587    }
588
589    // initialize config here in case setParameters is called prior to configure
590    Mutexed<Config>::Locked config(mConfig);
591    status_t err = config->initialize(mClient, comp);
592    if (err != OK) {
593        ALOGW("Failed to initialize configuration support");
594        // TODO: report error once we complete implementation.
595    }
596    config->queryConfiguration(comp);
597
598    mCallback->onComponentAllocated(comp->getName().c_str());
599}
600
601void CCodec::initiateConfigureComponent(const sp<AMessage> &format) {
602    auto checkAllocated = [this] {
603        Mutexed<State>::Locked state(mState);
604        return (state->get() != ALLOCATED) ? UNKNOWN_ERROR : OK;
605    };
606    if (tryAndReportOnError(checkAllocated) != OK) {
607        return;
608    }
609
610    sp<AMessage> msg(new AMessage(kWhatConfigure, this));
611    msg->setMessage("format", format);
612    msg->post();
613}
614
615void CCodec::configure(const sp<AMessage> &msg) {
616    std::shared_ptr<Codec2Client::Component> comp;
617    auto checkAllocated = [this, &comp] {
618        Mutexed<State>::Locked state(mState);
619        if (state->get() != ALLOCATED) {
620            state->set(RELEASED);
621            return UNKNOWN_ERROR;
622        }
623        comp = state->comp;
624        return OK;
625    };
626    if (tryAndReportOnError(checkAllocated) != OK) {
627        return;
628    }
629
630    auto doConfig = [msg, comp, this]() -> status_t {
631        AString mime;
632        if (!msg->findString("mime", &mime)) {
633            return BAD_VALUE;
634        }
635
636        int32_t encoder;
637        if (!msg->findInt32("encoder", &encoder)) {
638            encoder = false;
639        }
640
641        // TODO: read from intf()
642        if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) {
643            return UNKNOWN_ERROR;
644        }
645
646        int32_t storeMeta;
647        if (encoder
648                && msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
649                && storeMeta != kMetadataBufferTypeInvalid) {
650            if (storeMeta != kMetadataBufferTypeANWBuffer) {
651                ALOGD("Only ANW buffers are supported for legacy metadata mode");
652                return BAD_VALUE;
653            }
654            mChannel->setMetaMode(CCodecBufferChannel::MODE_ANW);
655        }
656
657        sp<RefBase> obj;
658        sp<Surface> surface;
659        if (msg->findObject("native-window", &obj)) {
660            surface = static_cast<Surface *>(obj.get());
661            setSurface(surface);
662        }
663
664        Mutexed<Config>::Locked config(mConfig);
665
666        /*
667         * Handle input surface configuration
668         */
669        if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
670                && (config->mDomain & Config::IS_ENCODER)) {
671            config->mISConfig.reset(new InputSurfaceWrapper::Config{});
672            {
673                config->mISConfig->mMinFps = 0;
674                int64_t value;
675                if (msg->findInt64("repeat-previous-frame-after", &value) && value > 0) {
676                    config->mISConfig->mMinFps = 1e6 / value;
677                }
678                (void)msg->findFloat("max-fps-to-encoder", &config->mISConfig->mMaxFps);
679                config->mISConfig->mMinAdjustedFps = 0;
680                config->mISConfig->mFixedAdjustedFps = 0;
681                if (msg->findInt64("max-pts-gap-to-encoder", &value)) {
682                    if (value < 0 && value >= INT32_MIN) {
683                        config->mISConfig->mFixedAdjustedFps = -1e6 / value;
684                    } else if (value > 0 && value <= INT32_MAX) {
685                        config->mISConfig->mMinAdjustedFps = 1e6 / value;
686                    }
687                }
688            }
689
690            {
691                double value;
692                if (!msg->findDouble("time-lapse-fps", &value)) {
693                    config->mISConfig->mCaptureFps = value;
694                }
695            }
696
697            {
698                config->mISConfig->mSuspended = false;
699                config->mISConfig->mSuspendAtUs = -1;
700                int32_t value;
701                if (msg->findInt32("create-input-buffers-suspended", &value) && value) {
702                    config->mISConfig->mSuspended = true;
703                }
704            }
705        }
706
707        /*
708         * Handle desired color format.
709         */
710        if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
711            int32_t format = -1;
712            if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) {
713                /*
714                 * Also handle default color format (encoders require color format, so this is only
715                 * needed for decoders.
716                 */
717                if (!(config->mDomain & Config::IS_ENCODER)) {
718                    format = (surface == nullptr) ? COLOR_FormatYUV420Planar : COLOR_FormatSurface;
719                }
720            }
721
722            if (format >= 0) {
723                msg->setInt32("android._color-format", format);
724            }
725        }
726
727        std::vector<std::unique_ptr<C2Param>> configUpdate;
728        status_t err = config->getConfigUpdateFromSdkParams(
729                comp, msg, Config::CONFIG, C2_DONT_BLOCK, &configUpdate);
730        if (err != OK) {
731            ALOGW("failed to convert configuration to c2 params");
732        }
733        err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK);
734        if (err != OK) {
735            ALOGW("failed to configure c2 params");
736            return err;
737        }
738
739        std::vector<std::unique_ptr<C2Param>> params;
740        C2StreamUsageTuning::input usage(0u, 0u);
741        C2StreamMaxBufferSizeInfo::input maxInputSize(0u, 0u);
742
743        std::initializer_list<C2Param::Index> indices {
744        };
745        c2_status_t c2err = comp->query(
746                { &usage, &maxInputSize },
747                indices,
748                C2_DONT_BLOCK,
749                &params);
750        if (c2err != C2_OK && c2err != C2_BAD_INDEX) {
751            ALOGE("Failed to query component interface: %d", c2err);
752            return UNKNOWN_ERROR;
753        }
754        if (params.size() != indices.size()) {
755            ALOGE("Component returns wrong number of params: expected %zu actual %zu",
756                    indices.size(), params.size());
757            return UNKNOWN_ERROR;
758        }
759        if (usage && (usage.value & C2MemoryUsage::CPU_READ)) {
760            config->mInputFormat->setInt32("using-sw-read-often", true);
761        }
762
763        // use client specified input size if specified
764        bool clientInputSize = msg->findInt32(KEY_MAX_INPUT_SIZE, (int32_t*)&maxInputSize.value);
765
766        // TEMP: enforce minimum buffer size of 1MB for video decoders
767        if (!clientInputSize && maxInputSize.value == 0
768                && !encoder && !(config->mDomain & Config::IS_AUDIO)) {
769            maxInputSize.value = 1048576u;
770        }
771
772        // TODO: do this based on component requiring linear allocator for input
773        if ((config->mDomain & Config::IS_DECODER) || (config->mDomain & Config::IS_AUDIO)) {
774            // Pass max input size on input format to the buffer channel (if supplied by the
775            // component or by a default)
776            if (maxInputSize.value) {
777                config->mInputFormat->setInt32(
778                        KEY_MAX_INPUT_SIZE,
779                        (int32_t)(c2_min(maxInputSize.value, uint32_t(INT32_MAX))));
780            }
781        }
782
783        if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
784            // Set desired color format from configuration parameter
785            int32_t format;
786            if (msg->findInt32("android._color-format", &format)) {
787                if (config->mDomain & Config::IS_ENCODER) {
788                    config->mInputFormat->setInt32(KEY_COLOR_FORMAT, format);
789                } else {
790                    config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format);
791                }
792            }
793        }
794
795        // propagate encoder delay and padding to output format
796        if ((config->mDomain & Config::IS_DECODER) && (config->mDomain & Config::IS_AUDIO)) {
797            int delay = 0;
798            if (msg->findInt32("encoder-delay", &delay)) {
799                config->mOutputFormat->setInt32("encoder-delay", delay);
800            }
801            int padding = 0;
802            if (msg->findInt32("encoder-padding", &padding)) {
803                config->mOutputFormat->setInt32("encoder-padding", padding);
804            }
805        }
806
807        ALOGD("setup formats input: %s and output: %s",
808                config->mInputFormat->debugString().c_str(),
809                config->mOutputFormat->debugString().c_str());
810        return OK;
811    };
812    if (tryAndReportOnError(doConfig) != OK) {
813        return;
814    }
815
816    Mutexed<Config>::Locked config(mConfig);
817
818    mCallback->onComponentConfigured(config->mInputFormat, config->mOutputFormat);
819}
820
821void CCodec::initiateCreateInputSurface() {
822    status_t err = [this] {
823        Mutexed<State>::Locked state(mState);
824        if (state->get() != ALLOCATED) {
825            return UNKNOWN_ERROR;
826        }
827        // TODO: read it from intf() properly.
828        if (state->comp->getName().find("encoder") == std::string::npos) {
829            return INVALID_OPERATION;
830        }
831        return OK;
832    }();
833    if (err != OK) {
834        mCallback->onInputSurfaceCreationFailed(err);
835        return;
836    }
837
838    (new AMessage(kWhatCreateInputSurface, this))->post();
839}
840
841void CCodec::createInputSurface() {
842    status_t err;
843    sp<IGraphicBufferProducer> bufferProducer;
844
845    sp<AMessage> inputFormat;
846    sp<AMessage> outputFormat;
847    {
848        Mutexed<Config>::Locked config(mConfig);
849        inputFormat = config->mInputFormat;
850        outputFormat = config->mOutputFormat;
851    }
852
853    // TODO: Remove this property check and assume it's always true.
854    if (property_get_bool("debug.stagefright.c2inputsurface", false)) {
855        std::shared_ptr<Codec2Client::InputSurface> surface;
856
857        err = static_cast<status_t>(mClient->createInputSurface(&surface));
858        if (err != OK) {
859            ALOGE("Failed to create input surface: %d", static_cast<int>(err));
860            mCallback->onInputSurfaceCreationFailed(err);
861            return;
862        }
863        if (!surface) {
864            ALOGE("Failed to create input surface: null input surface");
865            mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
866            return;
867        }
868        bufferProducer = surface->getGraphicBufferProducer();
869        err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(surface));
870    } else { // TODO: Remove this block.
871        using namespace ::android::hardware::media::omx::V1_0;
872        sp<IOmx> tOmx = IOmx::getService("default");
873        if (tOmx == nullptr) {
874            ALOGE("Failed to create input surface");
875            mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
876            return;
877        }
878        sp<IOMX> omx = new utils::LWOmx(tOmx);
879
880        sp<BGraphicBufferSource> bufferSource;
881        err = omx->createInputSurface(&bufferProducer, &bufferSource);
882
883        if (err != OK) {
884            ALOGE("Failed to create input surface: %d", err);
885            mCallback->onInputSurfaceCreationFailed(err);
886            return;
887        }
888        int32_t width = 0;
889        (void)outputFormat->findInt32("width", &width);
890        int32_t height = 0;
891        (void)outputFormat->findInt32("height", &height);
892        err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
893                bufferSource, width, height));
894    }
895
896    if (err != OK) {
897        ALOGE("Failed to set up input surface: %d", err);
898        mCallback->onInputSurfaceCreationFailed(err);
899        return;
900    }
901    mCallback->onInputSurfaceCreated(
902            inputFormat,
903            outputFormat,
904            new BufferProducerWrapper(bufferProducer));
905}
906
907status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) {
908    status_t err = mChannel->setInputSurface(surface);
909    if (err != OK) {
910        return err;
911    }
912
913    Mutexed<Config>::Locked config(mConfig);
914    config->mInputSurface = surface;
915    if (config->mISConfig) {
916        surface->configure(*config->mISConfig);
917    } else {
918        ALOGD("ISConfig: no configuration");
919    }
920
921    // TODO: configure |surface| with other settings.
922    return OK;
923}
924
925void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
926    sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this);
927    msg->setObject("surface", surface);
928    msg->post();
929}
930
931void CCodec::setInputSurface(const sp<PersistentSurface> &surface) {
932    sp<AMessage> inputFormat;
933    sp<AMessage> outputFormat;
934    {
935        Mutexed<Config>::Locked config(mConfig);
936        inputFormat = config->mInputFormat;
937        outputFormat = config->mOutputFormat;
938    }
939    int32_t width = 0;
940    (void)outputFormat->findInt32("width", &width);
941    int32_t height = 0;
942    (void)outputFormat->findInt32("height", &height);
943    status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
944            surface->getBufferSource(), width, height));
945    if (err != OK) {
946        ALOGE("Failed to set up input surface: %d", err);
947        mCallback->onInputSurfaceDeclined(err);
948        return;
949    }
950    mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
951}
952
953void CCodec::initiateStart() {
954    auto setStarting = [this] {
955        Mutexed<State>::Locked state(mState);
956        if (state->get() != ALLOCATED) {
957            return UNKNOWN_ERROR;
958        }
959        state->set(STARTING);
960        return OK;
961    };
962    if (tryAndReportOnError(setStarting) != OK) {
963        return;
964    }
965
966    (new AMessage(kWhatStart, this))->post();
967}
968
969void CCodec::start() {
970    std::shared_ptr<Codec2Client::Component> comp;
971    auto checkStarting = [this, &comp] {
972        Mutexed<State>::Locked state(mState);
973        if (state->get() != STARTING) {
974            return UNKNOWN_ERROR;
975        }
976        comp = state->comp;
977        return OK;
978    };
979    if (tryAndReportOnError(checkStarting) != OK) {
980        return;
981    }
982
983    c2_status_t err = comp->start();
984    if (err != C2_OK) {
985        // TODO: convert err into status_t
986        mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
987        return;
988    }
989    sp<AMessage> inputFormat;
990    sp<AMessage> outputFormat;
991    {
992        Mutexed<Config>::Locked config(mConfig);
993        inputFormat = config->mInputFormat;
994        outputFormat = config->mOutputFormat;
995    }
996    status_t err2 = mChannel->start(inputFormat, outputFormat);
997    if (err2 != OK) {
998        mCallback->onError(err2, ACTION_CODE_FATAL);
999        return;
1000    }
1001
1002    auto setRunning = [this] {
1003        Mutexed<State>::Locked state(mState);
1004        if (state->get() != STARTING) {
1005            return UNKNOWN_ERROR;
1006        }
1007        state->set(RUNNING);
1008        return OK;
1009    };
1010    if (tryAndReportOnError(setRunning) != OK) {
1011        return;
1012    }
1013    mCallback->onStartCompleted();
1014}
1015
1016void CCodec::initiateShutdown(bool keepComponentAllocated) {
1017    if (keepComponentAllocated) {
1018        initiateStop();
1019    } else {
1020        initiateRelease();
1021    }
1022}
1023
1024void CCodec::initiateStop() {
1025    {
1026        Mutexed<State>::Locked state(mState);
1027        if (state->get() == ALLOCATED
1028                || state->get()  == RELEASED
1029                || state->get() == STOPPING
1030                || state->get() == RELEASING) {
1031            // We're already stopped, released, or doing it right now.
1032            state.unlock();
1033            mCallback->onStopCompleted();
1034            state.lock();
1035            return;
1036        }
1037        state->set(STOPPING);
1038    }
1039
1040    mChannel->stop();
1041    (new AMessage(kWhatStop, this))->post();
1042}
1043
1044void CCodec::stop() {
1045    std::shared_ptr<Codec2Client::Component> comp;
1046    {
1047        Mutexed<State>::Locked state(mState);
1048        if (state->get() == RELEASING) {
1049            state.unlock();
1050            // We're already stopped or release is in progress.
1051            mCallback->onStopCompleted();
1052            state.lock();
1053            return;
1054        } else if (state->get() != STOPPING) {
1055            state.unlock();
1056            mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1057            state.lock();
1058            return;
1059        }
1060        comp = state->comp;
1061    }
1062    status_t err = comp->stop();
1063    if (err != C2_OK) {
1064        // TODO: convert err into status_t
1065        mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1066    }
1067
1068    {
1069        Mutexed<State>::Locked state(mState);
1070        if (state->get() == STOPPING) {
1071            state->set(ALLOCATED);
1072        }
1073    }
1074    mCallback->onStopCompleted();
1075}
1076
1077void CCodec::initiateRelease(bool sendCallback /* = true */) {
1078    {
1079        Mutexed<State>::Locked state(mState);
1080        if (state->get() == RELEASED || state->get() == RELEASING) {
1081            // We're already released or doing it right now.
1082            if (sendCallback) {
1083                state.unlock();
1084                mCallback->onReleaseCompleted();
1085                state.lock();
1086            }
1087            return;
1088        }
1089        if (state->get() == ALLOCATING) {
1090            state->set(RELEASING);
1091            // With the altered state allocate() would fail and clean up.
1092            if (sendCallback) {
1093                state.unlock();
1094                mCallback->onReleaseCompleted();
1095                state.lock();
1096            }
1097            return;
1098        }
1099        state->set(RELEASING);
1100    }
1101
1102    mChannel->stop();
1103    std::thread([this, sendCallback] { release(sendCallback); }).detach();
1104}
1105
1106void CCodec::release(bool sendCallback) {
1107    std::shared_ptr<Codec2Client::Component> comp;
1108    {
1109        Mutexed<State>::Locked state(mState);
1110        if (state->get() == RELEASED) {
1111            if (sendCallback) {
1112                state.unlock();
1113                mCallback->onReleaseCompleted();
1114                state.lock();
1115            }
1116            return;
1117        }
1118        comp = state->comp;
1119    }
1120    comp->release();
1121
1122    {
1123        Mutexed<State>::Locked state(mState);
1124        state->set(RELEASED);
1125        state->comp.reset();
1126    }
1127    if (sendCallback) {
1128        mCallback->onReleaseCompleted();
1129    }
1130}
1131
1132status_t CCodec::setSurface(const sp<Surface> &surface) {
1133    return mChannel->setSurface(surface);
1134}
1135
1136void CCodec::signalFlush() {
1137    status_t err = [this] {
1138        Mutexed<State>::Locked state(mState);
1139        if (state->get() == FLUSHED) {
1140            return ALREADY_EXISTS;
1141        }
1142        if (state->get() != RUNNING) {
1143            return UNKNOWN_ERROR;
1144        }
1145        state->set(FLUSHING);
1146        return OK;
1147    }();
1148    switch (err) {
1149        case ALREADY_EXISTS:
1150            mCallback->onFlushCompleted();
1151            return;
1152        case OK:
1153            break;
1154        default:
1155            mCallback->onError(err, ACTION_CODE_FATAL);
1156            return;
1157    }
1158
1159    mChannel->stop();
1160    (new AMessage(kWhatFlush, this))->post();
1161}
1162
1163void CCodec::flush() {
1164    std::shared_ptr<Codec2Client::Component> comp;
1165    auto checkFlushing = [this, &comp] {
1166        Mutexed<State>::Locked state(mState);
1167        if (state->get() != FLUSHING) {
1168            return UNKNOWN_ERROR;
1169        }
1170        comp = state->comp;
1171        return OK;
1172    };
1173    if (tryAndReportOnError(checkFlushing) != OK) {
1174        return;
1175    }
1176
1177    std::list<std::unique_ptr<C2Work>> flushedWork;
1178    c2_status_t err = comp->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
1179    if (err != C2_OK) {
1180        // TODO: convert err into status_t
1181        mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1182    }
1183
1184    mChannel->flush(flushedWork);
1185
1186    {
1187        Mutexed<State>::Locked state(mState);
1188        state->set(FLUSHED);
1189    }
1190    mCallback->onFlushCompleted();
1191}
1192
1193void CCodec::signalResume() {
1194    auto setResuming = [this] {
1195        Mutexed<State>::Locked state(mState);
1196        if (state->get() != FLUSHED) {
1197            return UNKNOWN_ERROR;
1198        }
1199        state->set(RESUMING);
1200        return OK;
1201    };
1202    if (tryAndReportOnError(setResuming) != OK) {
1203        return;
1204    }
1205
1206    (void)mChannel->start(nullptr, nullptr);
1207
1208    {
1209        Mutexed<State>::Locked state(mState);
1210        if (state->get() != RESUMING) {
1211            state.unlock();
1212            mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1213            state.lock();
1214            return;
1215        }
1216        state->set(RUNNING);
1217    }
1218}
1219
1220void CCodec::signalSetParameters(const sp<AMessage> &params) {
1221    sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
1222    msg->setMessage("params", params);
1223    msg->post();
1224}
1225
1226void CCodec::setParameters(const sp<AMessage> &params) {
1227    std::shared_ptr<Codec2Client::Component> comp;
1228    auto checkState = [this, &comp] {
1229        Mutexed<State>::Locked state(mState);
1230        if (state->get() == RELEASED) {
1231            return INVALID_OPERATION;
1232        }
1233        comp = state->comp;
1234        return OK;
1235    };
1236    if (tryAndReportOnError(checkState) != OK) {
1237        return;
1238    }
1239
1240    Mutexed<Config>::Locked config(mConfig);
1241
1242    /**
1243     * Handle input surface parameters
1244     */
1245    if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
1246            && (config->mDomain & Config::IS_ENCODER) && config->mInputSurface && config->mISConfig) {
1247        (void)params->findInt64("time-offset-us", &config->mISConfig->mTimeOffsetUs);
1248
1249        if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) {
1250            config->mISConfig->mStopped = false;
1251        } else if (params->findInt64("stop-time-us", &config->mISConfig->mStopAtUs)) {
1252            config->mISConfig->mStopped = true;
1253        }
1254
1255        int32_t value;
1256        if (params->findInt32("drop-input-frames", &value)) {
1257            config->mISConfig->mSuspended = value;
1258            config->mISConfig->mSuspendAtUs = -1;
1259            (void)params->findInt64("drop-start-time-us", &config->mISConfig->mSuspendAtUs);
1260        }
1261
1262        (void)config->mInputSurface->configure(*config->mISConfig);
1263        if (config->mISConfig->mStopped) {
1264            config->mInputFormat->setInt64(
1265                    "android._stop-time-offset-us", config->mISConfig->mInputDelayUs);
1266        }
1267    }
1268
1269    std::vector<std::unique_ptr<C2Param>> configUpdate;
1270    (void)config->getConfigUpdateFromSdkParams(comp, params, Config::PARAM, C2_MAY_BLOCK, &configUpdate);
1271    if (property_get_bool("debug.stagefright.ccodec_delayed_params", false)) {
1272        // mChannel->queueConfigUpdate(configUpdate);
1273    } else {
1274        (void)config->setParameters(comp, configUpdate, C2_MAY_BLOCK);
1275    }
1276}
1277
1278void CCodec::signalEndOfInputStream() {
1279    mCallback->onSignaledInputEOS(mChannel->signalEndOfInputStream());
1280}
1281
1282void CCodec::signalRequestIDRFrame() {
1283    // TODO
1284}
1285
1286void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
1287    Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
1288    queue->splice(queue->end(), workItems);
1289    (new AMessage(kWhatWorkDone, this))->post();
1290}
1291
1292void CCodec::onMessageReceived(const sp<AMessage> &msg) {
1293    TimePoint now = std::chrono::steady_clock::now();
1294    switch (msg->what()) {
1295        case kWhatAllocate: {
1296            // C2ComponentStore::createComponent() should return within 100ms.
1297            setDeadline(now + 150ms, "allocate");
1298            sp<RefBase> obj;
1299            CHECK(msg->findObject("codecInfo", &obj));
1300            allocate((MediaCodecInfo *)obj.get());
1301            break;
1302        }
1303        case kWhatConfigure: {
1304            // C2Component::commit_sm() should return within 5ms.
1305            setDeadline(now + 50ms, "configure");
1306            sp<AMessage> format;
1307            CHECK(msg->findMessage("format", &format));
1308            configure(format);
1309            break;
1310        }
1311        case kWhatStart: {
1312            // C2Component::start() should return within 500ms.
1313            setDeadline(now + 550ms, "start");
1314            start();
1315            break;
1316        }
1317        case kWhatStop: {
1318            // C2Component::stop() should return within 500ms.
1319            setDeadline(now + 550ms, "stop");
1320            stop();
1321            break;
1322        }
1323        case kWhatFlush: {
1324            // C2Component::flush_sm() should return within 5ms.
1325            setDeadline(now + 50ms, "flush");
1326            flush();
1327            break;
1328        }
1329        case kWhatCreateInputSurface: {
1330            // Surface operations may be briefly blocking.
1331            setDeadline(now + 100ms, "createInputSurface");
1332            createInputSurface();
1333            break;
1334        }
1335        case kWhatSetInputSurface: {
1336            // Surface operations may be briefly blocking.
1337            setDeadline(now + 100ms, "setInputSurface");
1338            sp<RefBase> obj;
1339            CHECK(msg->findObject("surface", &obj));
1340            sp<PersistentSurface> surface(static_cast<PersistentSurface *>(obj.get()));
1341            setInputSurface(surface);
1342            break;
1343        }
1344        case kWhatSetParameters: {
1345            setDeadline(now + 50ms, "setParameters");
1346            sp<AMessage> params;
1347            CHECK(msg->findMessage("params", &params));
1348            setParameters(params);
1349            break;
1350        }
1351        case kWhatWorkDone: {
1352            std::unique_ptr<C2Work> work;
1353            {
1354                Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
1355                if (queue->empty()) {
1356                    break;
1357                }
1358                work.swap(queue->front());
1359                queue->pop_front();
1360                if (!queue->empty()) {
1361                    (new AMessage(kWhatWorkDone, this))->post();
1362                }
1363            }
1364
1365            // handle configuration changes in work done
1366            Mutexed<Config>::Locked config(mConfig);
1367            bool changed = false;
1368            Config::Watcher<C2StreamInitDataInfo::output> initData =
1369                config->watch<C2StreamInitDataInfo::output>();
1370            if (!work->worklets.empty()
1371                    && (work->worklets.front()->output.flags
1372                            & C2FrameData::FLAG_DISCARD_FRAME) == 0) {
1373
1374                // copy buffer info to config
1375                std::vector<std::unique_ptr<C2Param>> updates =
1376                    std::move(work->worklets.front()->output.configUpdate);
1377                unsigned stream = 0;
1378                for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) {
1379                    for (const std::shared_ptr<const C2Info> &info : buf->info()) {
1380                        // move all info into output-stream #0 domain
1381                        updates.emplace_back(C2Param::CopyAsStream(*info, true /* output */, stream));
1382                    }
1383                    for (const C2ConstGraphicBlock &block : buf->data().graphicBlocks()) {
1384                        // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u",
1385                        //      block.crop().left, block.crop().top,
1386                        //      block.crop().width, block.crop().height,
1387                        //      block.width(), block.height());
1388                        updates.emplace_back(new C2StreamCropRectInfo::output(stream, block.crop()));
1389                        updates.emplace_back(new C2StreamPictureSizeInfo::output(
1390                                stream, block.width(), block.height()));
1391                        break; // for now only do the first block
1392                    }
1393                    ++stream;
1394                }
1395
1396                changed = config->updateConfiguration(updates, config->mOutputDomain);
1397
1398                // copy standard infos to graphic buffers if not already present (otherwise, we
1399                // may overwrite the actual intermediate value with a final value)
1400                stream = 0;
1401                const static std::vector<C2Param::Index> stdGfxInfos = {
1402                    C2StreamRotationInfo::output::PARAM_TYPE,
1403                    C2StreamColorAspectsInfo::output::PARAM_TYPE,
1404                    C2StreamHdrStaticInfo::output::PARAM_TYPE,
1405                    C2StreamPixelAspectRatioInfo::output::PARAM_TYPE,
1406                    C2StreamSurfaceScalingInfo::output::PARAM_TYPE
1407                };
1408                for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) {
1409                    if (buf->data().graphicBlocks().size()) {
1410                        for (C2Param::Index ix : stdGfxInfos) {
1411                            if (!buf->hasInfo(ix)) {
1412                                const C2Param *param =
1413                                    config->getConfigParameterValue(ix.withStream(stream));
1414                                if (param) {
1415                                    std::shared_ptr<C2Param> info(C2Param::Copy(*param));
1416                                    buf->setInfo(std::static_pointer_cast<C2Info>(info));
1417                                }
1418                            }
1419                        }
1420                    }
1421                    ++stream;
1422                }
1423            }
1424            mChannel->onWorkDone(
1425                    std::move(work), changed ? config->mOutputFormat : nullptr,
1426                    initData.hasChanged() ? initData.update().get() : nullptr);
1427            break;
1428        }
1429        default: {
1430            ALOGE("unrecognized message");
1431            break;
1432        }
1433    }
1434    setDeadline(TimePoint::max(), "none");
1435}
1436
1437void CCodec::setDeadline(const TimePoint &newDeadline, const char *name) {
1438    Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
1439    deadline->set(newDeadline, name);
1440}
1441
1442void CCodec::initiateReleaseIfStuck() {
1443    std::string name;
1444    {
1445        Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
1446        if (deadline->get() >= std::chrono::steady_clock::now()) {
1447            // We're not stuck.
1448            return;
1449        }
1450        name = deadline->getName();
1451    }
1452
1453    ALOGW("previous call to %s exceeded timeout", name.c_str());
1454    initiateRelease(false);
1455    mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1456}
1457
1458}  // namespace android
1459
1460extern "C" android::CodecBase *CreateCodec() {
1461    return new android::CCodec;
1462}
1463
1464