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 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 #endif | 210 #endif |
211 }; | 211 }; |
212 | 212 |
213 return std::find( | 213 return std::find( |
214 kEGLImageDrmFmtsSupported, | 214 kEGLImageDrmFmtsSupported, |
215 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported), | 215 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported), |
216 V4L2PixFmtToDrmFormat(v4l2_pixfmt)) != | 216 V4L2PixFmtToDrmFormat(v4l2_pixfmt)) != |
217 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported); | 217 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported); |
218 } | 218 } |
219 | 219 |
220 EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display, | 220 EGLImageKHR GenericV4L2Device::CreateEGLImage( |
221 EGLContext /* egl_context */, | 221 EGLDisplay egl_display, |
222 GLuint texture_id, | 222 EGLContext /* egl_context */, |
223 gfx::Size frame_buffer_size, | 223 GLuint texture_id, |
224 unsigned int buffer_index, | 224 const gfx::Size& size, |
225 uint32_t v4l2_pixfmt, | 225 unsigned int buffer_index, |
226 size_t num_v4l2_planes) { | 226 uint32_t v4l2_pixfmt, |
| 227 const std::vector<base::ScopedFD>& dmabuf_fds) { |
227 DVLOG(3) << "CreateEGLImage()"; | 228 DVLOG(3) << "CreateEGLImage()"; |
228 if (!CanCreateEGLImageFrom(v4l2_pixfmt)) { | 229 if (!CanCreateEGLImageFrom(v4l2_pixfmt)) { |
229 LOG(ERROR) << "Unsupported V4L2 pixel format"; | 230 LOG(ERROR) << "Unsupported V4L2 pixel format"; |
230 return EGL_NO_IMAGE_KHR; | 231 return EGL_NO_IMAGE_KHR; |
231 } | 232 } |
232 | 233 |
233 media::VideoPixelFormat vf_format = V4L2PixFmtToVideoPixelFormat(v4l2_pixfmt); | 234 media::VideoPixelFormat vf_format = V4L2PixFmtToVideoPixelFormat(v4l2_pixfmt); |
234 // 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 |
235 // just a buffer count. | 236 // just a buffer count. |
236 size_t num_planes = media::VideoFrame::NumPlanes(vf_format); | 237 size_t num_planes = media::VideoFrame::NumPlanes(vf_format); |
237 DCHECK_LE(num_planes, 3u); | 238 DCHECK_LE(num_planes, 3u); |
238 if (num_planes < num_v4l2_planes) { | 239 if (num_planes < dmabuf_fds.size()) { |
239 // 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, |
240 // 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. |
241 LOG(ERROR) << "Invalid plane count"; | 242 LOG(ERROR) << "Invalid plane count"; |
242 return EGL_NO_IMAGE_KHR; | 243 return EGL_NO_IMAGE_KHR; |
243 } | 244 } |
244 | 245 |
245 std::unique_ptr<base::ScopedFD[]> dmabuf_fds( | |
246 new base::ScopedFD[num_v4l2_planes]); | |
247 // Export dmabuf fds so we can create an EGLImage from them. | |
248 for (size_t i = 0; i < num_v4l2_planes; ++i) { | |
249 struct v4l2_exportbuffer expbuf; | |
250 memset(&expbuf, 0, sizeof(expbuf)); | |
251 expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
252 expbuf.index = buffer_index; | |
253 expbuf.plane = i; | |
254 expbuf.flags = O_CLOEXEC; | |
255 if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) { | |
256 return EGL_NO_IMAGE_KHR; | |
257 } | |
258 dmabuf_fds[i].reset(expbuf.fd); | |
259 } | |
260 | |
261 std::vector<EGLint> attrs; | 246 std::vector<EGLint> attrs; |
262 attrs.push_back(EGL_WIDTH); | 247 attrs.push_back(EGL_WIDTH); |
263 attrs.push_back(frame_buffer_size.width()); | 248 attrs.push_back(size.width()); |
264 attrs.push_back(EGL_HEIGHT); | 249 attrs.push_back(EGL_HEIGHT); |
265 attrs.push_back(frame_buffer_size.height()); | 250 attrs.push_back(size.height()); |
266 attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT); | 251 attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT); |
267 attrs.push_back(V4L2PixFmtToDrmFormat(v4l2_pixfmt)); | 252 attrs.push_back(V4L2PixFmtToDrmFormat(v4l2_pixfmt)); |
268 | 253 |
269 // For existing formats, if we have less buffers (V4L2 planes) than | 254 // For existing formats, if we have less buffers (V4L2 planes) than |
270 // components (planes), the remaining planes are stored in the last | 255 // components (planes), the remaining planes are stored in the last |
271 // 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 |
272 // 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 |
273 // 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 |
274 // V4L2 plane. | 259 // V4L2 plane. |
275 size_t v4l2_plane = 0; | 260 size_t v4l2_plane = 0; |
276 size_t plane_offset = 0; | 261 size_t plane_offset = 0; |
277 for (size_t plane = 0; plane < num_planes; ++plane) { | 262 for (size_t plane = 0; plane < num_planes; ++plane) { |
278 attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + plane * 3); | 263 attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + plane * 3); |
279 attrs.push_back(dmabuf_fds[v4l2_plane].get()); | 264 attrs.push_back(dmabuf_fds[v4l2_plane].get()); |
280 attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + plane * 3); | 265 attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + plane * 3); |
281 attrs.push_back(plane_offset); | 266 attrs.push_back(plane_offset); |
282 attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + plane * 3); | 267 attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + plane * 3); |
283 attrs.push_back(media::VideoFrame::RowBytes(plane, vf_format, | 268 attrs.push_back( |
284 frame_buffer_size.width())); | 269 media::VideoFrame::RowBytes(plane, vf_format, size.width())); |
285 | 270 |
286 if (v4l2_plane + 1 < num_v4l2_planes) { | 271 if (v4l2_plane + 1 < dmabuf_fds.size()) { |
287 ++v4l2_plane; | 272 ++v4l2_plane; |
| 273 plane_offset = 0; |
288 } else { | 274 } else { |
289 plane_offset += media::VideoFrame::PlaneSize( | 275 plane_offset += |
290 vf_format, plane, frame_buffer_size).GetArea(); | 276 media::VideoFrame::PlaneSize(vf_format, plane, size).GetArea(); |
291 } | 277 } |
292 } | 278 } |
293 | 279 |
294 attrs.push_back(EGL_NONE); | 280 attrs.push_back(EGL_NONE); |
295 | 281 |
296 EGLImageKHR egl_image = eglCreateImageKHR( | 282 EGLImageKHR egl_image = eglCreateImageKHR( |
297 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, &attrs[0]); | 283 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, &attrs[0]); |
298 if (egl_image == EGL_NO_IMAGE_KHR) { | 284 if (egl_image == EGL_NO_IMAGE_KHR) { |
299 LOG(ERROR) << "Failed creating EGL image: " << ui::GetLastEGLErrorString(); | 285 LOG(ERROR) << "Failed creating EGL image: " << ui::GetLastEGLErrorString(); |
300 return egl_image; | 286 return egl_image; |
(...skipping 24 matching lines...) Expand all Loading... |
325 StubPathMap paths; | 311 StubPathMap paths; |
326 paths[kModuleV4l2].push_back(kV4l2Lib); | 312 paths[kModuleV4l2].push_back(kV4l2Lib); |
327 | 313 |
328 return InitializeStubs(paths); | 314 return InitializeStubs(paths); |
329 #else | 315 #else |
330 return true; | 316 return true; |
331 #endif | 317 #endif |
332 } | 318 } |
333 | 319 |
334 } // namespace content | 320 } // namespace content |
OLD | NEW |