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

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

Powered by Google App Engine
This is Rietveld 408576698