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 #include "media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h"
6 #include <cstddef>
7
8 #include <memory>
9 #include <tuple>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/callback_forward.h"
14 #include "base/logging.h"
15 #include "base/optional.h"
16 #include "base/sequence_checker.h"
17 #include "base/sequenced_task_runner.h"
18 #include "media/base/video_codecs.h"
19 #include "media/gpu/chromeos/dmabuf_video_frame_pool.h"
20 #include "media/gpu/macros.h"
21 #include "media/gpu/v4l2/v4l2_device.h"
22 #include "media/gpu/v4l2/v4l2_vda_helpers.h"
23 #include "media/gpu/v4l2/v4l2_video_decoder_backend.h"
24
25 namespace media {
26
DecodeRequest(scoped_refptr<DecoderBuffer> buf,VideoDecoder::DecodeCB cb,int32_t id)27 V4L2StatefulVideoDecoderBackend::DecodeRequest::DecodeRequest(
28 scoped_refptr<DecoderBuffer> buf,
29 VideoDecoder::DecodeCB cb,
30 int32_t id)
31 : buffer(std::move(buf)), decode_cb(std::move(cb)), bitstream_id(id) {}
32
33 V4L2StatefulVideoDecoderBackend::DecodeRequest::DecodeRequest(DecodeRequest&&) =
34 default;
35 V4L2StatefulVideoDecoderBackend::DecodeRequest&
36 V4L2StatefulVideoDecoderBackend::DecodeRequest::operator=(DecodeRequest&&) =
37 default;
38
39 V4L2StatefulVideoDecoderBackend::DecodeRequest::~DecodeRequest() = default;
40
IsCompleted() const41 bool V4L2StatefulVideoDecoderBackend::DecodeRequest::IsCompleted() const {
42 return bytes_used == buffer->data_size();
43 }
44
V4L2StatefulVideoDecoderBackend(Client * const client,scoped_refptr<V4L2Device> device,VideoCodecProfile profile,scoped_refptr<base::SequencedTaskRunner> task_runner)45 V4L2StatefulVideoDecoderBackend::V4L2StatefulVideoDecoderBackend(
46 Client* const client,
47 scoped_refptr<V4L2Device> device,
48 VideoCodecProfile profile,
49 scoped_refptr<base::SequencedTaskRunner> task_runner)
50 : V4L2VideoDecoderBackend(client, std::move(device)),
51 profile_(profile),
52 task_runner_(task_runner) {
53 DVLOGF(3);
54 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
55 weak_this_ = weak_this_factory_.GetWeakPtr();
56 }
57
~V4L2StatefulVideoDecoderBackend()58 V4L2StatefulVideoDecoderBackend::~V4L2StatefulVideoDecoderBackend() {
59 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
60 DVLOGF(3);
61
62 if (flush_cb_ || current_decode_request_ || !decode_request_queue_.empty()) {
63 VLOGF(1) << "Should not destroy backend during pending decode!";
64 }
65
66 struct v4l2_event_subscription sub;
67 memset(&sub, 0, sizeof(sub));
68 sub.type = V4L2_EVENT_SOURCE_CHANGE;
69 if (device_->Ioctl(VIDIOC_UNSUBSCRIBE_EVENT, &sub) != 0) {
70 VLOGF(1) << "Cannot unsubscribe to event";
71 }
72 }
73
Initialize()74 bool V4L2StatefulVideoDecoderBackend::Initialize() {
75 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
76 DVLOGF(3);
77
78 if (!IsSupportedProfile(profile_)) {
79 VLOGF(1) << "Unsupported profile " << GetProfileName(profile_);
80 return false;
81 }
82
83 frame_splitter_ =
84 v4l2_vda_helpers::InputBufferFragmentSplitter::CreateFromProfile(
85 profile_);
86 if (!frame_splitter_) {
87 VLOGF(1) << "Failed to create frame splitter";
88 return false;
89 }
90
91 struct v4l2_event_subscription sub;
92 memset(&sub, 0, sizeof(sub));
93 sub.type = V4L2_EVENT_SOURCE_CHANGE;
94 if (device_->Ioctl(VIDIOC_SUBSCRIBE_EVENT, &sub) != 0) {
95 VLOGF(1) << "Cannot subscribe to event";
96 return false;
97 }
98
99 return true;
100 }
101
EnqueueDecodeTask(scoped_refptr<DecoderBuffer> buffer,VideoDecoder::DecodeCB decode_cb,int32_t bitstream_id)102 void V4L2StatefulVideoDecoderBackend::EnqueueDecodeTask(
103 scoped_refptr<DecoderBuffer> buffer,
104 VideoDecoder::DecodeCB decode_cb,
105 int32_t bitstream_id) {
106 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107 DVLOGF(3);
108
109 if (!buffer->end_of_stream()) {
110 has_pending_requests_ = true;
111 }
112
113 decode_request_queue_.push(
114 DecodeRequest(std::move(buffer), std::move(decode_cb), bitstream_id));
115
116 DoDecodeWork();
117 }
118
DoDecodeWork()119 void V4L2StatefulVideoDecoderBackend::DoDecodeWork() {
120 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
121 DVLOGF(3);
122
123 // Do not decode if a flush is in progress.
124 // This may actually be ok to do if we are changing resolution?
125 if (flush_cb_)
126 return;
127
128 // Get a new decode request if none is in progress.
129 if (!current_decode_request_) {
130 // No more decode request, nothing to do for now.
131 if (decode_request_queue_.empty())
132 return;
133
134 auto decode_request = std::move(decode_request_queue_.front());
135 decode_request_queue_.pop();
136
137 // Need to flush?
138 if (decode_request.buffer->end_of_stream()) {
139 InitiateFlush(std::move(decode_request.decode_cb));
140 return;
141 }
142
143 // This is our new decode request.
144 current_decode_request_ = std::move(decode_request);
145 DCHECK_EQ(current_decode_request_->bytes_used, 0u);
146 }
147
148 // Get a V4L2 buffer to copy the encoded data into.
149 if (!current_input_buffer_) {
150 current_input_buffer_ = input_queue_->GetFreeBuffer();
151 // We will be called again once an input buffer becomes available.
152 if (!current_input_buffer_)
153 return;
154
155 // Record timestamp of the input buffer so it propagates to the decoded
156 // frames.
157 const struct timespec timespec =
158 current_decode_request_->buffer->timestamp().ToTimeSpec();
159 struct timeval timestamp = {
160 .tv_sec = timespec.tv_sec,
161 .tv_usec = timespec.tv_nsec / 1000,
162 };
163 current_input_buffer_->SetTimeStamp(timestamp);
164 }
165
166 // From here on we have both a decode request and input buffer, so we can
167 // progress with decoding.
168 DCHECK(current_decode_request_.has_value());
169 DCHECK(current_input_buffer_.has_value());
170
171 const DecoderBuffer* current_buffer = current_decode_request_->buffer.get();
172 DCHECK_LT(current_decode_request_->bytes_used, current_buffer->data_size());
173 const uint8_t* const data =
174 current_buffer->data() + current_decode_request_->bytes_used;
175 const size_t data_size =
176 current_buffer->data_size() - current_decode_request_->bytes_used;
177 size_t bytes_to_copy = 0;
178
179 if (!frame_splitter_->AdvanceFrameFragment(data, data_size, &bytes_to_copy)) {
180 VLOGF(1) << "Invalid H.264 stream detected.";
181 std::move(current_decode_request_->decode_cb)
182 .Run(DecodeStatus::DECODE_ERROR);
183 current_decode_request_.reset();
184 current_input_buffer_.reset();
185 client_->OnBackendError();
186 return;
187 }
188
189 const size_t bytes_used = current_input_buffer_->GetPlaneBytesUsed(0);
190 if (bytes_used + bytes_to_copy > current_input_buffer_->GetPlaneSize(0)) {
191 VLOGF(1) << "V4L2 buffer size is too small to contain a whole frame.";
192 std::move(current_decode_request_->decode_cb)
193 .Run(DecodeStatus::DECODE_ERROR);
194 current_decode_request_.reset();
195 current_input_buffer_.reset();
196 client_->OnBackendError();
197 return;
198 }
199
200 uint8_t* dst =
201 static_cast<uint8_t*>(current_input_buffer_->GetPlaneMapping(0)) +
202 bytes_used;
203 memcpy(dst, data, bytes_to_copy);
204 current_input_buffer_->SetPlaneBytesUsed(0, bytes_used + bytes_to_copy);
205 current_decode_request_->bytes_used += bytes_to_copy;
206
207 // Release current_input_request_ if we reached its end.
208 if (current_decode_request_->IsCompleted()) {
209 std::move(current_decode_request_->decode_cb).Run(DecodeStatus::OK);
210 current_decode_request_.reset();
211 }
212
213 // If we have a partial frame, wait before submitting it.
214 if (frame_splitter_->IsPartialFramePending()) {
215 VLOGF(4) << "Partial frame pending, not queueing any buffer now.";
216 return;
217 }
218
219 // The V4L2 input buffer contains a decodable entity, queue it.
220 if (!std::move(*current_input_buffer_).QueueMMap()) {
221 LOG(ERROR) << "Error while queuing input buffer!";
222 client_->OnBackendError();
223 }
224 current_input_buffer_.reset();
225
226 // If we can still progress on a decode request, do it.
227 if (current_decode_request_ || !decode_request_queue_.empty())
228 ScheduleDecodeWork();
229 }
230
ScheduleDecodeWork()231 void V4L2StatefulVideoDecoderBackend::ScheduleDecodeWork() {
232 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
233 DVLOGF(3);
234
235 task_runner_->PostTask(
236 FROM_HERE, base::BindOnce(&V4L2StatefulVideoDecoderBackend::DoDecodeWork,
237 weak_this_));
238 }
239
ProcessEventQueue()240 void V4L2StatefulVideoDecoderBackend::ProcessEventQueue() {
241 while (base::Optional<struct v4l2_event> ev = device_->DequeueEvent()) {
242 if (ev->type == V4L2_EVENT_SOURCE_CHANGE &&
243 (ev->u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)) {
244 ChangeResolution();
245 }
246 }
247 }
248
OnServiceDeviceTask(bool event)249 void V4L2StatefulVideoDecoderBackend::OnServiceDeviceTask(bool event) {
250 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
251 DVLOGF(3);
252
253 if (event)
254 ProcessEventQueue();
255
256 // We can enqueue dequeued output buffers immediately.
257 EnqueueOutputBuffers();
258
259 // Try to progress on our work since we may have dequeued input buffers.
260 DoDecodeWork();
261 }
262
EnqueueOutputBuffers()263 void V4L2StatefulVideoDecoderBackend::EnqueueOutputBuffers() {
264 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
265 DVLOGF(3);
266 const v4l2_memory mem_type = output_queue_->GetMemoryType();
267
268 while (true) {
269 bool ret = false;
270 bool no_buffer = false;
271
272 base::Optional<V4L2WritableBufferRef> buffer;
273 switch (mem_type) {
274 case V4L2_MEMORY_MMAP:
275 buffer = output_queue_->GetFreeBuffer();
276 if (!buffer) {
277 no_buffer = true;
278 break;
279 }
280
281 ret = std::move(*buffer).QueueMMap();
282 break;
283 case V4L2_MEMORY_DMABUF: {
284 scoped_refptr<VideoFrame> video_frame = GetPoolVideoFrame();
285 // Running out of frame is not an error, we will be called again
286 // once frames are available.
287 if (!video_frame)
288 return;
289 buffer = output_queue_->GetFreeBufferForFrame(*video_frame);
290 if (!buffer) {
291 no_buffer = true;
292 break;
293 }
294
295 ret = std::move(*buffer).QueueDMABuf(std::move(video_frame));
296 break;
297 }
298 default:
299 NOTREACHED();
300 }
301
302 // Running out of V4L2 buffers is not an error, so just exit the loop
303 // gracefully.
304 if (no_buffer)
305 break;
306
307 if (!ret) {
308 LOG(ERROR) << "Error while queueing output buffer!";
309 client_->OnBackendError();
310 }
311 }
312
313 DVLOGF(3) << output_queue_->QueuedBuffersCount() << "/"
314 << output_queue_->AllocatedBuffersCount()
315 << " output buffers queued";
316 }
317
GetPoolVideoFrame()318 scoped_refptr<VideoFrame> V4L2StatefulVideoDecoderBackend::GetPoolVideoFrame() {
319 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
320 DVLOGF(3);
321 DmabufVideoFramePool* pool = client_->GetVideoFramePool();
322 DCHECK_EQ(output_queue_->GetMemoryType(), V4L2_MEMORY_DMABUF);
323 DCHECK_NE(pool, nullptr);
324
325 scoped_refptr<VideoFrame> frame = pool->GetFrame();
326 if (!frame) {
327 DVLOGF(3) << "No available videoframe for now";
328 // We will try again once a frame becomes available.
329 pool->NotifyWhenFrameAvailable(base::BindOnce(
330 base::IgnoreResult(&base::SequencedTaskRunner::PostTask), task_runner_,
331 FROM_HERE,
332 base::BindOnce(
333 base::IgnoreResult(
334 &V4L2StatefulVideoDecoderBackend::EnqueueOutputBuffers),
335 weak_this_)));
336 }
337
338 return frame;
339 }
340
341 // static
ReuseOutputBufferThunk(scoped_refptr<base::SequencedTaskRunner> task_runner,base::Optional<base::WeakPtr<V4L2StatefulVideoDecoderBackend>> weak_this,V4L2ReadableBufferRef buffer)342 void V4L2StatefulVideoDecoderBackend::ReuseOutputBufferThunk(
343 scoped_refptr<base::SequencedTaskRunner> task_runner,
344 base::Optional<base::WeakPtr<V4L2StatefulVideoDecoderBackend>> weak_this,
345 V4L2ReadableBufferRef buffer) {
346 DVLOGF(3);
347 DCHECK(weak_this);
348
349 if (task_runner->RunsTasksInCurrentSequence()) {
350 if (*weak_this)
351 (*weak_this)->ReuseOutputBuffer(std::move(buffer));
352 } else {
353 task_runner->PostTask(
354 FROM_HERE,
355 base::BindOnce(&V4L2StatefulVideoDecoderBackend::ReuseOutputBuffer,
356 *weak_this, std::move(buffer)));
357 }
358 }
359
ReuseOutputBuffer(V4L2ReadableBufferRef buffer)360 void V4L2StatefulVideoDecoderBackend::ReuseOutputBuffer(
361 V4L2ReadableBufferRef buffer) {
362 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
363 DVLOGF(3) << "Reuse output buffer #" << buffer->BufferId();
364
365 // Lose reference to the buffer so it goes back to the free list.
366 buffer.reset();
367
368 // Enqueue the newly available buffer.
369 EnqueueOutputBuffers();
370 }
371
OnOutputBufferDequeued(V4L2ReadableBufferRef buffer)372 void V4L2StatefulVideoDecoderBackend::OnOutputBufferDequeued(
373 V4L2ReadableBufferRef buffer) {
374 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
375 DVLOGF(3);
376
377 // Zero-bytes buffers are returned as part of a flush and can be dismissed.
378 if (buffer->GetPlaneBytesUsed(0) > 0) {
379 const struct timeval timeval = buffer->GetTimeStamp();
380 const struct timespec timespec = {
381 .tv_sec = timeval.tv_sec,
382 .tv_nsec = timeval.tv_usec * 1000,
383 };
384 const base::TimeDelta timestamp = base::TimeDelta::FromTimeSpec(timespec);
385
386 scoped_refptr<VideoFrame> frame;
387
388 switch (output_queue_->GetMemoryType()) {
389 case V4L2_MEMORY_MMAP: {
390 // Wrap the videoframe into another one so we can be signaled when the
391 // consumer is done with it and reuse the V4L2 buffer.
392 scoped_refptr<VideoFrame> origin_frame = buffer->GetVideoFrame();
393 frame = VideoFrame::WrapVideoFrame(origin_frame, origin_frame->format(),
394 origin_frame->visible_rect(),
395 origin_frame->natural_size());
396 frame->AddDestructionObserver(base::BindOnce(
397 &V4L2StatefulVideoDecoderBackend::ReuseOutputBufferThunk,
398 task_runner_, weak_this_, buffer));
399 break;
400 }
401 case V4L2_MEMORY_DMABUF:
402 // The pool VideoFrame we passed to QueueDMABuf() has been decoded into,
403 // pass it as-is.
404 frame = buffer->GetVideoFrame();
405 break;
406 default:
407 NOTREACHED();
408 }
409
410 client_->OutputFrame(std::move(frame), *visible_rect_, timestamp);
411 }
412
413 // We were waiting for the last buffer before a resolution change
414 // The order here is important! A flush event may come after a resolution
415 // change event (but not the opposite), so we must make sure both events
416 // are processed in the correct order.
417 if (buffer->IsLast()){
418 // Check that we don't have a resolution change event pending. If we do
419 // then this LAST buffer was related to it.
420 ProcessEventQueue();
421
422 if (resolution_change_cb_) {
423 std::move(resolution_change_cb_).Run();
424 } else if (flush_cb_) {
425 // We were waiting for a flush to complete, and received the last buffer.
426 CompleteFlush();
427 }
428 }
429
430 EnqueueOutputBuffers();
431 }
432
SendStopCommand()433 bool V4L2StatefulVideoDecoderBackend::SendStopCommand() {
434 struct v4l2_decoder_cmd cmd;
435 memset(&cmd, 0, sizeof(cmd));
436 cmd.cmd = V4L2_DEC_CMD_STOP;
437 if (device_->Ioctl(VIDIOC_DECODER_CMD, &cmd) != 0) {
438 LOG(ERROR) << "Failed to issue STOP command";
439 client_->OnBackendError();
440 return false;
441 }
442
443 return true;
444 }
445
InitiateFlush(VideoDecoder::DecodeCB flush_cb)446 bool V4L2StatefulVideoDecoderBackend::InitiateFlush(
447 VideoDecoder::DecodeCB flush_cb) {
448 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
449 DVLOGF(3);
450 DCHECK(!flush_cb_);
451
452 // Submit any pending input buffer at the time of flush.
453 if (current_input_buffer_) {
454 if (!std::move(*current_input_buffer_).QueueMMap()) {
455 LOG(ERROR) << "Error while queuing input buffer!";
456 client_->OnBackendError();
457 }
458 current_input_buffer_.reset();
459 }
460
461 client_->InitiateFlush();
462 flush_cb_ = std::move(flush_cb);
463
464 // Special case: if we haven't received any decoding request, we could
465 // complete the flush immediately.
466 if (!has_pending_requests_)
467 return CompleteFlush();
468
469 if (output_queue_->IsStreaming()) {
470 // If the CAPTURE queue is streaming, send the STOP command to the V4L2
471 // device. The device will let us know that the flush is completed by
472 // sending us a CAPTURE buffer with the LAST flag set.
473 return SendStopCommand();
474 } else {
475 // If the CAPTURE queue is not streaming, this means we received the flush
476 // request before the initial resolution has been established. The flush
477 // request will be processed in OnChangeResolutionDone(), when the CAPTURE
478 // queue starts streaming.
479 DVLOGF(2) << "Flush request to be processed after CAPTURE queue starts";
480 }
481
482 return true;
483 }
484
CompleteFlush()485 bool V4L2StatefulVideoDecoderBackend::CompleteFlush() {
486 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
487 DVLOGF(3);
488 DCHECK(flush_cb_);
489
490 // Signal that flush has properly been completed.
491 std::move(flush_cb_).Run(DecodeStatus::OK);
492
493 // If CAPTURE queue is streaming, send the START command to the V4L2 device
494 // to signal that we are resuming decoding with the same state.
495 if (output_queue_->IsStreaming()) {
496 struct v4l2_decoder_cmd cmd;
497 memset(&cmd, 0, sizeof(cmd));
498 cmd.cmd = V4L2_DEC_CMD_START;
499 if (device_->Ioctl(VIDIOC_DECODER_CMD, &cmd) != 0) {
500 LOG(ERROR) << "Failed to issue START command";
501 std::move(flush_cb_).Run(DecodeStatus::DECODE_ERROR);
502 client_->OnBackendError();
503 return false;
504 }
505 }
506
507 client_->CompleteFlush();
508
509 // Resume decoding if data is available.
510 ScheduleDecodeWork();
511
512 has_pending_requests_ = false;
513 return true;
514 }
515
OnStreamStopped(bool stop_input_queue)516 void V4L2StatefulVideoDecoderBackend::OnStreamStopped(bool stop_input_queue) {
517 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
518 DVLOGF(3);
519
520 // If we are resetting, also reset the splitter.
521 if (stop_input_queue)
522 frame_splitter_->Reset();
523 }
524
ChangeResolution()525 void V4L2StatefulVideoDecoderBackend::ChangeResolution() {
526 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
527 DVLOGF(3);
528
529 // Here we just query the new resolution, visible rect, and number of output
530 // buffers before asking the client to update the resolution.
531
532 auto format = output_queue_->GetFormat().first;
533 if (!format) {
534 client_->OnBackendError();
535 return;
536 }
537 const gfx::Size pic_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
538
539 auto visible_rect = output_queue_->GetVisibleRect();
540 if (!visible_rect) {
541 client_->OnBackendError();
542 return;
543 }
544
545 if (!gfx::Rect(pic_size).Contains(*visible_rect)) {
546 client_->OnBackendError();
547 return;
548 }
549
550 auto ctrl = device_->GetCtrl(V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
551 constexpr size_t DEFAULT_NUM_OUTPUT_BUFFERS = 7;
552 const size_t num_output_buffers =
553 ctrl ? ctrl->value : DEFAULT_NUM_OUTPUT_BUFFERS;
554 if (!ctrl)
555 VLOGF(1) << "Using default minimum number of CAPTURE buffers";
556
557 // Signal that we are flushing and initiate the resolution change.
558 // Our flush will be done when we receive a buffer with the LAST flag on the
559 // CAPTURE queue.
560 client_->InitiateFlush();
561 DCHECK(!resolution_change_cb_);
562 resolution_change_cb_ =
563 base::BindOnce(&V4L2StatefulVideoDecoderBackend::ContinueChangeResolution,
564 weak_this_, pic_size, *visible_rect, num_output_buffers);
565
566 // ...that is, unless we are not streaming yet, in which case the resolution
567 // change can take place immediately.
568 if (!output_queue_->IsStreaming())
569 std::move(resolution_change_cb_).Run();
570 }
571
ContinueChangeResolution(const gfx::Size & pic_size,const gfx::Rect & visible_rect,const size_t num_output_buffers)572 void V4L2StatefulVideoDecoderBackend::ContinueChangeResolution(
573 const gfx::Size& pic_size,
574 const gfx::Rect& visible_rect,
575 const size_t num_output_buffers) {
576 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
577 DVLOGF(3);
578
579 // Flush is done, but stay in flushing state and ask our client to set the new
580 // resolution.
581 client_->ChangeResolution(pic_size, visible_rect, num_output_buffers);
582 }
583
ApplyResolution(const gfx::Size & pic_size,const gfx::Rect & visible_rect,const size_t num_output_frames)584 bool V4L2StatefulVideoDecoderBackend::ApplyResolution(
585 const gfx::Size& pic_size,
586 const gfx::Rect& visible_rect,
587 const size_t num_output_frames) {
588 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
589 DVLOGF(3);
590
591 // Use the visible rect for all new frames.
592 visible_rect_ = visible_rect;
593
594 return true;
595 }
596
OnChangeResolutionDone(bool success)597 void V4L2StatefulVideoDecoderBackend::OnChangeResolutionDone(bool success) {
598 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
599 DVLOGF(3);
600
601 if (!success) {
602 client_->OnBackendError();
603 return;
604 }
605
606 // Flush can be considered completed on the client side.
607 client_->CompleteFlush();
608
609 // Enqueue all available output buffers now that they are allocated.
610 EnqueueOutputBuffers();
611
612 // If we had a flush request pending before the initial resolution change,
613 // process it now.
614 if (flush_cb_) {
615 DVLOGF(2) << "Processing pending flush request...";
616
617 client_->InitiateFlush();
618 if (!SendStopCommand())
619 return;
620 }
621
622 // Also try to progress on our work.
623 DoDecodeWork();
624 }
625
ClearPendingRequests(DecodeStatus status)626 void V4L2StatefulVideoDecoderBackend::ClearPendingRequests(
627 DecodeStatus status) {
628 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
629 DVLOGF(3);
630
631 resolution_change_cb_.Reset();
632
633 if (flush_cb_) {
634 std::move(flush_cb_).Run(status);
635 }
636
637 current_input_buffer_.reset();
638
639 if (current_decode_request_) {
640 std::move(current_decode_request_->decode_cb).Run(status);
641 current_decode_request_.reset();
642 }
643
644 while (!decode_request_queue_.empty()) {
645 std::move(decode_request_queue_.front().decode_cb).Run(status);
646 decode_request_queue_.pop();
647 }
648
649 has_pending_requests_ = false;
650 }
651
652 // TODO(b:149663704) move into helper function shared between both backends?
IsSupportedProfile(VideoCodecProfile profile)653 bool V4L2StatefulVideoDecoderBackend::IsSupportedProfile(
654 VideoCodecProfile profile) {
655 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
656 DCHECK(device_);
657 if (supported_profiles_.empty()) {
658 constexpr uint32_t kSupportedInputFourccs[] = {
659 V4L2_PIX_FMT_H264,
660 V4L2_PIX_FMT_VP8,
661 V4L2_PIX_FMT_VP9,
662 };
663 scoped_refptr<V4L2Device> device = V4L2Device::Create();
664 VideoDecodeAccelerator::SupportedProfiles profiles =
665 device->GetSupportedDecodeProfiles(base::size(kSupportedInputFourccs),
666 kSupportedInputFourccs);
667 for (const auto& profile : profiles)
668 supported_profiles_.push_back(profile.profile);
669 }
670 return std::find(supported_profiles_.begin(), supported_profiles_.end(),
671 profile) != supported_profiles_.end();
672 }
673
StopInputQueueOnResChange() const674 bool V4L2StatefulVideoDecoderBackend::StopInputQueueOnResChange() const {
675 return false;
676 }
677
678 } // namespace media
679