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/debug/trace_event.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/numerics/safe_conversions.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 SetEncoderState(kError); \
24 LOG(ERROR) << "calling NotifyError(): " << x; \
28 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \
30 if (device_->Ioctl(type, arg) != 0) { \
31 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
32 NOTIFY_ERROR(kPlatformFailureError); \
37 #define IOCTL_OR_ERROR_RETURN(type, arg) \
38 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0))
40 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
41 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false)
43 #define IOCTL_OR_LOG_ERROR(type, arg) \
45 if (device_->Ioctl(type, arg) != 0) \
46 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
51 struct V4L2VideoEncodeAccelerator::BitstreamBufferRef
{
52 BitstreamBufferRef(int32 id
, scoped_ptr
<base::SharedMemory
> shm
, size_t size
)
53 : id(id
), shm(shm
.Pass()), size(size
) {}
55 const scoped_ptr
<base::SharedMemory
> shm
;
59 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {
62 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord()
63 : at_device(false), address(NULL
), length(0) {
66 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator(
67 scoped_ptr
<V4L2Device
> device
)
68 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
69 output_buffer_byte_size_(0),
70 device_input_format_(media::VideoFrame::UNKNOWN
),
71 input_planes_count_(0),
72 output_format_fourcc_(0),
73 encoder_state_(kUninitialized
),
74 stream_header_size_(0),
75 device_(device
.Pass()),
76 input_streamon_(false),
77 input_buffer_queued_count_(0),
78 input_memory_type_(V4L2_MEMORY_USERPTR
),
79 output_streamon_(false),
80 output_buffer_queued_count_(0),
81 encoder_thread_("V4L2EncoderThread"),
82 device_poll_thread_("V4L2EncoderDevicePollThread"),
83 weak_this_ptr_factory_(this) {
84 weak_this_
= weak_this_ptr_factory_
.GetWeakPtr();
87 V4L2VideoEncodeAccelerator::~V4L2VideoEncodeAccelerator() {
88 DCHECK(!encoder_thread_
.IsRunning());
89 DCHECK(!device_poll_thread_
.IsRunning());
92 DestroyInputBuffers();
93 DestroyOutputBuffers();
96 bool V4L2VideoEncodeAccelerator::Initialize(
97 media::VideoFrame::Format input_format
,
98 const gfx::Size
& input_visible_size
,
99 media::VideoCodecProfile output_profile
,
100 uint32 initial_bitrate
,
102 DVLOG(3) << __func__
<< ": input_format="
103 << media::VideoFrame::FormatToString(input_format
)
104 << ", input_visible_size=" << input_visible_size
.ToString()
105 << ", output_profile=" << output_profile
106 << ", initial_bitrate=" << initial_bitrate
;
108 visible_size_
= input_visible_size
;
110 client_ptr_factory_
.reset(new base::WeakPtrFactory
<Client
>(client
));
111 client_
= client_ptr_factory_
->GetWeakPtr();
113 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
114 DCHECK_EQ(encoder_state_
, kUninitialized
);
116 struct v4l2_capability caps
;
117 memset(&caps
, 0, sizeof(caps
));
118 const __u32 kCapsRequired
= V4L2_CAP_VIDEO_CAPTURE_MPLANE
|
119 V4L2_CAP_VIDEO_OUTPUT_MPLANE
| V4L2_CAP_STREAMING
;
120 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP
, &caps
);
121 if ((caps
.capabilities
& kCapsRequired
) != kCapsRequired
) {
122 LOG(ERROR
) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
123 "caps check failed: 0x" << std::hex
<< caps
.capabilities
;
127 if (!SetFormats(input_format
, output_profile
)) {
128 LOG(ERROR
) << "Failed setting up formats";
132 if (input_format
!= device_input_format_
) {
133 DVLOG(1) << "Input format not supported by the HW, will convert to "
134 << media::VideoFrame::FormatToString(device_input_format_
);
136 scoped_ptr
<V4L2Device
> device
=
137 V4L2Device::Create(V4L2Device::kImageProcessor
);
138 image_processor_
.reset(new V4L2ImageProcessor(device
.Pass()));
140 // Convert from input_format to device_input_format_, keeping the size
141 // at visible_size_ and requiring the output buffers to be of at least
142 // input_allocated_size_.
143 if (!image_processor_
->Initialize(
145 device_input_format_
,
148 input_allocated_size_
,
149 base::Bind(&V4L2VideoEncodeAccelerator::ImageProcessorError
,
151 LOG(ERROR
) << "Failed initializing image processor";
159 if (!CreateOutputBuffers())
162 if (!encoder_thread_
.Start()) {
163 LOG(ERROR
) << "Initialize(): encoder thread failed to start";
167 RequestEncodingParametersChange(initial_bitrate
, kInitialFramerate
);
169 SetEncoderState(kInitialized
);
171 child_message_loop_proxy_
->PostTask(
173 base::Bind(&Client::RequireBitstreamBuffers
,
176 image_processor_
.get() ?
177 image_processor_
->input_allocated_size() :
178 input_allocated_size_
,
179 output_buffer_byte_size_
));
183 void V4L2VideoEncodeAccelerator::ImageProcessorError() {
184 LOG(ERROR
) << "Image processor error";
185 NOTIFY_ERROR(kPlatformFailureError
);
188 void V4L2VideoEncodeAccelerator::Encode(
189 const scoped_refptr
<media::VideoFrame
>& frame
,
190 bool force_keyframe
) {
191 DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe
;
192 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
194 if (image_processor_
) {
195 image_processor_
->Process(
197 base::Bind(&V4L2VideoEncodeAccelerator::FrameProcessed
,
201 encoder_thread_
.message_loop()->PostTask(
203 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask
,
204 base::Unretained(this),
210 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer(
211 const media::BitstreamBuffer
& buffer
) {
212 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer
.id();
213 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
215 if (buffer
.size() < output_buffer_byte_size_
) {
216 NOTIFY_ERROR(kInvalidArgumentError
);
220 scoped_ptr
<base::SharedMemory
> shm(
221 new base::SharedMemory(buffer
.handle(), false));
222 if (!shm
->Map(buffer
.size())) {
223 NOTIFY_ERROR(kPlatformFailureError
);
227 scoped_ptr
<BitstreamBufferRef
> buffer_ref(
228 new BitstreamBufferRef(buffer
.id(), shm
.Pass(), buffer
.size()));
229 encoder_thread_
.message_loop()->PostTask(
231 base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask
,
232 base::Unretained(this),
233 base::Passed(&buffer_ref
)));
236 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange(
239 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
240 << ", framerate=" << framerate
;
241 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
243 encoder_thread_
.message_loop()->PostTask(
246 &V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask
,
247 base::Unretained(this),
252 void V4L2VideoEncodeAccelerator::Destroy() {
253 DVLOG(3) << "Destroy()";
254 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
256 // We're destroying; cancel all callbacks.
257 client_ptr_factory_
.reset();
258 weak_this_ptr_factory_
.InvalidateWeakPtrs();
260 if (image_processor_
.get())
261 image_processor_
.release()->Destroy();
263 // If the encoder thread is running, destroy using posted task.
264 if (encoder_thread_
.IsRunning()) {
265 encoder_thread_
.message_loop()->PostTask(
267 base::Bind(&V4L2VideoEncodeAccelerator::DestroyTask
,
268 base::Unretained(this)));
269 // DestroyTask() will put the encoder into kError state and cause all tasks
271 encoder_thread_
.Stop();
273 // Otherwise, call the destroy task directly.
277 // Set to kError state just in case.
278 SetEncoderState(kError
);
283 std::vector
<media::VideoEncodeAccelerator::SupportedProfile
>
284 V4L2VideoEncodeAccelerator::GetSupportedProfiles() {
285 std::vector
<SupportedProfile
> profiles
;
286 SupportedProfile profile
;
287 profile
.max_resolution
.SetSize(1920, 1088);
288 profile
.max_framerate_numerator
= 30;
289 profile
.max_framerate_denominator
= 1;
291 v4l2_fmtdesc fmtdesc
;
292 memset(&fmtdesc
, 0, sizeof(fmtdesc
));
293 fmtdesc
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
294 for (; device_
->Ioctl(VIDIOC_ENUM_FMT
, &fmtdesc
) == 0; ++fmtdesc
.index
) {
295 switch (fmtdesc
.pixelformat
) {
296 case V4L2_PIX_FMT_H264
:
297 profile
.profile
= media::H264PROFILE_MAIN
;
298 profiles
.push_back(profile
);
300 case V4L2_PIX_FMT_VP8
:
301 profile
.profile
= media::VP8PROFILE_ANY
;
302 profiles
.push_back(profile
);
310 void V4L2VideoEncodeAccelerator::FrameProcessed(
312 const scoped_refptr
<media::VideoFrame
>& frame
) {
313 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
314 DVLOG(3) << "FrameProcessed(): force_keyframe=" << force_keyframe
;
316 encoder_thread_
.message_loop()->PostTask(
318 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask
,
319 base::Unretained(this),
324 void V4L2VideoEncodeAccelerator::EncodeTask(
325 const scoped_refptr
<media::VideoFrame
>& frame
,
326 bool force_keyframe
) {
327 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe
;
328 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
329 DCHECK_NE(encoder_state_
, kUninitialized
);
331 if (encoder_state_
== kError
) {
332 DVLOG(2) << "EncodeTask(): early out: kError state";
336 encoder_input_queue_
.push_back(frame
);
339 if (force_keyframe
) {
340 // TODO(posciak): this presently makes for slightly imprecise encoding
341 // parameters updates. To precisely align the parameter updates with the
342 // incoming input frame, we should queue the parameters together with the
343 // frame onto encoder_input_queue_ and apply them when the input is about
344 // to be queued to the codec.
345 struct v4l2_ext_control ctrls
[1];
346 struct v4l2_ext_controls control
;
347 memset(&ctrls
, 0, sizeof(ctrls
));
348 memset(&control
, 0, sizeof(control
));
349 ctrls
[0].id
= V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE
;
350 ctrls
[0].value
= V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME
;
351 control
.ctrl_class
= V4L2_CTRL_CLASS_MPEG
;
353 control
.controls
= ctrls
;
354 IOCTL_OR_ERROR_RETURN(VIDIOC_S_EXT_CTRLS
, &control
);
358 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask(
359 scoped_ptr
<BitstreamBufferRef
> buffer_ref
) {
360 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref
->id
;
361 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
363 encoder_output_queue_
.push_back(
364 linked_ptr
<BitstreamBufferRef
>(buffer_ref
.release()));
367 if (encoder_state_
== kInitialized
) {
368 // Finish setting up our OUTPUT queue. See: Initialize().
369 // VIDIOC_REQBUFS on OUTPUT queue.
370 if (!CreateInputBuffers())
372 if (!StartDevicePoll())
374 encoder_state_
= kEncoding
;
378 void V4L2VideoEncodeAccelerator::DestroyTask() {
379 DVLOG(3) << "DestroyTask()";
381 // DestroyTask() should run regardless of encoder_state_.
383 // Stop streaming and the device_poll_thread_.
386 // Set our state to kError, and early-out all tasks.
387 encoder_state_
= kError
;
390 void V4L2VideoEncodeAccelerator::ServiceDeviceTask() {
391 DVLOG(3) << "ServiceDeviceTask()";
392 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
393 DCHECK_NE(encoder_state_
, kUninitialized
);
394 DCHECK_NE(encoder_state_
, kInitialized
);
396 if (encoder_state_
== kError
) {
397 DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
404 // Clear the interrupt fd.
405 if (!device_
->ClearDevicePollInterrupt())
408 // Device can be polled as soon as either input or output buffers are queued.
410 (input_buffer_queued_count_
+ output_buffer_queued_count_
> 0);
412 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
414 // * device_poll_thread_ is running normally
415 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
416 // in which case we're in kError state, and we should have early-outed
418 DCHECK(device_poll_thread_
.message_loop());
419 // Queue the DevicePollTask() now.
420 device_poll_thread_
.message_loop()->PostTask(
422 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask
,
423 base::Unretained(this),
426 DVLOG(2) << __func__
<< ": buffer counts: ENC["
427 << encoder_input_queue_
.size() << "] => DEVICE["
428 << free_input_buffers_
.size() << "+"
429 << input_buffer_queued_count_
<< "/"
430 << input_buffer_map_
.size() << "->"
431 << free_output_buffers_
.size() << "+"
432 << output_buffer_queued_count_
<< "/"
433 << output_buffer_map_
.size() << "] => OUT["
434 << encoder_output_queue_
.size() << "]";
437 void V4L2VideoEncodeAccelerator::Enqueue() {
438 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
440 DVLOG(3) << "Enqueue() "
441 << "free_input_buffers: " << free_input_buffers_
.size()
442 << "input_queue: " << encoder_input_queue_
.size();
444 // Enqueue all the inputs we can.
445 const int old_inputs_queued
= input_buffer_queued_count_
;
446 // while (!ready_input_buffers_.empty()) {
447 while (!encoder_input_queue_
.empty() && !free_input_buffers_
.empty()) {
448 if (!EnqueueInputRecord())
451 if (old_inputs_queued
== 0 && input_buffer_queued_count_
!= 0) {
452 // We just started up a previously empty queue.
453 // Queue state changed; signal interrupt.
454 if (!device_
->SetDevicePollInterrupt())
456 // Start VIDIOC_STREAMON if we haven't yet.
457 if (!input_streamon_
) {
458 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
459 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON
, &type
);
460 input_streamon_
= true;
464 // Enqueue all the outputs we can.
465 const int old_outputs_queued
= output_buffer_queued_count_
;
466 while (!free_output_buffers_
.empty() && !encoder_output_queue_
.empty()) {
467 if (!EnqueueOutputRecord())
470 if (old_outputs_queued
== 0 && output_buffer_queued_count_
!= 0) {
471 // We just started up a previously empty queue.
472 // Queue state changed; signal interrupt.
473 if (!device_
->SetDevicePollInterrupt())
475 // Start VIDIOC_STREAMON if we haven't yet.
476 if (!output_streamon_
) {
477 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
478 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON
, &type
);
479 output_streamon_
= true;
484 void V4L2VideoEncodeAccelerator::Dequeue() {
485 DVLOG(3) << "Dequeue()";
486 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
488 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free
490 struct v4l2_buffer dqbuf
;
491 struct v4l2_plane planes
[VIDEO_MAX_PLANES
];
492 while (input_buffer_queued_count_
> 0) {
493 DVLOG(4) << "inputs queued: " << input_buffer_queued_count_
;
494 DCHECK(input_streamon_
);
495 memset(&dqbuf
, 0, sizeof(dqbuf
));
496 memset(&planes
, 0, sizeof(planes
));
497 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
498 dqbuf
.memory
= V4L2_MEMORY_MMAP
;
499 dqbuf
.m
.planes
= planes
;
500 dqbuf
.length
= input_planes_count_
;
501 if (device_
->Ioctl(VIDIOC_DQBUF
, &dqbuf
) != 0) {
502 if (errno
== EAGAIN
) {
503 // EAGAIN if we're just out of buffers to dequeue.
506 PLOG(ERROR
) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF";
507 NOTIFY_ERROR(kPlatformFailureError
);
510 InputRecord
& input_record
= input_buffer_map_
[dqbuf
.index
];
511 DCHECK(input_record
.at_device
);
512 input_record
.at_device
= false;
514 input_record
.frame
= NULL
;
515 free_input_buffers_
.push_back(dqbuf
.index
);
516 input_buffer_queued_count_
--;
519 // Dequeue completed output (VIDEO_CAPTURE) buffers, and recycle to the
520 // free list. Notify the client that an output buffer is complete.
521 while (output_buffer_queued_count_
> 0) {
522 DCHECK(output_streamon_
);
523 memset(&dqbuf
, 0, sizeof(dqbuf
));
524 memset(planes
, 0, sizeof(planes
));
525 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
526 dqbuf
.memory
= V4L2_MEMORY_MMAP
;
527 dqbuf
.m
.planes
= planes
;
529 if (device_
->Ioctl(VIDIOC_DQBUF
, &dqbuf
) != 0) {
530 if (errno
== EAGAIN
) {
531 // EAGAIN if we're just out of buffers to dequeue.
534 PLOG(ERROR
) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF";
535 NOTIFY_ERROR(kPlatformFailureError
);
538 const bool key_frame
= ((dqbuf
.flags
& V4L2_BUF_FLAG_KEYFRAME
) != 0);
539 OutputRecord
& output_record
= output_buffer_map_
[dqbuf
.index
];
540 DCHECK(output_record
.at_device
);
541 DCHECK(output_record
.buffer_ref
.get());
543 void* output_data
= output_record
.address
;
544 size_t output_size
= dqbuf
.m
.planes
[0].bytesused
;
545 // This shouldn't happen, but just in case. We should be able to recover
546 // after next keyframe after showing some corruption.
547 DCHECK_LE(output_size
, output_buffer_byte_size_
);
548 if (output_size
> output_buffer_byte_size_
)
549 output_size
= output_buffer_byte_size_
;
551 reinterpret_cast<uint8
*>(output_record
.buffer_ref
->shm
->memory());
552 if (output_format_fourcc_
== V4L2_PIX_FMT_H264
) {
553 if (stream_header_size_
== 0) {
554 // Assume that the first buffer dequeued is the stream header.
555 stream_header_size_
= output_size
;
556 stream_header_
.reset(new uint8
[stream_header_size_
]);
557 memcpy(stream_header_
.get(), output_data
, stream_header_size_
);
560 output_buffer_byte_size_
- stream_header_size_
>= output_size
) {
561 // Insert stream header before every keyframe.
562 memcpy(target_data
, stream_header_
.get(), stream_header_size_
);
563 memcpy(target_data
+ stream_header_size_
, output_data
, output_size
);
564 output_size
+= stream_header_size_
;
566 memcpy(target_data
, output_data
, output_size
);
569 memcpy(target_data
, output_data
, output_size
);
572 DVLOG(3) << "Dequeue(): returning "
573 "bitstream_buffer_id=" << output_record
.buffer_ref
->id
574 << ", size=" << output_size
<< ", key_frame=" << key_frame
;
575 child_message_loop_proxy_
->PostTask(
577 base::Bind(&Client::BitstreamBufferReady
,
579 output_record
.buffer_ref
->id
,
582 output_record
.at_device
= false;
583 output_record
.buffer_ref
.reset();
584 free_output_buffers_
.push_back(dqbuf
.index
);
585 output_buffer_queued_count_
--;
589 bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
590 DVLOG(3) << "EnqueueInputRecord()";
591 DCHECK(!free_input_buffers_
.empty());
592 DCHECK(!encoder_input_queue_
.empty());
594 // Enqueue an input (VIDEO_OUTPUT) buffer.
595 scoped_refptr
<media::VideoFrame
> frame
= encoder_input_queue_
.front();
596 const int index
= free_input_buffers_
.back();
597 InputRecord
& input_record
= input_buffer_map_
[index
];
598 DCHECK(!input_record
.at_device
);
599 struct v4l2_buffer qbuf
;
600 struct v4l2_plane qbuf_planes
[VIDEO_MAX_PLANES
];
601 memset(&qbuf
, 0, sizeof(qbuf
));
602 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
604 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
605 qbuf
.m
.planes
= qbuf_planes
;
607 DCHECK_EQ(device_input_format_
, frame
->format());
608 for (size_t i
= 0; i
< input_planes_count_
; ++i
) {
609 qbuf
.m
.planes
[i
].bytesused
=
610 base::checked_cast
<__u32
>(media::VideoFrame::PlaneAllocationSize(
611 frame
->format(), i
, input_allocated_size_
));
613 switch (input_memory_type_
) {
614 case V4L2_MEMORY_USERPTR
:
615 qbuf
.m
.planes
[i
].length
= qbuf
.m
.planes
[i
].bytesused
;
616 qbuf
.m
.planes
[i
].m
.userptr
=
617 reinterpret_cast<unsigned long>(frame
->data(i
));
618 DCHECK(qbuf
.m
.planes
[i
].m
.userptr
);
621 case V4L2_MEMORY_DMABUF
:
622 qbuf
.m
.planes
[i
].m
.fd
= frame
->dmabuf_fd(i
);
623 DCHECK_NE(qbuf
.m
.planes
[i
].m
.fd
, -1);
632 qbuf
.memory
= input_memory_type_
;
633 qbuf
.length
= input_planes_count_
;
635 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF
, &qbuf
);
636 input_record
.at_device
= true;
637 input_record
.frame
= frame
;
638 encoder_input_queue_
.pop_front();
639 free_input_buffers_
.pop_back();
640 input_buffer_queued_count_
++;
644 bool V4L2VideoEncodeAccelerator::EnqueueOutputRecord() {
645 DVLOG(3) << "EnqueueOutputRecord()";
646 DCHECK(!free_output_buffers_
.empty());
647 DCHECK(!encoder_output_queue_
.empty());
649 // Enqueue an output (VIDEO_CAPTURE) buffer.
650 linked_ptr
<BitstreamBufferRef
> output_buffer
= encoder_output_queue_
.back();
651 const int index
= free_output_buffers_
.back();
652 OutputRecord
& output_record
= output_buffer_map_
[index
];
653 DCHECK(!output_record
.at_device
);
654 DCHECK(!output_record
.buffer_ref
.get());
655 struct v4l2_buffer qbuf
;
656 struct v4l2_plane qbuf_planes
[1];
657 memset(&qbuf
, 0, sizeof(qbuf
));
658 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
660 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
661 qbuf
.memory
= V4L2_MEMORY_MMAP
;
662 qbuf
.m
.planes
= qbuf_planes
;
664 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF
, &qbuf
);
665 output_record
.at_device
= true;
666 output_record
.buffer_ref
= output_buffer
;
667 encoder_output_queue_
.pop_back();
668 free_output_buffers_
.pop_back();
669 output_buffer_queued_count_
++;
673 bool V4L2VideoEncodeAccelerator::StartDevicePoll() {
674 DVLOG(3) << "StartDevicePoll()";
675 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
676 DCHECK(!device_poll_thread_
.IsRunning());
678 // Start up the device poll thread and schedule its first DevicePollTask().
679 if (!device_poll_thread_
.Start()) {
680 LOG(ERROR
) << "StartDevicePoll(): Device thread failed to start";
681 NOTIFY_ERROR(kPlatformFailureError
);
684 // Enqueue a poll task with no devices to poll on -- it will wait only on the
686 device_poll_thread_
.message_loop()->PostTask(
688 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask
,
689 base::Unretained(this),
695 bool V4L2VideoEncodeAccelerator::StopDevicePoll() {
696 DVLOG(3) << "StopDevicePoll()";
698 // Signal the DevicePollTask() to stop, and stop the device poll thread.
699 if (!device_
->SetDevicePollInterrupt())
701 device_poll_thread_
.Stop();
702 // Clear the interrupt now, to be sure.
703 if (!device_
->ClearDevicePollInterrupt())
706 if (input_streamon_
) {
707 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
708 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF
, &type
);
710 input_streamon_
= false;
712 if (output_streamon_
) {
713 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
714 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF
, &type
);
716 output_streamon_
= false;
718 // Reset all our accounting info.
719 encoder_input_queue_
.clear();
720 free_input_buffers_
.clear();
721 for (size_t i
= 0; i
< input_buffer_map_
.size(); ++i
) {
722 InputRecord
& input_record
= input_buffer_map_
[i
];
723 input_record
.at_device
= false;
724 input_record
.frame
= NULL
;
725 free_input_buffers_
.push_back(i
);
727 input_buffer_queued_count_
= 0;
729 free_output_buffers_
.clear();
730 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
731 OutputRecord
& output_record
= output_buffer_map_
[i
];
732 output_record
.at_device
= false;
733 output_record
.buffer_ref
.reset();
734 free_output_buffers_
.push_back(i
);
736 output_buffer_queued_count_
= 0;
738 encoder_output_queue_
.clear();
740 DVLOG(3) << "StopDevicePoll(): device poll stopped";
744 void V4L2VideoEncodeAccelerator::DevicePollTask(bool poll_device
) {
745 DVLOG(3) << "DevicePollTask()";
746 DCHECK_EQ(device_poll_thread_
.message_loop(), base::MessageLoop::current());
749 if (!device_
->Poll(poll_device
, &event_pending
)) {
750 NOTIFY_ERROR(kPlatformFailureError
);
754 // All processing should happen on ServiceDeviceTask(), since we shouldn't
755 // touch encoder state from this thread.
756 encoder_thread_
.message_loop()->PostTask(
758 base::Bind(&V4L2VideoEncodeAccelerator::ServiceDeviceTask
,
759 base::Unretained(this)));
762 void V4L2VideoEncodeAccelerator::NotifyError(Error error
) {
763 DVLOG(1) << "NotifyError(): error=" << error
;
765 if (!child_message_loop_proxy_
->BelongsToCurrentThread()) {
766 child_message_loop_proxy_
->PostTask(
769 &V4L2VideoEncodeAccelerator::NotifyError
, weak_this_
, error
));
774 client_
->NotifyError(error
);
775 client_ptr_factory_
.reset();
779 void V4L2VideoEncodeAccelerator::SetEncoderState(State state
) {
780 DVLOG(3) << "SetEncoderState(): state=" << state
;
782 // We can touch encoder_state_ only if this is the encoder thread or the
783 // encoder thread isn't running.
784 if (encoder_thread_
.message_loop() != NULL
&&
785 encoder_thread_
.message_loop() != base::MessageLoop::current()) {
786 encoder_thread_
.message_loop()->PostTask(
788 base::Bind(&V4L2VideoEncodeAccelerator::SetEncoderState
,
789 base::Unretained(this),
792 encoder_state_
= state
;
796 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask(
799 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate
800 << ", framerate=" << framerate
;
801 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
808 struct v4l2_ext_control ctrls
[1];
809 struct v4l2_ext_controls control
;
810 memset(&ctrls
, 0, sizeof(ctrls
));
811 memset(&control
, 0, sizeof(control
));
812 ctrls
[0].id
= V4L2_CID_MPEG_VIDEO_BITRATE
;
813 ctrls
[0].value
= bitrate
;
814 control
.ctrl_class
= V4L2_CTRL_CLASS_MPEG
;
815 control
.count
= arraysize(ctrls
);
816 control
.controls
= ctrls
;
817 IOCTL_OR_ERROR_RETURN(VIDIOC_S_EXT_CTRLS
, &control
);
819 struct v4l2_streamparm parms
;
820 memset(&parms
, 0, sizeof(parms
));
821 parms
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
822 // Note that we are provided "frames per second" but V4L2 expects "time per
823 // frame"; hence we provide the reciprocal of the framerate here.
824 parms
.parm
.output
.timeperframe
.numerator
= 1;
825 parms
.parm
.output
.timeperframe
.denominator
= framerate
;
826 IOCTL_OR_ERROR_RETURN(VIDIOC_S_PARM
, &parms
);
829 bool V4L2VideoEncodeAccelerator::SetOutputFormat(
830 media::VideoCodecProfile output_profile
) {
831 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
832 DCHECK(!input_streamon_
);
833 DCHECK(!output_streamon_
);
835 output_format_fourcc_
=
836 V4L2Device::VideoCodecProfileToV4L2PixFmt(output_profile
);
837 if (!output_format_fourcc_
) {
838 LOG(ERROR
) << "Initialize(): invalid output_profile=" << output_profile
;
842 output_buffer_byte_size_
= kOutputBufferSize
;
844 struct v4l2_format format
;
845 memset(&format
, 0, sizeof(format
));
846 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
847 format
.fmt
.pix_mp
.width
= visible_size_
.width();
848 format
.fmt
.pix_mp
.height
= visible_size_
.height();
849 format
.fmt
.pix_mp
.pixelformat
= output_format_fourcc_
;
850 format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
=
851 base::checked_cast
<__u32
>(output_buffer_byte_size_
);
852 format
.fmt
.pix_mp
.num_planes
= 1;
853 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT
, &format
);
855 // Device might have adjusted the required output size.
856 size_t adjusted_output_buffer_size
=
857 base::checked_cast
<size_t>(format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
);
858 DCHECK_GE(adjusted_output_buffer_size
, output_buffer_byte_size_
);
859 output_buffer_byte_size_
= adjusted_output_buffer_size
;
864 bool V4L2VideoEncodeAccelerator::NegotiateInputFormat(
865 media::VideoFrame::Format input_format
) {
866 DVLOG(3) << "NegotiateInputFormat()";
867 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
868 DCHECK(!input_streamon_
);
869 DCHECK(!output_streamon_
);
871 device_input_format_
= media::VideoFrame::UNKNOWN
;
872 input_planes_count_
= 0;
874 uint32 input_format_fourcc
=
875 V4L2Device::VideoFrameFormatToV4L2PixFmt(input_format
);
876 if (!input_format_fourcc
) {
877 LOG(ERROR
) << "Unsupported input format";
881 size_t input_planes_count
= media::VideoFrame::NumPlanes(input_format
);
882 DCHECK_LE(input_planes_count
, static_cast<size_t>(VIDEO_MAX_PLANES
));
884 // First see if we the device can use the provided input_format directly.
885 struct v4l2_format format
;
886 memset(&format
, 0, sizeof(format
));
887 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
888 format
.fmt
.pix_mp
.width
= visible_size_
.width();
889 format
.fmt
.pix_mp
.height
= visible_size_
.height();
890 format
.fmt
.pix_mp
.pixelformat
= input_format_fourcc
;
891 format
.fmt
.pix_mp
.num_planes
= input_planes_count
;
892 if (device_
->Ioctl(VIDIOC_S_FMT
, &format
) != 0) {
893 // Error or format unsupported by device, try to negotiate a fallback.
894 input_format_fourcc
= device_
->PreferredInputFormat();
896 V4L2Device::V4L2PixFmtToVideoFrameFormat(input_format_fourcc
);
897 if (input_format
== media::VideoFrame::UNKNOWN
)
900 input_planes_count
= media::VideoFrame::NumPlanes(input_format
);
901 DCHECK_LE(input_planes_count
, static_cast<size_t>(VIDEO_MAX_PLANES
));
903 // Device might have adjusted parameters, reset them along with the format.
904 memset(&format
, 0, sizeof(format
));
905 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
906 format
.fmt
.pix_mp
.width
= visible_size_
.width();
907 format
.fmt
.pix_mp
.height
= visible_size_
.height();
908 format
.fmt
.pix_mp
.pixelformat
= input_format_fourcc
;
909 format
.fmt
.pix_mp
.num_planes
= input_planes_count
;
910 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT
, &format
);
911 DCHECK_EQ(format
.fmt
.pix_mp
.num_planes
, input_planes_count
);
914 // Take device-adjusted sizes for allocated size.
915 input_allocated_size_
= V4L2Device::CodedSizeFromV4L2Format(format
);
916 DCHECK(gfx::Rect(input_allocated_size_
).Contains(gfx::Rect(visible_size_
)));
918 device_input_format_
= input_format
;
919 input_planes_count_
= input_planes_count
;
923 bool V4L2VideoEncodeAccelerator::SetFormats(
924 media::VideoFrame::Format input_format
,
925 media::VideoCodecProfile output_profile
) {
926 DVLOG(3) << "SetFormats()";
927 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
928 DCHECK(!input_streamon_
);
929 DCHECK(!output_streamon_
);
931 if (!SetOutputFormat(output_profile
))
934 if (!NegotiateInputFormat(input_format
))
937 struct v4l2_crop crop
;
938 memset(&crop
, 0, sizeof(crop
));
939 crop
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
942 crop
.c
.width
= visible_size_
.width();
943 crop
.c
.height
= visible_size_
.height();
944 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP
, &crop
);
949 bool V4L2VideoEncodeAccelerator::InitControls() {
950 struct v4l2_ext_control ctrls
[9];
951 struct v4l2_ext_controls control
;
952 memset(&ctrls
, 0, sizeof(ctrls
));
953 memset(&control
, 0, sizeof(control
));
954 // No B-frames, for lowest decoding latency.
955 ctrls
[0].id
= V4L2_CID_MPEG_VIDEO_B_FRAMES
;
957 // Enable frame-level bitrate control.
958 ctrls
[1].id
= V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE
;
960 // Enable "tight" bitrate mode. For this to work properly, frame- and mb-level
961 // bitrate controls have to be enabled as well.
962 ctrls
[2].id
= V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF
;
964 // Force bitrate control to average over a GOP (for tight bitrate
966 ctrls
[3].id
= V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT
;
968 // Quantization parameter maximum value (for variable bitrate control).
969 ctrls
[4].id
= V4L2_CID_MPEG_VIDEO_H264_MAX_QP
;
971 // Separate stream header so we can cache it and insert into the stream.
972 ctrls
[5].id
= V4L2_CID_MPEG_VIDEO_HEADER_MODE
;
973 ctrls
[5].value
= V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE
;
974 // Enable macroblock-level bitrate control.
975 ctrls
[6].id
= V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE
;
977 // Use H.264 level 4.0 to match the supported max resolution.
978 ctrls
[7].id
= V4L2_CID_MPEG_VIDEO_H264_LEVEL
;
979 ctrls
[7].value
= V4L2_MPEG_VIDEO_H264_LEVEL_4_0
;
980 // Disable periodic key frames.
981 ctrls
[8].id
= V4L2_CID_MPEG_VIDEO_GOP_SIZE
;
983 control
.ctrl_class
= V4L2_CTRL_CLASS_MPEG
;
984 control
.count
= arraysize(ctrls
);
985 control
.controls
= ctrls
;
986 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS
, &control
);
991 bool V4L2VideoEncodeAccelerator::CreateInputBuffers() {
992 DVLOG(3) << "CreateInputBuffers()";
993 // This function runs on encoder_thread_ after output buffers have been
994 // provided by the client.
995 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
996 DCHECK(!input_streamon_
);
998 struct v4l2_requestbuffers reqbufs
;
999 memset(&reqbufs
, 0, sizeof(reqbufs
));
1000 // Driver will modify to the appropriate number of buffers.
1002 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1003 // TODO(posciak): Once we start doing zero-copy, we should decide based on
1004 // the current pipeline setup which memory type to use. This should probably
1005 // be decided based on an argument to Initialize().
1006 if (image_processor_
.get())
1007 input_memory_type_
= V4L2_MEMORY_DMABUF
;
1009 input_memory_type_
= V4L2_MEMORY_USERPTR
;
1011 reqbufs
.memory
= input_memory_type_
;
1012 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS
, &reqbufs
);
1014 DCHECK(input_buffer_map_
.empty());
1015 input_buffer_map_
.resize(reqbufs
.count
);
1016 for (size_t i
= 0; i
< input_buffer_map_
.size(); ++i
)
1017 free_input_buffers_
.push_back(i
);
1022 bool V4L2VideoEncodeAccelerator::CreateOutputBuffers() {
1023 DVLOG(3) << "CreateOutputBuffers()";
1024 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1025 DCHECK(!output_streamon_
);
1027 struct v4l2_requestbuffers reqbufs
;
1028 memset(&reqbufs
, 0, sizeof(reqbufs
));
1029 reqbufs
.count
= kOutputBufferCount
;
1030 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1031 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1032 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS
, &reqbufs
);
1034 DCHECK(output_buffer_map_
.empty());
1035 output_buffer_map_
.resize(reqbufs
.count
);
1036 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
1037 struct v4l2_plane planes
[1];
1038 struct v4l2_buffer buffer
;
1039 memset(&buffer
, 0, sizeof(buffer
));
1040 memset(planes
, 0, sizeof(planes
));
1042 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1043 buffer
.memory
= V4L2_MEMORY_MMAP
;
1044 buffer
.m
.planes
= planes
;
1045 buffer
.length
= arraysize(planes
);
1046 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF
, &buffer
);
1047 void* address
= device_
->Mmap(NULL
,
1048 buffer
.m
.planes
[0].length
,
1049 PROT_READ
| PROT_WRITE
,
1051 buffer
.m
.planes
[0].m
.mem_offset
);
1052 if (address
== MAP_FAILED
) {
1053 PLOG(ERROR
) << "CreateOutputBuffers(): mmap() failed";
1056 output_buffer_map_
[i
].address
= address
;
1057 output_buffer_map_
[i
].length
= buffer
.m
.planes
[0].length
;
1058 free_output_buffers_
.push_back(i
);
1064 void V4L2VideoEncodeAccelerator::DestroyInputBuffers() {
1065 DVLOG(3) << "DestroyInputBuffers()";
1066 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1067 DCHECK(!input_streamon_
);
1069 struct v4l2_requestbuffers reqbufs
;
1070 memset(&reqbufs
, 0, sizeof(reqbufs
));
1072 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1073 reqbufs
.memory
= input_memory_type_
;
1074 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS
, &reqbufs
);
1076 input_buffer_map_
.clear();
1077 free_input_buffers_
.clear();
1080 void V4L2VideoEncodeAccelerator::DestroyOutputBuffers() {
1081 DVLOG(3) << "DestroyOutputBuffers()";
1082 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1083 DCHECK(!output_streamon_
);
1085 for (size_t i
= 0; i
< output_buffer_map_
.size(); ++i
) {
1086 if (output_buffer_map_
[i
].address
!= NULL
)
1087 device_
->Munmap(output_buffer_map_
[i
].address
,
1088 output_buffer_map_
[i
].length
);
1091 struct v4l2_requestbuffers reqbufs
;
1092 memset(&reqbufs
, 0, sizeof(reqbufs
));
1094 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1095 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1096 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS
, &reqbufs
);
1098 output_buffer_map_
.clear();
1099 free_output_buffers_
.clear();
1102 } // namespace content