Chromium Code Reviews| 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 |