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 
29 #include <android/IGraphicBufferSource.h>
30 #include <android/IOMXBufferSource.h>
31 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
32 #include <android/hardware/media/omx/1.0/IOmx.h>
33 #include <android-base/stringprintf.h>
34 #include <cutils/properties.h>
35 #include <gui/IGraphicBufferProducer.h>
36 #include <gui/Surface.h>
37 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
38 #include <media/omx/1.0/WGraphicBufferSource.h>
39 #include <media/openmax/OMX_IndexExt.h>
40 #include <media/stagefright/BufferProducerWrapper.h>
41 #include <media/stagefright/MediaCodecConstants.h>
42 #include <media/stagefright/PersistentSurface.h>
43 
44 #include "C2OMXNode.h"
45 #include "CCodec.h"
46 #include "CCodecBufferChannel.h"
47 #include "InputSurfaceWrapper.h"
48 #include "Omx2IGraphicBufferSource.h"
49 
50 extern "C" android::PersistentSurface *CreateInputSurface();
51 
52 namespace android {
53 
54 using namespace std::chrono_literals;
55 using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
56 using android::base::StringPrintf;
57 using BGraphicBufferSource = ::android::IGraphicBufferSource;
58 using ::android::hardware::media::c2::V1_0::IInputSurface;
59 
60 namespace {
61 
62 class CCodecWatchdog : public AHandler {
63 private:
64     enum {
65         kWhatWatch,
66     };
67     constexpr static int64_t kWatchIntervalUs = 3300000;  // 3.3 secs
68 
69 public:
getInstance()70     static sp<CCodecWatchdog> getInstance() {
71         static sp<CCodecWatchdog> instance(new CCodecWatchdog);
72         static std::once_flag flag;
73         // Call Init() only once.
74         std::call_once(flag, Init, instance);
75         return instance;
76     }
77 
78     ~CCodecWatchdog() = default;
79 
watch(sp<CCodec> codec)80     void watch(sp<CCodec> codec) {
81         bool shouldPost = false;
82         {
83             Mutexed<std::set<wp<CCodec>>>::Locked codecs(mCodecsToWatch);
84             // If a watch message is in flight, piggy-back this instance as well.
85             // Otherwise, post a new watch message.
86             shouldPost = codecs->empty();
87             codecs->emplace(codec);
88         }
89         if (shouldPost) {
90             ALOGV("posting watch message");
91             (new AMessage(kWhatWatch, this))->post(kWatchIntervalUs);
92         }
93     }
94 
95 protected:
onMessageReceived(const sp<AMessage> & msg)96     void onMessageReceived(const sp<AMessage> &msg) {
97         switch (msg->what()) {
98             case kWhatWatch: {
99                 Mutexed<std::set<wp<CCodec>>>::Locked codecs(mCodecsToWatch);
100                 ALOGV("watch for %zu codecs", codecs->size());
101                 for (auto it = codecs->begin(); it != codecs->end(); ++it) {
102                     sp<CCodec> codec = it->promote();
103                     if (codec == nullptr) {
104                         continue;
105                     }
106                     codec->initiateReleaseIfStuck();
107                 }
108                 codecs->clear();
109                 break;
110             }
111 
112             default: {
113                 TRESPASS("CCodecWatchdog: unrecognized message");
114             }
115         }
116     }
117 
118 private:
CCodecWatchdog()119     CCodecWatchdog() : mLooper(new ALooper) {}
120 
Init(const sp<CCodecWatchdog> & thiz)121     static void Init(const sp<CCodecWatchdog> &thiz) {
122         ALOGV("Init");
123         thiz->mLooper->setName("CCodecWatchdog");
124         thiz->mLooper->registerHandler(thiz);
125         thiz->mLooper->start();
126     }
127 
128     sp<ALooper> mLooper;
129 
130     Mutexed<std::set<wp<CCodec>>> mCodecsToWatch;
131 };
132 
133 class C2InputSurfaceWrapper : public InputSurfaceWrapper {
134 public:
C2InputSurfaceWrapper(const std::shared_ptr<Codec2Client::InputSurface> & surface)135     explicit C2InputSurfaceWrapper(
136             const std::shared_ptr<Codec2Client::InputSurface> &surface) :
137         mSurface(surface) {
138     }
139 
140     ~C2InputSurfaceWrapper() override = default;
141 
connect(const std::shared_ptr<Codec2Client::Component> & comp)142     status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
143         if (mConnection != nullptr) {
144             return ALREADY_EXISTS;
145         }
146         return toStatusT(comp->connectToInputSurface(mSurface, &mConnection));
147     }
148 
disconnect()149     void disconnect() override {
150         if (mConnection != nullptr) {
151             mConnection->disconnect();
152             mConnection = nullptr;
153         }
154     }
155 
start()156     status_t start() override {
157         // InputSurface does not distinguish started state
158         return OK;
159     }
160 
signalEndOfInputStream()161     status_t signalEndOfInputStream() override {
162         C2InputSurfaceEosTuning eos(true);
163         std::vector<std::unique_ptr<C2SettingResult>> failures;
164         c2_status_t err = mSurface->config({&eos}, C2_MAY_BLOCK, &failures);
165         if (err != C2_OK) {
166             return UNKNOWN_ERROR;
167         }
168         return OK;
169     }
170 
configure(Config & config __unused)171     status_t configure(Config &config __unused) {
172         // TODO
173         return OK;
174     }
175 
176 private:
177     std::shared_ptr<Codec2Client::InputSurface> mSurface;
178     std::shared_ptr<Codec2Client::InputSurfaceConnection> mConnection;
179 };
180 
181 class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
182 public:
183 //    explicit GraphicBufferSourceWrapper(const sp<BGraphicBufferSource> &source) : mSource(source) {}
GraphicBufferSourceWrapper(const sp<BGraphicBufferSource> & source,uint32_t width,uint32_t height,uint64_t usage)184     GraphicBufferSourceWrapper(
185             const sp<BGraphicBufferSource> &source,
186             uint32_t width,
187             uint32_t height,
188             uint64_t usage)
189         : mSource(source), mWidth(width), mHeight(height) {
190         mDataSpace = HAL_DATASPACE_BT709;
191         mConfig.mUsage = usage;
192     }
193     ~GraphicBufferSourceWrapper() override = default;
194 
connect(const std::shared_ptr<Codec2Client::Component> & comp)195     status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
196         mNode = new C2OMXNode(comp);
197         mNode->setFrameSize(mWidth, mHeight);
198 
199         // Usage is queried during configure(), so setting it beforehand.
200         OMX_U32 usage = mConfig.mUsage & 0xFFFFFFFF;
201         (void)mNode->setParameter(
202                 (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
203                 &usage, sizeof(usage));
204 
205         // NOTE: we do not use/pass through color aspects from GraphicBufferSource as we
206         // communicate that directly to the component.
207         mSource->configure(mNode, mDataSpace);
208         return OK;
209     }
210 
disconnect()211     void disconnect() override {
212         if (mNode == nullptr) {
213             return;
214         }
215         sp<IOMXBufferSource> source = mNode->getSource();
216         if (source == nullptr) {
217             ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
218             return;
219         }
220         source->onOmxIdle();
221         source->onOmxLoaded();
222         mNode.clear();
223     }
224 
GetStatus(const binder::Status & status)225     status_t GetStatus(const binder::Status &status) {
226         status_t err = OK;
227         if (!status.isOk()) {
228             err = status.serviceSpecificErrorCode();
229             if (err == OK) {
230                 err = status.transactionError();
231                 if (err == OK) {
232                     // binder status failed, but there is no servie or transaction error
233                     err = UNKNOWN_ERROR;
234                 }
235             }
236         }
237         return err;
238     }
239 
start()240     status_t start() override {
241         sp<IOMXBufferSource> source = mNode->getSource();
242         if (source == nullptr) {
243             return NO_INIT;
244         }
245         constexpr size_t kNumSlots = 16;
246         for (size_t i = 0; i < kNumSlots; ++i) {
247             source->onInputBufferAdded(i);
248         }
249 
250         source->onOmxExecuting();
251         return OK;
252     }
253 
signalEndOfInputStream()254     status_t signalEndOfInputStream() override {
255         return GetStatus(mSource->signalEndOfInputStream());
256     }
257 
configure(Config & config)258     status_t configure(Config &config) {
259         std::stringstream status;
260         status_t err = OK;
261 
262         // handle each configuration granually, in case we need to handle part of the configuration
263         // elsewhere
264 
265         // TRICKY: we do not unset frame delay repeating
266         if (config.mMinFps > 0 && config.mMinFps != mConfig.mMinFps) {
267             int64_t us = 1e6 / config.mMinFps + 0.5;
268             status_t res = GetStatus(mSource->setRepeatPreviousFrameDelayUs(us));
269             status << " minFps=" << config.mMinFps << " => repeatDelayUs=" << us;
270             if (res != OK) {
271                 status << " (=> " << asString(res) << ")";
272                 err = res;
273             }
274             mConfig.mMinFps = config.mMinFps;
275         }
276 
277         // pts gap
278         if (config.mMinAdjustedFps > 0 || config.mFixedAdjustedFps > 0) {
279             if (mNode != nullptr) {
280                 OMX_PARAM_U32TYPE ptrGapParam = {};
281                 ptrGapParam.nSize = sizeof(OMX_PARAM_U32TYPE);
282                 float gap = (config.mMinAdjustedFps > 0)
283                         ? c2_min(INT32_MAX + 0., 1e6 / config.mMinAdjustedFps + 0.5)
284                         : c2_max(0. - INT32_MAX, -1e6 / config.mFixedAdjustedFps - 0.5);
285                 // float -> uint32_t is undefined if the value is negative.
286                 // First convert to int32_t to ensure the expected behavior.
287                 ptrGapParam.nU32 = int32_t(gap);
288                 (void)mNode->setParameter(
289                         (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl,
290                         &ptrGapParam, sizeof(ptrGapParam));
291             }
292         }
293 
294         // max fps
295         // TRICKY: we do not unset max fps to 0 unless using fixed fps
296         if ((config.mMaxFps > 0 || (config.mFixedAdjustedFps > 0 && config.mMaxFps == -1))
297                 && config.mMaxFps != mConfig.mMaxFps) {
298             status_t res = GetStatus(mSource->setMaxFps(config.mMaxFps));
299             status << " maxFps=" << config.mMaxFps;
300             if (res != OK) {
301                 status << " (=> " << asString(res) << ")";
302                 err = res;
303             }
304             mConfig.mMaxFps = config.mMaxFps;
305         }
306 
307         if (config.mTimeOffsetUs != mConfig.mTimeOffsetUs) {
308             status_t res = GetStatus(mSource->setTimeOffsetUs(config.mTimeOffsetUs));
309             status << " timeOffset " << config.mTimeOffsetUs << "us";
310             if (res != OK) {
311                 status << " (=> " << asString(res) << ")";
312                 err = res;
313             }
314             mConfig.mTimeOffsetUs = config.mTimeOffsetUs;
315         }
316 
317         if (config.mCaptureFps != mConfig.mCaptureFps || config.mCodedFps != mConfig.mCodedFps) {
318             status_t res =
319                 GetStatus(mSource->setTimeLapseConfig(config.mCodedFps, config.mCaptureFps));
320             status << " timeLapse " << config.mCaptureFps << "fps as " << config.mCodedFps << "fps";
321             if (res != OK) {
322                 status << " (=> " << asString(res) << ")";
323                 err = res;
324             }
325             mConfig.mCaptureFps = config.mCaptureFps;
326             mConfig.mCodedFps = config.mCodedFps;
327         }
328 
329         if (config.mStartAtUs != mConfig.mStartAtUs
330                 || (config.mStopped != mConfig.mStopped && !config.mStopped)) {
331             status_t res = GetStatus(mSource->setStartTimeUs(config.mStartAtUs));
332             status << " start at " << config.mStartAtUs << "us";
333             if (res != OK) {
334                 status << " (=> " << asString(res) << ")";
335                 err = res;
336             }
337             mConfig.mStartAtUs = config.mStartAtUs;
338             mConfig.mStopped = config.mStopped;
339         }
340 
341         // suspend-resume
342         if (config.mSuspended != mConfig.mSuspended) {
343             status_t res = GetStatus(mSource->setSuspend(config.mSuspended, config.mSuspendAtUs));
344             status << " " << (config.mSuspended ? "suspend" : "resume")
345                     << " at " << config.mSuspendAtUs << "us";
346             if (res != OK) {
347                 status << " (=> " << asString(res) << ")";
348                 err = res;
349             }
350             mConfig.mSuspended = config.mSuspended;
351             mConfig.mSuspendAtUs = config.mSuspendAtUs;
352         }
353 
354         if (config.mStopped != mConfig.mStopped && config.mStopped) {
355             status_t res = GetStatus(mSource->setStopTimeUs(config.mStopAtUs));
356             status << " stop at " << config.mStopAtUs << "us";
357             if (res != OK) {
358                 status << " (=> " << asString(res) << ")";
359                 err = res;
360             } else {
361                 status << " delayUs";
362                 res = GetStatus(mSource->getStopTimeOffsetUs(&config.mInputDelayUs));
363                 if (res != OK) {
364                     status << " (=> " << asString(res) << ")";
365                 } else {
366                     status << "=" << config.mInputDelayUs << "us";
367                 }
368                 mConfig.mInputDelayUs = config.mInputDelayUs;
369             }
370             mConfig.mStopAtUs = config.mStopAtUs;
371             mConfig.mStopped = config.mStopped;
372         }
373 
374         // color aspects (android._color-aspects)
375 
376         // consumer usage is queried earlier.
377 
378         ALOGD("ISConfig%s", status.str().c_str());
379         return err;
380     }
381 
onInputBufferDone(c2_cntr64_t index)382     void onInputBufferDone(c2_cntr64_t index) override {
383         mNode->onInputBufferDone(index);
384     }
385 
386 private:
387     sp<BGraphicBufferSource> mSource;
388     sp<C2OMXNode> mNode;
389     uint32_t mWidth;
390     uint32_t mHeight;
391     Config mConfig;
392 };
393 
394 class Codec2ClientInterfaceWrapper : public C2ComponentStore {
395     std::shared_ptr<Codec2Client> mClient;
396 
397 public:
Codec2ClientInterfaceWrapper(std::shared_ptr<Codec2Client> client)398     Codec2ClientInterfaceWrapper(std::shared_ptr<Codec2Client> client)
399         : mClient(client) { }
400 
401     virtual ~Codec2ClientInterfaceWrapper() = default;
402 
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)403     virtual c2_status_t config_sm(
404             const std::vector<C2Param *> &params,
405             std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
406         return mClient->config(params, C2_MAY_BLOCK, failures);
407     };
408 
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)409     virtual c2_status_t copyBuffer(
410             std::shared_ptr<C2GraphicBuffer>,
411             std::shared_ptr<C2GraphicBuffer>) {
412         return C2_OMITTED;
413     }
414 
createComponent(C2String,std::shared_ptr<C2Component> * const component)415     virtual c2_status_t createComponent(
416             C2String, std::shared_ptr<C2Component> *const component) {
417         component->reset();
418         return C2_OMITTED;
419     }
420 
createInterface(C2String,std::shared_ptr<C2ComponentInterface> * const interface)421     virtual c2_status_t createInterface(
422             C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
423         interface->reset();
424         return C2_OMITTED;
425     }
426 
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const427     virtual c2_status_t query_sm(
428             const std::vector<C2Param *> &stackParams,
429             const std::vector<C2Param::Index> &heapParamIndices,
430             std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
431         return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
432     }
433 
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const434     virtual c2_status_t querySupportedParams_nb(
435             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
436         return mClient->querySupportedParams(params);
437     }
438 
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const439     virtual c2_status_t querySupportedValues_sm(
440             std::vector<C2FieldSupportedValuesQuery> &fields) const {
441         return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
442     }
443 
getName() const444     virtual C2String getName() const {
445         return mClient->getName();
446     }
447 
getParamReflector() const448     virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
449         return mClient->getParamReflector();
450     }
451 
listComponents()452     virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() {
453         return std::vector<std::shared_ptr<const C2Component::Traits>>();
454     }
455 };
456 
457 }  // namespace
458 
459 // CCodec::ClientListener
460 
461 struct CCodec::ClientListener : public Codec2Client::Listener {
462 
ClientListenerandroid::CCodec::ClientListener463     explicit ClientListener(const wp<CCodec> &codec) : mCodec(codec) {}
464 
onWorkDoneandroid::CCodec::ClientListener465     virtual void onWorkDone(
466             const std::weak_ptr<Codec2Client::Component>& component,
467             std::list<std::unique_ptr<C2Work>>& workItems) override {
468         (void)component;
469         sp<CCodec> codec(mCodec.promote());
470         if (!codec) {
471             return;
472         }
473         codec->onWorkDone(workItems);
474     }
475 
onTrippedandroid::CCodec::ClientListener476     virtual void onTripped(
477             const std::weak_ptr<Codec2Client::Component>& component,
478             const std::vector<std::shared_ptr<C2SettingResult>>& settingResult
479             ) override {
480         // TODO
481         (void)component;
482         (void)settingResult;
483     }
484 
onErrorandroid::CCodec::ClientListener485     virtual void onError(
486             const std::weak_ptr<Codec2Client::Component>& component,
487             uint32_t errorCode) override {
488         // TODO
489         (void)component;
490         (void)errorCode;
491     }
492 
onDeathandroid::CCodec::ClientListener493     virtual void onDeath(
494             const std::weak_ptr<Codec2Client::Component>& component) override {
495         { // Log the death of the component.
496             std::shared_ptr<Codec2Client::Component> comp = component.lock();
497             if (!comp) {
498                 ALOGE("Codec2 component died.");
499             } else {
500                 ALOGE("Codec2 component \"%s\" died.", comp->getName().c_str());
501             }
502         }
503 
504         // Report to MediaCodec.
505         sp<CCodec> codec(mCodec.promote());
506         if (!codec || !codec->mCallback) {
507             return;
508         }
509         codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL);
510     }
511 
onFrameRenderedandroid::CCodec::ClientListener512     virtual void onFrameRendered(uint64_t bufferQueueId,
513                                  int32_t slotId,
514                                  int64_t timestampNs) override {
515         // TODO: implement
516         (void)bufferQueueId;
517         (void)slotId;
518         (void)timestampNs;
519     }
520 
onInputBufferDoneandroid::CCodec::ClientListener521     virtual void onInputBufferDone(
522             uint64_t frameIndex, size_t arrayIndex) override {
523         sp<CCodec> codec(mCodec.promote());
524         if (codec) {
525             codec->onInputBufferDone(frameIndex, arrayIndex);
526         }
527     }
528 
529 private:
530     wp<CCodec> mCodec;
531 };
532 
533 // CCodecCallbackImpl
534 
535 class CCodecCallbackImpl : public CCodecCallback {
536 public:
CCodecCallbackImpl(CCodec * codec)537     explicit CCodecCallbackImpl(CCodec *codec) : mCodec(codec) {}
538     ~CCodecCallbackImpl() override = default;
539 
onError(status_t err,enum ActionCode actionCode)540     void onError(status_t err, enum ActionCode actionCode) override {
541         mCodec->mCallback->onError(err, actionCode);
542     }
543 
onOutputFramesRendered(int64_t mediaTimeUs,nsecs_t renderTimeNs)544     void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override {
545         mCodec->mCallback->onOutputFramesRendered(
546                 {RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
547     }
548 
onOutputBuffersChanged()549     void onOutputBuffersChanged() override {
550         mCodec->mCallback->onOutputBuffersChanged();
551     }
552 
553 private:
554     CCodec *mCodec;
555 };
556 
557 // CCodec
558 
CCodec()559 CCodec::CCodec()
560     : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))) {
561 }
562 
~CCodec()563 CCodec::~CCodec() {
564 }
565 
getBufferChannel()566 std::shared_ptr<BufferChannelBase> CCodec::getBufferChannel() {
567     return mChannel;
568 }
569 
tryAndReportOnError(std::function<status_t ()> job)570 status_t CCodec::tryAndReportOnError(std::function<status_t()> job) {
571     status_t err = job();
572     if (err != C2_OK) {
573         mCallback->onError(err, ACTION_CODE_FATAL);
574     }
575     return err;
576 }
577 
initiateAllocateComponent(const sp<AMessage> & msg)578 void CCodec::initiateAllocateComponent(const sp<AMessage> &msg) {
579     auto setAllocating = [this] {
580         Mutexed<State>::Locked state(mState);
581         if (state->get() != RELEASED) {
582             return INVALID_OPERATION;
583         }
584         state->set(ALLOCATING);
585         return OK;
586     };
587     if (tryAndReportOnError(setAllocating) != OK) {
588         return;
589     }
590 
591     sp<RefBase> codecInfo;
592     CHECK(msg->findObject("codecInfo", &codecInfo));
593     // For Codec 2.0 components, componentName == codecInfo->getCodecName().
594 
595     sp<AMessage> allocMsg(new AMessage(kWhatAllocate, this));
596     allocMsg->setObject("codecInfo", codecInfo);
597     allocMsg->post();
598 }
599 
allocate(const sp<MediaCodecInfo> & codecInfo)600 void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) {
601     if (codecInfo == nullptr) {
602         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
603         return;
604     }
605     ALOGD("allocate(%s)", codecInfo->getCodecName());
606     mClientListener.reset(new ClientListener(this));
607 
608     AString componentName = codecInfo->getCodecName();
609     std::shared_ptr<Codec2Client> client;
610 
611     // set up preferred component store to access vendor store parameters
612     client = Codec2Client::CreateFromService("default");
613     if (client) {
614         ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str());
615         SetPreferredCodec2ComponentStore(
616                 std::make_shared<Codec2ClientInterfaceWrapper>(client));
617     }
618 
619     std::shared_ptr<Codec2Client::Component> comp =
620             Codec2Client::CreateComponentByName(
621             componentName.c_str(),
622             mClientListener,
623             &client);
624     if (!comp) {
625         ALOGE("Failed Create component: %s", componentName.c_str());
626         Mutexed<State>::Locked state(mState);
627         state->set(RELEASED);
628         state.unlock();
629         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
630         state.lock();
631         return;
632     }
633     ALOGI("Created component [%s]", componentName.c_str());
634     mChannel->setComponent(comp);
635     auto setAllocated = [this, comp, client] {
636         Mutexed<State>::Locked state(mState);
637         if (state->get() != ALLOCATING) {
638             state->set(RELEASED);
639             return UNKNOWN_ERROR;
640         }
641         state->set(ALLOCATED);
642         state->comp = comp;
643         mClient = client;
644         return OK;
645     };
646     if (tryAndReportOnError(setAllocated) != OK) {
647         return;
648     }
649 
650     // initialize config here in case setParameters is called prior to configure
651     Mutexed<Config>::Locked config(mConfig);
652     status_t err = config->initialize(mClient, comp);
653     if (err != OK) {
654         ALOGW("Failed to initialize configuration support");
655         // TODO: report error once we complete implementation.
656     }
657     config->queryConfiguration(comp);
658 
659     mCallback->onComponentAllocated(componentName.c_str());
660 }
661 
initiateConfigureComponent(const sp<AMessage> & format)662 void CCodec::initiateConfigureComponent(const sp<AMessage> &format) {
663     auto checkAllocated = [this] {
664         Mutexed<State>::Locked state(mState);
665         return (state->get() != ALLOCATED) ? UNKNOWN_ERROR : OK;
666     };
667     if (tryAndReportOnError(checkAllocated) != OK) {
668         return;
669     }
670 
671     sp<AMessage> msg(new AMessage(kWhatConfigure, this));
672     msg->setMessage("format", format);
673     msg->post();
674 }
675 
configure(const sp<AMessage> & msg)676 void CCodec::configure(const sp<AMessage> &msg) {
677     std::shared_ptr<Codec2Client::Component> comp;
678     auto checkAllocated = [this, &comp] {
679         Mutexed<State>::Locked state(mState);
680         if (state->get() != ALLOCATED) {
681             state->set(RELEASED);
682             return UNKNOWN_ERROR;
683         }
684         comp = state->comp;
685         return OK;
686     };
687     if (tryAndReportOnError(checkAllocated) != OK) {
688         return;
689     }
690 
691     auto doConfig = [msg, comp, this]() -> status_t {
692         AString mime;
693         if (!msg->findString("mime", &mime)) {
694             return BAD_VALUE;
695         }
696 
697         int32_t encoder;
698         if (!msg->findInt32("encoder", &encoder)) {
699             encoder = false;
700         }
701 
702         // TODO: read from intf()
703         if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) {
704             return UNKNOWN_ERROR;
705         }
706 
707         int32_t storeMeta;
708         if (encoder
709                 && msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
710                 && storeMeta != kMetadataBufferTypeInvalid) {
711             if (storeMeta != kMetadataBufferTypeANWBuffer) {
712                 ALOGD("Only ANW buffers are supported for legacy metadata mode");
713                 return BAD_VALUE;
714             }
715             mChannel->setMetaMode(CCodecBufferChannel::MODE_ANW);
716         }
717 
718         sp<RefBase> obj;
719         sp<Surface> surface;
720         if (msg->findObject("native-window", &obj)) {
721             surface = static_cast<Surface *>(obj.get());
722             setSurface(surface);
723         }
724 
725         Mutexed<Config>::Locked config(mConfig);
726         config->mUsingSurface = surface != nullptr;
727 
728         // Enforce required parameters
729         int32_t i32;
730         float flt;
731         if (config->mDomain & Config::IS_AUDIO) {
732             if (!msg->findInt32(KEY_SAMPLE_RATE, &i32)) {
733                 ALOGD("sample rate is missing, which is required for audio components.");
734                 return BAD_VALUE;
735             }
736             if (!msg->findInt32(KEY_CHANNEL_COUNT, &i32)) {
737                 ALOGD("channel count is missing, which is required for audio components.");
738                 return BAD_VALUE;
739             }
740             if ((config->mDomain & Config::IS_ENCODER)
741                     && !mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_FLAC)
742                     && !msg->findInt32(KEY_BIT_RATE, &i32)
743                     && !msg->findFloat(KEY_BIT_RATE, &flt)) {
744                 ALOGD("bitrate is missing, which is required for audio encoders.");
745                 return BAD_VALUE;
746             }
747         }
748         if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)) {
749             if (!msg->findInt32(KEY_WIDTH, &i32)) {
750                 ALOGD("width is missing, which is required for image/video components.");
751                 return BAD_VALUE;
752             }
753             if (!msg->findInt32(KEY_HEIGHT, &i32)) {
754                 ALOGD("height is missing, which is required for image/video components.");
755                 return BAD_VALUE;
756             }
757             if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) {
758                 int32_t mode = BITRATE_MODE_VBR;
759                 if (msg->findInt32(KEY_BITRATE_MODE, &mode) && mode == BITRATE_MODE_CQ) {
760                     if (!msg->findInt32(KEY_QUALITY, &i32)) {
761                         ALOGD("quality is missing, which is required for video encoders in CQ.");
762                         return BAD_VALUE;
763                     }
764                 } else {
765                     if (!msg->findInt32(KEY_BIT_RATE, &i32)
766                             && !msg->findFloat(KEY_BIT_RATE, &flt)) {
767                         ALOGD("bitrate is missing, which is required for video encoders.");
768                         return BAD_VALUE;
769                     }
770                 }
771                 if (!msg->findInt32(KEY_I_FRAME_INTERVAL, &i32)
772                         && !msg->findFloat(KEY_I_FRAME_INTERVAL, &flt)) {
773                     ALOGD("I frame interval is missing, which is required for video encoders.");
774                     return BAD_VALUE;
775                 }
776                 if (!msg->findInt32(KEY_FRAME_RATE, &i32)
777                         && !msg->findFloat(KEY_FRAME_RATE, &flt)) {
778                     ALOGD("frame rate is missing, which is required for video encoders.");
779                     return BAD_VALUE;
780                 }
781             }
782         }
783 
784         /*
785          * Handle input surface configuration
786          */
787         if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
788                 && (config->mDomain & Config::IS_ENCODER)) {
789             config->mISConfig.reset(new InputSurfaceWrapper::Config{});
790             {
791                 config->mISConfig->mMinFps = 0;
792                 int64_t value;
793                 if (msg->findInt64(KEY_REPEAT_PREVIOUS_FRAME_AFTER, &value) && value > 0) {
794                     config->mISConfig->mMinFps = 1e6 / value;
795                 }
796                 if (!msg->findFloat(
797                         KEY_MAX_FPS_TO_ENCODER, &config->mISConfig->mMaxFps)) {
798                     config->mISConfig->mMaxFps = -1;
799                 }
800                 config->mISConfig->mMinAdjustedFps = 0;
801                 config->mISConfig->mFixedAdjustedFps = 0;
802                 if (msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &value)) {
803                     if (value < 0 && value >= INT32_MIN) {
804                         config->mISConfig->mFixedAdjustedFps = -1e6 / value;
805                         config->mISConfig->mMaxFps = -1;
806                     } else if (value > 0 && value <= INT32_MAX) {
807                         config->mISConfig->mMinAdjustedFps = 1e6 / value;
808                     }
809                 }
810             }
811 
812             {
813                 double value;
814                 if (msg->findDouble("time-lapse-fps", &value)) {
815                     config->mISConfig->mCaptureFps = value;
816                     (void)msg->findAsFloat(KEY_FRAME_RATE, &config->mISConfig->mCodedFps);
817                 }
818             }
819 
820             {
821                 config->mISConfig->mSuspended = false;
822                 config->mISConfig->mSuspendAtUs = -1;
823                 int32_t value;
824                 if (msg->findInt32(KEY_CREATE_INPUT_SURFACE_SUSPENDED, &value) && value) {
825                     config->mISConfig->mSuspended = true;
826                 }
827             }
828             config->mISConfig->mUsage = 0;
829         }
830 
831         /*
832          * Handle desired color format.
833          */
834         if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
835             int32_t format = -1;
836             if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) {
837                 /*
838                  * Also handle default color format (encoders require color format, so this is only
839                  * needed for decoders.
840                  */
841                 if (!(config->mDomain & Config::IS_ENCODER)) {
842                     format = (surface == nullptr) ? COLOR_FormatYUV420Planar : COLOR_FormatSurface;
843                 }
844             }
845 
846             if (format >= 0) {
847                 msg->setInt32("android._color-format", format);
848             }
849         }
850 
851         std::vector<std::unique_ptr<C2Param>> configUpdate;
852         // NOTE: We used to ignore "video-bitrate" at configure; replicate
853         //       the behavior here.
854         sp<AMessage> sdkParams = msg;
855         int32_t videoBitrate;
856         if (sdkParams->findInt32(PARAMETER_KEY_VIDEO_BITRATE, &videoBitrate)) {
857             sdkParams = msg->dup();
858             sdkParams->removeEntryAt(sdkParams->findEntryByName(PARAMETER_KEY_VIDEO_BITRATE));
859         }
860         status_t err = config->getConfigUpdateFromSdkParams(
861                 comp, sdkParams, Config::IS_CONFIG, C2_DONT_BLOCK, &configUpdate);
862         if (err != OK) {
863             ALOGW("failed to convert configuration to c2 params");
864         }
865 
866         int32_t maxBframes = 0;
867         if ((config->mDomain & Config::IS_ENCODER)
868                 && (config->mDomain & Config::IS_VIDEO)
869                 && sdkParams->findInt32(KEY_MAX_B_FRAMES, &maxBframes)
870                 && maxBframes > 0) {
871             std::unique_ptr<C2StreamGopTuning::output> gop =
872                 C2StreamGopTuning::output::AllocUnique(2 /* flexCount */, 0u /* stream */);
873             gop->m.values[0] = { P_FRAME, UINT32_MAX };
874             gop->m.values[1] = {
875                 C2Config::picture_type_t(P_FRAME | B_FRAME),
876                 uint32_t(maxBframes)
877             };
878             configUpdate.push_back(std::move(gop));
879         }
880 
881         err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK);
882         if (err != OK) {
883             ALOGW("failed to configure c2 params");
884             return err;
885         }
886 
887         std::vector<std::unique_ptr<C2Param>> params;
888         C2StreamUsageTuning::input usage(0u, 0u);
889         C2StreamMaxBufferSizeInfo::input maxInputSize(0u, 0u);
890         C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
891 
892         std::initializer_list<C2Param::Index> indices {
893         };
894         c2_status_t c2err = comp->query(
895                 { &usage, &maxInputSize, &prepend },
896                 indices,
897                 C2_DONT_BLOCK,
898                 &params);
899         if (c2err != C2_OK && c2err != C2_BAD_INDEX) {
900             ALOGE("Failed to query component interface: %d", c2err);
901             return UNKNOWN_ERROR;
902         }
903         if (params.size() != indices.size()) {
904             ALOGE("Component returns wrong number of params: expected %zu actual %zu",
905                     indices.size(), params.size());
906             return UNKNOWN_ERROR;
907         }
908         if (usage) {
909             if (usage.value & C2MemoryUsage::CPU_READ) {
910                 config->mInputFormat->setInt32("using-sw-read-often", true);
911             }
912             if (config->mISConfig) {
913                 C2AndroidMemoryUsage androidUsage(C2MemoryUsage(usage.value));
914                 config->mISConfig->mUsage = androidUsage.asGrallocUsage();
915             }
916         }
917 
918         // NOTE: we don't blindly use client specified input size if specified as clients
919         // at times specify too small size. Instead, mimic the behavior from OMX, where the
920         // client specified size is only used to ask for bigger buffers than component suggested
921         // size.
922         int32_t clientInputSize = 0;
923         bool clientSpecifiedInputSize =
924             msg->findInt32(KEY_MAX_INPUT_SIZE, &clientInputSize) && clientInputSize > 0;
925         // TEMP: enforce minimum buffer size of 1MB for video decoders
926         // and 16K / 4K for audio encoders/decoders
927         if (maxInputSize.value == 0) {
928             if (config->mDomain & Config::IS_AUDIO) {
929                 maxInputSize.value = encoder ? 16384 : 4096;
930             } else if (!encoder) {
931                 maxInputSize.value = 1048576u;
932             }
933         }
934 
935         // verify that CSD fits into this size (if defined)
936         if ((config->mDomain & Config::IS_DECODER) && maxInputSize.value > 0) {
937             sp<ABuffer> csd;
938             for (size_t ix = 0; msg->findBuffer(StringPrintf("csd-%zu", ix).c_str(), &csd); ++ix) {
939                 if (csd && csd->size() > maxInputSize.value) {
940                     maxInputSize.value = csd->size();
941                 }
942             }
943         }
944 
945         // TODO: do this based on component requiring linear allocator for input
946         if ((config->mDomain & Config::IS_DECODER) || (config->mDomain & Config::IS_AUDIO)) {
947             if (clientSpecifiedInputSize) {
948                 // Warn that we're overriding client's max input size if necessary.
949                 if ((uint32_t)clientInputSize < maxInputSize.value) {
950                     ALOGD("client requested max input size %d, which is smaller than "
951                           "what component recommended (%u); overriding with component "
952                           "recommendation.", clientInputSize, maxInputSize.value);
953                     ALOGW("This behavior is subject to change. It is recommended that "
954                           "app developers double check whether the requested "
955                           "max input size is in reasonable range.");
956                 } else {
957                     maxInputSize.value = clientInputSize;
958                 }
959             }
960             // Pass max input size on input format to the buffer channel (if supplied by the
961             // component or by a default)
962             if (maxInputSize.value) {
963                 config->mInputFormat->setInt32(
964                         KEY_MAX_INPUT_SIZE,
965                         (int32_t)(c2_min(maxInputSize.value, uint32_t(INT32_MAX))));
966             }
967         }
968 
969         int32_t clientPrepend;
970         if ((config->mDomain & Config::IS_VIDEO)
971                 && (config->mDomain & Config::IS_ENCODER)
972                 && msg->findInt32(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES, &clientPrepend)
973                 && clientPrepend
974                 && (!prepend || prepend.value != PREPEND_HEADER_TO_ALL_SYNC)) {
975             ALOGE("Failed to set KEY_PREPEND_HEADERS_TO_SYNC_FRAMES");
976             return BAD_VALUE;
977         }
978 
979         if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
980             // propagate HDR static info to output format for both encoders and decoders
981             // if component supports this info, we will update from component, but only the raw port,
982             // so don't propagate if component already filled it in.
983             sp<ABuffer> hdrInfo;
984             if (msg->findBuffer(KEY_HDR_STATIC_INFO, &hdrInfo)
985                     && !config->mOutputFormat->findBuffer(KEY_HDR_STATIC_INFO, &hdrInfo)) {
986                 config->mOutputFormat->setBuffer(KEY_HDR_STATIC_INFO, hdrInfo);
987             }
988 
989             // Set desired color format from configuration parameter
990             int32_t format;
991             if (msg->findInt32("android._color-format", &format)) {
992                 if (config->mDomain & Config::IS_ENCODER) {
993                     config->mInputFormat->setInt32(KEY_COLOR_FORMAT, format);
994                 } else {
995                     config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format);
996                 }
997             }
998         }
999 
1000         // propagate encoder delay and padding to output format
1001         if ((config->mDomain & Config::IS_DECODER) && (config->mDomain & Config::IS_AUDIO)) {
1002             int delay = 0;
1003             if (msg->findInt32("encoder-delay", &delay)) {
1004                 config->mOutputFormat->setInt32("encoder-delay", delay);
1005             }
1006             int padding = 0;
1007             if (msg->findInt32("encoder-padding", &padding)) {
1008                 config->mOutputFormat->setInt32("encoder-padding", padding);
1009             }
1010         }
1011 
1012         // set channel-mask
1013         if (config->mDomain & Config::IS_AUDIO) {
1014             int32_t mask;
1015             if (msg->findInt32(KEY_CHANNEL_MASK, &mask)) {
1016                 if (config->mDomain & Config::IS_ENCODER) {
1017                     config->mInputFormat->setInt32(KEY_CHANNEL_MASK, mask);
1018                 } else {
1019                     config->mOutputFormat->setInt32(KEY_CHANNEL_MASK, mask);
1020                 }
1021             }
1022         }
1023 
1024         ALOGD("setup formats input: %s and output: %s",
1025                 config->mInputFormat->debugString().c_str(),
1026                 config->mOutputFormat->debugString().c_str());
1027         return OK;
1028     };
1029     if (tryAndReportOnError(doConfig) != OK) {
1030         return;
1031     }
1032 
1033     Mutexed<Config>::Locked config(mConfig);
1034 
1035     mCallback->onComponentConfigured(config->mInputFormat, config->mOutputFormat);
1036 }
1037 
initiateCreateInputSurface()1038 void CCodec::initiateCreateInputSurface() {
1039     status_t err = [this] {
1040         Mutexed<State>::Locked state(mState);
1041         if (state->get() != ALLOCATED) {
1042             return UNKNOWN_ERROR;
1043         }
1044         // TODO: read it from intf() properly.
1045         if (state->comp->getName().find("encoder") == std::string::npos) {
1046             return INVALID_OPERATION;
1047         }
1048         return OK;
1049     }();
1050     if (err != OK) {
1051         mCallback->onInputSurfaceCreationFailed(err);
1052         return;
1053     }
1054 
1055     (new AMessage(kWhatCreateInputSurface, this))->post();
1056 }
1057 
CreateOmxInputSurface()1058 sp<PersistentSurface> CCodec::CreateOmxInputSurface() {
1059     using namespace android::hardware::media::omx::V1_0;
1060     using namespace android::hardware::media::omx::V1_0::utils;
1061     using namespace android::hardware::graphics::bufferqueue::V1_0::utils;
1062     typedef android::hardware::media::omx::V1_0::Status OmxStatus;
1063     android::sp<IOmx> omx = IOmx::getService();
1064     typedef android::hardware::graphics::bufferqueue::V1_0::
1065             IGraphicBufferProducer HGraphicBufferProducer;
1066     typedef android::hardware::media::omx::V1_0::
1067             IGraphicBufferSource HGraphicBufferSource;
1068     OmxStatus s;
1069     android::sp<HGraphicBufferProducer> gbp;
1070     android::sp<HGraphicBufferSource> gbs;
1071 
1072     using ::android::hardware::Return;
1073     Return<void> transStatus = omx->createInputSurface(
1074             [&s, &gbp, &gbs](
1075                     OmxStatus status,
1076                     const android::sp<HGraphicBufferProducer>& producer,
1077                     const android::sp<HGraphicBufferSource>& source) {
1078                 s = status;
1079                 gbp = producer;
1080                 gbs = source;
1081             });
1082     if (transStatus.isOk() && s == OmxStatus::OK) {
1083         return new PersistentSurface(
1084                 new H2BGraphicBufferProducer(gbp),
1085                 sp<::android::IGraphicBufferSource>(new LWGraphicBufferSource(gbs)));
1086     }
1087 
1088     return nullptr;
1089 }
1090 
CreateCompatibleInputSurface()1091 sp<PersistentSurface> CCodec::CreateCompatibleInputSurface() {
1092     sp<PersistentSurface> surface(CreateInputSurface());
1093 
1094     if (surface == nullptr) {
1095         surface = CreateOmxInputSurface();
1096     }
1097 
1098     return surface;
1099 }
1100 
createInputSurface()1101 void CCodec::createInputSurface() {
1102     status_t err;
1103     sp<IGraphicBufferProducer> bufferProducer;
1104 
1105     sp<AMessage> inputFormat;
1106     sp<AMessage> outputFormat;
1107     uint64_t usage = 0;
1108     {
1109         Mutexed<Config>::Locked config(mConfig);
1110         inputFormat = config->mInputFormat;
1111         outputFormat = config->mOutputFormat;
1112         usage = config->mISConfig ? config->mISConfig->mUsage : 0;
1113     }
1114 
1115     sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface();
1116 
1117     if (persistentSurface->getHidlTarget()) {
1118         sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
1119                 persistentSurface->getHidlTarget());
1120         if (!hidlInputSurface) {
1121             ALOGE("Corrupted input surface");
1122             mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
1123             return;
1124         }
1125         std::shared_ptr<Codec2Client::InputSurface> inputSurface =
1126                 std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
1127         err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
1128                 inputSurface));
1129         bufferProducer = inputSurface->getGraphicBufferProducer();
1130     } else {
1131         int32_t width = 0;
1132         (void)outputFormat->findInt32("width", &width);
1133         int32_t height = 0;
1134         (void)outputFormat->findInt32("height", &height);
1135         err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
1136                 persistentSurface->getBufferSource(), width, height, usage));
1137         bufferProducer = persistentSurface->getBufferProducer();
1138     }
1139 
1140     if (err != OK) {
1141         ALOGE("Failed to set up input surface: %d", err);
1142         mCallback->onInputSurfaceCreationFailed(err);
1143         return;
1144     }
1145 
1146     mCallback->onInputSurfaceCreated(
1147             inputFormat,
1148             outputFormat,
1149             new BufferProducerWrapper(bufferProducer));
1150 }
1151 
setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> & surface)1152 status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) {
1153     Mutexed<Config>::Locked config(mConfig);
1154     config->mUsingSurface = true;
1155 
1156     // we are now using surface - apply default color aspects to input format - as well as
1157     // get dataspace
1158     bool inputFormatChanged = config->updateFormats(config->IS_INPUT);
1159     ALOGD("input format %s to %s",
1160             inputFormatChanged ? "changed" : "unchanged",
1161             config->mInputFormat->debugString().c_str());
1162 
1163     // configure dataspace
1164     static_assert(sizeof(int32_t) == sizeof(android_dataspace), "dataspace size mismatch");
1165     android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
1166     (void)config->mInputFormat->findInt32("android._dataspace", (int32_t*)&dataSpace);
1167     surface->setDataSpace(dataSpace);
1168 
1169     status_t err = mChannel->setInputSurface(surface);
1170     if (err != OK) {
1171         // undo input format update
1172         config->mUsingSurface = false;
1173         (void)config->updateFormats(config->IS_INPUT);
1174         return err;
1175     }
1176     config->mInputSurface = surface;
1177 
1178     if (config->mISConfig) {
1179         surface->configure(*config->mISConfig);
1180     } else {
1181         ALOGD("ISConfig: no configuration");
1182     }
1183 
1184     return OK;
1185 }
1186 
initiateSetInputSurface(const sp<PersistentSurface> & surface)1187 void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
1188     sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this);
1189     msg->setObject("surface", surface);
1190     msg->post();
1191 }
1192 
setInputSurface(const sp<PersistentSurface> & surface)1193 void CCodec::setInputSurface(const sp<PersistentSurface> &surface) {
1194     sp<AMessage> inputFormat;
1195     sp<AMessage> outputFormat;
1196     uint64_t usage = 0;
1197     {
1198         Mutexed<Config>::Locked config(mConfig);
1199         inputFormat = config->mInputFormat;
1200         outputFormat = config->mOutputFormat;
1201         usage = config->mISConfig ? config->mISConfig->mUsage : 0;
1202     }
1203     auto hidlTarget = surface->getHidlTarget();
1204     if (hidlTarget) {
1205         sp<IInputSurface> inputSurface =
1206                 IInputSurface::castFrom(hidlTarget);
1207         if (!inputSurface) {
1208             ALOGE("Failed to set input surface: Corrupted surface.");
1209             mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
1210             return;
1211         }
1212         status_t err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
1213                 std::make_shared<Codec2Client::InputSurface>(inputSurface)));
1214         if (err != OK) {
1215             ALOGE("Failed to set up input surface: %d", err);
1216             mCallback->onInputSurfaceDeclined(err);
1217             return;
1218         }
1219     } else {
1220         int32_t width = 0;
1221         (void)outputFormat->findInt32("width", &width);
1222         int32_t height = 0;
1223         (void)outputFormat->findInt32("height", &height);
1224         status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
1225                 surface->getBufferSource(), width, height, usage));
1226         if (err != OK) {
1227             ALOGE("Failed to set up input surface: %d", err);
1228             mCallback->onInputSurfaceDeclined(err);
1229             return;
1230         }
1231     }
1232     mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
1233 }
1234 
initiateStart()1235 void CCodec::initiateStart() {
1236     auto setStarting = [this] {
1237         Mutexed<State>::Locked state(mState);
1238         if (state->get() != ALLOCATED) {
1239             return UNKNOWN_ERROR;
1240         }
1241         state->set(STARTING);
1242         return OK;
1243     };
1244     if (tryAndReportOnError(setStarting) != OK) {
1245         return;
1246     }
1247 
1248     (new AMessage(kWhatStart, this))->post();
1249 }
1250 
start()1251 void CCodec::start() {
1252     std::shared_ptr<Codec2Client::Component> comp;
1253     auto checkStarting = [this, &comp] {
1254         Mutexed<State>::Locked state(mState);
1255         if (state->get() != STARTING) {
1256             return UNKNOWN_ERROR;
1257         }
1258         comp = state->comp;
1259         return OK;
1260     };
1261     if (tryAndReportOnError(checkStarting) != OK) {
1262         return;
1263     }
1264 
1265     c2_status_t err = comp->start();
1266     if (err != C2_OK) {
1267         mCallback->onError(toStatusT(err, C2_OPERATION_Component_start),
1268                            ACTION_CODE_FATAL);
1269         return;
1270     }
1271     sp<AMessage> inputFormat;
1272     sp<AMessage> outputFormat;
1273     status_t err2 = OK;
1274     {
1275         Mutexed<Config>::Locked config(mConfig);
1276         inputFormat = config->mInputFormat;
1277         outputFormat = config->mOutputFormat;
1278         if (config->mInputSurface) {
1279             err2 = config->mInputSurface->start();
1280         }
1281     }
1282     if (err2 != OK) {
1283         mCallback->onError(err2, ACTION_CODE_FATAL);
1284         return;
1285     }
1286     err2 = mChannel->start(inputFormat, outputFormat);
1287     if (err2 != OK) {
1288         mCallback->onError(err2, ACTION_CODE_FATAL);
1289         return;
1290     }
1291 
1292     auto setRunning = [this] {
1293         Mutexed<State>::Locked state(mState);
1294         if (state->get() != STARTING) {
1295             return UNKNOWN_ERROR;
1296         }
1297         state->set(RUNNING);
1298         return OK;
1299     };
1300     if (tryAndReportOnError(setRunning) != OK) {
1301         return;
1302     }
1303     mCallback->onStartCompleted();
1304 
1305     (void)mChannel->requestInitialInputBuffers();
1306 }
1307 
initiateShutdown(bool keepComponentAllocated)1308 void CCodec::initiateShutdown(bool keepComponentAllocated) {
1309     if (keepComponentAllocated) {
1310         initiateStop();
1311     } else {
1312         initiateRelease();
1313     }
1314 }
1315 
initiateStop()1316 void CCodec::initiateStop() {
1317     {
1318         Mutexed<State>::Locked state(mState);
1319         if (state->get() == ALLOCATED
1320                 || state->get()  == RELEASED
1321                 || state->get() == STOPPING
1322                 || state->get() == RELEASING) {
1323             // We're already stopped, released, or doing it right now.
1324             state.unlock();
1325             mCallback->onStopCompleted();
1326             state.lock();
1327             return;
1328         }
1329         state->set(STOPPING);
1330     }
1331 
1332     mChannel->stop();
1333     (new AMessage(kWhatStop, this))->post();
1334 }
1335 
stop()1336 void CCodec::stop() {
1337     std::shared_ptr<Codec2Client::Component> comp;
1338     {
1339         Mutexed<State>::Locked state(mState);
1340         if (state->get() == RELEASING) {
1341             state.unlock();
1342             // We're already stopped or release is in progress.
1343             mCallback->onStopCompleted();
1344             state.lock();
1345             return;
1346         } else if (state->get() != STOPPING) {
1347             state.unlock();
1348             mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1349             state.lock();
1350             return;
1351         }
1352         comp = state->comp;
1353     }
1354     status_t err = comp->stop();
1355     if (err != C2_OK) {
1356         // TODO: convert err into status_t
1357         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1358     }
1359 
1360     {
1361         Mutexed<Config>::Locked config(mConfig);
1362         if (config->mInputSurface) {
1363             config->mInputSurface->disconnect();
1364             config->mInputSurface = nullptr;
1365         }
1366     }
1367     {
1368         Mutexed<State>::Locked state(mState);
1369         if (state->get() == STOPPING) {
1370             state->set(ALLOCATED);
1371         }
1372     }
1373     mCallback->onStopCompleted();
1374 }
1375 
initiateRelease(bool sendCallback)1376 void CCodec::initiateRelease(bool sendCallback /* = true */) {
1377     bool clearInputSurfaceIfNeeded = false;
1378     {
1379         Mutexed<State>::Locked state(mState);
1380         if (state->get() == RELEASED || state->get() == RELEASING) {
1381             // We're already released or doing it right now.
1382             if (sendCallback) {
1383                 state.unlock();
1384                 mCallback->onReleaseCompleted();
1385                 state.lock();
1386             }
1387             return;
1388         }
1389         if (state->get() == ALLOCATING) {
1390             state->set(RELEASING);
1391             // With the altered state allocate() would fail and clean up.
1392             if (sendCallback) {
1393                 state.unlock();
1394                 mCallback->onReleaseCompleted();
1395                 state.lock();
1396             }
1397             return;
1398         }
1399         if (state->get() == STARTING
1400                 || state->get() == RUNNING
1401                 || state->get() == STOPPING) {
1402             // Input surface may have been started, so clean up is needed.
1403             clearInputSurfaceIfNeeded = true;
1404         }
1405         state->set(RELEASING);
1406     }
1407 
1408     if (clearInputSurfaceIfNeeded) {
1409         Mutexed<Config>::Locked config(mConfig);
1410         if (config->mInputSurface) {
1411             config->mInputSurface->disconnect();
1412             config->mInputSurface = nullptr;
1413         }
1414     }
1415 
1416     mChannel->stop();
1417     // thiz holds strong ref to this while the thread is running.
1418     sp<CCodec> thiz(this);
1419     std::thread([thiz, sendCallback] { thiz->release(sendCallback); }).detach();
1420 }
1421 
release(bool sendCallback)1422 void CCodec::release(bool sendCallback) {
1423     std::shared_ptr<Codec2Client::Component> comp;
1424     {
1425         Mutexed<State>::Locked state(mState);
1426         if (state->get() == RELEASED) {
1427             if (sendCallback) {
1428                 state.unlock();
1429                 mCallback->onReleaseCompleted();
1430                 state.lock();
1431             }
1432             return;
1433         }
1434         comp = state->comp;
1435     }
1436     comp->release();
1437 
1438     {
1439         Mutexed<State>::Locked state(mState);
1440         state->set(RELEASED);
1441         state->comp.reset();
1442     }
1443     if (sendCallback) {
1444         mCallback->onReleaseCompleted();
1445     }
1446 }
1447 
setSurface(const sp<Surface> & surface)1448 status_t CCodec::setSurface(const sp<Surface> &surface) {
1449     return mChannel->setSurface(surface);
1450 }
1451 
signalFlush()1452 void CCodec::signalFlush() {
1453     status_t err = [this] {
1454         Mutexed<State>::Locked state(mState);
1455         if (state->get() == FLUSHED) {
1456             return ALREADY_EXISTS;
1457         }
1458         if (state->get() != RUNNING) {
1459             return UNKNOWN_ERROR;
1460         }
1461         state->set(FLUSHING);
1462         return OK;
1463     }();
1464     switch (err) {
1465         case ALREADY_EXISTS:
1466             mCallback->onFlushCompleted();
1467             return;
1468         case OK:
1469             break;
1470         default:
1471             mCallback->onError(err, ACTION_CODE_FATAL);
1472             return;
1473     }
1474 
1475     mChannel->stop();
1476     (new AMessage(kWhatFlush, this))->post();
1477 }
1478 
flush()1479 void CCodec::flush() {
1480     std::shared_ptr<Codec2Client::Component> comp;
1481     auto checkFlushing = [this, &comp] {
1482         Mutexed<State>::Locked state(mState);
1483         if (state->get() != FLUSHING) {
1484             return UNKNOWN_ERROR;
1485         }
1486         comp = state->comp;
1487         return OK;
1488     };
1489     if (tryAndReportOnError(checkFlushing) != OK) {
1490         return;
1491     }
1492 
1493     std::list<std::unique_ptr<C2Work>> flushedWork;
1494     c2_status_t err = comp->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
1495     {
1496         Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
1497         flushedWork.splice(flushedWork.end(), *queue);
1498     }
1499     if (err != C2_OK) {
1500         // TODO: convert err into status_t
1501         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1502     }
1503 
1504     mChannel->flush(flushedWork);
1505 
1506     {
1507         Mutexed<State>::Locked state(mState);
1508         state->set(FLUSHED);
1509     }
1510     mCallback->onFlushCompleted();
1511 }
1512 
signalResume()1513 void CCodec::signalResume() {
1514     auto setResuming = [this] {
1515         Mutexed<State>::Locked state(mState);
1516         if (state->get() != FLUSHED) {
1517             return UNKNOWN_ERROR;
1518         }
1519         state->set(RESUMING);
1520         return OK;
1521     };
1522     if (tryAndReportOnError(setResuming) != OK) {
1523         return;
1524     }
1525 
1526     (void)mChannel->start(nullptr, nullptr);
1527 
1528     {
1529         Mutexed<State>::Locked state(mState);
1530         if (state->get() != RESUMING) {
1531             state.unlock();
1532             mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1533             state.lock();
1534             return;
1535         }
1536         state->set(RUNNING);
1537     }
1538 
1539     (void)mChannel->requestInitialInputBuffers();
1540 }
1541 
signalSetParameters(const sp<AMessage> & msg)1542 void CCodec::signalSetParameters(const sp<AMessage> &msg) {
1543     std::shared_ptr<Codec2Client::Component> comp;
1544     auto checkState = [this, &comp] {
1545         Mutexed<State>::Locked state(mState);
1546         if (state->get() == RELEASED) {
1547             return INVALID_OPERATION;
1548         }
1549         comp = state->comp;
1550         return OK;
1551     };
1552     if (tryAndReportOnError(checkState) != OK) {
1553         return;
1554     }
1555 
1556     // NOTE: We used to ignore "bitrate" at setParameters; replicate
1557     //       the behavior here.
1558     sp<AMessage> params = msg;
1559     int32_t bitrate;
1560     if (params->findInt32(KEY_BIT_RATE, &bitrate)) {
1561         params = msg->dup();
1562         params->removeEntryAt(params->findEntryByName(KEY_BIT_RATE));
1563     }
1564 
1565     Mutexed<Config>::Locked config(mConfig);
1566 
1567     /**
1568      * Handle input surface parameters
1569      */
1570     if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
1571             && (config->mDomain & Config::IS_ENCODER) && config->mInputSurface && config->mISConfig) {
1572         (void)params->findInt64(PARAMETER_KEY_OFFSET_TIME, &config->mISConfig->mTimeOffsetUs);
1573 
1574         if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) {
1575             config->mISConfig->mStopped = false;
1576         } else if (params->findInt64("stop-time-us", &config->mISConfig->mStopAtUs)) {
1577             config->mISConfig->mStopped = true;
1578         }
1579 
1580         int32_t value;
1581         if (params->findInt32(PARAMETER_KEY_SUSPEND, &value)) {
1582             config->mISConfig->mSuspended = value;
1583             config->mISConfig->mSuspendAtUs = -1;
1584             (void)params->findInt64(PARAMETER_KEY_SUSPEND_TIME, &config->mISConfig->mSuspendAtUs);
1585         }
1586 
1587         (void)config->mInputSurface->configure(*config->mISConfig);
1588         if (config->mISConfig->mStopped) {
1589             config->mInputFormat->setInt64(
1590                     "android._stop-time-offset-us", config->mISConfig->mInputDelayUs);
1591         }
1592     }
1593 
1594     std::vector<std::unique_ptr<C2Param>> configUpdate;
1595     (void)config->getConfigUpdateFromSdkParams(
1596             comp, params, Config::IS_PARAM, C2_MAY_BLOCK, &configUpdate);
1597     // Prefer to pass parameters to the buffer channel, so they can be synchronized with the frames.
1598     // Parameter synchronization is not defined when using input surface. For now, route
1599     // these directly to the component.
1600     if (config->mInputSurface == nullptr
1601             && (property_get_bool("debug.stagefright.ccodec_delayed_params", false)
1602                     || comp->getName().find("c2.android.") == 0)) {
1603         mChannel->setParameters(configUpdate);
1604     } else {
1605         (void)config->setParameters(comp, configUpdate, C2_MAY_BLOCK);
1606     }
1607 }
1608 
signalEndOfInputStream()1609 void CCodec::signalEndOfInputStream() {
1610     mCallback->onSignaledInputEOS(mChannel->signalEndOfInputStream());
1611 }
1612 
signalRequestIDRFrame()1613 void CCodec::signalRequestIDRFrame() {
1614     std::shared_ptr<Codec2Client::Component> comp;
1615     {
1616         Mutexed<State>::Locked state(mState);
1617         if (state->get() == RELEASED) {
1618             ALOGD("no IDR request sent since component is released");
1619             return;
1620         }
1621         comp = state->comp;
1622     }
1623     ALOGV("request IDR");
1624     Mutexed<Config>::Locked config(mConfig);
1625     std::vector<std::unique_ptr<C2Param>> params;
1626     params.push_back(
1627             std::make_unique<C2StreamRequestSyncFrameTuning::output>(0u, true));
1628     config->setParameters(comp, params, C2_MAY_BLOCK);
1629 }
1630 
onWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)1631 void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
1632     if (!workItems.empty()) {
1633         Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
1634         queue->splice(queue->end(), workItems);
1635     }
1636     (new AMessage(kWhatWorkDone, this))->post();
1637 }
1638 
onInputBufferDone(uint64_t frameIndex,size_t arrayIndex)1639 void CCodec::onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) {
1640     mChannel->onInputBufferDone(frameIndex, arrayIndex);
1641     if (arrayIndex == 0) {
1642         // We always put no more than one buffer per work, if we use an input surface.
1643         Mutexed<Config>::Locked config(mConfig);
1644         if (config->mInputSurface) {
1645             config->mInputSurface->onInputBufferDone(frameIndex);
1646         }
1647     }
1648 }
1649 
onMessageReceived(const sp<AMessage> & msg)1650 void CCodec::onMessageReceived(const sp<AMessage> &msg) {
1651     TimePoint now = std::chrono::steady_clock::now();
1652     CCodecWatchdog::getInstance()->watch(this);
1653     switch (msg->what()) {
1654         case kWhatAllocate: {
1655             // C2ComponentStore::createComponent() should return within 100ms.
1656             setDeadline(now, 1500ms, "allocate");
1657             sp<RefBase> obj;
1658             CHECK(msg->findObject("codecInfo", &obj));
1659             allocate((MediaCodecInfo *)obj.get());
1660             break;
1661         }
1662         case kWhatConfigure: {
1663             // C2Component::commit_sm() should return within 5ms.
1664             setDeadline(now, 1500ms, "configure");
1665             sp<AMessage> format;
1666             CHECK(msg->findMessage("format", &format));
1667             configure(format);
1668             break;
1669         }
1670         case kWhatStart: {
1671             // C2Component::start() should return within 500ms.
1672             setDeadline(now, 1500ms, "start");
1673             start();
1674             break;
1675         }
1676         case kWhatStop: {
1677             // C2Component::stop() should return within 500ms.
1678             setDeadline(now, 1500ms, "stop");
1679             stop();
1680             break;
1681         }
1682         case kWhatFlush: {
1683             // C2Component::flush_sm() should return within 5ms.
1684             setDeadline(now, 1500ms, "flush");
1685             flush();
1686             break;
1687         }
1688         case kWhatCreateInputSurface: {
1689             // Surface operations may be briefly blocking.
1690             setDeadline(now, 1500ms, "createInputSurface");
1691             createInputSurface();
1692             break;
1693         }
1694         case kWhatSetInputSurface: {
1695             // Surface operations may be briefly blocking.
1696             setDeadline(now, 1500ms, "setInputSurface");
1697             sp<RefBase> obj;
1698             CHECK(msg->findObject("surface", &obj));
1699             sp<PersistentSurface> surface(static_cast<PersistentSurface *>(obj.get()));
1700             setInputSurface(surface);
1701             break;
1702         }
1703         case kWhatWorkDone: {
1704             std::unique_ptr<C2Work> work;
1705             bool shouldPost = false;
1706             {
1707                 Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
1708                 if (queue->empty()) {
1709                     break;
1710                 }
1711                 work.swap(queue->front());
1712                 queue->pop_front();
1713                 shouldPost = !queue->empty();
1714             }
1715             if (shouldPost) {
1716                 (new AMessage(kWhatWorkDone, this))->post();
1717             }
1718 
1719             // handle configuration changes in work done
1720             Mutexed<Config>::Locked config(mConfig);
1721             bool changed = false;
1722             Config::Watcher<C2StreamInitDataInfo::output> initData =
1723                 config->watch<C2StreamInitDataInfo::output>();
1724             if (!work->worklets.empty()
1725                     && (work->worklets.front()->output.flags
1726                             & C2FrameData::FLAG_DISCARD_FRAME) == 0) {
1727 
1728                 // copy buffer info to config
1729                 std::vector<std::unique_ptr<C2Param>> updates;
1730                 for (const std::unique_ptr<C2Param> &param
1731                         : work->worklets.front()->output.configUpdate) {
1732                     updates.push_back(C2Param::Copy(*param));
1733                 }
1734                 unsigned stream = 0;
1735                 for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) {
1736                     for (const std::shared_ptr<const C2Info> &info : buf->info()) {
1737                         // move all info into output-stream #0 domain
1738                         updates.emplace_back(C2Param::CopyAsStream(*info, true /* output */, stream));
1739                     }
1740                     for (const C2ConstGraphicBlock &block : buf->data().graphicBlocks()) {
1741                         // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u",
1742                         //      block.crop().left, block.crop().top,
1743                         //      block.crop().width, block.crop().height,
1744                         //      block.width(), block.height());
1745                         updates.emplace_back(new C2StreamCropRectInfo::output(stream, block.crop()));
1746                         updates.emplace_back(new C2StreamPictureSizeInfo::output(
1747                                 stream, block.crop().width, block.crop().height));
1748                         break; // for now only do the first block
1749                     }
1750                     ++stream;
1751                 }
1752 
1753                 changed = config->updateConfiguration(updates, config->mOutputDomain);
1754 
1755                 // copy standard infos to graphic buffers if not already present (otherwise, we
1756                 // may overwrite the actual intermediate value with a final value)
1757                 stream = 0;
1758                 const static std::vector<C2Param::Index> stdGfxInfos = {
1759                     C2StreamRotationInfo::output::PARAM_TYPE,
1760                     C2StreamColorAspectsInfo::output::PARAM_TYPE,
1761                     C2StreamDataSpaceInfo::output::PARAM_TYPE,
1762                     C2StreamHdrStaticInfo::output::PARAM_TYPE,
1763                     C2StreamHdr10PlusInfo::output::PARAM_TYPE,
1764                     C2StreamPixelAspectRatioInfo::output::PARAM_TYPE,
1765                     C2StreamSurfaceScalingInfo::output::PARAM_TYPE
1766                 };
1767                 for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) {
1768                     if (buf->data().graphicBlocks().size()) {
1769                         for (C2Param::Index ix : stdGfxInfos) {
1770                             if (!buf->hasInfo(ix)) {
1771                                 const C2Param *param =
1772                                     config->getConfigParameterValue(ix.withStream(stream));
1773                                 if (param) {
1774                                     std::shared_ptr<C2Param> info(C2Param::Copy(*param));
1775                                     buf->setInfo(std::static_pointer_cast<C2Info>(info));
1776                                 }
1777                             }
1778                         }
1779                     }
1780                     ++stream;
1781                 }
1782             }
1783             if (config->mInputSurface) {
1784                 config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
1785             }
1786             mChannel->onWorkDone(
1787                     std::move(work), changed ? config->mOutputFormat : nullptr,
1788                     initData.hasChanged() ? initData.update().get() : nullptr);
1789             break;
1790         }
1791         case kWhatWatch: {
1792             // watch message already posted; no-op.
1793             break;
1794         }
1795         default: {
1796             ALOGE("unrecognized message");
1797             break;
1798         }
1799     }
1800     setDeadline(TimePoint::max(), 0ms, "none");
1801 }
1802 
setDeadline(const TimePoint & now,const std::chrono::milliseconds & timeout,const char * name)1803 void CCodec::setDeadline(
1804         const TimePoint &now,
1805         const std::chrono::milliseconds &timeout,
1806         const char *name) {
1807     int32_t mult = std::max(1, property_get_int32("debug.stagefright.ccodec_timeout_mult", 1));
1808     Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
1809     deadline->set(now + (timeout * mult), name);
1810 }
1811 
initiateReleaseIfStuck()1812 void CCodec::initiateReleaseIfStuck() {
1813     std::string name;
1814     bool pendingDeadline = false;
1815     {
1816         Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
1817         if (deadline->get() < std::chrono::steady_clock::now()) {
1818             name = deadline->getName();
1819         }
1820         if (deadline->get() != TimePoint::max()) {
1821             pendingDeadline = true;
1822         }
1823     }
1824     if (name.empty()) {
1825         constexpr std::chrono::steady_clock::duration kWorkDurationThreshold = 3s;
1826         std::chrono::steady_clock::duration elapsed = mChannel->elapsed();
1827         if (elapsed >= kWorkDurationThreshold) {
1828             name = "queue";
1829         }
1830         if (elapsed > 0s) {
1831             pendingDeadline = true;
1832         }
1833     }
1834     if (name.empty()) {
1835         // We're not stuck.
1836         if (pendingDeadline) {
1837             // If we are not stuck yet but still has deadline coming up,
1838             // post watch message to check back later.
1839             (new AMessage(kWhatWatch, this))->post();
1840         }
1841         return;
1842     }
1843 
1844     ALOGW("previous call to %s exceeded timeout", name.c_str());
1845     initiateRelease(false);
1846     mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1847 }
1848 
1849 }  // namespace android
1850 
CreateCodec()1851 extern "C" android::CodecBase *CreateCodec() {
1852     return new android::CCodec;
1853 }
1854 
1855 // Create Codec 2.0 input surface
CreateInputSurface()1856 extern "C" android::PersistentSurface *CreateInputSurface() {
1857     using namespace android;
1858     // Attempt to create a Codec2's input surface.
1859     std::shared_ptr<Codec2Client::InputSurface> inputSurface =
1860             Codec2Client::CreateInputSurface();
1861     if (!inputSurface) {
1862         if (property_get_int32("debug.stagefright.c2inputsurface", 0) == -1) {
1863             sp<IGraphicBufferProducer> gbp;
1864             sp<OmxGraphicBufferSource> gbs = new OmxGraphicBufferSource();
1865             status_t err = gbs->initCheck();
1866             if (err != OK) {
1867                 ALOGE("Failed to create persistent input surface: error %d", err);
1868                 return nullptr;
1869             }
1870             return new PersistentSurface(
1871                     gbs->getIGraphicBufferProducer(),
1872                     sp<IGraphicBufferSource>(
1873                         new Omx2IGraphicBufferSource(gbs)));
1874         } else {
1875             return nullptr;
1876         }
1877     }
1878     return new PersistentSurface(
1879             inputSurface->getGraphicBufferProducer(),
1880             static_cast<sp<android::hidl::base::V1_0::IBase>>(
1881             inputSurface->getHalInterface()));
1882 }
1883 
1884