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

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

Issue 11198060: VDA implementation for Exynos, using V4L2 (Closed) Base URL: https://git.chromium.org/git/chromium/src@git-svn
Patch Set: Halfway through .cc review.wq Created 8 years, 1 month 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) 2012 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 <dlfcn.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <linux/videodev2.h>
9 #include <sys/epoll.h>
10 #include <sys/ioctl.h>
11 #include <sys/mman.h>
12
13 #include "base/bind.h"
14 #include "base/message_loop.h"
15 #include "base/message_loop_proxy.h"
16 #include "base/shared_memory.h"
17 #include "content/common/gpu/media/exynos_video_decode_accelerator.h"
18 #include "ui/gl/gl_bindings.h"
19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_context_egl.h"
21 #include "ui/gl/gl_surface_egl.h"
22
23 namespace content {
24
25 #define NOTIFY_ERROR(x) \
26 do { \
27 LOG(ERROR) << "calling NotifyError(): " << x; \
28 NotifyError(x); \
29 } while (0)
30
31 #define EXYNOS_MFC_DEVICE "/dev/mfc-dec"
32 #define EXYNOS_GSC_DEVICE "/dev/gsc1"
33 #define EXYNOS_MALI_DRIVER "libmali.so"
34
35 static void* libmali_handle = NULL;
36 static EGLBoolean(*mali_egl_image_get_buffer_ext_phandle)(
37 EGLImageKHR, EGLint*, void*) = NULL;
38 static EGLSyncKHR(*egl_create_sync_khr)(
39 EGLDisplay, EGLenum, const EGLint*) = NULL;
40 static EGLBoolean(*egl_destroy_sync_khr)(
41 EGLDisplay, EGLSyncKHR) = NULL;
42 static EGLint(*egl_client_wait_sync_khr)(
43 EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR) = NULL;
44
45 ExynosVideoDecodeAccelerator::BitstreamBufferRecord::BitstreamBufferRecord(
46 base::SharedMemory* shm, size_t size, int32 input_id)
47 : shm(shm),
48 size(size),
49 input_id(input_id) {
50 }
51
52 ExynosVideoDecodeAccelerator::BitstreamBufferRecord::~BitstreamBufferRecord() {
53 }
54
55 ExynosVideoDecodeAccelerator::MfcInputRecord::MfcInputRecord()
56 : at_device(false),
57 offset(NULL),
58 length(0),
59 bytes_used(0),
60 input_id(-1) {
61 }
62
63 ExynosVideoDecodeAccelerator::MfcInputRecord::~MfcInputRecord() {
64 }
65
66 ExynosVideoDecodeAccelerator::MfcOutputRecord::MfcOutputRecord()
67 : at_device(false),
68 input_id(-1) {
69 bytes_used[0] = 0;
70 bytes_used[1] = 0;
71 offset[0] = NULL;
72 offset[1] = NULL;
73 length[0] = 0;
74 length[1] = 0;
75 }
76
77 ExynosVideoDecodeAccelerator::MfcOutputRecord::~MfcOutputRecord() {
78 }
79
80 ExynosVideoDecodeAccelerator::GscInputRecord::GscInputRecord()
81 : at_device(false),
82 mfc_output(-1) {
83 }
84
85 ExynosVideoDecodeAccelerator::GscInputRecord::~GscInputRecord() {
86 }
87
88 ExynosVideoDecodeAccelerator::GscOutputRecord::GscOutputRecord()
89 : at_device(false),
90 at_client(false),
91 fd(-1),
92 egl_image(EGL_NO_IMAGE_KHR),
93 egl_sync(EGL_NO_SYNC_KHR),
94 picture_id(-1) {
95 }
96
97 ExynosVideoDecodeAccelerator::GscOutputRecord::~GscOutputRecord() {
98 }
99
100 ExynosVideoDecodeAccelerator::EGLImageKHRArrayRef::EGLImageKHRArrayRef(
101 EGLDisplay egl_display, EGLImageKHR egl_images[], int egl_image_fds[],
102 int egl_images_count)
103 : egl_display(egl_display),
104 egl_images(egl_images),
105 egl_image_fds(egl_image_fds),
106 egl_images_count(egl_images_count) {
107 }
108
109 ExynosVideoDecodeAccelerator::EGLImageKHRArrayRef::~EGLImageKHRArrayRef() {
110 DCHECK_EQ(egl_images != NULL, egl_image_fds != NULL);
111 if (egl_images == NULL)
112 return;
113
114 for (int i = 0; i < egl_images_count; i++) {
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 pre-increment, not post- (everywhere)
sheu 2012/11/03 00:37:14 Style guide says both are fine for POD scalar type
115 if (egl_images[i] != EGL_NO_IMAGE_KHR)
116 eglDestroyImageKHR(egl_display, egl_images[i]);
117 if (egl_image_fds[i] != -1)
118 close(egl_image_fds[i]);
119 }
120 }
121
122 ExynosVideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef(
123 EGLDisplay egl_display, EGLSyncKHR egl_sync)
124 : egl_display(egl_display),
125 egl_sync(egl_sync) {
126 }
127
128 ExynosVideoDecodeAccelerator::EGLSyncKHRRef::~EGLSyncKHRRef() {
129 if (egl_sync != EGL_NO_SYNC_KHR)
130 egl_destroy_sync_khr(egl_display, egl_sync);
131 }
132
133 ExynosVideoDecodeAccelerator::ExynosVideoDecodeAccelerator(
134 gfx::GLContext* gl_context,
135 Client* client,
136 const base::Callback<bool(void)>& make_context_current)
137 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
138 weak_this_(base::AsWeakPtr(this)),
139 client_ptr_factory_(client),
140 client_(client_ptr_factory_.GetWeakPtr()),
141 decoder_thread_("ExynosDecoderThread"),
142 decoder_state_(kUninitialized),
143 decoder_current_bitstream_buffer_(NULL),
144 decoder_current_input_buffer_(-1),
145 decoder_decode_buffer_tasks_scheduled_(0),
146 decoder_frames_inflight_(0),
147 decoder_frames_at_client_(0),
148 decoder_flush_notify_requested_(false),
149 mfc_fd_(-1),
150 mfc_fd_closer_(&mfc_fd_),
151 mfc_input_streamon_(false),
152 mfc_input_buffer_count_(0),
153 mfc_input_buffer_queued_count_(0),
154 mfc_output_streamon_(false),
155 mfc_output_buffer_count_(0),
156 mfc_output_buffer_pixelformat_(0),
157 gsc_fd_(-1),
158 gsc_fd_closer_(&gsc_fd_),
159 gsc_input_streamon_(false),
160 gsc_input_buffer_count_(0),
161 gsc_output_streamon_(false),
162 gsc_output_buffer_count_(0),
163 gsc_output_buffer_prepared_count_(0),
164 gsc_output_buffer_queued_count_(0),
165 frame_buffer_size_(0, 0),
166 device_poll_thread_("ExynosDevicePollThread"),
167 gl_context_(gl_context),
168 make_context_current_(make_context_current),
169 egl_context_(EGL_NO_CONTEXT),
170 egl_display_(EGL_NO_DISPLAY),
171 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN) {
172 }
173
174 ExynosVideoDecodeAccelerator::~ExynosVideoDecodeAccelerator() {
175 Destroy();
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 Part of VDA::Destroy()'s API is that it deletes |t
sheu 2012/11/03 00:37:14 Did not see that. Alright, I'll have to run the V
176
177 // These maps have members that should be manually destroyed, e.g. file
178 // descriptors, mmap() segments, etc.
179 DCHECK(mfc_input_buffer_map_.empty());
180 DCHECK(mfc_output_buffer_map_.empty());
181 DCHECK(gsc_input_buffer_map_.empty());
182 DCHECK(gsc_output_buffer_map_.empty());
183 }
184
185 bool ExynosVideoDecodeAccelerator::Initialize(
186 media::VideoCodecProfile profile) {
187 DVLOG(3) << "Initialize()";
188 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
189 DCHECK_EQ(decoder_state_, kUninitialized);
190
191 switch (profile) {
192 case media::H264PROFILE_BASELINE:
193 DVLOG(2) << "Initialize(): profile H264PROFILE_BASELINE";
194 break;
195 case media::H264PROFILE_MAIN:
196 DVLOG(2) << "Initialize(): profile H264PROFILE_MAIN";
197 break;
198 case media::H264PROFILE_HIGH:
199 DVLOG(2) << "Initialize(): profile H264PROFILE_HIGH";
200 break;
201 case media::VP8PROFILE_MAIN:
202 DVLOG(2) << "Initialize(): profile VP8PROFILE_MAIN";
203 break;
204 default:
205 DLOG(ERROR) << "Initialize(): unsupported profile=" << profile;
206 return false;
207 };
208 video_profile_ = profile;
209
210 gfx::GLContextEGL* context_egl = static_cast<gfx::GLContextEGL*>(gl_context_);
211 static bool sandbox_initialized = PostSandboxInitialization();
212 if (!sandbox_initialized) {
213 DLOG(ERROR) << "Initialize(): PostSandboxInitialization() failed";
214 decoder_state_ = kError;
215 NOTIFY_ERROR(PLATFORM_FAILURE);
216 return false;
217 }
218
219 egl_context_ = reinterpret_cast<EGLContext>(context_egl->GetHandle());
220 if (egl_context_ == EGL_NO_CONTEXT) {
221 DLOG(ERROR) << "Initialize(): could not get EGLContext";
222 decoder_state_ = kError;
223 NOTIFY_ERROR(PLATFORM_FAILURE);
224 return false;
225 }
226 egl_display_ = gfx::GLSurfaceEGL::GetHardwareDisplay();
227 if (egl_display_ == EGL_NO_DISPLAY) {
228 DLOG(ERROR) << "Initialize(): could not get EGLDisplay";
229 decoder_state_ = kError;
230 NOTIFY_ERROR(PLATFORM_FAILURE);
231 return false;
232 }
233
234 // Open the video devices.
235 DVLOG(2) << "Initialize(): opening MFC device: " << EXYNOS_MFC_DEVICE;
236 errno = 0;
237 mfc_fd_ = open(EXYNOS_MFC_DEVICE, O_RDWR | O_NONBLOCK);
238 if (mfc_fd_ == -1) {
239 DPLOG(ERROR) << "Initialize(): could not open MFC device: "
240 << EXYNOS_MFC_DEVICE;
241 decoder_state_ = kError;
242 NOTIFY_ERROR(PLATFORM_FAILURE);
243 return false;
244 }
245 DVLOG(2) << "Initialize(): opening GSC device: " << EXYNOS_GSC_DEVICE;
246 errno = 0;
247 gsc_fd_ = open(EXYNOS_GSC_DEVICE, O_RDWR | O_NONBLOCK);
248 if (gsc_fd_ == -1) {
249 DPLOG(ERROR) << "Initialize(): could not open GSC device: "
250 << EXYNOS_GSC_DEVICE;
251 decoder_state_ = kError;
252 NOTIFY_ERROR(PLATFORM_FAILURE);
253 return false;
254 }
255
256 // Capabilities check.
257 int ret;
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 declare at first use (l.264 below
sheu 2012/11/03 00:37:14 Done.
258 struct v4l2_capability caps;
259 const __u32 kCapsRequired =
260 V4L2_CAP_VIDEO_CAPTURE_MPLANE |
261 V4L2_CAP_VIDEO_OUTPUT_MPLANE |
262 V4L2_CAP_STREAMING;
263 errno = 0;
264 ret = ioctl(mfc_fd_, VIDIOC_QUERYCAP, &caps);
265 if (ret != 0) {
266 DPLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP";
267 decoder_state_ = kError;
268 NOTIFY_ERROR(PLATFORM_FAILURE);
269 return false;
270 } else if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
271 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP"
272 ", caps check failed: 0x" << std::hex << caps.capabilities;
273 decoder_state_ = kError;
274 NOTIFY_ERROR(PLATFORM_FAILURE);
275 return false;
276 }
277 errno = 0;
278 ret = ioctl(gsc_fd_, VIDIOC_QUERYCAP, &caps);
279 if (ret != 0) {
280 DPLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP";
281 decoder_state_ = kError;
282 NOTIFY_ERROR(PLATFORM_FAILURE);
283 return false;
284 } else if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
285 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP"
286 ", caps check failed: 0x" << std::hex << caps.capabilities;
287 decoder_state_ = kError;
288 NOTIFY_ERROR(PLATFORM_FAILURE);
289 return false;
290 }
291
292 // Some random ioctls that Exynos requires.
293 struct v4l2_control control;
294 memset(&control, 0, sizeof(control));
295 control.id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY; // also VP8
296 control.value = 8; // Magic number from Samsung folks.
297 errno = 0;
298 ret = ioctl(mfc_fd_, VIDIOC_S_CTRL, &control);
299 if (ret != 0) {
300 DPLOG(ERROR) << "Initialize(): ioctl() failed: "
301 "V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY";
302 decoder_state_ = kError;
303 NOTIFY_ERROR(PLATFORM_FAILURE);
304 return false;
305 }
306
307 if (!make_context_current_.Run()) {
308 DLOG(ERROR) << "Initialize(): could not make context current";
309 decoder_state_ = kError;
310 NOTIFY_ERROR(PLATFORM_FAILURE);
311 return false;
312 }
313
314 if (!CreateMfcInputBuffers()) {
315 decoder_state_ = kError;
316 NOTIFY_ERROR(PLATFORM_FAILURE);
317 return false;
318 }
319
320 // MFC output format has to be setup before streaming starts.
321 struct v4l2_format format;
322 memset(&format, 0, sizeof(format));
323 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
324 format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
325 ret = ioctl(mfc_fd_, VIDIOC_S_FMT, &format);
326 if (ret != 0) {
327 DPLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_S_FMT";
328 return false;
329 }
330
331 if (!decoder_thread_.Start()) {
332 DLOG(ERROR) << "Initialize(): decoder thread failed to start";
333 decoder_state_ = kError;
334 NOTIFY_ERROR(PLATFORM_FAILURE);
335 return false;
336 }
337
338 // Decoder thread is started, but no tasks can have been posted to it yet.
339 // Safe to touch decoder_state_.
340 decoder_state_ = kInitialized;
341
342 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
343 &Client::NotifyInitializeDone, client_));
344 return true;
345 }
346
347 void ExynosVideoDecodeAccelerator::Decode(
348 const media::BitstreamBuffer& bitstream_buffer) {
349 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id()
350 << ", size=" << bitstream_buffer.size();
351 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
352
353 scoped_ptr<BitstreamBufferRecord> bitstream_record(new BitstreamBufferRecord(
354 new base::SharedMemory(bitstream_buffer.handle(), true),
355 bitstream_buffer.size(), bitstream_buffer.id()));
356 if (!bitstream_record->shm->Map(bitstream_buffer.size())) {
357 DLOG(ERROR) << "Decode(): could not map bitstream_buffer";
358 NOTIFY_ERROR(UNREADABLE_INPUT);
359 return;
360 }
361 DVLOG(3) << "Decode(): mapped to addr=" << bitstream_record->shm->memory();
362
363 // DecodeTask() will take care of running a DecodeBufferTask().
364 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
365 &ExynosVideoDecodeAccelerator::DecodeTask, base::Unretained(this),
366 base::Passed(&bitstream_record)));
367 }
368
369 void ExynosVideoDecodeAccelerator::AssignPictureBuffers(
370 const std::vector<media::PictureBuffer>& buffers) {
371 DVLOG(3) << "AssignPictureBuffers(): buffer_count=" << buffers.size();
372 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
373
374 if (!make_context_current_.Run()) {
375 DLOG(ERROR) << "AssignPictureBuffers(): could not make context current";
376 NOTIFY_ERROR(PLATFORM_FAILURE);
377 return;
378 }
379
380 DCHECK_EQ(gsc_output_buffer_count_, static_cast<int>(buffers.size()));
381 scoped_ptr<EGLImageKHRArrayRef> egl_images_ref(
382 new EGLImageKHRArrayRef(
383 egl_display_, new EGLImageKHR[buffers.size()],
384 new int[buffers.size()], buffers.size()));
385 for (int i = 0; i < egl_images_ref->egl_images_count; i++) {
386 egl_images_ref->egl_images[i] = EGL_NO_IMAGE_KHR;
387 egl_images_ref->egl_image_fds[i] = -1;
388 }
389
390 const static EGLint kImageAttrs[] = {
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 The translator only has support for backing pixmap
391 EGL_IMAGE_PRESERVED_KHR, 0,
392 EGL_NONE,
393 };
394 Display* x_display = base::MessagePumpForUI::GetDefaultXDisplay();
395 glActiveTexture(GL_TEXTURE0);
396 for (int i = 0; i < egl_images_ref->egl_images_count; i++) {
397 EGLImageKHR egl_image;
398 int fd, ret;
399 // Create the X pixmap and then create an EGLImageKHR from it, so we can
400 // get dma_buf backing.
401 Pixmap pixmap = XCreatePixmap(x_display, RootWindow(x_display, 0),
402 buffers[i].size().width(), buffers[i].size().height(), 32);
403 if (!pixmap) {
404 DLOG(ERROR) << "AssignPictureBuffers(): could not create X pixmap";
405 NOTIFY_ERROR(PLATFORM_FAILURE);
406 return;
407 }
408 glBindTexture(GL_TEXTURE_2D, buffers[i].texture_id());
409 egl_image = eglCreateImageKHR(
410 egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
411 (EGLClientBuffer)pixmap, kImageAttrs);
412 // We can free the X pixmap immediately -- according to the
413 // EGL_KHR_image_base spec, the backing storage does not go away until the
414 // last referencing EGLImage is destroyed.
415 XFreePixmap(x_display, pixmap);
416 if (egl_image == EGL_NO_IMAGE_KHR) {
417 DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR";
418 NOTIFY_ERROR(PLATFORM_FAILURE);
419 return;
420 }
421 egl_images_ref->egl_images[i] = egl_image;
422 ret = mali_egl_image_get_buffer_ext_phandle(
423 egl_images_ref->egl_images[i], NULL, &fd);
424 if (!ret) {
425 DLOG(ERROR) << "AssignPictureBuffers(): "
426 << "could not get EGLImageKHR dmabuf fd";
427 NOTIFY_ERROR(PLATFORM_FAILURE);
428 return;
429 }
430 egl_images_ref->egl_image_fds[i] = fd;
431 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image);
432 }
433 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
434 &ExynosVideoDecodeAccelerator::AssignPictureBuffersTask,
435 base::Unretained(this), base::Passed(&egl_images_ref)));
436 }
437
438 void ExynosVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
439 DVLOG(3) << "ReusePictureBuffer(): picture_buffer_id=" << picture_buffer_id;
440 // Must be run on child thread, as we'll insert a sync in the EGL context.
441 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
442
443 if (!make_context_current_.Run()) {
444 DLOG(ERROR) << "ReusePictureBuffer(): could not make context current";
445 NOTIFY_ERROR(PLATFORM_FAILURE);
446 return;
447 }
448
449 EGLSyncKHR egl_sync;
450 egl_sync = egl_create_sync_khr(egl_display_, EGL_SYNC_FENCE_KHR, NULL);
451 if (egl_sync == EGL_NO_SYNC_KHR) {
452 DLOG(ERROR) << "ReusePictureBuffer(): eglCreateSyncKHR() failed";
453 NOTIFY_ERROR(PLATFORM_FAILURE);
454 return;
455 }
456
457 scoped_ptr<EGLSyncKHRRef> egl_sync_ref(new EGLSyncKHRRef(
458 egl_display_, egl_sync));
459 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
460 &ExynosVideoDecodeAccelerator::ReusePictureBufferTask,
461 base::Unretained(this), picture_buffer_id, base::Passed(&egl_sync_ref)));
462 }
463
464 void ExynosVideoDecodeAccelerator::Flush() {
465 DVLOG(3) << "Flush()";
466 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
467 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
468 &ExynosVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
469 }
470
471 void ExynosVideoDecodeAccelerator::Reset() {
472 DVLOG(3) << "Reset()";
473 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
474 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
475 &ExynosVideoDecodeAccelerator::ResetTask, base::Unretained(this)));
476 }
477
478 void ExynosVideoDecodeAccelerator::Destroy() {
479 DVLOG(3) << "Destroy()";
480 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
481
482 // We're destroying; cancel all callbacks.
483 client_ptr_factory_.InvalidateWeakPtrs();
484
485 // If the decoder thread is running, destroy using posted task.
486 if (decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
487 &ExynosVideoDecodeAccelerator::DestroyTask, base::Unretained(this)))) {
488 // DestroyTask() will cause the decoder_thread_ to flush all tasks.
489 decoder_thread_.Stop();
490 } else {
491 // Otherwise, call the destroy task directly.
492 DestroyTask();
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 My point is that all other FooTask methods are unc
493 }
494
495 // Nuke the entire site from orbit -- it's the only way to be sure.
496 if (gsc_fd_ != -1) {
497 DestroyGscInputBuffers();
498 DestroyGscOutputBuffers();
499 close(gsc_fd_);
500 gsc_fd_ = -1;
501 }
502 if (mfc_fd_ != -1) {
503 DestroyMfcInputBuffers();
504 DestroyMfcOutputBuffers();
505 close(mfc_fd_);
506 mfc_fd_ = -1;
507 }
508
509 // Decoder thread is stopped by now; safe to touch decoder_state_.
510 decoder_state_ = kError;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 where's the delete this; ?
sheu 2012/11/03 00:37:14 Done.
511 }
512
513 // static
514 void ExynosVideoDecodeAccelerator::PreSandboxInitialization() {
515 DVLOG(3) << "PreSandboxInitialization()";
516 errno = 0;
517 libmali_handle = dlopen(EXYNOS_MALI_DRIVER, RTLD_LAZY | RTLD_LOCAL);
518 if (libmali_handle == NULL) {
519 DPLOG(ERROR) << "failed to dlopen() " << EXYNOS_MALI_DRIVER;
520 }
521 }
522
523 // static
524 bool ExynosVideoDecodeAccelerator::PostSandboxInitialization() {
525 DVLOG(3) << "PostSandboxInitialization()";
526 if (libmali_handle == NULL) {
527 DLOG(ERROR) << "PostSandboxInitialization(): no " << EXYNOS_MALI_DRIVER
528 " driver handle";
529 return false;
530 }
531
532 errno = 0;
533 mali_egl_image_get_buffer_ext_phandle =
534 reinterpret_cast<EGLBoolean(*)(EGLImageKHR, EGLint*, void*)>(
535 dlsym(libmali_handle, "mali_egl_image_get_buffer_ext_phandle"));
536 if (mali_egl_image_get_buffer_ext_phandle == NULL) {
537 DPLOG(ERROR) << "PostSandboxInitialization(): failed to dlsym()"
538 " mali_egl_image_get_buffer_ext_phandle";
539 return false;
540 }
541
542 errno = 0;
543 egl_create_sync_khr =
544 reinterpret_cast<EGLSyncKHR(*)(EGLDisplay, EGLenum, const EGLint*)>(
545 dlsym(libmali_handle, "eglCreateSyncKHR"));
546 if (egl_create_sync_khr == NULL) {
547 DPLOG(ERROR) << "PostSandboxInitialization(): failed to dlsym()"
548 " eglCreateSyncKHR";
549 return false;
550 }
551
552 errno = 0;
553 egl_destroy_sync_khr =
554 reinterpret_cast<EGLBoolean(*)(EGLDisplay, EGLSyncKHR)>(
555 dlsym(libmali_handle, "eglDestroySyncKHR"));
556 if (egl_destroy_sync_khr == NULL) {
557 DPLOG(ERROR) << "PostSandboxInitialization(): failed to dlsym()"
558 " eglDestroySyncKHR";
559 return false;
560 }
561
562 errno = 0;
563 egl_client_wait_sync_khr =
564 reinterpret_cast<EGLint(*)(EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR)>(
565 dlsym(libmali_handle, "eglClientWaitSyncKHR"));
566 if (egl_client_wait_sync_khr == NULL) {
567 DPLOG(ERROR) << "PostSandboxInitialization(): failed to dlsym()"
568 " eglClientWaitSyncKHR";
569 return false;
570 }
571
572 return true;
573 }
574
575 void ExynosVideoDecodeAccelerator::DecodeTask(
576 scoped_ptr<BitstreamBufferRecord> bitstream_record) {
577 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_record->input_id;
578 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
579 DCHECK_NE(decoder_state_, kUninitialized);
580
581 if (decoder_state_ == kResetting) {
582 DVLOG(2) << "DecodeTask(): early out: kResetting state";
583 return;
584 } else if (decoder_state_ == kError) {
585 DVLOG(2) << "DecodeTask(): early out: kError state";
586 return;
587 }
588
589 decoder_input_queue_.push_front(
590 linked_ptr<BitstreamBufferRecord>(bitstream_record.release()));
591 decoder_decode_buffer_tasks_scheduled_++;
592 DecodeBufferTask();
593 }
594
595 void ExynosVideoDecodeAccelerator::DecodeBufferTask() {
596 DVLOG(3) << "DecodeBufferTask()";
597 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
598 DCHECK_NE(decoder_state_, kUninitialized);
599
600 decoder_decode_buffer_tasks_scheduled_--;
601
602 if (decoder_state_ == kResetting) {
603 DVLOG(2) << "DecodeBufferTask(): early out: kResetting state";
604 return;
605 } else if (decoder_state_ == kError) {
606 DVLOG(2) << "DecodeBufferTask(): early out: kError state";
607 return;
608 }
609
610 if (decoder_current_bitstream_buffer_ == NULL) {
611 if (decoder_input_queue_.empty()) {
612 // We're waiting for a new buffer -- exit without scheduling a new task.
613 return;
614 }
615 // Setup to use the next buffer.
616 decoder_current_bitstream_buffer_.reset(
617 decoder_input_queue_.back().release());
618 decoder_input_queue_.pop_back();
619 DVLOG(3) << "DecodeBufferTask(): reading input_id="
620 << decoder_current_bitstream_buffer_->input_id
621 << ", addr=" << decoder_current_bitstream_buffer_->shm->memory()
622 << ", size=" << decoder_current_bitstream_buffer_->size;
623 }
624 bool decode_result = false;
625 const void* data = decoder_current_bitstream_buffer_->shm->memory();
626 size_t size = decoder_current_bitstream_buffer_->size;
627 switch (decoder_state_) {
628 case kInitialized:
629 case kAfterReset:
630 decode_result = DecodeBufferInitial(data, size);
631 break;
632 case kDecoding:
633 decode_result = DecodeBufferContinue(data, size);
634 break;
635 default:
636 decoder_state_ = kError;
637 NOTIFY_ERROR(ILLEGAL_STATE);
638 return;
639 }
640 if (decoder_state_ == kError) {
641 // Failed during decode.
642 return;
643 } else if (!decode_result) {
644 // We might not have failed decode completely, but returned false due to
645 // insufficient resources, etc. Retry this this buffer later; exit without
646 // scheduling another task.
647 return;
648 }
649
650 // Our current bitstream buffer is done; return it.
651 int32 input_id = decoder_current_bitstream_buffer_->input_id;
652 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id;
653 decoder_current_bitstream_buffer_.reset(NULL);
654 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
655 &Client::NotifyEndOfBitstreamBuffer, client_, input_id));
656
657 // If we're behind on tasks, schedule another one.
658 if (decoder_decode_buffer_tasks_scheduled_ <
659 static_cast<int>(decoder_input_queue_.size())) {
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 I wonder whether you'd be happier by turning a bun
660 decoder_decode_buffer_tasks_scheduled_++;
661 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
662 &ExynosVideoDecodeAccelerator::DecodeBufferTask,
663 base::Unretained(this)));
664 }
665 }
666
667 bool ExynosVideoDecodeAccelerator::DecodeBufferInitial(
668 const void* data, size_t size) {
669 DVLOG(3) << "DecodeBufferInitial(): data=" << data << ", size=" << size;
670 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
671 DCHECK_NE(decoder_state_, kUninitialized);
672 DCHECK_NE(decoder_state_, kDecoding);
673 DCHECK(!device_poll_thread_.IsRunning());
674 // Initial decode. We haven't been able to get output stream format info yet.
675 // Get it, and start decoding.
676
677 // Copy in and send to HW.
678 if (!AppendToInputFrame(data, size) || !FlushInputFrame())
679 return false;
680
681 // Recycle buffers.
682 DequeueMfc();
683
684 // Check and see if we have format info yet.
685 int ret;
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 decl at first assignment at l.689 below.
sheu 2012/11/03 00:37:14 Done.
686 struct v4l2_format format;
687 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
688 errno = 0;
689 ret = ioctl(mfc_fd_, VIDIOC_G_FMT, &format);
690 if (ret != 0) {
691 if (errno == EINVAL) {
692 // We will get EINVAL if we haven't seen sufficient stream to decode the
693 // format. Return true and go to the next buffer.
694 return true;
695 } else {
696 DPLOG(ERROR) << "DecodeBufferInitial(): ioctl() failed: VIDIOC_G_FMT";
697 decoder_state_ = kError;
698 NOTIFY_ERROR(PLATFORM_FAILURE);
699 return false;
700 }
701 }
702
703 // Run this initialization only on first startup.
704 if (decoder_state_ == kInitialized) {
705 DVLOG(3) << "DecodeBufferInitial(): running one-time initialization";
706 // Success! Setup our parameters.
707 DCHECK_EQ(format.fmt.pix_mp.num_planes, 2);
708 // We don't handle midstream resizes right now.
709 if (!frame_buffer_size_.IsEmpty()) {
710 if (frame_buffer_size_.width() !=
711 static_cast<int>(format.fmt.pix_mp.width) ||
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 The Chromium Way is to strongly prefer more-readab
sheu 2012/11/03 00:37:14 Done.
712 frame_buffer_size_.height() !=
713 static_cast<int>(format.fmt.pix_mp.height)) {
714 // We don't handle mistream resizes right now.
715 NOTIMPLEMENTED();
716 decoder_state_ = kError;
717 NOTIFY_ERROR(UNREADABLE_INPUT);
718 return false;
719 }
720 }
721 frame_buffer_size_.SetSize(
722 format.fmt.pix_mp.width, format.fmt.pix_mp.height);
723 mfc_output_buffer_size_[0] = format.fmt.pix_mp.plane_fmt[0].sizeimage;
724 mfc_output_buffer_size_[1] = format.fmt.pix_mp.plane_fmt[1].sizeimage;
725 mfc_output_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat;
726
727 // Create our other buffers.
728 if (!CreateMfcOutputBuffers() || !CreateGscInputBuffers() ||
729 !CreateGscOutputBuffers()) {
730 decoder_state_ = kError;
731 NOTIFY_ERROR(PLATFORM_FAILURE);
732 return false;
733 }
734 }
735
736 // StartDevicePoll will raise the error if there is one.
737 if (!StartDevicePoll()) {
738 return false;
739 }
740
741 decoder_state_ = kDecoding;
742
743 // This buffer contained the header that kicks off decoding of the video
744 // stream. Return false here so it gets recycled into the next
745 // DecodeBufferContinue() and the start of actual output stream.
746 return false;
747 }
748
749 bool ExynosVideoDecodeAccelerator::DecodeBufferContinue(
750 const void* data, size_t size) {
751 DVLOG(3) << "DecodeBufferContinue(): data=" << data << ", size=" << size;
752 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
753 DCHECK_EQ(decoder_state_, kDecoding);
754
755 // We've already setup our output stream parameters, so just keep on truckin'.
756 return (AppendToInputFrame(data, size) && FlushInputFrame());
757 }
758
759 bool ExynosVideoDecodeAccelerator::AppendToInputFrame(
760 const void* data, size_t size) {
761 DVLOG(3) << "AppendToInputFrame()";
762 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
763 // We should have started streaming when we created MFC input buffers.
764 DCHECK(mfc_input_streamon_);
765 DCHECK(decoder_state_ == kInitialized || decoder_state_ == kDecoding);
766
767 // Flush if we're too big
768 if (decoder_current_input_buffer_ != -1) {
769 MfcInputRecord& input_record =
770 mfc_input_buffer_map_[decoder_current_input_buffer_];
771 if (input_record.bytes_used + size > input_record.length) {
772 if (!FlushInputFrame())
773 return false;
774 decoder_current_input_buffer_ = -1;
775 }
776 }
777
778 // Try to get an available input buffer
779 if (decoder_current_input_buffer_ == -1) {
780 if (mfc_free_input_buffers_.empty()) {
781 // See if we can get more free buffers from HW
782 DequeueMfc();
783 if (mfc_free_input_buffers_.empty()) {
784 // Nope!
785 DVLOG(2) << "AppendToInputFrame(): stalled for input buffers";
786 return false;
787 }
788 }
789 decoder_current_input_buffer_ = mfc_free_input_buffers_.back();
790 mfc_free_input_buffers_.pop_back();
791 MfcInputRecord& input_record =
792 mfc_input_buffer_map_[decoder_current_input_buffer_];
793 DCHECK_EQ(input_record.bytes_used, 0);
794 DCHECK_EQ(input_record.input_id, -1);
795 DCHECK(decoder_current_bitstream_buffer_ != NULL);
796 input_record.input_id = decoder_current_bitstream_buffer_->input_id;
797 }
798
799 // Copy in to the buffer.
800 MfcInputRecord& input_record =
801 mfc_input_buffer_map_[decoder_current_input_buffer_];
802 if (size > input_record.length - input_record.bytes_used) {
803 LOG(ERROR) << "AppendToInputFrame(): over-size frame, erroring";
804 NOTIFY_ERROR(UNREADABLE_INPUT);
805 return false;
806 }
807 memcpy((char*)input_record.offset + input_record.bytes_used, data, size);
808 input_record.bytes_used += size;
809
810 return true;
811 }
812
813 bool ExynosVideoDecodeAccelerator::FlushInputFrame() {
814 DVLOG(3) << "FlushInputFrame()";
815 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
816 DCHECK(decoder_state_ == kInitialized || decoder_state_ == kDecoding);
817 if (decoder_current_input_buffer_ == -1)
818 return true;
819
820 MfcInputRecord& input_record =
821 mfc_input_buffer_map_[decoder_current_input_buffer_];
822 if (input_record.bytes_used == 0)
823 return true;
824
825 // Queue it to MFC.
826 mfc_input_ready_queue_.push_back(decoder_current_input_buffer_);
827 decoder_frames_inflight_++;
828 decoder_current_input_buffer_ = -1;
829 DVLOG(3) << "FlushInputFrame(): submitting input_id="
830 << input_record.input_id;
831 // Kick the MFC once since there's new available input for it.
832 EnqueueMfc();
833
834 return (decoder_state_ != kError);
835 }
836
837 void ExynosVideoDecodeAccelerator::AssignPictureBuffersTask(
838 scoped_ptr<EGLImageKHRArrayRef> egl_images_ref) {
839 DVLOG(3) << "AssignPictureBuffersTask()";
840 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
841 DCHECK_NE(decoder_state_, kUninitialized);
842
843 // We run AssignPictureBuffersTask even if we're in kResetting.
844 if (decoder_state_ == kError) {
845 DVLOG(2) << "AssignPictureBuffersTask(): early out: kError state";
846 return;
847 }
848
849 DCHECK_EQ(egl_images_ref->egl_images_count,
850 static_cast<int>(gsc_output_buffer_map_.size()));
851 for (size_t i = 0; i < gsc_output_buffer_map_.size(); i++) {
852 // We should be blank right now.
853 GscOutputRecord& output_record = gsc_output_buffer_map_[i];
854 DCHECK_EQ(output_record.fd, -1);
855 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR);
856 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR);
857 DCHECK_EQ(output_record.picture_id, -1);
858 output_record.fd = egl_images_ref->egl_image_fds[i];
859 output_record.egl_image = egl_images_ref->egl_images[i];
860 output_record.picture_id = i;
861
862 // Take ownership of the EGLImage and fd.
863 egl_images_ref->egl_images[i] = EGL_NO_IMAGE_KHR;
864 egl_images_ref->egl_image_fds[i] = -1;
865 // And add this buffer to the free list.
866 gsc_free_output_buffers_.push_front(i);
867 }
868
869 // StartDevicePoll will raise the error if there is one.
870 StartDevicePoll();
871 }
872
873 void ExynosVideoDecodeAccelerator::ServiceDeviceTask() {
874 DVLOG(3) << "ServiceDeviceTask()";
875 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
876 DCHECK_NE(decoder_state_, kUninitialized);
877 DCHECK_NE(decoder_state_, kInitialized);
878 DCHECK_NE(decoder_state_, kAfterReset);
879
880 if (decoder_state_ == kResetting) {
881 DVLOG(2) << "ServiceDeviceTask(): early out: kResetting state";
882 return;
883 } else if (decoder_state_ == kError) {
884 DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
885 return;
886 }
887
888 DequeueMfc();
889 DequeueGsc();
890 EnqueueMfc();
891 EnqueueGsc();
892
893 DVLOG(1) << "ServiceDeviceTask(): buffer counts: DEC["
894 << decoder_input_queue_.size() << "->"
895 << mfc_input_ready_queue_.size() << "] => MFC["
896 << mfc_free_input_buffers_.size() << "/"
897 << mfc_input_buffer_count_ << "->"
898 << mfc_free_output_buffers_.size() << "/"
899 << mfc_output_buffer_count_ << "] => "
900 << mfc_output_gsc_input_queue_.size() << " => GSC["
901 << gsc_free_input_buffers_.size() << "/"
902 << gsc_input_buffer_count_ << "->"
903 << gsc_free_output_buffers_.size() << "/"
904 << gsc_output_buffer_count_ << "] => VDA["
905 << decoder_frames_at_client_ << "]";
906 }
907
908 void ExynosVideoDecodeAccelerator::EnqueueMfc() {
909 DVLOG(3) << "EnqueueMfc()";
910 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
911 DCHECK_NE(decoder_state_, kUninitialized);
912
913 // Drain the pipe of completed decode buffers.
914 int ret;
915 struct v4l2_buffer qbuf;
916 struct v4l2_plane qbuf_planes[2];
917 while (!mfc_input_ready_queue_.empty()) {
918 // Enqueue the MFC input (VIDEO_OUTPUT) buffer.
919 int buffer = mfc_input_ready_queue_.back();
920 MfcInputRecord& input_record = mfc_input_buffer_map_[buffer];
921 DCHECK(!input_record.at_device);
922 memset(&qbuf, 0, sizeof(qbuf));
923 memset(qbuf_planes, 0, sizeof(qbuf_planes));
924 qbuf.index = buffer;
925 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
926 qbuf.timestamp.tv_sec = input_record.input_id;
927 qbuf.memory = V4L2_MEMORY_MMAP;
928 qbuf.m.planes = qbuf_planes;
929 qbuf.m.planes[0].bytesused = input_record.bytes_used;
930 qbuf.length = 1;
931 errno = 0;
932 ret = ioctl(mfc_fd_, VIDIOC_QBUF, &qbuf);
933 if (ret != 0) {
934 DPLOG(ERROR) << "EnqueueMfc(): ioctl() failed: VIDIOC_QBUF";
935 decoder_state_ = kError;
936 NOTIFY_ERROR(PLATFORM_FAILURE);
937 return;
938 }
939 input_record.at_device = true;
940 mfc_input_ready_queue_.pop_back();
941 mfc_input_buffer_queued_count_++;
942 DVLOG(3) << "EnqueueMfc(): enqueued input_id=" << input_record.input_id;
943 if (!mfc_input_streamon_) {
944 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
945 errno = 0;
946 ret = ioctl(mfc_fd_, VIDIOC_STREAMON, &type);
947 if (ret != 0) {
948 DPLOG(ERROR) << "EnqueueMfc(): ioctl() failed: VIDIOC_STREAMON";
949 decoder_state_ = kError;
950 NOTIFY_ERROR(PLATFORM_FAILURE);
951 return;
952 }
953 mfc_input_streamon_ = true;
954 }
955 }
956
957 // Enqueue all the MFC output (VIDEO_CAPTURE) buffers we can.
958 while (!mfc_free_output_buffers_.empty()) {
959 int buffer = mfc_free_output_buffers_.back();
960 MfcOutputRecord& output_record = mfc_output_buffer_map_[buffer];
961 DCHECK(!output_record.at_device);
962 DCHECK_EQ(output_record.input_id, -1);
963 memset(&qbuf, 0, sizeof(qbuf));
964 memset(qbuf_planes, 0, sizeof(qbuf_planes));
965 qbuf.index = buffer;
966 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
967 qbuf.memory = V4L2_MEMORY_MMAP;
968 qbuf.m.planes = qbuf_planes;
969 qbuf.length = 2;
970 errno = 0;
971 ret = ioctl(mfc_fd_, VIDIOC_QBUF, &qbuf);
972 if (ret != 0) {
973 DPLOG(ERROR) << "EnqueueMfc(): ioctl() failed: VIDIOC_QBUF";
974 decoder_state_ = kError;
975 NOTIFY_ERROR(PLATFORM_FAILURE);
976 return;
977 }
978 output_record.at_device = true;
979 mfc_free_output_buffers_.pop_back();
980 if (!mfc_output_streamon_) {
981 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
982 errno = 0;
983 ret = ioctl(mfc_fd_, VIDIOC_STREAMON, &type);
984 if (ret != 0) {
985 DPLOG(ERROR) << "EnqueueMfc(): ioctl() failed: VIDIOC_STREAMON";
986 decoder_state_ = kError;
987 NOTIFY_ERROR(PLATFORM_FAILURE);
988 return;
989 }
990 mfc_output_streamon_ = true;
991 }
992 }
993 }
994
995 void ExynosVideoDecodeAccelerator::DequeueMfc() {
996 DVLOG(3) << "DequeueMfc()";
997 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
998 DCHECK_NE(decoder_state_, kUninitialized);
999 DCHECK_NE(decoder_state_, kInitialized);
1000
1001 // Dequeue completed MFC input (VIDEO_OUTPUT) buffers, and recycle to the free
1002 // list. Note that if we ever run completely dry of input buffers on the MFC
1003 // device, epoll() will return EPOLLERR and our DevicePollLoop() will exit
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 It seems kinda crazy to have this affordance here.
sheu 2012/11/03 00:37:14 If DevicePollLoop() wants to be aware of this, it'
Ami GONE FROM CHROMIUM 2012/11/06 19:50:10 An example of what I meant is: have a mutex dedica
sheu 2012/11/08 21:16:30 Right, that would let us know if our EINVAL was du
1004 // early. Work around this by never _completely_ draining the MFC input
1005 // queue. Note
sheu 2012/11/01 03:30:00 Not uploaded yet, but fixed
1006 struct v4l2_buffer dqbuf;
1007 struct v4l2_plane planes[2];
1008 DCHECK_EQ((decoder_current_input_buffer_ != -1 ? 1 : 0) +
1009 static_cast<int>(mfc_input_ready_queue_.size()) +
1010 static_cast<int>(mfc_free_input_buffers_.size()) +
1011 mfc_input_buffer_queued_count_, mfc_input_buffer_count_);
1012 while (mfc_input_buffer_queued_count_ > 1) {
1013 int ret;
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 decl at first use (I'm going to stop saying that n
sheu 2012/11/03 00:37:14 Done.
1014 memset(&dqbuf, 0, sizeof(dqbuf));
1015 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1016 dqbuf.memory = V4L2_MEMORY_MMAP;
1017 errno = 0;
1018 ret = ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf);
1019 if (ret != 0) {
1020 if (errno == EAGAIN) {
1021 // Done all that we could.
1022 break;
1023 } else if (errno == EINVAL) {
1024 // We're not streaming this queue; skip.
1025 DVLOG(2) << "DequeueMfc(): VIDEO_OUTPUT not streaming, skipping";
1026 break;
1027 } else {
1028 DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
1029 decoder_state_ = kError;
1030 NOTIFY_ERROR(PLATFORM_FAILURE);
1031 return;
1032 }
1033 }
1034 MfcInputRecord& input_record = mfc_input_buffer_map_[dqbuf.index];
1035 DCHECK(input_record.at_device);
1036 input_record.at_device = false;
1037 input_record.bytes_used = 0;
1038 input_record.input_id = -1;
1039 mfc_free_input_buffers_.push_back(dqbuf.index);
1040 mfc_input_buffer_queued_count_--;
1041 }
1042
1043 // Dequeue completed MFC output (VIDEO_CAPTURE) buffers, and queue to the
1044 // completed queue.
1045 memset(&dqbuf, 0, sizeof(dqbuf));
1046 memset(planes, 0, sizeof(planes));
1047 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1048 dqbuf.memory = V4L2_MEMORY_MMAP;
1049 dqbuf.m.planes = planes;
1050 dqbuf.length = 2;
1051 errno = 0;
1052 while (ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf) == 0) {
1053 MfcOutputRecord& output_record = mfc_output_buffer_map_[dqbuf.index];
1054 DCHECK(output_record.at_device);
1055 output_record.at_device = false;
1056 output_record.input_id = dqbuf.timestamp.tv_sec;
1057 output_record.bytes_used[0] = dqbuf.m.planes[0].bytesused;
1058 output_record.bytes_used[1] = dqbuf.m.planes[1].bytesused;
1059 DVLOG(3) << "DequeueMfc(): dequeued input_id=" << dqbuf.timestamp.tv_sec;
1060 mfc_output_gsc_input_queue_.push_front(dqbuf.index);
1061 memset(&dqbuf, 0, sizeof(dqbuf));
1062 memset(planes, 0, sizeof(planes));
1063 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1064 dqbuf.memory = V4L2_MEMORY_MMAP;
1065 dqbuf.m.planes = planes;
1066 dqbuf.length = 2;
1067 errno = 0;
1068 }
1069 if (errno == EINVAL) {
1070 // We're not streaming this queue; skip.
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 does this happen only during startup/shutdown, and
sheu 2012/11/03 00:37:14 Again, the OUTPUT and CAPTURE queues for each devi
1071 DVLOG(2) << "DequeueMfc(): VIDEO_CAPTURE not streaming, skipping";
1072 } else if (errno != EAGAIN) {
1073 DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
1074 decoder_state_ = kError;
1075 NOTIFY_ERROR(PLATFORM_FAILURE);
1076 return;
1077 }
1078 }
1079
1080 void ExynosVideoDecodeAccelerator::EnqueueGsc() {
1081 DVLOG(3) << "EnqueueGsc()";
1082 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
1083 DCHECK_NE(decoder_state_, kUninitialized);
1084 DCHECK_NE(decoder_state_, kInitialized);
1085 DCHECK_NE(decoder_state_, kAfterReset);
1086
1087 // Drain the pipe of completed MFC output buffers.
1088 int ret;
1089 struct v4l2_buffer qbuf;
1090 struct v4l2_plane qbuf_planes[2];
1091 DCHECK(gsc_output_streamon_);
1092 while (!mfc_output_gsc_input_queue_.empty()) {
1093 if (gsc_free_input_buffers_.empty())
1094 break;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 return (it's a long way down to the closing braces
sheu 2012/11/03 00:37:14 It is a long way down, but this isn't like error-o
Ami GONE FROM CHROMIUM 2012/11/06 19:50:10 The flip side is code added at the bottom of this
1095 // Bug workaround: GSC is liable to race conditions if more than one
1096 // buffer is simultaneously queued.
1097 if (gsc_output_buffer_queued_count_ > 0)
1098 break;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 ditto return
1099 if (gsc_output_buffer_prepared_count_ == 0) {
1100 // Enqueue a GSC output (VIDEO_CAPTURE) buffer for the incoming GSC input
1101 // buffer.
1102 if (gsc_free_output_buffers_.empty())
1103 break;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 ditto
1104 int buffer = gsc_free_output_buffers_.back();
1105 GscOutputRecord& output_record = gsc_output_buffer_map_[buffer];
1106 DCHECK(!output_record.at_device);
1107 DCHECK(!output_record.at_client);
1108 if (output_record.egl_sync != EGL_NO_SYNC_KHR) {
1109 // If we have to wait for completion, wait. Note that
1110 // gsc_free_output_buffers_ is a FIFO queue.
1111 egl_client_wait_sync_khr(egl_display_, output_record.egl_sync, 0,
1112 EGL_FOREVER_KHR);
1113 egl_destroy_sync_khr(egl_display_, output_record.egl_sync);
1114 output_record.egl_sync = EGL_NO_SYNC_KHR;
1115 }
1116 memset(&qbuf, 0, sizeof(qbuf));
1117 memset(qbuf_planes, 0, sizeof(qbuf_planes));
1118 qbuf.index = buffer;
1119 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1120 qbuf.memory = V4L2_MEMORY_DMABUF;
1121 qbuf.m.planes = qbuf_planes;
1122 qbuf.m.planes[0].m.fd = output_record.fd;
1123 qbuf.length = 1;
1124 errno = 0;
1125 ret = ioctl(gsc_fd_, VIDIOC_QBUF, &qbuf);
1126 if (ret != 0) {
1127 DPLOG(ERROR) << "EnqueueGsc(): ioctl() failed: VIDIOC_QBUF";
1128 decoder_state_ = kError;
1129 NOTIFY_ERROR(PLATFORM_FAILURE);
1130 return;
1131 }
1132 output_record.at_device = true;
1133 gsc_free_output_buffers_.pop_back();
1134 gsc_output_buffer_prepared_count_++;
1135 }
1136 // Now enqueue the GSC input (VIDEO_OUTPUT) buffer for the complete MFC
1137 // output buffer. We defer requeuing the MFC output buffer to its free
1138 // list, as the GSC input will be using its data.
1139 int mfc_buffer, gsc_buffer;
1140 mfc_buffer = mfc_output_gsc_input_queue_.back();
1141 gsc_buffer = gsc_free_input_buffers_.back();
1142 MfcOutputRecord& output_record = mfc_output_buffer_map_[mfc_buffer];
1143 DCHECK(!output_record.at_device);
1144 GscInputRecord& input_record = gsc_input_buffer_map_[gsc_buffer];
1145 DCHECK(!input_record.at_device);
1146 DCHECK_EQ(input_record.mfc_output, -1);
1147 memset(&qbuf, 0, sizeof(qbuf));
1148 memset(qbuf_planes, 0, sizeof(qbuf_planes));
1149 qbuf.index = gsc_buffer;
1150 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1151 qbuf.timestamp.tv_sec = output_record.input_id;
1152 qbuf.memory = V4L2_MEMORY_USERPTR;
1153 qbuf.m.planes = qbuf_planes;
1154 qbuf.m.planes[0].bytesused = output_record.bytes_used[0];
1155 qbuf.m.planes[0].length = mfc_output_buffer_size_[0];
1156 qbuf.m.planes[0].m.userptr = (unsigned long)output_record.offset[0];
1157 qbuf.m.planes[1].bytesused = output_record.bytes_used[1];
1158 qbuf.m.planes[1].length = mfc_output_buffer_size_[1];
1159 qbuf.m.planes[1].m.userptr = (unsigned long)output_record.offset[1];
1160 qbuf.length = 2;
1161 errno = 0;
1162 ret = ioctl(gsc_fd_, VIDIOC_QBUF, &qbuf);
1163 if (ret != 0) {
1164 DPLOG(ERROR) << "EnqueueGsc(): ioctl() failed: VIDIOC_QBUF";
1165 decoder_state_ = kError;
1166 NOTIFY_ERROR(PLATFORM_FAILURE);
1167 return;
1168 }
1169 input_record.at_device = true;
1170 input_record.mfc_output = mfc_buffer;
1171 output_record.bytes_used[0] = 0;
1172 output_record.bytes_used[1] = 0;
1173 mfc_output_gsc_input_queue_.pop_back();
1174 gsc_free_input_buffers_.pop_back();
1175 gsc_output_buffer_prepared_count_--;
1176 gsc_output_buffer_queued_count_++;
1177 DVLOG(3) << "EnqueueGsc(): enqueued input_id=" << output_record.input_id;
1178 if (!gsc_input_streamon_) {
1179 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1180 errno = 0;
1181 ret = ioctl(gsc_fd_, VIDIOC_STREAMON, &type);
1182 if (ret != 0) {
1183 DPLOG(ERROR) << "EnqueueGsc(): ioctl() failed: VIDIOC_STREAMON";
1184 decoder_state_ = kError;
1185 NOTIFY_ERROR(PLATFORM_FAILURE);
1186 return;
1187 }
1188 gsc_input_streamon_ = true;
1189 }
1190 }
1191 }
1192
1193 void ExynosVideoDecodeAccelerator::DequeueGsc() {
1194 DVLOG(3) << "DequeueGsc()";
1195 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
1196 DCHECK_NE(decoder_state_, kUninitialized);
1197 DCHECK_NE(decoder_state_, kInitialized);
1198 DCHECK_NE(decoder_state_, kAfterReset);
1199
1200 // Dequeue completed GSC input (VIDEO_OUTPUT) buffers, and recycle to the free
1201 // list. Also recycle the corresponding MFC output buffers at this time.
1202 // Note that if we ever run completely dry of input buffers on the GSC device,
1203 // epoll() will return EPOLLERR and our DevicePollLoop() will exit early.
1204 // Work around this by never _completely_ draining the GSC input queue.
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 ditto point about synchronization vs. holding an e
sheu 2012/11/03 00:37:14 See above
1205 struct v4l2_buffer dqbuf;
1206 while (gsc_input_buffer_count_ >
1207 static_cast<int>(gsc_free_input_buffers_.size()) + 1) {
1208 int ret;
1209 memset(&dqbuf, 0, sizeof(dqbuf));
1210 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1211 dqbuf.memory = V4L2_MEMORY_DMABUF;
1212 errno = 0;
1213 ret = ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf);
1214 if (ret != 0) {
1215 if (errno == EAGAIN) {
1216 // Done all that we could.
1217 break;
1218 } else if (errno == EINVAL) {
1219 // We're not streaming this queue; skip.
1220 DVLOG(2) << "DequeueGsc(): VIDEO_OUTPUT not streaming, skipping";
1221 break;
1222 } else {
1223 DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
1224 decoder_state_ = kError;
1225 NOTIFY_ERROR(PLATFORM_FAILURE);
1226 return;
1227 }
1228 }
1229 GscInputRecord& input_record = gsc_input_buffer_map_[dqbuf.index];
1230 DCHECK(input_record.at_device);
1231 input_record.at_device = false;
1232 mfc_output_buffer_map_[input_record.mfc_output].input_id = -1;
1233 mfc_free_output_buffers_.push_back(input_record.mfc_output);
1234 input_record.mfc_output = -1;
1235 gsc_free_input_buffers_.push_back(dqbuf.index);
1236 }
1237
1238 // Dequeue completed GSC output (VIDEO_CAPTURE) buffers, and send them off to
1239 // the VDA. Don't recycle to its free list yet -- we can't do that until
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 s/VDA/VDA::Client/
sheu 2012/11/03 00:37:14 Done.
1240 // ReusePictureBuffer() returns it to us.
1241 memset(&dqbuf, 0, sizeof(dqbuf));
1242 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1243 dqbuf.memory = V4L2_MEMORY_DMABUF;
1244 errno = 0;
1245 while (ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf) == 0) {
1246 GscOutputRecord& output_record = gsc_output_buffer_map_[dqbuf.index];
1247 DCHECK(output_record.at_device);
1248 DCHECK(!output_record.at_client);
1249 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR);
1250 output_record.at_device = false;
1251 output_record.at_client = true;
1252 gsc_output_buffer_queued_count_--;
1253 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
1254 &Client::PictureReady, client_, media::Picture(
1255 output_record.picture_id, dqbuf.timestamp.tv_sec)));
1256 decoder_frames_inflight_--;
1257 decoder_frames_at_client_++;
1258 DVLOG(1) << "DequeueGsc(): dequeued input_id=" << dqbuf.timestamp.tv_sec
1259 << " as picture_id=" << output_record.picture_id;
1260 if (decoder_frames_inflight_ == 0 && decoder_flush_notify_requested_) {
1261 // We were asked for a flush notification, so let's do it.
1262 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
1263 &Client::NotifyFlushDone, client_));
1264 }
1265 memset(&dqbuf, 0, sizeof(dqbuf));
1266 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1267 dqbuf.memory = V4L2_MEMORY_DMABUF;
1268 errno = 0;
1269 }
1270 if (errno == EINVAL) {
1271 // We're not streaming this queue; skip.
1272 DVLOG(2) << "DequeueGsc(): VIDEO_CAPTURE not streaming, skipping";
1273 } else if (errno != EAGAIN) {
1274 DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
1275 decoder_state_ = kError;
1276 NOTIFY_ERROR(PLATFORM_FAILURE);
1277 return;
1278 }
1279 }
1280
1281 void ExynosVideoDecodeAccelerator::ReusePictureBufferTask(
1282 int32 picture_buffer_id, scoped_ptr<EGLSyncKHRRef> egl_sync_ref) {
1283 DVLOG(3) << "ReusePictureBufferTask(): picture_buffer_id="
1284 << picture_buffer_id;
1285 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
1286
1287 // We run ReusePictureBufferTask even if we're in kResetting.
1288 if (decoder_state_ == kError) {
1289 DVLOG(2) << "ReusePictureBufferTask(): early out: kError state";
1290 return;
1291 }
1292
1293 size_t index;
1294 for (index = 0; index < gsc_output_buffer_map_.size(); index++)
1295 if (gsc_output_buffer_map_[index].picture_id == picture_buffer_id)
1296 break;
1297
1298 if (index >= gsc_output_buffer_map_.size()) {
1299 DLOG(ERROR) << "ReusePictureBufferTask(): picture_buffer_id not found";
1300 decoder_state_ = kError;
1301 NOTIFY_ERROR(INVALID_ARGUMENT);
1302 return;
1303 }
1304
1305 GscOutputRecord& output_record = gsc_output_buffer_map_[index];
1306 DCHECK(!output_record.at_device);
1307 DCHECK(output_record.at_client);
1308 output_record.at_client = false;
1309 output_record.egl_sync = egl_sync_ref->egl_sync;
1310 gsc_free_output_buffers_.push_front(index);
1311 decoder_frames_at_client_--;
1312 // Take ownership of the EGLSync.
1313 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR;
1314 // We got a buffer back, so kick the GSC.
1315 EnqueueGsc();
1316 }
1317
1318 void ExynosVideoDecodeAccelerator::FlushTask() {
1319 DVLOG(3) << "FlushTask()";
1320 // Flush the currently-building frame.
1321 FlushInputFrame();
1322
1323 if (decoder_frames_inflight_ == 0) {
1324 // If we don't have anything actually queued, we can notify immediatey.
1325 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
1326 &Client::NotifyFlushDone, client_));
1327 } else {
1328 // We'll flag that we want a flush-finished notification, and just return.
1329 decoder_flush_notify_requested_ = true;
1330 }
1331 }
1332
1333 void ExynosVideoDecodeAccelerator::ResetTask() {
1334 DVLOG(3) << "ResetTask()";
1335 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
1336 // We stop streaming, but we _don't_ destroy our buffers.
1337 if (!StopDevicePoll())
1338 return;
1339
1340 if (decoder_current_bitstream_buffer_ != NULL) {
1341 int input_id;
1342 input_id = decoder_current_bitstream_buffer_->input_id;
1343 decoder_current_bitstream_buffer_.reset(NULL);
1344 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
1345 &Client::NotifyEndOfBitstreamBuffer, client_, input_id));
1346 }
1347 while (!decoder_input_queue_.empty()) {
1348 int input_id;
1349 scoped_ptr<BitstreamBufferRecord>
1350 bitstream_record(decoder_input_queue_.back().release());
1351 decoder_input_queue_.pop_back();
1352 input_id = bitstream_record->input_id;
1353 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
1354 &Client::NotifyEndOfBitstreamBuffer, client_, input_id));
1355 }
1356
1357 decoder_current_input_buffer_ = -1;
1358 decoder_decode_buffer_tasks_scheduled_ = 0;
1359 decoder_frames_inflight_ = 0;
1360 decoder_flush_notify_requested_ = false;
1361
1362 // Mark that we're resetting, then enqueue a ResetDoneTask(). All intervening
1363 // jobs will early-out in the kResetting state.
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 Do you want to make a pass and verify this? Many
sheu 2012/11/03 00:37:14 Done. FlushTask() was missing the early-return; e
1364 decoder_state_ = kResetting;
1365 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
1366 &ExynosVideoDecodeAccelerator::ResetDoneTask, base::Unretained(this)));
1367 }
1368
1369 void ExynosVideoDecodeAccelerator::ResetDoneTask() {
1370 DVLOG(3) << "ResetDoneTask()";
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 DCHECK decoder_thread
sheu 2012/11/03 00:37:14 Done.
1371 // Jobs drained, we're finished resetting.
1372 decoder_state_ = kAfterReset;
1373 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
1374 &Client::NotifyResetDone, client_));
1375 }
1376
1377 void ExynosVideoDecodeAccelerator::DestroyTask() {
1378 DVLOG(3) << "DestroyTask()";
1379 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
1380
1381 // Stop streaming and the device_poll_thread_.
1382 StopDevicePoll();
1383
1384 decoder_current_bitstream_buffer_.reset(NULL);
1385 decoder_current_input_buffer_ = -1;
1386 decoder_decode_buffer_tasks_scheduled_ = 0;
1387 decoder_frames_inflight_ = 0;
1388 decoder_frames_at_client_ = 0;
1389 decoder_flush_notify_requested_ = false;
1390 decoder_input_queue_.clear();
1391
1392 // Set our state to kError. This will cause all subsequent tasks to
1393 // early-exit.
1394 decoder_state_ = kError;
1395 }
1396
1397 bool ExynosVideoDecodeAccelerator::StartDevicePoll() {
1398 DVLOG(3) << "StartDevicePoll()";
1399 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
1400
1401 // Early-out if we're already running.
1402 if (device_poll_thread_.IsRunning()) {
1403 DVLOG(2) << "StartDevicePoll(): early out: "
1404 << "device poll thread already running";
1405 return true;
1406 }
1407
1408 // At least one of the OUTPUT or CAPTURE queues for each of MFC and GSC must
1409 // be in STREAMON state for epoll() not to return EPOLERR. So:
1410 // * for MFC, we'll start the CAPTURE queue
1411 // * for GSC, we'll start the CAPTURE queue
1412 // STREAMON requires, unfortunately, that we have buffers already queued.
1413 // We'll need to have the buffers available to queue.
1414 if ((!mfc_output_streamon_ && mfc_free_output_buffers_.empty()) ||
1415 gsc_free_output_buffers_.empty()) {
1416 DVLOG(2) << "StartDevicePoll(): early out: output buffers unavailable";
1417 return true;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 why true?
sheu 2012/11/03 00:37:14 Added comment. Basically, if we don't have output
1418 }
1419
1420 // The MFC output queue may already have been started when we started
1421 // enqueuing MFC input buffers.
1422 int ret;
1423 struct v4l2_buffer qbuf;
1424 struct v4l2_plane qbuf_planes[2];
1425 if (!mfc_output_streamon_) {
1426 // Queue and start the MFC CAPTURE queue
1427 int buffer;
1428 __u32 type;
1429 memset(&qbuf, 0, sizeof(qbuf));
1430 memset(qbuf_planes, 0, sizeof(qbuf_planes));
1431 buffer = mfc_free_output_buffers_.back();
1432 MfcOutputRecord& output_record = mfc_output_buffer_map_[buffer];
1433 DCHECK(!output_record.at_device);
1434 DCHECK_EQ(output_record.input_id, -1);
1435 qbuf.index = buffer;
1436 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1437 qbuf.memory = V4L2_MEMORY_MMAP;
1438 qbuf.m.planes = qbuf_planes;
1439 qbuf.length = 2;
1440 errno = 0;
1441 ret = ioctl(mfc_fd_, VIDIOC_QBUF, &qbuf);
1442 if (ret != 0) {
1443 DPLOG(ERROR) << "StartDevicePoll(): ioctl() failed: VIDIOC_QBUF";
1444 decoder_state_ = kError;
1445 NOTIFY_ERROR(PLATFORM_FAILURE);
1446 return false;
1447 }
1448 output_record.at_device = true;
1449 mfc_free_output_buffers_.pop_back();
1450 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1451 errno = 0;
1452 ret = ioctl(mfc_fd_, VIDIOC_STREAMON, &type);
1453 if (ret != 0) {
1454 DPLOG(ERROR) << "StartDevicePoll(): ioctl() failed: VIDIOC_STREAMON";
1455 decoder_state_ = kError;
1456 NOTIFY_ERROR(PLATFORM_FAILURE);
1457 return false;
1458 }
1459 mfc_output_streamon_ = true;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 can most/all of the last 30 lines be deduped again
sheu 2012/11/03 00:37:14 It could be, but I'd then be breaking the QBUF for
1460 }
1461
1462 // GSC output should not have been started before we received output buffers.
1463 DCHECK(!gsc_output_streamon_);
1464 {
1465 // Queue and start the GSC CAPTURE queue
1466 int buffer;
1467 __u32 type;
1468 memset(&qbuf, 0, sizeof(qbuf));
1469 memset(qbuf_planes, 0, sizeof(qbuf_planes));
1470 buffer = gsc_free_output_buffers_.back();
1471 GscOutputRecord& output_record = gsc_output_buffer_map_[buffer];
1472 DCHECK(!output_record.at_device);
1473 DCHECK(!output_record.at_client);
1474 qbuf.index = buffer;
1475 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1476 qbuf.memory = V4L2_MEMORY_DMABUF;
1477 qbuf.m.planes = qbuf_planes;
1478 qbuf.m.planes[0].m.fd = gsc_output_buffer_map_[buffer].fd;
1479 qbuf.length = 1;
1480 errno = 0;
1481 ret = ioctl(gsc_fd_, VIDIOC_QBUF, &qbuf);
1482 if (ret != 0) {
1483 DPLOG(ERROR) << "StartDevicePoll(): ioctl() failed: VIDIOC_QBUF";
1484 decoder_state_ = kError;
1485 NOTIFY_ERROR(PLATFORM_FAILURE);
1486 return false;
1487 }
1488 output_record.at_device = true;
1489 gsc_free_output_buffers_.pop_back();
1490 gsc_output_buffer_prepared_count_++;
1491 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1492 errno = 0;
1493 ret = ioctl(gsc_fd_, VIDIOC_STREAMON, &type);
1494 if (ret != 0) {
1495 DPLOG(ERROR) << "StartDevicePoll(): ioctl() failed: VIDIOC_STREAMON";
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 ditto dedup this ~30 lines
sheu 2012/11/03 00:37:14 See above
1496 decoder_state_ = kError;
1497 NOTIFY_ERROR(PLATFORM_FAILURE);
1498 return false;
1499 }
1500 gsc_output_streamon_ = true;
1501
1502 if (!device_poll_thread_.Start()) {
1503 DLOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
1504 decoder_state_ = kError;
1505 NOTIFY_ERROR(PLATFORM_FAILURE);
1506 return false;
1507 }
1508 device_poll_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
1509 &ExynosVideoDecodeAccelerator::DevicePollLoop, base::Unretained(this)));
1510 }
1511
1512 return true;
1513 }
1514
1515 bool ExynosVideoDecodeAccelerator::StopDevicePoll() {
1516 DVLOG(3) << "StopDevicePoll()";
1517 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current());
1518
1519 // Stop streaming.
1520 int ret;
1521 if (mfc_input_streamon_) {
1522 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1523 errno = 0;
1524 ret = ioctl(mfc_fd_, VIDIOC_STREAMOFF, &type);
1525 if (ret != 0) {
1526 DPLOG(ERROR) << "StopDevicePoll(): ioctl() failed: VIDIOC_STREAMOFF";
1527 decoder_state_ = kError;
1528 NOTIFY_ERROR(PLATFORM_FAILURE);
1529 return false;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 This ioctl'ing business look really ripe for a hel
sheu 2012/11/03 00:37:14 Don't know that I can actually make this very much
1530 }
1531 }
1532 mfc_input_streamon_ = false;
1533 if (mfc_output_streamon_) {
1534 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1535 errno = 0;
1536 ret = ioctl(mfc_fd_, VIDIOC_STREAMOFF, &type);
1537 if (ret != 0) {
1538 DPLOG(ERROR) << "StopDevicePoll(): ioctl() failed: VIDIOC_STREAMOFF";
1539 decoder_state_ = kError;
1540 NOTIFY_ERROR(PLATFORM_FAILURE);
1541 return false;
1542 }
1543 }
1544 mfc_output_streamon_ = false;
1545 if (gsc_input_streamon_) {
1546 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1547 errno = 0;
1548 ret = ioctl(gsc_fd_, VIDIOC_STREAMOFF, &type);
1549 if (ret != 0) {
1550 DPLOG(ERROR) << "StopDevicePoll(): ioctl() failed: VIDIOC_STREAMOFF";
1551 decoder_state_ = kError;
1552 NOTIFY_ERROR(PLATFORM_FAILURE);
1553 return false;
1554 }
1555 }
1556 gsc_input_streamon_ = false;
1557 if (gsc_output_streamon_) {
1558 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1559 errno = 0;
1560 ret = ioctl(gsc_fd_, VIDIOC_STREAMOFF, &type);
1561 if (ret != 0) {
1562 DPLOG(ERROR) << "StopDevicePoll(): ioctl() failed: VIDIOC_STREAMOFF";
1563 decoder_state_ = kError;
1564 NOTIFY_ERROR(PLATFORM_FAILURE);
1565 return false;
1566 }
1567 }
1568 gsc_output_streamon_ = false;
1569
1570 // Stopping streaming should cause DevicePollLoop() to exit. Join the thread.
1571 device_poll_thread_.Stop();
1572
1573 // Reset all our accounting info.
1574 mfc_input_ready_queue_.clear();
1575 mfc_free_input_buffers_.clear();
1576 DCHECK_EQ(mfc_input_buffer_count_,
1577 static_cast<int>(mfc_input_buffer_map_.size()));
1578 for (size_t i = 0; i < mfc_input_buffer_map_.size(); i++) {
1579 mfc_free_input_buffers_.push_back(i);
1580 mfc_input_buffer_map_[i].at_device = false;
1581 mfc_input_buffer_map_[i].bytes_used = 0;
1582 mfc_input_buffer_map_[i].input_id = -1;
1583 }
1584 mfc_input_buffer_queued_count_ = 0;
1585 mfc_free_output_buffers_.clear();
1586 DCHECK_EQ(mfc_output_buffer_count_,
1587 static_cast<int>(mfc_output_buffer_map_.size()));
1588 for (size_t i = 0; i < mfc_output_buffer_map_.size(); i++) {
1589 mfc_free_output_buffers_.push_back(i);
1590 mfc_output_buffer_map_[i].at_device = false;
1591 mfc_output_buffer_map_[i].input_id = -1;
1592 }
1593 mfc_output_gsc_input_queue_.clear();
1594 gsc_free_input_buffers_.clear();
1595 DCHECK_EQ(gsc_input_buffer_count_,
1596 static_cast<int>(gsc_input_buffer_map_.size()));
1597 for (size_t i = 0; i < gsc_input_buffer_map_.size(); i++) {
1598 gsc_free_input_buffers_.push_back(i);
1599 gsc_input_buffer_map_[i].at_device = false;
1600 gsc_input_buffer_map_[i].mfc_output = -1;
1601 }
1602 gsc_free_output_buffers_.clear();
1603 DCHECK_EQ(gsc_output_buffer_count_,
1604 static_cast<int>(gsc_output_buffer_map_.size()));
1605 for (size_t i = 0; i < gsc_output_buffer_map_.size(); i++) {
1606 // Only mark those free that aren't being held by the VDA.
1607 if (!gsc_output_buffer_map_[i].at_client) {
1608 gsc_free_output_buffers_.push_back(i);
1609 gsc_output_buffer_map_[i].at_device = false;
1610 }
1611 if (gsc_output_buffer_map_[i].egl_sync != EGL_NO_SYNC_KHR) {
1612 egl_destroy_sync_khr(egl_display_, gsc_output_buffer_map_[i].egl_sync);
1613 gsc_output_buffer_map_[i].egl_sync = EGL_NO_SYNC_KHR;
1614 }
1615 }
1616 gsc_output_buffer_prepared_count_ = 0;
1617 gsc_output_buffer_queued_count_ = 0;
1618
1619 DVLOG(3) << "StopDevicePoll(): device poll stopped";
1620 return true;
1621 }
1622
1623 void ExynosVideoDecodeAccelerator::DevicePollLoop() {
1624 DVLOG(3) << "DevicePollLoop()";
1625 DCHECK_EQ(device_poll_thread_.message_loop(), MessageLoop::current());
1626 // This routine just polls on the V4L2 devices, and notifies the
1627 // decoder_thread_ when processing needs to occur. The main loop will
1628 // terminate when we return an EPOLLERR to epoll() on the device file
1629 // descriptors, which should occur when the devices are sent VIDIOC_STREAMOFF
1630 // on their queuespoll .
sheu 2012/11/01 03:30:00 Not uploaded yet, but fixed.
1631
1632 int ret;
1633 int epoll_fd = -1;
1634 file_util::ScopedFD epoll_fd_closer(&epoll_fd);
1635 struct epoll_event event;
1636 errno = 0;
1637 epoll_fd = epoll_create(2);
1638 if (epoll_fd == -1) {
1639 DPLOG(ERROR) << "DevicePollLoop(): epoll() failed";
1640 NOTIFY_ERROR(PLATFORM_FAILURE);
1641 return;
1642 }
1643 event.events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLET;
1644 event.data.fd = mfc_fd_;
1645 errno = 0;
1646 ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mfc_fd_, &event);
1647 if (ret != 0) {
1648 DPLOG(ERROR) << "DevicePollLoop(): epoll_ctl() failed";
1649 NOTIFY_ERROR(PLATFORM_FAILURE);
1650 return;
1651 }
1652 event.events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLET;
1653 event.data.fd = gsc_fd_;
1654 errno = 0;
1655 ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, gsc_fd_, &event);
1656 if (ret != 0) {
1657 DPLOG(ERROR) << "DevicePollLoop(): epoll_ctl() failed";
1658 NOTIFY_ERROR(PLATFORM_FAILURE);
1659 return;
1660 }
1661
1662 for (;;) {
1663 // We epoll() and wait for more interesting things to happen.
1664 // If we get a VIDIOC_STREAMOFF to the device, epoll() will return EPOLLERR,
1665 // and we know to exit the loop that way.
1666 DVLOG(3) << "DevicePollLoop(): epoll()";
1667 struct epoll_event event;
1668 do {
1669 errno = 0;
1670 ret = epoll_wait(epoll_fd, &event, 1, -1);
1671 } while (ret < 1 && errno == EINTR);
1672 if (ret == -1) {
1673 DPLOG(ERROR) << "DevicePollLoop(): epoll_wait() failed";
1674 NOTIFY_ERROR(PLATFORM_FAILURE);
1675 return;
1676 }
1677 if (event.data.fd == mfc_fd_) {
1678 if ((event.events & EPOLLERR) != 0) {
1679 DVLOG(2) << "DevicePollLoop(): epoll() returned EPOLERR for mfc_fd_";
1680 // Not necessarily an error.
1681 return;
1682 }
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 this if block can be extracted out of the fd check
sheu 2012/11/03 00:37:14 done (see below)
1683 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
1684 &ExynosVideoDecodeAccelerator::ServiceDeviceTask,
1685 base::Unretained(this)));
1686 // If we're behind on tasks, schedule another one.
1687 int buffers_pending = static_cast<int>(decoder_input_queue_.size());
1688 if (decoder_current_bitstream_buffer_ != NULL)
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 why is it safe to inspect this on this thread?
sheu 2012/11/03 00:37:14 Dang. A real live thread-unsafety. Fixed by movi
1689 buffers_pending++;
1690 if (decoder_decode_buffer_tasks_scheduled_ < buffers_pending) {
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 ditto thread safety here and below.
sheu 2012/11/03 00:37:14 (see above)
1691 decoder_decode_buffer_tasks_scheduled_++;
1692 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
1693 &ExynosVideoDecodeAccelerator::DecodeBufferTask,
1694 base::Unretained(this)));
1695 }
1696 } else if (event.data.fd == gsc_fd_) {
1697 if ((event.events & EPOLLERR) != 0) {
1698 DVLOG(2) << "DevicePollLoop(): epoll() returned EPOLERR for gsc_fd_";
1699 // Not necessarily an error.
1700 return;
1701 }
1702 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
1703 &ExynosVideoDecodeAccelerator::ServiceDeviceTask,
1704 base::Unretained(this)));
1705 } else {
1706 DLOG(ERROR) << "DevicePollLoop(): epoll() returned unknown fd";
1707 NOTIFY_ERROR(PLATFORM_FAILURE);
Ami GONE FROM CHROMIUM 2012/11/02 17:57:06 Your rationale for not including decoder_state_=k
sheu 2012/11/03 01:30:09 That's error-prone, I agree. I was just counting
1708 return;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 I think you can simplify & shorten this function s
sheu 2012/11/03 00:37:14 My thoughts exactly. Done.
1709 }
1710 }
1711 }
1712
1713 void ExynosVideoDecodeAccelerator::NotifyError(Error error) {
1714 DVLOG(2) << "NotifyError()";
1715 if (child_message_loop_proxy_ != base::MessageLoopProxy::current()) {
1716 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
1717 &ExynosVideoDecodeAccelerator::NotifyError, weak_this_, error));
1718 return;
1719 }
1720
1721 if (client_) {
1722 client_->NotifyError(error);
1723 client_ptr_factory_.InvalidateWeakPtrs();
1724 }
1725 }
1726
1727 bool ExynosVideoDecodeAccelerator::CreateMfcInputBuffers() {
1728 DVLOG(3) << "CreateMfcInputBuffers()";
1729 // We always run this as we prepare to initialize.
1730 DCHECK_EQ(decoder_state_, kUninitialized);
1731 DCHECK(!mfc_input_streamon_);
1732 DCHECK_EQ(mfc_input_buffer_count_, 0);
1733
1734 __u32 pixelformat = 0;
1735 if (video_profile_ >= media::H264PROFILE_MIN &&
1736 video_profile_ <= media::H264PROFILE_MAX) {
1737 pixelformat = V4L2_PIX_FMT_H264;
1738 } else if (video_profile_ >= media::VP8PROFILE_MIN &&
1739 video_profile_ <= media::VP8PROFILE_MAX) {
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 indent
sheu 2012/11/03 00:37:14 Done.
1740 pixelformat = V4L2_PIX_FMT_VP8;
1741 }
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 else NOTREACHED?
sheu 2012/11/03 00:37:14 Done.
1742
1743 int ret;
1744 struct v4l2_format format;
1745 memset(&format, 0, sizeof(format));
1746 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1747 format.fmt.pix_mp.pixelformat = pixelformat;
1748 format.fmt.pix_mp.plane_fmt[0].sizeimage = kMfcInputBufferMaxSize;
1749 format.fmt.pix_mp.num_planes = 1;
1750 errno = 0;
1751 ret = ioctl(mfc_fd_, VIDIOC_S_FMT, &format);
1752 if (ret != 0) {
1753 DPLOG(ERROR) << "CreateMfcInputBuffers(): ioctl() failed: VIDIOC_S_FMT";
1754 return false;
1755 }
1756
1757 struct v4l2_requestbuffers reqbufs;
1758 memset(&reqbufs, 0, sizeof(reqbufs));
1759 reqbufs.count = kMfcInputBufferCount;
1760 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1761 reqbufs.memory = V4L2_MEMORY_MMAP;
1762 errno = 0;
1763 ret = ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
1764 if (ret != 0) {
1765 DPLOG(ERROR) << "CreateMfcInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1766 return false;
1767 }
1768 mfc_input_buffer_count_ = reqbufs.count;
1769 mfc_input_buffer_map_.resize(mfc_input_buffer_count_);
1770 for (int i = 0; i < mfc_input_buffer_count_; i++) {
1771 mfc_free_input_buffers_.push_back(i);
1772
1773 // Query for the MEMORY_MMAP pointer.
1774 struct v4l2_plane planes[1];
1775 struct v4l2_buffer buffer;
1776 memset(&buffer, 0, sizeof(buffer));
1777 memset(planes, 0, sizeof(planes));
1778 buffer.index = i;
1779 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1780 buffer.memory = V4L2_MEMORY_MMAP;
1781 buffer.m.planes = planes;
1782 buffer.length = 1;
1783 errno = 0;
1784 ret = ioctl(mfc_fd_, VIDIOC_QUERYBUF, &buffer);
1785 if (ret != 0) {
1786 DPLOG(ERROR) << "CreateMfcInputBuffers(): "
1787 << "ioctl() failed: VIDIOC_QUERYBUF";
1788 return false;
1789 }
1790 errno = 0;
1791 void* offset = mmap(NULL, buffer.m.planes[0].length,
1792 PROT_READ | PROT_WRITE, MAP_SHARED, mfc_fd_,
1793 buffer.m.planes[0].m.mem_offset);
1794 if (offset == MAP_FAILED) {
1795 DPLOG(ERROR) << "CreateMfcInputBuffers(): mmap() failed";
1796 return false;
1797 }
1798 mfc_input_buffer_map_[i].offset = offset;
1799 mfc_input_buffer_map_[i].length = buffer.m.planes[0].length;
1800 }
1801
1802 return true;
1803 }
1804
1805 bool ExynosVideoDecodeAccelerator::CreateMfcOutputBuffers() {
1806 DVLOG(3) << "CreateMfcOutputBuffers()";
1807 DCHECK_EQ(decoder_state_, kInitialized);
1808 DCHECK(!mfc_output_streamon_);
1809 DCHECK_EQ(mfc_output_buffer_count_, 0);
1810
1811 // Number of MFC output buffers we need.
1812 int ret;
1813 struct v4l2_control ctrl;
1814 memset(&ctrl, 0, sizeof(ctrl));
1815 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
1816 errno = 0;
1817 ret = ioctl(mfc_fd_, VIDIOC_G_CTRL, &ctrl);
1818 if (ret != 0) {
1819 DPLOG(ERROR) << "CreateMfcOutputBuffers(): ioctl() failed: VIDIOC_G_CTRL";
1820 return false;
1821 }
1822
1823 // Output format setup in Initialize().
1824
1825 // Allocate the output buffers.
1826 struct v4l2_requestbuffers reqbufs;
1827 memset(&reqbufs, 0, sizeof(reqbufs));
1828 reqbufs.count = ctrl.value + kMfcOutputBufferExtraCount;
1829 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1830 reqbufs.memory = V4L2_MEMORY_MMAP;
1831 errno = 0;
1832 ret = ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
1833 if (ret != 0) {
1834 DPLOG(ERROR) << "CreateMfcOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1835 return false;
1836 }
1837
1838 // Fill our free-buffers list, and create DMABUFs from them.
1839 mfc_output_buffer_count_ = reqbufs.count;
1840 mfc_output_buffer_map_.resize(mfc_output_buffer_count_);
1841 for (int i = 0; i < mfc_output_buffer_count_; i++) {
1842 mfc_free_output_buffers_.push_back(i);
1843
1844 // Query for the MEMORY_MMAP pointer.
1845 struct v4l2_plane planes[2];
1846 struct v4l2_buffer buffer;
1847 memset(&buffer, 0, sizeof(buffer));
1848 memset(planes, 0, sizeof(planes));
1849 buffer.index = i;
1850 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1851 buffer.memory = V4L2_MEMORY_MMAP;
1852 buffer.m.planes = planes;
1853 buffer.length = 2;
1854 errno = 0;
1855 ret = ioctl(mfc_fd_, VIDIOC_QUERYBUF, &buffer);
1856 if (ret != 0) {
1857 DPLOG(ERROR) << "CreateMfcOutputBuffers(): "
1858 << "ioctl() failed: VIDIOC_QUERYBUF";
1859 return false;
1860 }
1861
1862 // Get their user memory for GSC input.
1863 for (int j = 0; j < 2; j++) {
1864 errno = 0;
1865 void* offset = mmap(NULL, buffer.m.planes[j].length,
1866 PROT_READ | PROT_WRITE, MAP_SHARED, mfc_fd_,
1867 buffer.m.planes[j].m.mem_offset);
1868 if (offset == MAP_FAILED) {
1869 DPLOG(ERROR) << "CreateMfcInputBuffers(): mmap() failed";
1870 return false;
1871 }
1872 mfc_output_buffer_map_[i].offset[j] = offset;
1873 mfc_output_buffer_map_[i].length[j] = buffer.m.planes[j].length;
1874 }
1875 }
1876
1877 return true;
1878 }
1879
1880 bool ExynosVideoDecodeAccelerator::CreateGscInputBuffers() {
1881 DVLOG(3) << "CreateGscInputBuffers()";
1882 DCHECK_EQ(decoder_state_, kInitialized);
1883 DCHECK(!gsc_input_streamon_);
1884 DCHECK_EQ(gsc_input_buffer_count_, 0);
1885
1886 int ret;
1887 struct v4l2_format format;
1888 memset(&format, 0, sizeof(format));
1889 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1890 format.fmt.pix_mp.width = frame_buffer_size_.width();
1891 format.fmt.pix_mp.height = frame_buffer_size_.height();
1892 DCHECK_EQ(mfc_output_buffer_pixelformat_, V4L2_PIX_FMT_NV12MT_16X16);
1893 format.fmt.pix_mp.pixelformat = mfc_output_buffer_pixelformat_;
1894 format.fmt.pix_mp.plane_fmt[0].sizeimage = mfc_output_buffer_size_[0];
1895 format.fmt.pix_mp.plane_fmt[1].sizeimage = mfc_output_buffer_size_[1];
1896 // NV12MT_16X16 is a tiled format for which bytesperline doesn't make too much
1897 // sense. Convention seems to be to assume 8bpp for these tiled formats.
1898 format.fmt.pix_mp.plane_fmt[0].bytesperline = frame_buffer_size_.width();
1899 format.fmt.pix_mp.plane_fmt[1].bytesperline = frame_buffer_size_.width();
1900 format.fmt.pix_mp.num_planes = 2;
1901 errno = 0;
1902 ret = ioctl(gsc_fd_, VIDIOC_S_FMT, &format);
1903 if (ret != 0) {
1904 DPLOG(ERROR) << "CreateGscInputBuffers(): ioctl() failed: VIDIOC_S_FMT";
1905 return false;
1906 }
1907
1908 struct v4l2_control control;
1909 memset(&control, 0, sizeof(control));
1910 control.id = V4L2_CID_ROTATE;
1911 control.value = 0;
1912 errno = 0;
1913 ret = ioctl(gsc_fd_, VIDIOC_S_CTRL, &control);
1914 if (ret != 0) {
1915 DPLOG(ERROR) << "CreateGscInputBuffers(): ioctl() failed: VIDIOC_S_CTRL";
1916 return false;
1917 }
1918
1919 memset(&control, 0, sizeof(control));
1920 control.id = V4L2_CID_HFLIP;
1921 control.value = 0;
1922 errno = 0;
1923 ret = ioctl(gsc_fd_, VIDIOC_S_CTRL, &control);
1924 if (ret != 0) {
1925 DPLOG(ERROR) << "CreateGscInputBuffers(): ioctl() failed: VIDIOC_S_CTRL";
1926 return false;
1927 }
1928
1929 memset(&control, 0, sizeof(control));
1930 control.id = V4L2_CID_VFLIP;
1931 control.value = 0;
1932 errno = 0;
1933 ret = ioctl(gsc_fd_, VIDIOC_S_CTRL, &control);
1934 if (ret != 0) {
1935 DPLOG(ERROR) << "CreateGscInputBuffers(): ioctl() failed: VIDIOC_S_CTRL";
1936 return false;
1937 }
1938
1939 memset(&control, 0, sizeof(control));
1940 control.id = V4L2_CID_GLOBAL_ALPHA;
1941 control.value = 255;
1942 errno = 0;
1943 ret = ioctl(gsc_fd_, VIDIOC_S_CTRL, &control);
1944 if (ret != 0) {
1945 DPLOG(ERROR) << "CreateGscInputBuffers(): ioctl() failed: VIDIOC_S_CTRL";
1946 return false;
1947 }
1948
1949 struct v4l2_requestbuffers reqbufs;
1950 memset(&reqbufs, 0, sizeof(reqbufs));
1951 reqbufs.count = kGscOutputBufferCount;
1952 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1953 reqbufs.memory = V4L2_MEMORY_USERPTR;
1954 errno = 0;
1955 ret = ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
1956 if (ret != 0 ) {
1957 DPLOG(ERROR) << "CreateGscInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1958 return false;
1959 }
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 man, I *really* hope you figure out a way to do io
sheu 2012/11/03 00:37:14 I don't really know that there is, unfortunately.
Ami GONE FROM CHROMIUM 2012/11/06 19:50:10 Even if you can't reduce the LOCs, making dedicate
1960
1961 gsc_input_buffer_count_ = reqbufs.count;
1962 gsc_input_buffer_map_.resize(gsc_input_buffer_count_);
1963 for (int i = 0; i < gsc_input_buffer_count_; i++) {
1964 gsc_free_input_buffers_.push_back(i);
1965 gsc_input_buffer_map_[i].mfc_output = -1;
1966 }
1967
1968 return true;
1969 }
1970
1971 bool ExynosVideoDecodeAccelerator::CreateGscOutputBuffers() {
1972 DVLOG(3) << "CreateGscOutputBuffers()";
1973 DCHECK_EQ(decoder_state_, kInitialized);
1974 DCHECK(!gsc_output_streamon_);
1975 DCHECK_EQ(gsc_output_buffer_count_, 0);
1976
1977 // GSC outputs into the EGLImages we create from the textures we are
1978 // assigned. Assume RGBA8888 format.
1979 int ret;
1980 struct v4l2_format format;
1981 memset(&format, 0, sizeof(format));
1982 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1983 format.fmt.pix_mp.width = frame_buffer_size_.width();
1984 format.fmt.pix_mp.height = frame_buffer_size_.height();
1985 format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_RGB32;
Ami GONE FROM CHROMIUM 2012/11/02 21:11:08 Is V_P_F_RGB32 == RGBA8888 ?
sheu 2012/11/03 00:37:14 Yep. There's also V4L2_PIX_FMT_BGR32 for the othe
1986 format.fmt.pix_mp.plane_fmt[0].sizeimage =
1987 frame_buffer_size_.width() * frame_buffer_size_.height() * 4;
1988 format.fmt.pix_mp.plane_fmt[0].bytesperline = frame_buffer_size_.width() * 4;
1989 format.fmt.pix_mp.num_planes = 1;
1990 errno = 0;
1991 ret = ioctl(gsc_fd_, VIDIOC_S_FMT, &format);
1992 if (ret != 0) {
1993 DPLOG(ERROR) << "CreateGscOutputBuffers(): ioctl() failed: VIDIOC_S_FMT";
1994 return false;
1995 }
1996
1997 struct v4l2_requestbuffers reqbufs;
1998 memset(&reqbufs, 0, sizeof(reqbufs));
1999 reqbufs.count = kGscOutputBufferCount;
2000 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
2001 reqbufs.memory = V4L2_MEMORY_DMABUF;
2002 errno = 0;
2003 ret = ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
2004 if (ret != 0) {
2005 DPLOG(ERROR) << "CreateGscOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
2006 return false;
2007 }
2008
2009 // We don't actually fill in the freelist or the map here. That happens once
2010 // we have actual usable buffers, after AssignPictureBuffers();
2011 gsc_output_buffer_count_ = reqbufs.count;
2012 gsc_output_buffer_map_.resize(gsc_output_buffer_count_);
2013
2014 DVLOG(3) << "CreateGscOutputBuffers(): ProvidePictureBuffers(): "
2015 << "buffer_count=" << gsc_output_buffer_count_
2016 << ", width=" << frame_buffer_size_.width()
2017 << ", height=" << frame_buffer_size_.height();
sheu 2012/11/01 03:30:00 Not uploaded yet, but fixed
2018 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
2019 &Client::ProvidePictureBuffers, client_, gsc_output_buffer_count_,
2020 gfx::Size(frame_buffer_size_.width(), frame_buffer_size_.height()),
2021 GL_TEXTURE_2D));
2022
2023 return true;
2024 }
2025
2026 void ExynosVideoDecodeAccelerator::DestroyMfcInputBuffers() {
2027 DVLOG(3) << "DestroyMfcInputBuffers()";
2028 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
2029 DCHECK(!mfc_input_streamon_);
2030
2031 for (size_t i = 0; i < mfc_input_buffer_map_.size(); i++) {
2032 if (mfc_input_buffer_map_[i].offset != NULL) {
2033 munmap(mfc_input_buffer_map_[i].offset,
2034 mfc_input_buffer_map_[i].length);
2035 }
2036 }
2037
2038 int ret;
2039 struct v4l2_requestbuffers reqbufs;
2040 memset(&reqbufs, 0, sizeof(reqbufs));
2041 reqbufs.count = 0;
2042 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
2043 reqbufs.memory = V4L2_MEMORY_MMAP;
2044 errno = 0;
2045 ret = ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
2046 if (ret != 0)
2047 DPLOG(ERROR) << "DestroyMfcInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
2048
2049 mfc_input_buffer_map_.clear();
2050 mfc_free_input_buffers_.clear();
2051 mfc_input_buffer_count_ = 0;
2052 }
2053
2054 void ExynosVideoDecodeAccelerator::DestroyMfcOutputBuffers() {
2055 DVLOG(3) << "DestroyMfcOutputBuffers()";
2056 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
2057 DCHECK(!mfc_output_streamon_);
2058
2059 for (size_t i = 0; i < mfc_output_buffer_map_.size(); i++) {
2060 if (mfc_output_buffer_map_[i].offset[0] != NULL)
2061 munmap(mfc_output_buffer_map_[i].offset[0],
2062 mfc_output_buffer_map_[i].length[0]);
2063 if (mfc_output_buffer_map_[i].offset[1] != NULL)
2064 munmap(mfc_output_buffer_map_[i].offset[1],
2065 mfc_output_buffer_map_[i].length[1]);
2066 }
2067
2068 int ret;
2069 struct v4l2_requestbuffers reqbufs;
2070 memset(&reqbufs, 0, sizeof(reqbufs));
2071 reqbufs.count = 0;
2072 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
2073 reqbufs.memory = V4L2_MEMORY_MMAP;
2074 errno = 0;
2075 ret = ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
2076 if (ret != 0)
2077 DPLOG(ERROR) << "DestroyMfcOutputBuffers() ioctl() failed: VIDIOC_REQBUFS";
2078
2079 mfc_output_buffer_map_.clear();
2080 mfc_free_output_buffers_.clear();
2081 mfc_output_buffer_count_ = 0;
2082 }
2083
2084 void ExynosVideoDecodeAccelerator::DestroyGscInputBuffers() {
2085 DVLOG(3) << "DestroyGscInputBuffers()";
2086 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
2087 DCHECK(!gsc_input_streamon_);
2088
2089 int ret;
2090 struct v4l2_requestbuffers reqbufs;
2091 memset(&reqbufs, 0, sizeof(reqbufs));
2092 reqbufs.count = 0;
2093 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
2094 reqbufs.memory = V4L2_MEMORY_DMABUF;
2095 errno = 0;
2096 ret = ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
2097 if (ret != 0)
2098 DPLOG(ERROR) << "DestroyGscInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
2099
2100 gsc_input_buffer_map_.clear();
2101 gsc_free_input_buffers_.clear();
2102 gsc_input_buffer_count_ = 0;
2103 }
2104
2105 void ExynosVideoDecodeAccelerator::DestroyGscOutputBuffers() {
2106 DVLOG(3) << "DestroyGscOutputBuffers()";
2107 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
2108 DCHECK(!gsc_output_streamon_);
2109
2110 if (gsc_output_buffer_map_.size() != 0) {
2111 if (!make_context_current_.Run())
2112 DLOG(ERROR) << "DestroyGscOutputBuffers(): "
2113 << "could not make context current";
2114
2115 size_t i = 0;
2116 do {
2117 GscOutputRecord& output_record = gsc_output_buffer_map_[i];
2118 if (output_record.fd != -1)
2119 close(output_record.fd);
2120 if (output_record.egl_image != EGL_NO_IMAGE_KHR)
2121 eglDestroyImageKHR(egl_display_, output_record.egl_image);
2122 if (output_record.egl_sync != EGL_NO_SYNC_KHR)
2123 egl_destroy_sync_khr(egl_display_, output_record.egl_sync);
2124 if (client_)
2125 client_->DismissPictureBuffer(output_record.picture_id);
2126 i++;
2127 } while (i < gsc_output_buffer_map_.size());
2128 }
2129
2130 int ret;
2131 struct v4l2_requestbuffers reqbufs;
2132 memset(&reqbufs, 0, sizeof(reqbufs));
2133 reqbufs.count = 0;
2134 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
2135 reqbufs.memory = V4L2_MEMORY_DMABUF;
2136 errno = 0;
2137 ret = ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
2138 if (ret != 0)
2139 DPLOG(ERROR) << "DestroyGscOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
2140
2141 gsc_output_buffer_map_.clear();
2142 gsc_free_output_buffers_.clear();
2143 gsc_output_buffer_count_ = 0;
2144 }
2145
2146 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698