OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 | 5 |
6 #include <fcntl.h> | 6 #include <fcntl.h> |
7 #include <libdrm/drm_fourcc.h> | 7 #include <libdrm/drm_fourcc.h> |
8 #include <linux/videodev2.h> | 8 #include <linux/videodev2.h> |
9 #include <poll.h> | 9 #include <poll.h> |
10 #include <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
11 #include <sys/ioctl.h> | 11 #include <sys/ioctl.h> |
12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
13 | 13 |
14 #include "base/debug/trace_event.h" | 14 #include "base/debug/trace_event.h" |
15 #include "base/files/scoped_file.h" | 15 #include "base/files/scoped_file.h" |
16 #include "base/posix/eintr_wrapper.h" | 16 #include "base/posix/eintr_wrapper.h" |
17 #include "content/common/gpu/media/exynos_v4l2_video_device.h" | 17 #include "content/common/gpu/media/generic_v4l2_video_device.h" |
18 #include "ui/gl/gl_bindings.h" | 18 #include "ui/gl/gl_bindings.h" |
19 | 19 |
20 namespace content { | 20 namespace content { |
21 | 21 |
22 namespace { | 22 namespace { |
23 const char kDecoderDevice[] = "/dev/mfc-dec"; | 23 const char kDecoderDevice[] = "/dev/video-dec"; |
24 const char kEncoderDevice[] = "/dev/mfc-enc"; | 24 const char kEncoderDevice[] = "/dev/video-enc"; |
25 const char kImageProcessorDevice[] = "/dev/gsc1"; | 25 const char kImageProcessorDevice[] = "/dev/gsc1"; |
26 } | 26 } |
27 | 27 |
28 ExynosV4L2Device::ExynosV4L2Device(Type type) | 28 GenericV4L2Device::GenericV4L2Device(Type type) |
29 : type_(type), | 29 : type_(type), |
30 device_fd_(-1), | 30 device_fd_(-1), |
31 device_poll_interrupt_fd_(-1) {} | 31 device_poll_interrupt_fd_(-1) {} |
32 | 32 |
33 ExynosV4L2Device::~ExynosV4L2Device() { | 33 GenericV4L2Device::~GenericV4L2Device() { |
34 if (device_poll_interrupt_fd_ != -1) { | 34 if (device_poll_interrupt_fd_ != -1) { |
35 close(device_poll_interrupt_fd_); | 35 close(device_poll_interrupt_fd_); |
36 device_poll_interrupt_fd_ = -1; | 36 device_poll_interrupt_fd_ = -1; |
37 } | 37 } |
38 if (device_fd_ != -1) { | 38 if (device_fd_ != -1) { |
39 close(device_fd_); | 39 close(device_fd_); |
40 device_fd_ = -1; | 40 device_fd_ = -1; |
41 } | 41 } |
42 } | 42 } |
43 | 43 |
44 int ExynosV4L2Device::Ioctl(int request, void* arg) { | 44 int GenericV4L2Device::Ioctl(int request, void* arg) { |
45 return HANDLE_EINTR(ioctl(device_fd_, request, arg)); | 45 return HANDLE_EINTR(ioctl(device_fd_, request, arg)); |
46 } | 46 } |
47 | 47 |
48 bool ExynosV4L2Device::Poll(bool poll_device, bool* event_pending) { | 48 bool GenericV4L2Device::Poll(bool poll_device, bool* event_pending) { |
49 struct pollfd pollfds[2]; | 49 struct pollfd pollfds[2]; |
50 nfds_t nfds; | 50 nfds_t nfds; |
51 int pollfd = -1; | 51 int pollfd = -1; |
52 | 52 |
53 pollfds[0].fd = device_poll_interrupt_fd_; | 53 pollfds[0].fd = device_poll_interrupt_fd_; |
54 pollfds[0].events = POLLIN | POLLERR; | 54 pollfds[0].events = POLLIN | POLLERR; |
55 nfds = 1; | 55 nfds = 1; |
56 | 56 |
57 if (poll_device) { | 57 if (poll_device) { |
58 DVLOG(3) << "Poll(): adding device fd to poll() set"; | 58 DVLOG(3) << "Poll(): adding device fd to poll() set"; |
59 pollfds[nfds].fd = device_fd_; | 59 pollfds[nfds].fd = device_fd_; |
60 pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI; | 60 pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI; |
61 pollfd = nfds; | 61 pollfd = nfds; |
62 nfds++; | 62 nfds++; |
63 } | 63 } |
64 | 64 |
65 if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) { | 65 if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) { |
66 DPLOG(ERROR) << "poll() failed"; | 66 DPLOG(ERROR) << "poll() failed"; |
67 return false; | 67 return false; |
68 } | 68 } |
69 *event_pending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI); | 69 *event_pending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI); |
70 return true; | 70 return true; |
71 } | 71 } |
72 | 72 |
73 void* ExynosV4L2Device::Mmap(void* addr, | 73 void* GenericV4L2Device::Mmap(void* addr, |
74 unsigned int len, | 74 unsigned int len, |
75 int prot, | 75 int prot, |
76 int flags, | 76 int flags, |
77 unsigned int offset) { | 77 unsigned int offset) { |
78 return mmap(addr, len, prot, flags, device_fd_, offset); | 78 return mmap(addr, len, prot, flags, device_fd_, offset); |
79 } | 79 } |
80 | 80 |
81 void ExynosV4L2Device::Munmap(void* addr, unsigned int len) { | 81 void GenericV4L2Device::Munmap(void* addr, unsigned int len) { |
82 munmap(addr, len); | 82 munmap(addr, len); |
83 } | 83 } |
84 | 84 |
85 bool ExynosV4L2Device::SetDevicePollInterrupt() { | 85 bool GenericV4L2Device::SetDevicePollInterrupt() { |
86 DVLOG(3) << "SetDevicePollInterrupt()"; | 86 DVLOG(3) << "SetDevicePollInterrupt()"; |
87 | 87 |
88 const uint64 buf = 1; | 88 const uint64 buf = 1; |
89 if (HANDLE_EINTR(write(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) { | 89 if (HANDLE_EINTR(write(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) { |
90 DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed"; | 90 DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed"; |
91 return false; | 91 return false; |
92 } | 92 } |
93 return true; | 93 return true; |
94 } | 94 } |
95 | 95 |
96 bool ExynosV4L2Device::ClearDevicePollInterrupt() { | 96 bool GenericV4L2Device::ClearDevicePollInterrupt() { |
97 DVLOG(3) << "ClearDevicePollInterrupt()"; | 97 DVLOG(3) << "ClearDevicePollInterrupt()"; |
98 | 98 |
99 uint64 buf; | 99 uint64 buf; |
100 if (HANDLE_EINTR(read(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) { | 100 if (HANDLE_EINTR(read(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) { |
101 if (errno == EAGAIN) { | 101 if (errno == EAGAIN) { |
102 // No interrupt flag set, and we're reading nonblocking. Not an error. | 102 // No interrupt flag set, and we're reading nonblocking. Not an error. |
103 return true; | 103 return true; |
104 } else { | 104 } else { |
105 DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed"; | 105 DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed"; |
106 return false; | 106 return false; |
107 } | 107 } |
108 } | 108 } |
109 return true; | 109 return true; |
110 } | 110 } |
111 | 111 |
112 bool ExynosV4L2Device::Initialize() { | 112 bool GenericV4L2Device::Initialize() { |
113 const char* device_path = NULL; | 113 const char* device_path = NULL; |
114 switch (type_) { | 114 switch (type_) { |
115 case kDecoder: | 115 case kDecoder: |
116 device_path = kDecoderDevice; | 116 device_path = kDecoderDevice; |
117 break; | 117 break; |
118 case kEncoder: | 118 case kEncoder: |
119 device_path = kEncoderDevice; | 119 device_path = kEncoderDevice; |
120 break; | 120 break; |
121 case kImageProcessor: | 121 case kImageProcessor: |
122 device_path = kImageProcessorDevice; | 122 device_path = kImageProcessorDevice; |
123 break; | 123 break; |
124 } | 124 } |
125 | 125 |
126 DVLOG(2) << "Initialize(): opening device: " << device_path; | 126 DVLOG(2) << "Initialize(): opening device: " << device_path; |
127 // Open the video device. | 127 // Open the video device. |
128 device_fd_ = HANDLE_EINTR(open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC)); | 128 device_fd_ = HANDLE_EINTR(open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC)); |
129 if (device_fd_ == -1) { | 129 if (device_fd_ == -1) { |
130 return false; | 130 return false; |
131 } | 131 } |
132 | 132 |
133 device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); | 133 device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); |
134 if (device_poll_interrupt_fd_ == -1) { | 134 if (device_poll_interrupt_fd_ == -1) { |
135 return false; | 135 return false; |
136 } | 136 } |
137 return true; | 137 return true; |
138 } | 138 } |
139 | 139 |
140 EGLImageKHR ExynosV4L2Device::CreateEGLImage(EGLDisplay egl_display, | 140 EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display, |
141 EGLContext /* egl_context */, | 141 EGLContext /* egl_context */, |
142 GLuint texture_id, | 142 GLuint texture_id, |
143 gfx::Size frame_buffer_size, | 143 gfx::Size frame_buffer_size, |
144 unsigned int buffer_index, | 144 unsigned int buffer_index, |
145 size_t planes_count) { | 145 size_t planes_count) { |
146 DVLOG(3) << "CreateEGLImage()"; | 146 DVLOG(3) << "CreateEGLImage()"; |
147 | 147 |
148 scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[planes_count]); | 148 scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[planes_count]); |
149 for (size_t i = 0; i < planes_count; ++i) { | 149 for (size_t i = 0; i < planes_count; ++i) { |
150 // Export the DMABUF fd so we can export it as a texture. | 150 // Export the DMABUF fd so we can export it as a texture. |
(...skipping 29 matching lines...) Expand all Loading... |
180 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); | 180 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); |
181 if (egl_image == EGL_NO_IMAGE_KHR) { | 181 if (egl_image == EGL_NO_IMAGE_KHR) { |
182 return egl_image; | 182 return egl_image; |
183 } | 183 } |
184 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id); | 184 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id); |
185 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); | 185 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); |
186 | 186 |
187 return egl_image; | 187 return egl_image; |
188 } | 188 } |
189 | 189 |
190 EGLBoolean ExynosV4L2Device::DestroyEGLImage(EGLDisplay egl_display, | 190 EGLBoolean GenericV4L2Device::DestroyEGLImage(EGLDisplay egl_display, |
191 EGLImageKHR egl_image) { | 191 EGLImageKHR egl_image) { |
192 return eglDestroyImageKHR(egl_display, egl_image); | 192 return eglDestroyImageKHR(egl_display, egl_image); |
193 } | 193 } |
194 | 194 |
195 GLenum ExynosV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; } | 195 GLenum GenericV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; } |
196 | 196 |
197 uint32 ExynosV4L2Device::PreferredInputFormat() { | 197 uint32 GenericV4L2Device::PreferredInputFormat() { |
198 // TODO(posciak): We should support "dontcare" returns here once we | 198 // TODO(posciak): We should support "dontcare" returns here once we |
199 // implement proper handling (fallback, negotiation) for this in users. | 199 // implement proper handling (fallback, negotiation) for this in users. |
200 CHECK_EQ(type_, kEncoder); | 200 CHECK_EQ(type_, kEncoder); |
201 return V4L2_PIX_FMT_NV12M; | 201 return V4L2_PIX_FMT_NV12M; |
202 } | 202 } |
203 | 203 |
204 uint32 ExynosV4L2Device::PreferredOutputFormat() { | 204 uint32 GenericV4L2Device::PreferredOutputFormat() { |
205 // TODO(posciak): We should support "dontcare" returns here once we | 205 // TODO(posciak): We should support "dontcare" returns here once we |
206 // implement proper handling (fallback, negotiation) for this in users. | 206 // implement proper handling (fallback, negotiation) for this in users. |
207 CHECK_EQ(type_, kDecoder); | 207 CHECK_EQ(type_, kDecoder); |
208 return V4L2_PIX_FMT_NV12M; | 208 return V4L2_PIX_FMT_NV12M; |
209 } | 209 } |
210 | 210 |
211 } // namespace content | 211 } // namespace content |
OLD | NEW |