Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1055)

Side by Side Diff: content/common/gpu/media/exynos_video_encode_accelerator.cc

Issue 20962003: ExynosVideoEncodeAccelerator (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@screencast_vea
Patch Set: 98e247b0 EXPBUF fix. Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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.
4
5 #include "content/common/gpu/media/exynos_video_encode_accelerator.h"
6
7 #include <fcntl.h>
8 #include <linux/videodev2.h>
9 #include <poll.h>
10 #include <sys/eventfd.h>
11 #include <sys/ioctl.h>
12
13 #include "base/callback.h"
14 #include "base/debug/trace_event.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/posix/eintr_wrapper.h"
17 #include "media/base/bitstream_buffer.h"
18
19 #define NOTIFY_ERROR(x) \
20 do { \
21 SetEncoderState(kError); \
22 DLOG(ERROR) << "calling NotifyError(): " << x; \
23 NotifyError(x); \
24 } while (0)
25
26 #define IOCTL_OR_ERROR_RETURN(fd, type, arg) \
27 do { \
28 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
29 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
30 NOTIFY_ERROR(kPlatformFailureError); \
31 return; \
32 } \
33 } while (0)
34
35 #define IOCTL_OR_ERROR_RETURN_FALSE(fd, type, arg) \
36 do { \
37 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
38 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
39 NOTIFY_ERROR(kPlatformFailureError); \
40 return false; \
41 } \
42 } while (0)
43
44 namespace content {
45
46 namespace {
47
48 const char kExynosGscDevice[] = "/dev/gsc1";
49 const char kExynosMfcDevice[] = "/dev/mfc-enc";
50
51 } // anonymous namespace
52
53 struct ExynosVideoEncodeAccelerator::BitstreamBufferRef {
54 BitstreamBufferRef(int32 id, scoped_ptr<base::SharedMemory> shm, size_t size)
55 : id(id), shm(shm.Pass()), size(size) {}
56 const int32 id;
57 const scoped_ptr<base::SharedMemory> shm;
58 const size_t size;
59 };
60
61
62 ExynosVideoEncodeAccelerator::GscInputRecord::GscInputRecord()
63 : at_device(false) {}
64
65 ExynosVideoEncodeAccelerator::GscOutputRecord::GscOutputRecord()
66 : at_device(false), mfc_input(-1) {}
67
68 ExynosVideoEncodeAccelerator::MfcInputRecord::MfcInputRecord()
69 : at_device(false) {
70 fd[0] = fd[1] = -1;
71 }
72
73 ExynosVideoEncodeAccelerator::MfcOutputRecord::MfcOutputRecord()
74 : at_device(false) {}
75
76 ExynosVideoEncodeAccelerator::ExynosVideoEncodeAccelerator(
77 media::VideoEncodeAccelerator::Client* client)
78 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
79 weak_this_ptr_factory_(this),
80 weak_this_(weak_this_ptr_factory_.GetWeakPtr()),
81 client_ptr_factory_(client),
82 client_(client_ptr_factory_.GetWeakPtr()),
83 encoder_thread_("ExynosEncoderThread"),
84 encoder_state_(kUninitialized),
85 input_buffer_byte_size_(0),
86 output_buffer_byte_size_(0),
87 input_format_fourcc_(0),
88 output_format_fourcc_(0),
89 gsc_fd_(-1),
90 gsc_input_streamon_(false),
91 gsc_input_buffer_queued_count_(0),
92 gsc_output_streamon_(false),
93 gsc_output_buffer_queued_count_(0),
94 mfc_fd_(-1),
95 mfc_input_streamon_(false),
96 mfc_input_buffer_queued_count_(0),
97 mfc_output_streamon_(false),
98 mfc_output_buffer_queued_count_(0),
99 device_poll_thread_("ExynosDevicePollThread"),
100 device_poll_interrupt_fd_(-1) {
101 DCHECK(client_);
102 }
103
104 ExynosVideoEncodeAccelerator::~ExynosVideoEncodeAccelerator() {
105 DCHECK(!encoder_thread_.IsRunning());
106 DCHECK(!device_poll_thread_.IsRunning());
107
108 if (device_poll_interrupt_fd_ != -1) {
109 HANDLE_EINTR(close(device_poll_interrupt_fd_));
110 device_poll_interrupt_fd_ = -1;
111 }
112 if (mfc_fd_ != -1) {
113 DestroyMfcInputBuffers();
114 DestroyMfcOutputBuffers();
115 HANDLE_EINTR(close(mfc_fd_));
116 mfc_fd_ = -1;
117 }
118 if (gsc_fd_ != -1) {
119 DestroyGscInputBuffers();
120 DestroyGscOutputBuffers();
121 HANDLE_EINTR(close(gsc_fd_));
122 gsc_fd_ = -1;
123 }
124 }
125
126 void ExynosVideoEncodeAccelerator::Initialize(
127 media::VideoFrame::Format input_format,
128 const gfx::Size& input_resolution,
129 media::VideoCodecProfile output_profile,
130 int32 initial_bitrate) {
131 DVLOG(3) << "Initialize(): input_format=" << input_format
132 << ", input_resolution=" << input_resolution.width()
133 << "x" << input_resolution.height()
134 << ", output_profile=" << output_profile
135 << ", initial_bitrate=" << initial_bitrate;
136
137 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
138 DCHECK_EQ(encoder_state_, kUninitialized);
139
140 input_visible_size_ = input_resolution;
141 input_allocated_size_.SetSize((input_visible_size_.width() + 0xF) & ~0xF,
142 (input_visible_size_.height() + 0xF) & ~0xF);
143 converted_visible_size_.SetSize((input_visible_size_.width() + 0x1) & ~0x1,
144 (input_visible_size_.height() + 0x1) & ~0x1);
145 converted_allocated_size_.SetSize(
146 (converted_visible_size_.width() + 0xF) & ~0xF,
147 (converted_visible_size_.height() + 0xF) & ~0xF);
148 output_visible_size_ = converted_visible_size_;
149
150 switch (input_format) {
151 case media::VideoFrame::RGB32:
152 input_format_fourcc_ = V4L2_PIX_FMT_RGB32;
153 input_buffer_byte_size_ = input_allocated_size_.GetArea() * 4;
154 break;
155 case media::VideoFrame::I420:
156 input_format_fourcc_ = V4L2_PIX_FMT_YUV420M;
157 input_buffer_byte_size_ = input_allocated_size_.GetArea() * 3 / 2;
158 break;
159 default:
160 NOTIFY_ERROR(kInvalidArgumentError);
161 return;
162 }
163
164 if (output_profile >= media::H264PROFILE_MIN &&
165 output_profile <= media::H264PROFILE_MAX) {
166 output_format_fourcc_ = V4L2_PIX_FMT_H264;
167 } else {
168 NOTIFY_ERROR(kInvalidArgumentError);
169 return;
170 }
171
172 // Open the video converter device.
173 DVLOG(2) << "Initialize(): opening GSC device: " << kExynosGscDevice;
174 gsc_fd_ = HANDLE_EINTR(open(kExynosGscDevice,
175 O_RDWR | O_NONBLOCK | O_CLOEXEC));
176 if (gsc_fd_ == -1) {
177 DPLOG(ERROR) << "Initialize(): could not open GSC device: "
178 << kExynosGscDevice;
179 NOTIFY_ERROR(kPlatformFailureError);
180 return;
181 }
182
183 // Capabilities check.
184 struct v4l2_capability caps;
185 const __u32 kCapsRequired =
186 V4L2_CAP_VIDEO_CAPTURE_MPLANE |
187 V4L2_CAP_VIDEO_OUTPUT_MPLANE |
188 V4L2_CAP_STREAMING;
189 IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_QUERYCAP, &caps);
190 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
191 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
192 "caps check failed: 0x" << std::hex << caps.capabilities;
193 NOTIFY_ERROR(kPlatformFailureError);
194 return;
195 }
196
197 // Open the video encoder device.
198 mfc_fd_ = HANDLE_EINTR(open(kExynosMfcDevice,
199 O_RDWR | O_NONBLOCK | O_CLOEXEC));
200 if (mfc_fd_ == -1) {
201 DPLOG(ERROR) << "Initialize(): could not open MFC device: "
202 << kExynosMfcDevice;
203 NOTIFY_ERROR(kPlatformFailureError);
204 return;
205 }
206
207 IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_QUERYCAP, &caps);
208 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
209 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
210 "caps check failed: 0x" << std::hex << caps.capabilities;
211 NOTIFY_ERROR(kPlatformFailureError);
212 return;
213 }
214
215 // Create the interrupt fd.
216 DCHECK_EQ(device_poll_interrupt_fd_, -1);
217 device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
218 if (device_poll_interrupt_fd_ == -1) {
219 DPLOG(ERROR) << "Initialize(): eventfd() failed";
220 NOTIFY_ERROR(kPlatformFailureError);
221 return;
222 }
223
224 DVLOG(3)
225 << "Initialize(): input_visible_size_="
226 << input_visible_size_.width() << "x"
227 << input_visible_size_.height() << ", input_allocated_size_="
228 << input_allocated_size_.width() << "x"
229 << input_allocated_size_.height() << ", converted_visible_size_="
230 << converted_visible_size_.width() << "x"
231 << converted_visible_size_.height() << ", converted_allocated_size_="
232 << converted_allocated_size_.width() << "x"
233 << converted_allocated_size_.height() << ", output_visible_size_="
234 << output_visible_size_.width() << "x"
235 << output_visible_size_.height();
236
237 if (!CreateGscInputBuffers() || !CreateGscOutputBuffers())
238 return;
239
240 // MFC setup for encoding is rather particular in ordering:
241 //
242 // 1. Format (VIDIOC_S_FMT) set first on OUTPUT and CPATURE queues.
243 // 2. VIDIOC_REQBUFS, VIDIOC_QBUF, and VIDIOC_STREAMON on CAPTURE queue.
244 // 3. VIDIOC_REQBUFS (and later VIDIOC_QBUF and VIDIOC_STREAMON) on OUTPUT
245 // queue.
246 //
247 // Unfortunately, we cannot do (3) in Initialize() here since we have no
248 // buffers to QBUF in step (2) until the client has provided output buffers
249 // through UseOutputBitstreamBuffer(). So, we just do (1), and the
250 // VIDIOC_REQBUFS part of (2) here. The rest is done the first time we get
251 // a UseOutputBitstreamBuffer() callback.
252
253 if (!SetMfcFormats())
254 return;
255
256 // VIDIOC_REQBUFS on CAPTURE queue.
257 if (!CreateMfcOutputBuffers())
258 return;
259
260 SetBitrateTask(initial_bitrate);
261
262 if (!encoder_thread_.Start()) {
263 DLOG(ERROR) << "Initialize(): encoder thread failed to start";
264 NOTIFY_ERROR(kPlatformFailureError);
265 return;
266 }
267
268 SetEncoderState(kInitialized);
269
270 child_message_loop_proxy_->PostTask(
271 FROM_HERE, base::Bind(&Client::NotifyInitializeDone, client_));
272
273 child_message_loop_proxy_->PostTask(
274 FROM_HERE,
275 base::Bind(&Client::RequireBitstreamBuffers,
276 client_,
277 gsc_input_buffer_map_.size(),
278 output_visible_size_,
279 output_buffer_byte_size_));
280 }
281
282 void ExynosVideoEncodeAccelerator::Encode(const media::BitstreamBuffer& buffer,
283 bool force_keyframe) {
284 DVLOG(3) << "Encode(): buffer.id()=" << buffer.id();
285 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
286
287 if (buffer.size() < input_buffer_byte_size_) {
288 NOTIFY_ERROR(kInvalidArgumentError);
289 return;
290 }
291
292 scoped_ptr<base::SharedMemory> shm(
293 new base::SharedMemory(buffer.handle(), true));
294 if (!shm->Map(buffer.size())) {
295 NOTIFY_ERROR(kPlatformFailureError);
296 return;
297 }
298
299 scoped_ptr<BitstreamBufferRef> buffer_ref(
300 new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size()));
301 encoder_thread_.message_loop()->PostTask(
302 FROM_HERE,
303 base::Bind(&ExynosVideoEncodeAccelerator::EncodeTask,
304 base::Unretained(this),
305 base::Passed(&buffer_ref)));
306 }
307
308 void ExynosVideoEncodeAccelerator::UseOutputBitstreamBuffer(
309 const media::BitstreamBuffer& buffer) {
310 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id();
311 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
312
313 if (buffer.size() < output_buffer_byte_size_) {
314 NOTIFY_ERROR(kInvalidArgumentError);
315 return;
316 }
317
318 scoped_ptr<base::SharedMemory> shm(
319 new base::SharedMemory(buffer.handle(), true));
320 if (!shm->Map(buffer.size())) {
321 NOTIFY_ERROR(kPlatformFailureError);
322 return;
323 }
324
325 scoped_ptr<BitstreamBufferRef> buffer_ref(
326 new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size()));
327 encoder_thread_.message_loop()->PostTask(
328 FROM_HERE,
329 base::Bind(&ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
330 base::Unretained(this),
331 base::Passed(&buffer_ref)));
332 }
333
334 void ExynosVideoEncodeAccelerator::RequestEncodingParameterChange(
335 int32 bitrate) {
336 DVLOG(3) << "RequestEncodingParameterChange: bitrate=" << bitrate;
337 encoder_thread_.message_loop()->PostTask(
338 FROM_HERE,
339 base::Bind(&ExynosVideoEncodeAccelerator::SetBitrateTask,
340 base::Unretained(this),
341 bitrate));
342 }
343
344 void ExynosVideoEncodeAccelerator::Destroy() {
345 DVLOG(3) << "Destroy()";
346 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
347
348 // We're destroying; cancel all callbacks.
349 client_ptr_factory_.InvalidateWeakPtrs();
350
351 // If the encoder thread is running, destroy using posted task.
352 if (encoder_thread_.IsRunning()) {
353 encoder_thread_.message_loop()->PostTask(
354 FROM_HERE,
355 base::Bind(&ExynosVideoEncodeAccelerator::DestroyTask,
356 base::Unretained(this)));
357 // DestroyTask() will cause the encoder_thread_ to flush all tasks.
358 encoder_thread_.Stop();
359 } else {
360 // Otherwise, call the destroy task directly.
361 DestroyTask();
362 }
363
364 // Set to kError state just in case.
365 SetEncoderState(kError);
366
367 delete this;
368 }
369
370 // static
371 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
372 ExynosVideoEncodeAccelerator::GetSupportedProfiles() {
373 std::vector<SupportedProfile> profiles(1);
374 SupportedProfile& profile = profiles[0];
375 profile.profile = media::H264PROFILE_MAIN;
376 profile.max_resolution.SetSize(1920, 1088);
377 profile.max_framerate.numerator = 30;
378 profile.max_framerate.denominator = 1;
379 return profiles;
380 }
381
382 void ExynosVideoEncodeAccelerator::EncodeTask(
383 scoped_ptr<BitstreamBufferRef> buffer_ref) {
384 DVLOG(3) << "EncodeTask(): id=" << buffer_ref->id;
385 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
386 DCHECK_NE(encoder_state_, kUninitialized);
387
388 if (encoder_state_ == kError) {
389 DVLOG(2) << "EncodeTask(): early out: kError state";
390 return;
391 }
392
393 encoder_input_queue_.push_back(
394 linked_ptr<BitstreamBufferRef>(buffer_ref.release()));
395 EnqueueGsc();
396 }
397
398 void ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
399 scoped_ptr<BitstreamBufferRef> buffer_ref) {
400 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id;
401 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
402
403 encoder_output_queue_.push_back(
404 linked_ptr<BitstreamBufferRef>(buffer_ref.release()));
405 EnqueueMfc();
406
407 if (encoder_state_ == kInitialized) {
408 // Finish setting up our MFC OUTPUT queue. See: Initialize().
409 // VIDIOC_REQBUFS on OUTPUT queue.
410 if (!CreateMfcInputBuffers())
411 return;
412 if (!StartDevicePoll())
413 return;
414 encoder_state_ = kEncoding;
415 }
416 }
417
418 void ExynosVideoEncodeAccelerator::DestroyTask() {
419 DVLOG(3) << "DestroyTask()";
420
421 // DestroyTask() should run regardless of encoder_state_.
422
423 // Stop streaming and the device_poll_thread_.
424 StopDevicePoll();
425
426 // Set our state to kError. Just in case.
427 encoder_state_ = kError;
428 }
429
430 void ExynosVideoEncodeAccelerator::ServiceDeviceTask() {
431 DVLOG(3) << "ServiceDeviceTask()";
432 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
433 DCHECK_NE(encoder_state_, kUninitialized);
434 DCHECK_NE(encoder_state_, kInitialized);
435
436 if (encoder_state_ == kError) {
437 DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
438 return;
439 }
440
441 DequeueGsc();
442 DequeueMfc();
443 EnqueueGsc();
444 EnqueueMfc();
445
446 // Clear the interrupt fd.
447 if (!ClearDevicePollInterrupt())
448 return;
449
450 unsigned int poll_fds = 0;
451 // Add GSC fd, if we should poll on it.
452 // GSC has to wait until both input and output buffers are queued.
453 if (gsc_input_buffer_queued_count_ > 0 && gsc_output_buffer_queued_count_ > 0)
454 poll_fds |= kPollGsc;
455 // Add MFC fd, if we should poll on it.
456 // MFC can be polled as soon as either input or output buffers are queued.
457 if (mfc_input_buffer_queued_count_ + mfc_output_buffer_queued_count_ > 0)
458 poll_fds |= kPollMfc;
459
460 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
461 // so either:
462 // * device_poll_thread_ is running normally
463 // * device_poll_thread_ scheduled us, but then a ResetTask() or DestroyTask()
464 // shut it down, in which case we're either in kError state, and we should
465 // have early-outed already.
466 DCHECK(device_poll_thread_.message_loop());
467 // Queue the DevicePollTask() now.
468 device_poll_thread_.message_loop()->PostTask(
469 FROM_HERE,
470 base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
471 base::Unretained(this),
472 poll_fds));
473
474 DVLOG(2) << "ServiceDeviceTask(): buffer counts: ENC["
475 << encoder_input_queue_.size() << "] => GSC["
476 << gsc_free_input_buffers_.size() << "+"
477 << gsc_input_buffer_queued_count_ << "/"
478 << gsc_input_buffer_map_.size() << "->"
479 << gsc_free_output_buffers_.size() << "+"
480 << gsc_output_buffer_queued_count_ << "/"
481 << gsc_output_buffer_map_.size() << "] => "
482 << mfc_ready_input_buffers_.size() << " => MFC["
483 << mfc_free_input_buffers_.size() << "+"
484 << mfc_input_buffer_queued_count_ << "/"
485 << mfc_input_buffer_map_.size() << "->"
486 << mfc_free_output_buffers_.size() << "+"
487 << mfc_output_buffer_queued_count_ << "/"
488 << mfc_output_buffer_map_.size() << "] => OUT["
489 << encoder_output_queue_.size() << "]";
490 }
491
492 void ExynosVideoEncodeAccelerator::EnqueueGsc() {
493 DVLOG(3) << "EnqueueGsc()";
494 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
495
496 const int old_gsc_inputs_queued = gsc_input_buffer_queued_count_;
497 while (!encoder_input_queue_.empty() && !gsc_free_input_buffers_.empty()) {
498 if (!EnqueueGscInputRecord())
499 return;
500 }
501 if (old_gsc_inputs_queued == 0 && gsc_input_buffer_queued_count_ != 0) {
502 // We started up a previously empty queue.
503 // Queue state changed; signal interrupt.
504 if (!SetDevicePollInterrupt())
505 return;
506 // Start VIDIOC_STREAMON if we haven't yet.
507 if (!gsc_input_streamon_) {
508 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
509 IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_STREAMON, &type);
510 gsc_input_streamon_ = true;
511 }
512 }
513
514 // Enqueue a GSC output, only if we need one. GSC output buffers write
515 // directly to MFC input buffers, so we'll have to check for free MFC input
516 // buffers as well.
517 if (gsc_input_buffer_queued_count_ != 0 &&
518 gsc_output_buffer_queued_count_ == 0 &&
519 !gsc_free_output_buffers_.empty() && !mfc_free_input_buffers_.empty()) {
520 const int old_gsc_outputs_queued = gsc_output_buffer_queued_count_;
521 if (!EnqueueGscOutputRecord())
522 return;
523 if (old_gsc_outputs_queued == 0 && gsc_output_buffer_queued_count_ != 0) {
524 // We just started up a previously empty queue.
525 // Queue state changed; signal interrupt.
526 if (!SetDevicePollInterrupt())
527 return;
528 // Start VIDIOC_STREAMON if we haven't yet.
529 if (!gsc_output_streamon_) {
530 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
531 IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_STREAMON, &type);
532 gsc_output_streamon_ = true;
533 }
534 }
535 }
536 // Bug check: GSC is liable to race conditions if more than one buffer is
537 // simultaneously queued.
538 DCHECK_GE(1, gsc_output_buffer_queued_count_);
539 }
540
541 void ExynosVideoEncodeAccelerator::DequeueGsc() {
542 DVLOG(3) << "DequeueGsc()";
543 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
544
545 // Dequeue completed GSC input (VIDEO_OUTPUT) buffers, and recycle to the free
546 // list.
547 struct v4l2_buffer dqbuf;
548 struct v4l2_plane planes[3];
549 while (gsc_input_buffer_queued_count_ > 0) {
550 DCHECK(gsc_input_streamon_);
551 memset(&dqbuf, 0, sizeof(dqbuf));
552 memset(&planes, 0, sizeof(planes));
553 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
554 dqbuf.memory = V4L2_MEMORY_USERPTR;
555 dqbuf.m.planes = planes;
556 dqbuf.length = arraysize(planes);
557 if (ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf) != 0) {
558 if (errno == EAGAIN) {
559 // EAGAIN if we're just out of buffers to dequeue.
560 break;
561 }
562 DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
563 NOTIFY_ERROR(kPlatformFailureError);
564 return;
565 }
566 GscInputRecord& input_record = gsc_input_buffer_map_[dqbuf.index];
567 DCHECK(input_record.at_device);
568 DCHECK(input_record.buffer_ref.get());
569 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
570 &Client::NotifyInputDone, client_, input_record.buffer_ref->id));
571 input_record.at_device = false;
572 input_record.buffer_ref.reset();
573 gsc_free_input_buffers_.push_back(dqbuf.index);
574 gsc_input_buffer_queued_count_--;
575 }
576
577 // Dequeue completed GSC output (VIDEO_CAPTURE) buffers, and recycle to the
578 // free list. Queue the corresponding MFC buffer to the GSC->MFC holding
579 // queue.
580 while (gsc_output_buffer_queued_count_ > 0) {
581 DCHECK(gsc_output_streamon_);
582 memset(&dqbuf, 0, sizeof(dqbuf));
583 memset(&planes, 0, sizeof(planes));
584 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
585 dqbuf.memory = V4L2_MEMORY_DMABUF;
586 dqbuf.m.planes = planes;
587 dqbuf.length = 2;
588 if (ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf) != 0) {
589 if (errno == EAGAIN) {
590 // EAGAIN if we're just out of buffers to dequeue.
591 break;
592 }
593 DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
594 NOTIFY_ERROR(kPlatformFailureError);
595 return;
596 }
597 GscOutputRecord& output_record = gsc_output_buffer_map_[dqbuf.index];
598 DCHECK(output_record.at_device);
599 DCHECK(output_record.mfc_input != -1);
600 mfc_ready_input_buffers_.push_back(output_record.mfc_input);
601 output_record.at_device = false;
602 output_record.mfc_input = -1;
603 gsc_free_output_buffers_.push_back(dqbuf.index);
604 gsc_output_buffer_queued_count_--;
605 }
606 }
607 void ExynosVideoEncodeAccelerator::EnqueueMfc() {
608 DVLOG(3) << "EnqueueMfc()";
609
610 // Enqueue all the MFC inputs we can.
611 const int old_mfc_inputs_queued = mfc_input_buffer_queued_count_;
612 while (!mfc_free_input_buffers_.empty() && !encoder_input_queue_.empty()) {
Pawel Osciak 2013/08/02 13:54:45 Instead of: while (!mfc_free_input_buffers_.empty(
sheu 2013/08/03 02:41:19 Fixed up already, thanks.
613 if (!EnqueueMfcInputRecord())
614 return;
615 }
616 if (old_mfc_inputs_queued == 0 && mfc_input_buffer_queued_count_ != 0) {
617 // We just started up a previously empty queue.
618 // Queue state changed; signal interrupt.
619 if (!SetDevicePollInterrupt())
620 return;
621 // Start VIDIOC_STREAMON if we haven't yet.
622 if (!mfc_input_streamon_) {
623 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
624 IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_STREAMON, &type);
625 mfc_input_streamon_ = true;
626 }
627 }
628
629 // Enqueue all the MFC outputs we can.
630 const int old_mfc_outputs_queued = mfc_output_buffer_queued_count_;
631 while (!mfc_free_output_buffers_.empty() && !encoder_output_queue_.empty()) {
632 if (!EnqueueMfcOutputRecord())
633 return;
634 }
635 if (old_mfc_outputs_queued == 0 && mfc_output_buffer_queued_count_ != 0) {
636 // We just started up a previously empty queue.
637 // Queue state changed; signal interrupt.
638 if (!SetDevicePollInterrupt())
639 return;
640 // Start VIDIOC_STREAMON if we haven't yet.
641 if (!mfc_output_streamon_) {
642 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
643 IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_STREAMON, &type);
644 mfc_output_streamon_ = true;
645 }
646 }
647 }
648
649 void ExynosVideoEncodeAccelerator::DequeueMfc() {
650 DVLOG(3) << "DequeueMfc";
651
652 // Dequeue completed MFC input (VIDEO_OUTPUT) buffers, and recycle to the free
653 // list.
654 struct v4l2_buffer dqbuf;
655 struct v4l2_plane planes[2];
656 while (mfc_input_buffer_queued_count_ > 0) {
657 DCHECK(mfc_input_streamon_);
658 memset(&dqbuf, 0, sizeof(dqbuf));
659 memset(&planes, 0, sizeof(planes));
660 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
661 dqbuf.memory = V4L2_MEMORY_MMAP;
662 dqbuf.m.planes = planes;
663 dqbuf.length = 2;
664 if (ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf) != 0) {
665 if (errno == EAGAIN) {
666 // EAGAIN if we're just out of buffers to dequeue.
667 break;
668 }
669 DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
670 NOTIFY_ERROR(kPlatformFailureError);
671 return;
672 }
673 MfcInputRecord& input_record = mfc_input_buffer_map_[dqbuf.index];
674 DCHECK(input_record.at_device);
675 input_record.at_device = false;
676 mfc_free_input_buffers_.push_back(dqbuf.index);
677 mfc_input_buffer_queued_count_--;
678 }
679
680 // Dequeue completed MFC output (VIDEO_CAPTURE) buffers, and recycle to the
681 // free list. Notify the client that an output buffer is complete.
682 while (mfc_output_buffer_queued_count_ > 0) {
683 DCHECK(mfc_output_streamon_);
684 memset(&dqbuf, 0, sizeof(dqbuf));
685 memset(planes, 0, sizeof(planes));
686 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
687 dqbuf.memory = V4L2_MEMORY_USERPTR;
688 dqbuf.m.planes = planes;
689 dqbuf.length = 1;
690 if (ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf) != 0) {
691 if (errno == EAGAIN) {
692 // EAGAIN if we're just out of buffers to dequeue.
693 break;
694 }
695 DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
696 NOTIFY_ERROR(kPlatformFailureError);
697 return;
698 }
699 MfcOutputRecord& output_record = mfc_output_buffer_map_[dqbuf.index];
700 DCHECK(output_record.at_device);
701 DCHECK(output_record.buffer_ref.get());
702 child_message_loop_proxy_->PostTask(
703 FROM_HERE,
704 base::Bind(&Client::BitstreamBufferReady,
705 client_,
706 output_record.buffer_ref->id,
707 dqbuf.m.planes[0].bytesused,
708 false));
709 output_record.at_device = false;
710 output_record.buffer_ref.reset();
711 mfc_free_output_buffers_.push_back(dqbuf.index);
712 mfc_output_buffer_queued_count_--;
713 }
714 }
715
716 bool ExynosVideoEncodeAccelerator::EnqueueGscInputRecord() {
717 DVLOG(3) << "EnqueueGscInputRecord()";
718 DCHECK(!encoder_input_queue_.empty());
719 DCHECK(!gsc_free_input_buffers_.empty());
720
721 // Enqueue a GSC input (VIDEO_OUTPUT) buffer for an input video frame
722 linked_ptr<BitstreamBufferRef> input_buffer = encoder_input_queue_.front();
723 const int gsc_buffer = gsc_free_input_buffers_.back();
724 GscInputRecord& input_record = gsc_input_buffer_map_[gsc_buffer];
Pawel Osciak 2013/08/02 11:29:55 I think you need: input_record.buffer_ref = input
sheu 2013/08/03 02:41:19 Yeah, there was a segfault further down at l.733.
725 DCHECK(!input_record.at_device);
726 DCHECK(!input_record.buffer_ref.get());
Pawel Osciak 2013/08/02 11:29:55 s/!//, unless you wanted to DCHECK this before ass
sheu 2013/08/03 02:41:19 That was the idea.
727 struct v4l2_buffer qbuf;
728 struct v4l2_plane qbuf_planes[3];
729 memset(&qbuf, 0, sizeof(qbuf));
730 memset(qbuf_planes, 0, sizeof(qbuf_planes));
731 qbuf.index = gsc_buffer;
732 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
733 qbuf.timestamp.tv_sec = input_record.buffer_ref->id;
734 qbuf.memory = V4L2_MEMORY_USERPTR;
735 qbuf.m.planes = qbuf_planes;
736 switch (input_format_fourcc_) {
737 case V4L2_PIX_FMT_RGB32: {
738 const uint8* data =
739 reinterpret_cast<const uint8*>(input_buffer->shm->memory());
740 qbuf.m.planes[0].bytesused = input_allocated_size_.GetArea() * 4;
741 qbuf.m.planes[0].length = input_allocated_size_.GetArea() * 4;
742 qbuf.m.planes[0].m.userptr = reinterpret_cast<unsigned long>(data);
743 qbuf.length = 1;
744 break;
745 }
746 case V4L2_PIX_FMT_YUV420M: {
747 const uint8* data =
748 reinterpret_cast<const uint8*>(input_buffer->shm->memory());
749 qbuf.m.planes[0].bytesused = input_allocated_size_.GetArea();
750 qbuf.m.planes[0].length = input_allocated_size_.GetArea();
751 qbuf.m.planes[0].m.userptr = reinterpret_cast<unsigned long>(data);
752 data += qbuf.m.planes[0].length;
753 qbuf.m.planes[1].bytesused = input_allocated_size_.GetArea() / 4;
754 qbuf.m.planes[1].length = input_allocated_size_.GetArea() / 4;
755 qbuf.m.planes[1].m.userptr = reinterpret_cast<unsigned long>(data);
756 data += qbuf.m.planes[1].length;
757 qbuf.m.planes[2].bytesused = input_allocated_size_.GetArea() / 4;
758 qbuf.m.planes[2].length = input_allocated_size_.GetArea() / 4;
759 qbuf.m.planes[2].m.userptr = reinterpret_cast<unsigned long>(data);
760 qbuf.length = 3;
761 break;
762 }
763 default:
764 NOTREACHED();
765 NOTIFY_ERROR(kIllegalStateError);
766 return false;
767 }
768 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_QBUF, &qbuf);
769 input_record.at_device = true;
770 input_record.buffer_ref = input_buffer;
771 encoder_input_queue_.pop_front();
772 gsc_free_input_buffers_.pop_back();
773 gsc_input_buffer_queued_count_++;
774 DVLOG(3) << "EnqueueGscInputRecord(): enqueued buffer=" << gsc_buffer
775 << ", frame_id=" << input_buffer->id;
776 return true;
777 }
778
779 bool ExynosVideoEncodeAccelerator::EnqueueGscOutputRecord() {
780 DVLOG(3) << "EnqueueGscOutputRecord()";
781 DCHECK(!gsc_free_output_buffers_.empty());
782 DCHECK(!mfc_free_input_buffers_.empty());
783
784 // Enqueue a GSC output (VIDEO_CAPTURE) buffer.
785 const int gsc_buffer = gsc_free_output_buffers_.back();
786 const int mfc_buffer = mfc_free_input_buffers_.back();
787 GscOutputRecord& output_record = gsc_output_buffer_map_[gsc_buffer];
788 MfcInputRecord& input_record = mfc_input_buffer_map_[mfc_buffer];
789 DCHECK(!output_record.at_device);
790 DCHECK_EQ(output_record.mfc_input, -1);
791 DCHECK(!input_record.at_device);
792 struct v4l2_buffer qbuf;
793 struct v4l2_plane qbuf_planes[2];
794 memset(&qbuf, 0, sizeof(qbuf));
795 memset(qbuf_planes, 0, sizeof(qbuf_planes));
796 qbuf.index = gsc_buffer;
797 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
798 qbuf.memory = V4L2_MEMORY_DMABUF;
799 qbuf.m.planes = qbuf_planes;
800 qbuf.m.planes[0].m.fd = input_record.fd[0];
801 qbuf.m.planes[1].m.fd = input_record.fd[1];
802 qbuf.length = 2;
803 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_QBUF, &qbuf);
804 output_record.at_device = true;
805 output_record.mfc_input = mfc_buffer;
806 mfc_free_input_buffers_.pop_back();
807 gsc_free_output_buffers_.pop_back();
808 gsc_output_buffer_queued_count_++;
809 return true;
810 }
811
812 bool ExynosVideoEncodeAccelerator::EnqueueMfcInputRecord() {
813 DVLOG(3) << "EnqueueMfcInputRecord()";
814 DCHECK(!mfc_ready_input_buffers_.empty());
815
816 // Enqueue a MFC input (VIDEO_OUTPUT) buffer.
817 const int mfc_buffer = mfc_ready_input_buffers_.front();
818 MfcInputRecord& input_record = mfc_input_buffer_map_[mfc_buffer];
819 DCHECK(!input_record.at_device);
820 struct v4l2_buffer qbuf;
821 struct v4l2_plane qbuf_planes[2];
822 memset(&qbuf, 0, sizeof(qbuf));
823 memset(qbuf_planes, 0, sizeof(qbuf_planes));
824 qbuf.index = mfc_buffer;
825 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
826 qbuf.memory = V4L2_MEMORY_MMAP;
827 qbuf.m.planes = qbuf_planes;
828 qbuf.length = 2;
829 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_QBUF, &qbuf);
830 input_record.at_device = true;
831 mfc_ready_input_buffers_.pop_front();
832 mfc_input_buffer_queued_count_++;
833 return true;
834 }
835
836 bool ExynosVideoEncodeAccelerator::EnqueueMfcOutputRecord() {
837 DVLOG(3) << "EnqueueMfcOutputRecord()";
838 DCHECK(!mfc_free_output_buffers_.empty());
839 DCHECK(!encoder_output_queue_.empty());
840
841 // Enqueue a MFC output (VIDEO_CAPTURE) buffer.
842 linked_ptr<BitstreamBufferRef> output_buffer = encoder_output_queue_.back();
843 const int mfc_buffer = mfc_free_output_buffers_.back();
844 MfcOutputRecord& output_record = mfc_output_buffer_map_[mfc_buffer];
845 DCHECK(!output_record.at_device);
846 DCHECK(!output_record.buffer_ref.get());
847 struct v4l2_buffer qbuf;
848 struct v4l2_plane qbuf_planes[1];
849 memset(&qbuf, 0, sizeof(qbuf));
850 memset(qbuf_planes, 0, sizeof(qbuf_planes));
851 qbuf.index = mfc_buffer;
852 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
853 qbuf.memory = V4L2_MEMORY_USERPTR;
854 qbuf.m.planes = qbuf_planes;
855 qbuf.m.planes[0].bytesused = output_buffer->size;
856 qbuf.m.planes[0].length = output_buffer->size;
857 qbuf.m.planes[0].m.userptr =
858 reinterpret_cast<unsigned long>(output_buffer->shm->memory());
859 qbuf.length = 1;
860 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_QBUF, &qbuf);
861 output_record.at_device = true;
862 output_record.buffer_ref = output_buffer;
863 encoder_output_queue_.pop_back();
864 mfc_free_output_buffers_.pop_back();
865 mfc_output_buffer_queued_count_++;
866 return true;
867 }
868
869 bool ExynosVideoEncodeAccelerator::StartDevicePoll() {
870 DVLOG(3) << "StartDevicePoll()";
871 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
872 DCHECK(!device_poll_thread_.IsRunning());
873
874 // Start up the device poll thread and schedule its first DevicePollTask().
875 if (!device_poll_thread_.Start()) {
876 DLOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
877 NOTIFY_ERROR(kPlatformFailureError);
878 return false;
879 }
880 device_poll_thread_.message_loop()->PostTask(
881 FROM_HERE,
882 base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
883 base::Unretained(this),
884 0));
885
886 return true;
887 }
888
889 bool ExynosVideoEncodeAccelerator::StopDevicePoll() {
890 DVLOG(3) << "StopDevicePoll()";
891
892 // Signal the DevicePollTask() to stop, and stop the device poll thread.
893 if (!SetDevicePollInterrupt())
894 return false;
895 device_poll_thread_.Stop();
896 // Clear the interrupt now, to be sure.
897 if (!ClearDevicePollInterrupt())
898 return false;
899
900 // Stop streaming.
901 if (gsc_input_streamon_) {
902 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
903 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_STREAMOFF, &type);
904 }
905 gsc_input_streamon_ = false;
906 if (gsc_output_streamon_) {
907 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
908 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_STREAMOFF, &type);
909 }
910 gsc_output_streamon_ = false;
911 if (mfc_input_streamon_) {
912 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
913 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_STREAMOFF, &type);
914 }
915 mfc_input_streamon_ = false;
916 if (mfc_output_streamon_) {
917 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
918 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_STREAMOFF, &type);
919 }
920 mfc_output_streamon_ = false;
921
922 // Reset all our accounting info.
923 encoder_input_queue_.clear();
924 gsc_free_input_buffers_.clear();
925 for (size_t i = 0; i < gsc_input_buffer_map_.size(); ++i) {
926 GscInputRecord& input_record = gsc_input_buffer_map_[i];
927 input_record.at_device = false;
928 input_record.buffer_ref.reset();
929 gsc_free_input_buffers_.push_back(i);
930 }
931 gsc_input_buffer_queued_count_ = 0;
932 gsc_free_output_buffers_.clear();
933 for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i) {
934 GscOutputRecord& output_record = gsc_output_buffer_map_[i];
935 output_record.at_device = false;
936 output_record.mfc_input = -1;
937 gsc_free_output_buffers_.push_back(i);
938 }
939 gsc_output_buffer_queued_count_ = 0;
940 mfc_ready_input_buffers_.clear();
941 mfc_free_input_buffers_.clear();
942 for (size_t i = 0; i < mfc_input_buffer_map_.size(); ++i) {
943 MfcInputRecord& input_record = mfc_input_buffer_map_[i];
944 input_record.at_device = false;
945 mfc_free_input_buffers_.push_back(i);
946 }
947 mfc_input_buffer_queued_count_ = 0;
948 mfc_free_output_buffers_.clear();
949 for (size_t i = 0; i < mfc_output_buffer_map_.size(); ++i) {
950 MfcOutputRecord& output_record = mfc_output_buffer_map_[i];
951 output_record.at_device = false;
952 output_record.buffer_ref.reset();
953 mfc_free_output_buffers_.push_back(i);
954 }
955 mfc_output_buffer_queued_count_ = 0;
956 encoder_output_queue_.clear();
957
958 DVLOG(3) << "StopDevicePoll(): device poll stopped";
959 return true;
960 }
961
962 bool ExynosVideoEncodeAccelerator::SetDevicePollInterrupt() {
963 DVLOG(3) << "SetDevicePollInterrupt()";
964
965 const uint64 buf = 1;
966 if (HANDLE_EINTR(write(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) {
967 DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed";
968 NOTIFY_ERROR(kPlatformFailureError);
969 return false;
970 }
971 return true;
972 }
973
974 bool ExynosVideoEncodeAccelerator::ClearDevicePollInterrupt() {
975 DVLOG(3) << "ClearDevicePollInterrupt()";
976
977 uint64 buf;
978 if (HANDLE_EINTR(read(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) {
979 if (errno == EAGAIN) {
980 // No interrupt flag set, and we're reading nonblocking. Not an error.
981 return true;
982 } else {
983 DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
984 NOTIFY_ERROR(kPlatformFailureError);
985 return false;
986 }
987 }
988 return true;
989 }
990
991 void ExynosVideoEncodeAccelerator::DevicePollTask(unsigned int poll_fds) {
992 DVLOG(3) << "DevicePollTask()";
993 DCHECK_EQ(device_poll_thread_.message_loop(), base::MessageLoop::current());
994
995 // This routine just polls the set of device fds, and schedules a
996 // ServiceDeviceTask() on encoder_thread_ when processing needs to occur.
997 // Other threads may notify this task to return early by writing to
998 // device_poll_interrupt_fd_.
999 struct pollfd pollfds[3];
1000 nfds_t nfds;
1001
1002 // Add device_poll_interrupt_fd_;
1003 pollfds[0].fd = device_poll_interrupt_fd_;
1004 pollfds[0].events = POLLIN | POLLERR;
1005 nfds = 1;
1006
1007 // Add GSC fd, if we should poll on it.
1008 // GSC has to wait until both input and output buffers are queued.
1009 if (poll_fds & kPollGsc) {
1010 VLOG(3) << "DevicePollTask(): adding GSC to poll() set";
1011 pollfds[nfds].fd = gsc_fd_;
1012 pollfds[nfds].events = POLLIN | POLLOUT | POLLERR;
1013 nfds++;
1014 }
1015 if (poll_fds & kPollMfc) {
1016 DVLOG(3) << "DevicePollTask(): adding MFC to poll() set";
1017 pollfds[nfds].fd = mfc_fd_;
1018 pollfds[nfds].events = POLLIN | POLLOUT | POLLERR;
1019 nfds++;
1020 }
1021
1022 // Poll it!
1023 if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
1024 DPLOG(ERROR) << "DevicePollTask(): poll() failed";
1025 NOTIFY_ERROR(kPlatformFailureError);
1026 return;
1027 }
1028
1029 // All processing should happen on ServiceDeviceTask(), since we shouldn't
1030 // touch encoder state from this thread.
1031 encoder_thread_.message_loop()->PostTask(
1032 FROM_HERE,
1033 base::Bind(&ExynosVideoEncodeAccelerator::ServiceDeviceTask,
1034 base::Unretained(this)));
1035 }
1036
1037 void ExynosVideoEncodeAccelerator::NotifyError(Error error) {
1038 DVLOG(1) << "NotifyError(): error=" << error;
1039
1040 if (!child_message_loop_proxy_->BelongsToCurrentThread()) {
1041 child_message_loop_proxy_->PostTask(
1042 FROM_HERE,
1043 base::Bind(
1044 &ExynosVideoEncodeAccelerator::NotifyError, weak_this_, error));
1045 return;
1046 }
1047
1048 if (client_) {
1049 client_->NotifyError(error);
1050 client_ptr_factory_.InvalidateWeakPtrs();
1051 }
1052 }
1053
1054 void ExynosVideoEncodeAccelerator::SetEncoderState(State state) {
1055 DVLOG(3) << "SetEncoderState(): state=" << state;
1056
1057 // We can touch encoder_state_ only if this is the encoder thread or the
1058 // encoder thread isn't running.
1059 if (encoder_thread_.message_loop() != NULL &&
1060 encoder_thread_.message_loop() != base::MessageLoop::current()) {
1061 encoder_thread_.message_loop()->PostTask(
1062 FROM_HERE,
1063 base::Bind(&ExynosVideoEncodeAccelerator::SetEncoderState,
1064 base::Unretained(this),
1065 state));
1066 } else {
1067 encoder_state_ = state;
1068 }
1069 }
1070
1071 void ExynosVideoEncodeAccelerator::SetBitrateTask(int32 bitrate) {
1072 DVLOG(3) << "SetBitrateTask(): bitrate=" << bitrate;
1073
1074 struct v4l2_ext_control ctrls[1];
1075 struct v4l2_ext_controls control;
1076 memset(&ctrls, 0, sizeof(ctrls));
1077 memset(&control, 0, sizeof(control));
1078 ctrls[0].id = V4L2_CID_MPEG_VIDEO_BITRATE;
1079 ctrls[0].value = bitrate;
1080 control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
1081 control.count = 1;
1082 control.controls = ctrls;
1083 IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
1084 }
1085
1086 bool ExynosVideoEncodeAccelerator::CreateGscInputBuffers() {
1087 DVLOG(3) << "CreateGscInputBuffers()";
1088 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1089 DCHECK_EQ(encoder_state_, kUninitialized);
1090 DCHECK(!gsc_input_streamon_);
1091
1092 struct v4l2_control control;
1093 memset(&control, 0, sizeof(control));
1094 control.id = V4L2_CID_ROTATE;
1095 control.value = 0;
1096 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
1097
1098 // HFLIP actually seems to control vertical mirroring for GSC, and vice-versa.
1099 memset(&control, 0, sizeof(control));
1100 control.id = V4L2_CID_HFLIP;
1101 control.value = 1;
1102 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
1103
1104 memset(&control, 0, sizeof(control));
1105 control.id = V4L2_CID_VFLIP;
1106 control.value = 0;
1107 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
1108
1109 memset(&control, 0, sizeof(control));
1110 control.id = V4L2_CID_GLOBAL_ALPHA;
1111 control.value = 255;
1112 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
1113
1114 struct v4l2_format format;
1115 memset(&format, 0, sizeof(format));
1116 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1117 format.fmt.pix_mp.width = input_allocated_size_.width();
1118 format.fmt.pix_mp.height = input_allocated_size_.height();
1119 format.fmt.pix_mp.pixelformat = input_format_fourcc_;
1120 switch (input_format_fourcc_) {
1121 case V4L2_PIX_FMT_RGB32:
1122 format.fmt.pix_mp.plane_fmt[0].sizeimage =
1123 input_allocated_size_.GetArea() * 4;
1124 format.fmt.pix_mp.plane_fmt[0].bytesperline =
1125 input_allocated_size_.width() * 4;
1126 format.fmt.pix_mp.num_planes = 1;
1127 break;
1128 case V4L2_PIX_FMT_YUV420M:
1129 format.fmt.pix_mp.plane_fmt[0].sizeimage =
1130 input_allocated_size_.GetArea();
1131 format.fmt.pix_mp.plane_fmt[0].bytesperline =
1132 input_allocated_size_.width();
1133 format.fmt.pix_mp.plane_fmt[1].sizeimage =
1134 input_allocated_size_.GetArea() / 4;
1135 format.fmt.pix_mp.plane_fmt[1].bytesperline =
1136 input_allocated_size_.width() / 2;
1137 format.fmt.pix_mp.plane_fmt[2].sizeimage =
1138 input_allocated_size_.GetArea() / 4;
1139 format.fmt.pix_mp.plane_fmt[2].bytesperline =
1140 input_allocated_size_.width() / 2;
1141 format.fmt.pix_mp.num_planes = 3;
1142 break;
1143 default:
1144 NOTREACHED();
1145 NOTIFY_ERROR(kIllegalStateError);
1146 return false;
1147 }
1148 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_FMT, &format);
1149
1150 struct v4l2_crop crop;
1151 memset(&crop, 0, sizeof(crop));
1152 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1153 crop.c.left = 0;
1154 crop.c.top = 0;
1155 crop.c.width = input_visible_size_.width();
1156 crop.c.height = input_visible_size_.height();
1157 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CROP, &crop);
1158
1159 struct v4l2_requestbuffers reqbufs;
1160 memset(&reqbufs, 0, sizeof(reqbufs));
1161 reqbufs.count = kGscInputBufferCount;
1162 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1163 reqbufs.memory = V4L2_MEMORY_USERPTR;
1164 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
1165
1166 DCHECK(gsc_input_buffer_map_.empty());
1167 gsc_input_buffer_map_.resize(reqbufs.count);
1168 for (size_t i = 0; i < gsc_input_buffer_map_.size(); ++i)
1169 gsc_free_input_buffers_.push_back(i);
1170
1171 return true;
1172 }
1173
1174 bool ExynosVideoEncodeAccelerator::CreateGscOutputBuffers() {
1175 DVLOG(3) << "CreateGscOutputBuffers()";
1176 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1177 DCHECK_EQ(encoder_state_, kUninitialized);
1178 DCHECK(!gsc_output_streamon_);
1179
1180 struct v4l2_format format;
1181 memset(&format, 0, sizeof(format));
1182 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1183 format.fmt.pix_mp.width = converted_allocated_size_.width();
1184 format.fmt.pix_mp.height = converted_allocated_size_.height();
1185 format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
1186 format.fmt.pix_mp.plane_fmt[0].sizeimage =
1187 converted_allocated_size_.GetArea();
1188 format.fmt.pix_mp.plane_fmt[1].sizeimage =
1189 converted_allocated_size_.GetArea() / 2;
1190 format.fmt.pix_mp.plane_fmt[0].bytesperline =
1191 converted_allocated_size_.width();
1192 format.fmt.pix_mp.plane_fmt[1].bytesperline =
1193 converted_allocated_size_.width();
1194 format.fmt.pix_mp.num_planes = 2;
1195 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_FMT, &format);
1196
1197 struct v4l2_crop crop;
1198 memset(&crop, 0, sizeof(crop));
1199 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1200 crop.c.left = 0;
1201 crop.c.top = 0;
1202 crop.c.width = converted_visible_size_.width();
1203 crop.c.height = converted_visible_size_.height();
1204 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CROP, &crop);
1205
1206 struct v4l2_requestbuffers reqbufs;
1207 memset(&reqbufs, 0, sizeof(reqbufs));
1208 reqbufs.count = kGscOutputBufferCount;
1209 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1210 reqbufs.memory = V4L2_MEMORY_DMABUF;
1211 IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
1212
1213 DCHECK(gsc_output_buffer_map_.empty());
1214 gsc_output_buffer_map_.resize(reqbufs.count);
1215 for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i)
1216 gsc_free_output_buffers_.push_back(i);
1217 return true;
1218 }
1219
1220 bool ExynosVideoEncodeAccelerator::SetMfcFormats() {
1221 DVLOG(3) << "SetMfcFormats()";
1222 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1223 DCHECK(!mfc_input_streamon_);
1224 DCHECK(!mfc_output_streamon_);
1225
1226 // VIDIOC_S_FMT on OUTPUT queue.
1227 struct v4l2_format format;
1228 memset(&format, 0, sizeof(format));
1229 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1230 format.fmt.pix_mp.width = input_allocated_size_.width();
1231 format.fmt.pix_mp.height = input_allocated_size_.height();
1232 format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
1233 format.fmt.pix_mp.num_planes = 2;
1234 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_FMT, &format);
1235 // We read direct from GSC, so we rely on the HW not changing our set
1236 // size/stride.
1237 DCHECK_EQ(format.fmt.pix_mp.plane_fmt[0].sizeimage,
1238 static_cast<__u32>(input_allocated_size_.GetArea()));
1239 DCHECK_EQ(format.fmt.pix_mp.plane_fmt[0].bytesperline,
1240 static_cast<__u32>(input_allocated_size_.width()));
1241 DCHECK_EQ(format.fmt.pix_mp.plane_fmt[1].sizeimage,
1242 static_cast<__u32>(input_allocated_size_.GetArea() / 2));
1243 DCHECK_EQ(format.fmt.pix_mp.plane_fmt[1].bytesperline,
1244 static_cast<__u32>(input_allocated_size_.width()));
1245
1246 struct v4l2_crop crop;
1247 memset(&crop, 0, sizeof(crop));
1248 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1249 crop.c.left = 0;
1250 crop.c.top = 0;
1251 crop.c.width = input_visible_size_.width();
1252 crop.c.height = input_visible_size_.height();
1253 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_CROP, &crop);
1254
1255 // VIDIOC_S_FMT on CAPTURE queue.
1256 output_buffer_byte_size_ = kMfcOutputBufferSize;
1257 memset(&format, 0, sizeof(format));
1258 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1259 format.fmt.pix_mp.width = output_visible_size_.width();
1260 format.fmt.pix_mp.height = output_visible_size_.height();
1261 format.fmt.pix_mp.pixelformat = output_format_fourcc_;
1262 format.fmt.pix_mp.plane_fmt[0].sizeimage = output_buffer_byte_size_;
1263 format.fmt.pix_mp.num_planes = 1;
1264 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_FMT, &format);
1265
1266 struct v4l2_ext_control ctrls[7];
1267 struct v4l2_ext_controls control;
1268 memset(&ctrls, 0, sizeof(ctrls));
1269 memset(&control, 0, sizeof(control));
1270 ctrls[0].id = V4L2_CID_MPEG_VIDEO_B_FRAMES;
1271 ctrls[0].value = 0;
1272 ctrls[1].id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
1273 ctrls[1].value = 1;
1274 ctrls[2].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF;
1275 ctrls[2].value = 10;
1276 ctrls[3].id = V4L2_CID_MPEG_VIDEO_BITRATE;
1277 ctrls[3].value = 20480000;
1278 // These next controls are temporary, for debugging.
1279 ctrls[4].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
1280 ctrls[4].value = 16;
1281 ctrls[5].id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
1282 ctrls[5].value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE;
1283 ctrls[6].id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
1284 ctrls[6].value = 51;
1285 control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
1286 control.count = arraysize(ctrls);
1287 control.controls = ctrls;
1288 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
1289
1290 struct v4l2_streamparm parms;
1291 memset(&parms, 0, sizeof(parms));
1292 parms.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1293 parms.parm.output.timeperframe.numerator = 1000;
1294 parms.parm.output.timeperframe.denominator = 25;
1295 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_PARM, &parms);
1296
1297 return true;
1298 }
1299
1300 bool ExynosVideoEncodeAccelerator::CreateMfcInputBuffers() {
1301 DVLOG(3) << "CreateMfcInputBuffers()";
1302 // This function runs on encoder_thread_ after output buffers have been
1303 // provided by the client.
1304 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
1305 DCHECK(!mfc_input_streamon_);
1306
1307 struct v4l2_requestbuffers reqbufs;
1308 memset(&reqbufs, 0, sizeof(reqbufs));
1309 reqbufs.count = 0; // Driver will allocate the appropriate number of buffers.
1310 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1311 reqbufs.memory = V4L2_MEMORY_MMAP;
1312 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
1313
1314 DCHECK(mfc_input_buffer_map_.empty());
1315 mfc_input_buffer_map_.resize(reqbufs.count);
1316 for (size_t i = 0; i < mfc_input_buffer_map_.size(); ++i) {
1317 MfcInputRecord& input_record = mfc_input_buffer_map_[i];
1318 for (int j = 0; j < 2; ++j) {
1319 // Export the DMABUF fd so GSC can write to it.
1320 struct v4l2_exportbuffer expbuf;
1321 memset(&expbuf, 0, sizeof(expbuf));
1322 expbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1323 expbuf.index = i;
1324 expbuf.plane = j;
1325 expbuf.flags = O_CLOEXEC;
1326 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_EXPBUF, &expbuf);
1327 input_record.fd[j] = expbuf.fd;
1328 }
1329 mfc_free_input_buffers_.push_back(i);
1330 }
1331
1332 return true;
1333 }
1334
1335 bool ExynosVideoEncodeAccelerator::CreateMfcOutputBuffers() {
1336 DVLOG(3) << "CreateMfcOutputBuffers()";
1337 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1338 DCHECK(!mfc_output_streamon_);
1339
1340 struct v4l2_requestbuffers reqbufs;
1341 memset(&reqbufs, 0, sizeof(reqbufs));
1342 reqbufs.count = kMfcOutputBufferCount;
1343 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1344 reqbufs.memory = V4L2_MEMORY_USERPTR;
1345 IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
1346
1347 DCHECK(mfc_output_buffer_map_.empty());
1348 mfc_output_buffer_map_.resize(reqbufs.count);
1349 for (size_t i = 0; i < mfc_output_buffer_map_.size(); ++i)
1350 mfc_free_output_buffers_.push_back(i);
1351
1352 return true;
1353 }
1354
1355 void ExynosVideoEncodeAccelerator::DestroyGscInputBuffers() {
1356 DVLOG(3) << "DestroyGscInputBuffers()";
1357 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1358 DCHECK(!gsc_input_streamon_);
1359
1360 struct v4l2_requestbuffers reqbufs;
1361 memset(&reqbufs, 0, sizeof(reqbufs));
1362 reqbufs.count = 0;
1363 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1364 reqbufs.memory = V4L2_MEMORY_USERPTR;
1365 if (ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs) != 0)
1366 DPLOG(ERROR) << "DestroyGscInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1367
1368 gsc_input_buffer_map_.clear();
1369 gsc_free_input_buffers_.clear();
1370 }
1371
1372 void ExynosVideoEncodeAccelerator::DestroyGscOutputBuffers() {
1373 DVLOG(3) << "DestroyGscOutputBuffers()";
1374 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1375 DCHECK(!gsc_output_streamon_);
1376
1377 struct v4l2_requestbuffers reqbufs;
1378 memset(&reqbufs, 0, sizeof(reqbufs));
1379 reqbufs.count = 0;
1380 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1381 reqbufs.memory = V4L2_MEMORY_DMABUF;
1382 if (ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs) != 0)
1383 DPLOG(ERROR) << "DestroyGscOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1384
1385 gsc_output_buffer_map_.clear();
1386 gsc_free_output_buffers_.clear();
1387 }
1388
1389 void ExynosVideoEncodeAccelerator::DestroyMfcInputBuffers() {
1390 DVLOG(3) << "DestroyMfcInputBuffers()";
1391 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1392 DCHECK(!mfc_input_streamon_);
1393
1394 struct v4l2_requestbuffers reqbufs;
1395 memset(&reqbufs, 0, sizeof(reqbufs));
1396 reqbufs.count = 0;
1397 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1398 reqbufs.memory = V4L2_MEMORY_MMAP;
1399 if (ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs) != 0)
1400 DPLOG(ERROR) << "DestroyMfcInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1401
1402 mfc_input_buffer_map_.clear();
1403 mfc_free_input_buffers_.clear();
1404 }
1405
1406 void ExynosVideoEncodeAccelerator::DestroyMfcOutputBuffers() {
1407 DVLOG(3) << "DestroyMfcOutputBuffers()";
1408 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1409 DCHECK(!mfc_output_streamon_);
1410
1411 struct v4l2_requestbuffers reqbufs;
1412 memset(&reqbufs, 0, sizeof(reqbufs));
1413 reqbufs.count = 0;
1414 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1415 reqbufs.memory = V4L2_MEMORY_USERPTR;
1416 if (ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs) != 0)
1417 DPLOG(ERROR) << "DestroyMfcOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1418
1419 mfc_output_buffer_map_.clear();
1420 mfc_free_output_buffers_.clear();
1421 }
1422
1423 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/exynos_video_encode_accelerator.h ('k') | content/common/gpu/media/gpu_video_encode_accelerator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698