blob: 28e1b3b7e4aa28f265c0a5464a9ca1027ff34846 [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
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 Courbot78b1e642019-10-16 03:45:3920#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h"
Chih-Yu Huangde529a82019-06-06 03:26:0921
22namespace media {
23
24namespace {
25
26// See http://crbug.com/255116.
27constexpr int k1080pArea = 1920 * 1088;
28// Input bitstream buffer size for up to 1080p streams.
29constexpr size_t kInputBufferMaxSizeFor1080p = 1024 * 1024;
30// Input bitstream buffer size for up to 4k streams.
31constexpr size_t kInputBufferMaxSizeFor4k = 4 * kInputBufferMaxSizeFor1080p;
32constexpr size_t kNumInputBuffers = 16;
Chih-Yu Huangde529a82019-06-06 03:26:0933
Chih-Yu Huanga4bf8342019-06-27 04:03:4434// Input format V4L2 fourccs this class supports.
35constexpr uint32_t kSupportedInputFourccs[] = {
36 V4L2_PIX_FMT_H264_SLICE,
37 V4L2_PIX_FMT_VP8_FRAME,
38 V4L2_PIX_FMT_VP9_FRAME,
39};
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.
96 StopStreamV4L2Queue();
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) {
119 if (!StopStreamV4L2Queue()) {
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();
144 uint32_t input_format_fourcc =
145 V4L2Device::VideoCodecProfileToV4L2PixFmt(profile, true);
Chih-Yu Huang6052d1c2019-08-26 09:35:46146 if (!input_format_fourcc ||
147 !device_->Open(V4L2Device::Type::kDecoder, input_format_fourcc)) {
Chih-Yu Huangde529a82019-06-06 03:26:09148 VLOGF(1) << "Failed to open device for profile: " << profile
149 << " fourcc: " << FourccToString(input_format_fourcc);
Ted Meyer2a41e242020-03-20 08:01:27150 std::move(init_cb).Run(StatusCode::kV4l2NoDecoder);
Chih-Yu Huangde529a82019-06-06 03:26:09151 return;
152 }
153
154 struct v4l2_capability caps;
155 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
156 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) ||
157 (caps.capabilities & kCapsRequired) != kCapsRequired) {
158 VLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP, "
159 << "caps check failed: 0x" << std::hex << caps.capabilities;
Ted Meyer2a41e242020-03-20 08:01:27160 std::move(init_cb).Run(StatusCode::kV4l2FailedFileCapabilitiesCheck);
Chih-Yu Huangde529a82019-06-06 03:26:09161 return;
162 }
163
Hirokazu Honda23c6a6a2019-07-25 11:14:45164 pixel_aspect_ratio_ = config.GetPixelAspectRatio();
Chih-Yu Huangde529a82019-06-06 03:26:09165
Alexandre Courbot229c7fe32019-10-07 06:48:01166 // Create Input/Output V4L2Queue
167 input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
168 output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
169 if (!input_queue_ || !output_queue_) {
170 VLOGF(1) << "Failed to create V4L2 queue.";
Ted Meyer2a41e242020-03-20 08:01:27171 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Alexandre Courbot229c7fe32019-10-07 06:48:01172 return;
173 }
174
Alexandre Courbot78b1e642019-10-16 03:45:39175 // Create the backend (only stateless API supported as of now).
176 backend_ = std::make_unique<V4L2StatelessVideoDecoderBackend>(
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26177 this, device_, profile, decoder_task_runner_);
Alexandre Courbot78b1e642019-10-16 03:45:39178 if (!backend_->Initialize()) {
Ted Meyer2a41e242020-03-20 08:01:27179 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Alexandre Courbot78b1e642019-10-16 03:45:39180 return;
181 }
182
Chih-Yu Huangde529a82019-06-06 03:26:09183 // Setup input format.
184 if (!SetupInputFormat(input_format_fourcc)) {
185 VLOGF(1) << "Failed to setup input format.";
Ted Meyer2a41e242020-03-20 08:01:27186 std::move(init_cb).Run(StatusCode::kV4l2BadFormat);
Chih-Yu Huangde529a82019-06-06 03:26:09187 return;
188 }
189
Chih-Yu Huangde529a82019-06-06 03:26:09190 if (input_queue_->AllocateBuffers(kNumInputBuffers, V4L2_MEMORY_MMAP) == 0) {
191 VLOGF(1) << "Failed to allocate input buffer.";
Ted Meyer2a41e242020-03-20 08:01:27192 std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
Chih-Yu Huangde529a82019-06-06 03:26:09193 return;
194 }
Chih-Yu Huangde529a82019-06-06 03:26:09195
196 // Call init_cb
197 output_cb_ = output_cb;
198 SetState(State::kDecoding);
Ted Meyer2a41e242020-03-20 08:01:27199 std::move(init_cb).Run(::media::OkStatus());
Chih-Yu Huangde529a82019-06-06 03:26:09200}
201
202bool V4L2SliceVideoDecoder::SetupInputFormat(uint32_t input_format_fourcc) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36203 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09204 DCHECK_EQ(state_, State::kUninitialized);
205
206 // Check if the format is supported.
207 std::vector<uint32_t> formats = device_->EnumerateSupportedPixelformats(
208 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
209 if (std::find(formats.begin(), formats.end(), input_format_fourcc) ==
210 formats.end()) {
211 DVLOGF(3) << "Input fourcc " << input_format_fourcc
212 << " not supported by device.";
213 return false;
214 }
215
216 // Determine the input buffer size.
217 gfx::Size max_size, min_size;
218 device_->GetSupportedResolution(input_format_fourcc, &min_size, &max_size);
219 size_t input_size = max_size.GetArea() > k1080pArea
220 ? kInputBufferMaxSizeFor4k
221 : kInputBufferMaxSizeFor1080p;
222
223 // Setup the input format.
Yuki Shiino86b64ff2019-10-07 05:37:35224 auto format =
225 input_queue_->SetFormat(input_format_fourcc, gfx::Size(), input_size);
226 if (!format) {
Chih-Yu Huangde529a82019-06-06 03:26:09227 VPLOGF(1) << "Failed to call IOCTL to set input format.";
228 return false;
229 }
Yuki Shiino86b64ff2019-10-07 05:37:35230 DCHECK_EQ(format->fmt.pix_mp.pixelformat, input_format_fourcc);
Chih-Yu Huangde529a82019-06-06 03:26:09231
232 return true;
233}
234
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26235bool V4L2SliceVideoDecoder::SetupOutputFormat(const gfx::Size& size,
236 const gfx::Rect& visible_rect) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36237 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26238 DVLOGF(3) << "size: " << size.ToString()
239 << ", visible_rect: " << visible_rect.ToString();
Chih-Yu Huangde529a82019-06-06 03:26:09240
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26241 // Get the supported output formats and their corresponding negotiated sizes.
242 std::vector<std::pair<Fourcc, gfx::Size>> candidates;
243 for (const uint32_t& pixfmt : device_->EnumerateSupportedPixelformats(
244 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
Alexandre Courbot139ebe22019-12-12 01:46:39245 const auto candidate = Fourcc::FromV4L2PixFmt(pixfmt);
246 if (!candidate) {
247 DVLOGF(1) << "Pixel format " << FourccToString(pixfmt)
248 << " is not supported, skipping...";
249 continue;
250 }
251
Hirokazu Honda685bf012019-08-05 01:30:00252 base::Optional<struct v4l2_format> format =
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26253 output_queue_->SetFormat(pixfmt, size, 0);
Alexandre Courbot139ebe22019-12-12 01:46:39254 if (!format)
255 continue;
256
257 gfx::Size adjusted_size(format->fmt.pix_mp.width,
258 format->fmt.pix_mp.height);
259 candidates.push_back(std::make_pair(*candidate, adjusted_size));
Chih-Yu Huangde529a82019-06-06 03:26:09260 }
261
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26262 // Ask the pipeline to pick the output format.
Alexandre Courbot139ebe22019-12-12 01:46:39263 const base::Optional<Fourcc> fourcc =
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26264 client_->PickDecoderOutputFormat(candidates, visible_rect);
265 if (!fourcc) {
266 VLOGF(1) << "Failed to pick a output format.";
267 return false;
268 }
Chih-Yu Huangde529a82019-06-06 03:26:09269
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26270 // We successfully picked the output format. Now setup output format again.
271 base::Optional<struct v4l2_format> format =
Alexandre Courbot139ebe22019-12-12 01:46:39272 output_queue_->SetFormat(fourcc->ToV4L2PixFmt(), size, 0);
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26273 DCHECK(format);
274 gfx::Size adjusted_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
275 DCHECK_EQ(adjusted_size.width() % 16, 0);
276 DCHECK_EQ(adjusted_size.height() % 16, 0);
277 if (!gfx::Rect(adjusted_size).Contains(gfx::Rect(size))) {
278 VLOGF(1) << "The adjusted coded size (" << adjusted_size.ToString()
279 << ") should contains the original coded size(" << size.ToString()
280 << ").";
281 return false;
282 }
283
284 // Got the adjusted size from the V4L2 driver. Now setup the frame pool.
285 // TODO(akahuang): It is possible there is an allocatable formats among
286 // candidates, but PickDecoderOutputFormat() selects other non-allocatable
287 // format. The correct flow is to attach an info to candidates if it is
288 // created by VideoFramePool.
289 DmabufVideoFramePool* pool = client_->GetVideoFramePool();
290 if (pool) {
Miguel Casas6ee396b2020-01-17 21:21:16291 base::Optional<GpuBufferLayout> layout = pool->Initialize(
Alexandre Courbot139ebe22019-12-12 01:46:39292 *fourcc, adjusted_size, visible_rect,
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26293 GetNaturalSize(visible_rect, pixel_aspect_ratio_), num_output_frames_);
294 if (!layout) {
295 VLOGF(1) << "Failed to setup format to VFPool";
296 return false;
297 }
298 if (layout->size() != adjusted_size) {
299 VLOGF(1) << "The size adjusted by VFPool is different from one "
Alexandre Courbot139ebe22019-12-12 01:46:39300 << "adjusted by a video driver. fourcc: " << fourcc->ToString()
301 << ", (video driver v.s. VFPool) " << adjusted_size.ToString()
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26302 << " != " << layout->size().ToString();
303 return false;
304 }
305 }
306
307 return true;
Chih-Yu Huangf4635892019-07-11 14:20:29308}
309
Chih-Yu Huangde529a82019-06-06 03:26:09310void V4L2SliceVideoDecoder::Reset(base::OnceClosure closure) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36311 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09312 DVLOGF(3);
313
Chih-Yu Huang1141fdeb2019-12-10 06:16:13314 // Reset callback for resolution change, because the pipeline won't notify
315 // flushed after reset.
316 continue_change_resolution_cb_.Reset();
317
Chih-Yu Huangde529a82019-06-06 03:26:09318 // Call all pending decode callback.
Alexandre Courbot78b1e642019-10-16 03:45:39319 backend_->ClearPendingRequests(DecodeStatus::ABORTED);
Chih-Yu Huangde529a82019-06-06 03:26:09320
321 // Streamoff V4L2 queues to drop input and output buffers.
322 // If the queues are streaming before reset, then we need to start streaming
323 // them after stopping.
Alexandre Courbotba021e32019-09-26 07:24:35324 bool is_streaming = input_queue_->IsStreaming();
Chih-Yu Huangde529a82019-06-06 03:26:09325 if (!StopStreamV4L2Queue())
326 return;
327
Alexandre Courbotba021e32019-09-26 07:24:35328 if (is_streaming) {
Chih-Yu Huangde529a82019-06-06 03:26:09329 if (!StartStreamV4L2Queue())
330 return;
331 }
332
Chih-Yu Huang1141fdeb2019-12-10 06:16:13333 // If during flushing, Reset() will abort the following flush tasks.
334 // Now we are ready to decode new buffer. Go back to decoding state.
335 SetState(State::kDecoding);
336
Chih-Yu Huanga35c28a2019-10-21 02:43:09337 std::move(closure).Run();
Chih-Yu Huangde529a82019-06-06 03:26:09338}
339
Chih-Yu Huangde529a82019-06-06 03:26:09340void V4L2SliceVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
341 DecodeCB decode_cb) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36342 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huang30b5fca2019-09-24 09:03:34343 DCHECK_NE(state_, State::kUninitialized);
344
345 if (state_ == State::kError) {
Alexandre Courbot51ad52a82019-10-07 04:36:36346 std::move(decode_cb).Run(DecodeStatus::DECODE_ERROR);
Chih-Yu Huang30b5fca2019-09-24 09:03:34347 return;
348 }
Chih-Yu Huangde529a82019-06-06 03:26:09349
Alexandre Courbot51ad52a82019-10-07 04:36:36350 const int32_t bitstream_id = bitstream_id_generator_.GetNextBitstreamId();
Alexandre Courbot78b1e642019-10-16 03:45:39351 backend_->EnqueueDecodeTask(std::move(buffer), std::move(decode_cb),
352 bitstream_id);
Chih-Yu Huangde529a82019-06-06 03:26:09353}
354
355bool V4L2SliceVideoDecoder::StartStreamV4L2Queue() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36356 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09357 DVLOGF(3);
358
Chih-Yu Huangde529a82019-06-06 03:26:09359 if (!input_queue_->Streamon() || !output_queue_->Streamon()) {
360 VLOGF(1) << "Failed to streamon V4L2 queue.";
361 SetState(State::kError);
362 return false;
363 }
364
Alexandre Courbotba021e32019-09-26 07:24:35365 if (!device_->StartPolling(
366 base::BindRepeating(&V4L2SliceVideoDecoder::ServiceDeviceTask,
367 weak_this_),
368 base::BindRepeating(&V4L2SliceVideoDecoder::SetState, weak_this_,
369 State::kError))) {
370 SetState(State::kError);
371 return false;
372 }
373
Chih-Yu Huangde529a82019-06-06 03:26:09374 return true;
375}
376
377bool V4L2SliceVideoDecoder::StopStreamV4L2Queue() {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36378 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09379 DVLOGF(3);
380
Alexandre Courbotba021e32019-09-26 07:24:35381 if (!device_->StopPolling()) {
Chih-Yu Huangde529a82019-06-06 03:26:09382 SetState(State::kError);
383 return false;
384 }
385
Chih-Yu Huang1c5d4212019-08-01 07:04:47386 // Streamoff input and output queue.
387 if (input_queue_)
Chih-Yu Huangde529a82019-06-06 03:26:09388 input_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:47389 if (output_queue_)
Chih-Yu Huangde529a82019-06-06 03:26:09390 output_queue_->Streamoff();
Chih-Yu Huang1c5d4212019-08-01 07:04:47391
Alexandre Courbot78b1e642019-10-16 03:45:39392 if (backend_)
393 backend_->OnStreamStopped();
394
395 return true;
396}
397
398void V4L2SliceVideoDecoder::InitiateFlush() {
399 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
400 DVLOGF(3);
401
402 SetState(State::kFlushing);
403}
404
405void V4L2SliceVideoDecoder::CompleteFlush() {
406 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
407 DVLOGF(3);
408
409 SetState(State::kDecoding);
410}
411
Chih-Yu Huang63b0a1d2019-11-19 09:31:45412void V4L2SliceVideoDecoder::ChangeResolution(gfx::Size pic_size,
Alexandre Courbot78b1e642019-10-16 03:45:39413 gfx::Rect visible_rect,
414 size_t num_output_frames) {
415 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
416 DVLOGF(3);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45417 DCHECK(!continue_change_resolution_cb_);
418
419 // After the pipeline flushes all frames, we can start changing resolution.
420 continue_change_resolution_cb_ =
421 base::BindOnce(&V4L2SliceVideoDecoder::ContinueChangeResolution,
422 weak_this_, pic_size, visible_rect, num_output_frames);
423
424 DCHECK(client_);
425 client_->PrepareChangeResolution();
426}
427
Alexandre Courbot54dca902020-04-14 16:45:37428void V4L2SliceVideoDecoder::ApplyResolutionChange() {
Chih-Yu Huang63b0a1d2019-11-19 09:31:45429 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
430 DVLOGF(3);
431 DCHECK(continue_change_resolution_cb_);
432
Alexandre Courbotcddb357f2020-04-15 03:51:02433 std::move(continue_change_resolution_cb_).Run();
Chih-Yu Huang63b0a1d2019-11-19 09:31:45434}
435
436void V4L2SliceVideoDecoder::ContinueChangeResolution(
437 const gfx::Size& pic_size,
438 const gfx::Rect& visible_rect,
439 const size_t num_output_frames) {
440 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
441 DVLOGF(3);
Alexandre Courbot78b1e642019-10-16 03:45:39442 DCHECK_EQ(input_queue_->QueuedBuffersCount(), 0u);
443 DCHECK_EQ(output_queue_->QueuedBuffersCount(), 0u);
444
Chih-Yu Huang1141fdeb2019-12-10 06:16:13445 // If we already reset, then skip it.
446 if (state_ == State::kDecoding)
447 return;
448 DCHECK_EQ(state_, State::kFlushing);
449
Chih-Yu Huang63b0a1d2019-11-19 09:31:45450 // Notify |backend_| that changing resolution fails.
451 // Note: |backend_| is owned by this, using base::Unretained() is safe.
452 base::ScopedClosureRunner done_caller(
453 base::BindOnce(&V4L2VideoDecoderBackend::OnChangeResolutionDone,
454 base::Unretained(backend_.get()), false));
455
Chih-Yu Huangbab32ff2019-11-01 08:49:21456 num_output_frames_ = num_output_frames;
457
Alexandre Courbot78b1e642019-10-16 03:45:39458 if (!StopStreamV4L2Queue())
Chih-Yu Huang63b0a1d2019-11-19 09:31:45459 return;
Alexandre Courbot78b1e642019-10-16 03:45:39460
Francois Buergisser30e651a2019-10-18 16:22:45461 if (!output_queue_->DeallocateBuffers()) {
462 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45463 return;
Francois Buergisser30e651a2019-10-18 16:22:45464 }
465 DCHECK_GT(num_output_frames, 0u);
466
Alexandre Courbotf5936fe2020-04-02 07:24:12467 if (!backend_->ApplyResolution(pic_size, visible_rect, num_output_frames)) {
468 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45469 return;
Alexandre Courbot78b1e642019-10-16 03:45:39470 }
471
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26472 if (!SetupOutputFormat(pic_size, visible_rect)) {
473 VLOGF(1) << "Failed to setup output format.";
Alexandre Courbot78b1e642019-10-16 03:45:39474 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45475 return;
Alexandre Courbot78b1e642019-10-16 03:45:39476 }
477
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26478 v4l2_memory type =
479 client_->GetVideoFramePool() ? V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP;
480 if (output_queue_->AllocateBuffers(num_output_frames_, type) == 0) {
Alexandre Courbot78b1e642019-10-16 03:45:39481 VLOGF(1) << "Failed to request output buffers.";
482 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45483 return;
Alexandre Courbot78b1e642019-10-16 03:45:39484 }
Chih-Yu Huangbab32ff2019-11-01 08:49:21485 if (output_queue_->AllocatedBuffersCount() != num_output_frames_) {
Alexandre Courbot78b1e642019-10-16 03:45:39486 VLOGF(1) << "Could not allocate requested number of output buffers.";
487 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45488 return;
Alexandre Courbot78b1e642019-10-16 03:45:39489 }
Alexandre Courbot78b1e642019-10-16 03:45:39490
491 if (!StartStreamV4L2Queue()) {
492 SetState(State::kError);
Chih-Yu Huang63b0a1d2019-11-19 09:31:45493 return;
Alexandre Courbot78b1e642019-10-16 03:45:39494 }
Chih-Yu Huangde529a82019-06-06 03:26:09495
Chih-Yu Huang63b0a1d2019-11-19 09:31:45496 // Now notify |backend_| that changing resolution is done successfully.
497 // Note: |backend_| is owned by this, using base::Unretained() is safe.
498 done_caller.ReplaceClosure(
499 base::BindOnce(&V4L2VideoDecoderBackend::OnChangeResolutionDone,
500 base::Unretained(backend_.get()), true));
Chih-Yu Huangde529a82019-06-06 03:26:09501}
502
Alexandre Courbotba021e32019-09-26 07:24:35503void V4L2SliceVideoDecoder::ServiceDeviceTask(bool /* event */) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36504 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09505 DVLOGF(3) << "Number of queued input buffers: "
506 << input_queue_->QueuedBuffersCount()
507 << ", Number of queued output buffers: "
508 << output_queue_->QueuedBuffersCount();
509
510 // Dequeue V4L2 output buffer first to reduce output latency.
511 bool success;
512 V4L2ReadableBufferRef dequeued_buffer;
513 while (output_queue_->QueuedBuffersCount() > 0) {
514 std::tie(success, dequeued_buffer) = output_queue_->DequeueBuffer();
515 if (!success) {
516 SetState(State::kError);
517 return;
518 }
519 if (!dequeued_buffer)
520 break;
521
Alexandre Courbot78b1e642019-10-16 03:45:39522 backend_->OnOutputBufferDequeued(std::move(dequeued_buffer));
Chih-Yu Huangde529a82019-06-06 03:26:09523 }
524
525 // Dequeue V4L2 input buffer.
526 while (input_queue_->QueuedBuffersCount() > 0) {
527 std::tie(success, dequeued_buffer) = input_queue_->DequeueBuffer();
528 if (!success) {
529 SetState(State::kError);
530 return;
531 }
532 if (!dequeued_buffer)
533 break;
534 }
Chih-Yu Huangde529a82019-06-06 03:26:09535}
536
Alexandre Courbot78b1e642019-10-16 03:45:39537void V4L2SliceVideoDecoder::OutputFrame(scoped_refptr<VideoFrame> frame,
Chih-Yu Huangf4635892019-07-11 14:20:29538 const gfx::Rect& visible_rect,
Chih-Yu Huangccf46032019-07-11 11:48:06539 base::TimeDelta timestamp) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36540 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangccf46032019-07-11 11:48:06541 DVLOGF(4) << "timestamp: " << timestamp;
Chih-Yu Huangde529a82019-06-06 03:26:09542
Chih-Yu Huange497fcc2019-09-25 02:33:11543 // Set the timestamp at which the decode operation started on the
544 // |frame|. If the frame has been outputted before (e.g. because of VP9
545 // show-existing-frame feature) we can't overwrite the timestamp directly, as
546 // the original frame might still be in use. Instead we wrap the frame in
547 // another frame with a different timestamp.
Chih-Yu Huangeacec322019-09-24 05:51:34548 if (frame->timestamp().is_zero())
549 frame->set_timestamp(timestamp);
550
Chih-Yu Huangf4635892019-07-11 14:20:29551 if (frame->visible_rect() != visible_rect ||
552 frame->timestamp() != timestamp) {
553 gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_);
Chih-Yu Huangccf46032019-07-11 11:48:06554 scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
Ricky Liangb2075eb2019-10-01 07:44:50555 frame, frame->format(), visible_rect, natural_size);
Chih-Yu Huangccf46032019-07-11 11:48:06556 wrapped_frame->set_timestamp(timestamp);
Chih-Yu Huangccf46032019-07-11 11:48:06557
558 frame = std::move(wrapped_frame);
559 }
Chih-Yu Huang63b0a1d2019-11-19 09:31:45560
Chih-Yu Huanga35c28a2019-10-21 02:43:09561 output_cb_.Run(std::move(frame));
Chih-Yu Huangde529a82019-06-06 03:26:09562}
563
Shuo-Peng Liaoe6bf70c2019-12-05 01:44:26564DmabufVideoFramePool* V4L2SliceVideoDecoder::GetVideoFramePool() const {
565 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
566 DVLOGF(4);
567
568 return client_->GetVideoFramePool();
569}
570
Chih-Yu Huangde529a82019-06-06 03:26:09571void V4L2SliceVideoDecoder::SetState(State new_state) {
Alexandre Courbotdcb6ebb2019-06-25 04:25:36572 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
Chih-Yu Huangde529a82019-06-06 03:26:09573 DVLOGF(3) << "Change state from " << static_cast<int>(state_) << " to "
574 << static_cast<int>(new_state);
575
576 if (state_ == new_state)
577 return;
578 if (state_ == State::kError) {
579 DVLOGF(3) << "Already in kError state.";
580 return;
581 }
582
583 // Check if the state transition is valid.
584 switch (new_state) {
585 case State::kUninitialized:
586 if (state_ != State::kDecoding) {
587 VLOGF(1) << "Should not set to kUninitialized.";
588 new_state = State::kError;
589 }
590 break;
591
592 case State::kDecoding:
593 break;
594
Chih-Yu Huang40adcdf2019-07-11 03:37:02595 case State::kFlushing:
Chih-Yu Huangde529a82019-06-06 03:26:09596 if (state_ != State::kDecoding) {
Chih-Yu Huang40adcdf2019-07-11 03:37:02597 VLOGF(1) << "kFlushing should only be set when kDecoding.";
Chih-Yu Huangde529a82019-06-06 03:26:09598 new_state = State::kError;
599 }
600 break;
601
602 case State::kError:
603 break;
604 }
605
606 if (new_state == State::kError) {
607 VLOGF(1) << "Error occurred.";
Alexandre Courbot78b1e642019-10-16 03:45:39608 if (backend_)
609 backend_->ClearPendingRequests(DecodeStatus::DECODE_ERROR);
Chih-Yu Huangde529a82019-06-06 03:26:09610 return;
611 }
612 state_ = new_state;
613 return;
614}
615
Alexandre Courbot78b1e642019-10-16 03:45:39616void V4L2SliceVideoDecoder::OnBackendError() {
617 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
618 DVLOGF(2);
619
620 SetState(State::kError);
621}
622
623bool V4L2SliceVideoDecoder::IsDecoding() const {
624 DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
625 DVLOGF(3);
626
627 return state_ == State::kDecoding;
628}
629
Chih-Yu Huangde529a82019-06-06 03:26:09630} // namespace media