1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/common/gpu/media/exynos_video_encode_accelerator.h"
8 #include <linux/videodev2.h>
10 #include <sys/eventfd.h>
11 #include <sys/ioctl.h>
14 #include "base/callback.h"
15 #include "base/debug/trace_event.h"
16 #include "base/message_loop/message_loop_proxy.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "media/base/bitstream_buffer.h"
20 #define NOTIFY_ERROR(x) \
22 SetEncoderState(kError); \
23 DLOG(ERROR) << "calling NotifyError(): " << x; \
27 #define IOCTL_OR_ERROR_RETURN(fd, type, arg) \
29 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
30 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
31 NOTIFY_ERROR(kPlatformFailureError); \
36 #define IOCTL_OR_ERROR_RETURN_FALSE(fd, type, arg) \
38 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
39 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
40 NOTIFY_ERROR(kPlatformFailureError); \
49 const char kExynosGscDevice
[] = "/dev/gsc1";
50 const char kExynosMfcDevice
[] = "/dev/mfc-enc";
52 // File descriptors we need to poll, one-bit flag for each.
58 } // anonymous namespace
60 struct ExynosVideoEncodeAccelerator::BitstreamBufferRef
{
61 BitstreamBufferRef(int32 id
, scoped_ptr
<base::SharedMemory
> shm
, size_t size
)
62 : id(id
), shm(shm
.Pass()), size(size
) {}
64 const scoped_ptr
<base::SharedMemory
> shm
;
69 ExynosVideoEncodeAccelerator::GscInputRecord::GscInputRecord()
72 ExynosVideoEncodeAccelerator::GscOutputRecord::GscOutputRecord()
73 : at_device(false), mfc_input(-1) {}
75 ExynosVideoEncodeAccelerator::MfcInputRecord::MfcInputRecord()
80 ExynosVideoEncodeAccelerator::MfcOutputRecord::MfcOutputRecord()
81 : at_device(false), address(NULL
), length(0) {}
83 ExynosVideoEncodeAccelerator::ExynosVideoEncodeAccelerator(
84 media::VideoEncodeAccelerator::Client
* client
)
85 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
86 weak_this_ptr_factory_(this),
87 weak_this_(weak_this_ptr_factory_
.GetWeakPtr()),
88 client_ptr_factory_(client
),
89 client_(client_ptr_factory_
.GetWeakPtr()),
90 encoder_thread_("ExynosEncoderThread"),
91 encoder_state_(kUninitialized
),
92 output_buffer_byte_size_(0),
93 stream_header_size_(0),
94 input_format_fourcc_(0),
95 output_format_fourcc_(0),
97 gsc_input_streamon_(false),
98 gsc_input_buffer_queued_count_(0),
99 gsc_output_streamon_(false),
100 gsc_output_buffer_queued_count_(0),
102 mfc_input_streamon_(false),
103 mfc_input_buffer_queued_count_(0),
104 mfc_output_streamon_(false),
105 mfc_output_buffer_queued_count_(0),
106 device_poll_thread_("ExynosEncoderDevicePollThread"),
107 device_poll_interrupt_fd_(-1) {
111 ExynosVideoEncodeAccelerator::~ExynosVideoEncodeAccelerator() {
112 DCHECK(!encoder_thread_
.IsRunning());
113 DCHECK(!device_poll_thread_
.IsRunning());
115 if (device_poll_interrupt_fd_
!= -1) {
116 HANDLE_EINTR(close(device_poll_interrupt_fd_
));
117 device_poll_interrupt_fd_
= -1;
120 DestroyGscInputBuffers();
121 DestroyGscOutputBuffers();
122 HANDLE_EINTR(close(gsc_fd_
));
126 DestroyMfcInputBuffers();
127 DestroyMfcOutputBuffers();
128 HANDLE_EINTR(close(mfc_fd_
));
133 void ExynosVideoEncodeAccelerator::Initialize(
134 media::VideoFrame::Format input_format
,
135 const gfx::Size
& input_visible_size
,
136 media::VideoCodecProfile output_profile
,
137 uint32 initial_bitrate
) {
138 DVLOG(3) << "Initialize(): input_format=" << input_format
139 << ", input_visible_size=" << input_visible_size
.ToString()
140 << ", output_profile=" << output_profile
141 << ", initial_bitrate=" << initial_bitrate
;
143 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
144 DCHECK_EQ(encoder_state_
, kUninitialized
);
146 input_visible_size_
= input_visible_size
;
147 input_allocated_size_
.SetSize((input_visible_size_
.width() + 0xF) & ~0xF,
148 (input_visible_size_
.height() + 0xF) & ~0xF);
149 converted_visible_size_
.SetSize((input_visible_size_
.width() + 0x1) & ~0x1,
150 (input_visible_size_
.height() + 0x1) & ~0x1);
151 converted_allocated_size_
.SetSize(
152 (converted_visible_size_
.width() + 0xF) & ~0xF,
153 (converted_visible_size_
.height() + 0xF) & ~0xF);
154 output_visible_size_
= converted_visible_size_
;
156 switch (input_format
) {
157 case media::VideoFrame::RGB32
:
158 input_format_fourcc_
= V4L2_PIX_FMT_RGB32
;
160 case media::VideoFrame::I420
:
161 input_format_fourcc_
= V4L2_PIX_FMT_YUV420M
;
164 NOTIFY_ERROR(kInvalidArgumentError
);
168 if (output_profile
>= media::H264PROFILE_MIN
&&
169 output_profile
<= media::H264PROFILE_MAX
) {
170 output_format_fourcc_
= V4L2_PIX_FMT_H264
;
172 NOTIFY_ERROR(kInvalidArgumentError
);
176 // Open the color conversion device.
177 DVLOG(2) << "Initialize(): opening GSC device: " << kExynosGscDevice
;
179 HANDLE_EINTR(open(kExynosGscDevice
, O_RDWR
| O_NONBLOCK
| O_CLOEXEC
));
181 DPLOG(ERROR
) << "Initialize(): could not open GSC device: "
183 NOTIFY_ERROR(kPlatformFailureError
);
187 // Capabilities check.
188 struct v4l2_capability caps
;
189 memset(&caps
, 0, sizeof(caps
));
190 const __u32 kCapsRequired
= V4L2_CAP_VIDEO_CAPTURE_MPLANE
|
191 V4L2_CAP_VIDEO_OUTPUT_MPLANE
| V4L2_CAP_STREAMING
;
192 IOCTL_OR_ERROR_RETURN(gsc_fd_
, VIDIOC_QUERYCAP
, &caps
);
193 if ((caps
.capabilities
& kCapsRequired
) != kCapsRequired
) {
194 DLOG(ERROR
) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
195 "caps check failed: 0x" << std::hex
<< caps
.capabilities
;
196 NOTIFY_ERROR(kPlatformFailureError
);
200 // Open the video encoder device.
201 DVLOG(2) << "Initialize(): opening MFC device: " << kExynosMfcDevice
;
203 HANDLE_EINTR(open(kExynosMfcDevice
, O_RDWR
| O_NONBLOCK
| O_CLOEXEC
));
205 DPLOG(ERROR
) << "Initialize(): could not open MFC device: "
207 NOTIFY_ERROR(kPlatformFailureError
);
211 memset(&caps
, 0, sizeof(caps
));
212 IOCTL_OR_ERROR_RETURN(mfc_fd_
, VIDIOC_QUERYCAP
, &caps
);
213 if ((caps
.capabilities
& kCapsRequired
) != kCapsRequired
) {
214 DLOG(ERROR
) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
215 "caps check failed: 0x" << std::hex
<< caps
.capabilities
;
216 NOTIFY_ERROR(kPlatformFailureError
);
220 // Create the interrupt fd.
221 DCHECK_EQ(device_poll_interrupt_fd_
, -1);
222 device_poll_interrupt_fd_
= eventfd(0, EFD_NONBLOCK
| EFD_CLOEXEC
);
223 if (device_poll_interrupt_fd_
== -1) {
224 DPLOG(ERROR
) << "Initialize(): eventfd() failed";
225 NOTIFY_ERROR(kPlatformFailureError
);
230 << "Initialize(): input_visible_size_=" << input_visible_size_
.ToString()
231 << ", input_allocated_size_=" << input_allocated_size_
.ToString()
232 << ", converted_visible_size_=" << converted_visible_size_
.ToString()
233 << ", converted_allocated_size_=" << converted_allocated_size_
.ToString()
234 << ", output_visible_size_=" << output_visible_size_
.ToString();
236 if (!CreateGscInputBuffers() || !CreateGscOutputBuffers())
239 // MFC setup for encoding is rather particular in ordering:
241 // 1. Format (VIDIOC_S_FMT) set first on OUTPUT and CAPTURE queues.
242 // 2. VIDIOC_REQBUFS, VIDIOC_QBUF, and VIDIOC_STREAMON on CAPTURE queue.
243 // 3. VIDIOC_REQBUFS (and later VIDIOC_QBUF and VIDIOC_STREAMON) on OUTPUT
246 // Unfortunately, we cannot do (3) in Initialize() here since we have no
247 // buffers to QBUF in step (2) until the client has provided output buffers
248 // through UseOutputBitstreamBuffer(). So, we just do (1), and the
249 // VIDIOC_REQBUFS part of (2) here. The rest is done the first time we get
250 // a UseOutputBitstreamBuffer() callback.
252 if (!SetMfcFormats())
255 // VIDIOC_REQBUFS on CAPTURE queue.
256 if (!CreateMfcOutputBuffers())
260 if (!encoder_thread_
.Start()) {
261 DLOG(ERROR
) << "Initialize(): encoder thread failed to start";
262 NOTIFY_ERROR(kPlatformFailureError
);
266 RequestEncodingParametersChange(initial_bitrate
, kInitialFramerate
);
268 SetEncoderState(kInitialized
);
270 child_message_loop_proxy_
->PostTask(
271 FROM_HERE
, base::Bind(&Client::NotifyInitializeDone
, client_
));
273 child_message_loop_proxy_
->PostTask(
275 base::Bind(&Client::RequireBitstreamBuffers
,
277 gsc_input_buffer_map_
.size(),
278 input_allocated_size_
,
279 output_buffer_byte_size_
));
282 void ExynosVideoEncodeAccelerator::Encode(
283 const scoped_refptr
<media::VideoFrame
>& frame
,
284 bool force_keyframe
) {
285 DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe
;
286 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
288 encoder_thread_
.message_loop()->PostTask(
290 base::Bind(&ExynosVideoEncodeAccelerator::EncodeTask
,
291 base::Unretained(this),
296 void ExynosVideoEncodeAccelerator::UseOutputBitstreamBuffer(
297 const media::BitstreamBuffer
& buffer
) {
298 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer
.id();
299 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
301 if (buffer
.size() < output_buffer_byte_size_
) {
302 NOTIFY_ERROR(kInvalidArgumentError
);
306 scoped_ptr
<base::SharedMemory
> shm(
307 new base::SharedMemory(buffer
.handle(), false));
308 if (!shm
->Map(buffer
.size())) {
309 NOTIFY_ERROR(kPlatformFailureError
);
313 scoped_ptr
<BitstreamBufferRef
> buffer_ref(
314 new BitstreamBufferRef(buffer
.id(), shm
.Pass(), buffer
.size()));
315 encoder_thread_
.message_loop()->PostTask(
317 base::Bind(&ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask
,
318 base::Unretained(this),
319 base::Passed(&buffer_ref
)));
322 void ExynosVideoEncodeAccelerator::RequestEncodingParametersChange(
325 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
326 << ", framerate=" << framerate
;
327 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
329 encoder_thread_
.message_loop()->PostTask(
332 &ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask
,
333 base::Unretained(this),
338 void ExynosVideoEncodeAccelerator::Destroy() {
339 DVLOG(3) << "Destroy()";
340 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
342 // We're destroying; cancel all callbacks.
343 client_ptr_factory_
.InvalidateWeakPtrs();
345 // If the encoder thread is running, destroy using posted task.
346 if (encoder_thread_
.IsRunning()) {
347 encoder_thread_
.message_loop()->PostTask(
349 base::Bind(&ExynosVideoEncodeAccelerator::DestroyTask
,
350 base::Unretained(this)));
351 // DestroyTask() will put the encoder into kError state and cause all tasks
353 encoder_thread_
.Stop();
355 // Otherwise, call the destroy task directly.
359 // Set to kError state just in case.
360 SetEncoderState(kError
);
366 std::vector
<media::VideoEncodeAccelerator::SupportedProfile
>
367 ExynosVideoEncodeAccelerator::GetSupportedProfiles() {
368 std::vector
<SupportedProfile
> profiles(1);
369 SupportedProfile
& profile
= profiles
[0];
370 profile
.profile
= media::H264PROFILE_MAIN
;
371 profile
.max_resolution
.SetSize(1920, 1088);
372 profile
.max_framerate
.numerator
= 30;
373 profile
.max_framerate
.denominator
= 1;
377 void ExynosVideoEncodeAccelerator::EncodeTask(
378 const scoped_refptr
<media::VideoFrame
>& frame
, bool force_keyframe
) {
379 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe
;
380 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
381 DCHECK_NE(encoder_state_
, kUninitialized
);
383 if (encoder_state_
== kError
) {
384 DVLOG(2) << "EncodeTask(): early out: kError state";
388 encoder_input_queue_
.push_back(frame
);
391 if (force_keyframe
) {
392 // TODO(sheu): this presently makes for slightly imprecise encoding
393 // parameters updates. To precisely align the parameter updates with the
394 // incoming input frame, we should track the parameters through the GSC
395 // pipeline and only apply them when the MFC input is about to be queued.
396 struct v4l2_ext_control ctrls
[1];
397 struct v4l2_ext_controls control
;
398 memset(&ctrls
, 0, sizeof(ctrls
));
399 memset(&control
, 0, sizeof(control
));
400 ctrls
[0].id
= V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE
;
401 ctrls
[0].value
= V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME
;
402 control
.ctrl_class
= V4L2_CTRL_CLASS_MPEG
;
404 control
.controls
= ctrls
;
405 IOCTL_OR_ERROR_RETURN(mfc_fd_
, VIDIOC_S_EXT_CTRLS
, &control
);
409 void ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
410 scoped_ptr
<BitstreamBufferRef
> buffer_ref
) {
411 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref
->id
;
412 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
414 encoder_output_queue_
.push_back(
415 linked_ptr
<BitstreamBufferRef
>(buffer_ref
.release()));
418 if (encoder_state_
== kInitialized
) {
419 // Finish setting up our MFC OUTPUT queue. See: Initialize().
420 // VIDIOC_REQBUFS on OUTPUT queue.
421 if (!CreateMfcInputBuffers())
423 if (!StartDevicePoll())
425 encoder_state_
= kEncoding
;
429 void ExynosVideoEncodeAccelerator::DestroyTask() {
430 DVLOG(3) << "DestroyTask()";
432 // DestroyTask() should run regardless of encoder_state_.
434 // Stop streaming and the device_poll_thread_.
437 // Set our state to kError, and early-out all tasks.
438 encoder_state_
= kError
;
441 void ExynosVideoEncodeAccelerator::ServiceDeviceTask() {
442 DVLOG(3) << "ServiceDeviceTask()";
443 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
444 DCHECK_NE(encoder_state_
, kUninitialized
);
445 DCHECK_NE(encoder_state_
, kInitialized
);
447 if (encoder_state_
== kError
) {
448 DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
457 // Clear the interrupt fd.
458 if (!ClearDevicePollInterrupt())
461 unsigned int poll_fds
= 0;
462 // Add GSC fd, if we should poll on it.
463 // GSC has to wait until both input and output buffers are queued.
464 if (gsc_input_buffer_queued_count_
> 0 && gsc_output_buffer_queued_count_
> 0)
465 poll_fds
|= kPollGsc
;
466 // Add MFC fd, if we should poll on it.
467 // MFC can be polled as soon as either input or output buffers are queued.
468 if (mfc_input_buffer_queued_count_
+ mfc_output_buffer_queued_count_
> 0)
469 poll_fds
|= kPollMfc
;
471 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
473 // * device_poll_thread_ is running normally
474 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
475 // in which case we're in kError state, and we should have early-outed
477 DCHECK(device_poll_thread_
.message_loop());
478 // Queue the DevicePollTask() now.
479 device_poll_thread_
.message_loop()->PostTask(
481 base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask
,
482 base::Unretained(this),
485 DVLOG(2) << "ServiceDeviceTask(): buffer counts: ENC["
486 << encoder_input_queue_
.size() << "] => GSC["
487 << gsc_free_input_buffers_
.size() << "+"
488 << gsc_input_buffer_queued_count_
<< "/"
489 << gsc_input_buffer_map_
.size() << "->"
490 << gsc_free_output_buffers_
.size() << "+"
491 << gsc_output_buffer_queued_count_
<< "/"
492 << gsc_output_buffer_map_
.size() << "] => "
493 << mfc_ready_input_buffers_
.size() << " => MFC["
494 << mfc_free_input_buffers_
.size() << "+"
495 << mfc_input_buffer_queued_count_
<< "/"
496 << mfc_input_buffer_map_
.size() << "->"
497 << mfc_free_output_buffers_
.size() << "+"
498 << mfc_output_buffer_queued_count_
<< "/"
499 << mfc_output_buffer_map_
.size() << "] => OUT["
500 << encoder_output_queue_
.size() << "]";
503 void ExynosVideoEncodeAccelerator::EnqueueGsc() {
504 DVLOG(3) << "EnqueueGsc()";
505 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
507 const int old_gsc_inputs_queued
= gsc_input_buffer_queued_count_
;
508 while (!encoder_input_queue_
.empty() && !gsc_free_input_buffers_
.empty()) {
509 if (!EnqueueGscInputRecord())
512 if (old_gsc_inputs_queued
== 0 && gsc_input_buffer_queued_count_
!= 0) {
513 // We started up a previously empty queue.
514 // Queue state changed; signal interrupt.
515 if (!SetDevicePollInterrupt())
517 // Start VIDIOC_STREAMON if we haven't yet.
518 if (!gsc_input_streamon_
) {
519 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
520 IOCTL_OR_ERROR_RETURN(gsc_fd_
, VIDIOC_STREAMON
, &type
);
521 gsc_input_streamon_
= true;
525 // Enqueue a GSC output, only if we need one. GSC output buffers write
526 // directly to MFC input buffers, so we'll have to check for free MFC input
528 // GSC is liable to race conditions if more than one output buffer is
529 // simultaneously enqueued, so enqueue just one.
530 if (gsc_input_buffer_queued_count_
!= 0 &&
531 gsc_output_buffer_queued_count_
== 0 &&
532 !gsc_free_output_buffers_
.empty() && !mfc_free_input_buffers_
.empty()) {
533 const int old_gsc_outputs_queued
= gsc_output_buffer_queued_count_
;
534 if (!EnqueueGscOutputRecord())
536 if (old_gsc_outputs_queued
== 0 && gsc_output_buffer_queued_count_
!= 0) {
537 // We just started up a previously empty queue.
538 // Queue state changed; signal interrupt.
539 if (!SetDevicePollInterrupt())
541 // Start VIDIOC_STREAMON if we haven't yet.
542 if (!gsc_output_streamon_
) {
543 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
544 IOCTL_OR_ERROR_RETURN(gsc_fd_
, VIDIOC_STREAMON
, &type
);
545 gsc_output_streamon_
= true;
549 DCHECK_LE(gsc_output_buffer_queued_count_
, 1);
552 void ExynosVideoEncodeAccelerator::DequeueGsc() {
553 DVLOG(3) << "DequeueGsc()";
554 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
556 // Dequeue completed GSC input (VIDEO_OUTPUT) buffers, and recycle to the free
558 struct v4l2_buffer dqbuf
;
559 struct v4l2_plane planes
[3];
560 while (gsc_input_buffer_queued_count_
> 0) {
561 DCHECK(gsc_input_streamon_
);
562 memset(&dqbuf
, 0, sizeof(dqbuf
));
563 memset(&planes
, 0, sizeof(planes
));
564 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
565 dqbuf
.memory
= V4L2_MEMORY_USERPTR
;
566 dqbuf
.m
.planes
= planes
;
567 dqbuf
.length
= arraysize(planes
);
568 if (HANDLE_EINTR(ioctl(gsc_fd_
, VIDIOC_DQBUF
, &dqbuf
)) != 0) {
569 if (errno
== EAGAIN
) {
570 // EAGAIN if we're just out of buffers to dequeue.
573 DPLOG(ERROR
) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
574 NOTIFY_ERROR(kPlatformFailureError
);
577 GscInputRecord
& input_record
= gsc_input_buffer_map_
[dqbuf
.index
];
578 DCHECK(input_record
.at_device
);
579 DCHECK(input_record
.frame
.get());
580 input_record
.at_device
= false;
581 input_record
.frame
= NULL
;
582 gsc_free_input_buffers_
.push_back(dqbuf
.index
);
583 gsc_input_buffer_queued_count_
--;
586 // Dequeue completed GSC output (VIDEO_CAPTURE) buffers, and recycle to the
587 // free list. Queue the corresponding MFC buffer to the GSC->MFC holding
589 while (gsc_output_buffer_queued_count_
> 0) {
590 DCHECK(gsc_output_streamon_
);
591 memset(&dqbuf
, 0, sizeof(dqbuf
));
592 memset(&planes
, 0, sizeof(planes
));
593 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
594 dqbuf
.memory
= V4L2_MEMORY_DMABUF
;
595 dqbuf
.m
.planes
= planes
;
597 if (HANDLE_EINTR(ioctl(gsc_fd_
, VIDIOC_DQBUF
, &dqbuf
)) != 0) {
598 if (errno
== EAGAIN
) {
599 // EAGAIN if we're just out of buffers to dequeue.
602 DPLOG(ERROR
) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
603 NOTIFY_ERROR(kPlatformFailureError
);
606 GscOutputRecord
& output_record
= gsc_output_buffer_map_
[dqbuf
.index
];
607 DCHECK(output_record
.at_device
);
608 DCHECK(output_record
.mfc_input
!= -1);
609 mfc_ready_input_buffers_
.push_back(output_record
.mfc_input
);
610 output_record
.at_device
= false;
611 output_record
.mfc_input
= -1;
612 gsc_free_output_buffers_
.push_back(dqbuf
.index
);
613 gsc_output_buffer_queued_count_
--;
616 void ExynosVideoEncodeAccelerator::EnqueueMfc() {
617 DVLOG(3) << "EnqueueMfc()";
618 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
620 // Enqueue all the MFC inputs we can.
621 const int old_mfc_inputs_queued
= mfc_input_buffer_queued_count_
;
622 while (!mfc_ready_input_buffers_
.empty()) {
623 if (!EnqueueMfcInputRecord())
626 if (old_mfc_inputs_queued
== 0 && mfc_input_buffer_queued_count_
!= 0) {
627 // We just started up a previously empty queue.
628 // Queue state changed; signal interrupt.
629 if (!SetDevicePollInterrupt())
631 // Start VIDIOC_STREAMON if we haven't yet.
632 if (!mfc_input_streamon_
) {
633 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
634 IOCTL_OR_ERROR_RETURN(mfc_fd_
, VIDIOC_STREAMON
, &type
);
635 mfc_input_streamon_
= true;
639 // Enqueue all the MFC outputs we can.
640 const int old_mfc_outputs_queued
= mfc_output_buffer_queued_count_
;
641 while (!mfc_free_output_buffers_
.empty() && !encoder_output_queue_
.empty()) {
642 if (!EnqueueMfcOutputRecord())
645 if (old_mfc_outputs_queued
== 0 && mfc_output_buffer_queued_count_
!= 0) {
646 // We just started up a previously empty queue.
647 // Queue state changed; signal interrupt.
648 if (!SetDevicePollInterrupt())
650 // Start VIDIOC_STREAMON if we haven't yet.
651 if (!mfc_output_streamon_
) {
652 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
653 IOCTL_OR_ERROR_RETURN(mfc_fd_
, VIDIOC_STREAMON
, &type
);
654 mfc_output_streamon_
= true;
659 void ExynosVideoEncodeAccelerator::DequeueMfc() {
660 DVLOG(3) << "DequeueMfc()";
661 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
663 // Dequeue completed MFC input (VIDEO_OUTPUT) buffers, and recycle to the free
665 struct v4l2_buffer dqbuf
;
666 struct v4l2_plane planes
[2];
667 while (mfc_input_buffer_queued_count_
> 0) {
668 DCHECK(mfc_input_streamon_
);
669 memset(&dqbuf
, 0, sizeof(dqbuf
));
670 memset(&planes
, 0, sizeof(planes
));
671 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
672 dqbuf
.memory
= V4L2_MEMORY_MMAP
;
673 dqbuf
.m
.planes
= planes
;
675 if (HANDLE_EINTR(ioctl(mfc_fd_
, VIDIOC_DQBUF
, &dqbuf
)) != 0) {
676 if (errno
== EAGAIN
) {
677 // EAGAIN if we're just out of buffers to dequeue.
680 DPLOG(ERROR
) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
681 NOTIFY_ERROR(kPlatformFailureError
);
684 MfcInputRecord
& input_record
= mfc_input_buffer_map_
[dqbuf
.index
];
685 DCHECK(input_record
.at_device
);
686 input_record
.at_device
= false;
687 mfc_free_input_buffers_
.push_back(dqbuf
.index
);
688 mfc_input_buffer_queued_count_
--;
691 // Dequeue completed MFC output (VIDEO_CAPTURE) buffers, and recycle to the
692 // free list. Notify the client that an output buffer is complete.
693 while (mfc_output_buffer_queued_count_
> 0) {
694 DCHECK(mfc_output_streamon_
);
695 memset(&dqbuf
, 0, sizeof(dqbuf
));
696 memset(planes
, 0, sizeof(planes
));
697 dqbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
698 dqbuf
.memory
= V4L2_MEMORY_MMAP
;
699 dqbuf
.m
.planes
= planes
;
701 if (HANDLE_EINTR(ioctl(mfc_fd_
, VIDIOC_DQBUF
, &dqbuf
)) != 0) {
702 if (errno
== EAGAIN
) {
703 // EAGAIN if we're just out of buffers to dequeue.
706 DPLOG(ERROR
) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
707 NOTIFY_ERROR(kPlatformFailureError
);
710 const bool key_frame
= ((dqbuf
.flags
& V4L2_BUF_FLAG_KEYFRAME
) != 0);
711 MfcOutputRecord
& output_record
= mfc_output_buffer_map_
[dqbuf
.index
];
712 DCHECK(output_record
.at_device
);
713 DCHECK(output_record
.buffer_ref
.get());
715 void* output_data
= output_record
.address
;
716 size_t output_size
= dqbuf
.m
.planes
[0].bytesused
;
717 // This shouldn't happen, but just in case. We should be able to recover
718 // after next keyframe after showing some corruption.
719 DCHECK_LE(output_size
, output_buffer_byte_size_
);
720 if (output_size
> output_buffer_byte_size_
)
721 output_size
= output_buffer_byte_size_
;
723 reinterpret_cast<uint8
*>(output_record
.buffer_ref
->shm
->memory());
724 if (stream_header_size_
== 0) {
725 // Assume that the first buffer dequeued is the stream header.
726 stream_header_size_
= output_size
;
727 stream_header_
.reset(new uint8
[stream_header_size_
]);
728 memcpy(stream_header_
.get(), output_data
, stream_header_size_
);
731 output_buffer_byte_size_
- stream_header_size_
>= output_size
) {
732 // Insert stream header before every keyframe.
733 memcpy(target_data
, stream_header_
.get(), stream_header_size_
);
734 memcpy(target_data
+ stream_header_size_
, output_data
, output_size
);
735 output_size
+= stream_header_size_
;
737 memcpy(target_data
, output_data
, output_size
);
739 DVLOG(3) << "DequeueMfc(): returning "
740 "bitstream_buffer_id=" << output_record
.buffer_ref
->id
741 << ", key_frame=" << key_frame
;
742 child_message_loop_proxy_
->PostTask(
744 base::Bind(&Client::BitstreamBufferReady
,
746 output_record
.buffer_ref
->id
,
749 output_record
.at_device
= false;
750 output_record
.buffer_ref
.reset();
751 mfc_free_output_buffers_
.push_back(dqbuf
.index
);
752 mfc_output_buffer_queued_count_
--;
756 bool ExynosVideoEncodeAccelerator::EnqueueGscInputRecord() {
757 DVLOG(3) << "EnqueueGscInputRecord()";
758 DCHECK(!encoder_input_queue_
.empty());
759 DCHECK(!gsc_free_input_buffers_
.empty());
761 // Enqueue a GSC input (VIDEO_OUTPUT) buffer for an input video frame
762 scoped_refptr
<media::VideoFrame
> frame
= encoder_input_queue_
.front();
763 const int gsc_buffer
= gsc_free_input_buffers_
.back();
764 GscInputRecord
& input_record
= gsc_input_buffer_map_
[gsc_buffer
];
765 DCHECK(!input_record
.at_device
);
766 DCHECK(!input_record
.frame
.get());
767 struct v4l2_buffer qbuf
;
768 struct v4l2_plane qbuf_planes
[3];
769 memset(&qbuf
, 0, sizeof(qbuf
));
770 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
771 qbuf
.index
= gsc_buffer
;
772 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
773 qbuf
.memory
= V4L2_MEMORY_USERPTR
;
774 qbuf
.m
.planes
= qbuf_planes
;
775 switch (input_format_fourcc_
) {
776 case V4L2_PIX_FMT_RGB32
: {
777 qbuf
.m
.planes
[0].bytesused
= input_allocated_size_
.GetArea() * 4;
778 qbuf
.m
.planes
[0].length
= input_allocated_size_
.GetArea() * 4;
779 qbuf
.m
.planes
[0].m
.userptr
= reinterpret_cast<unsigned long>(
780 frame
->data(media::VideoFrame::kRGBPlane
));
784 case V4L2_PIX_FMT_YUV420M
: {
785 qbuf
.m
.planes
[0].bytesused
= input_allocated_size_
.GetArea();
786 qbuf
.m
.planes
[0].length
= input_allocated_size_
.GetArea();
787 qbuf
.m
.planes
[0].m
.userptr
= reinterpret_cast<unsigned long>(
788 frame
->data(media::VideoFrame::kYPlane
));
789 qbuf
.m
.planes
[1].bytesused
= input_allocated_size_
.GetArea() / 4;
790 qbuf
.m
.planes
[1].length
= input_allocated_size_
.GetArea() / 4;
791 qbuf
.m
.planes
[1].m
.userptr
= reinterpret_cast<unsigned long>(
792 frame
->data(media::VideoFrame::kUPlane
));
793 qbuf
.m
.planes
[2].bytesused
= input_allocated_size_
.GetArea() / 4;
794 qbuf
.m
.planes
[2].length
= input_allocated_size_
.GetArea() / 4;
795 qbuf
.m
.planes
[2].m
.userptr
= reinterpret_cast<unsigned long>(
796 frame
->data(media::VideoFrame::kVPlane
));
802 NOTIFY_ERROR(kIllegalStateError
);
805 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_QBUF
, &qbuf
);
806 input_record
.at_device
= true;
807 input_record
.frame
= frame
;
808 encoder_input_queue_
.pop_front();
809 gsc_free_input_buffers_
.pop_back();
810 gsc_input_buffer_queued_count_
++;
814 bool ExynosVideoEncodeAccelerator::EnqueueGscOutputRecord() {
815 DVLOG(3) << "EnqueueGscOutputRecord()";
816 DCHECK(!gsc_free_output_buffers_
.empty());
817 DCHECK(!mfc_free_input_buffers_
.empty());
819 // Enqueue a GSC output (VIDEO_CAPTURE) buffer.
820 const int gsc_buffer
= gsc_free_output_buffers_
.back();
821 const int mfc_buffer
= mfc_free_input_buffers_
.back();
822 GscOutputRecord
& output_record
= gsc_output_buffer_map_
[gsc_buffer
];
823 MfcInputRecord
& input_record
= mfc_input_buffer_map_
[mfc_buffer
];
824 DCHECK(!output_record
.at_device
);
825 DCHECK_EQ(output_record
.mfc_input
, -1);
826 DCHECK(!input_record
.at_device
);
827 struct v4l2_buffer qbuf
;
828 struct v4l2_plane qbuf_planes
[2];
829 memset(&qbuf
, 0, sizeof(qbuf
));
830 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
831 qbuf
.index
= gsc_buffer
;
832 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
833 qbuf
.memory
= V4L2_MEMORY_DMABUF
;
834 qbuf
.m
.planes
= qbuf_planes
;
835 qbuf
.m
.planes
[0].m
.fd
= input_record
.fd
[0];
836 qbuf
.m
.planes
[1].m
.fd
= input_record
.fd
[1];
838 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_QBUF
, &qbuf
);
839 output_record
.at_device
= true;
840 output_record
.mfc_input
= mfc_buffer
;
841 mfc_free_input_buffers_
.pop_back();
842 gsc_free_output_buffers_
.pop_back();
843 gsc_output_buffer_queued_count_
++;
847 bool ExynosVideoEncodeAccelerator::EnqueueMfcInputRecord() {
848 DVLOG(3) << "EnqueueMfcInputRecord()";
849 DCHECK(!mfc_ready_input_buffers_
.empty());
851 // Enqueue a MFC input (VIDEO_OUTPUT) buffer.
852 const int mfc_buffer
= mfc_ready_input_buffers_
.front();
853 MfcInputRecord
& input_record
= mfc_input_buffer_map_
[mfc_buffer
];
854 DCHECK(!input_record
.at_device
);
855 struct v4l2_buffer qbuf
;
856 struct v4l2_plane qbuf_planes
[2];
857 memset(&qbuf
, 0, sizeof(qbuf
));
858 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
859 qbuf
.index
= mfc_buffer
;
860 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
861 qbuf
.memory
= V4L2_MEMORY_MMAP
;
862 qbuf
.m
.planes
= qbuf_planes
;
864 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_QBUF
, &qbuf
);
865 input_record
.at_device
= true;
866 mfc_ready_input_buffers_
.pop_front();
867 mfc_input_buffer_queued_count_
++;
871 bool ExynosVideoEncodeAccelerator::EnqueueMfcOutputRecord() {
872 DVLOG(3) << "EnqueueMfcOutputRecord()";
873 DCHECK(!mfc_free_output_buffers_
.empty());
874 DCHECK(!encoder_output_queue_
.empty());
876 // Enqueue a MFC output (VIDEO_CAPTURE) buffer.
877 linked_ptr
<BitstreamBufferRef
> output_buffer
= encoder_output_queue_
.back();
878 const int mfc_buffer
= mfc_free_output_buffers_
.back();
879 MfcOutputRecord
& output_record
= mfc_output_buffer_map_
[mfc_buffer
];
880 DCHECK(!output_record
.at_device
);
881 DCHECK(!output_record
.buffer_ref
.get());
882 struct v4l2_buffer qbuf
;
883 struct v4l2_plane qbuf_planes
[1];
884 memset(&qbuf
, 0, sizeof(qbuf
));
885 memset(qbuf_planes
, 0, sizeof(qbuf_planes
));
886 qbuf
.index
= mfc_buffer
;
887 qbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
888 qbuf
.memory
= V4L2_MEMORY_MMAP
;
889 qbuf
.m
.planes
= qbuf_planes
;
891 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_QBUF
, &qbuf
);
892 output_record
.at_device
= true;
893 output_record
.buffer_ref
= output_buffer
;
894 encoder_output_queue_
.pop_back();
895 mfc_free_output_buffers_
.pop_back();
896 mfc_output_buffer_queued_count_
++;
900 bool ExynosVideoEncodeAccelerator::StartDevicePoll() {
901 DVLOG(3) << "StartDevicePoll()";
902 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
903 DCHECK(!device_poll_thread_
.IsRunning());
905 // Start up the device poll thread and schedule its first DevicePollTask().
906 if (!device_poll_thread_
.Start()) {
907 DLOG(ERROR
) << "StartDevicePoll(): Device thread failed to start";
908 NOTIFY_ERROR(kPlatformFailureError
);
911 // Enqueue a poll task with no devices to poll on -- it will wait only on the
913 device_poll_thread_
.message_loop()->PostTask(
915 base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask
,
916 base::Unretained(this),
922 bool ExynosVideoEncodeAccelerator::StopDevicePoll() {
923 DVLOG(3) << "StopDevicePoll()";
925 // Signal the DevicePollTask() to stop, and stop the device poll thread.
926 if (!SetDevicePollInterrupt())
928 device_poll_thread_
.Stop();
929 // Clear the interrupt now, to be sure.
930 if (!ClearDevicePollInterrupt())
934 if (gsc_input_streamon_
) {
935 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
936 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_STREAMOFF
, &type
);
938 gsc_input_streamon_
= false;
939 if (gsc_output_streamon_
) {
940 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
941 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_STREAMOFF
, &type
);
943 gsc_output_streamon_
= false;
944 if (mfc_input_streamon_
) {
945 __u32 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
946 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_STREAMOFF
, &type
);
948 mfc_input_streamon_
= false;
949 if (mfc_output_streamon_
) {
950 __u32 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
951 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_STREAMOFF
, &type
);
953 mfc_output_streamon_
= false;
955 // Reset all our accounting info.
956 encoder_input_queue_
.clear();
957 gsc_free_input_buffers_
.clear();
958 for (size_t i
= 0; i
< gsc_input_buffer_map_
.size(); ++i
) {
959 GscInputRecord
& input_record
= gsc_input_buffer_map_
[i
];
960 input_record
.at_device
= false;
961 input_record
.frame
= NULL
;
962 gsc_free_input_buffers_
.push_back(i
);
964 gsc_input_buffer_queued_count_
= 0;
965 gsc_free_output_buffers_
.clear();
966 for (size_t i
= 0; i
< gsc_output_buffer_map_
.size(); ++i
) {
967 GscOutputRecord
& output_record
= gsc_output_buffer_map_
[i
];
968 output_record
.at_device
= false;
969 output_record
.mfc_input
= -1;
970 gsc_free_output_buffers_
.push_back(i
);
972 gsc_output_buffer_queued_count_
= 0;
973 mfc_ready_input_buffers_
.clear();
974 mfc_free_input_buffers_
.clear();
975 for (size_t i
= 0; i
< mfc_input_buffer_map_
.size(); ++i
) {
976 MfcInputRecord
& input_record
= mfc_input_buffer_map_
[i
];
977 input_record
.at_device
= false;
978 mfc_free_input_buffers_
.push_back(i
);
980 mfc_input_buffer_queued_count_
= 0;
981 mfc_free_output_buffers_
.clear();
982 for (size_t i
= 0; i
< mfc_output_buffer_map_
.size(); ++i
) {
983 MfcOutputRecord
& output_record
= mfc_output_buffer_map_
[i
];
984 output_record
.at_device
= false;
985 output_record
.buffer_ref
.reset();
986 mfc_free_output_buffers_
.push_back(i
);
988 mfc_output_buffer_queued_count_
= 0;
989 encoder_output_queue_
.clear();
991 DVLOG(3) << "StopDevicePoll(): device poll stopped";
995 bool ExynosVideoEncodeAccelerator::SetDevicePollInterrupt() {
996 DVLOG(3) << "SetDevicePollInterrupt()";
998 // We might get called here if we fail during initialization, in which case we
999 // don't have a file descriptor.
1000 if (device_poll_interrupt_fd_
== -1)
1003 const uint64 buf
= 1;
1004 if (HANDLE_EINTR((write(device_poll_interrupt_fd_
, &buf
, sizeof(buf
)))) <
1005 static_cast<ssize_t
>(sizeof(buf
))) {
1006 DPLOG(ERROR
) << "SetDevicePollInterrupt(): write() failed";
1007 NOTIFY_ERROR(kPlatformFailureError
);
1013 bool ExynosVideoEncodeAccelerator::ClearDevicePollInterrupt() {
1014 DVLOG(3) << "ClearDevicePollInterrupt()";
1016 // We might get called here if we fail during initialization, in which case we
1017 // don't have a file descriptor.
1018 if (device_poll_interrupt_fd_
== -1)
1022 if (HANDLE_EINTR(read(device_poll_interrupt_fd_
, &buf
, sizeof(buf
))) <
1023 static_cast<ssize_t
>(sizeof(buf
))) {
1024 if (errno
== EAGAIN
) {
1025 // No interrupt flag set, and we're reading nonblocking. Not an error.
1028 DPLOG(ERROR
) << "ClearDevicePollInterrupt(): read() failed";
1029 NOTIFY_ERROR(kPlatformFailureError
);
1036 void ExynosVideoEncodeAccelerator::DevicePollTask(unsigned int poll_fds
) {
1037 DVLOG(3) << "DevicePollTask()";
1038 DCHECK_EQ(device_poll_thread_
.message_loop(), base::MessageLoop::current());
1039 DCHECK_NE(device_poll_interrupt_fd_
, -1);
1041 // This routine just polls the set of device fds, and schedules a
1042 // ServiceDeviceTask() on encoder_thread_ when processing needs to occur.
1043 // Other threads may notify this task to return early by writing to
1044 // device_poll_interrupt_fd_.
1045 struct pollfd pollfds
[3];
1048 // Add device_poll_interrupt_fd_;
1049 pollfds
[0].fd
= device_poll_interrupt_fd_
;
1050 pollfds
[0].events
= POLLIN
| POLLERR
;
1053 // Add GSC fd, if we should poll on it.
1054 // GSC has to wait until both input and output buffers are queued.
1055 if (poll_fds
& kPollGsc
) {
1056 DVLOG(3) << "DevicePollTask(): adding GSC to poll() set";
1057 pollfds
[nfds
].fd
= gsc_fd_
;
1058 pollfds
[nfds
].events
= POLLIN
| POLLOUT
| POLLERR
;
1061 if (poll_fds
& kPollMfc
) {
1062 DVLOG(3) << "DevicePollTask(): adding MFC to poll() set";
1063 pollfds
[nfds
].fd
= mfc_fd_
;
1064 pollfds
[nfds
].events
= POLLIN
| POLLOUT
| POLLERR
;
1069 if (HANDLE_EINTR(poll(pollfds
, nfds
, -1)) == -1) {
1070 DPLOG(ERROR
) << "DevicePollTask(): poll() failed";
1071 NOTIFY_ERROR(kPlatformFailureError
);
1075 // All processing should happen on ServiceDeviceTask(), since we shouldn't
1076 // touch encoder state from this thread.
1077 encoder_thread_
.message_loop()->PostTask(
1079 base::Bind(&ExynosVideoEncodeAccelerator::ServiceDeviceTask
,
1080 base::Unretained(this)));
1083 void ExynosVideoEncodeAccelerator::NotifyError(Error error
) {
1084 DVLOG(1) << "NotifyError(): error=" << error
;
1086 if (!child_message_loop_proxy_
->BelongsToCurrentThread()) {
1087 child_message_loop_proxy_
->PostTask(
1090 &ExynosVideoEncodeAccelerator::NotifyError
, weak_this_
, error
));
1095 client_
->NotifyError(error
);
1096 client_ptr_factory_
.InvalidateWeakPtrs();
1100 void ExynosVideoEncodeAccelerator::SetEncoderState(State state
) {
1101 DVLOG(3) << "SetEncoderState(): state=" << state
;
1103 // We can touch encoder_state_ only if this is the encoder thread or the
1104 // encoder thread isn't running.
1105 if (encoder_thread_
.message_loop() != NULL
&&
1106 encoder_thread_
.message_loop() != base::MessageLoop::current()) {
1107 encoder_thread_
.message_loop()->PostTask(
1109 base::Bind(&ExynosVideoEncodeAccelerator::SetEncoderState
,
1110 base::Unretained(this),
1113 encoder_state_
= state
;
1117 void ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
1120 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate
1121 << ", framerate=" << framerate
;
1122 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
1129 struct v4l2_ext_control ctrls
[1];
1130 struct v4l2_ext_controls control
;
1131 memset(&ctrls
, 0, sizeof(ctrls
));
1132 memset(&control
, 0, sizeof(control
));
1133 ctrls
[0].id
= V4L2_CID_MPEG_VIDEO_BITRATE
;
1134 ctrls
[0].value
= bitrate
;
1135 control
.ctrl_class
= V4L2_CTRL_CLASS_MPEG
;
1136 control
.count
= arraysize(ctrls
);
1137 control
.controls
= ctrls
;
1138 IOCTL_OR_ERROR_RETURN(mfc_fd_
, VIDIOC_S_EXT_CTRLS
, &control
);
1140 struct v4l2_streamparm parms
;
1141 memset(&parms
, 0, sizeof(parms
));
1142 parms
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1143 // Note that we are provided "frames per second" but V4L2 expects "time per
1144 // frame"; hence we provide the reciprocal of the framerate here.
1145 parms
.parm
.output
.timeperframe
.numerator
= 1;
1146 parms
.parm
.output
.timeperframe
.denominator
= framerate
;
1147 IOCTL_OR_ERROR_RETURN(mfc_fd_
, VIDIOC_S_PARM
, &parms
);
1150 bool ExynosVideoEncodeAccelerator::CreateGscInputBuffers() {
1151 DVLOG(3) << "CreateGscInputBuffers()";
1152 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1153 DCHECK_EQ(encoder_state_
, kUninitialized
);
1154 DCHECK(!gsc_input_streamon_
);
1156 struct v4l2_control control
;
1157 memset(&control
, 0, sizeof(control
));
1158 control
.id
= V4L2_CID_ROTATE
;
1160 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_CTRL
, &control
);
1162 // HFLIP actually seems to control vertical mirroring for GSC, and vice-versa.
1163 memset(&control
, 0, sizeof(control
));
1164 control
.id
= V4L2_CID_HFLIP
;
1166 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_CTRL
, &control
);
1168 memset(&control
, 0, sizeof(control
));
1169 control
.id
= V4L2_CID_VFLIP
;
1171 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_CTRL
, &control
);
1173 memset(&control
, 0, sizeof(control
));
1174 control
.id
= V4L2_CID_ALPHA_COMPONENT
;
1175 control
.value
= 255;
1176 if (HANDLE_EINTR(ioctl(gsc_fd_
, VIDIOC_S_CTRL
, &control
)) != 0) {
1177 // TODO(posciak): This is a temporary hack and should be removed when
1178 // all platforms migrate to kernel >=3.8.
1179 memset(&control
, 0, sizeof(control
));
1180 control
.id
= V4L2_CID_GLOBAL_ALPHA
;
1181 control
.value
= 255;
1182 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_CTRL
, &control
);
1185 struct v4l2_format format
;
1186 memset(&format
, 0, sizeof(format
));
1187 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1188 format
.fmt
.pix_mp
.width
= input_allocated_size_
.width();
1189 format
.fmt
.pix_mp
.height
= input_allocated_size_
.height();
1190 format
.fmt
.pix_mp
.pixelformat
= input_format_fourcc_
;
1191 switch (input_format_fourcc_
) {
1192 case V4L2_PIX_FMT_RGB32
:
1193 format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
=
1194 input_allocated_size_
.GetArea() * 4;
1195 format
.fmt
.pix_mp
.plane_fmt
[0].bytesperline
=
1196 input_allocated_size_
.width() * 4;
1197 format
.fmt
.pix_mp
.num_planes
= 1;
1199 case V4L2_PIX_FMT_YUV420M
:
1200 format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
=
1201 input_allocated_size_
.GetArea();
1202 format
.fmt
.pix_mp
.plane_fmt
[0].bytesperline
=
1203 input_allocated_size_
.width();
1204 format
.fmt
.pix_mp
.plane_fmt
[1].sizeimage
=
1205 input_allocated_size_
.GetArea() / 4;
1206 format
.fmt
.pix_mp
.plane_fmt
[1].bytesperline
=
1207 input_allocated_size_
.width() / 2;
1208 format
.fmt
.pix_mp
.plane_fmt
[2].sizeimage
=
1209 input_allocated_size_
.GetArea() / 4;
1210 format
.fmt
.pix_mp
.plane_fmt
[2].bytesperline
=
1211 input_allocated_size_
.width() / 2;
1212 format
.fmt
.pix_mp
.num_planes
= 3;
1216 NOTIFY_ERROR(kIllegalStateError
);
1219 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_FMT
, &format
);
1221 struct v4l2_crop crop
;
1222 memset(&crop
, 0, sizeof(crop
));
1223 crop
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1226 crop
.c
.width
= input_visible_size_
.width();
1227 crop
.c
.height
= input_visible_size_
.height();
1228 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_CROP
, &crop
);
1230 struct v4l2_requestbuffers reqbufs
;
1231 memset(&reqbufs
, 0, sizeof(reqbufs
));
1232 reqbufs
.count
= kGscInputBufferCount
;
1233 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1234 reqbufs
.memory
= V4L2_MEMORY_USERPTR
;
1235 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_REQBUFS
, &reqbufs
);
1237 DCHECK(gsc_input_buffer_map_
.empty());
1238 gsc_input_buffer_map_
.resize(reqbufs
.count
);
1239 for (size_t i
= 0; i
< gsc_input_buffer_map_
.size(); ++i
)
1240 gsc_free_input_buffers_
.push_back(i
);
1245 bool ExynosVideoEncodeAccelerator::CreateGscOutputBuffers() {
1246 DVLOG(3) << "CreateGscOutputBuffers()";
1247 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1248 DCHECK_EQ(encoder_state_
, kUninitialized
);
1249 DCHECK(!gsc_output_streamon_
);
1251 struct v4l2_format format
;
1252 memset(&format
, 0, sizeof(format
));
1253 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1254 format
.fmt
.pix_mp
.width
= converted_allocated_size_
.width();
1255 format
.fmt
.pix_mp
.height
= converted_allocated_size_
.height();
1256 format
.fmt
.pix_mp
.pixelformat
= V4L2_PIX_FMT_NV12M
;
1257 format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
=
1258 converted_allocated_size_
.GetArea();
1259 format
.fmt
.pix_mp
.plane_fmt
[1].sizeimage
=
1260 converted_allocated_size_
.GetArea() / 2;
1261 format
.fmt
.pix_mp
.plane_fmt
[0].bytesperline
=
1262 converted_allocated_size_
.width();
1263 format
.fmt
.pix_mp
.plane_fmt
[1].bytesperline
=
1264 converted_allocated_size_
.width();
1265 format
.fmt
.pix_mp
.num_planes
= 2;
1266 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_FMT
, &format
);
1268 struct v4l2_crop crop
;
1269 memset(&crop
, 0, sizeof(crop
));
1270 crop
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1273 crop
.c
.width
= converted_visible_size_
.width();
1274 crop
.c
.height
= converted_visible_size_
.height();
1275 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_S_CROP
, &crop
);
1277 struct v4l2_requestbuffers reqbufs
;
1278 memset(&reqbufs
, 0, sizeof(reqbufs
));
1279 reqbufs
.count
= kGscOutputBufferCount
;
1280 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1281 reqbufs
.memory
= V4L2_MEMORY_DMABUF
;
1282 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_
, VIDIOC_REQBUFS
, &reqbufs
);
1284 DCHECK(gsc_output_buffer_map_
.empty());
1285 gsc_output_buffer_map_
.resize(reqbufs
.count
);
1286 for (size_t i
= 0; i
< gsc_output_buffer_map_
.size(); ++i
)
1287 gsc_free_output_buffers_
.push_back(i
);
1291 bool ExynosVideoEncodeAccelerator::SetMfcFormats() {
1292 DVLOG(3) << "SetMfcFormats()";
1293 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1294 DCHECK(!mfc_input_streamon_
);
1295 DCHECK(!mfc_output_streamon_
);
1297 // VIDIOC_S_FMT on OUTPUT queue.
1298 struct v4l2_format format
;
1299 memset(&format
, 0, sizeof(format
));
1300 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1301 format
.fmt
.pix_mp
.width
= input_allocated_size_
.width();
1302 format
.fmt
.pix_mp
.height
= input_allocated_size_
.height();
1303 format
.fmt
.pix_mp
.pixelformat
= V4L2_PIX_FMT_NV12M
;
1304 format
.fmt
.pix_mp
.num_planes
= 2;
1305 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_S_FMT
, &format
);
1306 // We read direct from GSC, so we rely on the HW not changing our set
1308 DCHECK_EQ(format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
,
1309 static_cast<__u32
>(input_allocated_size_
.GetArea()));
1310 DCHECK_EQ(format
.fmt
.pix_mp
.plane_fmt
[0].bytesperline
,
1311 static_cast<__u32
>(input_allocated_size_
.width()));
1312 DCHECK_EQ(format
.fmt
.pix_mp
.plane_fmt
[1].sizeimage
,
1313 static_cast<__u32
>(input_allocated_size_
.GetArea() / 2));
1314 DCHECK_EQ(format
.fmt
.pix_mp
.plane_fmt
[1].bytesperline
,
1315 static_cast<__u32
>(input_allocated_size_
.width()));
1317 struct v4l2_crop crop
;
1318 memset(&crop
, 0, sizeof(crop
));
1319 crop
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
1322 crop
.c
.width
= input_visible_size_
.width();
1323 crop
.c
.height
= input_visible_size_
.height();
1324 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_S_CROP
, &crop
);
1326 // VIDIOC_S_FMT on CAPTURE queue.
1327 output_buffer_byte_size_
= kMfcOutputBufferSize
;
1328 memset(&format
, 0, sizeof(format
));
1329 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1330 format
.fmt
.pix_mp
.width
= output_visible_size_
.width();
1331 format
.fmt
.pix_mp
.height
= output_visible_size_
.height();
1332 format
.fmt
.pix_mp
.pixelformat
= output_format_fourcc_
;
1333 format
.fmt
.pix_mp
.plane_fmt
[0].sizeimage
= output_buffer_byte_size_
;
1334 format
.fmt
.pix_mp
.num_planes
= 1;
1335 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_S_FMT
, &format
);
1337 struct v4l2_ext_control ctrls
[7];
1338 struct v4l2_ext_controls control
;
1339 memset(&ctrls
, 0, sizeof(ctrls
));
1340 memset(&control
, 0, sizeof(control
));
1341 // No B-frames, for lowest decoding latency.
1342 ctrls
[0].id
= V4L2_CID_MPEG_VIDEO_B_FRAMES
;
1344 // Enable frame-level bitrate control.
1345 ctrls
[1].id
= V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE
;
1347 // Enable "tight" bitrate mode. For this to work properly, frame- and mb-level
1348 // bitrate controls have to be enabled as well.
1349 ctrls
[2].id
= V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF
;
1351 // Force bitrate control to average over a GOP (for tight bitrate
1353 ctrls
[3].id
= V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT
;
1355 // Quantization parameter maximum value (for variable bitrate control).
1356 ctrls
[4].id
= V4L2_CID_MPEG_VIDEO_H264_MAX_QP
;
1357 ctrls
[4].value
= 51;
1358 // Separate stream header so we can cache it and insert into the stream.
1359 ctrls
[5].id
= V4L2_CID_MPEG_VIDEO_HEADER_MODE
;
1360 ctrls
[5].value
= V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE
;
1361 // Enable macroblock-level bitrate control.
1362 ctrls
[6].id
= V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE
;
1364 control
.ctrl_class
= V4L2_CTRL_CLASS_MPEG
;
1365 control
.count
= arraysize(ctrls
);
1366 control
.controls
= ctrls
;
1367 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_S_EXT_CTRLS
, &control
);
1372 bool ExynosVideoEncodeAccelerator::CreateMfcInputBuffers() {
1373 DVLOG(3) << "CreateMfcInputBuffers()";
1374 // This function runs on encoder_thread_ after output buffers have been
1375 // provided by the client.
1376 DCHECK_EQ(encoder_thread_
.message_loop(), base::MessageLoop::current());
1377 DCHECK(!mfc_input_streamon_
);
1379 struct v4l2_requestbuffers reqbufs
;
1380 memset(&reqbufs
, 0, sizeof(reqbufs
));
1381 reqbufs
.count
= 1; // Driver will allocate the appropriate number of buffers.
1382 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1383 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1384 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_REQBUFS
, &reqbufs
);
1386 DCHECK(mfc_input_buffer_map_
.empty());
1387 mfc_input_buffer_map_
.resize(reqbufs
.count
);
1388 for (size_t i
= 0; i
< mfc_input_buffer_map_
.size(); ++i
) {
1389 MfcInputRecord
& input_record
= mfc_input_buffer_map_
[i
];
1390 for (int j
= 0; j
< 2; ++j
) {
1391 // Export the DMABUF fd so GSC can write to it.
1392 struct v4l2_exportbuffer expbuf
;
1393 memset(&expbuf
, 0, sizeof(expbuf
));
1394 expbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1397 expbuf
.flags
= O_CLOEXEC
;
1398 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_EXPBUF
, &expbuf
);
1399 input_record
.fd
[j
] = expbuf
.fd
;
1401 mfc_free_input_buffers_
.push_back(i
);
1407 bool ExynosVideoEncodeAccelerator::CreateMfcOutputBuffers() {
1408 DVLOG(3) << "CreateMfcOutputBuffers()";
1409 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1410 DCHECK(!mfc_output_streamon_
);
1412 struct v4l2_requestbuffers reqbufs
;
1413 memset(&reqbufs
, 0, sizeof(reqbufs
));
1414 reqbufs
.count
= kMfcOutputBufferCount
;
1415 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1416 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1417 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_REQBUFS
, &reqbufs
);
1419 DCHECK(mfc_output_buffer_map_
.empty());
1420 mfc_output_buffer_map_
.resize(reqbufs
.count
);
1421 for (size_t i
= 0; i
< mfc_output_buffer_map_
.size(); ++i
) {
1422 struct v4l2_plane planes
[1];
1423 struct v4l2_buffer buffer
;
1424 memset(&buffer
, 0, sizeof(buffer
));
1425 memset(planes
, 0, sizeof(planes
));
1427 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1428 buffer
.memory
= V4L2_MEMORY_MMAP
;
1429 buffer
.m
.planes
= planes
;
1430 buffer
.length
= arraysize(planes
);
1431 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_
, VIDIOC_QUERYBUF
, &buffer
);
1432 void* address
= mmap(NULL
, buffer
.m
.planes
[0].length
,
1433 PROT_READ
| PROT_WRITE
, MAP_SHARED
, mfc_fd_
,
1434 buffer
.m
.planes
[0].m
.mem_offset
);
1435 if (address
== MAP_FAILED
) {
1436 DPLOG(ERROR
) << "CreateMfcOutputBuffers(): mmap() failed";
1439 mfc_output_buffer_map_
[i
].address
= address
;
1440 mfc_output_buffer_map_
[i
].length
= buffer
.m
.planes
[0].length
;
1441 mfc_free_output_buffers_
.push_back(i
);
1447 void ExynosVideoEncodeAccelerator::DestroyGscInputBuffers() {
1448 DVLOG(3) << "DestroyGscInputBuffers()";
1449 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1450 DCHECK(!gsc_input_streamon_
);
1452 struct v4l2_requestbuffers reqbufs
;
1453 memset(&reqbufs
, 0, sizeof(reqbufs
));
1455 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1456 reqbufs
.memory
= V4L2_MEMORY_USERPTR
;
1457 if (HANDLE_EINTR(ioctl(gsc_fd_
, VIDIOC_REQBUFS
, &reqbufs
)) != 0)
1458 DPLOG(ERROR
) << "DestroyGscInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1460 gsc_input_buffer_map_
.clear();
1461 gsc_free_input_buffers_
.clear();
1464 void ExynosVideoEncodeAccelerator::DestroyGscOutputBuffers() {
1465 DVLOG(3) << "DestroyGscOutputBuffers()";
1466 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1467 DCHECK(!gsc_output_streamon_
);
1469 struct v4l2_requestbuffers reqbufs
;
1470 memset(&reqbufs
, 0, sizeof(reqbufs
));
1472 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1473 reqbufs
.memory
= V4L2_MEMORY_DMABUF
;
1474 if (HANDLE_EINTR(ioctl(gsc_fd_
, VIDIOC_REQBUFS
, &reqbufs
)) != 0)
1475 DPLOG(ERROR
) << "DestroyGscOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1477 gsc_output_buffer_map_
.clear();
1478 gsc_free_output_buffers_
.clear();
1481 void ExynosVideoEncodeAccelerator::DestroyMfcInputBuffers() {
1482 DVLOG(3) << "DestroyMfcInputBuffers()";
1483 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1484 DCHECK(!mfc_input_streamon_
);
1486 for (size_t buf
= 0; buf
< mfc_input_buffer_map_
.size(); ++buf
) {
1487 MfcInputRecord
& input_record
= mfc_input_buffer_map_
[buf
];
1489 for (size_t plane
= 0; plane
< arraysize(input_record
.fd
); ++plane
)
1490 HANDLE_EINTR(close(mfc_input_buffer_map_
[buf
].fd
[plane
]));
1493 struct v4l2_requestbuffers reqbufs
;
1494 memset(&reqbufs
, 0, sizeof(reqbufs
));
1496 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
1497 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1498 if (HANDLE_EINTR(ioctl(mfc_fd_
, VIDIOC_REQBUFS
, &reqbufs
)) != 0)
1499 DPLOG(ERROR
) << "DestroyMfcInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1501 mfc_input_buffer_map_
.clear();
1502 mfc_free_input_buffers_
.clear();
1505 void ExynosVideoEncodeAccelerator::DestroyMfcOutputBuffers() {
1506 DVLOG(3) << "DestroyMfcOutputBuffers()";
1507 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
1508 DCHECK(!mfc_output_streamon_
);
1510 for (size_t i
= 0; i
< mfc_output_buffer_map_
.size(); ++i
) {
1511 if (mfc_output_buffer_map_
[i
].address
!= NULL
) {
1512 munmap(mfc_output_buffer_map_
[i
].address
,
1513 mfc_output_buffer_map_
[i
].length
);
1517 struct v4l2_requestbuffers reqbufs
;
1518 memset(&reqbufs
, 0, sizeof(reqbufs
));
1520 reqbufs
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1521 reqbufs
.memory
= V4L2_MEMORY_MMAP
;
1522 if (HANDLE_EINTR(ioctl(mfc_fd_
, VIDIOC_REQBUFS
, &reqbufs
)) != 0)
1523 DPLOG(ERROR
) << "DestroyMfcOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1525 mfc_output_buffer_map_
.clear();
1526 mfc_free_output_buffers_
.clear();
1529 } // namespace content