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