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

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

Powered by Google App Engine
This is Rietveld 408576698