xref: /aosp_15_r20/external/v4l2_codec2/components/DecodeComponent.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
1*0ec5a0ecSAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors. All rights reserved.
2*0ec5a0ecSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*0ec5a0ecSAndroid Build Coastguard Worker // found in the LICENSE file.
4*0ec5a0ecSAndroid Build Coastguard Worker 
5*0ec5a0ecSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
6*0ec5a0ecSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_VIDEO
7*0ec5a0ecSAndroid Build Coastguard Worker #define LOG_TAG "DecodeComponent"
8*0ec5a0ecSAndroid Build Coastguard Worker 
9*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/DecodeComponent.h>
10*0ec5a0ecSAndroid Build Coastguard Worker 
11*0ec5a0ecSAndroid Build Coastguard Worker #include <inttypes.h>
12*0ec5a0ecSAndroid Build Coastguard Worker #include <linux/videodev2.h>
13*0ec5a0ecSAndroid Build Coastguard Worker #include <stdint.h>
14*0ec5a0ecSAndroid Build Coastguard Worker 
15*0ec5a0ecSAndroid Build Coastguard Worker #include <memory>
16*0ec5a0ecSAndroid Build Coastguard Worker 
17*0ec5a0ecSAndroid Build Coastguard Worker #include <C2.h>
18*0ec5a0ecSAndroid Build Coastguard Worker #include <C2PlatformSupport.h>
19*0ec5a0ecSAndroid Build Coastguard Worker #include <Codec2Mapper.h>
20*0ec5a0ecSAndroid Build Coastguard Worker #include <SimpleC2Interface.h>
21*0ec5a0ecSAndroid Build Coastguard Worker #include <base/bind.h>
22*0ec5a0ecSAndroid Build Coastguard Worker #include <base/callback_helpers.h>
23*0ec5a0ecSAndroid Build Coastguard Worker #include <base/strings/stringprintf.h>
24*0ec5a0ecSAndroid Build Coastguard Worker #include <base/time/time.h>
25*0ec5a0ecSAndroid Build Coastguard Worker #include <cutils/properties.h>
26*0ec5a0ecSAndroid Build Coastguard Worker #include <log/log.h>
27*0ec5a0ecSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ColorUtils.h>
28*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Trace.h>
29*0ec5a0ecSAndroid Build Coastguard Worker 
30*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/Common.h>
31*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/H264NalParser.h>
32*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/HEVCNalParser.h>
33*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/VideoTypes.h>
34*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/BitstreamBuffer.h>
35*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/VideoFramePool.h>
36*0ec5a0ecSAndroid Build Coastguard Worker 
37*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
38*0ec5a0ecSAndroid Build Coastguard Worker namespace {
39*0ec5a0ecSAndroid Build Coastguard Worker 
40*0ec5a0ecSAndroid Build Coastguard Worker // Mask against 30 bits to avoid (undefined) wraparound on signed integer.
frameIndexToBitstreamId(c2_cntr64_t frameIndex)41*0ec5a0ecSAndroid Build Coastguard Worker int32_t frameIndexToBitstreamId(c2_cntr64_t frameIndex) {
42*0ec5a0ecSAndroid Build Coastguard Worker     return static_cast<int32_t>(frameIndex.peeku() & 0x3FFFFFFF);
43*0ec5a0ecSAndroid Build Coastguard Worker }
44*0ec5a0ecSAndroid Build Coastguard Worker 
parseCodedColorAspects(const C2ConstLinearBlock & input,std::optional<VideoCodec> codec,C2StreamColorAspectsInfo::input * codedAspects)45*0ec5a0ecSAndroid Build Coastguard Worker bool parseCodedColorAspects(const C2ConstLinearBlock& input, std::optional<VideoCodec> codec,
46*0ec5a0ecSAndroid Build Coastguard Worker                             C2StreamColorAspectsInfo::input* codedAspects) {
47*0ec5a0ecSAndroid Build Coastguard Worker     C2ReadView view = input.map().get();
48*0ec5a0ecSAndroid Build Coastguard Worker     NalParser::ColorAspects aspects;
49*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<NalParser> parser;
50*0ec5a0ecSAndroid Build Coastguard Worker     if (codec == VideoCodec::H264) {
51*0ec5a0ecSAndroid Build Coastguard Worker         parser = std::make_unique<H264NalParser>(view.data(), view.capacity());
52*0ec5a0ecSAndroid Build Coastguard Worker     } else if (codec == VideoCodec::HEVC) {
53*0ec5a0ecSAndroid Build Coastguard Worker         parser = std::make_unique<HEVCNalParser>(view.data(), view.capacity());
54*0ec5a0ecSAndroid Build Coastguard Worker     } else {
55*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Unsupported codec for finding color aspects");
56*0ec5a0ecSAndroid Build Coastguard Worker         return false;
57*0ec5a0ecSAndroid Build Coastguard Worker     }
58*0ec5a0ecSAndroid Build Coastguard Worker 
59*0ec5a0ecSAndroid Build Coastguard Worker     if (!parser->locateSPS()) {
60*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Couldn't find SPS");
61*0ec5a0ecSAndroid Build Coastguard Worker         return false;
62*0ec5a0ecSAndroid Build Coastguard Worker     }
63*0ec5a0ecSAndroid Build Coastguard Worker 
64*0ec5a0ecSAndroid Build Coastguard Worker     if (!parser->findCodedColorAspects(&aspects)) {
65*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Couldn't find color description in SPS");
66*0ec5a0ecSAndroid Build Coastguard Worker         return false;
67*0ec5a0ecSAndroid Build Coastguard Worker     }
68*0ec5a0ecSAndroid Build Coastguard Worker 
69*0ec5a0ecSAndroid Build Coastguard Worker     // Convert ISO color aspects to ColorUtils::ColorAspects.
70*0ec5a0ecSAndroid Build Coastguard Worker     ColorAspects colorAspects;
71*0ec5a0ecSAndroid Build Coastguard Worker     ColorUtils::convertIsoColorAspectsToCodecAspects(
72*0ec5a0ecSAndroid Build Coastguard Worker             aspects.primaries, aspects.transfer, aspects.coeffs, aspects.fullRange, colorAspects);
73*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Parsed ColorAspects from bitstream: (R:%d, P:%d, M:%d, T:%d)", colorAspects.mRange,
74*0ec5a0ecSAndroid Build Coastguard Worker           colorAspects.mPrimaries, colorAspects.mMatrixCoeffs, colorAspects.mTransfer);
75*0ec5a0ecSAndroid Build Coastguard Worker 
76*0ec5a0ecSAndroid Build Coastguard Worker     // Map ColorUtils::ColorAspects to C2StreamColorAspectsInfo::input parameter.
77*0ec5a0ecSAndroid Build Coastguard Worker     if (!C2Mapper::map(colorAspects.mPrimaries, &codedAspects->primaries)) {
78*0ec5a0ecSAndroid Build Coastguard Worker         codedAspects->primaries = C2Color::PRIMARIES_UNSPECIFIED;
79*0ec5a0ecSAndroid Build Coastguard Worker     }
80*0ec5a0ecSAndroid Build Coastguard Worker     if (!C2Mapper::map(colorAspects.mRange, &codedAspects->range)) {
81*0ec5a0ecSAndroid Build Coastguard Worker         codedAspects->range = C2Color::RANGE_UNSPECIFIED;
82*0ec5a0ecSAndroid Build Coastguard Worker     }
83*0ec5a0ecSAndroid Build Coastguard Worker     if (!C2Mapper::map(colorAspects.mMatrixCoeffs, &codedAspects->matrix)) {
84*0ec5a0ecSAndroid Build Coastguard Worker         codedAspects->matrix = C2Color::MATRIX_UNSPECIFIED;
85*0ec5a0ecSAndroid Build Coastguard Worker     }
86*0ec5a0ecSAndroid Build Coastguard Worker     if (!C2Mapper::map(colorAspects.mTransfer, &codedAspects->transfer)) {
87*0ec5a0ecSAndroid Build Coastguard Worker         codedAspects->transfer = C2Color::TRANSFER_UNSPECIFIED;
88*0ec5a0ecSAndroid Build Coastguard Worker     }
89*0ec5a0ecSAndroid Build Coastguard Worker 
90*0ec5a0ecSAndroid Build Coastguard Worker     return true;
91*0ec5a0ecSAndroid Build Coastguard Worker }
92*0ec5a0ecSAndroid Build Coastguard Worker 
isWorkDone(const C2Work & work)93*0ec5a0ecSAndroid Build Coastguard Worker bool isWorkDone(const C2Work& work) {
94*0ec5a0ecSAndroid Build Coastguard Worker     const int32_t bitstreamId = frameIndexToBitstreamId(work.input.ordinal.frameIndex);
95*0ec5a0ecSAndroid Build Coastguard Worker 
96*0ec5a0ecSAndroid Build Coastguard Worker     // Exception: EOS work should be processed by reportEOSWork().
97*0ec5a0ecSAndroid Build Coastguard Worker     // Always return false here no matter the work is actually done.
98*0ec5a0ecSAndroid Build Coastguard Worker     if (work.input.flags & C2FrameData::FLAG_END_OF_STREAM) return false;
99*0ec5a0ecSAndroid Build Coastguard Worker 
100*0ec5a0ecSAndroid Build Coastguard Worker     // Work is done when all conditions meet:
101*0ec5a0ecSAndroid Build Coastguard Worker     // 1. mDecoder has released the work's input buffer.
102*0ec5a0ecSAndroid Build Coastguard Worker     // 2. mDecoder has returned the work's output buffer in normal case,
103*0ec5a0ecSAndroid Build Coastguard Worker     //    or the input buffer is CSD, or we decide to drop the frame.
104*0ec5a0ecSAndroid Build Coastguard Worker     bool inputReleased = (work.input.buffers.front() == nullptr);
105*0ec5a0ecSAndroid Build Coastguard Worker     bool outputReturned = !work.worklets.front()->output.buffers.empty();
106*0ec5a0ecSAndroid Build Coastguard Worker     bool ignoreOutput = (work.input.flags & C2FrameData::FLAG_CODEC_CONFIG) ||
107*0ec5a0ecSAndroid Build Coastguard Worker                         (work.worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME);
108*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("work(%d): inputReleased: %d, outputReturned: %d, ignoreOutput: %d", bitstreamId,
109*0ec5a0ecSAndroid Build Coastguard Worker           inputReleased, outputReturned, ignoreOutput);
110*0ec5a0ecSAndroid Build Coastguard Worker     return inputReleased && (outputReturned || ignoreOutput);
111*0ec5a0ecSAndroid Build Coastguard Worker }
112*0ec5a0ecSAndroid Build Coastguard Worker 
isNoShowFrameWork(const C2Work & work,const C2WorkOrdinalStruct & currOrdinal)113*0ec5a0ecSAndroid Build Coastguard Worker bool isNoShowFrameWork(const C2Work& work, const C2WorkOrdinalStruct& currOrdinal) {
114*0ec5a0ecSAndroid Build Coastguard Worker     // We consider Work contains no-show frame when all conditions meet:
115*0ec5a0ecSAndroid Build Coastguard Worker     // 1. Work's ordinal is smaller than current ordinal.
116*0ec5a0ecSAndroid Build Coastguard Worker     // 2. Work's output buffer is not returned.
117*0ec5a0ecSAndroid Build Coastguard Worker     // 3. Work is not EOS, CSD, or marked with dropped frame.
118*0ec5a0ecSAndroid Build Coastguard Worker     bool smallOrdinal = (work.input.ordinal.timestamp < currOrdinal.timestamp) &&
119*0ec5a0ecSAndroid Build Coastguard Worker                         (work.input.ordinal.frameIndex < currOrdinal.frameIndex);
120*0ec5a0ecSAndroid Build Coastguard Worker     bool outputReturned = !work.worklets.front()->output.buffers.empty();
121*0ec5a0ecSAndroid Build Coastguard Worker     bool specialWork = (work.input.flags & C2FrameData::FLAG_END_OF_STREAM) ||
122*0ec5a0ecSAndroid Build Coastguard Worker                        (work.input.flags & C2FrameData::FLAG_CODEC_CONFIG) ||
123*0ec5a0ecSAndroid Build Coastguard Worker                        (work.worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME);
124*0ec5a0ecSAndroid Build Coastguard Worker     return smallOrdinal && !outputReturned && !specialWork;
125*0ec5a0ecSAndroid Build Coastguard Worker }
126*0ec5a0ecSAndroid Build Coastguard Worker 
127*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace
128*0ec5a0ecSAndroid Build Coastguard Worker 
DecodeComponent(uint32_t debugStreamId,const std::string & name,c2_node_id_t id,const std::shared_ptr<DecodeInterface> & intfImpl)129*0ec5a0ecSAndroid Build Coastguard Worker DecodeComponent::DecodeComponent(uint32_t debugStreamId, const std::string& name, c2_node_id_t id,
130*0ec5a0ecSAndroid Build Coastguard Worker                                  const std::shared_ptr<DecodeInterface>& intfImpl)
131*0ec5a0ecSAndroid Build Coastguard Worker       : mDebugStreamId(debugStreamId),
132*0ec5a0ecSAndroid Build Coastguard Worker         mIntfImpl(intfImpl),
133*0ec5a0ecSAndroid Build Coastguard Worker         mIntf(std::make_shared<SimpleInterface<DecodeInterface>>(name.c_str(), id, mIntfImpl)) {
134*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(%s)", __func__, name.c_str());
135*0ec5a0ecSAndroid Build Coastguard Worker     mIsSecure = name.find(".secure") != std::string::npos;
136*0ec5a0ecSAndroid Build Coastguard Worker }
137*0ec5a0ecSAndroid Build Coastguard Worker 
~DecodeComponent()138*0ec5a0ecSAndroid Build Coastguard Worker DecodeComponent::~DecodeComponent() {
139*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
140*0ec5a0ecSAndroid Build Coastguard Worker     if (mDecoderThread.IsRunning() && !mDecoderTaskRunner->RunsTasksInCurrentSequence()) {
141*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner->PostTask(FROM_HERE,
142*0ec5a0ecSAndroid Build Coastguard Worker                                      ::base::BindOnce(&DecodeComponent::releaseTask, mWeakThis));
143*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderThread.Stop();
144*0ec5a0ecSAndroid Build Coastguard Worker     }
145*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s() done", __func__);
146*0ec5a0ecSAndroid Build Coastguard Worker }
147*0ec5a0ecSAndroid Build Coastguard Worker 
start()148*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::start() {
149*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
150*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mStartStopLock);
151*0ec5a0ecSAndroid Build Coastguard Worker 
152*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
153*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState != ComponentState::STOPPED) {
154*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Could not start at %s state", ComponentStateToString(currentState));
155*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
156*0ec5a0ecSAndroid Build Coastguard Worker     }
157*0ec5a0ecSAndroid Build Coastguard Worker 
158*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDecoderThread.Start()) {
159*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Decoder thread failed to start.");
160*0ec5a0ecSAndroid Build Coastguard Worker         return C2_CORRUPTED;
161*0ec5a0ecSAndroid Build Coastguard Worker     }
162*0ec5a0ecSAndroid Build Coastguard Worker     mDecoderTaskRunner = mDecoderThread.task_runner();
163*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThis = mWeakThisFactory.GetWeakPtr();
164*0ec5a0ecSAndroid Build Coastguard Worker 
165*0ec5a0ecSAndroid Build Coastguard Worker     c2_status_t status = C2_CORRUPTED;
166*0ec5a0ecSAndroid Build Coastguard Worker     ::base::WaitableEvent done;
167*0ec5a0ecSAndroid Build Coastguard Worker     mDecoderTaskRunner->PostTask(
168*0ec5a0ecSAndroid Build Coastguard Worker             FROM_HERE, ::base::BindOnce(&DecodeComponent::startTask, mWeakThis,
169*0ec5a0ecSAndroid Build Coastguard Worker                                         ::base::Unretained(&status), ::base::Unretained(&done)));
170*0ec5a0ecSAndroid Build Coastguard Worker     done.Wait();
171*0ec5a0ecSAndroid Build Coastguard Worker 
172*0ec5a0ecSAndroid Build Coastguard Worker     if (status == C2_OK) mComponentState.store(ComponentState::RUNNING);
173*0ec5a0ecSAndroid Build Coastguard Worker     return status;
174*0ec5a0ecSAndroid Build Coastguard Worker }
175*0ec5a0ecSAndroid Build Coastguard Worker 
getVideoFramePool(const ui::Size & size,HalPixelFormat pixelFormat,size_t numBuffers)176*0ec5a0ecSAndroid Build Coastguard Worker std::unique_ptr<VideoFramePool> DecodeComponent::getVideoFramePool(const ui::Size& size,
177*0ec5a0ecSAndroid Build Coastguard Worker                                                                    HalPixelFormat pixelFormat,
178*0ec5a0ecSAndroid Build Coastguard Worker                                                                    size_t numBuffers) {
179*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
180*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
181*0ec5a0ecSAndroid Build Coastguard Worker 
182*0ec5a0ecSAndroid Build Coastguard Worker     auto sharedThis = weak_from_this().lock();
183*0ec5a0ecSAndroid Build Coastguard Worker     if (sharedThis == nullptr) {
184*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("%s(): DecodeComponent instance is destroyed.", __func__);
185*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
186*0ec5a0ecSAndroid Build Coastguard Worker     }
187*0ec5a0ecSAndroid Build Coastguard Worker 
188*0ec5a0ecSAndroid Build Coastguard Worker     // (b/157113946): Prevent malicious dynamic resolution change exhausts system memory.
189*0ec5a0ecSAndroid Build Coastguard Worker     constexpr int kMaximumSupportedArea = 4096 * 4096;
190*0ec5a0ecSAndroid Build Coastguard Worker     if (getArea(size).value_or(INT_MAX) > kMaximumSupportedArea) {
191*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("The output size (%dx%d) is larger than supported size (4096x4096)", size.width,
192*0ec5a0ecSAndroid Build Coastguard Worker               size.height);
193*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_BAD_VALUE);
194*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
195*0ec5a0ecSAndroid Build Coastguard Worker     }
196*0ec5a0ecSAndroid Build Coastguard Worker 
197*0ec5a0ecSAndroid Build Coastguard Worker     // Get block pool ID configured from the client.
198*0ec5a0ecSAndroid Build Coastguard Worker     auto poolId = mIntfImpl->getBlockPoolId();
199*0ec5a0ecSAndroid Build Coastguard Worker     ALOGI("Using C2BlockPool ID = %" PRIu64 " for allocating output buffers", poolId);
200*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2BlockPool> blockPool;
201*0ec5a0ecSAndroid Build Coastguard Worker     auto status = GetCodec2BlockPool(poolId, std::move(sharedThis), &blockPool);
202*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK) {
203*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Graphic block allocator is invalid: %d", status);
204*0ec5a0ecSAndroid Build Coastguard Worker         reportError(status);
205*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
206*0ec5a0ecSAndroid Build Coastguard Worker     }
207*0ec5a0ecSAndroid Build Coastguard Worker 
208*0ec5a0ecSAndroid Build Coastguard Worker     return VideoFramePool::Create(std::move(blockPool), numBuffers, size, pixelFormat, mIsSecure,
209*0ec5a0ecSAndroid Build Coastguard Worker                                   mDecoderTaskRunner);
210*0ec5a0ecSAndroid Build Coastguard Worker }
211*0ec5a0ecSAndroid Build Coastguard Worker 
stop()212*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::stop() {
213*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
214*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mStartStopLock);
215*0ec5a0ecSAndroid Build Coastguard Worker 
216*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
217*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState != ComponentState::RUNNING && currentState != ComponentState::ERROR) {
218*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Could not stop at %s state", ComponentStateToString(currentState));
219*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
220*0ec5a0ecSAndroid Build Coastguard Worker     }
221*0ec5a0ecSAndroid Build Coastguard Worker 
222*0ec5a0ecSAndroid Build Coastguard Worker     if (mDecoderThread.IsRunning()) {
223*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner->PostTask(FROM_HERE,
224*0ec5a0ecSAndroid Build Coastguard Worker                                      ::base::BindOnce(&DecodeComponent::stopTask, mWeakThis));
225*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderThread.Stop();
226*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner = nullptr;
227*0ec5a0ecSAndroid Build Coastguard Worker     }
228*0ec5a0ecSAndroid Build Coastguard Worker 
229*0ec5a0ecSAndroid Build Coastguard Worker     mComponentState.store(ComponentState::STOPPED);
230*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
231*0ec5a0ecSAndroid Build Coastguard Worker }
232*0ec5a0ecSAndroid Build Coastguard Worker 
stopTask()233*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::stopTask() {
234*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
235*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
236*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
237*0ec5a0ecSAndroid Build Coastguard Worker 
238*0ec5a0ecSAndroid Build Coastguard Worker     reportAbandonedWorks();
239*0ec5a0ecSAndroid Build Coastguard Worker     mIsDraining = false;
240*0ec5a0ecSAndroid Build Coastguard Worker 
241*0ec5a0ecSAndroid Build Coastguard Worker     releaseTask();
242*0ec5a0ecSAndroid Build Coastguard Worker }
243*0ec5a0ecSAndroid Build Coastguard Worker 
reset()244*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::reset() {
245*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
246*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
247*0ec5a0ecSAndroid Build Coastguard Worker 
248*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState == ComponentState::STOPPED)
249*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OK;
250*0ec5a0ecSAndroid Build Coastguard Worker 
251*0ec5a0ecSAndroid Build Coastguard Worker     return stop();
252*0ec5a0ecSAndroid Build Coastguard Worker }
253*0ec5a0ecSAndroid Build Coastguard Worker 
release()254*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::release() {
255*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
256*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mStartStopLock);
257*0ec5a0ecSAndroid Build Coastguard Worker 
258*0ec5a0ecSAndroid Build Coastguard Worker     if (mDecoderThread.IsRunning()) {
259*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner->PostTask(FROM_HERE,
260*0ec5a0ecSAndroid Build Coastguard Worker                                      ::base::BindOnce(&DecodeComponent::releaseTask, mWeakThis));
261*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderThread.Stop();
262*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner = nullptr;
263*0ec5a0ecSAndroid Build Coastguard Worker     }
264*0ec5a0ecSAndroid Build Coastguard Worker 
265*0ec5a0ecSAndroid Build Coastguard Worker     mComponentState.store(ComponentState::RELEASED);
266*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
267*0ec5a0ecSAndroid Build Coastguard Worker }
268*0ec5a0ecSAndroid Build Coastguard Worker 
releaseTask()269*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::releaseTask() {
270*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
271*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
272*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
273*0ec5a0ecSAndroid Build Coastguard Worker 
274*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThisFactory.InvalidateWeakPtrs();
275*0ec5a0ecSAndroid Build Coastguard Worker     mDecoder = nullptr;
276*0ec5a0ecSAndroid Build Coastguard Worker }
277*0ec5a0ecSAndroid Build Coastguard Worker 
setListener_vb(const std::shared_ptr<C2Component::Listener> & listener,c2_blocking_t mayBlock)278*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::setListener_vb(const std::shared_ptr<C2Component::Listener>& listener,
279*0ec5a0ecSAndroid Build Coastguard Worker                                             c2_blocking_t mayBlock) {
280*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
281*0ec5a0ecSAndroid Build Coastguard Worker 
282*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
283*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState == ComponentState::RELEASED ||
284*0ec5a0ecSAndroid Build Coastguard Worker         (currentState == ComponentState::RUNNING && listener)) {
285*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Could not set listener at %s state", ComponentStateToString(currentState));
286*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
287*0ec5a0ecSAndroid Build Coastguard Worker     }
288*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState == ComponentState::RUNNING && mayBlock != C2_MAY_BLOCK) {
289*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Could not set listener at %s state non-blocking",
290*0ec5a0ecSAndroid Build Coastguard Worker               ComponentStateToString(currentState));
291*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BLOCKING;
292*0ec5a0ecSAndroid Build Coastguard Worker     }
293*0ec5a0ecSAndroid Build Coastguard Worker 
294*0ec5a0ecSAndroid Build Coastguard Worker     // If the decoder thread is not running it's safe to update the listener directly.
295*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDecoderThread.IsRunning()) {
296*0ec5a0ecSAndroid Build Coastguard Worker         mListener = listener;
297*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OK;
298*0ec5a0ecSAndroid Build Coastguard Worker     }
299*0ec5a0ecSAndroid Build Coastguard Worker 
300*0ec5a0ecSAndroid Build Coastguard Worker     ::base::WaitableEvent done;
301*0ec5a0ecSAndroid Build Coastguard Worker     mDecoderTaskRunner->PostTask(
302*0ec5a0ecSAndroid Build Coastguard Worker             FROM_HERE, ::base::Bind(&DecodeComponent::setListenerTask, mWeakThis, listener, &done));
303*0ec5a0ecSAndroid Build Coastguard Worker     done.Wait();
304*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
305*0ec5a0ecSAndroid Build Coastguard Worker }
306*0ec5a0ecSAndroid Build Coastguard Worker 
setListenerTask(const std::shared_ptr<Listener> & listener,::base::WaitableEvent * done)307*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::setListenerTask(const std::shared_ptr<Listener>& listener,
308*0ec5a0ecSAndroid Build Coastguard Worker                                       ::base::WaitableEvent* done) {
309*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
310*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
311*0ec5a0ecSAndroid Build Coastguard Worker 
312*0ec5a0ecSAndroid Build Coastguard Worker     mListener = listener;
313*0ec5a0ecSAndroid Build Coastguard Worker     done->Signal();
314*0ec5a0ecSAndroid Build Coastguard Worker }
315*0ec5a0ecSAndroid Build Coastguard Worker 
queue_nb(std::list<std::unique_ptr<C2Work>> * const items)316*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::queue_nb(std::list<std::unique_ptr<C2Work>>* const items) {
317*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
318*0ec5a0ecSAndroid Build Coastguard Worker 
319*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
320*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState != ComponentState::RUNNING) {
321*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Could not queue at state: %s", ComponentStateToString(currentState));
322*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
323*0ec5a0ecSAndroid Build Coastguard Worker     }
324*0ec5a0ecSAndroid Build Coastguard Worker 
325*0ec5a0ecSAndroid Build Coastguard Worker     while (!items->empty()) {
326*0ec5a0ecSAndroid Build Coastguard Worker         if (ATRACE_ENABLED()) {
327*0ec5a0ecSAndroid Build Coastguard Worker             const std::string atraceLabel = ::base::StringPrintf("#%u C2Work", mDebugStreamId);
328*0ec5a0ecSAndroid Build Coastguard Worker             ATRACE_ASYNC_BEGIN(atraceLabel.c_str(),
329*0ec5a0ecSAndroid Build Coastguard Worker                                items->front()->input.ordinal.frameIndex.peekull());
330*0ec5a0ecSAndroid Build Coastguard Worker         }
331*0ec5a0ecSAndroid Build Coastguard Worker 
332*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner->PostTask(FROM_HERE,
333*0ec5a0ecSAndroid Build Coastguard Worker                                      ::base::BindOnce(&DecodeComponent::queueTask, mWeakThis,
334*0ec5a0ecSAndroid Build Coastguard Worker                                                       std::move(items->front())));
335*0ec5a0ecSAndroid Build Coastguard Worker         items->pop_front();
336*0ec5a0ecSAndroid Build Coastguard Worker     }
337*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
338*0ec5a0ecSAndroid Build Coastguard Worker }
339*0ec5a0ecSAndroid Build Coastguard Worker 
queueTask(std::unique_ptr<C2Work> work)340*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::queueTask(std::unique_ptr<C2Work> work) {
341*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
342*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): flags=0x%x, index=%llu, timestamp=%llu", __func__, work->input.flags,
343*0ec5a0ecSAndroid Build Coastguard Worker           work->input.ordinal.frameIndex.peekull(), work->input.ordinal.timestamp.peekull());
344*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
345*0ec5a0ecSAndroid Build Coastguard Worker 
346*0ec5a0ecSAndroid Build Coastguard Worker     if (work->worklets.size() != 1u || work->input.buffers.size() > 1u) {
347*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid work: worklets.size()=%zu, input.buffers.size()=%zu", work->worklets.size(),
348*0ec5a0ecSAndroid Build Coastguard Worker               work->input.buffers.size());
349*0ec5a0ecSAndroid Build Coastguard Worker         work->result = C2_CORRUPTED;
350*0ec5a0ecSAndroid Build Coastguard Worker         reportWork(std::move(work));
351*0ec5a0ecSAndroid Build Coastguard Worker         return;
352*0ec5a0ecSAndroid Build Coastguard Worker     }
353*0ec5a0ecSAndroid Build Coastguard Worker 
354*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.flags = static_cast<C2FrameData::flags_t>(0);
355*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.buffers.clear();
356*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.ordinal = work->input.ordinal;
357*0ec5a0ecSAndroid Build Coastguard Worker     if (work->input.buffers.empty()) {
358*0ec5a0ecSAndroid Build Coastguard Worker         // Client may queue a work with no input buffer for either it's EOS or empty CSD, otherwise
359*0ec5a0ecSAndroid Build Coastguard Worker         // every work must have one input buffer.
360*0ec5a0ecSAndroid Build Coastguard Worker         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) == 0 &&
361*0ec5a0ecSAndroid Build Coastguard Worker             (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) == 0) {
362*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Invalid work: work with no input buffer should be EOS or CSD.");
363*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_BAD_VALUE);
364*0ec5a0ecSAndroid Build Coastguard Worker             return;
365*0ec5a0ecSAndroid Build Coastguard Worker         }
366*0ec5a0ecSAndroid Build Coastguard Worker 
367*0ec5a0ecSAndroid Build Coastguard Worker         // Emplace a nullptr to unify the check for work done.
368*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Got a work with no input buffer! Emplace a nullptr inside.");
369*0ec5a0ecSAndroid Build Coastguard Worker         work->input.buffers.emplace_back(nullptr);
370*0ec5a0ecSAndroid Build Coastguard Worker     }
371*0ec5a0ecSAndroid Build Coastguard Worker 
372*0ec5a0ecSAndroid Build Coastguard Worker     mPendingWorks.push(std::move(work));
373*0ec5a0ecSAndroid Build Coastguard Worker     pumpPendingWorks();
374*0ec5a0ecSAndroid Build Coastguard Worker }
375*0ec5a0ecSAndroid Build Coastguard Worker 
pumpPendingWorks()376*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::pumpPendingWorks() {
377*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
378*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
379*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
380*0ec5a0ecSAndroid Build Coastguard Worker 
381*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
382*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState != ComponentState::RUNNING) {
383*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Could not pump C2Work at state: %s", ComponentStateToString(currentState));
384*0ec5a0ecSAndroid Build Coastguard Worker         return;
385*0ec5a0ecSAndroid Build Coastguard Worker     }
386*0ec5a0ecSAndroid Build Coastguard Worker 
387*0ec5a0ecSAndroid Build Coastguard Worker     while (!mPendingWorks.empty() && !mIsDraining) {
388*0ec5a0ecSAndroid Build Coastguard Worker         std::unique_ptr<C2Work> pendingWork(std::move(mPendingWorks.front()));
389*0ec5a0ecSAndroid Build Coastguard Worker         mPendingWorks.pop();
390*0ec5a0ecSAndroid Build Coastguard Worker 
391*0ec5a0ecSAndroid Build Coastguard Worker         const int32_t bitstreamId = frameIndexToBitstreamId(pendingWork->input.ordinal.frameIndex);
392*0ec5a0ecSAndroid Build Coastguard Worker         const bool isCSDWork = pendingWork->input.flags & C2FrameData::FLAG_CODEC_CONFIG;
393*0ec5a0ecSAndroid Build Coastguard Worker         const bool isEmptyWork = pendingWork->input.buffers.front() == nullptr;
394*0ec5a0ecSAndroid Build Coastguard Worker         const bool isEOSWork = pendingWork->input.flags & C2FrameData::FLAG_END_OF_STREAM;
395*0ec5a0ecSAndroid Build Coastguard Worker         const C2Work* work = pendingWork.get();
396*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Process C2Work bitstreamId=%d isCSDWork=%d, isEmptyWork=%d", bitstreamId, isCSDWork,
397*0ec5a0ecSAndroid Build Coastguard Worker               isEmptyWork);
398*0ec5a0ecSAndroid Build Coastguard Worker 
399*0ec5a0ecSAndroid Build Coastguard Worker         auto res = mWorksAtDecoder.insert(std::make_pair(bitstreamId, std::move(pendingWork)));
400*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW_IF(!res.second, "We already inserted bitstreamId %d to decoder?", bitstreamId);
401*0ec5a0ecSAndroid Build Coastguard Worker 
402*0ec5a0ecSAndroid Build Coastguard Worker         if (!isEmptyWork) {
403*0ec5a0ecSAndroid Build Coastguard Worker             if (isCSDWork) {
404*0ec5a0ecSAndroid Build Coastguard Worker                 processCSDWork(bitstreamId, work);
405*0ec5a0ecSAndroid Build Coastguard Worker             } else {
406*0ec5a0ecSAndroid Build Coastguard Worker                 processWork(bitstreamId, work);
407*0ec5a0ecSAndroid Build Coastguard Worker             }
408*0ec5a0ecSAndroid Build Coastguard Worker         }
409*0ec5a0ecSAndroid Build Coastguard Worker 
410*0ec5a0ecSAndroid Build Coastguard Worker         if (isEOSWork) {
411*0ec5a0ecSAndroid Build Coastguard Worker             mDecoder->drain(::base::BindOnce(&DecodeComponent::onDrainDone, mWeakThis));
412*0ec5a0ecSAndroid Build Coastguard Worker             mIsDraining = true;
413*0ec5a0ecSAndroid Build Coastguard Worker         }
414*0ec5a0ecSAndroid Build Coastguard Worker 
415*0ec5a0ecSAndroid Build Coastguard Worker         // Directly report the empty CSD work as finished.
416*0ec5a0ecSAndroid Build Coastguard Worker         if (isCSDWork && isEmptyWork) reportWorkIfFinished(bitstreamId);
417*0ec5a0ecSAndroid Build Coastguard Worker     }
418*0ec5a0ecSAndroid Build Coastguard Worker }
419*0ec5a0ecSAndroid Build Coastguard Worker 
processCSDWork(const int32_t bitstreamId,const C2Work * work)420*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::processCSDWork(const int32_t bitstreamId, const C2Work* work) {
421*0ec5a0ecSAndroid Build Coastguard Worker     // If input.buffers is not empty, the buffer should have meaningful content inside.
422*0ec5a0ecSAndroid Build Coastguard Worker     C2ConstLinearBlock linearBlock = work->input.buffers.front()->data().linearBlocks().front();
423*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(linearBlock.size() > 0u, "Input buffer of work(%d) is empty.", bitstreamId);
424*0ec5a0ecSAndroid Build Coastguard Worker 
425*0ec5a0ecSAndroid Build Coastguard Worker     if (mIntfImpl->getVideoCodec() == VideoCodec::VP9) {
426*0ec5a0ecSAndroid Build Coastguard Worker         // The VP9 decoder does not support and does not need the Codec Specific Data (CSD):
427*0ec5a0ecSAndroid Build Coastguard Worker         // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate.
428*0ec5a0ecSAndroid Build Coastguard Worker         // The most of its content (profile, level, bit depth and chroma subsampling)
429*0ec5a0ecSAndroid Build Coastguard Worker         // can be extracted directly from VP9 bitstream. Ignore CSD if it was passed.
430*0ec5a0ecSAndroid Build Coastguard Worker         reportWorkIfFinished(bitstreamId);
431*0ec5a0ecSAndroid Build Coastguard Worker         return;
432*0ec5a0ecSAndroid Build Coastguard Worker     } else if ((!mIsSecure && mIntfImpl->getVideoCodec() == VideoCodec::H264) ||
433*0ec5a0ecSAndroid Build Coastguard Worker                mIntfImpl->getVideoCodec() == VideoCodec::HEVC) {
434*0ec5a0ecSAndroid Build Coastguard Worker         // Try to parse color aspects from bitstream for CSD work of non-secure H264 codec or HEVC
435*0ec5a0ecSAndroid Build Coastguard Worker         // codec (HEVC will only be CENCv3 which is parseable for secure).
436*0ec5a0ecSAndroid Build Coastguard Worker         C2StreamColorAspectsInfo::input codedAspects = {0u};
437*0ec5a0ecSAndroid Build Coastguard Worker         if (parseCodedColorAspects(linearBlock, mIntfImpl->getVideoCodec(), &codedAspects)) {
438*0ec5a0ecSAndroid Build Coastguard Worker             std::vector<std::unique_ptr<C2SettingResult>> failures;
439*0ec5a0ecSAndroid Build Coastguard Worker             c2_status_t status = mIntfImpl->config({&codedAspects}, C2_MAY_BLOCK, &failures);
440*0ec5a0ecSAndroid Build Coastguard Worker             if (status != C2_OK) {
441*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("Failed to config color aspects to interface: %d", status);
442*0ec5a0ecSAndroid Build Coastguard Worker                 reportError(status);
443*0ec5a0ecSAndroid Build Coastguard Worker                 return;
444*0ec5a0ecSAndroid Build Coastguard Worker             }
445*0ec5a0ecSAndroid Build Coastguard Worker             // Record current frame index, color aspects should be updated only for output
446*0ec5a0ecSAndroid Build Coastguard Worker             // buffers whose frame indices are not less than this one.
447*0ec5a0ecSAndroid Build Coastguard Worker             mPendingColorAspectsChange = true;
448*0ec5a0ecSAndroid Build Coastguard Worker             mPendingColorAspectsChangeFrameIndex = work->input.ordinal.frameIndex.peeku();
449*0ec5a0ecSAndroid Build Coastguard Worker         }
450*0ec5a0ecSAndroid Build Coastguard Worker     }
451*0ec5a0ecSAndroid Build Coastguard Worker 
452*0ec5a0ecSAndroid Build Coastguard Worker     processWorkBuffer(bitstreamId, linearBlock);
453*0ec5a0ecSAndroid Build Coastguard Worker }
454*0ec5a0ecSAndroid Build Coastguard Worker 
processWork(const int32_t bitstreamId,const C2Work * work)455*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::processWork(const int32_t bitstreamId, const C2Work* work) {
456*0ec5a0ecSAndroid Build Coastguard Worker     // If input.buffers is not empty, the buffer should have meaningful content inside.
457*0ec5a0ecSAndroid Build Coastguard Worker     C2ConstLinearBlock linearBlock = work->input.buffers.front()->data().linearBlocks().front();
458*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(linearBlock.size() > 0u, "Input buffer of work(%d) is empty.", bitstreamId);
459*0ec5a0ecSAndroid Build Coastguard Worker 
460*0ec5a0ecSAndroid Build Coastguard Worker     processWorkBuffer(bitstreamId, linearBlock);
461*0ec5a0ecSAndroid Build Coastguard Worker }
462*0ec5a0ecSAndroid Build Coastguard Worker 
processWorkBuffer(const int32_t bitstreamId,const C2ConstLinearBlock & linearBlock)463*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::processWorkBuffer(const int32_t bitstreamId,
464*0ec5a0ecSAndroid Build Coastguard Worker                                         const C2ConstLinearBlock& linearBlock) {
465*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<ConstBitstreamBuffer> buffer = std::make_unique<ConstBitstreamBuffer>(
466*0ec5a0ecSAndroid Build Coastguard Worker             bitstreamId, linearBlock, linearBlock.offset(), linearBlock.size());
467*0ec5a0ecSAndroid Build Coastguard Worker     if (!buffer) {
468*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
469*0ec5a0ecSAndroid Build Coastguard Worker         return;
470*0ec5a0ecSAndroid Build Coastguard Worker     }
471*0ec5a0ecSAndroid Build Coastguard Worker     mDecoder->decode(std::move(buffer),
472*0ec5a0ecSAndroid Build Coastguard Worker                      ::base::BindOnce(&DecodeComponent::onDecodeDone, mWeakThis, bitstreamId));
473*0ec5a0ecSAndroid Build Coastguard Worker }
474*0ec5a0ecSAndroid Build Coastguard Worker 
onDecodeDone(int32_t bitstreamId,VideoDecoder::DecodeStatus status)475*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::onDecodeDone(int32_t bitstreamId, VideoDecoder::DecodeStatus status) {
476*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
477*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(bitstreamId=%d, status=%s)", __func__, bitstreamId,
478*0ec5a0ecSAndroid Build Coastguard Worker           VideoDecoder::DecodeStatusToString(status));
479*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
480*0ec5a0ecSAndroid Build Coastguard Worker 
481*0ec5a0ecSAndroid Build Coastguard Worker     auto it = mWorksAtDecoder.find(bitstreamId);
482*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(it != mWorksAtDecoder.end());
483*0ec5a0ecSAndroid Build Coastguard Worker     C2Work* work = it->second.get();
484*0ec5a0ecSAndroid Build Coastguard Worker 
485*0ec5a0ecSAndroid Build Coastguard Worker     switch (status) {
486*0ec5a0ecSAndroid Build Coastguard Worker     case VideoDecoder::DecodeStatus::kAborted:
487*0ec5a0ecSAndroid Build Coastguard Worker         work->input.buffers.front().reset();
488*0ec5a0ecSAndroid Build Coastguard Worker         work->worklets.front()->output.flags = static_cast<C2FrameData::flags_t>(
489*0ec5a0ecSAndroid Build Coastguard Worker                 work->worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME);
490*0ec5a0ecSAndroid Build Coastguard Worker         mOutputBitstreamIds.push(bitstreamId);
491*0ec5a0ecSAndroid Build Coastguard Worker 
492*0ec5a0ecSAndroid Build Coastguard Worker         pumpReportWork();
493*0ec5a0ecSAndroid Build Coastguard Worker         return;
494*0ec5a0ecSAndroid Build Coastguard Worker 
495*0ec5a0ecSAndroid Build Coastguard Worker     case VideoDecoder::DecodeStatus::kError:
496*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
497*0ec5a0ecSAndroid Build Coastguard Worker         return;
498*0ec5a0ecSAndroid Build Coastguard Worker 
499*0ec5a0ecSAndroid Build Coastguard Worker     case VideoDecoder::DecodeStatus::kOk:
500*0ec5a0ecSAndroid Build Coastguard Worker         // Release the input buffer.
501*0ec5a0ecSAndroid Build Coastguard Worker         work->input.buffers.front().reset();
502*0ec5a0ecSAndroid Build Coastguard Worker 
503*0ec5a0ecSAndroid Build Coastguard Worker         // CSD Work doesn't have output buffer, the corresponding onOutputFrameReady() won't be
504*0ec5a0ecSAndroid Build Coastguard Worker         // called. Push the bitstreamId here.
505*0ec5a0ecSAndroid Build Coastguard Worker         if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)
506*0ec5a0ecSAndroid Build Coastguard Worker             mOutputBitstreamIds.push(bitstreamId);
507*0ec5a0ecSAndroid Build Coastguard Worker 
508*0ec5a0ecSAndroid Build Coastguard Worker         pumpReportWork();
509*0ec5a0ecSAndroid Build Coastguard Worker         return;
510*0ec5a0ecSAndroid Build Coastguard Worker     }
511*0ec5a0ecSAndroid Build Coastguard Worker }
512*0ec5a0ecSAndroid Build Coastguard Worker 
onOutputFrameReady(std::unique_ptr<VideoFrame> frame)513*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::onOutputFrameReady(std::unique_ptr<VideoFrame> frame) {
514*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(bitstreamId=%d)", __func__, frame->getBitstreamId());
515*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
516*0ec5a0ecSAndroid Build Coastguard Worker 
517*0ec5a0ecSAndroid Build Coastguard Worker     const int32_t bitstreamId = frame->getBitstreamId();
518*0ec5a0ecSAndroid Build Coastguard Worker     auto it = mWorksAtDecoder.find(bitstreamId);
519*0ec5a0ecSAndroid Build Coastguard Worker     if (it == mWorksAtDecoder.end()) {
520*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Work with bitstreamId=%d not found, already abandoned?", bitstreamId);
521*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
522*0ec5a0ecSAndroid Build Coastguard Worker         return;
523*0ec5a0ecSAndroid Build Coastguard Worker     }
524*0ec5a0ecSAndroid Build Coastguard Worker     C2Work* work = it->second.get();
525*0ec5a0ecSAndroid Build Coastguard Worker 
526*0ec5a0ecSAndroid Build Coastguard Worker     C2ConstGraphicBlock constBlock = std::move(frame)->getGraphicBlock();
527*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(std::move(constBlock));
528*0ec5a0ecSAndroid Build Coastguard Worker     if (mPendingColorAspectsChange &&
529*0ec5a0ecSAndroid Build Coastguard Worker         work->input.ordinal.frameIndex.peeku() >= mPendingColorAspectsChangeFrameIndex) {
530*0ec5a0ecSAndroid Build Coastguard Worker         mIntfImpl->queryColorAspects(&mCurrentColorAspects);
531*0ec5a0ecSAndroid Build Coastguard Worker         mPendingColorAspectsChange = false;
532*0ec5a0ecSAndroid Build Coastguard Worker     }
533*0ec5a0ecSAndroid Build Coastguard Worker     if (mCurrentColorAspects) {
534*0ec5a0ecSAndroid Build Coastguard Worker         buffer->setInfo(mCurrentColorAspects);
535*0ec5a0ecSAndroid Build Coastguard Worker     }
536*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.buffers.emplace_back(std::move(buffer));
537*0ec5a0ecSAndroid Build Coastguard Worker 
538*0ec5a0ecSAndroid Build Coastguard Worker     // Check no-show frame by timestamps for VP8/VP9 cases before reporting the current work.
539*0ec5a0ecSAndroid Build Coastguard Worker     if (mIntfImpl->getVideoCodec() == VideoCodec::VP8 ||
540*0ec5a0ecSAndroid Build Coastguard Worker         mIntfImpl->getVideoCodec() == VideoCodec::VP9) {
541*0ec5a0ecSAndroid Build Coastguard Worker         detectNoShowFrameWorksAndReportIfFinished(work->input.ordinal);
542*0ec5a0ecSAndroid Build Coastguard Worker     }
543*0ec5a0ecSAndroid Build Coastguard Worker 
544*0ec5a0ecSAndroid Build Coastguard Worker     mOutputBitstreamIds.push(bitstreamId);
545*0ec5a0ecSAndroid Build Coastguard Worker     pumpReportWork();
546*0ec5a0ecSAndroid Build Coastguard Worker }
547*0ec5a0ecSAndroid Build Coastguard Worker 
detectNoShowFrameWorksAndReportIfFinished(const C2WorkOrdinalStruct & currOrdinal)548*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::detectNoShowFrameWorksAndReportIfFinished(
549*0ec5a0ecSAndroid Build Coastguard Worker         const C2WorkOrdinalStruct& currOrdinal) {
550*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
551*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
552*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
553*0ec5a0ecSAndroid Build Coastguard Worker 
554*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<int32_t> noShowFrameBitstreamIds;
555*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& kv : mWorksAtDecoder) {
556*0ec5a0ecSAndroid Build Coastguard Worker         const int32_t bitstreamId = kv.first;
557*0ec5a0ecSAndroid Build Coastguard Worker         const C2Work* work = kv.second.get();
558*0ec5a0ecSAndroid Build Coastguard Worker 
559*0ec5a0ecSAndroid Build Coastguard Worker         // A work in mWorksAtDecoder would be considered to have no-show frame if there is no
560*0ec5a0ecSAndroid Build Coastguard Worker         // corresponding output buffer returned while the one of the work with latter timestamp is
561*0ec5a0ecSAndroid Build Coastguard Worker         // already returned. (VD is outputted in display order.)
562*0ec5a0ecSAndroid Build Coastguard Worker         if (isNoShowFrameWork(*work, currOrdinal)) {
563*0ec5a0ecSAndroid Build Coastguard Worker             work->worklets.front()->output.flags = C2FrameData::FLAG_DROP_FRAME;
564*0ec5a0ecSAndroid Build Coastguard Worker 
565*0ec5a0ecSAndroid Build Coastguard Worker             // We need to call reportWorkIfFinished() for all detected no-show frame works. However,
566*0ec5a0ecSAndroid Build Coastguard Worker             // we should do it after the detection loop since reportWorkIfFinished() may erase
567*0ec5a0ecSAndroid Build Coastguard Worker             // entries in |mWorksAtDecoder|.
568*0ec5a0ecSAndroid Build Coastguard Worker             noShowFrameBitstreamIds.push_back(bitstreamId);
569*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Detected no-show frame work index=%llu timestamp=%llu",
570*0ec5a0ecSAndroid Build Coastguard Worker                   work->input.ordinal.frameIndex.peekull(),
571*0ec5a0ecSAndroid Build Coastguard Worker                   work->input.ordinal.timestamp.peekull());
572*0ec5a0ecSAndroid Build Coastguard Worker         }
573*0ec5a0ecSAndroid Build Coastguard Worker     }
574*0ec5a0ecSAndroid Build Coastguard Worker 
575*0ec5a0ecSAndroid Build Coastguard Worker     // Try to report works with no-show frame.
576*0ec5a0ecSAndroid Build Coastguard Worker     for (const int32_t bitstreamId : noShowFrameBitstreamIds) reportWorkIfFinished(bitstreamId);
577*0ec5a0ecSAndroid Build Coastguard Worker }
578*0ec5a0ecSAndroid Build Coastguard Worker 
pumpReportWork()579*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::pumpReportWork() {
580*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
581*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
582*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
583*0ec5a0ecSAndroid Build Coastguard Worker 
584*0ec5a0ecSAndroid Build Coastguard Worker     while (!mOutputBitstreamIds.empty()) {
585*0ec5a0ecSAndroid Build Coastguard Worker         if (!reportWorkIfFinished(mOutputBitstreamIds.front())) break;
586*0ec5a0ecSAndroid Build Coastguard Worker         mOutputBitstreamIds.pop();
587*0ec5a0ecSAndroid Build Coastguard Worker     }
588*0ec5a0ecSAndroid Build Coastguard Worker }
589*0ec5a0ecSAndroid Build Coastguard Worker 
reportWorkIfFinished(int32_t bitstreamId)590*0ec5a0ecSAndroid Build Coastguard Worker bool DecodeComponent::reportWorkIfFinished(int32_t bitstreamId) {
591*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
592*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(bitstreamId = %d)", __func__, bitstreamId);
593*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
594*0ec5a0ecSAndroid Build Coastguard Worker 
595*0ec5a0ecSAndroid Build Coastguard Worker     // EOS work will not be reported here. reportEOSWork() does it.
596*0ec5a0ecSAndroid Build Coastguard Worker     if (mIsDraining && mWorksAtDecoder.size() == 1u) {
597*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("work(bitstreamId = %d) is EOS Work.", bitstreamId);
598*0ec5a0ecSAndroid Build Coastguard Worker         return false;
599*0ec5a0ecSAndroid Build Coastguard Worker     }
600*0ec5a0ecSAndroid Build Coastguard Worker 
601*0ec5a0ecSAndroid Build Coastguard Worker     auto it = mWorksAtDecoder.find(bitstreamId);
602*0ec5a0ecSAndroid Build Coastguard Worker     if (it == mWorksAtDecoder.end()) {
603*0ec5a0ecSAndroid Build Coastguard Worker         ALOGI("work(bitstreamId = %d) is dropped, skip.", bitstreamId);
604*0ec5a0ecSAndroid Build Coastguard Worker         return true;
605*0ec5a0ecSAndroid Build Coastguard Worker     }
606*0ec5a0ecSAndroid Build Coastguard Worker 
607*0ec5a0ecSAndroid Build Coastguard Worker     if (!isWorkDone(*(it->second))) {
608*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("work(bitstreamId = %d) is not done yet.", bitstreamId);
609*0ec5a0ecSAndroid Build Coastguard Worker         return false;
610*0ec5a0ecSAndroid Build Coastguard Worker     }
611*0ec5a0ecSAndroid Build Coastguard Worker 
612*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<C2Work> work = std::move(it->second);
613*0ec5a0ecSAndroid Build Coastguard Worker     mWorksAtDecoder.erase(it);
614*0ec5a0ecSAndroid Build Coastguard Worker 
615*0ec5a0ecSAndroid Build Coastguard Worker     work->result = C2_OK;
616*0ec5a0ecSAndroid Build Coastguard Worker     work->workletsProcessed = static_cast<uint32_t>(work->worklets.size());
617*0ec5a0ecSAndroid Build Coastguard Worker     // A work with neither flags nor output buffer would be treated as no-corresponding
618*0ec5a0ecSAndroid Build Coastguard Worker     // output by C2 framework, and regain pipeline capacity immediately.
619*0ec5a0ecSAndroid Build Coastguard Worker     if (work->worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME)
620*0ec5a0ecSAndroid Build Coastguard Worker         work->worklets.front()->output.flags = static_cast<C2FrameData::flags_t>(0);
621*0ec5a0ecSAndroid Build Coastguard Worker 
622*0ec5a0ecSAndroid Build Coastguard Worker     return reportWork(std::move(work));
623*0ec5a0ecSAndroid Build Coastguard Worker }
624*0ec5a0ecSAndroid Build Coastguard Worker 
reportEOSWork()625*0ec5a0ecSAndroid Build Coastguard Worker bool DecodeComponent::reportEOSWork() {
626*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
627*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
628*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
629*0ec5a0ecSAndroid Build Coastguard Worker 
630*0ec5a0ecSAndroid Build Coastguard Worker     const auto it =
631*0ec5a0ecSAndroid Build Coastguard Worker             std::find_if(mWorksAtDecoder.begin(), mWorksAtDecoder.end(), [](const auto& kv) {
632*0ec5a0ecSAndroid Build Coastguard Worker                 return kv.second->input.flags & C2FrameData::FLAG_END_OF_STREAM;
633*0ec5a0ecSAndroid Build Coastguard Worker             });
634*0ec5a0ecSAndroid Build Coastguard Worker     if (it == mWorksAtDecoder.end()) {
635*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to find EOS work.");
636*0ec5a0ecSAndroid Build Coastguard Worker         return false;
637*0ec5a0ecSAndroid Build Coastguard Worker     }
638*0ec5a0ecSAndroid Build Coastguard Worker 
639*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<C2Work> eosWork(std::move(it->second));
640*0ec5a0ecSAndroid Build Coastguard Worker     mWorksAtDecoder.erase(it);
641*0ec5a0ecSAndroid Build Coastguard Worker 
642*0ec5a0ecSAndroid Build Coastguard Worker     eosWork->result = C2_OK;
643*0ec5a0ecSAndroid Build Coastguard Worker     eosWork->workletsProcessed = static_cast<uint32_t>(eosWork->worklets.size());
644*0ec5a0ecSAndroid Build Coastguard Worker     eosWork->worklets.front()->output.flags = C2FrameData::FLAG_END_OF_STREAM;
645*0ec5a0ecSAndroid Build Coastguard Worker     if (!eosWork->input.buffers.empty()) eosWork->input.buffers.front().reset();
646*0ec5a0ecSAndroid Build Coastguard Worker 
647*0ec5a0ecSAndroid Build Coastguard Worker     if (!mWorksAtDecoder.empty()) {
648*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("There are remaining works except EOS work. abandon them.");
649*0ec5a0ecSAndroid Build Coastguard Worker         for (const auto& kv : mWorksAtDecoder) {
650*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("bitstreamId(%d) => Work index=%llu, timestamp=%llu", kv.first,
651*0ec5a0ecSAndroid Build Coastguard Worker                   kv.second->input.ordinal.frameIndex.peekull(),
652*0ec5a0ecSAndroid Build Coastguard Worker                   kv.second->input.ordinal.timestamp.peekull());
653*0ec5a0ecSAndroid Build Coastguard Worker         }
654*0ec5a0ecSAndroid Build Coastguard Worker         reportAbandonedWorks();
655*0ec5a0ecSAndroid Build Coastguard Worker     }
656*0ec5a0ecSAndroid Build Coastguard Worker 
657*0ec5a0ecSAndroid Build Coastguard Worker     return reportWork(std::move(eosWork));
658*0ec5a0ecSAndroid Build Coastguard Worker }
659*0ec5a0ecSAndroid Build Coastguard Worker 
reportWork(std::unique_ptr<C2Work> work)660*0ec5a0ecSAndroid Build Coastguard Worker bool DecodeComponent::reportWork(std::unique_ptr<C2Work> work) {
661*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
662*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(work=%llu)", __func__, work->input.ordinal.frameIndex.peekull());
663*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
664*0ec5a0ecSAndroid Build Coastguard Worker 
665*0ec5a0ecSAndroid Build Coastguard Worker     if (!mListener) {
666*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("mListener is nullptr, setListener_vb() not called?");
667*0ec5a0ecSAndroid Build Coastguard Worker         return false;
668*0ec5a0ecSAndroid Build Coastguard Worker     }
669*0ec5a0ecSAndroid Build Coastguard Worker 
670*0ec5a0ecSAndroid Build Coastguard Worker     if (ATRACE_ENABLED()) {
671*0ec5a0ecSAndroid Build Coastguard Worker         const std::string atraceLabel = ::base::StringPrintf("#%u C2Work", mDebugStreamId);
672*0ec5a0ecSAndroid Build Coastguard Worker         ATRACE_ASYNC_END(atraceLabel.c_str(), work->input.ordinal.frameIndex.peekull());
673*0ec5a0ecSAndroid Build Coastguard Worker     }
674*0ec5a0ecSAndroid Build Coastguard Worker     std::list<std::unique_ptr<C2Work>> finishedWorks;
675*0ec5a0ecSAndroid Build Coastguard Worker     finishedWorks.emplace_back(std::move(work));
676*0ec5a0ecSAndroid Build Coastguard Worker     mListener->onWorkDone_nb(weak_from_this(), std::move(finishedWorks));
677*0ec5a0ecSAndroid Build Coastguard Worker     return true;
678*0ec5a0ecSAndroid Build Coastguard Worker }
679*0ec5a0ecSAndroid Build Coastguard Worker 
flush_sm(flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const)680*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::flush_sm(flush_mode_t mode,
681*0ec5a0ecSAndroid Build Coastguard Worker                                       std::list<std::unique_ptr<C2Work>>* const /* flushedWork */) {
682*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
683*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
684*0ec5a0ecSAndroid Build Coastguard Worker 
685*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
686*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState != ComponentState::RUNNING) {
687*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Could not flush at state: %s", ComponentStateToString(currentState));
688*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
689*0ec5a0ecSAndroid Build Coastguard Worker     }
690*0ec5a0ecSAndroid Build Coastguard Worker     if (mode != FLUSH_COMPONENT) {
691*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OMITTED;  // Tunneling is not supported by now
692*0ec5a0ecSAndroid Build Coastguard Worker     }
693*0ec5a0ecSAndroid Build Coastguard Worker 
694*0ec5a0ecSAndroid Build Coastguard Worker     mDecoderTaskRunner->PostTask(FROM_HERE,
695*0ec5a0ecSAndroid Build Coastguard Worker                                  ::base::BindOnce(&DecodeComponent::flushTask, mWeakThis));
696*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
697*0ec5a0ecSAndroid Build Coastguard Worker }
698*0ec5a0ecSAndroid Build Coastguard Worker 
flushTask()699*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::flushTask() {
700*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
701*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
702*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
703*0ec5a0ecSAndroid Build Coastguard Worker 
704*0ec5a0ecSAndroid Build Coastguard Worker     mDecoder->flush();
705*0ec5a0ecSAndroid Build Coastguard Worker     reportAbandonedWorks();
706*0ec5a0ecSAndroid Build Coastguard Worker 
707*0ec5a0ecSAndroid Build Coastguard Worker     // Pending EOS work will be abandoned here due to component flush if any.
708*0ec5a0ecSAndroid Build Coastguard Worker     mIsDraining = false;
709*0ec5a0ecSAndroid Build Coastguard Worker }
710*0ec5a0ecSAndroid Build Coastguard Worker 
reportAbandonedWorks()711*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::reportAbandonedWorks() {
712*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
713*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
714*0ec5a0ecSAndroid Build Coastguard Worker 
715*0ec5a0ecSAndroid Build Coastguard Worker     std::list<std::unique_ptr<C2Work>> abandonedWorks;
716*0ec5a0ecSAndroid Build Coastguard Worker     while (!mPendingWorks.empty()) {
717*0ec5a0ecSAndroid Build Coastguard Worker         abandonedWorks.emplace_back(std::move(mPendingWorks.front()));
718*0ec5a0ecSAndroid Build Coastguard Worker         mPendingWorks.pop();
719*0ec5a0ecSAndroid Build Coastguard Worker     }
720*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& kv : mWorksAtDecoder) {
721*0ec5a0ecSAndroid Build Coastguard Worker         abandonedWorks.emplace_back(std::move(kv.second));
722*0ec5a0ecSAndroid Build Coastguard Worker     }
723*0ec5a0ecSAndroid Build Coastguard Worker     mWorksAtDecoder.clear();
724*0ec5a0ecSAndroid Build Coastguard Worker 
725*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& work : abandonedWorks) {
726*0ec5a0ecSAndroid Build Coastguard Worker         // TODO: correlate the definition of flushed work result to framework.
727*0ec5a0ecSAndroid Build Coastguard Worker         work->result = C2_NOT_FOUND;
728*0ec5a0ecSAndroid Build Coastguard Worker         // When the work is abandoned, buffer in input.buffers shall reset by component.
729*0ec5a0ecSAndroid Build Coastguard Worker         if (!work->input.buffers.empty()) {
730*0ec5a0ecSAndroid Build Coastguard Worker             work->input.buffers.front().reset();
731*0ec5a0ecSAndroid Build Coastguard Worker         }
732*0ec5a0ecSAndroid Build Coastguard Worker 
733*0ec5a0ecSAndroid Build Coastguard Worker         if (ATRACE_ENABLED()) {
734*0ec5a0ecSAndroid Build Coastguard Worker             const std::string atraceLabel = ::base::StringPrintf("#%u C2Work", mDebugStreamId);
735*0ec5a0ecSAndroid Build Coastguard Worker             ATRACE_ASYNC_END(atraceLabel.c_str(), work->input.ordinal.frameIndex.peekull());
736*0ec5a0ecSAndroid Build Coastguard Worker         }
737*0ec5a0ecSAndroid Build Coastguard Worker     }
738*0ec5a0ecSAndroid Build Coastguard Worker     if (!abandonedWorks.empty()) {
739*0ec5a0ecSAndroid Build Coastguard Worker         if (!mListener) {
740*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("mListener is nullptr, setListener_vb() not called?");
741*0ec5a0ecSAndroid Build Coastguard Worker             return;
742*0ec5a0ecSAndroid Build Coastguard Worker         }
743*0ec5a0ecSAndroid Build Coastguard Worker         mListener->onWorkDone_nb(weak_from_this(), std::move(abandonedWorks));
744*0ec5a0ecSAndroid Build Coastguard Worker     }
745*0ec5a0ecSAndroid Build Coastguard Worker }
746*0ec5a0ecSAndroid Build Coastguard Worker 
drain_nb(drain_mode_t mode)747*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::drain_nb(drain_mode_t mode) {
748*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(mode=%u)", __func__, mode);
749*0ec5a0ecSAndroid Build Coastguard Worker 
750*0ec5a0ecSAndroid Build Coastguard Worker     auto currentState = mComponentState.load();
751*0ec5a0ecSAndroid Build Coastguard Worker     if (currentState != ComponentState::RUNNING) {
752*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Could not drain at state: %s", ComponentStateToString(currentState));
753*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
754*0ec5a0ecSAndroid Build Coastguard Worker     }
755*0ec5a0ecSAndroid Build Coastguard Worker 
756*0ec5a0ecSAndroid Build Coastguard Worker     switch (mode) {
757*0ec5a0ecSAndroid Build Coastguard Worker     case DRAIN_CHAIN:
758*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OMITTED;  // Tunneling is not supported.
759*0ec5a0ecSAndroid Build Coastguard Worker 
760*0ec5a0ecSAndroid Build Coastguard Worker     case DRAIN_COMPONENT_NO_EOS:
761*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OK;  // Do nothing special.
762*0ec5a0ecSAndroid Build Coastguard Worker 
763*0ec5a0ecSAndroid Build Coastguard Worker     case DRAIN_COMPONENT_WITH_EOS:
764*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner->PostTask(FROM_HERE,
765*0ec5a0ecSAndroid Build Coastguard Worker                                      ::base::BindOnce(&DecodeComponent::drainTask, mWeakThis));
766*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OK;
767*0ec5a0ecSAndroid Build Coastguard Worker     }
768*0ec5a0ecSAndroid Build Coastguard Worker }
769*0ec5a0ecSAndroid Build Coastguard Worker 
drainTask()770*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::drainTask() {
771*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
772*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
773*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
774*0ec5a0ecSAndroid Build Coastguard Worker 
775*0ec5a0ecSAndroid Build Coastguard Worker     if (!mPendingWorks.empty()) {
776*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Set EOS flag at last queued work.");
777*0ec5a0ecSAndroid Build Coastguard Worker         auto& flags = mPendingWorks.back()->input.flags;
778*0ec5a0ecSAndroid Build Coastguard Worker         flags = static_cast<C2FrameData::flags_t>(flags | C2FrameData::FLAG_END_OF_STREAM);
779*0ec5a0ecSAndroid Build Coastguard Worker         return;
780*0ec5a0ecSAndroid Build Coastguard Worker     }
781*0ec5a0ecSAndroid Build Coastguard Worker 
782*0ec5a0ecSAndroid Build Coastguard Worker     if (!mWorksAtDecoder.empty()) {
783*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Drain the pending works at the decoder.");
784*0ec5a0ecSAndroid Build Coastguard Worker         mDecoder->drain(::base::BindOnce(&DecodeComponent::onDrainDone, mWeakThis));
785*0ec5a0ecSAndroid Build Coastguard Worker         mIsDraining = true;
786*0ec5a0ecSAndroid Build Coastguard Worker     }
787*0ec5a0ecSAndroid Build Coastguard Worker }
788*0ec5a0ecSAndroid Build Coastguard Worker 
onDrainDone(VideoDecoder::DecodeStatus status)789*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::onDrainDone(VideoDecoder::DecodeStatus status) {
790*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(status=%s)", __func__, VideoDecoder::DecodeStatusToString(status));
791*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
792*0ec5a0ecSAndroid Build Coastguard Worker 
793*0ec5a0ecSAndroid Build Coastguard Worker     switch (status) {
794*0ec5a0ecSAndroid Build Coastguard Worker     case VideoDecoder::DecodeStatus::kAborted:
795*0ec5a0ecSAndroid Build Coastguard Worker         return;
796*0ec5a0ecSAndroid Build Coastguard Worker 
797*0ec5a0ecSAndroid Build Coastguard Worker     case VideoDecoder::DecodeStatus::kError:
798*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
799*0ec5a0ecSAndroid Build Coastguard Worker         return;
800*0ec5a0ecSAndroid Build Coastguard Worker 
801*0ec5a0ecSAndroid Build Coastguard Worker     case VideoDecoder::DecodeStatus::kOk:
802*0ec5a0ecSAndroid Build Coastguard Worker         mIsDraining = false;
803*0ec5a0ecSAndroid Build Coastguard Worker         if (!reportEOSWork()) {
804*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_CORRUPTED);
805*0ec5a0ecSAndroid Build Coastguard Worker             return;
806*0ec5a0ecSAndroid Build Coastguard Worker         }
807*0ec5a0ecSAndroid Build Coastguard Worker 
808*0ec5a0ecSAndroid Build Coastguard Worker         mDecoderTaskRunner->PostTask(
809*0ec5a0ecSAndroid Build Coastguard Worker                 FROM_HERE, ::base::BindOnce(&DecodeComponent::pumpPendingWorks, mWeakThis));
810*0ec5a0ecSAndroid Build Coastguard Worker         return;
811*0ec5a0ecSAndroid Build Coastguard Worker     }
812*0ec5a0ecSAndroid Build Coastguard Worker }
813*0ec5a0ecSAndroid Build Coastguard Worker 
reportError(c2_status_t error)814*0ec5a0ecSAndroid Build Coastguard Worker void DecodeComponent::reportError(c2_status_t error) {
815*0ec5a0ecSAndroid Build Coastguard Worker     ALOGE("%s(error=%u)", __func__, static_cast<uint32_t>(error));
816*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
817*0ec5a0ecSAndroid Build Coastguard Worker 
818*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState.load() == ComponentState::ERROR) return;
819*0ec5a0ecSAndroid Build Coastguard Worker     mComponentState.store(ComponentState::ERROR);
820*0ec5a0ecSAndroid Build Coastguard Worker 
821*0ec5a0ecSAndroid Build Coastguard Worker     if (!mListener) {
822*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("mListener is nullptr, setListener_vb() not called?");
823*0ec5a0ecSAndroid Build Coastguard Worker         return;
824*0ec5a0ecSAndroid Build Coastguard Worker     }
825*0ec5a0ecSAndroid Build Coastguard Worker     mListener->onError_nb(weak_from_this(), static_cast<uint32_t>(error));
826*0ec5a0ecSAndroid Build Coastguard Worker }
827*0ec5a0ecSAndroid Build Coastguard Worker 
announce_nb(const std::vector<C2WorkOutline> &)828*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t DecodeComponent::announce_nb(const std::vector<C2WorkOutline>& /* items */) {
829*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OMITTED;  // Tunneling is not supported by now
830*0ec5a0ecSAndroid Build Coastguard Worker }
831*0ec5a0ecSAndroid Build Coastguard Worker 
intf()832*0ec5a0ecSAndroid Build Coastguard Worker std::shared_ptr<C2ComponentInterface> DecodeComponent::intf() {
833*0ec5a0ecSAndroid Build Coastguard Worker     return mIntf;
834*0ec5a0ecSAndroid Build Coastguard Worker }
835*0ec5a0ecSAndroid Build Coastguard Worker 
836*0ec5a0ecSAndroid Build Coastguard Worker // static
ComponentStateToString(ComponentState state)837*0ec5a0ecSAndroid Build Coastguard Worker const char* DecodeComponent::ComponentStateToString(ComponentState state) {
838*0ec5a0ecSAndroid Build Coastguard Worker     switch (state) {
839*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::STOPPED:
840*0ec5a0ecSAndroid Build Coastguard Worker         return "STOPPED";
841*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::RUNNING:
842*0ec5a0ecSAndroid Build Coastguard Worker         return "RUNNING";
843*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::RELEASED:
844*0ec5a0ecSAndroid Build Coastguard Worker         return "RELEASED";
845*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::ERROR:
846*0ec5a0ecSAndroid Build Coastguard Worker         return "ERROR";
847*0ec5a0ecSAndroid Build Coastguard Worker     }
848*0ec5a0ecSAndroid Build Coastguard Worker }
849*0ec5a0ecSAndroid Build Coastguard Worker 
850*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
851