blob: 390b830ff1fa5b99dea755d5a698c7f7f2317a0f [file] [log] [blame]
Chih-Yu Huangde529a82019-06-06 03:26:091// 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_slice_video_decoder.h"
6
Francois Buergisser7fee4d12019-10-03 09:22:327#include <fcntl.h>
8#include <linux/media.h>
9#include <sys/ioctl.h>
10
Chih-Yu Huangde529a82019-06-06 03:26:0911#include <algorithm>
12
13#include "base/bind.h"
14#include "base/bind_helpers.h"
15#include "base/logging.h"
16#include "base/memory/ptr_util.h"
17#include "base/task/post_task.h"
18#include "media/base/scopedfd_helper.h"
Chih-Yu Huangf4635892019-07-11 14:20:2919#include "media/base/video_util.h"
Chih-Yu Huangde529a82019-06-06 03:26:0920#include "media/gpu/accelerated_video_decoder.h"
Chih-Yu Huanga4bf8342019-06-27 04:03:4421#include "media/gpu/gpu_video_decode_accelerator_helpers.h"
Yuchen Liu241d1c82019-07-16 01:50:1022#include "media/gpu/linux/dmabuf_video_frame_pool.h"
Chih-Yu Huangde529a82019-06-06 03:26:0923#include "media/gpu/macros.h"
Francois Buergisser7fee4d12019-10-03 09:22:3224#include "media/gpu/v4l2/v4l2_h264_accelerator.h"
Alexandre Courbot447e1f682019-08-20 07:54:5625#include "media/gpu/v4l2/v4l2_h264_accelerator_legacy.h"
Francois Buergisser7fee4d12019-10-03 09:22:3226#include "media/gpu/v4l2/v4l2_vp8_accelerator.h"
Alexandre Courbotd7482212019-09-03 07:39:2127#include "media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h"
Chih-Yu Huangde529a82019-06-06 03:26:0928#include "media/gpu/v4l2/v4l2_vp9_accelerator.h"
Chih-Yu Huangde529a82019-06-06 03:26:0929
30namespace media {
31
32namespace {
33
34// See http://crbug.com/255116.
35constexpr int k1080pArea = 1920 * 1088;
36// Input bitstream buffer size for up to 1080p streams.
37constexpr size_t kInputBufferMaxSizeFor1080p = 1024 * 1024;
38// Input bitstream buffer size for up to 4k streams.
39constexpr size_t kInputBufferMaxSizeFor4k = 4 * kInputBufferMaxSizeFor1080p;
40constexpr size_t kNumInputBuffers = 16;
41constexpr size_t kNumInputPlanes = 1;
42
David Staessens59766d62019-09-06 04:24:4643// Size of the timestamp cache, needs to be large enough for frame-reordering.
44constexpr size_t kTimestampCacheSize = 128;
45
Chih-Yu Huanga4bf8342019-06-27 04:03:4446// Input format V4L2 fourccs this class supports.
47constexpr uint32_t kSupportedInputFourccs[] = {
48 V4L2_PIX_FMT_H264_SLICE,
49 V4L2_PIX_FMT_VP8_FRAME,
50 V4L2_PIX_FMT_VP9_FRAME,
51};
52
Hirokazu Hondac1f0a602019-06-12 11:09:2953// Checks an underlying video frame buffer of |frame| is valid for VIDIOC_DQBUF
54// that requires |target_num_fds| fds.
55bool IsValidFrameForQueueDMABuf(const VideoFrame* frame,
56 size_t target_num_fds) {
Chih-Yu Huangde529a82019-06-06 03:26:0957 DCHECK(frame);
58 if (frame->DmabufFds().size() < target_num_fds) {
59 VLOGF(1) << "The count of dmabuf fds (" << frame->DmabufFds().size()
60 << ") are not enough, needs " << target_num_fds << " fds.";
Hirokazu Hondac1f0a602019-06-12 11:09:2961 return false;
Chih-Yu Huangde529a82019-06-06 03:26:0962 }
63
Shuo-Peng Liao57ec8582019-09-27 08:56:5964 const auto& planes = frame->layout().planes();
Chih-Yu Huangde529a82019-06-06 03:26:0965 for (size_t i = frame->DmabufFds().size() - 1; i >= target_num_fds; --i) {
66 // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
67 // Otherwise, if offset == 0, return error as surface_it may be pointing to
68 // a new plane.
69 if (planes[i].offset == 0) {
70 VLOGF(1) << "Additional dmabuf fds point to a new buffer.";
Hirokazu Hondac1f0a602019-06-12 11:09:2971 return false;
Chih-Yu Huangde529a82019-06-06 03:26:0972 }
73 }
74
Hirokazu Hondac1f0a602019-06-12 11:09:2975 return true;
Chih-Yu Huangde529a82019-06-06 03:26:0976}
77
78} // namespace
79
Alexandre Courbotfdd3b552019-08-05 08:55:0280V4L2SliceVideoDecoder::DecodeRequest::DecodeRequest(
81 scoped_refptr<DecoderBuffer> buf,
82 DecodeCB cb,
83 int32_t id)
84 : buffer(std::move(buf)), decode_cb(std::move(cb)), bitstream_id(id) {}
85
86V4L2SliceVideoDecoder::DecodeRequest::DecodeRequest(DecodeRequest&&) = default;
87V4L2SliceVideoDecoder::DecodeRequest& V4L2SliceVideoDecoder::DecodeRequest::
88operator=(DecodeRequest&&) = default;
89
90V4L2SliceVideoDecoder::DecodeRequest::~DecodeRequest() = default;
91
Chih-Yu Huangde529a82019-06-06 03:26:0992struct V4L2SliceVideoDecoder::OutputRequest {
93 enum OutputRequestType {
94 // The surface to be outputted.
95 kSurface,
96 // The fence to indicate the flush request.
97 kFlushFence,
98 // The fence to indicate resolution change request.
99 kChangeResolutionFence,
100 };
101
102 // The type of the request.
103 const OutputRequestType type;
104 // The surface to be outputted.
105 scoped_refptr<V4L2DecodeSurface> surface;
Chih-Yu Huangccf46032019-07-11 11:48:06106 // The timestamp of the output frame. Because a surface might be outputted
107 // multiple times with different timestamp, we need to store timestamp out of
108 // surface.
109 base::TimeDelta timestamp;
Chih-Yu Huangde529a82019-06-06 03:26:09110
Chih-Yu Huangccf46032019-07-11 11:48:06111 static OutputRequest Surface(scoped_refptr<V4L2DecodeSurface> s,
112 base::TimeDelta t) {
113 return OutputRequest(std::move(s), t);
Alexandre Courbot92afc8b72019-06-12 10:48:32114 }
115
116 static OutputRequest FlushFence() { return OutputRequest(kFlushFence); }
117
118 static OutputRequest ChangeResolutionFence() {
119 return OutputRequest(kChangeResolutionFence);
Chih-Yu Huangde529a82019-06-06 03:26:09120 }
121
122 bool IsReady() const {
123 return (type != OutputRequestType::kSurface) || surface->decoded();
124 }
Alexandre Courbot92afc8b72019-06-12 10:48:32125
126 // Allow move, but not copy.
127 OutputRequest(OutputRequest&&) = default;
128
129 private:
Chih-Yu Huangccf46032019-07-11 11:48:06130 OutputRequest(scoped_refptr<V4L2DecodeSurface> s, base::TimeDelta t)
131 : type(kSurface), surface(std::move(s)), timestamp(t) {}
Alexandre Courbot92afc8b72019-06-12 10:48:32132 explicit OutputRequest(OutputRequestType t) : type(t) {}
133
134 DISALLOW_COPY_AND_ASSIGN(OutputRequest);
Chih-Yu Huangde529a82019-06-06 03:26:09135};
136
137// static
138std::unique_ptr<VideoDecoder> V4L2SliceVideoDecoder::Create(
139 scoped_refptr<base::SequencedTaskRunner> client_task_runner,
Chih-Yu Huangfc163802019-09-02 06:17:48140 scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
141 GetFramePoolCB get_pool_cb) {
Chih-Yu Huangde529a82019-06-06 03:26:09142 DCHECK(client_task_runner->RunsTasksInCurrentSequence());
Chih-Yu Huangfc163802019-09-02 06:17:48143 DCHECK(get_pool_cb);
Chih-Yu Huangde529a82019-06-06 03:26:09144
145 scoped_refptr<V4L2Device> device = V4L2Device::Create();
146 if (!device) {
147 VLOGF(1) << "Failed to create V4L2 device.";
148 return nullptr;
149 }
150
151 return base::WrapUnique<VideoDecoder>(new V4L2SliceVideoDecoder(
Chih-Yu Huangfc163802019-09-02 06:17:48152 std::move(client_task_runner), std::move(decoder_task_runner),
153 std::move(device), std::move(get_pool_cb)));
Chih-Yu Huangde529a82019-06-06 03:26:09154}
155
Chih-Yu Huanga4bf8342019-06-27 04:03:44156// static
157SupportedVideoDecoderConfigs V4L2SliceVideoDecoder::GetSupportedConfigs() {
158 scoped_refptr<V4L2Device> device = V4L2Device::Create();
159 if (!device)
160 return SupportedVideoDecoderConfigs();
161
162 return ConvertFromSupportedProfiles(
163 device->GetSupportedDecodeProfiles(base::size(kSupportedInputFourccs),
164 kSupportedInputFourccs),
165 false);
166}
167
Chih-Yu Huangde529a82019-06-06 03:26:09168V4L2SliceVideoDecoder::V4L2SliceVideoDecoder(
169 scoped_refptr<base::SequencedTaskRunner> client_task_runner,
Chih-Yu Huangfc163802019-09-02 06:17:48170 scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
Chih-Yu Huangde529a82019-06-06 03:26:09171 scoped_refptr<V4L2Device> device,
Chih-Yu Huangfc163802019-09-02 06:17:48172 GetFramePoolCB get_pool_cb)
Chih-Yu Huangde529a82019-06-06 03:26:09173 : device_(std::move(device)),
Chih-Yu Huangfc163802019-09-02 06:17:48174 get_pool_cb_(std::move(get_pool_cb)),
Chih-Yu Huangde529a82019-06-06 03:26:09175 client_task_runner_(std::move(client_task_runner)),
Chih-Yu Huangfc163802019-09-02 06:17:48176 decoder_task_runner_(std::move(decoder_task_runner)),
David Staessens59766d62019-09-06 04:24:46177 bitstream_id_to_timestamp_(kTimestampCacheSize),
Chih-Yu Huangde529a82019-06-06 03:26:09178 weak_this_factory_(this) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36179 DETACH_FROM_SEQUENCE(client_sequence_checker_);
180 DETACH_FROM_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09181 VLOGF(2);
182 weak_this_ = weak_this_factory_.GetWeakPtr();
Chih-Yu Huangde529a82019-06-06 03:26:09183}
184
185V4L2SliceVideoDecoder::~V4L2SliceVideoDecoder() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36186 // We might be called from either the client or the decoder sequence.
187 DETACH_FROM_SEQUENCE(client_sequence_checker_);
188 DETACH_FROM_SEQUENCE(decoder_sequence_checker_);
Francois Buergisser7fee4d12019-10-03 09:22:32189 DCHECK(requests_.empty());
Chih-Yu Huangde529a82019-06-06 03:26:09190 VLOGF(2);
191}
192
193std::string V4L2SliceVideoDecoder::GetDisplayName() const {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36194 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
195
Chih-Yu Huangde529a82019-06-06 03:26:09196 return "V4L2SliceVideoDecoder";
197}
198
199bool V4L2SliceVideoDecoder::IsPlatformDecoder() const {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36200 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
201
Chih-Yu Huangde529a82019-06-06 03:26:09202 return true;
203}
204
205int V4L2SliceVideoDecoder::GetMaxDecodeRequests() const {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36206 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
207
Chih-Yu Huangde529a82019-06-06 03:26:09208 return 4;
209}
210
211bool V4L2SliceVideoDecoder::NeedsBitstreamConversion() const {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36212 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
213
Chih-Yu Huangde529a82019-06-06 03:26:09214 return needs_bitstream_conversion_;
215}
216
217bool V4L2SliceVideoDecoder::CanReadWithoutStalling() const {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36218 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
219
Chih-Yu Huangde529a82019-06-06 03:26:09220 return frame_pool_ && !frame_pool_->IsExhausted();
221}
222
223void V4L2SliceVideoDecoder::Destroy() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36224 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09225 VLOGF(2);
226
227 decoder_task_runner_->PostTask(
228 FROM_HERE,
229 base::BindOnce(&V4L2SliceVideoDecoder::DestroyTask, weak_this_));
230}
231
232void V4L2SliceVideoDecoder::DestroyTask() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36233 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09234 DVLOGF(2);
235
Chih-Yu Huangde529a82019-06-06 03:26:09236 // Call all pending decode callback.
237 ClearPendingRequests(DecodeStatus::ABORTED);
238
Chih-Yu Huang30b5fca2019-09-24 09:03:34239 avd_ = nullptr;
240
Chih-Yu Huangde529a82019-06-06 03:26:09241 // Stop and Destroy device.
242 StopStreamV4L2Queue();
Chih-Yu Huang1c5d4212019-08-01 07:04:47243 if (input_queue_) {
244 input_queue_->DeallocateBuffers();
245 input_queue_ = nullptr;
246 }
247 if (output_queue_) {
248 output_queue_->DeallocateBuffers();
249 output_queue_ = nullptr;
250 }
Chih-Yu Huangde529a82019-06-06 03:26:09251 DCHECK(surfaces_at_device_.empty());
252
Francois Buergisser7fee4d12019-10-03 09:22:32253 if (supports_requests_) {
254 requests_ = {};
255 media_fd_.reset();
256 }
257
Chih-Yu Huangde529a82019-06-06 03:26:09258 weak_this_factory_.InvalidateWeakPtrs();
Chih-Yu Huangfc163802019-09-02 06:17:48259
Chih-Yu Huangde529a82019-06-06 03:26:09260 delete this;
261 VLOGF(2) << "Destroyed";
262}
263
264void V4L2SliceVideoDecoder::Initialize(const VideoDecoderConfig& config,
265 bool low_delay,
266 CdmContext* cdm_context,
267 InitCB init_cb,
268 const OutputCB& output_cb,
269 const WaitingCB& /* waiting_cb */) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36270 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09271 VLOGF(2) << "config: " << config.AsHumanReadableString();
272
273 if (!config.IsValidConfig()) {
274 VLOGF(1) << "config is not valid";
275 std::move(init_cb).Run(false);
276 return;
277 }
278 if (cdm_context) {
279 VLOGF(1) << "cdm_context is not supported.";
280 std::move(init_cb).Run(false);
281 return;
282 }
283
284 decoder_task_runner_->PostTask(
285 FROM_HERE,
286 base::BindOnce(&V4L2SliceVideoDecoder::InitializeTask, weak_this_, config,
287 std::move(init_cb), std::move(output_cb)));
288}
289
290void V4L2SliceVideoDecoder::InitializeTask(const VideoDecoderConfig& config,
291 InitCB init_cb,
292 const OutputCB& output_cb) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36293 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09294 DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding);
295 DVLOGF(3);
296
297 if (!output_request_queue_.empty() || flush_cb_ || current_decode_request_ ||
298 !decode_request_queue_.empty()) {
299 VLOGF(1) << "Should not call Initialize() during pending decode";
300 client_task_runner_->PostTask(FROM_HERE,
301 base::BindOnce(std::move(init_cb), false));
302 return;
303 }
304
305 // Reset V4L2 device and queue if reinitializing decoder.
306 if (state_ != State::kUninitialized) {
307 if (!StopStreamV4L2Queue()) {
308 client_task_runner_->PostTask(FROM_HERE,
309 base::BindOnce(std::move(init_cb), false));
310 return;
311 }
312
313 input_queue_->DeallocateBuffers();
314 output_queue_->DeallocateBuffers();
315 input_queue_ = nullptr;
316 output_queue_ = nullptr;
317
318 device_ = V4L2Device::Create();
319 if (!device_) {
320 VLOGF(1) << "Failed to create V4L2 device.";
321 client_task_runner_->PostTask(FROM_HERE,
322 base::BindOnce(std::move(init_cb), false));
323 return;
324 }
325
326 if (avd_) {
327 avd_->Reset();
328 avd_ = nullptr;
329 }
330 SetState(State::kUninitialized);
331 }
332
Chih-Yu Huangfc163802019-09-02 06:17:48333 // Setup frame pool.
334 frame_pool_ = get_pool_cb_.Run();
335
Chih-Yu Huangde529a82019-06-06 03:26:09336 // Open V4L2 device.
337 VideoCodecProfile profile = config.profile();
338 uint32_t input_format_fourcc =
339 V4L2Device::VideoCodecProfileToV4L2PixFmt(profile, true);
Chih-Yu Huang6052d1c2019-08-26 09:35:46340 if (!input_format_fourcc ||
341 !device_->Open(V4L2Device::Type::kDecoder, input_format_fourcc)) {
Chih-Yu Huangde529a82019-06-06 03:26:09342 VLOGF(1) << "Failed to open device for profile: " << profile
343 << " fourcc: " << FourccToString(input_format_fourcc);
344 client_task_runner_->PostTask(FROM_HERE,
345 base::BindOnce(std::move(init_cb), false));
346 return;
347 }
348
349 struct v4l2_capability caps;
350 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
351 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) ||
352 (caps.capabilities & kCapsRequired) != kCapsRequired) {
353 VLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP, "
354 << "caps check failed: 0x" << std::hex << caps.capabilities;
355 client_task_runner_->PostTask(FROM_HERE,
356 base::BindOnce(std::move(init_cb), false));
357 return;
358 }
359
Francois Buergisser7fee4d12019-10-03 09:22:32360 if (!CheckRequestAPISupport()) {
361 VPLOGF(1) << "Failed to check request api support.";
362 client_task_runner_->PostTask(FROM_HERE,
363 base::BindOnce(std::move(init_cb), false));
364 return;
365 }
366
Chih-Yu Huangde529a82019-06-06 03:26:09367 // Create codec-specific AcceleratedVideoDecoder.
368 // TODO(akahuang): Check the profile is supported.
369 if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
Francois Buergisser7fee4d12019-10-03 09:22:32370 if (supports_requests_) {
371 avd_.reset(new H264Decoder(
372 std::make_unique<V4L2H264Accelerator>(this, device_.get())));
373 } else {
374 avd_.reset(new H264Decoder(
375 std::make_unique<V4L2LegacyH264Accelerator>(this, device_.get())));
376 }
Chih-Yu Huangde529a82019-06-06 03:26:09377 } else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) {
Francois Buergisser7fee4d12019-10-03 09:22:32378 if (supports_requests_) {
379 avd_.reset(new VP8Decoder(
380 std::make_unique<V4L2VP8Accelerator>(this, device_.get())));
381 } else {
382 avd_.reset(new VP8Decoder(
383 std::make_unique<V4L2LegacyVP8Accelerator>(this, device_.get())));
384 }
Chih-Yu Huangde529a82019-06-06 03:26:09385 } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
386 avd_.reset(new VP9Decoder(
387 std::make_unique<V4L2VP9Accelerator>(this, device_.get())));
388 } else {
389 VLOGF(1) << "Unsupported profile " << GetProfileName(profile);
390 client_task_runner_->PostTask(FROM_HERE,
391 base::BindOnce(std::move(init_cb), false));
392 return;
393 }
Hirokazu Honda23c6a6a2019-07-25 11:14:45394
Chih-Yu Huangde529a82019-06-06 03:26:09395 needs_bitstream_conversion_ = (config.codec() == kCodecH264);
Hirokazu Honda23c6a6a2019-07-25 11:14:45396 pixel_aspect_ratio_ = config.GetPixelAspectRatio();
Chih-Yu Huangde529a82019-06-06 03:26:09397
398 // Setup input format.
399 if (!SetupInputFormat(input_format_fourcc)) {
400 VLOGF(1) << "Failed to setup input format.";
401 client_task_runner_->PostTask(FROM_HERE,
402 base::BindOnce(std::move(init_cb), false));
403 return;
404 }
405
406 // Setup output format.
Hirokazu Honda23c6a6a2019-07-25 11:14:45407 if (!SetupOutputFormat(config.coded_size(), config.visible_rect())) {
Chih-Yu Huangde529a82019-06-06 03:26:09408 VLOGF(1) << "Failed to setup output format.";
409 client_task_runner_->PostTask(FROM_HERE,
410 base::BindOnce(std::move(init_cb), false));
411 return;
412 }
413
Chih-Yu Huangde529a82019-06-06 03:26:09414 // Create Input/Output V4L2Queue
415 input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
416 output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
417 if (!input_queue_ || !output_queue_) {
418 VLOGF(1) << "Failed to create V4L2 queue.";
419 client_task_runner_->PostTask(FROM_HERE,
420 base::BindOnce(std::move(init_cb), false));
421 return;
422 }
423 if (input_queue_->AllocateBuffers(kNumInputBuffers, V4L2_MEMORY_MMAP) == 0) {
424 VLOGF(1) << "Failed to allocate input buffer.";
425 client_task_runner_->PostTask(FROM_HERE,
426 base::BindOnce(std::move(init_cb), false));
427 return;
428 }
Chih-Yu Huangde529a82019-06-06 03:26:09429
Francois Buergisser7fee4d12019-10-03 09:22:32430 if (supports_requests_ && !AllocateRequests()) {
431 client_task_runner_->PostTask(FROM_HERE,
432 base::BindOnce(std::move(init_cb), false));
433 return;
434 }
435
Chih-Yu Huangde529a82019-06-06 03:26:09436 // Call init_cb
437 output_cb_ = output_cb;
438 SetState(State::kDecoding);
439 client_task_runner_->PostTask(FROM_HERE,
440 base::BindOnce(std::move(init_cb), true));
441}
442
Francois Buergisser7fee4d12019-10-03 09:22:32443bool V4L2SliceVideoDecoder::CheckRequestAPISupport() {
444 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
445 DVLOGF(3);
446
447 struct v4l2_requestbuffers reqbufs;
448 memset(&reqbufs, 0, sizeof(reqbufs));
449 reqbufs.count = 0;
450 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
451 reqbufs.memory = V4L2_MEMORY_MMAP;
452 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) {
453 VPLOGF(1) << "VIDIOC_REQBUFS ioctl failed.";
454 return false;
455 }
456 if (reqbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) {
457 supports_requests_ = true;
458 VLOGF(1) << "Using request API.";
459 DCHECK(!media_fd_.is_valid());
460 // Let's try to open the media device
461 // TODO(crbug.com/985230): remove this hardcoding, replace with V4L2Device
462 // integration.
463 int media_fd = open("/dev/media-dec0", O_RDWR, 0);
464 if (media_fd < 0) {
465 VPLOGF(1) << "Failed to open media device.";
466 return false;
467 }
468 media_fd_ = base::ScopedFD(media_fd);
469 } else {
470 VLOGF(1) << "Using config store.";
471 }
472
473 return true;
474}
475
476bool V4L2SliceVideoDecoder::AllocateRequests() {
477 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
478 DVLOGF(3);
479
480 DCHECK(requests_.empty());
481
482 for (size_t i = 0; i < input_queue_->AllocatedBuffersCount(); i++) {
483 int request_fd;
484
485 int ret = HANDLE_EINTR(
486 ioctl(media_fd_.get(), MEDIA_IOC_REQUEST_ALLOC, &request_fd));
487 if (ret < 0) {
488 VPLOGF(1) << "Failed to create request: ";
489 return false;
490 }
491
492 requests_.push(base::ScopedFD(request_fd));
493 }
494 DCHECK_EQ(requests_.size(), input_queue_->AllocatedBuffersCount());
495
496 return true;
497}
498
Chih-Yu Huangde529a82019-06-06 03:26:09499bool V4L2SliceVideoDecoder::SetupInputFormat(uint32_t input_format_fourcc) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36500 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09501 DCHECK_EQ(state_, State::kUninitialized);
502
503 // Check if the format is supported.
504 std::vector<uint32_t> formats = device_->EnumerateSupportedPixelformats(
505 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
506 if (std::find(formats.begin(), formats.end(), input_format_fourcc) ==
507 formats.end()) {
508 DVLOGF(3) << "Input fourcc " << input_format_fourcc
509 << " not supported by device.";
510 return false;
511 }
512
513 // Determine the input buffer size.
514 gfx::Size max_size, min_size;
515 device_->GetSupportedResolution(input_format_fourcc, &min_size, &max_size);
516 size_t input_size = max_size.GetArea() > k1080pArea
517 ? kInputBufferMaxSizeFor4k
518 : kInputBufferMaxSizeFor1080p;
519
520 // Setup the input format.
521 struct v4l2_format format;
522 memset(&format, 0, sizeof(format));
523 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
524 format.fmt.pix_mp.pixelformat = input_format_fourcc;
525 format.fmt.pix_mp.plane_fmt[0].sizeimage = input_size;
526 format.fmt.pix_mp.num_planes = kNumInputPlanes;
527 if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) {
528 VPLOGF(1) << "Failed to call IOCTL to set input format.";
529 return false;
530 }
531 DCHECK_EQ(format.fmt.pix_mp.pixelformat, input_format_fourcc);
532
533 return true;
534}
535
Hirokazu Honda23c6a6a2019-07-25 11:14:45536base::Optional<struct v4l2_format>
Hirokazu Honda685bf012019-08-05 01:30:00537V4L2SliceVideoDecoder::SetV4L2FormatOnOutputQueue(uint32_t format_fourcc,
538 const gfx::Size& size) {
Hirokazu Honda23c6a6a2019-07-25 11:14:45539 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
540
541 struct v4l2_format format = {};
542 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
543 format.fmt.pix_mp.pixelformat = format_fourcc;
544 format.fmt.pix_mp.width = size.width();
545 format.fmt.pix_mp.height = size.height();
546 format.fmt.pix_mp.num_planes =
547 V4L2Device::GetNumPlanesOfV4L2PixFmt(format_fourcc);
548 if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0 ||
549 format.fmt.pix_mp.pixelformat != format_fourcc) {
550 VPLOGF(2) << "Failed to set output format. format_fourcc=" << format_fourcc;
551 return base::nullopt;
552 }
553 return format;
554}
555
556base::Optional<VideoFrameLayout> V4L2SliceVideoDecoder::SetupOutputFormat(
557 const gfx::Size& size,
558 const gfx::Rect& visible_rect) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36559 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09560
561 const std::vector<uint32_t> formats = device_->EnumerateSupportedPixelformats(
562 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
563 DCHECK(!formats.empty());
Hirokazu Honda23c6a6a2019-07-25 11:14:45564 for (const auto format_fourcc : formats) {
565 if (!device_->CanCreateEGLImageFrom(format_fourcc))
566 continue;
567
Hirokazu Honda685bf012019-08-05 01:30:00568 base::Optional<struct v4l2_format> format =
569 SetV4L2FormatOnOutputQueue(format_fourcc, size);
570 if (!format)
571 continue;
572
573 // S_FMT is successful. Next make sure VFPool can allocate video frames with
574 // width and height adjusted by a video driver.
575 gfx::Size adjusted_size(format->fmt.pix_mp.width,
576 format->fmt.pix_mp.height);
577
Hirokazu Honda23c6a6a2019-07-25 11:14:45578 // Make sure VFPool can allocate video frames with width and height.
579 auto frame_layout =
Hirokazu Honda685bf012019-08-05 01:30:00580 UpdateVideoFramePoolFormat(format_fourcc, adjusted_size, visible_rect);
581 if (frame_layout) {
582 if (frame_layout->coded_size() != adjusted_size) {
583 VLOGF(1) << "The size adjusted by VFPool is different from one "
584 << "adjusted by a video driver";
585 continue;
586 }
Hirokazu Honda23c6a6a2019-07-25 11:14:45587
Hirokazu Honda23c6a6a2019-07-25 11:14:45588 num_output_planes_ = format->fmt.pix_mp.num_planes;
589 return frame_layout;
Chih-Yu Huangde529a82019-06-06 03:26:09590 }
591 }
592
593 // TODO(akahuang): Use ImageProcessor in this case.
594 VLOGF(2) << "WARNING: Cannot find format that can create EGL image. "
595 << "We need ImageProcessor to convert pixel format.";
Hirokazu Honda23c6a6a2019-07-25 11:14:45596 NOTIMPLEMENTED();
597 return base::nullopt;
Chih-Yu Huangde529a82019-06-06 03:26:09598}
599
Hirokazu Honda23c6a6a2019-07-25 11:14:45600base::Optional<VideoFrameLayout>
601V4L2SliceVideoDecoder::UpdateVideoFramePoolFormat(
602 uint32_t output_format_fourcc,
603 const gfx::Size& size,
Hirokazu Honda815c8412019-07-17 08:15:53604 const gfx::Rect& visible_rect) {
Hirokazu Honda23c6a6a2019-07-25 11:14:45605 VideoPixelFormat output_format =
606 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc);
607 if (output_format == PIXEL_FORMAT_UNKNOWN) {
608 return base::nullopt;
609 }
610 auto layout = VideoFrameLayout::Create(output_format, size);
611 if (!layout) {
612 VLOGF(1) << "Failed to create video frame layout.";
613 return base::nullopt;
614 }
615
Hirokazu Honda815c8412019-07-17 08:15:53616 gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_);
Hirokazu Honda23c6a6a2019-07-25 11:14:45617 return frame_pool_->NegotiateFrameFormat(*layout, visible_rect, natural_size);
Chih-Yu Huangf4635892019-07-11 14:20:29618}
619
Chih-Yu Huangde529a82019-06-06 03:26:09620void V4L2SliceVideoDecoder::Reset(base::OnceClosure closure) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36621 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09622 DVLOGF(3);
623
624 decoder_task_runner_->PostTask(
625 FROM_HERE, base::BindOnce(&V4L2SliceVideoDecoder::ResetTask, weak_this_,
626 std::move(closure)));
627}
628
629void V4L2SliceVideoDecoder::ResetTask(base::OnceClosure closure) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36630 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09631 DVLOGF(3);
632
Chih-Yu Huangde529a82019-06-06 03:26:09633 // Call all pending decode callback.
634 ClearPendingRequests(DecodeStatus::ABORTED);
635
636 // Streamoff V4L2 queues to drop input and output buffers.
637 // If the queues are streaming before reset, then we need to start streaming
638 // them after stopping.
Alexandre Courbotba021e32019-09-26 07:24:35639 bool is_streaming = input_queue_->IsStreaming();
Chih-Yu Huangde529a82019-06-06 03:26:09640 if (!StopStreamV4L2Queue())
641 return;
642
Alexandre Courbotba021e32019-09-26 07:24:35643 if (is_streaming) {
Chih-Yu Huangde529a82019-06-06 03:26:09644 if (!StartStreamV4L2Queue())
645 return;
646 }
647
648 client_task_runner_->PostTask(FROM_HERE, std::move(closure));
649}
650
651void V4L2SliceVideoDecoder::ClearPendingRequests(DecodeStatus status) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36652 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09653 DVLOGF(3);
654
Chih-Yu Huang30b5fca2019-09-24 09:03:34655 if (avd_)
656 avd_->Reset();
657
Chih-Yu Huangde529a82019-06-06 03:26:09658 // Clear output_request_queue_.
659 while (!output_request_queue_.empty())
660 output_request_queue_.pop();
661
662 if (flush_cb_)
663 RunDecodeCB(std::move(flush_cb_), status);
664
665 // Clear current_decode_request_ and decode_request_queue_.
666 if (current_decode_request_) {
667 RunDecodeCB(std::move(current_decode_request_->decode_cb), status);
Alexandre Courbot399c547f2019-06-12 08:22:46668 current_decode_request_ = base::nullopt;
Chih-Yu Huangde529a82019-06-06 03:26:09669 }
670
671 while (!decode_request_queue_.empty()) {
672 auto request = std::move(decode_request_queue_.front());
673 decode_request_queue_.pop();
Alexandre Courbot399c547f2019-06-12 08:22:46674 RunDecodeCB(std::move(request.decode_cb), status);
Chih-Yu Huangde529a82019-06-06 03:26:09675 }
676}
677
678void V4L2SliceVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
679 DecodeCB decode_cb) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36680 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09681
682 decoder_task_runner_->PostTask(
683 FROM_HERE,
Alexandre Courbot399c547f2019-06-12 08:22:46684 base::BindOnce(&V4L2SliceVideoDecoder::EnqueueDecodeTask, weak_this_,
685 DecodeRequest(std::move(buffer), std::move(decode_cb),
686 GetNextBitstreamId())));
Chih-Yu Huangde529a82019-06-06 03:26:09687}
688
Alexandre Courbot399c547f2019-06-12 08:22:46689void V4L2SliceVideoDecoder::EnqueueDecodeTask(DecodeRequest request) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36690 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huang30b5fca2019-09-24 09:03:34691 DCHECK_NE(state_, State::kUninitialized);
692
693 if (state_ == State::kError) {
694 std::move(request.decode_cb).Run(DecodeStatus::DECODE_ERROR);
695 return;
696 }
Chih-Yu Huangde529a82019-06-06 03:26:09697
Chih-Yu Huangccf46032019-07-11 11:48:06698 if (!request.buffer->end_of_stream()) {
David Staessens59766d62019-09-06 04:24:46699 bitstream_id_to_timestamp_.Put(request.bitstream_id,
700 request.buffer->timestamp());
Chih-Yu Huangccf46032019-07-11 11:48:06701 }
Chih-Yu Huangde529a82019-06-06 03:26:09702 decode_request_queue_.push(std::move(request));
Chih-Yu Huang1a5f9fc2019-07-09 04:18:24703 // If we are already decoding, then we don't need to pump again.
704 if (!current_decode_request_)
705 PumpDecodeTask();
Chih-Yu Huangde529a82019-06-06 03:26:09706}
707
708void V4L2SliceVideoDecoder::PumpDecodeTask() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36709 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09710 DVLOGF(3) << "state_:" << static_cast<int>(state_)
711 << " Number of Decode requests: " << decode_request_queue_.size();
712
Chih-Yu Huang30b5fca2019-09-24 09:03:34713 if (state_ != State::kDecoding)
Chih-Yu Huangde529a82019-06-06 03:26:09714 return;
715
Chih-Yu Huang40adcdf2019-07-11 03:37:02716 pause_reason_ = PauseReason::kNone;
Chih-Yu Huangde529a82019-06-06 03:26:09717 while (true) {
718 switch (avd_->Decode()) {
719 case AcceleratedVideoDecoder::kAllocateNewSurfaces:
720 DVLOGF(3) << "Need to change resolution. Pause decoding.";
Chih-Yu Huang40adcdf2019-07-11 03:37:02721 SetState(State::kFlushing);
Chih-Yu Huangde529a82019-06-06 03:26:09722
Alexandre Courbot92afc8b72019-06-12 10:48:32723 output_request_queue_.push(OutputRequest::ChangeResolutionFence());
Chih-Yu Huangde529a82019-06-06 03:26:09724 PumpOutputSurfaces();
725 return;
726
727 case AcceleratedVideoDecoder::kRanOutOfStreamData:
728 // Current decode request is finished processing.
729 if (current_decode_request_) {
730 DCHECK(current_decode_request_->decode_cb);
731 RunDecodeCB(std::move(current_decode_request_->decode_cb),
732 DecodeStatus::OK);
Alexandre Courbot399c547f2019-06-12 08:22:46733 current_decode_request_ = base::nullopt;
Chih-Yu Huangde529a82019-06-06 03:26:09734 }
735
736 // Process next decodee request.
737 if (decode_request_queue_.empty())
738 return;
739 current_decode_request_ = std::move(decode_request_queue_.front());
740 decode_request_queue_.pop();
741
742 if (current_decode_request_->buffer->end_of_stream()) {
743 if (!avd_->Flush()) {
744 VLOGF(1) << "Failed flushing the decoder.";
745 SetState(State::kError);
746 return;
747 }
748 // Put the decoder in an idle state, ready to resume.
749 avd_->Reset();
750
Chih-Yu Huang40adcdf2019-07-11 03:37:02751 SetState(State::kFlushing);
Chih-Yu Huangde529a82019-06-06 03:26:09752 DCHECK(!flush_cb_);
753 flush_cb_ = std::move(current_decode_request_->decode_cb);
754
Alexandre Courbot92afc8b72019-06-12 10:48:32755 output_request_queue_.push(OutputRequest::FlushFence());
Chih-Yu Huangde529a82019-06-06 03:26:09756 PumpOutputSurfaces();
Alexandre Courbot399c547f2019-06-12 08:22:46757 current_decode_request_ = base::nullopt;
Chih-Yu Huangde529a82019-06-06 03:26:09758 return;
759 }
760
761 avd_->SetStream(current_decode_request_->bitstream_id,
Hirokazu Honda23132c32019-07-09 14:31:20762 *current_decode_request_->buffer);
Chih-Yu Huangde529a82019-06-06 03:26:09763 break;
764
765 case AcceleratedVideoDecoder::kRanOutOfSurfaces:
766 DVLOGF(3) << "Ran out of surfaces. Resume when buffer is returned.";
Chih-Yu Huang40adcdf2019-07-11 03:37:02767 pause_reason_ = PauseReason::kRanOutOfSurfaces;
Chih-Yu Huangde529a82019-06-06 03:26:09768 return;
769
770 case AcceleratedVideoDecoder::kNeedContextUpdate:
771 DVLOGF(3) << "Awaiting context update";
Chih-Yu Huang40adcdf2019-07-11 03:37:02772 pause_reason_ = PauseReason::kWaitSubFrameDecoded;
Chih-Yu Huangde529a82019-06-06 03:26:09773 return;
774
775 case AcceleratedVideoDecoder::kDecodeError:
776 DVLOGF(3) << "Error decoding stream";
777 SetState(State::kError);
778 return;
779
780 case AcceleratedVideoDecoder::kTryAgain:
781 NOTREACHED() << "Should not reach here unless this class accepts "
782 "encrypted streams.";
783 DVLOGF(4) << "No key for decoding stream.";
784 SetState(State::kError);
785 return;
786 }
787 }
788}
789
790void V4L2SliceVideoDecoder::PumpOutputSurfaces() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36791 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09792 DVLOGF(3) << "state_: " << static_cast<int>(state_)
793 << " Number of display surfaces: " << output_request_queue_.size();
794
795 bool resume_decode = false;
796 while (!output_request_queue_.empty()) {
Alexandre Courbot92afc8b72019-06-12 10:48:32797 if (!output_request_queue_.front().IsReady()) {
Chih-Yu Huangde529a82019-06-06 03:26:09798 DVLOGF(3) << "The first surface is not ready yet.";
799 break;
800 }
801
Alexandre Courbot92afc8b72019-06-12 10:48:32802 OutputRequest request = std::move(output_request_queue_.front());
Chih-Yu Huangde529a82019-06-06 03:26:09803 output_request_queue_.pop();
Alexandre Courbot92afc8b72019-06-12 10:48:32804 switch (request.type) {
Chih-Yu Huangde529a82019-06-06 03:26:09805 case OutputRequest::kFlushFence:
806 DCHECK(output_request_queue_.empty());
807 DVLOGF(2) << "Flush finished.";
808 RunDecodeCB(std::move(flush_cb_), DecodeStatus::OK);
809 resume_decode = true;
810 break;
811
812 case OutputRequest::kChangeResolutionFence:
813 DCHECK(output_request_queue_.empty());
814 if (!ChangeResolution()) {
815 SetState(State::kError);
816 return;
817 }
818 resume_decode = true;
819 break;
820
821 case OutputRequest::kSurface:
Alexandre Courbot92afc8b72019-06-12 10:48:32822 scoped_refptr<V4L2DecodeSurface> surface = std::move(request.surface);
Chih-Yu Huangde529a82019-06-06 03:26:09823
Alexandre Courbotb2196352019-06-14 03:28:50824 DCHECK(surface->video_frame());
Chih-Yu Huangf4635892019-07-11 14:20:29825 RunOutputCB(surface->video_frame(), surface->visible_rect(),
826 request.timestamp);
Chih-Yu Huangde529a82019-06-06 03:26:09827 break;
828 }
829 }
830
831 if (resume_decode) {
832 SetState(State::kDecoding);
833 decoder_task_runner_->PostTask(
834 FROM_HERE,
835 base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_));
836 }
837}
838
839bool V4L2SliceVideoDecoder::ChangeResolution() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36840 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huang40adcdf2019-07-11 03:37:02841 DCHECK_EQ(state_, State::kFlushing);
Chih-Yu Huangde529a82019-06-06 03:26:09842 // We change resolution after outputting all pending surfaces, there should
Alexandre Courbotb2196352019-06-14 03:28:50843 // be no V4L2DecodeSurface left.
Chih-Yu Huangde529a82019-06-06 03:26:09844 DCHECK(surfaces_at_device_.empty());
Alexandre Courbotb2196352019-06-14 03:28:50845 DCHECK_EQ(input_queue_->QueuedBuffersCount(), 0u);
846 DCHECK_EQ(output_queue_->QueuedBuffersCount(), 0u);
Chih-Yu Huangde529a82019-06-06 03:26:09847
848 DCHECK(output_request_queue_.empty());
849 if (!StopStreamV4L2Queue())
850 return false;
851
Hirokazu Honda23c6a6a2019-07-25 11:14:45852 // Set output format with the new resolution.
Chih-Yu Huangde529a82019-06-06 03:26:09853 gfx::Size pic_size = avd_->GetPicSize();
854 DCHECK(!pic_size.IsEmpty());
855 DVLOGF(3) << "Change resolution to " << pic_size.width() << "x"
856 << pic_size.height();
Hirokazu Honda23c6a6a2019-07-25 11:14:45857 auto frame_layout = SetupOutputFormat(pic_size, avd_->GetVisibleRect());
858 if (!frame_layout) {
859 VLOGF(1) << "No format is available with thew new resolution";
Chih-Yu Huangde529a82019-06-06 03:26:09860 return false;
861 }
862
Hirokazu Honda23c6a6a2019-07-25 11:14:45863 auto coded_size = frame_layout->coded_size();
Chih-Yu Huangde529a82019-06-06 03:26:09864 DCHECK_EQ(coded_size.width() % 16, 0);
865 DCHECK_EQ(coded_size.height() % 16, 0);
866 if (!gfx::Rect(coded_size).Contains(gfx::Rect(pic_size))) {
867 VLOGF(1) << "Got invalid adjusted coded size: " << coded_size.ToString();
868 return false;
869 }
Chih-Yu Huangde529a82019-06-06 03:26:09870
871 // Allocate new output buffers.
Chih-Yu Huangf4635892019-07-11 14:20:29872 if (!output_queue_->DeallocateBuffers())
873 return false;
Chih-Yu Huangde529a82019-06-06 03:26:09874 size_t num_output_frames = avd_->GetRequiredNumOfPictures();
875 DCHECK_GT(num_output_frames, 0u);
876 if (output_queue_->AllocateBuffers(num_output_frames, V4L2_MEMORY_DMABUF) ==
877 0) {
878 VLOGF(1) << "Failed to request output buffers.";
879 return false;
880 }
881 if (output_queue_->AllocatedBuffersCount() != num_output_frames) {
882 VLOGF(1) << "Could not allocate requested number of output buffers.";
883 return false;
884 }
885 frame_pool_->SetMaxNumFrames(num_output_frames);
886
887 if (!StartStreamV4L2Queue())
888 return false;
889
890 SetState(State::kDecoding);
891 return true;
892}
893
894scoped_refptr<V4L2DecodeSurface> V4L2SliceVideoDecoder::CreateSurface() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36895 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09896 DVLOGF(4);
897
898 // Request VideoFrame.
899 scoped_refptr<VideoFrame> frame = frame_pool_->GetFrame();
900 if (!frame) {
901 // We allocate the same number of output buffer slot in V4L2 device and the
902 // output VideoFrame. If there is free output buffer slot but no free
903 // VideoFrame, surface_it means the VideoFrame is not released at client
Chih-Yu Huangbe8d9a02019-06-13 07:25:54904 // side. Post PumpDecodeTask when the pool has available frames.
Chih-Yu Huangde529a82019-06-06 03:26:09905 DVLOGF(3) << "There is no available VideoFrame.";
Chih-Yu Huangbe8d9a02019-06-13 07:25:54906 frame_pool_->NotifyWhenFrameAvailable(base::BindOnce(
907 base::IgnoreResult(&base::SequencedTaskRunner::PostTask),
908 decoder_task_runner_, FROM_HERE,
909 base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_)));
Chih-Yu Huangde529a82019-06-06 03:26:09910 return nullptr;
911 }
Chih-Yu Huangde529a82019-06-06 03:26:09912
913 // Request V4L2 input and output buffers.
914 V4L2WritableBufferRef input_buf = input_queue_->GetFreeBuffer();
915 V4L2WritableBufferRef output_buf = output_queue_->GetFreeBuffer();
Chih-Yu Huangbe8d9a02019-06-13 07:25:54916 if (!input_buf.IsValid() || !output_buf.IsValid()) {
917 DVLOGF(3) << "There is no free V4L2 buffer.";
Chih-Yu Huangde529a82019-06-06 03:26:09918 return nullptr;
Chih-Yu Huangbe8d9a02019-06-13 07:25:54919 }
Chih-Yu Huangde529a82019-06-06 03:26:09920
Francois Buergisser7fee4d12019-10-03 09:22:32921 scoped_refptr<V4L2DecodeSurface> dec_surface;
922 if (supports_requests_) {
923 DCHECK(!requests_.empty());
924 base::ScopedFD request = std::move(requests_.front());
925 requests_.pop();
926 auto ret = V4L2RequestDecodeSurface::Create(
927 std::move(input_buf), std::move(output_buf), std::move(frame),
928 request.get());
929 requests_.push(std::move(request));
930 if (!ret) {
931 DVLOGF(3) << "Could not create surface.";
932 return nullptr;
933 }
934 dec_surface = std::move(*ret);
935 } else {
936 dec_surface = new V4L2ConfigStoreDecodeSurface(
937 std::move(input_buf), std::move(output_buf), std::move(frame));
938 }
939
940 return dec_surface;
Chih-Yu Huangde529a82019-06-06 03:26:09941}
942
Alexandre Courbot3f8a0bd2019-06-12 13:30:08943void V4L2SliceVideoDecoder::ReuseOutputBuffer(V4L2ReadableBufferRef buffer) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36944 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Alexandre Courbot3f8a0bd2019-06-12 13:30:08945 DVLOGF(3) << "Reuse output surface #" << buffer->BufferId();
Chih-Yu Huangde529a82019-06-06 03:26:09946
Chih-Yu Huangde529a82019-06-06 03:26:09947 // Resume decoding in case of ran out of surface.
Chih-Yu Huang40adcdf2019-07-11 03:37:02948 if (pause_reason_ == PauseReason::kRanOutOfSurfaces) {
Chih-Yu Huangde529a82019-06-06 03:26:09949 decoder_task_runner_->PostTask(
950 FROM_HERE,
951 base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_));
952 }
953}
954
955bool V4L2SliceVideoDecoder::SubmitSlice(
956 const scoped_refptr<V4L2DecodeSurface>& dec_surface,
957 const uint8_t* data,
958 size_t size) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36959 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09960 DVLOGF(3);
961
Alexandre Courbotb2196352019-06-14 03:28:50962 size_t plane_size = dec_surface->input_buffer().GetPlaneSize(0);
963 size_t bytes_used = dec_surface->input_buffer().GetPlaneBytesUsed(0);
Chih-Yu Huangde529a82019-06-06 03:26:09964 if (size > plane_size - bytes_used) {
965 VLOGF(1) << "The size of submitted slice(" << size
966 << ") is larger than the remaining buffer size("
967 << plane_size - bytes_used << "). Plane size is " << plane_size;
968 SetState(State::kError);
969 return false;
970 }
971
Alexandre Courbotb2196352019-06-14 03:28:50972 void* mapping = dec_surface->input_buffer().GetPlaneMapping(0);
Chih-Yu Huangde529a82019-06-06 03:26:09973 memcpy(reinterpret_cast<uint8_t*>(mapping) + bytes_used, data, size);
Alexandre Courbotb2196352019-06-14 03:28:50974 dec_surface->input_buffer().SetPlaneBytesUsed(0, bytes_used + size);
Chih-Yu Huangde529a82019-06-06 03:26:09975 return true;
976}
977
978void V4L2SliceVideoDecoder::DecodeSurface(
979 const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36980 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09981 DVLOGF(3);
982
983 // Enqueue input_buf and output_buf
Alexandre Courbot52611e72019-07-29 04:57:40984 dec_surface->input_buffer().PrepareQueueBuffer(*dec_surface);
Alexandre Courbotb2196352019-06-14 03:28:50985 if (!std::move(dec_surface->input_buffer()).QueueMMap()) {
Chih-Yu Huangde529a82019-06-06 03:26:09986 SetState(State::kError);
987 return;
988 }
Chih-Yu Huangde529a82019-06-06 03:26:09989
Alexandre Courbotb2196352019-06-14 03:28:50990 if (!IsValidFrameForQueueDMABuf(dec_surface->video_frame().get(),
Hirokazu Hondac1f0a602019-06-12 11:09:29991 num_output_planes_)) {
Chih-Yu Huangde529a82019-06-06 03:26:09992 SetState(State::kError);
993 return;
994 }
Alexandre Courbotb2196352019-06-14 03:28:50995 if (!std::move(dec_surface->output_buffer())
996 .QueueDMABuf(dec_surface->video_frame()->DmabufFds())) {
Chih-Yu Huangde529a82019-06-06 03:26:09997 SetState(State::kError);
998 return;
999 }
Chih-Yu Huangde529a82019-06-06 03:26:091000
1001 if (!dec_surface->Submit()) {
1002 VLOGF(1) << "Error while submitting frame for decoding!";
1003 SetState(State::kError);
1004 return;
1005 }
1006
Alexandre Courbot5f7f2ef2019-06-12 06:39:171007 surfaces_at_device_.push(std::move(dec_surface));
Chih-Yu Huangde529a82019-06-06 03:26:091008}
1009
1010void V4L2SliceVideoDecoder::SurfaceReady(
1011 const scoped_refptr<V4L2DecodeSurface>& dec_surface,
1012 int32_t bitstream_id,
1013 const gfx::Rect& visible_rect,
1014 const VideoColorSpace& /* color_space */) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361015 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:091016 DVLOGF(3);
1017
Chih-Yu Huange497fcc2019-09-25 02:33:111018 // Find the timestamp associated with |bitstream_id|. It's possible that a
1019 // surface is output multiple times for different |bitstream_id|s (e.g. VP9
1020 // show_existing_frame feature). This means we need to output the same frame
1021 // again with a different timestamp.
1022 // On some rare occasions it's also possible that a single DecoderBuffer
1023 // produces multiple surfaces with the same |bitstream_id|, so we shouldn't
1024 // remove the timestamp from the cache.
David Staessens59766d62019-09-06 04:24:461025 const auto it = bitstream_id_to_timestamp_.Peek(bitstream_id);
Chih-Yu Huangccf46032019-07-11 11:48:061026 DCHECK(it != bitstream_id_to_timestamp_.end());
1027 base::TimeDelta timestamp = it->second;
Chih-Yu Huangccf46032019-07-11 11:48:061028
Chih-Yu Huangde529a82019-06-06 03:26:091029 dec_surface->SetVisibleRect(visible_rect);
Chih-Yu Huangccf46032019-07-11 11:48:061030 output_request_queue_.push(
1031 OutputRequest::Surface(std::move(dec_surface), timestamp));
Chih-Yu Huangde529a82019-06-06 03:26:091032 PumpOutputSurfaces();
1033}
1034
1035bool V4L2SliceVideoDecoder::StartStreamV4L2Queue() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361036 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:091037 DVLOGF(3);
1038
Chih-Yu Huangde529a82019-06-06 03:26:091039 if (!input_queue_->Streamon() || !output_queue_->Streamon()) {
1040 VLOGF(1) << "Failed to streamon V4L2 queue.";
1041 SetState(State::kError);
1042 return false;
1043 }
1044
Alexandre Courbotba021e32019-09-26 07:24:351045 if (!device_->StartPolling(
1046 base::BindRepeating(&V4L2SliceVideoDecoder::ServiceDeviceTask,
1047 weak_this_),
1048 base::BindRepeating(&V4L2SliceVideoDecoder::SetState, weak_this_,
1049 State::kError))) {
1050 SetState(State::kError);
1051 return false;
1052 }
1053
Chih-Yu Huangde529a82019-06-06 03:26:091054 return true;
1055}
1056
1057bool V4L2SliceVideoDecoder::StopStreamV4L2Queue() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361058 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:091059 DVLOGF(3);
1060
Alexandre Courbotba021e32019-09-26 07:24:351061 if (!device_->StopPolling()) {
Chih-Yu Huangde529a82019-06-06 03:26:091062 SetState(State::kError);
1063 return false;
1064 }
1065
Chih-Yu Huang1c5d4212019-08-01 07:04:471066 // Streamoff input and output queue.
1067 if (input_queue_)
Chih-Yu Huangde529a82019-06-06 03:26:091068 input_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:471069 if (output_queue_)
Chih-Yu Huangde529a82019-06-06 03:26:091070 output_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:471071
Alexandre Courbot5f7f2ef2019-06-12 06:39:171072 while (!surfaces_at_device_.empty())
1073 surfaces_at_device_.pop();
Chih-Yu Huangde529a82019-06-06 03:26:091074
1075 return true;
1076}
1077
Alexandre Courbotba021e32019-09-26 07:24:351078void V4L2SliceVideoDecoder::ServiceDeviceTask(bool /* event */) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361079 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:091080 DVLOGF(3) << "Number of queued input buffers: "
1081 << input_queue_->QueuedBuffersCount()
1082 << ", Number of queued output buffers: "
1083 << output_queue_->QueuedBuffersCount();
1084
Chih-Yu Huang40adcdf2019-07-11 03:37:021085 bool resume_decode = false;
Chih-Yu Huangde529a82019-06-06 03:26:091086 // Dequeue V4L2 output buffer first to reduce output latency.
1087 bool success;
1088 V4L2ReadableBufferRef dequeued_buffer;
1089 while (output_queue_->QueuedBuffersCount() > 0) {
1090 std::tie(success, dequeued_buffer) = output_queue_->DequeueBuffer();
1091 if (!success) {
1092 SetState(State::kError);
1093 return;
1094 }
1095 if (!dequeued_buffer)
1096 break;
1097
1098 // Mark the output buffer decoded, and try to output surface.
Alexandre Courbot5f7f2ef2019-06-12 06:39:171099 DCHECK(!surfaces_at_device_.empty());
1100 auto surface = std::move(surfaces_at_device_.front());
1101 DCHECK_EQ(static_cast<size_t>(surface->output_record()),
1102 dequeued_buffer->BufferId());
1103 surfaces_at_device_.pop();
1104
1105 surface->SetDecoded();
Chih-Yu Huang40adcdf2019-07-11 03:37:021106 // VP9Decoder update context after surface is decoded. Resume decoding for
1107 // previous pause of AVD::kWaitSubFrameDecoded.
1108 resume_decode = true;
Chih-Yu Huangde529a82019-06-06 03:26:091109
Alexandre Courbot3f8a0bd2019-06-12 13:30:081110 // Keep a reference to the V4L2 buffer until the buffer is reused. The
1111 // reason for this is that the config store uses V4L2 buffer IDs to
1112 // reference frames, therefore we cannot reuse the same V4L2 buffer ID for
1113 // another decode operation until all references to that frame are gone.
1114 // Request API does not have this limitation, so we can probably remove this
1115 // after config store is gone.
1116 surface->SetReleaseCallback(
1117 base::BindOnce(&V4L2SliceVideoDecoder::ReuseOutputBuffer, weak_this_,
1118 std::move(dequeued_buffer)));
Chih-Yu Huangde529a82019-06-06 03:26:091119
1120 PumpOutputSurfaces();
1121 }
1122
1123 // Dequeue V4L2 input buffer.
1124 while (input_queue_->QueuedBuffersCount() > 0) {
1125 std::tie(success, dequeued_buffer) = input_queue_->DequeueBuffer();
1126 if (!success) {
1127 SetState(State::kError);
1128 return;
1129 }
1130 if (!dequeued_buffer)
1131 break;
1132 }
1133
Chih-Yu Huang40adcdf2019-07-11 03:37:021134 if (resume_decode && pause_reason_ == PauseReason::kWaitSubFrameDecoded) {
1135 decoder_task_runner_->PostTask(
1136 FROM_HERE,
1137 base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_));
1138 }
Chih-Yu Huangde529a82019-06-06 03:26:091139}
1140
1141int32_t V4L2SliceVideoDecoder::GetNextBitstreamId() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361142 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:091143
1144 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x7FFFFFFF;
1145 return next_bitstream_buffer_id_;
1146}
1147
1148void V4L2SliceVideoDecoder::RunDecodeCB(DecodeCB cb, DecodeStatus status) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361149 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:091150
1151 client_task_runner_->PostTask(FROM_HERE,
1152 base::BindOnce(std::move(cb), status));
1153}
1154
Chih-Yu Huangccf46032019-07-11 11:48:061155void V4L2SliceVideoDecoder::RunOutputCB(scoped_refptr<VideoFrame> frame,
Chih-Yu Huangf4635892019-07-11 14:20:291156 const gfx::Rect& visible_rect,
Chih-Yu Huangccf46032019-07-11 11:48:061157 base::TimeDelta timestamp) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361158 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangccf46032019-07-11 11:48:061159 DVLOGF(4) << "timestamp: " << timestamp;
Chih-Yu Huangde529a82019-06-06 03:26:091160
Chih-Yu Huange497fcc2019-09-25 02:33:111161 // Set the timestamp at which the decode operation started on the
1162 // |frame|. If the frame has been outputted before (e.g. because of VP9
1163 // show-existing-frame feature) we can't overwrite the timestamp directly, as
1164 // the original frame might still be in use. Instead we wrap the frame in
1165 // another frame with a different timestamp.
Chih-Yu Huangeacec322019-09-24 05:51:341166 if (frame->timestamp().is_zero())
1167 frame->set_timestamp(timestamp);
1168
Chih-Yu Huangf4635892019-07-11 14:20:291169 if (frame->visible_rect() != visible_rect ||
1170 frame->timestamp() != timestamp) {
1171 gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_);
Chih-Yu Huangccf46032019-07-11 11:48:061172 scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
Ricky Liangb2075eb2019-10-01 07:44:501173 frame, frame->format(), visible_rect, natural_size);
Chih-Yu Huangccf46032019-07-11 11:48:061174 wrapped_frame->set_timestamp(timestamp);
Chih-Yu Huangccf46032019-07-11 11:48:061175
1176 frame = std::move(wrapped_frame);
1177 }
Chih-Yu Huangccf46032019-07-11 11:48:061178
Chih-Yu Huangde529a82019-06-06 03:26:091179 // Although the document of VideoDecoder says "should run |output_cb| as soon
1180 // as possible (without thread trampolining)", MojoVideoDecoderService still
1181 // assumes the callback is called at original thread.
1182 // TODO(akahuang): call the callback directly after updating MojoVDService.
Yuchen Liu1adaf9b2019-07-16 20:41:431183 client_task_runner_->PostTask(FROM_HERE,
1184 base::BindOnce(output_cb_, std::move(frame)));
Chih-Yu Huangde529a82019-06-06 03:26:091185}
1186
1187void V4L2SliceVideoDecoder::SetState(State new_state) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:361188 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:091189 DVLOGF(3) << "Change state from " << static_cast<int>(state_) << " to "
1190 << static_cast<int>(new_state);
1191
1192 if (state_ == new_state)
1193 return;
1194 if (state_ == State::kError) {
1195 DVLOGF(3) << "Already in kError state.";
1196 return;
1197 }
1198
1199 // Check if the state transition is valid.
1200 switch (new_state) {
1201 case State::kUninitialized:
1202 if (state_ != State::kDecoding) {
1203 VLOGF(1) << "Should not set to kUninitialized.";
1204 new_state = State::kError;
1205 }
1206 break;
1207
1208 case State::kDecoding:
1209 break;
1210
Chih-Yu Huang40adcdf2019-07-11 03:37:021211 case State::kFlushing:
Chih-Yu Huangde529a82019-06-06 03:26:091212 if (state_ != State::kDecoding) {
Chih-Yu Huang40adcdf2019-07-11 03:37:021213 VLOGF(1) << "kFlushing should only be set when kDecoding.";
Chih-Yu Huangde529a82019-06-06 03:26:091214 new_state = State::kError;
1215 }
1216 break;
1217
1218 case State::kError:
1219 break;
1220 }
1221
1222 if (new_state == State::kError) {
1223 VLOGF(1) << "Error occurred.";
1224 ClearPendingRequests(DecodeStatus::DECODE_ERROR);
1225 return;
1226 }
1227 state_ = new_state;
1228 return;
1229}
1230
1231} // namespace media