1 // Copyright 2015 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.
5 #include <linux/videodev2.h>
8 #include "base/big_endian.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "content/common/gpu/media/v4l2_jpeg_decode_accelerator.h"
12 #include "media/filters/jpeg_parser.h"
13 #include "third_party/libyuv/include/libyuv.h"
15 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_name) \
17 if (device_->Ioctl(type, arg) != 0) { \
18 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_name; \
19 PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); \
24 #define IOCTL_OR_ERROR_RETURN(type, arg) \
25 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type)
27 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
28 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type)
30 #define IOCTL_OR_LOG_ERROR(type, arg) \
32 if (device_->Ioctl(type, arg) != 0) { \
33 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
34 PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); \
38 #define READ_U8_OR_RETURN_FALSE(reader, out) \
41 if (!reader.ReadU8(&_out)) { \
43 << "Error in stream: unexpected EOS while trying to read " #out; \
49 #define READ_U16_OR_RETURN_FALSE(reader, out) \
52 if (!reader.ReadU16(&_out)) { \
54 << "Error in stream: unexpected EOS while trying to read " #out; \
62 // This is default huffman segment for 8-bit precision luminance and
63 // chrominance. The default huffman segment is constructed with the tables from
64 // JPEG standard section K.3. Actually there are no default tables. They are
65 // typical tables. These tables are useful for many applications. Lots of
66 // softwares use them as standard tables such as ffmpeg.
67 const uint8_t kDefaultDhtSeg
[] = {
68 0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
69 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
70 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x01, 0x00, 0x03,
71 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
72 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
73 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05,
74 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04,
75 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22,
76 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15,
77 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17,
78 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36,
79 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
80 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
81 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
82 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95,
83 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
84 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2,
85 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5,
86 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
87 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
88 0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
89 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
90 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
91 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33,
92 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25,
93 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36,
94 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
95 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
96 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
97 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
98 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
99 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA,
100 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
101 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
102 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
105 V4L2JpegDecodeAccelerator::BufferRecord::BufferRecord()
106 : address(nullptr), length(0), at_device(false) {
109 V4L2JpegDecodeAccelerator::BufferRecord::~BufferRecord() {
112 V4L2JpegDecodeAccelerator::JobRecord::JobRecord(
113 media::BitstreamBuffer bitstream_buffer
,
114 scoped_refptr
<media::VideoFrame
> video_frame
)
115 : bitstream_buffer(bitstream_buffer
), out_frame(video_frame
) {
118 V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() {
121 V4L2JpegDecodeAccelerator::V4L2JpegDecodeAccelerator(
122 const scoped_refptr
<V4L2Device
>& device
,
123 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_task_runner
)
124 : recreate_input_buffers_pending_(false),
125 recreate_output_buffers_pending_(false),
126 child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
127 io_task_runner_(io_task_runner
),
130 decoder_thread_("V4L2JpegDecodeThread"),
131 device_poll_thread_("V4L2JpegDecodeDevicePollThread"),
132 input_streamon_(false),
133 output_streamon_(false),
134 weak_factory_(this) {
135 weak_ptr_
= weak_factory_
.GetWeakPtr();
138 V4L2JpegDecodeAccelerator::~V4L2JpegDecodeAccelerator() {
139 DCHECK(child_task_runner_
->BelongsToCurrentThread());
141 if (decoder_thread_
.IsRunning()) {
142 decoder_task_runner_
->PostTask(
143 FROM_HERE
, base::Bind(&V4L2JpegDecodeAccelerator::DestroyTask
,
144 base::Unretained(this)));
145 decoder_thread_
.Stop();
147 weak_factory_
.InvalidateWeakPtrs();
148 DCHECK(!device_poll_thread_
.IsRunning());
151 void V4L2JpegDecodeAccelerator::DestroyTask() {
152 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
153 while (!input_jobs_
.empty())
155 while (!running_jobs_
.empty())
158 // Stop streaming and the device_poll_thread_.
162 DestroyInputBuffers();
163 DestroyOutputBuffers();
166 void V4L2JpegDecodeAccelerator::VideoFrameReady(int32_t bitstream_buffer_id
) {
167 DCHECK(child_task_runner_
->BelongsToCurrentThread());
168 client_
->VideoFrameReady(bitstream_buffer_id
);
171 void V4L2JpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id
,
173 DCHECK(child_task_runner_
->BelongsToCurrentThread());
174 LOG(ERROR
) << "Notifying of error " << error
<< " for buffer id "
175 << bitstream_buffer_id
;
176 client_
->NotifyError(bitstream_buffer_id
, error
);
179 void V4L2JpegDecodeAccelerator::PostNotifyError(
180 int32_t bitstream_buffer_id
,
182 child_task_runner_
->PostTask(
184 base::Bind(&V4L2JpegDecodeAccelerator::NotifyError
, weak_ptr_
,
185 bitstream_buffer_id
, error
));
188 bool V4L2JpegDecodeAccelerator::Initialize(Client
* client
) {
189 DCHECK(child_task_runner_
->BelongsToCurrentThread());
191 // Capabilities check.
192 struct v4l2_capability caps
;
193 const __u32 kCapsRequired
= V4L2_CAP_STREAMING
| V4L2_CAP_VIDEO_M2M
;
194 memset(&caps
, 0, sizeof(caps
));
195 if (device_
->Ioctl(VIDIOC_QUERYCAP
, &caps
) != 0) {
196 PLOG(ERROR
) << __func__
<< "(): ioctl() failed: VIDIOC_QUERYCAP";
199 if ((caps
.capabilities
& kCapsRequired
) != kCapsRequired
) {
200 LOG(ERROR
) << "Initialize(): VIDIOC_QUERYCAP, caps check failed: 0x"
201 << std::hex
<< caps
.capabilities
;
205 if (!decoder_thread_
.Start()) {
206 LOG(ERROR
) << "Initialize(): decoder thread failed to start";
210 decoder_task_runner_
= decoder_thread_
.task_runner();
212 decoder_task_runner_
->PostTask(
213 FROM_HERE
, base::Bind(&V4L2JpegDecodeAccelerator::StartDevicePoll
,
214 base::Unretained(this)));
216 DVLOG(1) << "V4L2JpegDecodeAccelerator initialized.";
220 void V4L2JpegDecodeAccelerator::Decode(
221 const media::BitstreamBuffer
& bitstream_buffer
,
222 const scoped_refptr
<media::VideoFrame
>& video_frame
) {
223 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer
.id()
224 << ", size=" << bitstream_buffer
.size();
225 DCHECK(io_task_runner_
->BelongsToCurrentThread());
227 if (video_frame
->format() != media::PIXEL_FORMAT_I420
) {
228 PostNotifyError(bitstream_buffer
.id(), UNSUPPORTED_JPEG
);
232 scoped_ptr
<JobRecord
> job_record(
233 new JobRecord(bitstream_buffer
, video_frame
));
235 decoder_task_runner_
->PostTask(
236 FROM_HERE
, base::Bind(&V4L2JpegDecodeAccelerator::DecodeTask
,
237 base::Unretained(this), base::Passed(&job_record
)));
240 bool V4L2JpegDecodeAccelerator::IsSupported() {
241 v4l2_fmtdesc fmtdesc
;
242 memset(&fmtdesc
, 0, sizeof(fmtdesc
));
243 fmtdesc
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
245 for (; device_
->Ioctl(VIDIOC_ENUM_FMT
, &fmtdesc
) == 0; ++fmtdesc
.index
) {
246 if (fmtdesc
.pixelformat
== V4L2_PIX_FMT_JPEG
)
252 void V4L2JpegDecodeAccelerator::DecodeTask(scoped_ptr
<JobRecord
> job_record
) {
253 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
254 job_record
->shm
.reset(
255 new base::SharedMemory(job_record
->bitstream_buffer
.handle(), true));
256 if (!job_record
->shm
->Map(job_record
->bitstream_buffer
.size())) {
257 PLOG(ERROR
) << "DecodeTask(): could not map bitstream_buffer";
258 PostNotifyError(job_record
->bitstream_buffer
.id(), UNREADABLE_INPUT
);
261 input_jobs_
.push(make_linked_ptr(job_record
.release()));
266 size_t V4L2JpegDecodeAccelerator::InputBufferQueuedCount() {
267 return input_buffer_map_
.size() - free_input_buffers_
.size();
270 size_t V4L2JpegDecodeAccelerator::OutputBufferQueuedCount() {
271 return output_buffer_map_
.size() - free_output_buffers_
.size();
274 bool V4L2JpegDecodeAccelerator::ShouldRecreateInputBuffers() {
275 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
276 if (input_jobs_
.empty())
279 linked_ptr
<JobRecord
> job_record
= input_jobs_
.front();
280 // Check input buffer size is enough
281 return (input_buffer_map_
.empty() ||
282 (job_record
->bitstream_buffer
.size() + sizeof(kDefaultDhtSeg
)) >
283 input_buffer_map_
.front().length
);
286 bool V4L2JpegDecodeAccelerator::ShouldRecreateOutputBuffers() {
287 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
288 if (input_jobs_
.empty())
291 linked_ptr
<JobRecord
> job_record
= input_jobs_
.front();
292 // Check image resolution is the same as previous.
293 if (job_record
->out_frame
->coded_size() != image_coded_size_
) {
294 size_t frame_size
= media::VideoFrame::AllocationSize(
295 job_record
->out_frame
->format(), job_record
->out_frame
->coded_size());
296 if (output_buffer_map_
.empty() ||
297 frame_size
> output_buffer_map_
.front().length
) {
304 bool V4L2JpegDecodeAccelerator::CreateBuffersIfNecessary() {
305 DVLOG(3) << __func__
;
306 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
308 recreate_input_buffers_pending_
= ShouldRecreateInputBuffers();
309 recreate_output_buffers_pending_
= ShouldRecreateOutputBuffers();
310 if (!recreate_input_buffers_pending_
&& !recreate_output_buffers_pending_
)
313 // If running queue is not empty, we should wait until pending frames finish.
314 if (!running_jobs_
.empty())
317 if (input_streamon_
|| output_streamon_
)
320 if (recreate_input_buffers_pending_
)
321 DestroyInputBuffers();
322 if (recreate_output_buffers_pending_
)
323 DestroyOutputBuffers();
325 if (recreate_input_buffers_pending_
&& !CreateInputBuffers()) {
326 LOG(ERROR
) << "Create input buffers failed.";
329 if (recreate_output_buffers_pending_
&& !CreateOutputBuffers()) {
330 LOG(ERROR
) << "Create output buffers failed.";
337 bool V4L2JpegDecodeAccelerator::CreateInputBuffers() {
338 DVLOG(3) << __func__
;
339 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
340 DCHECK(!input_streamon_
);
341 DCHECK(!input_jobs_
.empty());
342 linked_ptr
<JobRecord
> job_record
= input_jobs_
.front();
343 // The input image may miss huffman table. We didn't parse the image before,
344 // so we create more to avoid the situation of not enough memory.
345 // Reserve twice size to avoid recreating input buffer frequently.
346 size_t reserve_size
=
347 (job_record
->bitstream_buffer
.size() + sizeof(kDefaultDhtSeg
)) * 2;
348 struct v4l2_format format
;
349 memset(&format
, 0, sizeof(format
));
350 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
351 format
.fmt
.pix
.width
= job_record
->out_frame
->coded_size().width();
352 format
.fmt
.pix
.height
= job_record
->out_frame
->coded_size().height();
353 format
.fmt
.pix
.pixelformat
= V4L2_PIX_FMT_JPEG
;
354 format
.fmt
.pix
.sizeimage
= reserve_size
;
355 format
.fmt
.pix
.field
= V4L2_FIELD_ANY
;
356 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT
, &format
);
358 struct v4l2_requestbuffers reqbufs
;
359 memset(&reqbufs
, 0, sizeof(reqbufs
));
360 reqbufs
.count
= kBufferCount
;
361 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
362 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
363 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS
, &reqbufs
);
365 DCHECK(input_buffer_map_
.empty());
366 input_buffer_map_
.resize(reqbufs
.count
);
368 for (size_t i
= 0; i
< input_buffer_map_
.size(); ++i
) {
369 free_input_buffers_
.push_back(i
);
371 struct v4l2_buffer buffer
;
372 memset(&buffer
, 0, sizeof(buffer
));
374 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
375 buffer
.memory
= V4L2_MEMORY_MMAP
;
376 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF
, &buffer
);
377 void* address
= device_
->Mmap(NULL
, buffer
.length
, PROT_READ
| PROT_WRITE
,
378 MAP_SHARED
, buffer
.m
.offset
);
379 if (address
== MAP_FAILED
) {
380 PLOG(ERROR
) << "CreateInputBuffers(): mmap() failed";
381 PostNotifyError(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
384 input_buffer_map_
[i
].address
= address
;
385 input_buffer_map_
[i
].length
= buffer
.length
;
387 recreate_input_buffers_pending_
= false;
392 bool V4L2JpegDecodeAccelerator::CreateOutputBuffers() {
393 DVLOG(3) << __func__
;
394 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
395 DCHECK(!output_streamon_
);
396 DCHECK(!input_jobs_
.empty());
397 linked_ptr
<JobRecord
> job_record
= input_jobs_
.front();
399 size_t frame_size
= media::VideoFrame::AllocationSize(
400 media::PIXEL_FORMAT_I420
, job_record
->out_frame
->coded_size());
401 struct v4l2_format format
;
402 memset(&format
, 0, sizeof(format
));
403 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
404 format
.fmt
.pix
.width
= job_record
->out_frame
->coded_size().width();
405 format
.fmt
.pix
.height
= job_record
->out_frame
->coded_size().height();
406 format
.fmt
.pix
.sizeimage
= frame_size
;
407 format
.fmt
.pix
.pixelformat
= V4L2_PIX_FMT_YUV420
;
408 format
.fmt
.pix
.field
= V4L2_FIELD_ANY
;
409 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT
, &format
);
411 struct v4l2_requestbuffers reqbufs
;
412 memset(&reqbufs
, 0, sizeof(reqbufs
));
413 reqbufs
.count
= kBufferCount
;
414 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
415 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
416 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS
, &reqbufs
);
418 DCHECK(output_buffer_map_
.empty());
419 output_buffer_map_
.resize(reqbufs
.count
);
421 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
422 free_output_buffers_
.push_back(i
);
424 struct v4l2_buffer buffer
;
425 memset(&buffer
, 0, sizeof(buffer
));
427 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
428 buffer
.memory
= V4L2_MEMORY_MMAP
;
429 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF
, &buffer
);
431 DCHECK_GE(buffer
.length
,
432 media::VideoFrame::AllocationSize(
433 media::PIXEL_FORMAT_I420
,
434 gfx::Size(format
.fmt
.pix
.width
, format
.fmt
.pix
.height
)));
436 void* address
= device_
->Mmap(NULL
, buffer
.length
, PROT_READ
| PROT_WRITE
,
437 MAP_SHARED
, buffer
.m
.offset
);
438 if (address
== MAP_FAILED
) {
439 PLOG(ERROR
) << "CreateOutputBuffers(): mmap() failed";
440 PostNotifyError(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
443 output_buffer_map_
[i
].address
= address
;
444 output_buffer_map_
[i
].length
= buffer
.length
;
446 image_coded_size_
= job_record
->out_frame
->coded_size();
447 recreate_output_buffers_pending_
= false;
452 void V4L2JpegDecodeAccelerator::DestroyInputBuffers() {
453 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
454 DCHECK(!input_streamon_
);
456 for (size_t buf
= 0; buf
< input_buffer_map_
.size(); ++buf
) {
457 BufferRecord
& input_record
= input_buffer_map_
[buf
];
458 device_
->Munmap(input_record
.address
, input_record
.length
);
461 struct v4l2_requestbuffers reqbufs
;
462 memset(&reqbufs
, 0, sizeof(reqbufs
));
464 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
465 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
466 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS
, &reqbufs
);
468 input_buffer_map_
.clear();
469 free_input_buffers_
.clear();
472 void V4L2JpegDecodeAccelerator::DestroyOutputBuffers() {
473 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
474 DCHECK(!output_streamon_
);
476 for (size_t buf
= 0; buf
< output_buffer_map_
.size(); ++buf
) {
477 BufferRecord
& output_record
= output_buffer_map_
[buf
];
478 device_
->Munmap(output_record
.address
, output_record
.length
);
481 struct v4l2_requestbuffers reqbufs
;
482 memset(&reqbufs
, 0, sizeof(reqbufs
));
484 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
485 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
486 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS
, &reqbufs
);
488 output_buffer_map_
.clear();
489 free_output_buffers_
.clear();
492 void V4L2JpegDecodeAccelerator::DevicePollTask() {
493 DCHECK(device_poll_task_runner_
->BelongsToCurrentThread());
496 if (!device_
->Poll(true, &event_pending
)) {
497 PLOG(ERROR
) << "DevicePollTask(): Poll device error.";
498 PostNotifyError(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
502 // All processing should happen on ServiceDeviceTask(), since we shouldn't
503 // touch decoder state from this thread.
504 decoder_task_runner_
->PostTask(
505 FROM_HERE
, base::Bind(&V4L2JpegDecodeAccelerator::ServiceDeviceTask
,
506 base::Unretained(this)));
509 void V4L2JpegDecodeAccelerator::ServiceDeviceTask() {
510 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
511 // If DestroyTask() shuts |device_poll_thread_| down, we should early-out.
512 if (!device_poll_thread_
.IsRunning())
515 if (!running_jobs_
.empty())
517 if (!CreateBuffersIfNecessary())
523 if (!running_jobs_
.empty()) {
524 device_poll_task_runner_
->PostTask(
525 FROM_HERE
, base::Bind(&V4L2JpegDecodeAccelerator::DevicePollTask
,
526 base::Unretained(this)));
529 DVLOG(2) << __func__
<< ": buffer counts: INPUT["
530 << input_jobs_
.size() << "] => DEVICE["
531 << free_input_buffers_
.size() << "/"
532 << input_buffer_map_
.size() << "->"
533 << free_output_buffers_
.size() << "/"
534 << output_buffer_map_
.size() << "]";
537 void V4L2JpegDecodeAccelerator::EnqueueInput() {
538 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
539 while (!input_jobs_
.empty() && !free_input_buffers_
.empty()) {
540 // Do not enqueue input record when input/output buffers are required to
541 // re-create until all pending frames are handled by device.
542 if (recreate_input_buffers_pending_
|| recreate_output_buffers_pending_
)
544 if (!EnqueueInputRecord())
546 recreate_input_buffers_pending_
= ShouldRecreateInputBuffers();
547 recreate_output_buffers_pending_
= ShouldRecreateOutputBuffers();
549 // Check here because we cannot STREAMON before QBUF in earlier kernel.
550 if (!input_streamon_
&& InputBufferQueuedCount()) {
551 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
552 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON
, &type
);
553 input_streamon_
= true;
557 void V4L2JpegDecodeAccelerator::EnqueueOutput() {
558 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
559 // Output record can be enqueued because the output coded sizes of the frames
560 // currently in the pipeline are all the same.
561 while (running_jobs_
.size() > OutputBufferQueuedCount() &&
562 !free_output_buffers_
.empty()) {
563 if (!EnqueueOutputRecord())
566 // Check here because we cannot STREAMON before QBUF in earlier kernel.
567 if (!output_streamon_
&& OutputBufferQueuedCount()) {
568 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
569 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON
, &type
);
570 output_streamon_
= true;
574 static bool CopyOutputImage(
575 const void* src_addr
, const gfx::Size
& src_coded_size
,
576 const scoped_refptr
<media::VideoFrame
>& dst_frame
) {
577 scoped_refptr
<media::VideoFrame
> src_frame
=
578 media::VideoFrame::WrapExternalData(
579 media::PIXEL_FORMAT_I420
,
581 gfx::Rect(src_coded_size
),
583 static_cast<uint8_t*>(const_cast<void*>(src_addr
)),
584 media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420
,
588 uint8_t* src_y
= src_frame
->data(media::VideoFrame::kYPlane
);
589 uint8_t* src_u
= src_frame
->data(media::VideoFrame::kUPlane
);
590 uint8_t* src_v
= src_frame
->data(media::VideoFrame::kVPlane
);
591 size_t src_y_stride
= src_frame
->stride(media::VideoFrame::kYPlane
);
592 size_t src_u_stride
= src_frame
->stride(media::VideoFrame::kUPlane
);
593 size_t src_v_stride
= src_frame
->stride(media::VideoFrame::kVPlane
);
594 uint8_t* dst_y
= dst_frame
->data(media::VideoFrame::kYPlane
);
595 uint8_t* dst_u
= dst_frame
->data(media::VideoFrame::kUPlane
);
596 uint8_t* dst_v
= dst_frame
->data(media::VideoFrame::kVPlane
);
597 size_t dst_y_stride
= dst_frame
->stride(media::VideoFrame::kYPlane
);
598 size_t dst_u_stride
= dst_frame
->stride(media::VideoFrame::kUPlane
);
599 size_t dst_v_stride
= dst_frame
->stride(media::VideoFrame::kVPlane
);
601 if (libyuv::I420Copy(src_y
, src_y_stride
,
607 dst_frame
->coded_size().width(),
608 dst_frame
->coded_size().height())) {
609 LOG(ERROR
) << "I420Copy failed";
615 void V4L2JpegDecodeAccelerator::Dequeue() {
616 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
618 // Dequeue completed input (VIDEO_OUTPUT) buffers,
619 // and recycle to the free list.
620 struct v4l2_buffer dqbuf
;
621 while (InputBufferQueuedCount() > 0) {
622 DCHECK(input_streamon_
);
623 memset(&dqbuf
, 0, sizeof(dqbuf
));
624 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
625 dqbuf
.memory
= V4L2_MEMORY_MMAP
;
626 if (device_
->Ioctl(VIDIOC_DQBUF
, &dqbuf
) != 0) {
627 if (errno
== EAGAIN
) {
628 // EAGAIN if we're just out of buffers to dequeue.
631 PLOG(ERROR
) << "ioctl() failed: input buffer VIDIOC_DQBUF failed.";
632 PostNotifyError(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
635 BufferRecord
& input_record
= input_buffer_map_
[dqbuf
.index
];
636 DCHECK(input_record
.at_device
);
637 input_record
.at_device
= false;
638 free_input_buffers_
.push_back(dqbuf
.index
);
640 if (dqbuf
.flags
& V4L2_BUF_FLAG_ERROR
) {
641 DVLOG(1) << "Dequeue input buffer error.";
642 PostNotifyError(kInvalidBitstreamBufferId
, UNSUPPORTED_JPEG
);
647 // Dequeue completed output (VIDEO_CAPTURE) buffers, recycle to the free list.
648 // Return the finished buffer to the client via the job ready callback.
649 // If dequeued input buffer has an error, the error frame has removed from
650 // |running_jobs_|. We check the size of |running_jobs_| instead of
651 // OutputBufferQueueCount() to avoid calling DQBUF unnecessarily.
652 while (!running_jobs_
.empty()) {
653 DCHECK(OutputBufferQueuedCount() > 0);
654 DCHECK(output_streamon_
);
655 memset(&dqbuf
, 0, sizeof(dqbuf
));
656 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
657 dqbuf
.memory
= V4L2_MEMORY_MMAP
;
658 if (device_
->Ioctl(VIDIOC_DQBUF
, &dqbuf
) != 0) {
659 if (errno
== EAGAIN
) {
660 // EAGAIN if we're just out of buffers to dequeue.
663 PLOG(ERROR
) << "ioctl() failed: output buffer VIDIOC_DQBUF failed.";
664 PostNotifyError(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
667 BufferRecord
& output_record
= output_buffer_map_
[dqbuf
.index
];
668 DCHECK(output_record
.at_device
);
669 output_record
.at_device
= false;
670 free_output_buffers_
.push_back(dqbuf
.index
);
672 // Jobs are always processed in FIFO order.
673 linked_ptr
<JobRecord
> job_record
= running_jobs_
.front();
676 if (dqbuf
.flags
& V4L2_BUF_FLAG_ERROR
) {
677 DVLOG(1) << "Dequeue output buffer error.";
678 PostNotifyError(kInvalidBitstreamBufferId
, UNSUPPORTED_JPEG
);
680 struct v4l2_format format
;
681 memset(&format
, 0, sizeof(format
));
682 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
683 IOCTL_OR_ERROR_RETURN(VIDIOC_G_FMT
, &format
);
685 if (!CopyOutputImage(
686 output_record
.address
,
687 gfx::Size(format
.fmt
.pix
.width
, format
.fmt
.pix
.height
),
688 job_record
->out_frame
)) {
689 PostNotifyError(job_record
->bitstream_buffer
.id(), PLATFORM_FAILURE
);
693 DVLOG(3) << "Decoding finished, returning bitstream buffer, id="
694 << job_record
->bitstream_buffer
.id();
696 child_task_runner_
->PostTask(
698 base::Bind(&V4L2JpegDecodeAccelerator::VideoFrameReady
, weak_ptr_
,
699 job_record
->bitstream_buffer
.id()));
704 static bool AddHuffmanTable(const void* input_ptr
,
707 size_t output_size
) {
710 DCHECK_LE((input_size
+ sizeof(kDefaultDhtSeg
)), output_size
);
712 base::BigEndianReader
reader(static_cast<const char*>(input_ptr
), input_size
);
713 bool has_marker_dht
= false;
714 bool has_marker_sos
= false;
715 uint8_t marker1
, marker2
;
716 READ_U8_OR_RETURN_FALSE(reader
, &marker1
);
717 READ_U8_OR_RETURN_FALSE(reader
, &marker2
);
718 if (marker1
!= media::JPEG_MARKER_PREFIX
|| marker2
!= media::JPEG_SOI
) {
719 DLOG(ERROR
) << __func__
<< ": The input is not a Jpeg";
723 // copy SOI marker (0xFF, 0xD8)
724 memcpy(output_ptr
, input_ptr
, 2);
725 size_t current_offset
= 2;
727 while (!has_marker_sos
&& !has_marker_dht
) {
728 const char* start_addr
= reader
.ptr();
729 READ_U8_OR_RETURN_FALSE(reader
, &marker1
);
730 if (marker1
!= media::JPEG_MARKER_PREFIX
) {
731 DLOG(ERROR
) << __func__
<< ": marker1 != 0xFF";
735 READ_U8_OR_RETURN_FALSE(reader
, &marker2
);
736 } while (marker2
== media::JPEG_MARKER_PREFIX
); // skip fill bytes
739 READ_U16_OR_RETURN_FALSE(reader
, &size
);
740 // The size includes the size field itself.
741 if (size
< sizeof(size
)) {
742 DLOG(ERROR
) << __func__
<< ": Ill-formed JPEG. Segment size (" << size
743 << ") is smaller than size field (" << sizeof(size
) << ")";
746 size
-= sizeof(size
);
749 case media::JPEG_DHT
: {
750 has_marker_dht
= true;
753 case media::JPEG_SOS
: {
754 if (!has_marker_dht
) {
755 memcpy(static_cast<uint8_t*>(output_ptr
) + current_offset
,
756 kDefaultDhtSeg
, sizeof(kDefaultDhtSeg
));
757 current_offset
+= sizeof(kDefaultDhtSeg
);
759 has_marker_sos
= true;
766 if (!reader
.Skip(size
)) {
767 DLOG(ERROR
) << __func__
<< ": Ill-formed JPEG. Remaining size ("
768 << reader
.remaining()
769 << ") is smaller than header specified (" << size
<< ")";
773 size_t segment_size
= static_cast<size_t>(reader
.ptr() - start_addr
);
774 memcpy(static_cast<uint8_t*>(output_ptr
) + current_offset
, start_addr
,
776 current_offset
+= segment_size
;
778 if (reader
.remaining()) {
779 memcpy(static_cast<uint8_t*>(output_ptr
) + current_offset
, reader
.ptr(),
785 bool V4L2JpegDecodeAccelerator::EnqueueInputRecord() {
786 DCHECK(!input_jobs_
.empty());
787 DCHECK(!free_input_buffers_
.empty());
789 // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame.
790 linked_ptr
<JobRecord
> job_record
= input_jobs_
.front();
792 const int index
= free_input_buffers_
.back();
793 BufferRecord
& input_record
= input_buffer_map_
[index
];
794 DCHECK(!input_record
.at_device
);
796 // It will add default huffman segment if it's missing.
797 if (!AddHuffmanTable(job_record
->shm
->memory(),
798 job_record
->bitstream_buffer
.size(),
799 input_record
.address
, input_record
.length
)) {
800 PostNotifyError(job_record
->bitstream_buffer
.id(), PARSE_JPEG_FAILED
);
804 struct v4l2_buffer qbuf
;
805 memset(&qbuf
, 0, sizeof(qbuf
));
807 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
808 qbuf
.memory
= V4L2_MEMORY_MMAP
;
809 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF
, &qbuf
);
810 input_record
.at_device
= true;
811 running_jobs_
.push(job_record
);
812 free_input_buffers_
.pop_back();
814 DVLOG(3) << __func__
<< ": enqueued frame id="
815 << job_record
->bitstream_buffer
.id() << " to device.";
819 bool V4L2JpegDecodeAccelerator::EnqueueOutputRecord() {
820 DCHECK(!free_output_buffers_
.empty());
822 // Enqueue an output (VIDEO_CAPTURE) buffer.
823 const int index
= free_output_buffers_
.back();
824 BufferRecord
& output_record
= output_buffer_map_
[index
];
825 DCHECK(!output_record
.at_device
);
826 struct v4l2_buffer qbuf
;
827 memset(&qbuf
, 0, sizeof(qbuf
));
829 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
830 qbuf
.memory
= V4L2_MEMORY_MMAP
;
831 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF
, &qbuf
);
832 output_record
.at_device
= true;
833 free_output_buffers_
.pop_back();
837 void V4L2JpegDecodeAccelerator::ResetQueues() {
838 if (input_streamon_
) {
839 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
840 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF
, &type
);
841 input_streamon_
= false;
844 if (output_streamon_
) {
845 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
846 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF
, &type
);
847 output_streamon_
= false;
850 free_input_buffers_
.clear();
851 for (size_t i
= 0; i
< input_buffer_map_
.size(); ++i
) {
852 BufferRecord
& input_record
= input_buffer_map_
[i
];
853 input_record
.at_device
= false;
854 free_input_buffers_
.push_back(i
);
857 free_output_buffers_
.clear();
858 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
859 BufferRecord
& output_record
= output_buffer_map_
[i
];
860 output_record
.at_device
= false;
861 free_output_buffers_
.push_back(i
);
865 void V4L2JpegDecodeAccelerator::StartDevicePoll() {
866 DVLOG(3) << __func__
<< ": starting device poll";
867 DCHECK(decoder_task_runner_
->BelongsToCurrentThread());
868 DCHECK(!device_poll_thread_
.IsRunning());
870 if (!device_poll_thread_
.Start()) {
871 LOG(ERROR
) << "StartDevicePoll(): Device thread failed to start";
872 PostNotifyError(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
875 device_poll_task_runner_
= device_poll_thread_
.task_runner();
878 bool V4L2JpegDecodeAccelerator::StopDevicePoll() {
879 DVLOG(3) << __func__
<< ": stopping device poll";
880 // Signal the DevicePollTask() to stop, and stop the device poll thread.
881 if (!device_
->SetDevicePollInterrupt()) {
882 LOG(ERROR
) << "StopDevicePoll(): SetDevicePollInterrupt failed.";
883 PostNotifyError(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
887 device_poll_thread_
.Stop();
889 // Clear the interrupt now, to be sure.
890 if (!device_
->ClearDevicePollInterrupt())
896 } // namespace content