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