Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: content/common/gpu/media/generic_v4l2_video_device.cc

Issue 839523002: V4L2VDA: Generalize EGLImage import and query driver for output formats. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/generic_v4l2_video_device.h" 17 #include "content/common/gpu/media/generic_v4l2_video_device.h"
18 #include "ui/gl/egl_util.h"
18 #include "ui/gl/gl_bindings.h" 19 #include "ui/gl/gl_bindings.h"
19 20
20 namespace content { 21 namespace content {
21 22
22 namespace { 23 namespace {
23 const char kDecoderDevice[] = "/dev/video-dec"; 24 const char kDecoderDevice[] = "/dev/video-dec";
24 const char kEncoderDevice[] = "/dev/video-enc"; 25 const char kEncoderDevice[] = "/dev/video-enc";
25 const char kImageProcessorDevice[] = "/dev/gsc1"; 26 const char kImageProcessorDevice[] = "/dev/gsc1";
26 } 27 }
27 28
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 return false; 131 return false;
131 } 132 }
132 133
133 device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 134 device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
134 if (device_poll_interrupt_fd_ == -1) { 135 if (device_poll_interrupt_fd_ == -1) {
135 return false; 136 return false;
136 } 137 }
137 return true; 138 return true;
138 } 139 }
139 140
141 bool GenericV4L2Device::CanCreateEGLImageFrom(uint32_t v4l2_pixfmt) {
142 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.
143 DRM_FORMAT_ARGB8888,
144 #if defined(ARCH_CPU_ARMEL)
145 DRM_FORMAT_NV12,
146 #endif
147 };
148
149 return std::find(
150 kEGLImageDrmFmtsSupported,
151 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported),
152 V4L2PixFmtToDrmFormat(v4l2_pixfmt)) !=
153 kEGLImageDrmFmtsSupported + arraysize(kEGLImageDrmFmtsSupported);
154 }
155
140 EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display, 156 EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display,
141 EGLContext /* egl_context */, 157 EGLContext /* egl_context */,
142 GLuint texture_id, 158 GLuint texture_id,
143 gfx::Size frame_buffer_size, 159 gfx::Size frame_buffer_size,
144 unsigned int buffer_index, 160 unsigned int buffer_index,
145 size_t planes_count) { 161 uint32_t v4l2_pixfmt,
162 size_t num_v4l2_planes) {
146 DVLOG(3) << "CreateEGLImage()"; 163 DVLOG(3) << "CreateEGLImage()";
164 if (!CanCreateEGLImageFrom(v4l2_pixfmt)) {
165 LOG(ERROR) << "Unsupported V4L2 pixel format";
166 return EGL_NO_IMAGE_KHR;
167 }
147 168
148 scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[planes_count]); 169 media::VideoFrame::Format vf_format =
149 for (size_t i = 0; i < planes_count; ++i) { 170 V4L2PixFmtToVideoFrameFormat(v4l2_pixfmt);
150 // Export the DMABUF fd so we can export it as a texture. 171 // Number of components, as opposed to the number of V4L2 planes, which is
172 // just a buffer count.
173 size_t num_planes = media::VideoFrame::NumPlanes(vf_format);
174 DCHECK_LE(num_planes, 3u);
175 if (num_planes < num_v4l2_planes) {
176 // It's possible for more than one DRM plane to reside in one V4L2 plane,
177 // but not the other way around. We must use all V4L2 planes.
178 LOG(ERROR) << "Invalid plane count";
179 return EGL_NO_IMAGE_KHR;
180 }
181
182 scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[num_v4l2_planes]);
183 // Export dmabuf fds so we can create an EGLImage from them.
184 for (size_t i = 0; i < num_v4l2_planes; ++i) {
151 struct v4l2_exportbuffer expbuf; 185 struct v4l2_exportbuffer expbuf;
152 memset(&expbuf, 0, sizeof(expbuf)); 186 memset(&expbuf, 0, sizeof(expbuf));
153 expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 187 expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
154 expbuf.index = buffer_index; 188 expbuf.index = buffer_index;
155 expbuf.plane = i; 189 expbuf.plane = i;
156 expbuf.flags = O_CLOEXEC; 190 expbuf.flags = O_CLOEXEC;
157 if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) { 191 if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) {
158 return EGL_NO_IMAGE_KHR; 192 return EGL_NO_IMAGE_KHR;
159 } 193 }
160 dmabuf_fds[i].reset(expbuf.fd); 194 dmabuf_fds[i].reset(expbuf.fd);
161 } 195 }
162 DCHECK_EQ(planes_count, 2u); 196
163 EGLint attrs[] = { 197 std::vector<EGLint> attrs;
164 EGL_WIDTH, 0, EGL_HEIGHT, 0, 198 attrs.push_back(EGL_WIDTH);
165 EGL_LINUX_DRM_FOURCC_EXT, 0, EGL_DMA_BUF_PLANE0_FD_EXT, 0, 199 attrs.push_back(frame_buffer_size.width());
166 EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, 0, 200 attrs.push_back(EGL_HEIGHT);
167 EGL_DMA_BUF_PLANE1_FD_EXT, 0, EGL_DMA_BUF_PLANE1_OFFSET_EXT, 0, 201 attrs.push_back(frame_buffer_size.height());
168 EGL_DMA_BUF_PLANE1_PITCH_EXT, 0, EGL_NONE, }; 202 attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
169 attrs[1] = frame_buffer_size.width(); 203 attrs.push_back(V4L2PixFmtToDrmFormat(v4l2_pixfmt));
170 attrs[3] = frame_buffer_size.height(); 204
171 attrs[5] = DRM_FORMAT_NV12; 205 // For existing formats, if we have less buffers (V4L2 planes) than
172 attrs[7] = dmabuf_fds[0].get(); 206 // components (planes), the remaining planes are stored in the last
173 attrs[9] = 0; 207 // V4L2 plane. Use one V4L2 plane per each component until we run out of V4L2
174 attrs[11] = frame_buffer_size.width(); 208 // planes, and use the last V4L2 plane for all remaining components, each
175 attrs[13] = dmabuf_fds[1].get(); 209 // with an offset equal to the size of the preceding planes in the same
176 attrs[15] = 0; 210 // V4L2 plane.
177 attrs[17] = frame_buffer_size.width(); 211 size_t v4l2_plane = 0;
212 size_t plane_offset = 0;
213 for (size_t plane = 0; plane < num_planes; ++plane) {
214 attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + plane * 3);
215 attrs.push_back(dmabuf_fds[v4l2_plane].get());
216 attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + plane * 3);
217 attrs.push_back(plane_offset);
218 attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + plane * 3);
219 attrs.push_back(media::VideoFrame::RowBytes(plane, vf_format,
220 frame_buffer_size.width()));
221
222 if (v4l2_plane + 1 < num_v4l2_planes) {
223 ++v4l2_plane;
224 } else {
225 plane_offset += media::VideoFrame::PlaneAllocationSize(
226 vf_format, plane, frame_buffer_size);
227 }
228 }
229
230 attrs.push_back(EGL_NONE);
178 231
179 EGLImageKHR egl_image = eglCreateImageKHR( 232 EGLImageKHR egl_image = eglCreateImageKHR(
180 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); 233 egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, &attrs[0]);
181 if (egl_image == EGL_NO_IMAGE_KHR) { 234 if (egl_image == EGL_NO_IMAGE_KHR) {
235 LOG(ERROR) << "Failed creating EGL image: " << ui::GetLastEGLErrorString();
182 return egl_image; 236 return egl_image;
183 } 237 }
184 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id); 238 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
185 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); 239 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image);
186 240
187 return egl_image; 241 return egl_image;
188 } 242 }
189 243
190 EGLBoolean GenericV4L2Device::DestroyEGLImage(EGLDisplay egl_display, 244 EGLBoolean GenericV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
191 EGLImageKHR egl_image) { 245 EGLImageKHR egl_image) {
192 return eglDestroyImageKHR(egl_display, egl_image); 246 return eglDestroyImageKHR(egl_display, egl_image);
193 } 247 }
194 248
195 GLenum GenericV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; } 249 GLenum GenericV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; }
196 250
197 uint32 GenericV4L2Device::PreferredInputFormat() { 251 uint32 GenericV4L2Device::PreferredInputFormat() {
198 // TODO(posciak): We should support "dontcare" returns here once we 252 // TODO(posciak): We should support "dontcare" returns here once we
199 // implement proper handling (fallback, negotiation) for this in users. 253 // implement proper handling (fallback, negotiation) for this in users.
200 CHECK_EQ(type_, kEncoder); 254 CHECK_EQ(type_, kEncoder);
201 return V4L2_PIX_FMT_NV12M; 255 return V4L2_PIX_FMT_NV12M;
202 } 256 }
203 257
204 uint32 GenericV4L2Device::PreferredOutputFormat() {
205 // TODO(posciak): We should support "dontcare" returns here once we
206 // implement proper handling (fallback, negotiation) for this in users.
207 CHECK_EQ(type_, kDecoder);
208 return V4L2_PIX_FMT_NV12M;
209 }
210
211 } // namespace content 258 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698