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