Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / common / gpu / media / exynos_video_encode_accelerator.cc
blob1ecf7c8b74b7a4de4c8200bc1105cadc3acf074f
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"
7 #include <fcntl.h>
8 #include <linux/videodev2.h>
9 #include <poll.h>
10 #include <sys/eventfd.h>
11 #include <sys/ioctl.h>
12 #include <sys/mman.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) \
21 do { \
22 SetEncoderState(kError); \
23 DLOG(ERROR) << "calling NotifyError(): " << x; \
24 NotifyError(x); \
25 } while (0)
27 #define IOCTL_OR_ERROR_RETURN(fd, type, arg) \
28 do { \
29 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
30 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
31 NOTIFY_ERROR(kPlatformFailureError); \
32 return; \
33 } \
34 } while (0)
36 #define IOCTL_OR_ERROR_RETURN_FALSE(fd, type, arg) \
37 do { \
38 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
39 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
40 NOTIFY_ERROR(kPlatformFailureError); \
41 return false; \
42 } \
43 } while (0)
45 namespace content {
47 namespace {
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.
53 enum PollFds {
54 kPollGsc = (1 << 0),
55 kPollMfc = (1 << 1),
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) {}
63 const int32 id;
64 const scoped_ptr<base::SharedMemory> shm;
65 const size_t size;
69 ExynosVideoEncodeAccelerator::GscInputRecord::GscInputRecord()
70 : at_device(false) {}
72 ExynosVideoEncodeAccelerator::GscOutputRecord::GscOutputRecord()
73 : at_device(false), mfc_input(-1) {}
75 ExynosVideoEncodeAccelerator::MfcInputRecord::MfcInputRecord()
76 : at_device(false) {
77 fd[0] = fd[1] = -1;
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),
96 gsc_fd_(-1),
97 gsc_input_streamon_(false),
98 gsc_input_buffer_queued_count_(0),
99 gsc_output_streamon_(false),
100 gsc_output_buffer_queued_count_(0),
101 mfc_fd_(-1),
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) {
108 DCHECK(client_);
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;
119 if (gsc_fd_ != -1) {
120 DestroyGscInputBuffers();
121 DestroyGscOutputBuffers();
122 HANDLE_EINTR(close(gsc_fd_));
123 gsc_fd_ = -1;
125 if (mfc_fd_ != -1) {
126 DestroyMfcInputBuffers();
127 DestroyMfcOutputBuffers();
128 HANDLE_EINTR(close(mfc_fd_));
129 mfc_fd_ = -1;
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;
159 break;
160 case media::VideoFrame::I420:
161 input_format_fourcc_ = V4L2_PIX_FMT_YUV420M;
162 break;
163 default:
164 NOTIFY_ERROR(kInvalidArgumentError);
165 return;
168 if (output_profile >= media::H264PROFILE_MIN &&
169 output_profile <= media::H264PROFILE_MAX) {
170 output_format_fourcc_ = V4L2_PIX_FMT_H264;
171 } else {
172 NOTIFY_ERROR(kInvalidArgumentError);
173 return;
176 // Open the color conversion device.
177 DVLOG(2) << "Initialize(): opening GSC device: " << kExynosGscDevice;
178 gsc_fd_ =
179 HANDLE_EINTR(open(kExynosGscDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
180 if (gsc_fd_ == -1) {
181 DPLOG(ERROR) << "Initialize(): could not open GSC device: "
182 << kExynosGscDevice;
183 NOTIFY_ERROR(kPlatformFailureError);
184 return;
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);
197 return;
200 // Open the video encoder device.
201 DVLOG(2) << "Initialize(): opening MFC device: " << kExynosMfcDevice;
202 mfc_fd_ =
203 HANDLE_EINTR(open(kExynosMfcDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
204 if (mfc_fd_ == -1) {
205 DPLOG(ERROR) << "Initialize(): could not open MFC device: "
206 << kExynosMfcDevice;
207 NOTIFY_ERROR(kPlatformFailureError);
208 return;
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);
217 return;
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);
226 return;
229 DVLOG(3)
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())
237 return;
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
244 // queue.
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())
253 return;
255 // VIDIOC_REQBUFS on CAPTURE queue.
256 if (!CreateMfcOutputBuffers())
257 return;
260 if (!encoder_thread_.Start()) {
261 DLOG(ERROR) << "Initialize(): encoder thread failed to start";
262 NOTIFY_ERROR(kPlatformFailureError);
263 return;
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(
274 FROM_HERE,
275 base::Bind(&Client::RequireBitstreamBuffers,
276 client_,
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(
289 FROM_HERE,
290 base::Bind(&ExynosVideoEncodeAccelerator::EncodeTask,
291 base::Unretained(this),
292 frame,
293 force_keyframe));
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);
303 return;
306 scoped_ptr<base::SharedMemory> shm(
307 new base::SharedMemory(buffer.handle(), false));
308 if (!shm->Map(buffer.size())) {
309 NOTIFY_ERROR(kPlatformFailureError);
310 return;
313 scoped_ptr<BitstreamBufferRef> buffer_ref(
314 new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size()));
315 encoder_thread_.message_loop()->PostTask(
316 FROM_HERE,
317 base::Bind(&ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
318 base::Unretained(this),
319 base::Passed(&buffer_ref)));
322 void ExynosVideoEncodeAccelerator::RequestEncodingParametersChange(
323 uint32 bitrate,
324 uint32 framerate) {
325 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
326 << ", framerate=" << framerate;
327 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
329 encoder_thread_.message_loop()->PostTask(
330 FROM_HERE,
331 base::Bind(
332 &ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask,
333 base::Unretained(this),
334 bitrate,
335 framerate));
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(
348 FROM_HERE,
349 base::Bind(&ExynosVideoEncodeAccelerator::DestroyTask,
350 base::Unretained(this)));
351 // DestroyTask() will put the encoder into kError state and cause all tasks
352 // to no-op.
353 encoder_thread_.Stop();
354 } else {
355 // Otherwise, call the destroy task directly.
356 DestroyTask();
359 // Set to kError state just in case.
360 SetEncoderState(kError);
362 delete this;
365 // static
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;
374 return profiles;
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";
385 return;
388 encoder_input_queue_.push_back(frame);
389 EnqueueGsc();
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;
403 control.count = 1;
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()));
416 EnqueueMfc();
418 if (encoder_state_ == kInitialized) {
419 // Finish setting up our MFC OUTPUT queue. See: Initialize().
420 // VIDIOC_REQBUFS on OUTPUT queue.
421 if (!CreateMfcInputBuffers())
422 return;
423 if (!StartDevicePoll())
424 return;
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_.
435 StopDevicePoll();
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";
449 return;
452 DequeueGsc();
453 DequeueMfc();
454 EnqueueGsc();
455 EnqueueMfc();
457 // Clear the interrupt fd.
458 if (!ClearDevicePollInterrupt())
459 return;
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(),
472 // so either:
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
476 // already.
477 DCHECK(device_poll_thread_.message_loop());
478 // Queue the DevicePollTask() now.
479 device_poll_thread_.message_loop()->PostTask(
480 FROM_HERE,
481 base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
482 base::Unretained(this),
483 poll_fds));
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())
510 return;
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())
516 return;
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
527 // buffers as well.
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())
535 return;
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())
540 return;
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
557 // list.
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.
571 break;
573 DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
574 NOTIFY_ERROR(kPlatformFailureError);
575 return;
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
588 // queue.
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;
596 dqbuf.length = 2;
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.
600 break;
602 DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
603 NOTIFY_ERROR(kPlatformFailureError);
604 return;
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())
624 return;
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())
630 return;
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())
643 return;
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())
649 return;
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
664 // list.
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;
674 dqbuf.length = 2;
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.
678 break;
680 DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
681 NOTIFY_ERROR(kPlatformFailureError);
682 return;
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;
700 dqbuf.length = 1;
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.
704 break;
706 DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
707 NOTIFY_ERROR(kPlatformFailureError);
708 return;
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_;
722 uint8* target_data =
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_);
730 if (key_frame &&
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_;
736 } else {
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(
743 FROM_HERE,
744 base::Bind(&Client::BitstreamBufferReady,
745 client_,
746 output_record.buffer_ref->id,
747 output_size,
748 key_frame));
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));
781 qbuf.length = 1;
782 break;
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));
797 qbuf.length = 3;
798 break;
800 default:
801 NOTREACHED();
802 NOTIFY_ERROR(kIllegalStateError);
803 return false;
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_++;
811 return true;
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];
837 qbuf.length = 2;
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_++;
844 return true;
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;
863 qbuf.length = 2;
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_++;
868 return true;
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;
890 qbuf.length = 1;
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_++;
897 return true;
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);
909 return false;
911 // Enqueue a poll task with no devices to poll on -- it will wait only on the
912 // interrupt fd.
913 device_poll_thread_.message_loop()->PostTask(
914 FROM_HERE,
915 base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
916 base::Unretained(this),
917 0));
919 return true;
922 bool ExynosVideoEncodeAccelerator::StopDevicePoll() {
923 DVLOG(3) << "StopDevicePoll()";
925 // Signal the DevicePollTask() to stop, and stop the device poll thread.
926 if (!SetDevicePollInterrupt())
927 return false;
928 device_poll_thread_.Stop();
929 // Clear the interrupt now, to be sure.
930 if (!ClearDevicePollInterrupt())
931 return false;
933 // Stop streaming.
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";
992 return true;
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)
1001 return true;
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);
1008 return false;
1010 return true;
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)
1019 return true;
1021 uint64 buf;
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.
1026 return true;
1027 } else {
1028 DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
1029 NOTIFY_ERROR(kPlatformFailureError);
1030 return false;
1033 return true;
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];
1046 nfds_t nfds;
1048 // Add device_poll_interrupt_fd_;
1049 pollfds[0].fd = device_poll_interrupt_fd_;
1050 pollfds[0].events = POLLIN | POLLERR;
1051 nfds = 1;
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;
1059 nfds++;
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;
1065 nfds++;
1068 // Poll it!
1069 if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
1070 DPLOG(ERROR) << "DevicePollTask(): poll() failed";
1071 NOTIFY_ERROR(kPlatformFailureError);
1072 return;
1075 // All processing should happen on ServiceDeviceTask(), since we shouldn't
1076 // touch encoder state from this thread.
1077 encoder_thread_.message_loop()->PostTask(
1078 FROM_HERE,
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(
1088 FROM_HERE,
1089 base::Bind(
1090 &ExynosVideoEncodeAccelerator::NotifyError, weak_this_, error));
1091 return;
1094 if (client_) {
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(
1108 FROM_HERE,
1109 base::Bind(&ExynosVideoEncodeAccelerator::SetEncoderState,
1110 base::Unretained(this),
1111 state));
1112 } else {
1113 encoder_state_ = state;
1117 void ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
1118 uint32 bitrate,
1119 uint32 framerate) {
1120 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate
1121 << ", framerate=" << framerate;
1122 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
1124 if (bitrate < 1)
1125 bitrate = 1;
1126 if (framerate < 1)
1127 framerate = 1;
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;
1159 control.value = 0;
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;
1165 control.value = 0;
1166 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
1168 memset(&control, 0, sizeof(control));
1169 control.id = V4L2_CID_VFLIP;
1170 control.value = 0;
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;
1198 break;
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;
1213 break;
1214 default:
1215 NOTREACHED();
1216 NOTIFY_ERROR(kIllegalStateError);
1217 return false;
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;
1224 crop.c.left = 0;
1225 crop.c.top = 0;
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);
1242 return true;
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;
1271 crop.c.left = 0;
1272 crop.c.top = 0;
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);
1288 return true;
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
1307 // size/stride.
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;
1320 crop.c.left = 0;
1321 crop.c.top = 0;
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;
1343 ctrls[0].value = 0;
1344 // Enable frame-level bitrate control.
1345 ctrls[1].id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
1346 ctrls[1].value = 1;
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;
1350 ctrls[2].value = 1;
1351 // Force bitrate control to average over a GOP (for tight bitrate
1352 // tolerance).
1353 ctrls[3].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT;
1354 ctrls[3].value = 1;
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;
1363 ctrls[6].value = 1;
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);
1369 return true;
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;
1395 expbuf.index = i;
1396 expbuf.plane = j;
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);
1404 return true;
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));
1426 buffer.index = i;
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";
1437 return false;
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);
1444 return true;
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));
1454 reqbufs.count = 0;
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));
1471 reqbufs.count = 0;
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));
1495 reqbufs.count = 0;
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));
1519 reqbufs.count = 0;
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