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 <errno.h> | 6 #include <errno.h> |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <libdrm/drm_fourcc.h> | 8 #include <libdrm/drm_fourcc.h> |
9 #include <linux/videodev2.h> | 9 #include <linux/videodev2.h> |
10 #include <poll.h> | 10 #include <poll.h> |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 } | 169 } |
170 #endif | 170 #endif |
171 | 171 |
172 device_poll_interrupt_fd_.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)); | 172 device_poll_interrupt_fd_.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)); |
173 if (!device_poll_interrupt_fd_.is_valid()) { | 173 if (!device_poll_interrupt_fd_.is_valid()) { |
174 return false; | 174 return false; |
175 } | 175 } |
176 return true; | 176 return true; |
177 } | 177 } |
178 | 178 |
179 std::vector<base::ScopedFD> GenericV4L2Device::GetDmabufsForV4L2Buffer( | |
180 int index, | |
181 size_t num_planes, | |
182 enum v4l2_buf_type type) { | |
183 DCHECK(V4L2_TYPE_IS_MULTIPLANAR(type)); | |
184 | |
185 std::vector<base::ScopedFD> dmabuf_fds; | |
186 for (size_t i = 0; i < num_planes; ++i) { | |
187 struct v4l2_exportbuffer expbuf; | |
188 memset(&expbuf, 0, sizeof(expbuf)); | |
189 expbuf.type = type; | |
190 expbuf.index = index; | |
191 expbuf.plane = i; | |
192 expbuf.flags = O_CLOEXEC; | |
193 if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) { | |
194 dmabuf_fds.clear(); | |
195 break; | |
196 } | |
197 | |
198 dmabuf_fds.push_back(base::ScopedFD(expbuf.fd)); | |
199 } | |
200 | |
201 return dmabuf_fds; | |
202 } | |
203 | |
179 bool GenericV4L2Device::CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) { | 204 bool GenericV4L2Device::CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) { |
180 static uint32_t kEGLImageDrmFmtsSupported[] = { | 205 static uint32_t kEGLImageDrmFmtsSupported[] = { |
181 DRM_FORMAT_ARGB8888, | 206 DRM_FORMAT_ARGB8888, |
182 #if defined(ARCH_CPU_ARMEL) | 207 #if defined(ARCH_CPU_ARMEL) |
183 DRM_FORMAT_NV12, | 208 DRM_FORMAT_NV12, |
184 DRM_FORMAT_MT21, | 209 DRM_FORMAT_MT21, |
185 #endif | 210 #endif |
186 }; | 211 }; |
187 | 212 |
188 return std::find( | 213 return std::find( |
189 kEGLImageDrmFmtsSupported, | 214 kEGLImageDrmFmtsSupported, |
190 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported), | 215 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported), |
191 V4L2PixFmtToDrmFormat(v4l2_pixfmt)) != | 216 V4L2PixFmtToDrmFormat(v4l2_pixfmt)) != |
192 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported); | 217 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported); |
193 } | 218 } |
194 | 219 |
195 EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display, | 220 EGLImageKHR GenericV4L2Device::CreateEGLImage( |
196 EGLContext /* egl_context */, | 221 EGLDisplay egl_display, |
197 GLuint texture_id, | 222 EGLContext /* egl_context */, |
198 gfx::Size frame_buffer_size, | 223 GLuint texture_id, |
199 unsigned int buffer_index, | 224 const gfx::Size& size, |
200 uint32_t v4l2_pixfmt, | 225 unsigned int buffer_index, |
201 size_t num_v4l2_planes) { | 226 uint32_t v4l2_pixfmt, |
227 const std::vector<base::ScopedFD>& dmabuf_fds) { | |
202 DVLOG(3) << "CreateEGLImage()"; | 228 DVLOG(3) << "CreateEGLImage()"; |
203 if (!CanCreateEGLImageFrom(v4l2_pixfmt)) { | 229 if (!CanCreateEGLImageFrom(v4l2_pixfmt)) { |
204 LOG(ERROR) << "Unsupported V4L2 pixel format"; | 230 LOG(ERROR) << "Unsupported V4L2 pixel format"; |
205 return EGL_NO_IMAGE_KHR; | 231 return EGL_NO_IMAGE_KHR; |
206 } | 232 } |
207 | 233 |
208 media::VideoPixelFormat vf_format = V4L2PixFmtToVideoPixelFormat(v4l2_pixfmt); | 234 media::VideoPixelFormat vf_format = V4L2PixFmtToVideoPixelFormat(v4l2_pixfmt); |
209 // Number of components, as opposed to the number of V4L2 planes, which is | 235 // Number of components, as opposed to the number of V4L2 planes, which is |
210 // just a buffer count. | 236 // just a buffer count. |
211 size_t num_planes = media::VideoFrame::NumPlanes(vf_format); | 237 size_t num_planes = media::VideoFrame::NumPlanes(vf_format); |
212 DCHECK_LE(num_planes, 3u); | 238 DCHECK_LE(num_planes, 3u); |
213 if (num_planes < num_v4l2_planes) { | 239 if (num_planes < dmabuf_fds.size()) { |
214 // It's possible for more than one DRM plane to reside in one V4L2 plane, | 240 // It's possible for more than one DRM plane to reside in one V4L2 plane, |
215 // but not the other way around. We must use all V4L2 planes. | 241 // but not the other way around. We must use all V4L2 planes. |
216 LOG(ERROR) << "Invalid plane count"; | 242 LOG(ERROR) << "Invalid plane count"; |
217 return EGL_NO_IMAGE_KHR; | 243 return EGL_NO_IMAGE_KHR; |
218 } | 244 } |
219 | 245 |
220 scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[num_v4l2_planes]); | |
221 // Export dmabuf fds so we can create an EGLImage from them. | |
222 for (size_t i = 0; i < num_v4l2_planes; ++i) { | |
223 struct v4l2_exportbuffer expbuf; | |
224 memset(&expbuf, 0, sizeof(expbuf)); | |
225 expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
226 expbuf.index = buffer_index; | |
227 expbuf.plane = i; | |
228 expbuf.flags = O_CLOEXEC; | |
229 if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) { | |
230 return EGL_NO_IMAGE_KHR; | |
231 } | |
232 dmabuf_fds[i].reset(expbuf.fd); | |
233 } | |
234 | |
235 std::vector<EGLint> attrs; | 246 std::vector<EGLint> attrs; |
236 attrs.push_back(EGL_WIDTH); | 247 attrs.push_back(EGL_WIDTH); |
237 attrs.push_back(frame_buffer_size.width()); | 248 attrs.push_back(size.width()); |
238 attrs.push_back(EGL_HEIGHT); | 249 attrs.push_back(EGL_HEIGHT); |
239 attrs.push_back(frame_buffer_size.height()); | 250 attrs.push_back(size.height()); |
240 attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT); | 251 attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT); |
241 attrs.push_back(V4L2PixFmtToDrmFormat(v4l2_pixfmt)); | 252 attrs.push_back(V4L2PixFmtToDrmFormat(v4l2_pixfmt)); |
242 | 253 |
243 // For existing formats, if we have less buffers (V4L2 planes) than | 254 // For existing formats, if we have less buffers (V4L2 planes) than |
244 // components (planes), the remaining planes are stored in the last | 255 // components (planes), the remaining planes are stored in the last |
245 // V4L2 plane. Use one V4L2 plane per each component until we run out of V4L2 | 256 // V4L2 plane. Use one V4L2 plane per each component until we run out of V4L2 |
246 // planes, and use the last V4L2 plane for all remaining components, each | 257 // planes, and use the last V4L2 plane for all remaining components, each |
247 // with an offset equal to the size of the preceding planes in the same | 258 // with an offset equal to the size of the preceding planes in the same |
248 // V4L2 plane. | 259 // V4L2 plane. |
249 size_t v4l2_plane = 0; | 260 size_t v4l2_plane = 0; |
250 size_t plane_offset = 0; | 261 size_t plane_offset = 0; |
251 for (size_t plane = 0; plane < num_planes; ++plane) { | 262 for (size_t plane = 0; plane < num_planes; ++plane) { |
252 attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + plane * 3); | 263 attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + plane * 3); |
253 attrs.push_back(dmabuf_fds[v4l2_plane].get()); | 264 attrs.push_back(dmabuf_fds[v4l2_plane].get()); |
254 attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + plane * 3); | 265 attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + plane * 3); |
255 attrs.push_back(plane_offset); | 266 attrs.push_back(plane_offset); |
256 attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + plane * 3); | 267 attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + plane * 3); |
257 attrs.push_back(media::VideoFrame::RowBytes(plane, vf_format, | 268 attrs.push_back( |
258 frame_buffer_size.width())); | 269 media::VideoFrame::RowBytes(plane, vf_format, size.width())); |
259 | 270 |
260 if (v4l2_plane + 1 < num_v4l2_planes) { | 271 if (v4l2_plane + 1 < dmabuf_fds.size()) { |
261 ++v4l2_plane; | 272 ++v4l2_plane; |
kcwu
2016/03/28 02:28:36
reset plane_offset to 0 here?
Pawel Osciak
2016/03/31 05:42:33
Good catch, thanks. Done.
| |
262 } else { | 273 } else { |
263 plane_offset += media::VideoFrame::PlaneSize( | 274 plane_offset += |
264 vf_format, plane, frame_buffer_size).GetArea(); | 275 media::VideoFrame::PlaneSize(vf_format, plane, size).GetArea(); |
265 } | 276 } |
266 } | 277 } |
267 | 278 |
268 attrs.push_back(EGL_NONE); | 279 attrs.push_back(EGL_NONE); |
269 | 280 |
270 EGLImageKHR egl_image = eglCreateImageKHR( | 281 EGLImageKHR egl_image = eglCreateImageKHR( |
271 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, &attrs[0]); | 282 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, &attrs[0]); |
272 if (egl_image == EGL_NO_IMAGE_KHR) { | 283 if (egl_image == EGL_NO_IMAGE_KHR) { |
273 LOG(ERROR) << "Failed creating EGL image: " << ui::GetLastEGLErrorString(); | 284 LOG(ERROR) << "Failed creating EGL image: " << ui::GetLastEGLErrorString(); |
274 return egl_image; | 285 return egl_image; |
(...skipping 24 matching lines...) Expand all Loading... | |
299 StubPathMap paths; | 310 StubPathMap paths; |
300 paths[kModuleV4l2].push_back(kV4l2Lib); | 311 paths[kModuleV4l2].push_back(kV4l2Lib); |
301 | 312 |
302 return InitializeStubs(paths); | 313 return InitializeStubs(paths); |
303 #else | 314 #else |
304 return true; | 315 return true; |
305 #endif | 316 #endif |
306 } | 317 } |
307 | 318 |
308 } // namespace content | 319 } // namespace content |
OLD | NEW |