Chromium Code Reviews| Index: content/common/gpu/media/generic_v4l2_video_device.cc |
| diff --git a/content/common/gpu/media/generic_v4l2_video_device.cc b/content/common/gpu/media/generic_v4l2_video_device.cc |
| index b0cbe58676c1c1a0052b3912118e60895cc1ca53..769e8f713890b17408cf9e1225219f009a1e6dce 100644 |
| --- a/content/common/gpu/media/generic_v4l2_video_device.cc |
| +++ b/content/common/gpu/media/generic_v4l2_video_device.cc |
| @@ -15,6 +15,7 @@ |
| #include "base/files/scoped_file.h" |
| #include "base/posix/eintr_wrapper.h" |
| #include "content/common/gpu/media/generic_v4l2_video_device.h" |
| +#include "ui/gl/egl_util.h" |
| #include "ui/gl/gl_bindings.h" |
| namespace content { |
| @@ -137,17 +138,50 @@ bool GenericV4L2Device::Initialize() { |
| return true; |
| } |
| +bool GenericV4L2Device::CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) { |
| + static uint32_t kEGLImageDrmFmtsSupported[] { |
|
kcwu
2015/01/06 08:28:52
= {
"(Uniform) Initialization Syntax" is disallowe
Pawel Osciak
2015/01/06 13:09:58
Oh typo, thanks.
|
| + DRM_FORMAT_ARGB8888, |
| +#if defined(ARCH_CPU_ARMEL) |
| + DRM_FORMAT_NV12, |
| +#endif |
| + }; |
| + |
| + return std::find( |
| + kEGLImageDrmFmtsSupported, |
| + kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported), |
| + V4L2PixFmtToDrmFormat(v4l2_pixfmt)) != |
| + kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported); |
| +} |
| + |
| EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display, |
| - EGLContext /* egl_context */, |
| - GLuint texture_id, |
| - gfx::Size frame_buffer_size, |
| - unsigned int buffer_index, |
| - size_t planes_count) { |
| + EGLContext /* egl_context */, |
| + GLuint texture_id, |
| + gfx::Size frame_buffer_size, |
| + unsigned int buffer_index, |
| + uint32_t v4l2_pixfmt, |
| + size_t num_v4l2_planes) { |
| DVLOG(3) << "CreateEGLImage()"; |
| + if (!CanCreateEGLImageFrom(v4l2_pixfmt)) { |
| + LOG(ERROR) << "Unsupported V4L2 pixel format"; |
| + return EGL_NO_IMAGE_KHR; |
| + } |
| - scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[planes_count]); |
| - for (size_t i = 0; i < planes_count; ++i) { |
| - // Export the DMABUF fd so we can export it as a texture. |
| + media::VideoFrame::Format vf_format = |
| + V4L2PixFmtToVideoFrameFormat(v4l2_pixfmt); |
| + // Number of components, as opposed to the number of V4L2 planes, which is |
| + // just a buffer count. |
| + size_t num_planes = media::VideoFrame::NumPlanes(vf_format); |
| + DCHECK_LE(num_planes, 3u); |
| + if (num_planes < num_v4l2_planes) { |
| + // It's possible for more than one DRM plane to reside in one V4L2 plane, |
| + // but not the other way around. We must use all V4L2 planes. |
| + LOG(ERROR) << "Invalid plane count"; |
| + return EGL_NO_IMAGE_KHR; |
| + } |
| + |
| + scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[num_v4l2_planes]); |
| + // Export dmabuf fds so we can create an EGLImage from them. |
| + for (size_t i = 0; i < num_v4l2_planes; ++i) { |
| struct v4l2_exportbuffer expbuf; |
| memset(&expbuf, 0, sizeof(expbuf)); |
| expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| @@ -159,26 +193,46 @@ EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display, |
| } |
| dmabuf_fds[i].reset(expbuf.fd); |
| } |
| - DCHECK_EQ(planes_count, 2u); |
| - EGLint attrs[] = { |
| - EGL_WIDTH, 0, EGL_HEIGHT, 0, |
| - EGL_LINUX_DRM_FOURCC_EXT, 0, EGL_DMA_BUF_PLANE0_FD_EXT, 0, |
| - EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, 0, |
| - EGL_DMA_BUF_PLANE1_FD_EXT, 0, EGL_DMA_BUF_PLANE1_OFFSET_EXT, 0, |
| - EGL_DMA_BUF_PLANE1_PITCH_EXT, 0, EGL_NONE, }; |
| - attrs[1] = frame_buffer_size.width(); |
| - attrs[3] = frame_buffer_size.height(); |
| - attrs[5] = DRM_FORMAT_NV12; |
| - attrs[7] = dmabuf_fds[0].get(); |
| - attrs[9] = 0; |
| - attrs[11] = frame_buffer_size.width(); |
| - attrs[13] = dmabuf_fds[1].get(); |
| - attrs[15] = 0; |
| - attrs[17] = frame_buffer_size.width(); |
| + |
| + std::vector<EGLint> attrs; |
| + attrs.push_back(EGL_WIDTH); |
| + attrs.push_back(frame_buffer_size.width()); |
| + attrs.push_back(EGL_HEIGHT); |
| + attrs.push_back(frame_buffer_size.height()); |
| + attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT); |
| + attrs.push_back(V4L2PixFmtToDrmFormat(v4l2_pixfmt)); |
| + |
| + // For existing formats, if we have less buffers (V4L2 planes) than |
| + // components (planes), the remaining planes are stored in the last |
| + // V4L2 plane. Use one V4L2 plane per each component until we run out of V4L2 |
| + // planes, and use the last V4L2 plane for all remaining components, each |
| + // with an offset equal to the size of the preceding planes in the same |
| + // V4L2 plane. |
| + size_t v4l2_plane = 0; |
| + size_t plane_offset = 0; |
| + for (size_t plane = 0; plane < num_planes; ++plane) { |
| + attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + plane * 3); |
| + attrs.push_back(dmabuf_fds[v4l2_plane].get()); |
| + attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + plane * 3); |
| + attrs.push_back(plane_offset); |
| + attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + plane * 3); |
| + attrs.push_back(media::VideoFrame::RowBytes(plane, vf_format, |
| + frame_buffer_size.width())); |
| + |
| + if (v4l2_plane + 1 < num_v4l2_planes) { |
| + ++v4l2_plane; |
| + } else { |
| + plane_offset += media::VideoFrame::PlaneAllocationSize( |
| + vf_format, plane, frame_buffer_size); |
| + } |
| + } |
| + |
| + attrs.push_back(EGL_NONE); |
| EGLImageKHR egl_image = eglCreateImageKHR( |
| - egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); |
| + egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, &attrs[0]); |
| if (egl_image == EGL_NO_IMAGE_KHR) { |
| + LOG(ERROR) << "Failed creating EGL image: " << ui::GetLastEGLErrorString(); |
| return egl_image; |
| } |
| glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id); |
| @@ -201,11 +255,4 @@ uint32 GenericV4L2Device::PreferredInputFormat() { |
| return V4L2_PIX_FMT_NV12M; |
| } |
| -uint32 GenericV4L2Device::PreferredOutputFormat() { |
| - // TODO(posciak): We should support "dontcare" returns here once we |
| - // implement proper handling (fallback, negotiation) for this in users. |
| - CHECK_EQ(type_, kDecoder); |
| - return V4L2_PIX_FMT_NV12M; |
| -} |
| - |
| } // namespace content |