1 // Copyright 2014 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.
6 #include <linux/videodev2.h>
8 #include <sys/eventfd.h>
12 #include "base/callback.h"
13 #include "base/command_line.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/numerics/safe_conversions.h"
16 #include "base/trace_event/trace_event.h"
17 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
18 #include "content/public/common/content_switches.h"
19 #include "media/base/bitstream_buffer.h"
21 #define NOTIFY_ERROR(x) \
23 LOG(ERROR) << "Setting error state:" << x; \
27 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \
29 if (device_->Ioctl(type, arg) != 0) { \
30 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
31 NOTIFY_ERROR(kPlatformFailureError); \
36 #define IOCTL_OR_ERROR_RETURN(type, arg) \
37 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0))
39 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
40 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false)
42 #define IOCTL_OR_LOG_ERROR(type, arg) \
44 if (device_->Ioctl(type, arg) != 0) \
45 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
50 struct V4L2VideoEncodeAccelerator::BitstreamBufferRef
{
51 BitstreamBufferRef(int32 id
, scoped_ptr
<base::SharedMemory
> shm
, size_t size
)
52 : id(id
), shm(shm
.Pass()), size(size
) {}
54 const scoped_ptr
<base::SharedMemory
> shm
;
58 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {
61 V4L2VideoEncodeAccelerator::InputRecord::~InputRecord() {
64 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord()
65 : at_device(false), address(NULL
), length(0) {
68 V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() {
71 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator(
72 const scoped_refptr
<V4L2Device
>& device
)
73 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
74 output_buffer_byte_size_(0),
75 device_input_format_(media::VideoFrame::UNKNOWN
),
76 input_planes_count_(0),
77 output_format_fourcc_(0),
78 encoder_state_(kUninitialized
),
79 stream_header_size_(0),
81 input_streamon_(false),
82 input_buffer_queued_count_(0),
83 input_memory_type_(V4L2_MEMORY_USERPTR
),
84 output_streamon_(false),
85 output_buffer_queued_count_(0),
86 encoder_thread_("V4L2EncoderThread"),
87 device_poll_thread_("V4L2EncoderDevicePollThread"),
88 weak_this_ptr_factory_(this) {
89 weak_this_
= weak_this_ptr_factory_
.GetWeakPtr();
92 V4L2VideoEncodeAccelerator::~V4L2VideoEncodeAccelerator() {
93 DCHECK(!encoder_thread_
.IsRunning());
94 DCHECK(!device_poll_thread_
.IsRunning());
97 DestroyInputBuffers();
98 DestroyOutputBuffers();
101 bool V4L2VideoEncodeAccelerator::Initialize(
102 media::VideoFrame::Format input_format
,
103 const gfx::Size
& input_visible_size
,
104 media::VideoCodecProfile output_profile
,
105 uint32 initial_bitrate
,
107 DVLOG(3) << __func__
<< ": input_format="
108 << media::VideoFrame::FormatToString(input_format
)
109 << ", input_visible_size=" << input_visible_size
.ToString()
110 << ", output_profile=" << output_profile
111 << ", initial_bitrate=" << initial_bitrate
;
113 visible_size_
= input_visible_size
;
115 client_ptr_factory_
.reset(new base::WeakPtrFactory
<Client
>(client
));
116 client_
= client_ptr_factory_
->GetWeakPtr();
118 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
119 DCHECK_EQ(encoder_state_
, kUninitialized
);
121 struct v4l2_capability caps
;
122 memset(&caps
, 0, sizeof(caps
));
123 const __u32 kCapsRequired
= V4L2_CAP_VIDEO_CAPTURE_MPLANE
|
124 V4L2_CAP_VIDEO_OUTPUT_MPLANE
| V4L2_CAP_STREAMING
;
125 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP
, &caps
);
126 if ((caps
.capabilities
& kCapsRequired
) != kCapsRequired
) {
127 LOG(ERROR
) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
128 "caps check failed: 0x" << std::hex
<< caps
.capabilities
;
132 if (!SetFormats(input_format
, output_profile
)) {
133 LOG(ERROR
) << "Failed setting up formats";
137 if (input_format
!= device_input_format_
) {
138 DVLOG(1) << "Input format not supported by the HW, will convert to "
139 << media::VideoFrame::FormatToString(device_input_format_
);
141 scoped_refptr
<V4L2Device
> device
=
142 V4L2Device::Create(V4L2Device::kImageProcessor
);
143 image_processor_
.reset(new V4L2ImageProcessor(device
));
145 // Convert from input_format to device_input_format_, keeping the size
146 // at visible_size_ and requiring the output buffers to be of at least
147 // input_allocated_size_.
148 if (!image_processor_
->Initialize(
150 device_input_format_
,
153 input_allocated_size_
,
154 base::Bind(&V4L2VideoEncodeAccelerator::ImageProcessorError
,
156 LOG(ERROR
) << "Failed initializing image processor";
164 if (!CreateOutputBuffers())
167 if (!encoder_thread_
.Start()) {
168 LOG(ERROR
) << "Initialize(): encoder thread failed to start";
172 RequestEncodingParametersChange(initial_bitrate
, kInitialFramerate
);
174 encoder_state_
= kInitialized
;
176 child_message_loop_proxy_
->PostTask(
178 base::Bind(&Client::RequireBitstreamBuffers
,
181 image_processor_
.get() ?
182 image_processor_
->input_allocated_size() :
183 input_allocated_size_
,
184 output_buffer_byte_size_
));
188 void V4L2VideoEncodeAccelerator::ImageProcessorError() {
189 LOG(ERROR
) << "Image processor error";
190 NOTIFY_ERROR(kPlatformFailureError
);
193 void V4L2VideoEncodeAccelerator::Encode(
194 const scoped_refptr
<media::VideoFrame
>& frame
,
195 bool force_keyframe
) {
196 DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe
;
197 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
199 if (image_processor_
) {
200 image_processor_
->Process(
202 base::Bind(&V4L2VideoEncodeAccelerator::FrameProcessed
,
206 encoder_thread_
.message_loop()->PostTask(
208 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask
,
209 base::Unretained(this),
215 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer(
216 const media::BitstreamBuffer
& buffer
) {
217 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer
.id();
218 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
220 if (buffer
.size() < output_buffer_byte_size_
) {
221 NOTIFY_ERROR(kInvalidArgumentError
);
225 scoped_ptr
<base::SharedMemory
> shm(
226 new base::SharedMemory(buffer
.handle(), false));
227 if (!shm
->Map(buffer
.size())) {
228 NOTIFY_ERROR(kPlatformFailureError
);
232 scoped_ptr
<BitstreamBufferRef
> buffer_ref(
233 new BitstreamBufferRef(buffer
.id(), shm
.Pass(), buffer
.size()));
234 encoder_thread_
.message_loop()->PostTask(
236 base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask
,
237 base::Unretained(this),
238 base::Passed(&buffer_ref
)));
241 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange(
244 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
245 << ", framerate=" << framerate
;
246 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
248 encoder_thread_
.message_loop()->PostTask(
251 &V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask
,
252 base::Unretained(this),
257 void V4L2VideoEncodeAccelerator::Destroy() {
258 DVLOG(3) << "Destroy()";
259 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
261 // We're destroying; cancel all callbacks.
262 client_ptr_factory_
.reset();
263 weak_this_ptr_factory_
.InvalidateWeakPtrs();
265 if (image_processor_
.get())
266 image_processor_
.release()->Destroy();
268 // If the encoder thread is running, destroy using posted task.
269 if (encoder_thread_
.IsRunning()) {
270 encoder_thread_
.message_loop()->PostTask(
272 base::Bind(&V4L2VideoEncodeAccelerator::DestroyTask
,
273 base::Unretained(this)));
274 // DestroyTask() will put the encoder into kError state and cause all tasks
276 encoder_thread_
.Stop();
278 // Otherwise, call the destroy task directly.
282 // Set to kError state just in case.
283 encoder_state_
= kError
;
288 std::vector
<media::VideoEncodeAccelerator::SupportedProfile
>
289 V4L2VideoEncodeAccelerator::GetSupportedProfiles() {
290 std::vector
<SupportedProfile
> profiles
;
291 SupportedProfile profile
;
292 profile
.max_resolution
.SetSize(1920, 1088);
293 profile
.max_framerate_numerator
= 30;
294 profile
.max_framerate_denominator
= 1;
296 v4l2_fmtdesc fmtdesc
;
297 memset(&fmtdesc
, 0, sizeof(fmtdesc
));
298 fmtdesc
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
299 for (; device_
->Ioctl(VIDIOC_ENUM_FMT
, &fmtdesc
) == 0; ++fmtdesc
.index
) {
300 switch (fmtdesc
.pixelformat
) {
301 case V4L2_PIX_FMT_H264
:
302 profile
.profile
= media::H264PROFILE_MAIN
;
303 profiles
.push_back(profile
);
305 case V4L2_PIX_FMT_VP8
:
306 profile
.profile
= media::VP8PROFILE_ANY
;
307 profiles
.push_back(profile
);
315 void V4L2VideoEncodeAccelerator::FrameProcessed(
317 const scoped_refptr
<media::VideoFrame
>& frame
) {
318 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
319 DVLOG(3) << "FrameProcessed(): force_keyframe=" << force_keyframe
;
321 encoder_thread_
.message_loop()->PostTask(
323 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask
,
324 base::Unretained(this),
329 void V4L2VideoEncodeAccelerator::EncodeTask(
330 const scoped_refptr
<media::VideoFrame
>& frame
,
331 bool force_keyframe
) {
332 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe
;
333 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
334 DCHECK_NE(encoder_state_
, kUninitialized
);
336 if (encoder_state_
== kError
) {
337 DVLOG(2) << "EncodeTask(): early out: kError state";
341 encoder_input_queue_
.push_back(frame
);
344 if (force_keyframe
) {
345 // TODO(posciak): this presently makes for slightly imprecise encoding
346 // parameters updates. To precisely align the parameter updates with the
347 // incoming input frame, we should queue the parameters together with the
348 // frame onto encoder_input_queue_ and apply them when the input is about
349 // to be queued to the codec.
350 std::vector
<struct v4l2_ext_control
> ctrls
;
351 struct v4l2_ext_control ctrl
;
352 memset(&ctrl
, 0, sizeof(ctrl
));
353 ctrl
.id
= V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE
;
354 ctrl
.value
= V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME
;
355 ctrls
.push_back(ctrl
);
356 if (!SetExtCtrls(ctrls
)) {
357 LOG(ERROR
) << "Failed requesting keyframe";
358 NOTIFY_ERROR(kPlatformFailureError
);
364 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask(
365 scoped_ptr
<BitstreamBufferRef
> buffer_ref
) {
366 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref
->id
;
367 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
369 encoder_output_queue_
.push_back(
370 linked_ptr
<BitstreamBufferRef
>(buffer_ref
.release()));
373 if (encoder_state_
== kInitialized
) {
374 // Finish setting up our OUTPUT queue. See: Initialize().
375 // VIDIOC_REQBUFS on OUTPUT queue.
376 if (!CreateInputBuffers())
378 if (!StartDevicePoll())
380 encoder_state_
= kEncoding
;
384 void V4L2VideoEncodeAccelerator::DestroyTask() {
385 DVLOG(3) << "DestroyTask()";
387 // DestroyTask() should run regardless of encoder_state_.
389 // Stop streaming and the device_poll_thread_.
392 // Set our state to kError, and early-out all tasks.
393 encoder_state_
= kError
;
396 void V4L2VideoEncodeAccelerator::ServiceDeviceTask() {
397 DVLOG(3) << "ServiceDeviceTask()";
398 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
399 DCHECK_NE(encoder_state_
, kUninitialized
);
400 DCHECK_NE(encoder_state_
, kInitialized
);
402 if (encoder_state_
== kError
) {
403 DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
410 // Clear the interrupt fd.
411 if (!device_
->ClearDevicePollInterrupt())
414 // Device can be polled as soon as either input or output buffers are queued.
416 (input_buffer_queued_count_
+ output_buffer_queued_count_
> 0);
418 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
420 // * device_poll_thread_ is running normally
421 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
422 // in which case we're in kError state, and we should have early-outed
424 DCHECK(device_poll_thread_
.message_loop());
425 // Queue the DevicePollTask() now.
426 device_poll_thread_
.message_loop()->PostTask(
428 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask
,
429 base::Unretained(this),
432 DVLOG(2) << __func__
<< ": buffer counts: ENC["
433 << encoder_input_queue_
.size() << "] => DEVICE["
434 << free_input_buffers_
.size() << "+"
435 << input_buffer_queued_count_
<< "/"
436 << input_buffer_map_
.size() << "->"
437 << free_output_buffers_
.size() << "+"
438 << output_buffer_queued_count_
<< "/"
439 << output_buffer_map_
.size() << "] => OUT["
440 << encoder_output_queue_
.size() << "]";
443 void V4L2VideoEncodeAccelerator::Enqueue() {
444 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
446 DVLOG(3) << "Enqueue() "
447 << "free_input_buffers: " << free_input_buffers_
.size()
448 << "input_queue: " << encoder_input_queue_
.size();
450 // Enqueue all the inputs we can.
451 const int old_inputs_queued
= input_buffer_queued_count_
;
452 // while (!ready_input_buffers_.empty()) {
453 while (!encoder_input_queue_
.empty() && !free_input_buffers_
.empty()) {
454 if (!EnqueueInputRecord())
457 if (old_inputs_queued
== 0 && input_buffer_queued_count_
!= 0) {
458 // We just started up a previously empty queue.
459 // Queue state changed; signal interrupt.
460 if (!device_
->SetDevicePollInterrupt())
462 // Start VIDIOC_STREAMON if we haven't yet.
463 if (!input_streamon_
) {
464 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
465 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON
, &type
);
466 input_streamon_
= true;
470 // Enqueue all the outputs we can.
471 const int old_outputs_queued
= output_buffer_queued_count_
;
472 while (!free_output_buffers_
.empty() && !encoder_output_queue_
.empty()) {
473 if (!EnqueueOutputRecord())
476 if (old_outputs_queued
== 0 && output_buffer_queued_count_
!= 0) {
477 // We just started up a previously empty queue.
478 // Queue state changed; signal interrupt.
479 if (!device_
->SetDevicePollInterrupt())
481 // Start VIDIOC_STREAMON if we haven't yet.
482 if (!output_streamon_
) {
483 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
484 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON
, &type
);
485 output_streamon_
= true;
490 void V4L2VideoEncodeAccelerator::Dequeue() {
491 DVLOG(3) << "Dequeue()";
492 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
494 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free
496 struct v4l2_buffer dqbuf
;
497 struct v4l2_plane planes
[VIDEO_MAX_PLANES
];
498 while (input_buffer_queued_count_
> 0) {
499 DVLOG(4) << "inputs queued: " << input_buffer_queued_count_
;
500 DCHECK(input_streamon_
);
501 memset(&dqbuf
, 0, sizeof(dqbuf
));
502 memset(&planes
, 0, sizeof(planes
));
503 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
504 dqbuf
.memory
= input_memory_type_
;
505 dqbuf
.m
.planes
= planes
;
506 dqbuf
.length
= input_planes_count_
;
507 if (device_
->Ioctl(VIDIOC_DQBUF
, &dqbuf
) != 0) {
508 if (errno
== EAGAIN
) {
509 // EAGAIN if we're just out of buffers to dequeue.
512 PLOG(ERROR
) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF";
513 NOTIFY_ERROR(kPlatformFailureError
);
516 InputRecord
& input_record
= input_buffer_map_
[dqbuf
.index
];
517 DCHECK(input_record
.at_device
);
518 input_record
.at_device
= false;
520 input_record
.frame
= NULL
;
521 free_input_buffers_
.push_back(dqbuf
.index
);
522 input_buffer_queued_count_
--;
525 // Dequeue completed output (VIDEO_CAPTURE) buffers, and recycle to the
526 // free list. Notify the client that an output buffer is complete.
527 while (output_buffer_queued_count_
> 0) {
528 DCHECK(output_streamon_
);
529 memset(&dqbuf
, 0, sizeof(dqbuf
));
530 memset(planes
, 0, sizeof(planes
));
531 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
532 dqbuf
.memory
= V4L2_MEMORY_MMAP
;
533 dqbuf
.m
.planes
= planes
;
535 if (device_
->Ioctl(VIDIOC_DQBUF
, &dqbuf
) != 0) {
536 if (errno
== EAGAIN
) {
537 // EAGAIN if we're just out of buffers to dequeue.
540 PLOG(ERROR
) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF";
541 NOTIFY_ERROR(kPlatformFailureError
);
544 const bool key_frame
= ((dqbuf
.flags
& V4L2_BUF_FLAG_KEYFRAME
) != 0);
545 OutputRecord
& output_record
= output_buffer_map_
[dqbuf
.index
];
546 DCHECK(output_record
.at_device
);
547 DCHECK(output_record
.buffer_ref
.get());
549 void* output_data
= output_record
.address
;
550 size_t output_size
= dqbuf
.m
.planes
[0].bytesused
;
551 // This shouldn't happen, but just in case. We should be able to recover
552 // after next keyframe after showing some corruption.
553 DCHECK_LE(output_size
, output_buffer_byte_size_
);
554 if (output_size
> output_buffer_byte_size_
)
555 output_size
= output_buffer_byte_size_
;
557 reinterpret_cast<uint8
*>(output_record
.buffer_ref
->shm
->memory());
558 if (output_format_fourcc_
== V4L2_PIX_FMT_H264
) {
559 if (stream_header_size_
== 0) {
560 // Assume that the first buffer dequeued is the stream header.
561 stream_header_size_
= output_size
;
562 stream_header_
.reset(new uint8
[stream_header_size_
]);
563 memcpy(stream_header_
.get(), output_data
, stream_header_size_
);
566 output_buffer_byte_size_
- stream_header_size_
>= output_size
) {
567 // Insert stream header before every keyframe.
568 memcpy(target_data
, stream_header_
.get(), stream_header_size_
);
569 memcpy(target_data
+ stream_header_size_
, output_data
, output_size
);
570 output_size
+= stream_header_size_
;
572 memcpy(target_data
, output_data
, output_size
);
575 memcpy(target_data
, output_data
, output_size
);
578 DVLOG(3) << "Dequeue(): returning "
579 "bitstream_buffer_id=" << output_record
.buffer_ref
->id
580 << ", size=" << output_size
<< ", key_frame=" << key_frame
;
581 child_message_loop_proxy_
->PostTask(
583 base::Bind(&Client::BitstreamBufferReady
,
585 output_record
.buffer_ref
->id
,
588 output_record
.at_device
= false;
589 output_record
.buffer_ref
.reset();
590 free_output_buffers_
.push_back(dqbuf
.index
);
591 output_buffer_queued_count_
--;
595 bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
596 DVLOG(3) << "EnqueueInputRecord()";
597 DCHECK(!free_input_buffers_
.empty());
598 DCHECK(!encoder_input_queue_
.empty());
600 // Enqueue an input (VIDEO_OUTPUT) buffer.
601 scoped_refptr
<media::VideoFrame
> frame
= encoder_input_queue_
.front();
602 const int index
= free_input_buffers_
.back();
603 InputRecord
& input_record
= input_buffer_map_
[index
];
604 DCHECK(!input_record
.at_device
);
605 struct v4l2_buffer qbuf
;
606 struct v4l2_plane qbuf_planes
[VIDEO_MAX_PLANES
];
607 memset(&qbuf
, 0, sizeof(qbuf
));
608 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
610 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
611 qbuf
.m
.planes
= qbuf_planes
;
613 DCHECK_EQ(device_input_format_
, frame
->format());
614 for (size_t i
= 0; i
< input_planes_count_
; ++i
) {
615 qbuf
.m
.planes
[i
].bytesused
=
616 base::checked_cast
<__u32
>(media::VideoFrame::PlaneAllocationSize(
617 frame
->format(), i
, input_allocated_size_
));
619 switch (input_memory_type_
) {
620 case V4L2_MEMORY_USERPTR
:
621 qbuf
.m
.planes
[i
].length
= qbuf
.m
.planes
[i
].bytesused
;
622 qbuf
.m
.planes
[i
].m
.userptr
=
623 reinterpret_cast<unsigned long>(frame
->data(i
));
624 DCHECK(qbuf
.m
.planes
[i
].m
.userptr
);
627 case V4L2_MEMORY_DMABUF
:
628 qbuf
.m
.planes
[i
].m
.fd
= frame
->dmabuf_fd(i
);
629 DCHECK_NE(qbuf
.m
.planes
[i
].m
.fd
, -1);
638 qbuf
.memory
= input_memory_type_
;
639 qbuf
.length
= input_planes_count_
;
641 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF
, &qbuf
);
642 input_record
.at_device
= true;
643 input_record
.frame
= frame
;
644 encoder_input_queue_
.pop_front();
645 free_input_buffers_
.pop_back();
646 input_buffer_queued_count_
++;
650 bool V4L2VideoEncodeAccelerator::EnqueueOutputRecord() {
651 DVLOG(3) << "EnqueueOutputRecord()";
652 DCHECK(!free_output_buffers_
.empty());
653 DCHECK(!encoder_output_queue_
.empty());
655 // Enqueue an output (VIDEO_CAPTURE) buffer.
656 linked_ptr
<BitstreamBufferRef
> output_buffer
= encoder_output_queue_
.back();
657 const int index
= free_output_buffers_
.back();
658 OutputRecord
& output_record
= output_buffer_map_
[index
];
659 DCHECK(!output_record
.at_device
);
660 DCHECK(!output_record
.buffer_ref
.get());
661 struct v4l2_buffer qbuf
;
662 struct v4l2_plane qbuf_planes
[1];
663 memset(&qbuf
, 0, sizeof(qbuf
));
664 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
666 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
667 qbuf
.memory
= V4L2_MEMORY_MMAP
;
668 qbuf
.m
.planes
= qbuf_planes
;
670 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF
, &qbuf
);
671 output_record
.at_device
= true;
672 output_record
.buffer_ref
= output_buffer
;
673 encoder_output_queue_
.pop_back();
674 free_output_buffers_
.pop_back();
675 output_buffer_queued_count_
++;
679 bool V4L2VideoEncodeAccelerator::StartDevicePoll() {
680 DVLOG(3) << "StartDevicePoll()";
681 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
682 DCHECK(!device_poll_thread_
.IsRunning());
684 // Start up the device poll thread and schedule its first DevicePollTask().
685 if (!device_poll_thread_
.Start()) {
686 LOG(ERROR
) << "StartDevicePoll(): Device thread failed to start";
687 NOTIFY_ERROR(kPlatformFailureError
);
690 // Enqueue a poll task with no devices to poll on -- it will wait only on the
692 device_poll_thread_
.message_loop()->PostTask(
694 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask
,
695 base::Unretained(this),
701 bool V4L2VideoEncodeAccelerator::StopDevicePoll() {
702 DVLOG(3) << "StopDevicePoll()";
704 // Signal the DevicePollTask() to stop, and stop the device poll thread.
705 if (!device_
->SetDevicePollInterrupt())
707 device_poll_thread_
.Stop();
708 // Clear the interrupt now, to be sure.
709 if (!device_
->ClearDevicePollInterrupt())
712 if (input_streamon_
) {
713 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
714 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF
, &type
);
716 input_streamon_
= false;
718 if (output_streamon_
) {
719 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
720 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF
, &type
);
722 output_streamon_
= false;
724 // Reset all our accounting info.
725 encoder_input_queue_
.clear();
726 free_input_buffers_
.clear();
727 for (size_t i
= 0; i
< input_buffer_map_
.size(); ++i
) {
728 InputRecord
& input_record
= input_buffer_map_
[i
];
729 input_record
.at_device
= false;
730 input_record
.frame
= NULL
;
731 free_input_buffers_
.push_back(i
);
733 input_buffer_queued_count_
= 0;
735 free_output_buffers_
.clear();
736 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
737 OutputRecord
& output_record
= output_buffer_map_
[i
];
738 output_record
.at_device
= false;
739 output_record
.buffer_ref
.reset();
740 free_output_buffers_
.push_back(i
);
742 output_buffer_queued_count_
= 0;
744 encoder_output_queue_
.clear();
746 DVLOG(3) << "StopDevicePoll(): device poll stopped";
750 void V4L2VideoEncodeAccelerator::DevicePollTask(bool poll_device
) {
751 DVLOG(3) << "DevicePollTask()";
752 DCHECK_EQ(device_poll_thread_
.message_loop(), base::MessageLoop::current());
755 if (!device_
->Poll(poll_device
, &event_pending
)) {
756 NOTIFY_ERROR(kPlatformFailureError
);
760 // All processing should happen on ServiceDeviceTask(), since we shouldn't
761 // touch encoder state from this thread.
762 encoder_thread_
.message_loop()->PostTask(
764 base::Bind(&V4L2VideoEncodeAccelerator::ServiceDeviceTask
,
765 base::Unretained(this)));
768 void V4L2VideoEncodeAccelerator::NotifyError(Error error
) {
769 DVLOG(1) << "NotifyError(): error=" << error
;
771 if (!child_message_loop_proxy_
->BelongsToCurrentThread()) {
772 child_message_loop_proxy_
->PostTask(
775 &V4L2VideoEncodeAccelerator::NotifyError
, weak_this_
, error
));
780 client_
->NotifyError(error
);
781 client_ptr_factory_
.reset();
785 void V4L2VideoEncodeAccelerator::SetErrorState(Error error
) {
786 // We can touch encoder_state_ only if this is the encoder thread or the
787 // encoder thread isn't running.
788 if (encoder_thread_
.message_loop() != NULL
&&
789 encoder_thread_
.message_loop() != base::MessageLoop::current()) {
790 encoder_thread_
.message_loop()->PostTask(
791 FROM_HERE
, base::Bind(&V4L2VideoEncodeAccelerator::SetErrorState
,
792 base::Unretained(this), error
));
796 // Post NotifyError only if we are already initialized, as the API does
797 // not allow doing so before that.
798 if (encoder_state_
!= kError
&& encoder_state_
!= kUninitialized
)
801 encoder_state_
= kError
;
804 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask(
807 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate
808 << ", framerate=" << framerate
;
809 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
816 std::vector
<struct v4l2_ext_control
> ctrls
;
817 struct v4l2_ext_control ctrl
;
818 memset(&ctrl
, 0, sizeof(ctrl
));
819 ctrl
.id
= V4L2_CID_MPEG_VIDEO_BITRATE
;
820 ctrl
.value
= bitrate
;
821 ctrls
.push_back(ctrl
);
822 if (!SetExtCtrls(ctrls
)) {
823 LOG(ERROR
) << "Failed changing bitrate";
824 NOTIFY_ERROR(kPlatformFailureError
);
828 struct v4l2_streamparm parms
;
829 memset(&parms
, 0, sizeof(parms
));
830 parms
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
831 // Note that we are provided "frames per second" but V4L2 expects "time per
832 // frame"; hence we provide the reciprocal of the framerate here.
833 parms
.parm
.output
.timeperframe
.numerator
= 1;
834 parms
.parm
.output
.timeperframe
.denominator
= framerate
;
835 IOCTL_OR_ERROR_RETURN(VIDIOC_S_PARM
, &parms
);
838 bool V4L2VideoEncodeAccelerator::SetOutputFormat(
839 media::VideoCodecProfile output_profile
) {
840 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
841 DCHECK(!input_streamon_
);
842 DCHECK(!output_streamon_
);
844 output_format_fourcc_
=
845 V4L2Device::VideoCodecProfileToV4L2PixFmt(output_profile
, false);
846 if (!output_format_fourcc_
) {
847 LOG(ERROR
) << "Initialize(): invalid output_profile=" << output_profile
;
851 output_buffer_byte_size_
= kOutputBufferSize
;
853 struct v4l2_format format
;
854 memset(&format
, 0, sizeof(format
));
855 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
856 format
.fmt
.pix_mp
.width
= visible_size_
.width();
857 format
.fmt
.pix_mp
.height
= visible_size_
.height();
858 format
.fmt
.pix_mp
.pixelformat
= output_format_fourcc_
;
859 format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
=
860 base::checked_cast
<__u32
>(output_buffer_byte_size_
);
861 format
.fmt
.pix_mp
.num_planes
= 1;
862 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT
, &format
);
864 // Device might have adjusted the required output size.
865 size_t adjusted_output_buffer_size
=
866 base::checked_cast
<size_t>(format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
);
867 DCHECK_GE(adjusted_output_buffer_size
, output_buffer_byte_size_
);
868 output_buffer_byte_size_
= adjusted_output_buffer_size
;
873 bool V4L2VideoEncodeAccelerator::NegotiateInputFormat(
874 media::VideoFrame::Format input_format
) {
875 DVLOG(3) << "NegotiateInputFormat()";
876 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
877 DCHECK(!input_streamon_
);
878 DCHECK(!output_streamon_
);
880 device_input_format_
= media::VideoFrame::UNKNOWN
;
881 input_planes_count_
= 0;
883 uint32 input_format_fourcc
=
884 V4L2Device::VideoFrameFormatToV4L2PixFmt(input_format
);
885 if (!input_format_fourcc
) {
886 LOG(ERROR
) << "Unsupported input format";
890 size_t input_planes_count
= media::VideoFrame::NumPlanes(input_format
);
891 DCHECK_LE(input_planes_count
, static_cast<size_t>(VIDEO_MAX_PLANES
));
893 // First see if we the device can use the provided input_format directly.
894 struct v4l2_format format
;
895 memset(&format
, 0, sizeof(format
));
896 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
897 format
.fmt
.pix_mp
.width
= visible_size_
.width();
898 format
.fmt
.pix_mp
.height
= visible_size_
.height();
899 format
.fmt
.pix_mp
.pixelformat
= input_format_fourcc
;
900 format
.fmt
.pix_mp
.num_planes
= input_planes_count
;
901 if (device_
->Ioctl(VIDIOC_S_FMT
, &format
) != 0) {
902 // Error or format unsupported by device, try to negotiate a fallback.
903 input_format_fourcc
= device_
->PreferredInputFormat();
905 V4L2Device::V4L2PixFmtToVideoFrameFormat(input_format_fourcc
);
906 if (input_format
== media::VideoFrame::UNKNOWN
)
909 input_planes_count
= media::VideoFrame::NumPlanes(input_format
);
910 DCHECK_LE(input_planes_count
, static_cast<size_t>(VIDEO_MAX_PLANES
));
912 // Device might have adjusted parameters, reset them along with the format.
913 memset(&format
, 0, sizeof(format
));
914 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
915 format
.fmt
.pix_mp
.width
= visible_size_
.width();
916 format
.fmt
.pix_mp
.height
= visible_size_
.height();
917 format
.fmt
.pix_mp
.pixelformat
= input_format_fourcc
;
918 format
.fmt
.pix_mp
.num_planes
= input_planes_count
;
919 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT
, &format
);
920 DCHECK_EQ(format
.fmt
.pix_mp
.num_planes
, input_planes_count
);
923 // Take device-adjusted sizes for allocated size.
924 input_allocated_size_
= V4L2Device::CodedSizeFromV4L2Format(format
);
925 DCHECK(gfx::Rect(input_allocated_size_
).Contains(gfx::Rect(visible_size_
)));
927 device_input_format_
= input_format
;
928 input_planes_count_
= input_planes_count
;
932 bool V4L2VideoEncodeAccelerator::SetFormats(
933 media::VideoFrame::Format input_format
,
934 media::VideoCodecProfile output_profile
) {
935 DVLOG(3) << "SetFormats()";
936 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
937 DCHECK(!input_streamon_
);
938 DCHECK(!output_streamon_
);
940 if (!SetOutputFormat(output_profile
))
943 if (!NegotiateInputFormat(input_format
))
946 struct v4l2_crop crop
;
947 memset(&crop
, 0, sizeof(crop
));
948 crop
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
951 crop
.c
.width
= visible_size_
.width();
952 crop
.c
.height
= visible_size_
.height();
953 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP
, &crop
);
958 bool V4L2VideoEncodeAccelerator::SetExtCtrls(
959 std::vector
<struct v4l2_ext_control
> ctrls
) {
960 struct v4l2_ext_controls ext_ctrls
;
961 memset(&ext_ctrls
, 0, sizeof(ext_ctrls
));
962 ext_ctrls
.ctrl_class
= V4L2_CTRL_CLASS_MPEG
;
963 ext_ctrls
.count
= ctrls
.size();
964 ext_ctrls
.controls
= &ctrls
[0];
965 return device_
->Ioctl(VIDIOC_S_EXT_CTRLS
, &ext_ctrls
) == 0;
968 bool V4L2VideoEncodeAccelerator::InitControls() {
969 std::vector
<struct v4l2_ext_control
> ctrls
;
970 struct v4l2_ext_control ctrl
;
972 // Enable frame-level bitrate control. This is the only mandatory control.
973 memset(&ctrl
, 0, sizeof(ctrl
));
974 ctrl
.id
= V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE
;
976 ctrls
.push_back(ctrl
);
977 if (!SetExtCtrls(ctrls
)) {
978 LOG(ERROR
) << "Failed enabling bitrate control";
979 NOTIFY_ERROR(kPlatformFailureError
);
983 // Optional controls.
985 if (output_format_fourcc_
== V4L2_PIX_FMT_H264
) {
986 // No B-frames, for lowest decoding latency.
987 memset(&ctrl
, 0, sizeof(ctrl
));
988 ctrl
.id
= V4L2_CID_MPEG_VIDEO_B_FRAMES
;
990 ctrls
.push_back(ctrl
);
992 // Quantization parameter maximum value (for variable bitrate control).
993 memset(&ctrl
, 0, sizeof(ctrl
));
994 ctrl
.id
= V4L2_CID_MPEG_VIDEO_H264_MAX_QP
;
996 ctrls
.push_back(ctrl
);
998 // Use H.264 level 4.0 to match the supported max resolution.
999 memset(&ctrl
, 0, sizeof(ctrl
));
1000 ctrl
.id
= V4L2_CID_MPEG_VIDEO_H264_LEVEL
;
1001 ctrl
.value
= V4L2_MPEG_VIDEO_H264_LEVEL_4_0
;
1002 ctrls
.push_back(ctrl
);
1004 // Separate stream header so we can cache it and insert into the stream.
1005 memset(&ctrl
, 0, sizeof(ctrl
));
1006 ctrl
.id
= V4L2_CID_MPEG_VIDEO_HEADER_MODE
;
1007 ctrl
.value
= V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE
;
1008 ctrls
.push_back(ctrl
);
1011 // Enable "tight" bitrate mode. For this to work properly, frame- and mb-level
1012 // bitrate controls have to be enabled as well.
1013 memset(&ctrl
, 0, sizeof(ctrl
));
1014 ctrl
.id
= V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF
;
1016 ctrls
.push_back(ctrl
);
1018 // Force bitrate control to average over a GOP (for tight bitrate
1020 memset(&ctrl
, 0, sizeof(ctrl
));
1021 ctrl
.id
= V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT
;
1023 ctrls
.push_back(ctrl
);
1025 // Enable macroblock-level bitrate control.
1026 memset(&ctrl
, 0, sizeof(ctrl
));
1027 ctrl
.id
= V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE
;
1029 ctrls
.push_back(ctrl
);
1031 // Disable periodic key frames.
1032 memset(&ctrl
, 0, sizeof(ctrl
));
1033 ctrl
.id
= V4L2_CID_MPEG_VIDEO_GOP_SIZE
;
1035 ctrls
.push_back(ctrl
);
1037 // Ignore return value as these controls are optional.
1043 bool V4L2VideoEncodeAccelerator::CreateInputBuffers() {
1044 DVLOG(3) << "CreateInputBuffers()";
1045 // This function runs on encoder_thread_ after output buffers have been
1046 // provided by the client.
1047 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
1048 DCHECK(!input_streamon_
);
1050 struct v4l2_requestbuffers reqbufs
;
1051 memset(&reqbufs
, 0, sizeof(reqbufs
));
1052 // Driver will modify to the appropriate number of buffers.
1054 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1055 // TODO(posciak): Once we start doing zero-copy, we should decide based on
1056 // the current pipeline setup which memory type to use. This should probably
1057 // be decided based on an argument to Initialize().
1058 if (image_processor_
.get())
1059 input_memory_type_
= V4L2_MEMORY_DMABUF
;
1061 input_memory_type_
= V4L2_MEMORY_USERPTR
;
1063 reqbufs
.memory
= input_memory_type_
;
1064 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS
, &reqbufs
);
1066 DCHECK(input_buffer_map_
.empty());
1067 input_buffer_map_
.resize(reqbufs
.count
);
1068 for (size_t i
= 0; i
< input_buffer_map_
.size(); ++i
)
1069 free_input_buffers_
.push_back(i
);
1074 bool V4L2VideoEncodeAccelerator::CreateOutputBuffers() {
1075 DVLOG(3) << "CreateOutputBuffers()";
1076 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1077 DCHECK(!output_streamon_
);
1079 struct v4l2_requestbuffers reqbufs
;
1080 memset(&reqbufs
, 0, sizeof(reqbufs
));
1081 reqbufs
.count
= kOutputBufferCount
;
1082 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1083 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1084 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS
, &reqbufs
);
1086 DCHECK(output_buffer_map_
.empty());
1087 output_buffer_map_
.resize(reqbufs
.count
);
1088 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
1089 struct v4l2_plane planes
[1];
1090 struct v4l2_buffer buffer
;
1091 memset(&buffer
, 0, sizeof(buffer
));
1092 memset(planes
, 0, sizeof(planes
));
1094 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1095 buffer
.memory
= V4L2_MEMORY_MMAP
;
1096 buffer
.m
.planes
= planes
;
1097 buffer
.length
= arraysize(planes
);
1098 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF
, &buffer
);
1099 void* address
= device_
->Mmap(NULL
,
1100 buffer
.m
.planes
[0].length
,
1101 PROT_READ
| PROT_WRITE
,
1103 buffer
.m
.planes
[0].m
.mem_offset
);
1104 if (address
== MAP_FAILED
) {
1105 PLOG(ERROR
) << "CreateOutputBuffers(): mmap() failed";
1108 output_buffer_map_
[i
].address
= address
;
1109 output_buffer_map_
[i
].length
= buffer
.m
.planes
[0].length
;
1110 free_output_buffers_
.push_back(i
);
1116 void V4L2VideoEncodeAccelerator::DestroyInputBuffers() {
1117 DVLOG(3) << "DestroyInputBuffers()";
1118 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1119 DCHECK(!input_streamon_
);
1121 struct v4l2_requestbuffers reqbufs
;
1122 memset(&reqbufs
, 0, sizeof(reqbufs
));
1124 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1125 reqbufs
.memory
= input_memory_type_
;
1126 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS
, &reqbufs
);
1128 input_buffer_map_
.clear();
1129 free_input_buffers_
.clear();
1132 void V4L2VideoEncodeAccelerator::DestroyOutputBuffers() {
1133 DVLOG(3) << "DestroyOutputBuffers()";
1134 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1135 DCHECK(!output_streamon_
);
1137 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
1138 if (output_buffer_map_
[i
].address
!= NULL
)
1139 device_
->Munmap(output_buffer_map_
[i
].address
,
1140 output_buffer_map_
[i
].length
);
1143 struct v4l2_requestbuffers reqbufs
;
1144 memset(&reqbufs
, 0, sizeof(reqbufs
));
1146 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1147 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1148 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS
, &reqbufs
);
1150 output_buffer_map_
.clear();
1151 free_output_buffers_
.clear();
1154 } // namespace content