1 // Copyright 2019 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_stateless.h"
6
7 #include <fcntl.h>
8 #include <linux/media.h>
9 #include <sys/ioctl.h>
10
11 #include <memory>
12
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/sequenced_task_runner.h"
17 #include "media/base/decode_status.h"
18 #include "media/base/video_codecs.h"
19 #include "media/base/video_frame.h"
20 #include "media/gpu/accelerated_video_decoder.h"
21 #include "media/gpu/chromeos/dmabuf_video_frame_pool.h"
22 #include "media/gpu/macros.h"
23 #include "media/gpu/v4l2/v4l2_device.h"
24 #include "media/gpu/v4l2/v4l2_h264_accelerator.h"
25 #include "media/gpu/v4l2/v4l2_h264_accelerator_legacy.h"
26 #include "media/gpu/v4l2/v4l2_vp8_accelerator.h"
27 #include "media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h"
28 #include "media/gpu/v4l2/v4l2_vp9_accelerator_legacy.h"
29
30 namespace media {
31
32 namespace {
33
34 // Size of the timestamp cache, needs to be large enough for frame-reordering.
35 constexpr size_t kTimestampCacheSize = 128;
36 // Number of requests to allocate for submitting input buffers, if requests
37 // are used.
38
39 } // namespace
40
41 struct V4L2StatelessVideoDecoderBackend::OutputRequest {
Surfacemedia::V4L2StatelessVideoDecoderBackend::OutputRequest42 static OutputRequest Surface(scoped_refptr<V4L2DecodeSurface> s,
43 base::TimeDelta t) {
44 return OutputRequest(std::move(s), t);
45 }
46
FlushFencemedia::V4L2StatelessVideoDecoderBackend::OutputRequest47 static OutputRequest FlushFence() { return OutputRequest(kFlushFence); }
48
ChangeResolutionFencemedia::V4L2StatelessVideoDecoderBackend::OutputRequest49 static OutputRequest ChangeResolutionFence() {
50 return OutputRequest(kChangeResolutionFence);
51 }
52
IsReadymedia::V4L2StatelessVideoDecoderBackend::OutputRequest53 bool IsReady() const {
54 return (type != OutputRequestType::kSurface) || surface->decoded();
55 }
56
57 // Allow move, but not copy.
58 OutputRequest(OutputRequest&&) = default;
59
60 enum OutputRequestType {
61 // The surface to be outputted.
62 kSurface,
63 // The fence to indicate the flush request.
64 kFlushFence,
65 // The fence to indicate resolution change request.
66 kChangeResolutionFence,
67 };
68
69 // The type of the request.
70 const OutputRequestType type;
71 // The surface to be outputted.
72 scoped_refptr<V4L2DecodeSurface> surface;
73 // The timestamp of the output frame. Because a surface might be outputted
74 // multiple times with different timestamp, we need to store timestamp out of
75 // surface.
76 base::TimeDelta timestamp;
77
78 private:
OutputRequestmedia::V4L2StatelessVideoDecoderBackend::OutputRequest79 OutputRequest(scoped_refptr<V4L2DecodeSurface> s, base::TimeDelta t)
80 : type(kSurface), surface(std::move(s)), timestamp(t) {}
OutputRequestmedia::V4L2StatelessVideoDecoderBackend::OutputRequest81 explicit OutputRequest(OutputRequestType t) : type(t) {}
82
83 DISALLOW_COPY_AND_ASSIGN(OutputRequest);
84 };
85
DecodeRequest(scoped_refptr<DecoderBuffer> buf,VideoDecoder::DecodeCB cb,int32_t id)86 V4L2StatelessVideoDecoderBackend::DecodeRequest::DecodeRequest(
87 scoped_refptr<DecoderBuffer> buf,
88 VideoDecoder::DecodeCB cb,
89 int32_t id)
90 : buffer(std::move(buf)), decode_cb(std::move(cb)), bitstream_id(id) {}
91
92 V4L2StatelessVideoDecoderBackend::DecodeRequest::DecodeRequest(
93 DecodeRequest&&) = default;
94 V4L2StatelessVideoDecoderBackend::DecodeRequest&
95 V4L2StatelessVideoDecoderBackend::DecodeRequest::operator=(DecodeRequest&&) =
96 default;
97
98 V4L2StatelessVideoDecoderBackend::DecodeRequest::~DecodeRequest() = default;
99
V4L2StatelessVideoDecoderBackend(Client * const client,scoped_refptr<V4L2Device> device,VideoCodecProfile profile,scoped_refptr<base::SequencedTaskRunner> task_runner)100 V4L2StatelessVideoDecoderBackend::V4L2StatelessVideoDecoderBackend(
101 Client* const client,
102 scoped_refptr<V4L2Device> device,
103 VideoCodecProfile profile,
104 scoped_refptr<base::SequencedTaskRunner> task_runner)
105 : V4L2VideoDecoderBackend(client, std::move(device)),
106 profile_(profile),
107 bitstream_id_to_timestamp_(kTimestampCacheSize),
108 task_runner_(task_runner) {
109 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
110
111 weak_this_ = weak_this_factory_.GetWeakPtr();
112 }
113
~V4L2StatelessVideoDecoderBackend()114 V4L2StatelessVideoDecoderBackend::~V4L2StatelessVideoDecoderBackend() {
115 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
116 DCHECK(surfaces_at_device_.empty());
117
118 if (!output_request_queue_.empty() || flush_cb_ || current_decode_request_ ||
119 !decode_request_queue_.empty()) {
120 VLOGF(1) << "Should not destroy backend during pending decode!";
121 }
122 }
123
Initialize()124 bool V4L2StatelessVideoDecoderBackend::Initialize() {
125 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
126
127 if (!IsSupportedProfile(profile_)) {
128 VLOGF(1) << "Unsupported profile " << GetProfileName(profile_);
129 return false;
130 }
131
132 if (!CreateAvd())
133 return false;
134
135 if (input_queue_->SupportsRequests()) {
136 requests_queue_ = device_->GetRequestsQueue();
137 if (requests_queue_ == nullptr)
138 return false;
139 }
140
141 return true;
142 }
143
144 // static
ReuseOutputBufferThunk(scoped_refptr<base::SequencedTaskRunner> task_runner,base::Optional<base::WeakPtr<V4L2StatelessVideoDecoderBackend>> weak_this,V4L2ReadableBufferRef buffer)145 void V4L2StatelessVideoDecoderBackend::ReuseOutputBufferThunk(
146 scoped_refptr<base::SequencedTaskRunner> task_runner,
147 base::Optional<base::WeakPtr<V4L2StatelessVideoDecoderBackend>> weak_this,
148 V4L2ReadableBufferRef buffer) {
149 DVLOGF(3);
150 DCHECK(weak_this);
151
152 if (task_runner->RunsTasksInCurrentSequence()) {
153 if (*weak_this) {
154 (*weak_this)->ReuseOutputBuffer(std::move(buffer));
155 }
156 } else {
157 task_runner->PostTask(
158 FROM_HERE,
159 base::BindOnce(&V4L2StatelessVideoDecoderBackend::ReuseOutputBuffer,
160 *weak_this, std::move(buffer)));
161 }
162 }
163
ReuseOutputBuffer(V4L2ReadableBufferRef buffer)164 void V4L2StatelessVideoDecoderBackend::ReuseOutputBuffer(
165 V4L2ReadableBufferRef buffer) {
166 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
167 DVLOGF(3) << "Reuse output surface #" << buffer->BufferId();
168
169 // Resume decoding in case of ran out of surface.
170 if (pause_reason_ == PauseReason::kRanOutOfSurfaces) {
171 pause_reason_ = PauseReason::kNone;
172 task_runner_->PostTask(
173 FROM_HERE,
174 base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
175 weak_this_));
176 }
177 }
178
OnOutputBufferDequeued(V4L2ReadableBufferRef dequeued_buffer)179 void V4L2StatelessVideoDecoderBackend::OnOutputBufferDequeued(
180 V4L2ReadableBufferRef dequeued_buffer) {
181 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
182
183 // Mark the output buffer decoded, and try to output surface.
184 DCHECK(!surfaces_at_device_.empty());
185 auto surface = std::move(surfaces_at_device_.front());
186 DCHECK_EQ(static_cast<size_t>(surface->output_record()),
187 dequeued_buffer->BufferId());
188 surfaces_at_device_.pop();
189
190 surface->SetDecoded();
191
192 auto reuse_buffer_cb =
193 base::BindOnce(&V4L2StatelessVideoDecoderBackend::ReuseOutputBufferThunk,
194 task_runner_, weak_this_, std::move(dequeued_buffer));
195 if (output_queue_->GetMemoryType() == V4L2_MEMORY_MMAP) {
196 // Keep a reference to the V4L2 buffer until the frame is reused, because
197 // the frame is backed up by the V4L2 buffer's memory.
198 surface->video_frame()->AddDestructionObserver(std::move(reuse_buffer_cb));
199 } else {
200 // Keep a reference to the V4L2 buffer until the buffer is reused. The
201 // reason for this is that the config store uses V4L2 buffer IDs to
202 // reference frames, therefore we cannot reuse the same V4L2 buffer ID for
203 // another decode operation until all references to that frame are gone.
204 // Request API does not have this limitation, so we can probably remove this
205 // after config store is gone.
206 surface->SetReleaseCallback(std::move(reuse_buffer_cb));
207 }
208
209 PumpOutputSurfaces();
210
211 // If we were waiting for an output buffer to be available, schedule a
212 // decode task.
213 if (pause_reason_ == PauseReason::kWaitSubFrameDecoded) {
214 pause_reason_ = PauseReason::kNone;
215 task_runner_->PostTask(
216 FROM_HERE,
217 base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
218 weak_this_));
219 }
220 }
221
222 scoped_refptr<V4L2DecodeSurface>
CreateSurface()223 V4L2StatelessVideoDecoderBackend::CreateSurface() {
224 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
225 DVLOGF(4);
226
227 // Request V4L2 input and output buffers.
228 auto input_buf = input_queue_->GetFreeBuffer();
229 auto output_buf = output_queue_->GetFreeBuffer();
230 if (!input_buf || !output_buf) {
231 DVLOGF(3) << "There is no free V4L2 buffer.";
232 return nullptr;
233 }
234
235 DmabufVideoFramePool* pool = client_->GetVideoFramePool();
236 scoped_refptr<VideoFrame> frame;
237 if (!pool) {
238 // Get VideoFrame from the V4L2 buffer because now we allocate from V4L2
239 // driver via MMAP. The VideoFrame received from V4L2 buffer will remain
240 // until deallocating V4L2Queue. But we need to know when the buffer is not
241 // used by the client. So we wrap the frame here.
242 scoped_refptr<VideoFrame> origin_frame = output_buf->GetVideoFrame();
243 frame = VideoFrame::WrapVideoFrame(origin_frame, origin_frame->format(),
244 origin_frame->visible_rect(),
245 origin_frame->natural_size());
246 } else {
247 // Try to get VideoFrame from the pool.
248 frame = pool->GetFrame();
249 if (!frame) {
250 // We allocate the same number of output buffer slot in V4L2 device and
251 // the output VideoFrame. If there is free output buffer slot but no free
252 // VideoFrame, it means the VideoFrame is not released at client
253 // side. Post DoDecodeWork when the pool has available frames.
254 DVLOGF(3) << "There is no available VideoFrame.";
255 pool->NotifyWhenFrameAvailable(base::BindOnce(
256 base::IgnoreResult(&base::SequencedTaskRunner::PostTask),
257 task_runner_, FROM_HERE,
258 base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
259 weak_this_)));
260 return nullptr;
261 }
262 }
263
264 scoped_refptr<V4L2DecodeSurface> dec_surface;
265 if (input_queue_->SupportsRequests()) {
266 base::Optional<V4L2RequestRef> request_ref =
267 requests_queue_->GetFreeRequest();
268 if (!request_ref) {
269 DVLOGF(1) << "Could not get free request.";
270 return nullptr;
271 }
272
273 dec_surface = new V4L2RequestDecodeSurface(
274 std::move(*input_buf), std::move(*output_buf), std::move(frame),
275 std::move(*request_ref));
276 } else {
277 dec_surface = new V4L2ConfigStoreDecodeSurface(
278 std::move(*input_buf), std::move(*output_buf), std::move(frame));
279 }
280
281 return dec_surface;
282 }
283
SubmitSlice(V4L2DecodeSurface * dec_surface,const uint8_t * data,size_t size)284 bool V4L2StatelessVideoDecoderBackend::SubmitSlice(
285 V4L2DecodeSurface* dec_surface,
286 const uint8_t* data,
287 size_t size) {
288 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
289 DVLOGF(3);
290
291 size_t plane_size = dec_surface->input_buffer().GetPlaneSize(0);
292 size_t bytes_used = dec_surface->input_buffer().GetPlaneBytesUsed(0);
293 if (size > plane_size - bytes_used) {
294 VLOGF(1) << "The size of submitted slice(" << size
295 << ") is larger than the remaining buffer size("
296 << plane_size - bytes_used << "). Plane size is " << plane_size;
297 client_->OnBackendError();
298 return false;
299 }
300
301 void* mapping = dec_surface->input_buffer().GetPlaneMapping(0);
302 memcpy(reinterpret_cast<uint8_t*>(mapping) + bytes_used, data, size);
303 dec_surface->input_buffer().SetPlaneBytesUsed(0, bytes_used + size);
304 return true;
305 }
306
DecodeSurface(scoped_refptr<V4L2DecodeSurface> dec_surface)307 void V4L2StatelessVideoDecoderBackend::DecodeSurface(
308 scoped_refptr<V4L2DecodeSurface> dec_surface) {
309 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
310 DVLOGF(3);
311
312 if (!dec_surface->Submit()) {
313 VLOGF(1) << "Error while submitting frame for decoding!";
314 client_->OnBackendError();
315 return;
316 }
317
318 surfaces_at_device_.push(std::move(dec_surface));
319 }
320
SurfaceReady(scoped_refptr<V4L2DecodeSurface> dec_surface,int32_t bitstream_id,const gfx::Rect & visible_rect,const VideoColorSpace &)321 void V4L2StatelessVideoDecoderBackend::SurfaceReady(
322 scoped_refptr<V4L2DecodeSurface> dec_surface,
323 int32_t bitstream_id,
324 const gfx::Rect& visible_rect,
325 const VideoColorSpace& /* color_space */) {
326 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
327 DVLOGF(3);
328
329 // Find the timestamp associated with |bitstream_id|. It's possible that a
330 // surface is output multiple times for different |bitstream_id|s (e.g. VP9
331 // show_existing_frame feature). This means we need to output the same frame
332 // again with a different timestamp.
333 // On some rare occasions it's also possible that a single DecoderBuffer
334 // produces multiple surfaces with the same |bitstream_id|, so we shouldn't
335 // remove the timestamp from the cache.
336 const auto it = bitstream_id_to_timestamp_.Peek(bitstream_id);
337 DCHECK(it != bitstream_id_to_timestamp_.end());
338 base::TimeDelta timestamp = it->second;
339
340 dec_surface->SetVisibleRect(visible_rect);
341 output_request_queue_.push(
342 OutputRequest::Surface(std::move(dec_surface), timestamp));
343 PumpOutputSurfaces();
344 }
345
EnqueueDecodeTask(scoped_refptr<DecoderBuffer> buffer,VideoDecoder::DecodeCB decode_cb,int32_t bitstream_id)346 void V4L2StatelessVideoDecoderBackend::EnqueueDecodeTask(
347 scoped_refptr<DecoderBuffer> buffer,
348 VideoDecoder::DecodeCB decode_cb,
349 int32_t bitstream_id) {
350 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
351
352 if (!buffer->end_of_stream()) {
353 bitstream_id_to_timestamp_.Put(bitstream_id, buffer->timestamp());
354 }
355
356 decode_request_queue_.push(
357 DecodeRequest(std::move(buffer), std::move(decode_cb), bitstream_id));
358
359 // If we are already decoding, then we don't need to pump again.
360 if (!current_decode_request_)
361 DoDecodeWork();
362 }
363
DoDecodeWork()364 void V4L2StatelessVideoDecoderBackend::DoDecodeWork() {
365 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
366
367 if (!client_->IsDecoding())
368 return;
369
370 if (!PumpDecodeTask())
371 client_->OnBackendError();
372 }
373
PumpDecodeTask()374 bool V4L2StatelessVideoDecoderBackend::PumpDecodeTask() {
375 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
376 DVLOGF(3) << " Number of Decode requests: " << decode_request_queue_.size();
377
378 pause_reason_ = PauseReason::kNone;
379 while (true) {
380 switch (avd_->Decode()) {
381 case AcceleratedVideoDecoder::kConfigChange:
382 if (profile_ != avd_->GetProfile()) {
383 DVLOGF(3) << "Profile is changed: " << profile_ << " -> "
384 << avd_->GetProfile();
385 if (!IsSupportedProfile(avd_->GetProfile())) {
386 VLOGF(2) << "Unsupported profile: " << avd_->GetProfile();
387 return false;
388 }
389
390 profile_ = avd_->GetProfile();
391 }
392
393 if (pic_size_ == avd_->GetPicSize()) {
394 // There is no need to do anything in V4L2 API when only a profile is
395 // changed.
396 DVLOGF(3) << "Only profile is changed. No need to do anything.";
397 continue;
398 }
399
400 DVLOGF(3) << "Need to change resolution. Pause decoding.";
401 client_->InitiateFlush();
402
403 output_request_queue_.push(OutputRequest::ChangeResolutionFence());
404 PumpOutputSurfaces();
405 return true;
406
407 case AcceleratedVideoDecoder::kRanOutOfStreamData:
408 // Current decode request is finished processing.
409 if (current_decode_request_) {
410 DCHECK(current_decode_request_->decode_cb);
411 std::move(current_decode_request_->decode_cb).Run(DecodeStatus::OK);
412 current_decode_request_ = base::nullopt;
413 }
414
415 // Process next decode request.
416 if (decode_request_queue_.empty())
417 return true;
418 current_decode_request_ = std::move(decode_request_queue_.front());
419 decode_request_queue_.pop();
420
421 if (current_decode_request_->buffer->end_of_stream()) {
422 if (!avd_->Flush()) {
423 VLOGF(1) << "Failed flushing the decoder.";
424 return false;
425 }
426 // Put the decoder in an idle state, ready to resume.
427 avd_->Reset();
428
429 client_->InitiateFlush();
430 DCHECK(!flush_cb_);
431 flush_cb_ = std::move(current_decode_request_->decode_cb);
432
433 output_request_queue_.push(OutputRequest::FlushFence());
434 PumpOutputSurfaces();
435 current_decode_request_ = base::nullopt;
436 return true;
437 }
438
439 avd_->SetStream(current_decode_request_->bitstream_id,
440 *current_decode_request_->buffer);
441 break;
442
443 case AcceleratedVideoDecoder::kRanOutOfSurfaces:
444 DVLOGF(3) << "Ran out of surfaces. Resume when buffer is returned.";
445 pause_reason_ = PauseReason::kRanOutOfSurfaces;
446 return true;
447
448 case AcceleratedVideoDecoder::kNeedContextUpdate:
449 DVLOGF(3) << "Awaiting context update";
450 pause_reason_ = PauseReason::kWaitSubFrameDecoded;
451 return true;
452
453 case AcceleratedVideoDecoder::kDecodeError:
454 DVLOGF(3) << "Error decoding stream";
455 return false;
456
457 case AcceleratedVideoDecoder::kTryAgain:
458 NOTREACHED() << "Should not reach here unless this class accepts "
459 "encrypted streams.";
460 DVLOGF(4) << "No key for decoding stream.";
461 return false;
462 }
463 }
464 }
465
PumpOutputSurfaces()466 void V4L2StatelessVideoDecoderBackend::PumpOutputSurfaces() {
467 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
468 DVLOGF(3) << "Number of display surfaces: " << output_request_queue_.size();
469
470 bool resume_decode = false;
471 while (!output_request_queue_.empty()) {
472 if (!output_request_queue_.front().IsReady()) {
473 DVLOGF(3) << "The first surface is not ready yet.";
474 break;
475 }
476
477 OutputRequest request = std::move(output_request_queue_.front());
478 output_request_queue_.pop();
479 switch (request.type) {
480 case OutputRequest::kFlushFence:
481 DCHECK(output_request_queue_.empty());
482 DVLOGF(2) << "Flush finished.";
483 std::move(flush_cb_).Run(DecodeStatus::OK);
484 resume_decode = true;
485 break;
486
487 case OutputRequest::kChangeResolutionFence:
488 DCHECK(output_request_queue_.empty());
489 ChangeResolution();
490 break;
491
492 case OutputRequest::kSurface:
493 scoped_refptr<V4L2DecodeSurface> surface = std::move(request.surface);
494
495 DCHECK(surface->video_frame());
496 client_->OutputFrame(surface->video_frame(), surface->visible_rect(),
497 request.timestamp);
498 break;
499 }
500 }
501
502 if (resume_decode) {
503 client_->CompleteFlush();
504 task_runner_->PostTask(
505 FROM_HERE,
506 base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
507 weak_this_));
508 }
509 }
510
ChangeResolution()511 void V4L2StatelessVideoDecoderBackend::ChangeResolution() {
512 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
513 // We change resolution after outputting all pending surfaces, there should
514 // be no V4L2DecodeSurface left.
515 DCHECK(surfaces_at_device_.empty());
516 DCHECK(output_request_queue_.empty());
517
518 size_t num_output_frames = avd_->GetRequiredNumOfPictures();
519 gfx::Rect visible_rect = avd_->GetVisibleRect();
520 gfx::Size pic_size = avd_->GetPicSize();
521 // Set output format with the new resolution.
522 DCHECK(!pic_size.IsEmpty());
523 DVLOGF(3) << "Change resolution to " << pic_size.ToString();
524 client_->ChangeResolution(pic_size, visible_rect, num_output_frames);
525 }
526
ApplyResolution(const gfx::Size & pic_size,const gfx::Rect & visible_rect,const size_t num_output_frames)527 bool V4L2StatelessVideoDecoderBackend::ApplyResolution(
528 const gfx::Size& pic_size,
529 const gfx::Rect& visible_rect,
530 const size_t num_output_frames) {
531 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
532 DCHECK_EQ(input_queue_->QueuedBuffersCount(), 0u);
533
534 auto ret = input_queue_->GetFormat().first;
535 if (!ret) {
536 VPLOGF(1) << "Failed getting OUTPUT format";
537 return false;
538 }
539 struct v4l2_format format = std::move(*ret);
540
541 format.fmt.pix_mp.width = pic_size.width();
542 format.fmt.pix_mp.height = pic_size.height();
543 if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) {
544 VPLOGF(1) << "Failed setting OUTPUT format";
545 return false;
546 }
547
548 return true;
549 }
550
OnChangeResolutionDone(bool success)551 void V4L2StatelessVideoDecoderBackend::OnChangeResolutionDone(bool success) {
552 if (!success) {
553 client_->OnBackendError();
554 return;
555 }
556
557 pic_size_ = avd_->GetPicSize();
558 client_->CompleteFlush();
559 task_runner_->PostTask(
560 FROM_HERE, base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
561 weak_this_));
562 }
563
OnStreamStopped(bool stop_input_queue)564 void V4L2StatelessVideoDecoderBackend::OnStreamStopped(bool stop_input_queue) {
565 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
566 DVLOGF(3);
567
568 // The V4L2 stream has been stopped stopped, so all surfaces on the device
569 // have been returned to the client.
570 surfaces_at_device_ = {};
571 }
572
ClearPendingRequests(DecodeStatus status)573 void V4L2StatelessVideoDecoderBackend::ClearPendingRequests(
574 DecodeStatus status) {
575 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
576 DVLOGF(3);
577
578 if (avd_) {
579 // If we reset during resolution change, re-create AVD. Then the new AVD
580 // will trigger resolution change again after reset.
581 if (pic_size_ != avd_->GetPicSize()) {
582 CreateAvd();
583 } else {
584 avd_->Reset();
585 }
586 }
587
588 // Clear output_request_queue_.
589 while (!output_request_queue_.empty())
590 output_request_queue_.pop();
591
592 if (flush_cb_)
593 std::move(flush_cb_).Run(status);
594
595 // Clear current_decode_request_ and decode_request_queue_.
596 if (current_decode_request_) {
597 std::move(current_decode_request_->decode_cb).Run(status);
598 current_decode_request_ = base::nullopt;
599 }
600
601 while (!decode_request_queue_.empty()) {
602 auto request = std::move(decode_request_queue_.front());
603 decode_request_queue_.pop();
604 std::move(request.decode_cb).Run(status);
605 }
606 }
607
StopInputQueueOnResChange() const608 bool V4L2StatelessVideoDecoderBackend::StopInputQueueOnResChange() const {
609 return true;
610 }
611
IsSupportedProfile(VideoCodecProfile profile)612 bool V4L2StatelessVideoDecoderBackend::IsSupportedProfile(
613 VideoCodecProfile profile) {
614 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
615 DCHECK(device_);
616 if (supported_profiles_.empty()) {
617 constexpr uint32_t kSupportedInputFourccs[] = {
618 V4L2_PIX_FMT_H264_SLICE,
619 V4L2_PIX_FMT_VP8_FRAME,
620 V4L2_PIX_FMT_VP9_FRAME,
621 };
622 scoped_refptr<V4L2Device> device = V4L2Device::Create();
623 VideoDecodeAccelerator::SupportedProfiles profiles =
624 device->GetSupportedDecodeProfiles(base::size(kSupportedInputFourccs),
625 kSupportedInputFourccs);
626 for (const auto& profile : profiles)
627 supported_profiles_.push_back(profile.profile);
628 }
629 return std::find(supported_profiles_.begin(), supported_profiles_.end(),
630 profile) != supported_profiles_.end();
631 }
632
CreateAvd()633 bool V4L2StatelessVideoDecoderBackend::CreateAvd() {
634 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
635 DVLOGF(3);
636
637 pic_size_ = gfx::Size();
638
639 if (profile_ >= H264PROFILE_MIN && profile_ <= H264PROFILE_MAX) {
640 if (input_queue_->SupportsRequests()) {
641 avd_ = std::make_unique<H264Decoder>(
642 std::make_unique<V4L2H264Accelerator>(this, device_.get()), profile_);
643 } else {
644 avd_ = std::make_unique<H264Decoder>(
645 std::make_unique<V4L2LegacyH264Accelerator>(this, device_.get()),
646 profile_);
647 }
648 } else if (profile_ >= VP8PROFILE_MIN && profile_ <= VP8PROFILE_MAX) {
649 if (input_queue_->SupportsRequests()) {
650 avd_ = std::make_unique<VP8Decoder>(
651 std::make_unique<V4L2VP8Accelerator>(this, device_.get()));
652 } else {
653 avd_ = std::make_unique<VP8Decoder>(
654 std::make_unique<V4L2LegacyVP8Accelerator>(this, device_.get()));
655 }
656 } else if (profile_ >= VP9PROFILE_MIN && profile_ <= VP9PROFILE_MAX) {
657 avd_ = std::make_unique<VP9Decoder>(
658 std::make_unique<V4L2LegacyVP9Accelerator>(this, device_.get()),
659 profile_);
660 } else {
661 VLOGF(1) << "Unsupported profile " << GetProfileName(profile_);
662 return false;
663 }
664 return true;
665 }
666
667 } // namespace media
668