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

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