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

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

Powered by Google App Engine
This is Rietveld 408576698