OLD | NEW |
---|---|
(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 | |
OLD | NEW |