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