blob: 0772ec992ca4ec8ee0e04ac8cd595cdd6cfb5a05 [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"
Alexandre Courbot139ebe22019-12-12 01:46:3914#include "media/base/video_types.h"
Chih-Yu Huangf4635892019-07-11 14:20:2915#include "media/base/video_util.h"
Chih-Yu Huang5dc635d62019-10-25 10:30:3916#include "media/gpu/chromeos/dmabuf_video_frame_pool.h"
Shuo-Peng Liao761b0ec72019-10-09 05:00:2017#include "media/gpu/chromeos/fourcc.h"
Chih-Yu Huanga4bf8342019-06-27 04:03:4418#include "media/gpu/gpu_video_decode_accelerator_helpers.h"
Chih-Yu Huangde529a82019-06-06 03:26:0919#include "media/gpu/macros.h"
Alexandre Courbot071818f2020-06-12 07:15:3120#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h"
Alexandre Courbot78b1e642019-10-16 03:45:3921#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h"
Chih-Yu Huangde529a82019-06-06 03:26:0922
23namespace media {
24
25namespace {
26
27// See http://crbug.com/255116.
28constexpr int k1080pArea = 1920 * 1088;
29// Input bitstream buffer size for up to 1080p streams.
30constexpr size_t kInputBufferMaxSizeFor1080p = 1024 * 1024;
31// Input bitstream buffer size for up to 4k streams.
32constexpr size_t kInputBufferMaxSizeFor4k = 4 * kInputBufferMaxSizeFor1080p;
33constexpr size_t kNumInputBuffers = 16;
Chih-Yu Huangde529a82019-06-06 03:26:0934
Chih-Yu Huanga4bf8342019-06-27 04:03:4435// Input format V4L2 fourccs this class supports.
36constexpr uint32_t kSupportedInputFourccs[] = {
Alexandre Courbot071818f2020-06-12 07:15:3137 V4L2_PIX_FMT_H264_SLICE, V4L2_PIX_FMT_VP8_FRAME, V4L2_PIX_FMT_VP9_FRAME,
38 V4L2_PIX_FMT_H264, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9,
Chih-Yu Huanga4bf8342019-06-27 04:03:4439};
40
Chih-Yu Huangde529a82019-06-06 03:26:0941} // namespace
42
Chih-Yu Huangde529a82019-06-06 03:26:0943// static
Chih-Yu Huang63b0a1d2019-11-19 09:31:4544std::unique_ptr<DecoderInterface> V4L2SliceVideoDecoder::Create(
Chih-Yu Huangfc163802019-09-02 06:17:4845 scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
Chih-Yu Huang63b0a1d2019-11-19 09:31:4546 base::WeakPtr<DecoderInterface::Client> client) {
Chih-Yu Huanga35c28a2019-10-21 02:43:0947 DCHECK(decoder_task_runner->RunsTasksInCurrentSequence());
Chih-Yu Huang63b0a1d2019-11-19 09:31:4548 DCHECK(client);
Chih-Yu Huangde529a82019-06-06 03:26:0949
50 scoped_refptr<V4L2Device> device = V4L2Device::Create();
51 if (!device) {
52 VLOGF(1) << "Failed to create V4L2 device.";
53 return nullptr;
54 }
55
Chih-Yu Huang63b0a1d2019-11-19 09:31:4556 return base::WrapUnique<DecoderInterface>(new V4L2SliceVideoDecoder(
57 std::move(decoder_task_runner), std::move(client), std::move(device)));
Chih-Yu Huangde529a82019-06-06 03:26:0958}
59
Chih-Yu Huanga4bf8342019-06-27 04:03:4460// static
61SupportedVideoDecoderConfigs V4L2SliceVideoDecoder::GetSupportedConfigs() {
62 scoped_refptr<V4L2Device> device = V4L2Device::Create();
63 if (!device)
64 return SupportedVideoDecoderConfigs();
65
66 return ConvertFromSupportedProfiles(
67 device->GetSupportedDecodeProfiles(base::size(kSupportedInputFourccs),
68 kSupportedInputFourccs),
69 false);
70}
71
Chih-Yu Huangde529a82019-06-06 03:26:0972V4L2SliceVideoDecoder::V4L2SliceVideoDecoder(
Chih-Yu Huangfc163802019-09-02 06:17:4873 scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
Chih-Yu Huang63b0a1d2019-11-19 09:31:4574 base::WeakPtr<DecoderInterface::Client> client,
75 scoped_refptr<V4L2Device> device)
76 : DecoderInterface(std::move(decoder_task_runner), std::move(client)),
77 device_(std::move(device)),
Chih-Yu Huangde529a82019-06-06 03:26:0978 weak_this_factory_(this) {
Chih-Yu Huanga35c28a2019-10-21 02:43:0979 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:0980 VLOGF(2);
Chih-Yu Huanga35c28a2019-10-21 02:43:0981
Chih-Yu Huangde529a82019-06-06 03:26:0982 weak_this_ = weak_this_factory_.GetWeakPtr();
Chih-Yu Huangde529a82019-06-06 03:26:0983}
84
85V4L2SliceVideoDecoder::~V4L2SliceVideoDecoder() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:3686 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:0987 DVLOGF(2);
88
Chih-Yu Huangde529a82019-06-06 03:26:0989 // Call all pending decode callback.
Alexandre Courbot78b1e642019-10-16 03:45:3990 if (backend_) {
91 backend_->ClearPendingRequests(DecodeStatus::ABORTED);
92 backend_ = nullptr;
93 }
Chih-Yu Huang30b5fca2019-09-24 09:03:3494
Chih-Yu Huangde529a82019-06-06 03:26:0995 // Stop and Destroy device.
Alexandre Courbot9270ddc2020-06-09 14:37:1696 StopStreamV4L2Queue(true);
Chih-Yu Huang1c5d4212019-08-01 07:04:4797 if (input_queue_) {
98 input_queue_->DeallocateBuffers();
99 input_queue_ = nullptr;
100 }
101 if (output_queue_) {
102 output_queue_->DeallocateBuffers();
103 output_queue_ = nullptr;
104 }
Francois Buergisser7fee4d12019-10-03 09:22:32105
Chih-Yu Huangde529a82019-06-06 03:26:09106 weak_this_factory_.InvalidateWeakPtrs();
Chih-Yu Huangde529a82019-06-06 03:26:09107}
108
109void V4L2SliceVideoDecoder::Initialize(const VideoDecoderConfig& config,
Chih-Yu Huangde529a82019-06-06 03:26:09110 InitCB init_cb,
Chih-Yu Huang27b72502019-10-18 08:22:49111 const OutputCB& output_cb) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36112 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huanga35c28a2019-10-21 02:43:09113 DCHECK(config.IsValidConfig());
Chih-Yu Huangde529a82019-06-06 03:26:09114 DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding);
115 DVLOGF(3);
116
Chih-Yu Huangde529a82019-06-06 03:26:09117 // Reset V4L2 device and queue if reinitializing decoder.
118 if (state_ != State::kUninitialized) {
Alexandre Courbot9270ddc2020-06-09 14:37:16119 if (!StopStreamV4L2Queue(true)) {
Ted Meyer2a41e242020-03-20 08:01:27120 std::move(init_cb).Run(StatusCode::kV4l2FailedToStopStreamQueue);
Chih-Yu Huangde529a82019-06-06 03:26:09121 return;
122 }
123
124 input_queue_->DeallocateBuffers();
125 output_queue_->DeallocateBuffers();
126 input_queue_ = nullptr;
127 output_queue_ = nullptr;
128
129 device_ = V4L2Device::Create();
130 if (!device_) {
131 VLOGF(1) << "Failed to create V4L2 device.";
Ted Meyer2a41e242020-03-20 08:01:27132 std::move(init_cb).Run(StatusCode::kV4l2NoDevice);
Chih-Yu Huangde529a82019-06-06 03:26:09133 return;
134 }
135
Alexandre Courbot78b1e642019-10-16 03:45:39136 if (backend_)
137 backend_ = nullptr;
138
Chih-Yu Huangde529a82019-06-06 03:26:09139 SetState(State::kUninitialized);
140 }
141
Chih-Yu Huangde529a82019-06-06 03:26:09142 // Open V4L2 device.
143 VideoCodecProfile profile = config.profile();
Alexandre Courbot071818f2020-06-12 07:15:31144 uint32_t input_format_fourcc_stateless =
Chih-Yu Huangde529a82019-06-06 03:26:09145 V4L2Device::VideoCodecProfileToV4L2PixFmt(profile, true);
Alexandre Courbot071818f2020-06-12 07:15:31146 if (!input_format_fourcc_stateless ||
147 !device_->Open(V4L2Device::Type::kDecoder,
148 input_format_fourcc_stateless)) {
Chih-Yu Huangde529a82019-06-06 03:26:09149 VLOGF(1) << "Failed to open device for profile: " << profile
Alexandre Courbot071818f2020-06-12 07:15:31150 << " fourcc: " << FourccToString(input_format_fourcc_stateless);
151 input_format_fourcc_stateless = 0;
152 } else {
153 VLOGF(1) << "Found V4L2 device capable of stateless decoding for "
154 << FourccToString(input_format_fourcc_stateless);
155 }
156
157 uint32_t input_format_fourcc_stateful =
158 V4L2Device::VideoCodecProfileToV4L2PixFmt(profile, false);
159 if (!input_format_fourcc_stateful ||
160 !device_->Open(V4L2Device::Type::kDecoder,
161 input_format_fourcc_stateful)) {
162 VLOGF(1) << "Failed to open device for profile: " << profile
163 << " fourcc: " << FourccToString(input_format_fourcc_stateful);
164 input_format_fourcc_stateful = 0;
165 } else {
166 VLOGF(1) << "Found V4L2 device capable of stateful decoding for "
167 << FourccToString(input_format_fourcc_stateful);
168 }
169
170 if (!input_format_fourcc_stateless && !input_format_fourcc_stateful) {
Ted Meyer2a41e242020-03-20 08:01:27171 std::move(init_cb).Run(StatusCode::kV4l2NoDecoder);
Chih-Yu Huangde529a82019-06-06 03:26:09172 return;
173 }
174
175 struct v4l2_capability caps;
176 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
177 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) ||
178 (caps.capabilities & kCapsRequired) != kCapsRequired) {
179 VLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP, "
180 << "caps check failed: 0x" << std::hex << caps.capabilities;
Ted Meyer2a41e242020-03-20 08:01:27181 std::move(init_cb).Run(StatusCode::kV4l2FailedFileCapabilitiesCheck);
Chih-Yu Huangde529a82019-06-06 03:26:09182 return;
183 }
184
Hirokazu Honda23c6a6a2019-07-25 11:14:45185 pixel_aspect_ratio_ = config.GetPixelAspectRatio();
Chih-Yu Huangde529a82019-06-06 03:26:09186
Alexandre Courbot229c7fe32019-10-07 06:48:01187 // Create Input/Output V4L2Queue
188 input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
189 output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
190 if (!input_queue_ || !output_queue_) {
191 VLOGF(1) << "Failed to create V4L2 queue.";
Ted Meyer2a41e242020-03-20 08:01:27192 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Alexandre Courbot229c7fe32019-10-07 06:48:01193 return;
194 }
195
Alexandre Courbot071818f2020-06-12 07:15:31196 uint32_t input_format_fourcc;
197 if (input_format_fourcc_stateful) {
198 backend_ = std::make_unique<V4L2StatefulVideoDecoderBackend>(
199 this, device_, profile, decoder_task_runner_);
200 input_format_fourcc = input_format_fourcc_stateful;
201 } else if (input_format_fourcc_stateless) {
202 backend_ = std::make_unique<V4L2StatelessVideoDecoderBackend>(
203 this, device_, profile, decoder_task_runner_);
204 input_format_fourcc = input_format_fourcc_stateless;
205 } else {
206 VLOGF(1) << "No backend capable of taking this profile.";
207 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
208 return;
209 }
210
Alexandre Courbot78b1e642019-10-16 03:45:39211 if (!backend_->Initialize()) {
Alexandre Courbot071818f2020-06-12 07:15:31212 VLOGF(1) << "Failed to initialize backend.";
Ted Meyer2a41e242020-03-20 08:01:27213 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Alexandre Courbot78b1e642019-10-16 03:45:39214 return;
215 }
216
Chih-Yu Huangde529a82019-06-06 03:26:09217 // Setup input format.
218 if (!SetupInputFormat(input_format_fourcc)) {
219 VLOGF(1) << "Failed to setup input format.";
Ted Meyer2a41e242020-03-20 08:01:27220 std::move(init_cb).Run(StatusCode::kV4l2BadFormat);
Chih-Yu Huangde529a82019-06-06 03:26:09221 return;
222 }
223
Chih-Yu Huangde529a82019-06-06 03:26:09224 if (input_queue_->AllocateBuffers(kNumInputBuffers, V4L2_MEMORY_MMAP) == 0) {
225 VLOGF(1) << "Failed to allocate input buffer.";
Ted Meyer2a41e242020-03-20 08:01:27226 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Chih-Yu Huangde529a82019-06-06 03:26:09227 return;
228 }
Chih-Yu Huangde529a82019-06-06 03:26:09229
Alexandre Courbot62369b5e2020-06-11 14:11:15230 // Start streaming input queue and polling. This is required for the stateful
231 // decoder, and doesn't hurt for the stateless one.
232 if (!StartStreamV4L2Queue(false)) {
233 VLOGF(1) << "Failed to start streaming.";
234 std::move(init_cb).Run(StatusCode::kV4L2FailedToStartStreamQueue);
235 return;
236 }
237
Chih-Yu Huangde529a82019-06-06 03:26:09238 // Call init_cb
239 output_cb_ = output_cb;
240 SetState(State::kDecoding);
Ted Meyer2a41e242020-03-20 08:01:27241 std::move(init_cb).Run(::media::OkStatus());
Chih-Yu Huangde529a82019-06-06 03:26:09242}
243
244bool V4L2SliceVideoDecoder::SetupInputFormat(uint32_t input_format_fourcc) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36245 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09246 DCHECK_EQ(state_, State::kUninitialized);
247
248 // Check if the format is supported.
249 std::vector<uint32_t> formats = device_->EnumerateSupportedPixelformats(
250 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
251 if (std::find(formats.begin(), formats.end(), input_format_fourcc) ==
252 formats.end()) {
253 DVLOGF(3) << "Input fourcc " << input_format_fourcc
254 << " not supported by device.";
255 return false;
256 }
257
258 // Determine the input buffer size.
259 gfx::Size max_size, min_size;
260 device_->GetSupportedResolution(input_format_fourcc, &min_size, &max_size);
261 size_t input_size = max_size.GetArea() > k1080pArea
262 ? kInputBufferMaxSizeFor4k
263 : kInputBufferMaxSizeFor1080p;
264
265 // Setup the input format.
Yuki Shiino86b64ff2019-10-07 05:37:35266 auto format =
267 input_queue_->SetFormat(input_format_fourcc, gfx::Size(), input_size);
268 if (!format) {
Chih-Yu Huangde529a82019-06-06 03:26:09269 VPLOGF(1) << "Failed to call IOCTL to set input format.";
270 return false;
271 }
Yuki Shiino86b64ff2019-10-07 05:37:35272 DCHECK_EQ(format->fmt.pix_mp.pixelformat, input_format_fourcc);
Chih-Yu Huangde529a82019-06-06 03:26:09273
274 return true;
275}
276
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26277bool V4L2SliceVideoDecoder::SetupOutputFormat(const gfx::Size& size,
278 const gfx::Rect& visible_rect) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36279 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26280 DVLOGF(3) << "size: " << size.ToString()
281 << ", visible_rect: " << visible_rect.ToString();
Chih-Yu Huangde529a82019-06-06 03:26:09282
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26283 // Get the supported output formats and their corresponding negotiated sizes.
284 std::vector<std::pair<Fourcc, gfx::Size>> candidates;
285 for (const uint32_t& pixfmt : device_->EnumerateSupportedPixelformats(
286 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
Alexandre Courbot139ebe22019-12-12 01:46:39287 const auto candidate = Fourcc::FromV4L2PixFmt(pixfmt);
288 if (!candidate) {
289 DVLOGF(1) << "Pixel format " << FourccToString(pixfmt)
290 << " is not supported, skipping...";
291 continue;
292 }
293
Hirokazu Honda685bf012019-08-05 01:30:00294 base::Optional<struct v4l2_format> format =
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26295 output_queue_->SetFormat(pixfmt, size, 0);
Alexandre Courbot139ebe22019-12-12 01:46:39296 if (!format)
297 continue;
298
299 gfx::Size adjusted_size(format->fmt.pix_mp.width,
300 format->fmt.pix_mp.height);
301 candidates.push_back(std::make_pair(*candidate, adjusted_size));
Chih-Yu Huangde529a82019-06-06 03:26:09302 }
303
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26304 // Ask the pipeline to pick the output format.
Alexandre Courbot139ebe22019-12-12 01:46:39305 const base::Optional<Fourcc> fourcc =
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26306 client_->PickDecoderOutputFormat(candidates, visible_rect);
307 if (!fourcc) {
308 VLOGF(1) << "Failed to pick a output format.";
309 return false;
310 }
Chih-Yu Huangde529a82019-06-06 03:26:09311
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26312 // We successfully picked the output format. Now setup output format again.
313 base::Optional<struct v4l2_format> format =
Alexandre Courbot139ebe22019-12-12 01:46:39314 output_queue_->SetFormat(fourcc->ToV4L2PixFmt(), size, 0);
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26315 DCHECK(format);
316 gfx::Size adjusted_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
317 DCHECK_EQ(adjusted_size.width() % 16, 0);
318 DCHECK_EQ(adjusted_size.height() % 16, 0);
319 if (!gfx::Rect(adjusted_size).Contains(gfx::Rect(size))) {
320 VLOGF(1) << "The adjusted coded size (" << adjusted_size.ToString()
321 << ") should contains the original coded size(" << size.ToString()
322 << ").";
323 return false;
324 }
325
326 // Got the adjusted size from the V4L2 driver. Now setup the frame pool.
327 // TODO(akahuang): It is possible there is an allocatable formats among
328 // candidates, but PickDecoderOutputFormat() selects other non-allocatable
329 // format. The correct flow is to attach an info to candidates if it is
330 // created by VideoFramePool.
331 DmabufVideoFramePool* pool = client_->GetVideoFramePool();
332 if (pool) {
Miguel Casas6ee396b2020-01-17 21:21:16333 base::Optional<GpuBufferLayout> layout = pool->Initialize(
Alexandre Courbot139ebe22019-12-12 01:46:39334 *fourcc, adjusted_size, visible_rect,
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26335 GetNaturalSize(visible_rect, pixel_aspect_ratio_), num_output_frames_);
336 if (!layout) {
337 VLOGF(1) << "Failed to setup format to VFPool";
338 return false;
339 }
340 if (layout->size() != adjusted_size) {
341 VLOGF(1) << "The size adjusted by VFPool is different from one "
Alexandre Courbot139ebe22019-12-12 01:46:39342 << "adjusted by a video driver. fourcc: " << fourcc->ToString()
343 << ", (video driver v.s. VFPool) " << adjusted_size.ToString()
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26344 << " != " << layout->size().ToString();
345 return false;
346 }
347 }
348
349 return true;
Chih-Yu Huangf4635892019-07-11 14:20:29350}
351
Chih-Yu Huangde529a82019-06-06 03:26:09352void V4L2SliceVideoDecoder::Reset(base::OnceClosure closure) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36353 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09354 DVLOGF(3);
355
Chih-Yu Huang1141fdeb2019-12-10 06:16:13356 // Reset callback for resolution change, because the pipeline won't notify
357 // flushed after reset.
358 continue_change_resolution_cb_.Reset();
359
Chih-Yu Huangde529a82019-06-06 03:26:09360 // Call all pending decode callback.
Alexandre Courbot78b1e642019-10-16 03:45:39361 backend_->ClearPendingRequests(DecodeStatus::ABORTED);
Chih-Yu Huangde529a82019-06-06 03:26:09362
363 // Streamoff V4L2 queues to drop input and output buffers.
364 // If the queues are streaming before reset, then we need to start streaming
365 // them after stopping.
Alexandre Courbot9270ddc2020-06-09 14:37:16366 const bool is_input_streaming = input_queue_->IsStreaming();
367 const bool is_output_streaming = output_queue_->IsStreaming();
368 if (!StopStreamV4L2Queue(true))
Chih-Yu Huangde529a82019-06-06 03:26:09369 return;
370
Alexandre Courbot9270ddc2020-06-09 14:37:16371 if (is_input_streaming) {
372 if (!StartStreamV4L2Queue(is_output_streaming))
Chih-Yu Huangde529a82019-06-06 03:26:09373 return;
374 }
375
Chih-Yu Huang1141fdeb2019-12-10 06:16:13376 // If during flushing, Reset() will abort the following flush tasks.
377 // Now we are ready to decode new buffer. Go back to decoding state.
378 SetState(State::kDecoding);
379
Chih-Yu Huanga35c28a2019-10-21 02:43:09380 std::move(closure).Run();
Chih-Yu Huangde529a82019-06-06 03:26:09381}
382
Chih-Yu Huangde529a82019-06-06 03:26:09383void V4L2SliceVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
384 DecodeCB decode_cb) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36385 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huang30b5fca2019-09-24 09:03:34386 DCHECK_NE(state_, State::kUninitialized);
387
388 if (state_ == State::kError) {
Alexandre Courbot51ad52a82019-10-07 04:36:36389 std::move(decode_cb).Run(DecodeStatus::DECODE_ERROR);
Chih-Yu Huang30b5fca2019-09-24 09:03:34390 return;
391 }
Chih-Yu Huangde529a82019-06-06 03:26:09392
Alexandre Courbot51ad52a82019-10-07 04:36:36393 const int32_t bitstream_id = bitstream_id_generator_.GetNextBitstreamId();
Alexandre Courbot78b1e642019-10-16 03:45:39394 backend_->EnqueueDecodeTask(std::move(buffer), std::move(decode_cb),
395 bitstream_id);
Chih-Yu Huangde529a82019-06-06 03:26:09396}
397
Alexandre Courbot9270ddc2020-06-09 14:37:16398bool V4L2SliceVideoDecoder::StartStreamV4L2Queue(bool start_output_queue) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36399 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09400 DVLOGF(3);
401
Alexandre Courbot9270ddc2020-06-09 14:37:16402 if (!input_queue_->Streamon() ||
403 (start_output_queue && !output_queue_->Streamon())) {
Chih-Yu Huangde529a82019-06-06 03:26:09404 VLOGF(1) << "Failed to streamon V4L2 queue.";
405 SetState(State::kError);
406 return false;
407 }
408
Alexandre Courbotba021e32019-09-26 07:24:35409 if (!device_->StartPolling(
410 base::BindRepeating(&V4L2SliceVideoDecoder::ServiceDeviceTask,
411 weak_this_),
412 base::BindRepeating(&V4L2SliceVideoDecoder::SetState, weak_this_,
413 State::kError))) {
414 SetState(State::kError);
415 return false;
416 }
417
Chih-Yu Huangde529a82019-06-06 03:26:09418 return true;
419}
420
Alexandre Courbot9270ddc2020-06-09 14:37:16421bool V4L2SliceVideoDecoder::StopStreamV4L2Queue(bool stop_input_queue) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36422 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09423 DVLOGF(3);
424
Alexandre Courbotba021e32019-09-26 07:24:35425 if (!device_->StopPolling()) {
Chih-Yu Huangde529a82019-06-06 03:26:09426 SetState(State::kError);
427 return false;
428 }
429
Chih-Yu Huang1c5d4212019-08-01 07:04:47430 // Streamoff input and output queue.
Alexandre Courbot9270ddc2020-06-09 14:37:16431 if (input_queue_ && stop_input_queue)
Chih-Yu Huangde529a82019-06-06 03:26:09432 input_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:47433 if (output_queue_)
Chih-Yu Huangde529a82019-06-06 03:26:09434 output_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:47435
Alexandre Courbot78b1e642019-10-16 03:45:39436 if (backend_)
Alexandre Courbotb6f96b62020-06-23 02:24:04437 backend_->OnStreamStopped(stop_input_queue);
Alexandre Courbot78b1e642019-10-16 03:45:39438
439 return true;
440}
441
442void V4L2SliceVideoDecoder::InitiateFlush() {
443 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
444 DVLOGF(3);
445
446 SetState(State::kFlushing);
447}
448
449void V4L2SliceVideoDecoder::CompleteFlush() {
450 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
451 DVLOGF(3);
452
453 SetState(State::kDecoding);
454}
455
Chih-Yu Huang63b0a1d2019-11-19 09:31:45456void V4L2SliceVideoDecoder::ChangeResolution(gfx::Size pic_size,
Alexandre Courbot78b1e642019-10-16 03:45:39457 gfx::Rect visible_rect,
458 size_t num_output_frames) {
459 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
460 DVLOGF(3);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45461 DCHECK(!continue_change_resolution_cb_);
462
463 // After the pipeline flushes all frames, we can start changing resolution.
464 continue_change_resolution_cb_ =
465 base::BindOnce(&V4L2SliceVideoDecoder::ContinueChangeResolution,
466 weak_this_, pic_size, visible_rect, num_output_frames);
467
468 DCHECK(client_);
469 client_->PrepareChangeResolution();
470}
471
Alexandre Courbot54dca902020-04-14 16:45:37472void V4L2SliceVideoDecoder::ApplyResolutionChange() {
Chih-Yu Huang63b0a1d2019-11-19 09:31:45473 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
474 DVLOGF(3);
475 DCHECK(continue_change_resolution_cb_);
476
Alexandre Courbotcddb357f2020-04-15 03:51:02477 std::move(continue_change_resolution_cb_).Run();
Chih-Yu Huang63b0a1d2019-11-19 09:31:45478}
479
480void V4L2SliceVideoDecoder::ContinueChangeResolution(
481 const gfx::Size& pic_size,
482 const gfx::Rect& visible_rect,
483 const size_t num_output_frames) {
484 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
485 DVLOGF(3);
Alexandre Courbot78b1e642019-10-16 03:45:39486 DCHECK_EQ(output_queue_->QueuedBuffersCount(), 0u);
487
Chih-Yu Huang1141fdeb2019-12-10 06:16:13488 // If we already reset, then skip it.
489 if (state_ == State::kDecoding)
490 return;
491 DCHECK_EQ(state_, State::kFlushing);
492
Chih-Yu Huang63b0a1d2019-11-19 09:31:45493 // Notify |backend_| that changing resolution fails.
494 // Note: |backend_| is owned by this, using base::Unretained() is safe.
495 base::ScopedClosureRunner done_caller(
496 base::BindOnce(&V4L2VideoDecoderBackend::OnChangeResolutionDone,
497 base::Unretained(backend_.get()), false));
498
Chih-Yu Huangbab32ff2019-11-01 08:49:21499 num_output_frames_ = num_output_frames;
500
Alexandre Courbot9270ddc2020-06-09 14:37:16501 // Stateful decoders require the input queue to keep running during resolution
502 // changes, but stateless ones require it to be stopped.
503 if (!StopStreamV4L2Queue(backend_->StopInputQueueOnResChange()))
Chih-Yu Huang63b0a1d2019-11-19 09:31:45504 return;
Alexandre Courbot78b1e642019-10-16 03:45:39505
Francois Buergisser30e651a2019-10-18 16:22:45506 if (!output_queue_->DeallocateBuffers()) {
507 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45508 return;
Francois Buergisser30e651a2019-10-18 16:22:45509 }
510 DCHECK_GT(num_output_frames, 0u);
511
Alexandre Courbotf5936fe2020-04-02 07:24:12512 if (!backend_->ApplyResolution(pic_size, visible_rect, num_output_frames)) {
513 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45514 return;
Alexandre Courbot78b1e642019-10-16 03:45:39515 }
516
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26517 if (!SetupOutputFormat(pic_size, visible_rect)) {
518 VLOGF(1) << "Failed to setup output format.";
Alexandre Courbot78b1e642019-10-16 03:45:39519 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45520 return;
Alexandre Courbot78b1e642019-10-16 03:45:39521 }
522
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26523 v4l2_memory type =
524 client_->GetVideoFramePool() ? V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP;
525 if (output_queue_->AllocateBuffers(num_output_frames_, type) == 0) {
Alexandre Courbot78b1e642019-10-16 03:45:39526 VLOGF(1) << "Failed to request output buffers.";
527 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45528 return;
Alexandre Courbot78b1e642019-10-16 03:45:39529 }
Chih-Yu Huangbab32ff2019-11-01 08:49:21530 if (output_queue_->AllocatedBuffersCount() != num_output_frames_) {
Alexandre Courbot78b1e642019-10-16 03:45:39531 VLOGF(1) << "Could not allocate requested number of output buffers.";
532 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45533 return;
Alexandre Courbot78b1e642019-10-16 03:45:39534 }
Alexandre Courbot78b1e642019-10-16 03:45:39535
Alexandre Courbot9270ddc2020-06-09 14:37:16536 if (!StartStreamV4L2Queue(true)) {
Alexandre Courbot78b1e642019-10-16 03:45:39537 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45538 return;
Alexandre Courbot78b1e642019-10-16 03:45:39539 }
Chih-Yu Huangde529a82019-06-06 03:26:09540
Chih-Yu Huang63b0a1d2019-11-19 09:31:45541 // Now notify |backend_| that changing resolution is done successfully.
542 // Note: |backend_| is owned by this, using base::Unretained() is safe.
543 done_caller.ReplaceClosure(
544 base::BindOnce(&V4L2VideoDecoderBackend::OnChangeResolutionDone,
545 base::Unretained(backend_.get()), true));
Chih-Yu Huangde529a82019-06-06 03:26:09546}
547
Alexandre Courbot071818f2020-06-12 07:15:31548void V4L2SliceVideoDecoder::ServiceDeviceTask(bool event) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36549 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09550 DVLOGF(3) << "Number of queued input buffers: "
551 << input_queue_->QueuedBuffersCount()
552 << ", Number of queued output buffers: "
553 << output_queue_->QueuedBuffersCount();
554
555 // Dequeue V4L2 output buffer first to reduce output latency.
556 bool success;
Chih-Yu Huangde529a82019-06-06 03:26:09557 while (output_queue_->QueuedBuffersCount() > 0) {
Alexandre Courbot360b5f12020-06-11 15:25:52558 V4L2ReadableBufferRef dequeued_buffer;
559
Chih-Yu Huangde529a82019-06-06 03:26:09560 std::tie(success, dequeued_buffer) = output_queue_->DequeueBuffer();
561 if (!success) {
562 SetState(State::kError);
563 return;
564 }
565 if (!dequeued_buffer)
566 break;
567
Alexandre Courbot78b1e642019-10-16 03:45:39568 backend_->OnOutputBufferDequeued(std::move(dequeued_buffer));
Chih-Yu Huangde529a82019-06-06 03:26:09569 }
570
571 // Dequeue V4L2 input buffer.
572 while (input_queue_->QueuedBuffersCount() > 0) {
Alexandre Courbot360b5f12020-06-11 15:25:52573 V4L2ReadableBufferRef dequeued_buffer;
574
Chih-Yu Huangde529a82019-06-06 03:26:09575 std::tie(success, dequeued_buffer) = input_queue_->DequeueBuffer();
576 if (!success) {
577 SetState(State::kError);
578 return;
579 }
580 if (!dequeued_buffer)
581 break;
582 }
Alexandre Courbot071818f2020-06-12 07:15:31583
584 backend_->OnServiceDeviceTask(event);
Chih-Yu Huangde529a82019-06-06 03:26:09585}
586
Alexandre Courbot78b1e642019-10-16 03:45:39587void V4L2SliceVideoDecoder::OutputFrame(scoped_refptr<VideoFrame> frame,
Chih-Yu Huangf4635892019-07-11 14:20:29588 const gfx::Rect& visible_rect,
Chih-Yu Huangccf46032019-07-11 11:48:06589 base::TimeDelta timestamp) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36590 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Fritz Koenig9c234092020-06-18 00:51:29591 DVLOGF(4) << "timestamp: " << timestamp.InMilliseconds() << " msec";
Chih-Yu Huangde529a82019-06-06 03:26:09592
Chih-Yu Huange497fcc2019-09-25 02:33:11593 // Set the timestamp at which the decode operation started on the
594 // |frame|. If the frame has been outputted before (e.g. because of VP9
595 // show-existing-frame feature) we can't overwrite the timestamp directly, as
596 // the original frame might still be in use. Instead we wrap the frame in
597 // another frame with a different timestamp.
Chih-Yu Huangeacec322019-09-24 05:51:34598 if (frame->timestamp().is_zero())
599 frame->set_timestamp(timestamp);
600
Chih-Yu Huangf4635892019-07-11 14:20:29601 if (frame->visible_rect() != visible_rect ||
602 frame->timestamp() != timestamp) {
603 gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_);
Chih-Yu Huangccf46032019-07-11 11:48:06604 scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
Ricky Liangb2075eb2019-10-01 07:44:50605 frame, frame->format(), visible_rect, natural_size);
Chih-Yu Huangccf46032019-07-11 11:48:06606 wrapped_frame->set_timestamp(timestamp);
Chih-Yu Huangccf46032019-07-11 11:48:06607
608 frame = std::move(wrapped_frame);
609 }
Chih-Yu Huang63b0a1d2019-11-19 09:31:45610
Chih-Yu Huanga35c28a2019-10-21 02:43:09611 output_cb_.Run(std::move(frame));
Chih-Yu Huangde529a82019-06-06 03:26:09612}
613
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26614DmabufVideoFramePool* V4L2SliceVideoDecoder::GetVideoFramePool() const {
615 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
616 DVLOGF(4);
617
618 return client_->GetVideoFramePool();
619}
620
Chih-Yu Huangde529a82019-06-06 03:26:09621void V4L2SliceVideoDecoder::SetState(State new_state) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36622 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09623 DVLOGF(3) << "Change state from " << static_cast<int>(state_) << " to "
624 << static_cast<int>(new_state);
625
626 if (state_ == new_state)
627 return;
628 if (state_ == State::kError) {
629 DVLOGF(3) << "Already in kError state.";
630 return;
631 }
632
633 // Check if the state transition is valid.
634 switch (new_state) {
635 case State::kUninitialized:
636 if (state_ != State::kDecoding) {
637 VLOGF(1) << "Should not set to kUninitialized.";
638 new_state = State::kError;
639 }
640 break;
641
642 case State::kDecoding:
643 break;
644
Chih-Yu Huang40adcdf2019-07-11 03:37:02645 case State::kFlushing:
Chih-Yu Huangde529a82019-06-06 03:26:09646 if (state_ != State::kDecoding) {
Chih-Yu Huang40adcdf2019-07-11 03:37:02647 VLOGF(1) << "kFlushing should only be set when kDecoding.";
Chih-Yu Huangde529a82019-06-06 03:26:09648 new_state = State::kError;
649 }
650 break;
651
652 case State::kError:
653 break;
654 }
655
656 if (new_state == State::kError) {
657 VLOGF(1) << "Error occurred.";
Alexandre Courbot78b1e642019-10-16 03:45:39658 if (backend_)
659 backend_->ClearPendingRequests(DecodeStatus::DECODE_ERROR);
Chih-Yu Huangde529a82019-06-06 03:26:09660 return;
661 }
662 state_ = new_state;
663 return;
664}
665
Alexandre Courbot78b1e642019-10-16 03:45:39666void V4L2SliceVideoDecoder::OnBackendError() {
667 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
668 DVLOGF(2);
669
670 SetState(State::kError);
671}
672
673bool V4L2SliceVideoDecoder::IsDecoding() const {
674 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
675 DVLOGF(3);
676
677 return state_ == State::kDecoding;
678}
679
Chih-Yu Huangde529a82019-06-06 03:26:09680} // namespace media