blob: 98a116721c0faff0949fff184ce4c34e6ff63999 [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
Alexandre Courbot400c4bf92020-06-25 02:32:105#include "media/gpu/v4l2/v4l2_video_decoder.h"
Chih-Yu Huangde529a82019-06-06 03:26:096
7#include <algorithm>
8
9#include "base/bind.h"
Chih-Yu Huang63b0a1d2019-11-19 09:31:4510#include "base/callback_helpers.h"
Chih-Yu Huangde529a82019-06-06 03:26:0911#include "base/logging.h"
12#include "base/memory/ptr_util.h"
13#include "base/task/post_task.h"
Jeffrey Kardatzkeb30b88b2020-09-29 02:28:0814#include "media/base/limits.h"
Alexandre Courbot139ebe22019-12-12 01:46:3915#include "media/base/video_types.h"
Chih-Yu Huangf4635892019-07-11 14:20:2916#include "media/base/video_util.h"
Chih-Yu Huang5dc635d62019-10-25 10:30:3917#include "media/gpu/chromeos/dmabuf_video_frame_pool.h"
Shuo-Peng Liao761b0ec72019-10-09 05:00:2018#include "media/gpu/chromeos/fourcc.h"
Chih-Yu Huanga4bf8342019-06-27 04:03:4419#include "media/gpu/gpu_video_decode_accelerator_helpers.h"
Chih-Yu Huangde529a82019-06-06 03:26:0920#include "media/gpu/macros.h"
Alexandre Courbot071818f2020-06-12 07:15:3121#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h"
Alexandre Courbot78b1e642019-10-16 03:45:3922#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h"
Chih-Yu Huangde529a82019-06-06 03:26:0923
24namespace media {
25
26namespace {
27
28// See http://crbug.com/255116.
29constexpr int k1080pArea = 1920 * 1088;
30// Input bitstream buffer size for up to 1080p streams.
31constexpr size_t kInputBufferMaxSizeFor1080p = 1024 * 1024;
32// Input bitstream buffer size for up to 4k streams.
33constexpr size_t kInputBufferMaxSizeFor4k = 4 * kInputBufferMaxSizeFor1080p;
34constexpr size_t kNumInputBuffers = 16;
Chih-Yu Huangde529a82019-06-06 03:26:0935
Chih-Yu Huanga4bf8342019-06-27 04:03:4436// Input format V4L2 fourccs this class supports.
37constexpr uint32_t kSupportedInputFourccs[] = {
Alexandre Courbot071818f2020-06-12 07:15:3138 V4L2_PIX_FMT_H264_SLICE, V4L2_PIX_FMT_VP8_FRAME, V4L2_PIX_FMT_VP9_FRAME,
39 V4L2_PIX_FMT_H264, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9,
Chih-Yu Huanga4bf8342019-06-27 04:03:4440};
41
Jeffrey Kardatzkeb30b88b2020-09-29 02:28:0842// Number of output buffers to use for each VD stage above what's required by
43// the decoder (e.g. DPB size, in H264). We need limits::kMaxVideoFrames to
44// fill up the GpuVideoDecode pipeline, and +1 for a frame in transit.
45constexpr size_t kDpbOutputBufferExtraCount = limits::kMaxVideoFrames + 1;
46
Chih-Yu Huangde529a82019-06-06 03:26:0947} // namespace
48
Chih-Yu Huangde529a82019-06-06 03:26:0949// static
Alexandre Courbot34f0e092020-06-25 02:44:3850std::unique_ptr<DecoderInterface> V4L2VideoDecoder::Create(
Chih-Yu Huangfc163802019-09-02 06:17:4851 scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
Chih-Yu Huang63b0a1d2019-11-19 09:31:4552 base::WeakPtr<DecoderInterface::Client> client) {
Chih-Yu Huanga35c28a2019-10-21 02:43:0953 DCHECK(decoder_task_runner->RunsTasksInCurrentSequence());
Chih-Yu Huang63b0a1d2019-11-19 09:31:4554 DCHECK(client);
Chih-Yu Huangde529a82019-06-06 03:26:0955
56 scoped_refptr<V4L2Device> device = V4L2Device::Create();
57 if (!device) {
58 VLOGF(1) << "Failed to create V4L2 device.";
59 return nullptr;
60 }
61
Alexandre Courbot34f0e092020-06-25 02:44:3862 return base::WrapUnique<DecoderInterface>(new V4L2VideoDecoder(
Chih-Yu Huang63b0a1d2019-11-19 09:31:4563 std::move(decoder_task_runner), std::move(client), std::move(device)));
Chih-Yu Huangde529a82019-06-06 03:26:0964}
65
Chih-Yu Huanga4bf8342019-06-27 04:03:4466// static
Alexandre Courbot34f0e092020-06-25 02:44:3867SupportedVideoDecoderConfigs V4L2VideoDecoder::GetSupportedConfigs() {
Chih-Yu Huanga4bf8342019-06-27 04:03:4468 scoped_refptr<V4L2Device> device = V4L2Device::Create();
69 if (!device)
70 return SupportedVideoDecoderConfigs();
71
72 return ConvertFromSupportedProfiles(
73 device->GetSupportedDecodeProfiles(base::size(kSupportedInputFourccs),
74 kSupportedInputFourccs),
75 false);
76}
77
Alexandre Courbot34f0e092020-06-25 02:44:3878V4L2VideoDecoder::V4L2VideoDecoder(
Chih-Yu Huangfc163802019-09-02 06:17:4879 scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
Chih-Yu Huang63b0a1d2019-11-19 09:31:4580 base::WeakPtr<DecoderInterface::Client> client,
81 scoped_refptr<V4L2Device> device)
82 : DecoderInterface(std::move(decoder_task_runner), std::move(client)),
83 device_(std::move(device)),
Chih-Yu Huangde529a82019-06-06 03:26:0984 weak_this_factory_(this) {
Chih-Yu Huanga35c28a2019-10-21 02:43:0985 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:0986 VLOGF(2);
Chih-Yu Huanga35c28a2019-10-21 02:43:0987
Chih-Yu Huangde529a82019-06-06 03:26:0988 weak_this_ = weak_this_factory_.GetWeakPtr();
Chih-Yu Huangde529a82019-06-06 03:26:0989}
90
Alexandre Courbot34f0e092020-06-25 02:44:3891V4L2VideoDecoder::~V4L2VideoDecoder() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:3692 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:0993 DVLOGF(2);
94
Chih-Yu Huangde529a82019-06-06 03:26:0995 // Call all pending decode callback.
Alexandre Courbot78b1e642019-10-16 03:45:3996 if (backend_) {
97 backend_->ClearPendingRequests(DecodeStatus::ABORTED);
98 backend_ = nullptr;
99 }
Chih-Yu Huang30b5fca2019-09-24 09:03:34100
Chih-Yu Huangde529a82019-06-06 03:26:09101 // Stop and Destroy device.
Alexandre Courbot9270ddc2020-06-09 14:37:16102 StopStreamV4L2Queue(true);
Chih-Yu Huang1c5d4212019-08-01 07:04:47103 if (input_queue_) {
104 input_queue_->DeallocateBuffers();
105 input_queue_ = nullptr;
106 }
107 if (output_queue_) {
108 output_queue_->DeallocateBuffers();
109 output_queue_ = nullptr;
110 }
Francois Buergisser7fee4d12019-10-03 09:22:32111
Chih-Yu Huangde529a82019-06-06 03:26:09112 weak_this_factory_.InvalidateWeakPtrs();
Chih-Yu Huangde529a82019-06-06 03:26:09113}
114
Alexandre Courbot34f0e092020-06-25 02:44:38115void V4L2VideoDecoder::Initialize(const VideoDecoderConfig& config,
116 InitCB init_cb,
117 const OutputCB& output_cb) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36118 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huanga35c28a2019-10-21 02:43:09119 DCHECK(config.IsValidConfig());
Chih-Yu Huangde529a82019-06-06 03:26:09120 DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding);
121 DVLOGF(3);
122
Chih-Yu Huangde529a82019-06-06 03:26:09123 // Reset V4L2 device and queue if reinitializing decoder.
124 if (state_ != State::kUninitialized) {
Alexandre Courbot9270ddc2020-06-09 14:37:16125 if (!StopStreamV4L2Queue(true)) {
Ted Meyer2a41e242020-03-20 08:01:27126 std::move(init_cb).Run(StatusCode::kV4l2FailedToStopStreamQueue);
Chih-Yu Huangde529a82019-06-06 03:26:09127 return;
128 }
129
130 input_queue_->DeallocateBuffers();
131 output_queue_->DeallocateBuffers();
132 input_queue_ = nullptr;
133 output_queue_ = nullptr;
134
135 device_ = V4L2Device::Create();
136 if (!device_) {
137 VLOGF(1) << "Failed to create V4L2 device.";
Ted Meyer2a41e242020-03-20 08:01:27138 std::move(init_cb).Run(StatusCode::kV4l2NoDevice);
Chih-Yu Huangde529a82019-06-06 03:26:09139 return;
140 }
141
Alexandre Courbot78b1e642019-10-16 03:45:39142 if (backend_)
143 backend_ = nullptr;
144
Chih-Yu Huangde529a82019-06-06 03:26:09145 SetState(State::kUninitialized);
146 }
147
Chih-Yu Huangde529a82019-06-06 03:26:09148 // Open V4L2 device.
149 VideoCodecProfile profile = config.profile();
Alexandre Courbot071818f2020-06-12 07:15:31150 uint32_t input_format_fourcc_stateless =
Chih-Yu Huangde529a82019-06-06 03:26:09151 V4L2Device::VideoCodecProfileToV4L2PixFmt(profile, true);
Alexandre Courbot071818f2020-06-12 07:15:31152 if (!input_format_fourcc_stateless ||
153 !device_->Open(V4L2Device::Type::kDecoder,
154 input_format_fourcc_stateless)) {
Chih-Yu Huangde529a82019-06-06 03:26:09155 VLOGF(1) << "Failed to open device for profile: " << profile
Alexandre Courbot071818f2020-06-12 07:15:31156 << " fourcc: " << FourccToString(input_format_fourcc_stateless);
157 input_format_fourcc_stateless = 0;
158 } else {
159 VLOGF(1) << "Found V4L2 device capable of stateless decoding for "
160 << FourccToString(input_format_fourcc_stateless);
161 }
162
163 uint32_t input_format_fourcc_stateful =
164 V4L2Device::VideoCodecProfileToV4L2PixFmt(profile, false);
165 if (!input_format_fourcc_stateful ||
166 !device_->Open(V4L2Device::Type::kDecoder,
167 input_format_fourcc_stateful)) {
168 VLOGF(1) << "Failed to open device for profile: " << profile
169 << " fourcc: " << FourccToString(input_format_fourcc_stateful);
170 input_format_fourcc_stateful = 0;
171 } else {
172 VLOGF(1) << "Found V4L2 device capable of stateful decoding for "
173 << FourccToString(input_format_fourcc_stateful);
174 }
175
176 if (!input_format_fourcc_stateless && !input_format_fourcc_stateful) {
Ted Meyer2a41e242020-03-20 08:01:27177 std::move(init_cb).Run(StatusCode::kV4l2NoDecoder);
Chih-Yu Huangde529a82019-06-06 03:26:09178 return;
179 }
180
181 struct v4l2_capability caps;
182 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
183 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) ||
184 (caps.capabilities & kCapsRequired) != kCapsRequired) {
185 VLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP, "
186 << "caps check failed: 0x" << std::hex << caps.capabilities;
Ted Meyer2a41e242020-03-20 08:01:27187 std::move(init_cb).Run(StatusCode::kV4l2FailedFileCapabilitiesCheck);
Chih-Yu Huangde529a82019-06-06 03:26:09188 return;
189 }
190
Hirokazu Honda23c6a6a2019-07-25 11:14:45191 pixel_aspect_ratio_ = config.GetPixelAspectRatio();
Chih-Yu Huangde529a82019-06-06 03:26:09192
Alexandre Courbot229c7fe32019-10-07 06:48:01193 // Create Input/Output V4L2Queue
194 input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
195 output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
196 if (!input_queue_ || !output_queue_) {
197 VLOGF(1) << "Failed to create V4L2 queue.";
Ted Meyer2a41e242020-03-20 08:01:27198 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Alexandre Courbot229c7fe32019-10-07 06:48:01199 return;
200 }
201
Alexandre Courbot071818f2020-06-12 07:15:31202 uint32_t input_format_fourcc;
203 if (input_format_fourcc_stateful) {
204 backend_ = std::make_unique<V4L2StatefulVideoDecoderBackend>(
205 this, device_, profile, decoder_task_runner_);
206 input_format_fourcc = input_format_fourcc_stateful;
207 } else if (input_format_fourcc_stateless) {
208 backend_ = std::make_unique<V4L2StatelessVideoDecoderBackend>(
209 this, device_, profile, decoder_task_runner_);
210 input_format_fourcc = input_format_fourcc_stateless;
211 } else {
212 VLOGF(1) << "No backend capable of taking this profile.";
213 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
214 return;
215 }
216
Alexandre Courbot78b1e642019-10-16 03:45:39217 if (!backend_->Initialize()) {
Alexandre Courbot071818f2020-06-12 07:15:31218 VLOGF(1) << "Failed to initialize backend.";
Ted Meyer2a41e242020-03-20 08:01:27219 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Alexandre Courbot78b1e642019-10-16 03:45:39220 return;
221 }
222
Chih-Yu Huangde529a82019-06-06 03:26:09223 // Setup input format.
224 if (!SetupInputFormat(input_format_fourcc)) {
225 VLOGF(1) << "Failed to setup input format.";
Ted Meyer2a41e242020-03-20 08:01:27226 std::move(init_cb).Run(StatusCode::kV4l2BadFormat);
Chih-Yu Huangde529a82019-06-06 03:26:09227 return;
228 }
229
Chih-Yu Huangde529a82019-06-06 03:26:09230 if (input_queue_->AllocateBuffers(kNumInputBuffers, V4L2_MEMORY_MMAP) == 0) {
231 VLOGF(1) << "Failed to allocate input buffer.";
Ted Meyer2a41e242020-03-20 08:01:27232 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Chih-Yu Huangde529a82019-06-06 03:26:09233 return;
234 }
Chih-Yu Huangde529a82019-06-06 03:26:09235
Alexandre Courbot62369b5e2020-06-11 14:11:15236 // Start streaming input queue and polling. This is required for the stateful
237 // decoder, and doesn't hurt for the stateless one.
238 if (!StartStreamV4L2Queue(false)) {
239 VLOGF(1) << "Failed to start streaming.";
240 std::move(init_cb).Run(StatusCode::kV4L2FailedToStartStreamQueue);
241 return;
242 }
243
Chih-Yu Huangde529a82019-06-06 03:26:09244 // Call init_cb
245 output_cb_ = output_cb;
246 SetState(State::kDecoding);
Ted Meyer2a41e242020-03-20 08:01:27247 std::move(init_cb).Run(::media::OkStatus());
Chih-Yu Huangde529a82019-06-06 03:26:09248}
249
Alexandre Courbot34f0e092020-06-25 02:44:38250bool V4L2VideoDecoder::SetupInputFormat(uint32_t input_format_fourcc) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36251 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09252 DCHECK_EQ(state_, State::kUninitialized);
253
254 // Check if the format is supported.
255 std::vector<uint32_t> formats = device_->EnumerateSupportedPixelformats(
256 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
257 if (std::find(formats.begin(), formats.end(), input_format_fourcc) ==
258 formats.end()) {
259 DVLOGF(3) << "Input fourcc " << input_format_fourcc
260 << " not supported by device.";
261 return false;
262 }
263
264 // Determine the input buffer size.
265 gfx::Size max_size, min_size;
266 device_->GetSupportedResolution(input_format_fourcc, &min_size, &max_size);
267 size_t input_size = max_size.GetArea() > k1080pArea
268 ? kInputBufferMaxSizeFor4k
269 : kInputBufferMaxSizeFor1080p;
270
271 // Setup the input format.
Yuki Shiino86b64ff2019-10-07 05:37:35272 auto format =
273 input_queue_->SetFormat(input_format_fourcc, gfx::Size(), input_size);
274 if (!format) {
Chih-Yu Huangde529a82019-06-06 03:26:09275 VPLOGF(1) << "Failed to call IOCTL to set input format.";
276 return false;
277 }
Yuki Shiino86b64ff2019-10-07 05:37:35278 DCHECK_EQ(format->fmt.pix_mp.pixelformat, input_format_fourcc);
Chih-Yu Huangde529a82019-06-06 03:26:09279
280 return true;
281}
282
Alexandre Courbot34f0e092020-06-25 02:44:38283bool V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size,
284 const gfx::Rect& visible_rect) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36285 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26286 DVLOGF(3) << "size: " << size.ToString()
287 << ", visible_rect: " << visible_rect.ToString();
Chih-Yu Huangde529a82019-06-06 03:26:09288
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26289 // Get the supported output formats and their corresponding negotiated sizes.
290 std::vector<std::pair<Fourcc, gfx::Size>> candidates;
291 for (const uint32_t& pixfmt : device_->EnumerateSupportedPixelformats(
292 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
Alexandre Courbot139ebe22019-12-12 01:46:39293 const auto candidate = Fourcc::FromV4L2PixFmt(pixfmt);
294 if (!candidate) {
295 DVLOGF(1) << "Pixel format " << FourccToString(pixfmt)
296 << " is not supported, skipping...";
297 continue;
298 }
299
Hirokazu Honda685bf012019-08-05 01:30:00300 base::Optional<struct v4l2_format> format =
Alexandre Courbotae2120182020-09-22 17:49:26301 output_queue_->TryFormat(pixfmt, size, 0);
Alexandre Courbot139ebe22019-12-12 01:46:39302 if (!format)
303 continue;
304
305 gfx::Size adjusted_size(format->fmt.pix_mp.width,
306 format->fmt.pix_mp.height);
Alexandre Courbot646b4ae2020-09-11 12:08:23307 candidates.emplace_back(*candidate, adjusted_size);
Chih-Yu Huangde529a82019-06-06 03:26:09308 }
309
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26310 // Ask the pipeline to pick the output format.
Alexandre Courbot0276e8f2020-09-14 03:04:06311 const base::Optional<std::pair<Fourcc, gfx::Size>> output_format =
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26312 client_->PickDecoderOutputFormat(candidates, visible_rect);
Alexandre Courbot0276e8f2020-09-14 03:04:06313 if (!output_format) {
314 VLOGF(1) << "Failed to pick an output format.";
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26315 return false;
316 }
Alexandre Courbot0276e8f2020-09-14 03:04:06317 Fourcc fourcc = std::move(output_format->first);
318 gfx::Size picked_size = std::move(output_format->second);
Chih-Yu Huangde529a82019-06-06 03:26:09319
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26320 // We successfully picked the output format. Now setup output format again.
321 base::Optional<struct v4l2_format> format =
Alexandre Courbot0276e8f2020-09-14 03:04:06322 output_queue_->SetFormat(fourcc.ToV4L2PixFmt(), picked_size, 0);
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26323 DCHECK(format);
324 gfx::Size adjusted_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
325 DCHECK_EQ(adjusted_size.width() % 16, 0);
326 DCHECK_EQ(adjusted_size.height() % 16, 0);
Alexandre Courbot0276e8f2020-09-14 03:04:06327 if (!gfx::Rect(adjusted_size).Contains(gfx::Rect(picked_size))) {
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26328 VLOGF(1) << "The adjusted coded size (" << adjusted_size.ToString()
Alexandre Courbot0276e8f2020-09-14 03:04:06329 << ") should contains the original coded size("
330 << picked_size.ToString() << ").";
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26331 return false;
332 }
333
334 // Got the adjusted size from the V4L2 driver. Now setup the frame pool.
335 // TODO(akahuang): It is possible there is an allocatable formats among
336 // candidates, but PickDecoderOutputFormat() selects other non-allocatable
337 // format. The correct flow is to attach an info to candidates if it is
338 // created by VideoFramePool.
339 DmabufVideoFramePool* pool = client_->GetVideoFramePool();
340 if (pool) {
Miguel Casas6ee396b2020-01-17 21:21:16341 base::Optional<GpuBufferLayout> layout = pool->Initialize(
Alexandre Courbot0276e8f2020-09-14 03:04:06342 fourcc, adjusted_size, visible_rect,
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26343 GetNaturalSize(visible_rect, pixel_aspect_ratio_), num_output_frames_);
344 if (!layout) {
345 VLOGF(1) << "Failed to setup format to VFPool";
346 return false;
347 }
348 if (layout->size() != adjusted_size) {
349 VLOGF(1) << "The size adjusted by VFPool is different from one "
Alexandre Courbot0276e8f2020-09-14 03:04:06350 << "adjusted by a video driver. fourcc: " << fourcc.ToString()
Alexandre Courbot139ebe22019-12-12 01:46:39351 << ", (video driver v.s. VFPool) " << adjusted_size.ToString()
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26352 << " != " << layout->size().ToString();
353 return false;
354 }
Fritz Koenigb7b206e2020-09-02 17:48:49355
356 if (layout->modifier() &&
357 layout->modifier() != gfx::NativePixmapHandle::kNoModifier) {
358 base::Optional<struct v4l2_format> modifier_format =
Alexandre Courbot0276e8f2020-09-14 03:04:06359 output_queue_->SetModifierFormat(layout->modifier(), picked_size);
Fritz Koenigb7b206e2020-09-02 17:48:49360 if (!modifier_format)
361 return false;
362
363 gfx::Size size_for_modifier_format(format->fmt.pix_mp.width,
364 format->fmt.pix_mp.height);
365 if (size_for_modifier_format != adjusted_size) {
366 VLOGF(1)
367 << "Buffers were allocated for " << adjusted_size.ToString()
368 << " but modifier format is expecting buffers to be allocated for "
369 << size_for_modifier_format.ToString();
370 return false;
371 }
372 }
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26373 }
374
375 return true;
Chih-Yu Huangf4635892019-07-11 14:20:29376}
377
Alexandre Courbot34f0e092020-06-25 02:44:38378void V4L2VideoDecoder::Reset(base::OnceClosure closure) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36379 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09380 DVLOGF(3);
381
Chih-Yu Huang1141fdeb2019-12-10 06:16:13382 // Reset callback for resolution change, because the pipeline won't notify
383 // flushed after reset.
384 continue_change_resolution_cb_.Reset();
385
Chih-Yu Huangde529a82019-06-06 03:26:09386 // Call all pending decode callback.
Alexandre Courbot78b1e642019-10-16 03:45:39387 backend_->ClearPendingRequests(DecodeStatus::ABORTED);
Chih-Yu Huangde529a82019-06-06 03:26:09388
389 // Streamoff V4L2 queues to drop input and output buffers.
390 // If the queues are streaming before reset, then we need to start streaming
391 // them after stopping.
Alexandre Courbot9270ddc2020-06-09 14:37:16392 const bool is_input_streaming = input_queue_->IsStreaming();
393 const bool is_output_streaming = output_queue_->IsStreaming();
394 if (!StopStreamV4L2Queue(true))
Chih-Yu Huangde529a82019-06-06 03:26:09395 return;
396
Alexandre Courbot9270ddc2020-06-09 14:37:16397 if (is_input_streaming) {
398 if (!StartStreamV4L2Queue(is_output_streaming))
Chih-Yu Huangde529a82019-06-06 03:26:09399 return;
400 }
401
Chih-Yu Huang1141fdeb2019-12-10 06:16:13402 // If during flushing, Reset() will abort the following flush tasks.
403 // Now we are ready to decode new buffer. Go back to decoding state.
404 SetState(State::kDecoding);
405
Chih-Yu Huanga35c28a2019-10-21 02:43:09406 std::move(closure).Run();
Chih-Yu Huangde529a82019-06-06 03:26:09407}
408
Alexandre Courbot34f0e092020-06-25 02:44:38409void V4L2VideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
410 DecodeCB decode_cb) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36411 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huang30b5fca2019-09-24 09:03:34412 DCHECK_NE(state_, State::kUninitialized);
413
414 if (state_ == State::kError) {
Alexandre Courbot51ad52a82019-10-07 04:36:36415 std::move(decode_cb).Run(DecodeStatus::DECODE_ERROR);
Chih-Yu Huang30b5fca2019-09-24 09:03:34416 return;
417 }
Chih-Yu Huangde529a82019-06-06 03:26:09418
Alexandre Courbot51ad52a82019-10-07 04:36:36419 const int32_t bitstream_id = bitstream_id_generator_.GetNextBitstreamId();
Alexandre Courbot78b1e642019-10-16 03:45:39420 backend_->EnqueueDecodeTask(std::move(buffer), std::move(decode_cb),
421 bitstream_id);
Chih-Yu Huangde529a82019-06-06 03:26:09422}
423
Alexandre Courbot34f0e092020-06-25 02:44:38424bool V4L2VideoDecoder::StartStreamV4L2Queue(bool start_output_queue) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36425 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09426 DVLOGF(3);
427
Alexandre Courbot9270ddc2020-06-09 14:37:16428 if (!input_queue_->Streamon() ||
429 (start_output_queue && !output_queue_->Streamon())) {
Chih-Yu Huangde529a82019-06-06 03:26:09430 VLOGF(1) << "Failed to streamon V4L2 queue.";
431 SetState(State::kError);
432 return false;
433 }
434
Alexandre Courbotba021e32019-09-26 07:24:35435 if (!device_->StartPolling(
Alexandre Courbot34f0e092020-06-25 02:44:38436 base::BindRepeating(&V4L2VideoDecoder::ServiceDeviceTask, weak_this_),
437 base::BindRepeating(&V4L2VideoDecoder::SetState, weak_this_,
Alexandre Courbotba021e32019-09-26 07:24:35438 State::kError))) {
439 SetState(State::kError);
440 return false;
441 }
442
Chih-Yu Huangde529a82019-06-06 03:26:09443 return true;
444}
445
Alexandre Courbot34f0e092020-06-25 02:44:38446bool V4L2VideoDecoder::StopStreamV4L2Queue(bool stop_input_queue) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36447 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09448 DVLOGF(3);
449
Alexandre Courbotba021e32019-09-26 07:24:35450 if (!device_->StopPolling()) {
Chih-Yu Huangde529a82019-06-06 03:26:09451 SetState(State::kError);
452 return false;
453 }
454
Chih-Yu Huang1c5d4212019-08-01 07:04:47455 // Streamoff input and output queue.
Alexandre Courbot9270ddc2020-06-09 14:37:16456 if (input_queue_ && stop_input_queue)
Chih-Yu Huangde529a82019-06-06 03:26:09457 input_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:47458 if (output_queue_)
Chih-Yu Huangde529a82019-06-06 03:26:09459 output_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:47460
Alexandre Courbot78b1e642019-10-16 03:45:39461 if (backend_)
Alexandre Courbotb6f96b62020-06-23 02:24:04462 backend_->OnStreamStopped(stop_input_queue);
Alexandre Courbot78b1e642019-10-16 03:45:39463
464 return true;
465}
466
Alexandre Courbot34f0e092020-06-25 02:44:38467void V4L2VideoDecoder::InitiateFlush() {
Alexandre Courbot78b1e642019-10-16 03:45:39468 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
469 DVLOGF(3);
470
471 SetState(State::kFlushing);
472}
473
Alexandre Courbot34f0e092020-06-25 02:44:38474void V4L2VideoDecoder::CompleteFlush() {
Alexandre Courbot78b1e642019-10-16 03:45:39475 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
476 DVLOGF(3);
477
478 SetState(State::kDecoding);
479}
480
Alexandre Courbot34f0e092020-06-25 02:44:38481void V4L2VideoDecoder::ChangeResolution(gfx::Size pic_size,
482 gfx::Rect visible_rect,
483 size_t num_output_frames) {
Alexandre Courbot78b1e642019-10-16 03:45:39484 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
485 DVLOGF(3);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45486 DCHECK(!continue_change_resolution_cb_);
487
488 // After the pipeline flushes all frames, we can start changing resolution.
489 continue_change_resolution_cb_ =
Alexandre Courbot34f0e092020-06-25 02:44:38490 base::BindOnce(&V4L2VideoDecoder::ContinueChangeResolution, weak_this_,
491 pic_size, visible_rect, num_output_frames);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45492
493 DCHECK(client_);
494 client_->PrepareChangeResolution();
495}
496
Alexandre Courbot34f0e092020-06-25 02:44:38497void V4L2VideoDecoder::ApplyResolutionChange() {
Chih-Yu Huang63b0a1d2019-11-19 09:31:45498 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
499 DVLOGF(3);
500 DCHECK(continue_change_resolution_cb_);
501
Alexandre Courbotcddb357f2020-04-15 03:51:02502 std::move(continue_change_resolution_cb_).Run();
Chih-Yu Huang63b0a1d2019-11-19 09:31:45503}
504
Alexandre Courbot34f0e092020-06-25 02:44:38505void V4L2VideoDecoder::ContinueChangeResolution(
Chih-Yu Huang63b0a1d2019-11-19 09:31:45506 const gfx::Size& pic_size,
507 const gfx::Rect& visible_rect,
508 const size_t num_output_frames) {
509 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
510 DVLOGF(3);
Alexandre Courbot78b1e642019-10-16 03:45:39511
Chih-Yu Huang1141fdeb2019-12-10 06:16:13512 // If we already reset, then skip it.
513 if (state_ == State::kDecoding)
514 return;
515 DCHECK_EQ(state_, State::kFlushing);
516
Chih-Yu Huang63b0a1d2019-11-19 09:31:45517 // Notify |backend_| that changing resolution fails.
518 // Note: |backend_| is owned by this, using base::Unretained() is safe.
519 base::ScopedClosureRunner done_caller(
520 base::BindOnce(&V4L2VideoDecoderBackend::OnChangeResolutionDone,
521 base::Unretained(backend_.get()), false));
522
Jeffrey Kardatzkeb30b88b2020-09-29 02:28:08523 DCHECK_GT(num_output_frames, 0u);
524 num_output_frames_ = num_output_frames + kDpbOutputBufferExtraCount;
Chih-Yu Huangbab32ff2019-11-01 08:49:21525
Alexandre Courbot9270ddc2020-06-09 14:37:16526 // Stateful decoders require the input queue to keep running during resolution
527 // changes, but stateless ones require it to be stopped.
528 if (!StopStreamV4L2Queue(backend_->StopInputQueueOnResChange()))
Chih-Yu Huang63b0a1d2019-11-19 09:31:45529 return;
Alexandre Courbot78b1e642019-10-16 03:45:39530
Francois Buergisser30e651a2019-10-18 16:22:45531 if (!output_queue_->DeallocateBuffers()) {
532 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45533 return;
Francois Buergisser30e651a2019-10-18 16:22:45534 }
Francois Buergisser30e651a2019-10-18 16:22:45535
Jeffrey Kardatzkeb30b88b2020-09-29 02:28:08536 if (!backend_->ApplyResolution(pic_size, visible_rect, num_output_frames_)) {
Alexandre Courbotf5936fe2020-04-02 07:24:12537 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45538 return;
Alexandre Courbot78b1e642019-10-16 03:45:39539 }
540
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26541 if (!SetupOutputFormat(pic_size, visible_rect)) {
542 VLOGF(1) << "Failed to setup output format.";
Alexandre Courbot78b1e642019-10-16 03:45:39543 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45544 return;
Alexandre Courbot78b1e642019-10-16 03:45:39545 }
546
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26547 v4l2_memory type =
548 client_->GetVideoFramePool() ? V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP;
549 if (output_queue_->AllocateBuffers(num_output_frames_, type) == 0) {
Alexandre Courbot78b1e642019-10-16 03:45:39550 VLOGF(1) << "Failed to request output buffers.";
551 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45552 return;
Alexandre Courbot78b1e642019-10-16 03:45:39553 }
Chih-Yu Huangbab32ff2019-11-01 08:49:21554 if (output_queue_->AllocatedBuffersCount() != num_output_frames_) {
Alexandre Courbot78b1e642019-10-16 03:45:39555 VLOGF(1) << "Could not allocate requested number of output buffers.";
556 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45557 return;
Alexandre Courbot78b1e642019-10-16 03:45:39558 }
Alexandre Courbot78b1e642019-10-16 03:45:39559
Alexandre Courbot9270ddc2020-06-09 14:37:16560 if (!StartStreamV4L2Queue(true)) {
Alexandre Courbot78b1e642019-10-16 03:45:39561 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45562 return;
Alexandre Courbot78b1e642019-10-16 03:45:39563 }
Chih-Yu Huangde529a82019-06-06 03:26:09564
Chih-Yu Huang63b0a1d2019-11-19 09:31:45565 // Now notify |backend_| that changing resolution is done successfully.
566 // Note: |backend_| is owned by this, using base::Unretained() is safe.
567 done_caller.ReplaceClosure(
568 base::BindOnce(&V4L2VideoDecoderBackend::OnChangeResolutionDone,
569 base::Unretained(backend_.get()), true));
Chih-Yu Huangde529a82019-06-06 03:26:09570}
571
Alexandre Courbot34f0e092020-06-25 02:44:38572void V4L2VideoDecoder::ServiceDeviceTask(bool event) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36573 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09574 DVLOGF(3) << "Number of queued input buffers: "
575 << input_queue_->QueuedBuffersCount()
576 << ", Number of queued output buffers: "
577 << output_queue_->QueuedBuffersCount();
578
Fritz Koenige6283bc2020-09-10 15:29:51579 backend_->OnServiceDeviceTask(event);
580
Chih-Yu Huangde529a82019-06-06 03:26:09581 // Dequeue V4L2 output buffer first to reduce output latency.
582 bool success;
Chih-Yu Huangde529a82019-06-06 03:26:09583 while (output_queue_->QueuedBuffersCount() > 0) {
Alexandre Courbot360b5f12020-06-11 15:25:52584 V4L2ReadableBufferRef dequeued_buffer;
585
Chih-Yu Huangde529a82019-06-06 03:26:09586 std::tie(success, dequeued_buffer) = output_queue_->DequeueBuffer();
587 if (!success) {
588 SetState(State::kError);
589 return;
590 }
591 if (!dequeued_buffer)
592 break;
593
Alexandre Courbot78b1e642019-10-16 03:45:39594 backend_->OnOutputBufferDequeued(std::move(dequeued_buffer));
Chih-Yu Huangde529a82019-06-06 03:26:09595 }
596
597 // Dequeue V4L2 input buffer.
598 while (input_queue_->QueuedBuffersCount() > 0) {
Alexandre Courbot360b5f12020-06-11 15:25:52599 V4L2ReadableBufferRef dequeued_buffer;
600
Chih-Yu Huangde529a82019-06-06 03:26:09601 std::tie(success, dequeued_buffer) = input_queue_->DequeueBuffer();
602 if (!success) {
603 SetState(State::kError);
604 return;
605 }
606 if (!dequeued_buffer)
607 break;
608 }
Chih-Yu Huangde529a82019-06-06 03:26:09609}
610
Alexandre Courbot34f0e092020-06-25 02:44:38611void V4L2VideoDecoder::OutputFrame(scoped_refptr<VideoFrame> frame,
612 const gfx::Rect& visible_rect,
613 base::TimeDelta timestamp) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36614 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Fritz Koenig9c234092020-06-18 00:51:29615 DVLOGF(4) << "timestamp: " << timestamp.InMilliseconds() << " msec";
Chih-Yu Huangde529a82019-06-06 03:26:09616
Chih-Yu Huange497fcc2019-09-25 02:33:11617 // Set the timestamp at which the decode operation started on the
618 // |frame|. If the frame has been outputted before (e.g. because of VP9
619 // show-existing-frame feature) we can't overwrite the timestamp directly, as
620 // the original frame might still be in use. Instead we wrap the frame in
621 // another frame with a different timestamp.
Chih-Yu Huangeacec322019-09-24 05:51:34622 if (frame->timestamp().is_zero())
623 frame->set_timestamp(timestamp);
624
Chih-Yu Huangf4635892019-07-11 14:20:29625 if (frame->visible_rect() != visible_rect ||
626 frame->timestamp() != timestamp) {
627 gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_);
Chih-Yu Huangccf46032019-07-11 11:48:06628 scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
Ricky Liangb2075eb2019-10-01 07:44:50629 frame, frame->format(), visible_rect, natural_size);
Chih-Yu Huangccf46032019-07-11 11:48:06630 wrapped_frame->set_timestamp(timestamp);
Chih-Yu Huangccf46032019-07-11 11:48:06631
632 frame = std::move(wrapped_frame);
633 }
Chih-Yu Huang63b0a1d2019-11-19 09:31:45634
Chih-Yu Huanga35c28a2019-10-21 02:43:09635 output_cb_.Run(std::move(frame));
Chih-Yu Huangde529a82019-06-06 03:26:09636}
637
Alexandre Courbot34f0e092020-06-25 02:44:38638DmabufVideoFramePool* V4L2VideoDecoder::GetVideoFramePool() const {
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26639 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
640 DVLOGF(4);
641
642 return client_->GetVideoFramePool();
643}
644
Alexandre Courbot34f0e092020-06-25 02:44:38645void V4L2VideoDecoder::SetState(State new_state) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36646 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09647 DVLOGF(3) << "Change state from " << static_cast<int>(state_) << " to "
648 << static_cast<int>(new_state);
649
650 if (state_ == new_state)
651 return;
652 if (state_ == State::kError) {
653 DVLOGF(3) << "Already in kError state.";
654 return;
655 }
656
657 // Check if the state transition is valid.
658 switch (new_state) {
659 case State::kUninitialized:
660 if (state_ != State::kDecoding) {
661 VLOGF(1) << "Should not set to kUninitialized.";
662 new_state = State::kError;
663 }
664 break;
665
666 case State::kDecoding:
667 break;
668
Chih-Yu Huang40adcdf2019-07-11 03:37:02669 case State::kFlushing:
Chih-Yu Huangde529a82019-06-06 03:26:09670 if (state_ != State::kDecoding) {
Chih-Yu Huang40adcdf2019-07-11 03:37:02671 VLOGF(1) << "kFlushing should only be set when kDecoding.";
Chih-Yu Huangde529a82019-06-06 03:26:09672 new_state = State::kError;
673 }
674 break;
675
676 case State::kError:
677 break;
678 }
679
680 if (new_state == State::kError) {
681 VLOGF(1) << "Error occurred.";
Alexandre Courbot78b1e642019-10-16 03:45:39682 if (backend_)
683 backend_->ClearPendingRequests(DecodeStatus::DECODE_ERROR);
Chih-Yu Huangde529a82019-06-06 03:26:09684 return;
685 }
686 state_ = new_state;
687 return;
688}
689
Alexandre Courbot34f0e092020-06-25 02:44:38690void V4L2VideoDecoder::OnBackendError() {
Alexandre Courbot78b1e642019-10-16 03:45:39691 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
692 DVLOGF(2);
693
694 SetState(State::kError);
695}
696
Alexandre Courbot34f0e092020-06-25 02:44:38697bool V4L2VideoDecoder::IsDecoding() const {
Alexandre Courbot78b1e642019-10-16 03:45:39698 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
699 DVLOGF(3);
700
701 return state_ == State::kDecoding;
702}
703
Chih-Yu Huangde529a82019-06-06 03:26:09704} // namespace media