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