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