1 // Copyright 2018 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_jpeg_encode_accelerator.h"
6
7 #include <errno.h>
8 #include <linux/videodev2.h>
9 #include <string.h>
10 #include <sys/mman.h>
11
12 #include <memory>
13
14 #include "base/bind.h"
15 #include "base/bind_helpers.h"
16 #include "base/numerics/ranges.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "media/gpu/chromeos/fourcc.h"
19 #include "media/gpu/chromeos/platform_video_frame_utils.h"
20 #include "media/gpu/macros.h"
21 #include "media/gpu/v4l2/v4l2_device.h"
22 #include "third_party/libyuv/include/libyuv.h"
23
24 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_name) \
25 do { \
26 if (device_->Ioctl(type, arg) != 0) { \
27 VPLOGF(1) << "ioctl() failed: " << type_name; \
28 NotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); \
29 return value; \
30 } \
31 } while (0)
32
33 #define IOCTL_OR_ERROR_RETURN(type, arg) \
34 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type)
35
36 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
37 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type)
38
39 #define IOCTL_OR_LOG_ERROR(type, arg) \
40 do { \
41 if (device_->Ioctl(type, arg) != 0) { \
42 VPLOGF(1) << "ioctl() failed: " << #type; \
43 NotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); \
44 } \
45 } while (0)
46
47 namespace media {
48
I420BufferRecord()49 V4L2JpegEncodeAccelerator::I420BufferRecord::I420BufferRecord()
50 : at_device(false) {
51 memset(address, 0, sizeof(address));
52 memset(length, 0, sizeof(length));
53 }
54
~I420BufferRecord()55 V4L2JpegEncodeAccelerator::I420BufferRecord::~I420BufferRecord() {}
56
JpegBufferRecord()57 V4L2JpegEncodeAccelerator::JpegBufferRecord::JpegBufferRecord()
58 : at_device(false) {
59 memset(address, 0, sizeof(address));
60 memset(length, 0, sizeof(length));
61 }
62
~JpegBufferRecord()63 V4L2JpegEncodeAccelerator::JpegBufferRecord::~JpegBufferRecord() {}
64
JobRecord(scoped_refptr<VideoFrame> input_frame,scoped_refptr<VideoFrame> output_frame,int quality,int32_t task_id,BitstreamBuffer * exif_buffer)65 V4L2JpegEncodeAccelerator::JobRecord::JobRecord(
66 scoped_refptr<VideoFrame> input_frame,
67 scoped_refptr<VideoFrame> output_frame,
68 int quality,
69 int32_t task_id,
70 BitstreamBuffer* exif_buffer)
71 : input_frame(input_frame),
72 output_frame(output_frame),
73 quality(quality),
74 task_id(task_id),
75 output_shm(base::subtle::PlatformSharedMemoryRegion(), 0, true), // dummy
76 exif_shm(nullptr) {
77 if (exif_buffer) {
78 exif_shm.reset(new UnalignedSharedMemory(exif_buffer->TakeRegion(),
79 exif_buffer->size(), false));
80 exif_offset = exif_buffer->offset();
81 }
82 }
83
JobRecord(scoped_refptr<VideoFrame> input_frame,int quality,BitstreamBuffer * exif_buffer,BitstreamBuffer output_buffer)84 V4L2JpegEncodeAccelerator::JobRecord::JobRecord(
85 scoped_refptr<VideoFrame> input_frame,
86 int quality,
87 BitstreamBuffer* exif_buffer,
88 BitstreamBuffer output_buffer)
89 : input_frame(input_frame),
90 quality(quality),
91 task_id(output_buffer.id()),
92 output_shm(output_buffer.TakeRegion(), output_buffer.size(), false),
93 output_offset(output_buffer.offset()),
94 exif_shm(nullptr) {
95 if (exif_buffer) {
96 exif_shm.reset(new UnalignedSharedMemory(exif_buffer->TakeRegion(),
97 exif_buffer->size(), false));
98 exif_offset = exif_buffer->offset();
99 }
100 }
101
~JobRecord()102 V4L2JpegEncodeAccelerator::JobRecord::~JobRecord() {}
103
EncodedInstance(V4L2JpegEncodeAccelerator * parent)104 V4L2JpegEncodeAccelerator::EncodedInstance::EncodedInstance(
105 V4L2JpegEncodeAccelerator* parent)
106 : parent_(parent),
107 input_streamon_(false),
108 output_streamon_(false),
109 input_buffer_pixelformat_(0),
110 input_buffer_num_planes_(0),
111 output_buffer_pixelformat_(0) {}
112
~EncodedInstance()113 V4L2JpegEncodeAccelerator::EncodedInstance::~EncodedInstance() {}
114
DestroyTask()115 void V4L2JpegEncodeAccelerator::EncodedInstance::DestroyTask() {
116 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
117 while (!input_job_queue_.empty())
118 input_job_queue_.pop();
119 while (!running_job_queue_.empty())
120 running_job_queue_.pop();
121
122 DestroyInputBuffers();
123 DestroyOutputBuffers();
124 }
125
Initialize()126 bool V4L2JpegEncodeAccelerator::EncodedInstance::Initialize() {
127 device_ = V4L2Device::Create();
128
129 if (!device_) {
130 VLOGF(1) << "Failed to Create V4L2Device";
131 return false;
132 }
133
134 output_buffer_pixelformat_ = V4L2_PIX_FMT_JPEG_RAW;
135 if (!device_->Open(V4L2Device::Type::kJpegEncoder,
136 output_buffer_pixelformat_)) {
137 VLOGF(1) << "Failed to open device";
138 return false;
139 }
140
141 // Capabilities check.
142 struct v4l2_capability caps;
143 const __u32 kCapsRequired = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
144 memset(&caps, 0, sizeof(caps));
145 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
146 VPLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP";
147 return false;
148 }
149 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
150 VLOGF(1) << "VIDIOC_QUERYCAP, caps check failed: 0x" << std::hex
151 << caps.capabilities;
152 return false;
153 }
154
155 return true;
156 }
157
158 // static
FillQuantizationTable(int quality,const uint8_t * basic_table,uint8_t * dst_table)159 void V4L2JpegEncodeAccelerator::EncodedInstance::FillQuantizationTable(
160 int quality,
161 const uint8_t* basic_table,
162 uint8_t* dst_table) {
163 unsigned int temp;
164
165 if (quality < 50)
166 quality = 5000 / quality;
167 else
168 quality = 200 - quality * 2;
169
170 for (size_t i = 0; i < kDctSize; i++) {
171 temp = ((unsigned int)basic_table[kZigZag8x8[i]] * quality + 50) / 100;
172 /* limit the values to the valid range */
173 dst_table[i] = base::ClampToRange(temp, 1u, 255u);
174 }
175 }
176
PrepareJpegMarkers(gfx::Size coded_size)177 void V4L2JpegEncodeAccelerator::EncodedInstance::PrepareJpegMarkers(
178 gfx::Size coded_size) {
179 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
180 // Quantization Tables.
181 // i = 0 for Luminance
182 // i = 1 for Chrominance
183 const int kNumDQT = 2;
184 for (size_t i = 0; i < kNumDQT; ++i) {
185 const uint8_t kQuantSegment[] = {
186 0xFF, JPEG_DQT, 0x00,
187 0x03 + kDctSize, // Segment length:67 (2-byte).
188 static_cast<uint8_t>(i) // Precision (4-bit high) = 0,
189 // Index (4-bit low) = i.
190 };
191 for (size_t j = 0; j < sizeof(kQuantSegment); ++j) {
192 jpeg_markers_.push_back(kQuantSegment[j]);
193 }
194
195 for (size_t j = 0; j < kDctSize; ++j) {
196 jpeg_markers_.push_back(quantization_table_[i].value[j]);
197 }
198 }
199
200 // Start of Frame - Baseline.
201 const int kNumOfComponents = 3;
202 const uint8_t kStartOfFrame[] = {
203 0xFF,
204 JPEG_SOF0, // Baseline.
205 0x00,
206 0x11, // Segment length:17 (2-byte).
207 8, // Data precision.
208 static_cast<uint8_t>((coded_size.height() >> 8) & 0xFF),
209 static_cast<uint8_t>(coded_size.height() & 0xFF),
210 static_cast<uint8_t>((coded_size.width() >> 8) & 0xFF),
211 static_cast<uint8_t>(coded_size.width() & 0xFF),
212 kNumOfComponents,
213 };
214 for (size_t i = 0; i < sizeof(kStartOfFrame); ++i) {
215 jpeg_markers_.push_back(kStartOfFrame[i]);
216 }
217 // i = 0 for Y Plane
218 // i = 1 for U Plane
219 // i = 2 for V Plane
220 for (size_t i = 0; i < kNumOfComponents; ++i) {
221 // These are the values for U and V planes.
222 uint8_t h_sample_factor = 1;
223 uint8_t v_sample_factor = 1;
224 uint8_t quant_table_number = 1;
225 if (!i) {
226 // These are the values for Y plane.
227 h_sample_factor = 2;
228 v_sample_factor = 2;
229 quant_table_number = 0;
230 }
231
232 jpeg_markers_.push_back(i + 1);
233 // Horizontal Sample Factor (4-bit high),
234 // Vertical Sample Factor (4-bit low).
235 jpeg_markers_.push_back((h_sample_factor << 4) | v_sample_factor);
236 jpeg_markers_.push_back(quant_table_number);
237 }
238
239 // Huffman Tables.
240 static const uint8_t kDcSegment[] = {
241 0xFF, JPEG_DHT, 0x00,
242 0x1F, // Segment length:31 (2-byte).
243 };
244 static const uint8_t kAcSegment[] = {
245 0xFF, JPEG_DHT, 0x00,
246 0xB5, // Segment length:181 (2-byte).
247 };
248
249 // i = 0 for Luminance
250 // i = 1 for Chrominance
251 const int kNumHuffmanTables = 2;
252 for (size_t i = 0; i < kNumHuffmanTables; ++i) {
253 // DC Table.
254 for (size_t j = 0; j < sizeof(kDcSegment); ++j) {
255 jpeg_markers_.push_back(kDcSegment[j]);
256 }
257
258 // Type (4-bit high) = 0:DC, Index (4-bit low).
259 jpeg_markers_.push_back(static_cast<uint8_t>(i));
260
261 const JpegHuffmanTable& dcTable = kDefaultDcTable[i];
262 for (size_t j = 0; j < kNumDcRunSizeBits; ++j)
263 jpeg_markers_.push_back(dcTable.code_length[j]);
264 for (size_t j = 0; j < kNumDcCodeWordsHuffVal; ++j)
265 jpeg_markers_.push_back(dcTable.code_value[j]);
266
267 // AC Table.
268 for (size_t j = 0; j < sizeof(kAcSegment); ++j) {
269 jpeg_markers_.push_back(kAcSegment[j]);
270 }
271
272 // Type (4-bit high) = 1:AC, Index (4-bit low).
273 jpeg_markers_.push_back(0x10 | static_cast<uint8_t>(i));
274
275 const JpegHuffmanTable& acTable = kDefaultAcTable[i];
276 for (size_t j = 0; j < kNumAcRunSizeBits; ++j)
277 jpeg_markers_.push_back(acTable.code_length[j]);
278 for (size_t j = 0; j < kNumAcCodeWordsHuffVal; ++j)
279 jpeg_markers_.push_back(acTable.code_value[j]);
280 }
281
282 // Start of Scan.
283 static const uint8_t kStartOfScan[] = {
284 0xFF, JPEG_SOS, 0x00,
285 0x0C, // Segment Length:12 (2-byte).
286 0x03 // Number of components in scan.
287 };
288 for (size_t i = 0; i < sizeof(kStartOfScan); ++i) {
289 jpeg_markers_.push_back(kStartOfScan[i]);
290 }
291
292 // i = 0 for Y Plane
293 // i = 1 for U Plane
294 // i = 2 for V Plane
295 for (uint8_t i = 0; i < kNumOfComponents; ++i) {
296 uint8_t dc_table_number = 1;
297 uint8_t ac_table_number = 1;
298 if (!i) {
299 dc_table_number = 0;
300 ac_table_number = 0;
301 }
302
303 jpeg_markers_.push_back(i + 1);
304 // DC Table Selector (4-bit high), AC Table Selector (4-bit low).
305 jpeg_markers_.push_back((dc_table_number << 4) | ac_table_number);
306 }
307 jpeg_markers_.push_back(0x00); // 0 for Baseline.
308 jpeg_markers_.push_back(0x3F); // 63 for Baseline.
309 jpeg_markers_.push_back(0x00); // 0 for Baseline.
310 }
311
SetUpJpegParameters(int quality,gfx::Size coded_size)312 bool V4L2JpegEncodeAccelerator::EncodedInstance::SetUpJpegParameters(
313 int quality,
314 gfx::Size coded_size) {
315 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
316
317 struct v4l2_ext_controls ctrls;
318 struct v4l2_ext_control ctrl;
319
320 memset(&ctrls, 0, sizeof(ctrls));
321 memset(&ctrl, 0, sizeof(ctrl));
322
323 ctrls.ctrl_class = V4L2_CTRL_CLASS_JPEG;
324 ctrls.controls = &ctrl;
325 ctrls.count = 1;
326
327 switch (output_buffer_pixelformat_) {
328 case V4L2_PIX_FMT_JPEG_RAW:
329 FillQuantizationTable(quality, kDefaultQuantTable[0].value,
330 quantization_table_[0].value);
331 FillQuantizationTable(quality, kDefaultQuantTable[1].value,
332 quantization_table_[1].value);
333
334 ctrl.id = V4L2_CID_JPEG_LUMA_QUANTIZATION;
335 ctrl.size = kDctSize;
336 ctrl.ptr = quantization_table_[0].value;
337 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, &ctrls);
338
339 ctrl.id = V4L2_CID_JPEG_CHROMA_QUANTIZATION;
340 ctrl.size = kDctSize;
341 ctrl.ptr = quantization_table_[1].value;
342 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, &ctrls);
343
344 // We need to prepare our own JPEG Markers.
345 PrepareJpegMarkers(coded_size);
346 break;
347
348 default:
349 NOTREACHED();
350 }
351
352 return true;
353 }
354
InputBufferQueuedCount()355 size_t V4L2JpegEncodeAccelerator::EncodedInstance::InputBufferQueuedCount() {
356 return input_buffer_map_.size() - free_input_buffers_.size();
357 }
358
OutputBufferQueuedCount()359 size_t V4L2JpegEncodeAccelerator::EncodedInstance::OutputBufferQueuedCount() {
360 return output_buffer_map_.size() - free_output_buffers_.size();
361 }
362
CreateBuffers(gfx::Size coded_size,size_t output_buffer_size)363 bool V4L2JpegEncodeAccelerator::EncodedInstance::CreateBuffers(
364 gfx::Size coded_size,
365 size_t output_buffer_size) {
366 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
367
368 // The order of set output/input formats matters.
369 // rk3399 reset input format when we set output format.
370 if (!SetOutputBufferFormat(coded_size, output_buffer_size)) {
371 return false;
372 }
373
374 if (!SetInputBufferFormat(coded_size)) {
375 return false;
376 }
377
378 if (!RequestInputBuffers()) {
379 return false;
380 }
381
382 if (!RequestOutputBuffers()) {
383 return false;
384 }
385
386 return true;
387 }
388
SetInputBufferFormat(gfx::Size coded_size)389 bool V4L2JpegEncodeAccelerator::EncodedInstance::SetInputBufferFormat(
390 gfx::Size coded_size) {
391 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
392 DCHECK(!input_streamon_);
393 DCHECK(input_job_queue_.empty());
394
395 constexpr uint32_t input_pix_fmt_candidates[] = {
396 V4L2_PIX_FMT_YUV420M,
397 V4L2_PIX_FMT_YUV420,
398 };
399
400 struct v4l2_format format;
401 input_buffer_pixelformat_ = 0;
402 for (const auto input_pix_fmt : input_pix_fmt_candidates) {
403 DCHECK_EQ(Fourcc::FromV4L2PixFmt(input_pix_fmt)->ToVideoPixelFormat(),
404 PIXEL_FORMAT_I420);
405 memset(&format, 0, sizeof(format));
406 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
407 format.fmt.pix_mp.num_planes = kMaxI420Plane;
408 format.fmt.pix_mp.pixelformat = input_pix_fmt;
409 format.fmt.pix_mp.field = V4L2_FIELD_ANY;
410 format.fmt.pix_mp.width = coded_size.width();
411 format.fmt.pix_mp.height = coded_size.height();
412
413 if (device_->Ioctl(VIDIOC_S_FMT, &format) == 0 &&
414 format.fmt.pix_mp.pixelformat == input_pix_fmt) {
415 // Save V4L2 returned values.
416 input_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat;
417 input_buffer_num_planes_ = format.fmt.pix_mp.num_planes;
418 input_buffer_height_ = format.fmt.pix_mp.height;
419 break;
420 }
421 }
422
423 if (input_buffer_pixelformat_ == 0) {
424 VLOGF(1) << "Neither YUV420 nor YUV420M is supported.";
425 return false;
426 }
427
428 if (format.fmt.pix_mp.width != static_cast<uint32_t>(coded_size.width()) ||
429 format.fmt.pix_mp.height != static_cast<uint32_t>(coded_size.height())) {
430 VLOGF(1) << "Width " << coded_size.width() << "->"
431 << format.fmt.pix_mp.width << ",Height " << coded_size.height()
432 << "->" << format.fmt.pix_mp.height;
433 return false;
434 }
435 for (int i = 0; i < format.fmt.pix_mp.num_planes; i++) {
436 bytes_per_line_[i] = format.fmt.pix_mp.plane_fmt[i].bytesperline;
437 VLOGF(3) << "Bytes Per Line:" << bytes_per_line_[i];
438 }
439
440 return true;
441 }
442
SetOutputBufferFormat(gfx::Size coded_size,size_t buffer_size)443 bool V4L2JpegEncodeAccelerator::EncodedInstance::SetOutputBufferFormat(
444 gfx::Size coded_size,
445 size_t buffer_size) {
446 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
447 DCHECK(!output_streamon_);
448 DCHECK(running_job_queue_.empty());
449
450 struct v4l2_format format;
451 memset(&format, 0, sizeof(format));
452 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
453 format.fmt.pix_mp.num_planes = kMaxJpegPlane;
454 format.fmt.pix_mp.pixelformat = output_buffer_pixelformat_;
455 format.fmt.pix_mp.field = V4L2_FIELD_ANY;
456 format.fmt.pix_mp.plane_fmt[0].sizeimage = buffer_size;
457 format.fmt.pix_mp.width = coded_size.width();
458 format.fmt.pix_mp.height = coded_size.height();
459 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
460 DCHECK_EQ(format.fmt.pix_mp.pixelformat, output_buffer_pixelformat_);
461
462 return true;
463 }
464
RequestInputBuffers()465 bool V4L2JpegEncodeAccelerator::EncodedInstance::RequestInputBuffers() {
466 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
467 struct v4l2_format format;
468 memset(&format, 0, sizeof(format));
469 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
470 format.fmt.pix_mp.pixelformat = input_buffer_pixelformat_;
471 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_FMT, &format);
472
473 struct v4l2_requestbuffers reqbufs;
474 memset(&reqbufs, 0, sizeof(reqbufs));
475 reqbufs.count = kBufferCount;
476 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
477 reqbufs.memory = V4L2_MEMORY_MMAP;
478 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
479
480 DCHECK(input_buffer_map_.empty());
481 input_buffer_map_.resize(reqbufs.count);
482
483 for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
484 free_input_buffers_.push_back(i);
485
486 struct v4l2_buffer buffer;
487 struct v4l2_plane planes[kMaxI420Plane];
488 memset(&buffer, 0, sizeof(buffer));
489 memset(planes, 0, sizeof(planes));
490 buffer.index = i;
491 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
492 buffer.memory = V4L2_MEMORY_MMAP;
493 buffer.m.planes = planes;
494 buffer.length = base::size(planes);
495 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer);
496
497 if (input_buffer_num_planes_ != buffer.length) {
498 return false;
499 }
500 for (size_t j = 0; j < buffer.length; ++j) {
501 if (base::checked_cast<int64_t>(planes[j].length) <
502 VideoFrame::PlaneSize(
503 PIXEL_FORMAT_I420, j,
504 gfx::Size(format.fmt.pix_mp.width, format.fmt.pix_mp.height))
505 .GetArea()) {
506 return false;
507 }
508 void* address =
509 device_->Mmap(NULL, planes[j].length, PROT_READ | PROT_WRITE,
510 MAP_SHARED, planes[j].m.mem_offset);
511 if (address == MAP_FAILED) {
512 VPLOGF(1) << "mmap() failed";
513 return false;
514 }
515 input_buffer_map_[i].address[j] = address;
516 input_buffer_map_[i].length[j] = planes[j].length;
517 }
518 }
519
520 return true;
521 }
522
RequestOutputBuffers()523 bool V4L2JpegEncodeAccelerator::EncodedInstance::RequestOutputBuffers() {
524 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
525 struct v4l2_requestbuffers reqbufs;
526 memset(&reqbufs, 0, sizeof(reqbufs));
527 reqbufs.count = kBufferCount;
528 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
529 reqbufs.memory = V4L2_MEMORY_MMAP;
530 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
531
532 DCHECK(output_buffer_map_.empty());
533 output_buffer_map_.resize(reqbufs.count);
534
535 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
536 free_output_buffers_.push_back(i);
537
538 struct v4l2_buffer buffer;
539 struct v4l2_plane planes[kMaxJpegPlane];
540 memset(&buffer, 0, sizeof(buffer));
541 memset(planes, 0, sizeof(planes));
542 buffer.index = i;
543 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
544 buffer.m.planes = planes;
545 buffer.length = base::size(planes);
546 buffer.memory = V4L2_MEMORY_MMAP;
547 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer);
548 if (buffer.length != kMaxJpegPlane) {
549 return false;
550 }
551 void* address =
552 device_->Mmap(NULL, planes[0].length, PROT_READ | PROT_WRITE,
553 MAP_SHARED, planes[0].m.mem_offset);
554 if (address == MAP_FAILED) {
555 VPLOGF(1) << "mmap() failed";
556 return false;
557 }
558 output_buffer_map_[i].address[0] = address;
559 output_buffer_map_[i].length[0] = planes[0].length;
560 }
561
562 return true;
563 }
564
DestroyInputBuffers()565 void V4L2JpegEncodeAccelerator::EncodedInstance::DestroyInputBuffers() {
566 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
567 free_input_buffers_.clear();
568
569 if (input_buffer_map_.empty())
570 return;
571
572 if (input_streamon_) {
573 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
574 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
575 input_streamon_ = false;
576 }
577
578 for (const auto& input_record : input_buffer_map_) {
579 for (size_t i = 0; i < input_buffer_num_planes_; ++i) {
580 device_->Munmap(input_record.address[i], input_record.length[i]);
581 }
582 }
583
584 struct v4l2_requestbuffers reqbufs;
585 memset(&reqbufs, 0, sizeof(reqbufs));
586 reqbufs.count = 0;
587 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
588 reqbufs.memory = V4L2_MEMORY_MMAP;
589 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
590
591 input_buffer_map_.clear();
592 input_buffer_num_planes_ = 0;
593 }
594
DestroyOutputBuffers()595 void V4L2JpegEncodeAccelerator::EncodedInstance::DestroyOutputBuffers() {
596 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
597 free_output_buffers_.clear();
598
599 if (output_buffer_map_.empty())
600 return;
601
602 if (output_streamon_) {
603 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
604 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
605 output_streamon_ = false;
606 }
607
608 for (const auto& output_record : output_buffer_map_) {
609 device_->Munmap(output_record.address[0], output_record.length[0]);
610 }
611
612 struct v4l2_requestbuffers reqbufs;
613 memset(&reqbufs, 0, sizeof(reqbufs));
614 reqbufs.count = 0;
615 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
616 reqbufs.memory = V4L2_MEMORY_MMAP;
617 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
618
619 output_buffer_map_.clear();
620 }
621
ServiceDevice()622 void V4L2JpegEncodeAccelerator::EncodedInstance::ServiceDevice() {
623 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
624
625 if (!running_job_queue_.empty()) {
626 Dequeue();
627 }
628
629 EnqueueInput();
630 EnqueueOutput();
631
632 DVLOGF(3) << "buffer counts: INPUT[" << input_job_queue_.size()
633 << "] => DEVICE[" << free_input_buffers_.size() << "/"
634 << input_buffer_map_.size() << "->" << free_output_buffers_.size()
635 << "/" << output_buffer_map_.size() << "]";
636 }
637
EnqueueInput()638 void V4L2JpegEncodeAccelerator::EncodedInstance::EnqueueInput() {
639 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
640 while (!input_job_queue_.empty() && !free_input_buffers_.empty()) {
641 if (!EnqueueInputRecord())
642 return;
643 }
644
645 if (!input_streamon_ && InputBufferQueuedCount()) {
646 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
647 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
648 input_streamon_ = true;
649 }
650 }
651
EnqueueOutput()652 void V4L2JpegEncodeAccelerator::EncodedInstance::EnqueueOutput() {
653 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
654 while (running_job_queue_.size() > OutputBufferQueuedCount() &&
655 !free_output_buffers_.empty()) {
656 if (!EnqueueOutputRecord())
657 return;
658 }
659
660 if (!output_streamon_ && OutputBufferQueuedCount()) {
661 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
662 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
663 output_streamon_ = true;
664 }
665 }
666
EnqueueInputRecord()667 bool V4L2JpegEncodeAccelerator::EncodedInstance::EnqueueInputRecord() {
668 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
669 DCHECK(!input_job_queue_.empty());
670 DCHECK(!free_input_buffers_.empty());
671
672 // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame.
673 std::unique_ptr<JobRecord> job_record = std::move(input_job_queue_.front());
674 input_job_queue_.pop();
675 const int index = free_input_buffers_.back();
676 I420BufferRecord& input_record = input_buffer_map_[index];
677 DCHECK(!input_record.at_device);
678
679 // Copy image from user memory to MMAP memory.
680 uint8_t* src_y = job_record->input_frame->data(VideoFrame::kYPlane);
681 uint8_t* src_u = job_record->input_frame->data(VideoFrame::kUPlane);
682 uint8_t* src_v = job_record->input_frame->data(VideoFrame::kVPlane);
683 size_t src_y_stride = job_record->input_frame->stride(VideoFrame::kYPlane);
684 size_t src_u_stride = job_record->input_frame->stride(VideoFrame::kUPlane);
685 size_t src_v_stride = job_record->input_frame->stride(VideoFrame::kVPlane);
686
687 size_t input_coded_width = job_record->input_frame->coded_size().width();
688 size_t input_coded_height = job_record->input_frame->coded_size().height();
689
690 size_t dst_y_stride = bytes_per_line_[0];
691 size_t dst_u_stride;
692 size_t dst_v_stride;
693
694 uint8_t* dst_y = static_cast<uint8_t*>(input_record.address[0]);
695 uint8_t* dst_u;
696 uint8_t* dst_v;
697
698 if (input_buffer_num_planes_ == 1) {
699 dst_u_stride = dst_y_stride / 2;
700 dst_v_stride = dst_y_stride / 2;
701 dst_u = dst_y + dst_y_stride * input_buffer_height_;
702 dst_v = dst_u + dst_u_stride * input_buffer_height_ / 2;
703 } else {
704 DCHECK(input_buffer_num_planes_ == 3);
705
706 dst_u_stride = bytes_per_line_[1];
707 dst_v_stride = bytes_per_line_[2];
708
709 dst_u = static_cast<uint8_t*>(input_record.address[1]);
710 dst_v = static_cast<uint8_t*>(input_record.address[2]);
711 }
712
713 if (libyuv::I420Copy(src_y, src_y_stride, src_u, src_u_stride, src_v,
714 src_v_stride, dst_y, dst_y_stride, dst_u, dst_u_stride,
715 dst_v, dst_v_stride, input_coded_width,
716 input_coded_height)) {
717 VLOGF(1) << "I420Copy failed";
718 return false;
719 }
720
721 struct v4l2_buffer qbuf;
722 struct v4l2_plane planes[kMaxI420Plane];
723 memset(&qbuf, 0, sizeof(qbuf));
724 memset(planes, 0, sizeof(planes));
725 qbuf.index = index;
726 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
727 qbuf.memory = V4L2_MEMORY_MMAP;
728 qbuf.length = base::size(planes);
729 for (size_t i = 0; i < input_buffer_num_planes_; i++) {
730 // sets this to 0 means the size of the plane.
731 planes[i].bytesused = 0;
732 }
733 qbuf.m.planes = planes;
734 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
735 input_record.at_device = true;
736 running_job_queue_.push(std::move(job_record));
737 free_input_buffers_.pop_back();
738
739 DVLOGF(3) << "enqueued frame id=" << job_record->task_id << " to device.";
740 return true;
741 }
742
EnqueueOutputRecord()743 bool V4L2JpegEncodeAccelerator::EncodedInstance::EnqueueOutputRecord() {
744 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
745 DCHECK(!free_output_buffers_.empty());
746
747 // Enqueue an output (VIDEO_CAPTURE) buffer.
748 const int index = free_output_buffers_.back();
749 JpegBufferRecord& output_record = output_buffer_map_[index];
750 DCHECK(!output_record.at_device);
751 struct v4l2_buffer qbuf;
752 struct v4l2_plane planes[kMaxJpegPlane];
753 memset(&qbuf, 0, sizeof(qbuf));
754 memset(planes, 0, sizeof(planes));
755 qbuf.index = index;
756 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
757 qbuf.memory = V4L2_MEMORY_MMAP;
758 qbuf.length = base::size(planes);
759 qbuf.m.planes = planes;
760 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
761 output_record.at_device = true;
762 free_output_buffers_.pop_back();
763 return true;
764 }
765
FinalizeJpegImage(uint8_t * dst_ptr,const JpegBufferRecord & output_buffer,size_t buffer_size,std::unique_ptr<UnalignedSharedMemory> exif_shm)766 size_t V4L2JpegEncodeAccelerator::EncodedInstance::FinalizeJpegImage(
767 uint8_t* dst_ptr,
768 const JpegBufferRecord& output_buffer,
769 size_t buffer_size,
770 std::unique_ptr<UnalignedSharedMemory> exif_shm) {
771 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
772 size_t idx;
773
774 // Fill SOI and EXIF markers.
775 dst_ptr[0] = 0xFF;
776 dst_ptr[1] = JPEG_SOI;
777 idx = 2;
778
779 if (exif_shm) {
780 uint8_t* exif_buffer = static_cast<uint8_t*>(exif_shm->memory());
781 size_t exif_buffer_size = exif_shm->size();
782 // Application Segment for Exif data.
783 uint16_t exif_segment_size = static_cast<uint16_t>(exif_buffer_size + 2);
784 const uint8_t kAppSegment[] = {
785 0xFF, JPEG_APP1, static_cast<uint8_t>(exif_segment_size / 256),
786 static_cast<uint8_t>(exif_segment_size % 256)};
787 memcpy(dst_ptr + idx, kAppSegment, sizeof(kAppSegment));
788 idx += sizeof(kAppSegment);
789 memcpy(dst_ptr + idx, exif_buffer, exif_buffer_size);
790 idx += exif_buffer_size;
791 } else {
792 // Application Segment - JFIF standard 1.01.
793 static const uint8_t kAppSegment[] = {
794 0xFF, JPEG_APP0, 0x00,
795 0x10, // Segment length:16 (2-byte).
796 0x4A, // J
797 0x46, // F
798 0x49, // I
799 0x46, // F
800 0x00, // 0
801 0x01, // Major version.
802 0x01, // Minor version.
803 0x01, // Density units 0:no units, 1:pixels per inch,
804 // 2: pixels per cm.
805 0x00,
806 0x48, // X density (2-byte).
807 0x00,
808 0x48, // Y density (2-byte).
809 0x00, // Thumbnail width.
810 0x00 // Thumbnail height.
811 };
812 memcpy(dst_ptr + idx, kAppSegment, sizeof(kAppSegment));
813 idx += sizeof(kAppSegment);
814 }
815
816 switch (output_buffer_pixelformat_) {
817 case V4L2_PIX_FMT_JPEG_RAW:
818 // Fill the other jpeg markers for RAW JPEG.
819 memcpy(dst_ptr + idx, jpeg_markers_.data(), jpeg_markers_.size());
820 idx += jpeg_markers_.size();
821 // Fill Compressed stream.
822 memcpy(dst_ptr + idx, output_buffer.address[0], buffer_size);
823 idx += buffer_size;
824 // Fill EOI. Before Fill EOI we checked if the V4L2 device filled EOI
825 // first.
826 if (dst_ptr[idx - 2] != 0xFF && dst_ptr[idx - 1] != JPEG_EOI) {
827 dst_ptr[idx] = 0xFF;
828 dst_ptr[idx + 1] = JPEG_EOI;
829 idx += 2;
830 }
831 break;
832
833 default:
834 NOTREACHED() << "Unsupported output pixel format";
835 }
836
837 return idx;
838 }
839
Dequeue()840 void V4L2JpegEncodeAccelerator::EncodedInstance::Dequeue() {
841 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
842 // Dequeue completed input (VIDEO_OUTPUT) buffers,
843 // and recycle to the free list.
844 struct v4l2_buffer dqbuf;
845 struct v4l2_plane planes[kMaxI420Plane];
846 while (InputBufferQueuedCount() > 0) {
847 DCHECK(input_streamon_);
848 memset(&dqbuf, 0, sizeof(dqbuf));
849 memset(planes, 0, sizeof(planes));
850 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
851 dqbuf.memory = V4L2_MEMORY_MMAP;
852 dqbuf.length = base::size(planes);
853 dqbuf.m.planes = planes;
854 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
855 if (errno == EAGAIN) {
856 // EAGAIN if we're just out of buffers to dequeue.
857 break;
858 }
859 VPLOGF(1) << "ioctl() failed: input buffer VIDIOC_DQBUF failed.";
860 NotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
861 return;
862 }
863 I420BufferRecord& input_record = input_buffer_map_[dqbuf.index];
864 DCHECK(input_record.at_device);
865 input_record.at_device = false;
866 free_input_buffers_.push_back(dqbuf.index);
867
868 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
869 VLOGF(1) << "Error in dequeued input buffer.";
870 NotifyError(kInvalidBitstreamBufferId, PARSE_IMAGE_FAILED);
871 running_job_queue_.pop();
872 }
873 }
874
875 // Dequeue completed output (VIDEO_CAPTURE) buffers, recycle to the free list.
876 // Return the finished buffer to the client via the job ready callback.
877 // If dequeued input buffer has an error, the error frame has removed from
878 // |running_job_queue_|. We only have to dequeue output buffer when we
879 // actually have pending frames in |running_job_queue_| and also enqueued
880 // output buffers.
881 while (!running_job_queue_.empty() && OutputBufferQueuedCount() > 0) {
882 DCHECK(output_streamon_);
883 memset(&dqbuf, 0, sizeof(dqbuf));
884 memset(planes, 0, sizeof(planes));
885 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
886 dqbuf.memory = V4L2_MEMORY_MMAP;
887 dqbuf.length = base::size(planes);
888 dqbuf.m.planes = planes;
889 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
890 if (errno == EAGAIN) {
891 // EAGAIN if we're just out of buffers to dequeue.
892 break;
893 }
894 VPLOGF(1) << "ioctl() failed: output buffer VIDIOC_DQBUF failed.";
895 NotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
896 return;
897 }
898 JpegBufferRecord& output_record = output_buffer_map_[dqbuf.index];
899 DCHECK(output_record.at_device);
900 output_record.at_device = false;
901 free_output_buffers_.push_back(dqbuf.index);
902
903 // Jobs are always processed in FIFO order.
904 std::unique_ptr<JobRecord> job_record =
905 std::move(running_job_queue_.front());
906 running_job_queue_.pop();
907
908 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
909 VLOGF(1) << "Error in dequeued output buffer.";
910 NotifyError(kInvalidBitstreamBufferId, PARSE_IMAGE_FAILED);
911 return;
912 }
913
914 size_t jpeg_size = FinalizeJpegImage(
915 static_cast<uint8_t*>(job_record->output_shm.memory()), output_record,
916 planes[0].bytesused, std::move(job_record->exif_shm));
917 if (!jpeg_size) {
918 NotifyError(job_record->task_id, PLATFORM_FAILURE);
919 return;
920 }
921 DVLOGF(4) << "Encoding finished, returning bitstream buffer, id="
922 << job_record->task_id;
923
924 parent_->VideoFrameReady(job_record->task_id, jpeg_size);
925 }
926 }
927
NotifyError(int32_t task_id,Status status)928 void V4L2JpegEncodeAccelerator::EncodedInstance::NotifyError(int32_t task_id,
929 Status status) {
930 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
931 parent_->NotifyError(task_id, status);
932 }
933
EncodedInstanceDmaBuf(V4L2JpegEncodeAccelerator * parent)934 V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::EncodedInstanceDmaBuf(
935 V4L2JpegEncodeAccelerator* parent)
936 : parent_(parent),
937 input_streamon_(false),
938 output_streamon_(false),
939 input_buffer_pixelformat_(0),
940 input_buffer_num_planes_(0),
941 output_buffer_pixelformat_(0) {}
942
~EncodedInstanceDmaBuf()943 V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::~EncodedInstanceDmaBuf() {}
944
DestroyTask()945 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::DestroyTask() {
946 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
947 while (!input_job_queue_.empty())
948 input_job_queue_.pop();
949 while (!running_job_queue_.empty())
950 running_job_queue_.pop();
951
952 DestroyInputBuffers();
953 DestroyOutputBuffers();
954 }
955
Initialize()956 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::Initialize() {
957 device_ = V4L2Device::Create();
958 gpu_memory_buffer_support_ = std::make_unique<gpu::GpuMemoryBufferSupport>();
959
960 if (!device_) {
961 VLOGF(1) << "Failed to Create V4L2Device";
962 return false;
963 }
964
965 output_buffer_pixelformat_ = V4L2_PIX_FMT_JPEG_RAW;
966 if (!device_->Open(V4L2Device::Type::kJpegEncoder,
967 output_buffer_pixelformat_)) {
968 VLOGF(1) << "Failed to open device";
969 return false;
970 }
971
972 // Capabilities check.
973 struct v4l2_capability caps;
974 const __u32 kCapsRequired = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
975 memset(&caps, 0, sizeof(caps));
976 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
977 VPLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP";
978 return false;
979 }
980 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
981 VLOGF(1) << "VIDIOC_QUERYCAP, caps check failed: 0x" << std::hex
982 << caps.capabilities;
983 return false;
984 }
985
986 return true;
987 }
988
989 // static
FillQuantizationTable(int quality,const uint8_t * basic_table,uint8_t * dst_table)990 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::FillQuantizationTable(
991 int quality,
992 const uint8_t* basic_table,
993 uint8_t* dst_table) {
994 unsigned int temp;
995
996 if (quality < 50)
997 quality = 5000 / quality;
998 else
999 quality = 200 - quality * 2;
1000
1001 for (size_t i = 0; i < kDctSize; i++) {
1002 temp = ((unsigned int)basic_table[kZigZag8x8[i]] * quality + 50) / 100;
1003 /* limit the values to the valid range */
1004 dst_table[i] = base::ClampToRange(temp, 1u, 255u);
1005 }
1006 }
1007
PrepareJpegMarkers(gfx::Size coded_size)1008 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::PrepareJpegMarkers(
1009 gfx::Size coded_size) {
1010 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1011 // Quantization Tables.
1012 // i = 0 for Luminance
1013 // i = 1 for Chrominance
1014 const int kNumDQT = 2;
1015 for (size_t i = 0; i < kNumDQT; ++i) {
1016 const uint8_t kQuantSegment[] = {
1017 0xFF, JPEG_DQT, 0x00,
1018 0x03 + kDctSize, // Segment length:67 (2-byte).
1019 static_cast<uint8_t>(i) // Precision (4-bit high) = 0,
1020 // Index (4-bit low) = i.
1021 };
1022 for (size_t j = 0; j < sizeof(kQuantSegment); ++j) {
1023 jpeg_markers_.push_back(kQuantSegment[j]);
1024 }
1025
1026 for (size_t j = 0; j < kDctSize; ++j) {
1027 jpeg_markers_.push_back(quantization_table_[i].value[j]);
1028 }
1029 }
1030
1031 // Start of Frame - Baseline.
1032 const int kNumOfComponents = 3;
1033 const uint8_t kStartOfFrame[] = {
1034 0xFF,
1035 JPEG_SOF0, // Baseline.
1036 0x00,
1037 0x11, // Segment length:17 (2-byte).
1038 8, // Data precision.
1039 static_cast<uint8_t>((coded_size.height() >> 8) & 0xFF),
1040 static_cast<uint8_t>(coded_size.height() & 0xFF),
1041 static_cast<uint8_t>((coded_size.width() >> 8) & 0xFF),
1042 static_cast<uint8_t>(coded_size.width() & 0xFF),
1043 kNumOfComponents,
1044 };
1045 for (size_t i = 0; i < sizeof(kStartOfFrame); ++i) {
1046 jpeg_markers_.push_back(kStartOfFrame[i]);
1047 }
1048 // i = 0 for Y Plane
1049 // i = 1 for U Plane
1050 // i = 2 for V Plane
1051 for (size_t i = 0; i < kNumOfComponents; ++i) {
1052 // These are the values for U and V planes.
1053 uint8_t h_sample_factor = 1;
1054 uint8_t v_sample_factor = 1;
1055 uint8_t quant_table_number = 1;
1056 if (!i) {
1057 // These are the values for Y plane.
1058 h_sample_factor = 2;
1059 v_sample_factor = 2;
1060 quant_table_number = 0;
1061 }
1062
1063 jpeg_markers_.push_back(i + 1);
1064 // Horizontal Sample Factor (4-bit high),
1065 // Vertical Sample Factor (4-bit low).
1066 jpeg_markers_.push_back((h_sample_factor << 4) | v_sample_factor);
1067 jpeg_markers_.push_back(quant_table_number);
1068 }
1069
1070 // Huffman Tables.
1071 static const uint8_t kDcSegment[] = {
1072 0xFF, JPEG_DHT, 0x00,
1073 0x1F, // Segment length:31 (2-byte).
1074 };
1075 static const uint8_t kAcSegment[] = {
1076 0xFF, JPEG_DHT, 0x00,
1077 0xB5, // Segment length:181 (2-byte).
1078 };
1079
1080 // i = 0 for Luminance
1081 // i = 1 for Chrominance
1082 const int kNumHuffmanTables = 2;
1083 for (size_t i = 0; i < kNumHuffmanTables; ++i) {
1084 // DC Table.
1085 for (size_t j = 0; j < sizeof(kDcSegment); ++j) {
1086 jpeg_markers_.push_back(kDcSegment[j]);
1087 }
1088
1089 // Type (4-bit high) = 0:DC, Index (4-bit low).
1090 jpeg_markers_.push_back(static_cast<uint8_t>(i));
1091
1092 const JpegHuffmanTable& dcTable = kDefaultDcTable[i];
1093 for (size_t j = 0; j < kNumDcRunSizeBits; ++j)
1094 jpeg_markers_.push_back(dcTable.code_length[j]);
1095 for (size_t j = 0; j < kNumDcCodeWordsHuffVal; ++j)
1096 jpeg_markers_.push_back(dcTable.code_value[j]);
1097
1098 // AC Table.
1099 for (size_t j = 0; j < sizeof(kAcSegment); ++j) {
1100 jpeg_markers_.push_back(kAcSegment[j]);
1101 }
1102
1103 // Type (4-bit high) = 1:AC, Index (4-bit low).
1104 jpeg_markers_.push_back(0x10 | static_cast<uint8_t>(i));
1105
1106 const JpegHuffmanTable& acTable = kDefaultAcTable[i];
1107 for (size_t j = 0; j < kNumAcRunSizeBits; ++j)
1108 jpeg_markers_.push_back(acTable.code_length[j]);
1109 for (size_t j = 0; j < kNumAcCodeWordsHuffVal; ++j)
1110 jpeg_markers_.push_back(acTable.code_value[j]);
1111 }
1112
1113 // Start of Scan.
1114 static const uint8_t kStartOfScan[] = {
1115 0xFF, JPEG_SOS, 0x00,
1116 0x0C, // Segment Length:12 (2-byte).
1117 0x03 // Number of components in scan.
1118 };
1119 for (size_t i = 0; i < sizeof(kStartOfScan); ++i) {
1120 jpeg_markers_.push_back(kStartOfScan[i]);
1121 }
1122
1123 // i = 0 for Y Plane
1124 // i = 1 for U Plane
1125 // i = 2 for V Plane
1126 for (uint8_t i = 0; i < kNumOfComponents; ++i) {
1127 uint8_t dc_table_number = 1;
1128 uint8_t ac_table_number = 1;
1129 if (!i) {
1130 dc_table_number = 0;
1131 ac_table_number = 0;
1132 }
1133
1134 jpeg_markers_.push_back(i + 1);
1135 // DC Table Selector (4-bit high), AC Table Selector (4-bit low).
1136 jpeg_markers_.push_back((dc_table_number << 4) | ac_table_number);
1137 }
1138 jpeg_markers_.push_back(0x00); // 0 for Baseline.
1139 jpeg_markers_.push_back(0x3F); // 63 for Baseline.
1140 jpeg_markers_.push_back(0x00); // 0 for Baseline.
1141 }
1142
SetUpJpegParameters(int quality,gfx::Size coded_size)1143 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::SetUpJpegParameters(
1144 int quality,
1145 gfx::Size coded_size) {
1146 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1147
1148 struct v4l2_ext_controls ctrls;
1149 struct v4l2_ext_control ctrl;
1150
1151 memset(&ctrls, 0, sizeof(ctrls));
1152 memset(&ctrl, 0, sizeof(ctrl));
1153
1154 ctrls.ctrl_class = V4L2_CTRL_CLASS_JPEG;
1155 ctrls.controls = &ctrl;
1156 ctrls.count = 1;
1157
1158 switch (output_buffer_pixelformat_) {
1159 case V4L2_PIX_FMT_JPEG_RAW:
1160 FillQuantizationTable(quality, kDefaultQuantTable[0].value,
1161 quantization_table_[0].value);
1162 FillQuantizationTable(quality, kDefaultQuantTable[1].value,
1163 quantization_table_[1].value);
1164
1165 ctrl.id = V4L2_CID_JPEG_LUMA_QUANTIZATION;
1166 ctrl.size = kDctSize;
1167 ctrl.ptr = quantization_table_[0].value;
1168 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, &ctrls);
1169
1170 ctrl.id = V4L2_CID_JPEG_CHROMA_QUANTIZATION;
1171 ctrl.size = kDctSize;
1172 ctrl.ptr = quantization_table_[1].value;
1173 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, &ctrls);
1174
1175 // We need to prepare our own JPEG Markers.
1176 PrepareJpegMarkers(coded_size);
1177 break;
1178
1179 default:
1180 NOTREACHED();
1181 }
1182
1183 return true;
1184 }
1185
1186 size_t
InputBufferQueuedCount()1187 V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::InputBufferQueuedCount() {
1188 return kBufferCount - free_input_buffers_.size();
1189 }
1190
1191 size_t
OutputBufferQueuedCount()1192 V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::OutputBufferQueuedCount() {
1193 return kBufferCount - free_output_buffers_.size();
1194 }
1195
CreateBuffers(gfx::Size coded_size,const VideoFrameLayout & input_layout,size_t output_buffer_size)1196 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::CreateBuffers(
1197 gfx::Size coded_size,
1198 const VideoFrameLayout& input_layout,
1199 size_t output_buffer_size) {
1200 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1201
1202 // The order of set output/input formats matters.
1203 // rk3399 reset input format when we set output format.
1204 if (!SetOutputBufferFormat(coded_size, output_buffer_size)) {
1205 return false;
1206 }
1207
1208 if (!SetInputBufferFormat(coded_size, input_layout)) {
1209 return false;
1210 }
1211
1212 if (!RequestInputBuffers()) {
1213 return false;
1214 }
1215
1216 if (!RequestOutputBuffers()) {
1217 return false;
1218 }
1219
1220 return true;
1221 }
1222
SetInputBufferFormat(gfx::Size coded_size,const VideoFrameLayout & input_layout)1223 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::SetInputBufferFormat(
1224 gfx::Size coded_size,
1225 const VideoFrameLayout& input_layout) {
1226 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1227 DCHECK(!input_streamon_);
1228 DCHECK(input_job_queue_.empty());
1229
1230 constexpr uint32_t input_pix_fmt_candidates[] = {V4L2_PIX_FMT_NV12M,
1231 V4L2_PIX_FMT_NV12};
1232
1233 struct v4l2_format format;
1234 input_buffer_pixelformat_ = 0;
1235 for (const auto input_pix_fmt : input_pix_fmt_candidates) {
1236 DCHECK_EQ(Fourcc::FromV4L2PixFmt(input_pix_fmt)->ToVideoPixelFormat(),
1237 PIXEL_FORMAT_NV12);
1238 memset(&format, 0, sizeof(format));
1239 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1240 format.fmt.pix_mp.num_planes = kMaxNV12Plane;
1241 format.fmt.pix_mp.pixelformat = input_pix_fmt;
1242 format.fmt.pix_mp.field = V4L2_FIELD_ANY;
1243 format.fmt.pix_mp.width = coded_size.width();
1244 format.fmt.pix_mp.height = coded_size.height();
1245
1246 auto num_planes = input_layout.num_planes();
1247 for (size_t i = 0; i < num_planes; i++) {
1248 format.fmt.pix_mp.plane_fmt[i].sizeimage = input_layout.planes()[i].size;
1249 format.fmt.pix_mp.plane_fmt[i].bytesperline =
1250 input_layout.planes()[i].stride;
1251 }
1252
1253 if (device_->Ioctl(VIDIOC_S_FMT, &format) == 0 &&
1254 format.fmt.pix_mp.pixelformat == input_pix_fmt) {
1255 device_input_layout_ = V4L2Device::V4L2FormatToVideoFrameLayout(format);
1256
1257 // Save V4L2 returned values.
1258 input_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat;
1259 input_buffer_num_planes_ = format.fmt.pix_mp.num_planes;
1260 input_buffer_height_ = format.fmt.pix_mp.height;
1261 break;
1262 }
1263 }
1264
1265 if (input_buffer_pixelformat_ == 0) {
1266 VLOGF(1) << "Neither NV12 nor NV12M is supported.";
1267 return false;
1268 }
1269
1270 if (format.fmt.pix_mp.width != static_cast<uint32_t>(coded_size.width()) ||
1271 format.fmt.pix_mp.height != static_cast<uint32_t>(coded_size.height())) {
1272 VLOGF(1) << "Width " << coded_size.width() << "->"
1273 << format.fmt.pix_mp.width << ",Height " << coded_size.height()
1274 << "->" << format.fmt.pix_mp.height;
1275 return false;
1276 }
1277 return true;
1278 }
1279
SetOutputBufferFormat(gfx::Size coded_size,size_t buffer_size)1280 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::SetOutputBufferFormat(
1281 gfx::Size coded_size,
1282 size_t buffer_size) {
1283 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1284 DCHECK(!output_streamon_);
1285 DCHECK(running_job_queue_.empty());
1286
1287 struct v4l2_format format;
1288 memset(&format, 0, sizeof(format));
1289 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1290 format.fmt.pix_mp.num_planes = kMaxJpegPlane;
1291 format.fmt.pix_mp.pixelformat = output_buffer_pixelformat_;
1292 format.fmt.pix_mp.field = V4L2_FIELD_ANY;
1293 format.fmt.pix_mp.plane_fmt[0].sizeimage = buffer_size;
1294 format.fmt.pix_mp.width = coded_size.width();
1295 format.fmt.pix_mp.height = coded_size.height();
1296 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
1297 DCHECK_EQ(format.fmt.pix_mp.pixelformat, output_buffer_pixelformat_);
1298
1299 return true;
1300 }
1301
RequestInputBuffers()1302 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::RequestInputBuffers() {
1303 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1304 struct v4l2_format format;
1305 memset(&format, 0, sizeof(format));
1306 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1307 format.fmt.pix_mp.pixelformat = input_buffer_pixelformat_;
1308 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_FMT, &format);
1309
1310 struct v4l2_requestbuffers reqbufs;
1311 memset(&reqbufs, 0, sizeof(reqbufs));
1312 reqbufs.count = kBufferCount;
1313 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1314 reqbufs.memory = V4L2_MEMORY_DMABUF;
1315 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
1316
1317 DCHECK(free_input_buffers_.empty());
1318 for (size_t i = 0; i < reqbufs.count; ++i) {
1319 free_input_buffers_.push_back(i);
1320 }
1321
1322 return true;
1323 }
1324
RequestOutputBuffers()1325 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::RequestOutputBuffers() {
1326 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1327 struct v4l2_requestbuffers reqbufs;
1328 memset(&reqbufs, 0, sizeof(reqbufs));
1329 reqbufs.count = kBufferCount;
1330 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1331 reqbufs.memory = V4L2_MEMORY_DMABUF;
1332 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
1333
1334 DCHECK(free_output_buffers_.empty());
1335 for (size_t i = 0; i < reqbufs.count; ++i) {
1336 free_output_buffers_.push_back(i);
1337 }
1338
1339 return true;
1340 }
1341
DestroyInputBuffers()1342 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::DestroyInputBuffers() {
1343 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1344 free_input_buffers_.clear();
1345
1346 if (input_streamon_) {
1347 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1348 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
1349 input_streamon_ = false;
1350 }
1351
1352 struct v4l2_requestbuffers reqbufs;
1353 memset(&reqbufs, 0, sizeof(reqbufs));
1354 reqbufs.count = 0;
1355 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1356 reqbufs.memory = V4L2_MEMORY_DMABUF;
1357 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
1358
1359 input_buffer_num_planes_ = 0;
1360 }
1361
DestroyOutputBuffers()1362 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::DestroyOutputBuffers() {
1363 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1364 free_output_buffers_.clear();
1365
1366 if (output_streamon_) {
1367 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1368 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
1369 output_streamon_ = false;
1370 }
1371
1372 struct v4l2_requestbuffers reqbufs;
1373 memset(&reqbufs, 0, sizeof(reqbufs));
1374 reqbufs.count = 0;
1375 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1376 reqbufs.memory = V4L2_MEMORY_DMABUF;
1377 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
1378 }
1379
ServiceDevice()1380 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::ServiceDevice() {
1381 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1382
1383 if (!running_job_queue_.empty()) {
1384 Dequeue();
1385 }
1386
1387 EnqueueInput();
1388 EnqueueOutput();
1389
1390 DVLOGF(3) << "buffer counts: INPUT[" << input_job_queue_.size()
1391 << "] => DEVICE[" << free_input_buffers_.size() << "/"
1392 << "->" << free_output_buffers_.size() << "]";
1393 }
1394
EnqueueInput()1395 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::EnqueueInput() {
1396 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1397 while (!input_job_queue_.empty() && !free_input_buffers_.empty()) {
1398 if (!EnqueueInputRecord())
1399 return;
1400 }
1401
1402 if (!input_streamon_ && InputBufferQueuedCount()) {
1403 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1404 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
1405 input_streamon_ = true;
1406 }
1407 }
1408
EnqueueOutput()1409 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::EnqueueOutput() {
1410 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1411 while (running_job_queue_.size() > OutputBufferQueuedCount() &&
1412 !free_output_buffers_.empty()) {
1413 if (!EnqueueOutputRecord())
1414 return;
1415 }
1416
1417 if (!output_streamon_ && OutputBufferQueuedCount()) {
1418 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1419 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
1420 output_streamon_ = true;
1421 }
1422 }
1423
EnqueueInputRecord()1424 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::EnqueueInputRecord() {
1425 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1426 DCHECK(!input_job_queue_.empty());
1427 DCHECK(!free_input_buffers_.empty());
1428
1429 // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame.
1430 std::unique_ptr<JobRecord> job_record = std::move(input_job_queue_.front());
1431 input_job_queue_.pop();
1432 const int index = free_input_buffers_.back();
1433
1434 struct v4l2_buffer qbuf;
1435 struct v4l2_plane planes[kMaxNV12Plane];
1436 memset(&qbuf, 0, sizeof(qbuf));
1437 memset(planes, 0, sizeof(planes));
1438 qbuf.index = index;
1439 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1440 qbuf.memory = V4L2_MEMORY_DMABUF;
1441 qbuf.length = base::size(planes);
1442 qbuf.m.planes = planes;
1443
1444 const auto& frame = job_record->input_frame;
1445 for (size_t i = 0; i < input_buffer_num_planes_; i++) {
1446 if (device_input_layout_->is_multi_planar()) {
1447 qbuf.m.planes[i].bytesused = base::checked_cast<__u32>(
1448 VideoFrame::PlaneSize(frame->format(), i,
1449 device_input_layout_->coded_size())
1450 .GetArea());
1451 } else {
1452 qbuf.m.planes[i].bytesused = VideoFrame::AllocationSize(
1453 frame->format(), device_input_layout_->coded_size());
1454 }
1455
1456 const auto& fds = frame->DmabufFds();
1457 const auto& planes = frame->layout().planes();
1458 qbuf.m.planes[i].m.fd = (i < fds.size()) ? fds[i].get() : fds.back().get();
1459 qbuf.m.planes[i].data_offset = planes[i].offset;
1460 qbuf.m.planes[i].bytesused += qbuf.m.planes[i].data_offset;
1461 qbuf.m.planes[i].length = planes[i].size + qbuf.m.planes[i].data_offset;
1462 }
1463
1464 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
1465 running_job_queue_.push(std::move(job_record));
1466 free_input_buffers_.pop_back();
1467 return true;
1468 }
1469
EnqueueOutputRecord()1470 bool V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::EnqueueOutputRecord() {
1471 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1472 DCHECK(!free_output_buffers_.empty());
1473
1474 // Enqueue an output (VIDEO_CAPTURE) buffer.
1475 const int index = free_output_buffers_.back();
1476 struct v4l2_buffer qbuf;
1477 struct v4l2_plane planes[kMaxJpegPlane];
1478 memset(&qbuf, 0, sizeof(qbuf));
1479 memset(planes, 0, sizeof(planes));
1480 qbuf.index = index;
1481 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1482 qbuf.memory = V4L2_MEMORY_DMABUF;
1483 qbuf.length = base::size(planes);
1484 qbuf.m.planes = planes;
1485
1486 auto& job_record = running_job_queue_.back();
1487 for (size_t i = 0; i < qbuf.length; i++) {
1488 planes[i].m.fd = job_record->output_frame->DmabufFds()[i].get();
1489 }
1490 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
1491 free_output_buffers_.pop_back();
1492 return true;
1493 }
1494
FinalizeJpegImage(scoped_refptr<VideoFrame> output_frame,size_t buffer_size,std::unique_ptr<UnalignedSharedMemory> exif_shm)1495 size_t V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::FinalizeJpegImage(
1496 scoped_refptr<VideoFrame> output_frame,
1497 size_t buffer_size,
1498 std::unique_ptr<UnalignedSharedMemory> exif_shm) {
1499 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1500 size_t idx = 0;
1501
1502 auto output_gmb_handle = CreateGpuMemoryBufferHandle(output_frame.get());
1503 DCHECK(!output_gmb_handle.is_null());
1504
1505 // In this case, we use the R_8 buffer with height == 1 to represent a data
1506 // container. As a result, we use plane.stride as size of the data here since
1507 // plane.size might be larger due to height alignment.
1508 const gfx::Size output_gmb_buffer_size(
1509 base::checked_cast<int32_t>(output_frame->layout().planes()[0].stride),
1510 1);
1511
1512 auto output_gmb_buffer =
1513 gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle(
1514 std::move(output_gmb_handle), output_gmb_buffer_size,
1515 gfx::BufferFormat::R_8, gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE,
1516 base::DoNothing());
1517
1518 bool isMapped = output_gmb_buffer->Map();
1519 if (!isMapped) {
1520 VLOGF(1) << "Failed to map gmb buffer";
1521 return 0;
1522 }
1523 uint8_t* dst_ptr = static_cast<uint8_t*>(output_gmb_buffer->memory(0));
1524
1525 // Fill SOI and EXIF markers.
1526 static const uint8_t kJpegStart[] = {0xFF, JPEG_SOI};
1527
1528 if (exif_shm) {
1529 uint8_t* exif_buffer = static_cast<uint8_t*>(exif_shm->memory());
1530 size_t exif_buffer_size = exif_shm->size();
1531 // Application Segment for Exif data.
1532 uint16_t exif_segment_size = static_cast<uint16_t>(exif_buffer_size + 2);
1533 const uint8_t kAppSegment[] = {
1534 0xFF, JPEG_APP1, static_cast<uint8_t>(exif_segment_size / 256),
1535 static_cast<uint8_t>(exif_segment_size % 256)};
1536
1537 // Move compressed data first.
1538 size_t compressed_data_offset = sizeof(kJpegStart) + sizeof(kAppSegment) +
1539 exif_buffer_size + jpeg_markers_.size();
1540 memmove(dst_ptr + compressed_data_offset, dst_ptr, buffer_size);
1541
1542 memcpy(dst_ptr, kJpegStart, sizeof(kJpegStart));
1543 idx += sizeof(kJpegStart);
1544 memcpy(dst_ptr + idx, kAppSegment, sizeof(kAppSegment));
1545 idx += sizeof(kAppSegment);
1546 memcpy(dst_ptr + idx, exif_buffer, exif_buffer_size);
1547 idx += exif_buffer_size;
1548 } else {
1549 // Application Segment - JFIF standard 1.01.
1550 static const uint8_t kAppSegment[] = {
1551 0xFF, JPEG_APP0, 0x00,
1552 0x10, // Segment length:16 (2-byte).
1553 0x4A, // J
1554 0x46, // F
1555 0x49, // I
1556 0x46, // F
1557 0x00, // 0
1558 0x01, // Major version.
1559 0x01, // Minor version.
1560 0x01, // Density units 0:no units, 1:pixels per inch,
1561 // 2: pixels per cm.
1562 0x00,
1563 0x48, // X density (2-byte).
1564 0x00,
1565 0x48, // Y density (2-byte).
1566 0x00, // Thumbnail width.
1567 0x00 // Thumbnail height.
1568 };
1569
1570 // Move compressed data first.
1571 size_t compressed_data_offset =
1572 sizeof(kJpegStart) + sizeof(kAppSegment) + jpeg_markers_.size();
1573 memmove(dst_ptr + compressed_data_offset, dst_ptr, buffer_size);
1574
1575 memcpy(dst_ptr, kJpegStart, sizeof(kJpegStart));
1576 idx += sizeof(kJpegStart);
1577
1578 memcpy(dst_ptr + idx, kAppSegment, sizeof(kAppSegment));
1579 idx += sizeof(kAppSegment);
1580 }
1581
1582 switch (output_buffer_pixelformat_) {
1583 case V4L2_PIX_FMT_JPEG_RAW:
1584 // Fill the other jpeg markers for RAW JPEG.
1585 memcpy(dst_ptr + idx, jpeg_markers_.data(), jpeg_markers_.size());
1586 idx += jpeg_markers_.size();
1587 // We already moved the compressed data.
1588 idx += buffer_size;
1589 // Fill EOI. Before Fill EOI we checked if the V4L2 device filled EOI
1590 // first.
1591 if (dst_ptr[idx - 2] != 0xFF && dst_ptr[idx - 1] != JPEG_EOI) {
1592 dst_ptr[idx] = 0xFF;
1593 dst_ptr[idx + 1] = JPEG_EOI;
1594 idx += 2;
1595 }
1596 break;
1597
1598 default:
1599 NOTREACHED() << "Unsupported output pixel format";
1600 }
1601
1602 output_gmb_buffer->Unmap();
1603
1604 return idx;
1605 }
1606
Dequeue()1607 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::Dequeue() {
1608 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1609 // Dequeue completed input (VIDEO_OUTPUT) buffers,
1610 // and recycle to the free list.
1611 struct v4l2_buffer dqbuf;
1612 struct v4l2_plane planes[kMaxNV12Plane];
1613 while (InputBufferQueuedCount() > 0) {
1614 DCHECK(input_streamon_);
1615 memset(&dqbuf, 0, sizeof(dqbuf));
1616 memset(planes, 0, sizeof(planes));
1617 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1618 dqbuf.memory = V4L2_MEMORY_DMABUF;
1619 dqbuf.length = base::size(planes);
1620 dqbuf.m.planes = planes;
1621 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
1622 if (errno == EAGAIN) {
1623 // EAGAIN if we're just out of buffers to dequeue.
1624 break;
1625 }
1626 VPLOGF(1) << "ioctl() failed: input buffer VIDIOC_DQBUF failed.";
1627 NotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
1628 return;
1629 }
1630 free_input_buffers_.push_back(dqbuf.index);
1631
1632 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
1633 VLOGF(1) << "Error in dequeued input buffer.";
1634 NotifyError(kInvalidBitstreamBufferId, PARSE_IMAGE_FAILED);
1635 running_job_queue_.pop();
1636 }
1637 }
1638
1639 // Dequeue completed output (VIDEO_CAPTURE) buffers, recycle to the free list.
1640 // Return the finished buffer to the client via the job ready callback.
1641 // If dequeued input buffer has an error, the error frame has removed from
1642 // |running_job_queue_|. We only have to dequeue output buffer when we
1643 // actually have pending frames in |running_job_queue_| and also enqueued
1644 // output buffers.
1645 while (!running_job_queue_.empty() && OutputBufferQueuedCount() > 0) {
1646 DCHECK(output_streamon_);
1647 memset(&dqbuf, 0, sizeof(dqbuf));
1648 memset(planes, 0, sizeof(planes));
1649 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1650 dqbuf.memory = V4L2_MEMORY_DMABUF;
1651 dqbuf.length = base::size(planes);
1652 dqbuf.m.planes = planes;
1653 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
1654 if (errno == EAGAIN) {
1655 // EAGAIN if we're just out of buffers to dequeue.
1656 break;
1657 }
1658 VPLOGF(1) << "ioctl() failed: output buffer VIDIOC_DQBUF failed.";
1659 NotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
1660 return;
1661 }
1662 free_output_buffers_.push_back(dqbuf.index);
1663
1664 // Jobs are always processed in FIFO order.
1665 std::unique_ptr<JobRecord> job_record =
1666 std::move(running_job_queue_.front());
1667 running_job_queue_.pop();
1668
1669 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
1670 VLOGF(1) << "Error in dequeued output buffer.";
1671 NotifyError(kInvalidBitstreamBufferId, PARSE_IMAGE_FAILED);
1672 return;
1673 }
1674
1675 size_t jpeg_size =
1676 FinalizeJpegImage(job_record->output_frame, planes[0].bytesused,
1677 std::move(job_record->exif_shm));
1678
1679 if (!jpeg_size) {
1680 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1681 return;
1682 }
1683 DVLOGF(4) << "Encoding finished, returning bitstream buffer, id="
1684 << job_record->task_id;
1685
1686 parent_->VideoFrameReady(job_record->task_id, jpeg_size);
1687 }
1688 }
1689
NotifyError(int32_t task_id,Status status)1690 void V4L2JpegEncodeAccelerator::EncodedInstanceDmaBuf::NotifyError(
1691 int32_t task_id,
1692 Status status) {
1693 DCHECK(parent_->encoder_task_runner_->BelongsToCurrentThread());
1694 parent_->NotifyError(task_id, status);
1695 }
1696
V4L2JpegEncodeAccelerator(const scoped_refptr<base::SingleThreadTaskRunner> & io_task_runner)1697 V4L2JpegEncodeAccelerator::V4L2JpegEncodeAccelerator(
1698 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
1699 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
1700 io_task_runner_(io_task_runner),
1701 client_(nullptr),
1702 encoder_thread_("V4L2JpegEncodeThread"),
1703 weak_factory_(this) {
1704 weak_ptr_ = weak_factory_.GetWeakPtr();
1705 }
1706
~V4L2JpegEncodeAccelerator()1707 V4L2JpegEncodeAccelerator::~V4L2JpegEncodeAccelerator() {
1708 DCHECK(child_task_runner_->BelongsToCurrentThread());
1709
1710 if (encoder_thread_.IsRunning()) {
1711 encoder_task_runner_->PostTask(
1712 FROM_HERE, base::BindOnce(&V4L2JpegEncodeAccelerator::DestroyTask,
1713 base::Unretained(this)));
1714 encoder_thread_.Stop();
1715 }
1716 weak_factory_.InvalidateWeakPtrs();
1717 }
1718
DestroyTask()1719 void V4L2JpegEncodeAccelerator::DestroyTask() {
1720 DCHECK(encoder_task_runner_->BelongsToCurrentThread());
1721
1722 while (!encoded_instances_.empty()) {
1723 encoded_instances_.front()->DestroyTask();
1724 encoded_instances_.pop();
1725 }
1726
1727 while (!encoded_instances_dma_buf_.empty()) {
1728 encoded_instances_dma_buf_.front()->DestroyTask();
1729 encoded_instances_dma_buf_.pop();
1730 }
1731 }
1732
VideoFrameReady(int32_t task_id,size_t encoded_picture_size)1733 void V4L2JpegEncodeAccelerator::VideoFrameReady(int32_t task_id,
1734 size_t encoded_picture_size) {
1735 if (!child_task_runner_->BelongsToCurrentThread()) {
1736 child_task_runner_->PostTask(
1737 FROM_HERE, base::BindOnce(&V4L2JpegEncodeAccelerator::VideoFrameReady,
1738 weak_ptr_, task_id, encoded_picture_size));
1739 return;
1740 }
1741 VLOGF(1) << "Encoding finished task id=" << task_id
1742 << " Compressed size:" << encoded_picture_size;
1743 client_->VideoFrameReady(task_id, encoded_picture_size);
1744 }
1745
NotifyError(int32_t task_id,Status status)1746 void V4L2JpegEncodeAccelerator::NotifyError(int32_t task_id, Status status) {
1747 if (!child_task_runner_->BelongsToCurrentThread()) {
1748 child_task_runner_->PostTask(
1749 FROM_HERE, base::BindOnce(&V4L2JpegEncodeAccelerator::NotifyError,
1750 weak_ptr_, task_id, status));
1751
1752 return;
1753 }
1754 VLOGF(1) << "Notifying of error " << status << " for task id " << task_id;
1755 client_->NotifyError(task_id, status);
1756 }
1757
1758 chromeos_camera::JpegEncodeAccelerator::Status
Initialize(chromeos_camera::JpegEncodeAccelerator::Client * client)1759 V4L2JpegEncodeAccelerator::Initialize(
1760 chromeos_camera::JpegEncodeAccelerator::Client* client) {
1761 DCHECK(child_task_runner_->BelongsToCurrentThread());
1762
1763 std::unique_ptr<EncodedInstanceDmaBuf> encoded_device(
1764 new EncodedInstanceDmaBuf(this));
1765
1766 // We just check if we can initialize device here.
1767 if (!encoded_device->Initialize()) {
1768 VLOGF(1) << "Failed to initialize device";
1769 return HW_JPEG_ENCODE_NOT_SUPPORTED;
1770 }
1771
1772 if (!encoder_thread_.Start()) {
1773 VLOGF(1) << "encoder thread failed to start";
1774 return THREAD_CREATION_FAILED;
1775 }
1776
1777 client_ = client;
1778
1779 encoder_task_runner_ = encoder_thread_.task_runner();
1780
1781 VLOGF(2) << "V4L2JpegEncodeAccelerator initialized.";
1782 return ENCODE_OK;
1783 }
1784
GetMaxCodedBufferSize(const gfx::Size & picture_size)1785 size_t V4L2JpegEncodeAccelerator::GetMaxCodedBufferSize(
1786 const gfx::Size& picture_size) {
1787 return picture_size.GetArea() * 3 / 2 + kJpegDefaultHeaderSize;
1788 }
1789
Encode(scoped_refptr<media::VideoFrame> video_frame,int quality,BitstreamBuffer * exif_buffer,BitstreamBuffer output_buffer)1790 void V4L2JpegEncodeAccelerator::Encode(
1791 scoped_refptr<media::VideoFrame> video_frame,
1792 int quality,
1793 BitstreamBuffer* exif_buffer,
1794 BitstreamBuffer output_buffer) {
1795 DCHECK(io_task_runner_->BelongsToCurrentThread());
1796
1797 DVLOGF(4) << "task_id=" << output_buffer.id()
1798 << ", size=" << output_buffer.size();
1799
1800 if (quality <= 0 || quality > 100) {
1801 VLOGF(1) << "quality is not in range. " << quality;
1802 NotifyError(output_buffer.id(), INVALID_ARGUMENT);
1803 return;
1804 }
1805
1806 if (video_frame->format() != VideoPixelFormat::PIXEL_FORMAT_I420) {
1807 VLOGF(1) << "Format is not I420";
1808 NotifyError(output_buffer.id(), INVALID_ARGUMENT);
1809 return;
1810 }
1811
1812 if (exif_buffer) {
1813 VLOGF(4) << "EXIF size " << exif_buffer->size();
1814 if (exif_buffer->size() > kMaxMarkerSizeAllowed) {
1815 NotifyError(output_buffer.id(), INVALID_ARGUMENT);
1816 return;
1817 }
1818 }
1819
1820 std::unique_ptr<JobRecord> job_record(new JobRecord(
1821 video_frame, quality, exif_buffer, std::move(output_buffer)));
1822
1823 encoder_task_runner_->PostTask(
1824 FROM_HERE,
1825 base::BindOnce(&V4L2JpegEncodeAccelerator::EncodeTaskLegacy,
1826 base::Unretained(this), base::Passed(&job_record)));
1827 }
1828
EncodeWithDmaBuf(scoped_refptr<VideoFrame> input_frame,scoped_refptr<VideoFrame> output_frame,int quality,int32_t task_id,BitstreamBuffer * exif_buffer)1829 void V4L2JpegEncodeAccelerator::EncodeWithDmaBuf(
1830 scoped_refptr<VideoFrame> input_frame,
1831 scoped_refptr<VideoFrame> output_frame,
1832 int quality,
1833 int32_t task_id,
1834 BitstreamBuffer* exif_buffer) {
1835 DCHECK(io_task_runner_->BelongsToCurrentThread());
1836
1837 if (quality <= 0 || quality > 100) {
1838 VLOGF(1) << "quality is not in range. " << quality;
1839 NotifyError(task_id, INVALID_ARGUMENT);
1840 return;
1841 }
1842
1843 if (input_frame->format() != VideoPixelFormat::PIXEL_FORMAT_NV12) {
1844 VLOGF(1) << "Format is not NV12";
1845 NotifyError(task_id, INVALID_ARGUMENT);
1846 return;
1847 }
1848
1849 if (exif_buffer) {
1850 VLOGF(4) << "EXIF size " << exif_buffer->size();
1851 if (exif_buffer->size() > kMaxMarkerSizeAllowed) {
1852 NotifyError(task_id, INVALID_ARGUMENT);
1853 return;
1854 }
1855 }
1856
1857 std::unique_ptr<JobRecord> job_record(
1858 new JobRecord(input_frame, output_frame, quality, task_id, exif_buffer));
1859
1860 encoder_task_runner_->PostTask(
1861 FROM_HERE,
1862 base::BindOnce(&V4L2JpegEncodeAccelerator::EncodeTask,
1863 base::Unretained(this), base::Passed(&job_record)));
1864 }
1865
EncodeTaskLegacy(std::unique_ptr<JobRecord> job_record)1866 void V4L2JpegEncodeAccelerator::EncodeTaskLegacy(
1867 std::unique_ptr<JobRecord> job_record) {
1868 DCHECK(encoder_task_runner_->BelongsToCurrentThread());
1869 if (!job_record->output_shm.MapAt(job_record->output_offset,
1870 job_record->output_shm.size())) {
1871 VPLOGF(1) << "could not map I420 bitstream_buffer";
1872 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1873 return;
1874 }
1875 if (job_record->exif_shm &&
1876 !job_record->exif_shm->MapAt(job_record->exif_offset,
1877 job_record->exif_shm->size())) {
1878 VPLOGF(1) << "could not map exif bitstream_buffer";
1879 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1880 return;
1881 }
1882
1883 // Check if the parameters of input frame changes.
1884 // If it changes, we open a new device and put the job in it.
1885 // If it doesn't change, we use the same device as last used.
1886 gfx::Size coded_size = job_record->input_frame->coded_size();
1887 if (latest_input_buffer_coded_size_legacy_ != coded_size ||
1888 latest_quality_legacy_ != job_record->quality) {
1889 std::unique_ptr<EncodedInstance> encoded_device(new EncodedInstance(this));
1890 VLOGF(1) << "Open Device for quality " << job_record->quality
1891 << ", width: " << coded_size.width()
1892 << ", height: " << coded_size.height();
1893 if (!encoded_device->Initialize()) {
1894 VLOGF(1) << "Failed to initialize device";
1895 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1896 return;
1897 }
1898
1899 if (!encoded_device->SetUpJpegParameters(job_record->quality, coded_size)) {
1900 VLOGF(1) << "SetUpJpegParameters failed";
1901 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1902 return;
1903 }
1904
1905 if (!encoded_device->CreateBuffers(coded_size,
1906 job_record->output_shm.size())) {
1907 VLOGF(1) << "Create buffers failed.";
1908 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1909 return;
1910 }
1911
1912 latest_input_buffer_coded_size_legacy_ = coded_size;
1913 latest_quality_legacy_ = job_record->quality;
1914
1915 encoded_instances_.push(std::move(encoded_device));
1916 }
1917
1918 // Always use latest opened device for new job.
1919 encoded_instances_.back()->input_job_queue_.push(std::move(job_record));
1920
1921 ServiceDeviceTaskLegacy();
1922 }
1923
EncodeTask(std::unique_ptr<JobRecord> job_record)1924 void V4L2JpegEncodeAccelerator::EncodeTask(
1925 std::unique_ptr<JobRecord> job_record) {
1926 DCHECK(encoder_task_runner_->BelongsToCurrentThread());
1927 if (job_record->exif_shm &&
1928 !job_record->exif_shm->MapAt(job_record->exif_offset,
1929 job_record->exif_shm->size())) {
1930 VPLOGF(1) << "could not map exif bitstream_buffer";
1931 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1932 return;
1933 }
1934
1935 // Check if the parameters of input frame changes.
1936 // If it changes, we open a new device and put the job in it.
1937 // If it doesn't change, we use the same device as last used.
1938 gfx::Size coded_size = job_record->input_frame->coded_size();
1939 if (latest_input_buffer_coded_size_ != coded_size ||
1940 latest_quality_ != job_record->quality) {
1941 std::unique_ptr<EncodedInstanceDmaBuf> encoded_device(
1942 new EncodedInstanceDmaBuf(this));
1943 VLOGF(1) << "Open Device for quality " << job_record->quality
1944 << ", width: " << coded_size.width()
1945 << ", height: " << coded_size.height();
1946 if (!encoded_device->Initialize()) {
1947 VLOGF(1) << "Failed to initialize device";
1948 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1949 return;
1950 }
1951
1952 if (!encoded_device->SetUpJpegParameters(job_record->quality, coded_size)) {
1953 VLOGF(1) << "SetUpJpegParameters failed";
1954 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1955 return;
1956 }
1957
1958 // The output buffer size is coded in the first plane's size.
1959 if (!encoded_device->CreateBuffers(
1960 coded_size, job_record->input_frame->layout(),
1961 job_record->output_frame->layout().planes()[0].size)) {
1962 VLOGF(1) << "Create buffers failed.";
1963 NotifyError(job_record->task_id, PLATFORM_FAILURE);
1964 return;
1965 }
1966
1967 latest_input_buffer_coded_size_ = coded_size;
1968 latest_quality_ = job_record->quality;
1969
1970 encoded_instances_dma_buf_.push(std::move(encoded_device));
1971 }
1972
1973 // Always use latest opened device for new job.
1974 encoded_instances_dma_buf_.back()->input_job_queue_.push(
1975 std::move(job_record));
1976
1977 ServiceDeviceTask();
1978 }
1979
ServiceDeviceTaskLegacy()1980 void V4L2JpegEncodeAccelerator::ServiceDeviceTaskLegacy() {
1981 DCHECK(encoder_task_runner_->BelongsToCurrentThread());
1982
1983 // Always service the first device to keep the input order.
1984 encoded_instances_.front()->ServiceDevice();
1985
1986 // If we have more than 1 devices, we can remove the oldest one after all jobs
1987 // finished.
1988 if (encoded_instances_.size() > 1) {
1989 if (encoded_instances_.front()->running_job_queue_.empty() &&
1990 encoded_instances_.front()->input_job_queue_.empty()) {
1991 encoded_instances_.pop();
1992 }
1993 }
1994
1995 if (!encoded_instances_.front()->running_job_queue_.empty() ||
1996 !encoded_instances_.front()->input_job_queue_.empty()) {
1997 encoder_task_runner_->PostTask(
1998 FROM_HERE,
1999 base::BindOnce(&V4L2JpegEncodeAccelerator::ServiceDeviceTaskLegacy,
2000 base::Unretained(this)));
2001 }
2002 }
2003
ServiceDeviceTask()2004 void V4L2JpegEncodeAccelerator::ServiceDeviceTask() {
2005 DCHECK(encoder_task_runner_->BelongsToCurrentThread());
2006
2007 // Always service the first device to keep the input order.
2008 encoded_instances_dma_buf_.front()->ServiceDevice();
2009
2010 // If we have more than 1 devices, we can remove the oldest one after all jobs
2011 // finished.
2012 if (encoded_instances_dma_buf_.size() > 1) {
2013 if (encoded_instances_dma_buf_.front()->running_job_queue_.empty() &&
2014 encoded_instances_dma_buf_.front()->input_job_queue_.empty()) {
2015 encoded_instances_dma_buf_.pop();
2016 }
2017 }
2018
2019 if (!encoded_instances_dma_buf_.front()->running_job_queue_.empty() ||
2020 !encoded_instances_dma_buf_.front()->input_job_queue_.empty()) {
2021 encoder_task_runner_->PostTask(
2022 FROM_HERE, base::BindOnce(&V4L2JpegEncodeAccelerator::ServiceDeviceTask,
2023 base::Unretained(this)));
2024 }
2025 }
2026
2027 } // namespace media
2028