1 From 56c58831b61cdb79f61f2f68c32854646241326b Mon Sep 17 00:00:00 2001
2 From: Carlos Rafael Giani <dv@pseudoterminal.org>
3 Date: Wed, 28 Mar 2018 00:47:33 +0200
4 Subject: [PATCH 2/2] gl/egl: Add gst_egl_image_from_dmabuf_direct() function
6 This also renames the existing gst_egl_image_from_dmabuf() to clarify the
7 difference between the two
9 https://bugzilla.gnome.org/show_bug.cgi?id=783521
11 docs/libs/gst-plugins-base-libs-sections.txt | 3 +-
12 gst-libs/gst/gl/egl/gsteglimage.c | 238 ++++++++++++++++++++++++++-
13 gst-libs/gst/gl/egl/gsteglimage.h | 8 +-
14 3 files changed, 239 insertions(+), 10 deletions(-)
16 diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt
17 index c2c528a76..3c4dfdf61 100644
18 --- a/docs/libs/gst-plugins-base-libs-sections.txt
19 +++ b/docs/libs/gst-plugins-base-libs-sections.txt
20 @@ -3853,7 +3853,8 @@ GstGLBaseFilterPrivate
22 <FILE>gsteglimage</FILE>
23 <TITLE>GstEGLImage</TITLE>
24 -gst_egl_image_from_dmabuf
25 +gst_egl_image_from_dmabuf_as_rgba_plane
26 +gst_egl_image_from_dmabuf_direct
27 gst_egl_image_from_texture
28 gst_egl_image_get_image
29 gst_egl_image_new_wrapped
30 diff --git a/gst-libs/gst/gl/egl/gsteglimage.c b/gst-libs/gst/gl/egl/gsteglimage.c
31 index fdd603807..9f4a018fc 100644
32 --- a/gst-libs/gst/gl/egl/gsteglimage.c
33 +++ b/gst-libs/gst/gl/egl/gsteglimage.c
36 * #GstEGLImage represents and holds an #EGLImage handle.
38 - * A #GstEGLImage can be created from a dmabuf with gst_egl_image_from_dmabuf()
39 - * or #GstGLMemoryEGL provides a #GstAllocator to allocate #EGLImage's bound to
40 - * and OpenGL texture.
41 + * A #GstEGLImage can be created from a dmabuf with gst_egl_image_from_dmabuf_direct()
42 + * or gst_egl_image_from_dmabuf_as_rgba_plane(), or #GstGLMemoryEGL provides a
43 + * #GstAllocator to allocate #EGLImage's bound to and OpenGL texture.
47 @@ -344,12 +344,12 @@ gst_egl_image_from_texture (GstGLContext * context, GstGLMemory * gl_mem,
49 * GStreamer format descriptions differ from DRM formats as the representation
50 * is relative to a register, hence in native endianness. To reduce the driver
51 - * requirement, we only import with a subset of texture formats and use
52 + * requirement, we only import with a subset of RGBA texture formats and use
53 * shaders to convert. This way we avoid having to use external texture
57 -_drm_fourcc_from_info (GstVideoInfo * info, int plane)
58 +_drm_rgba_fourcc_from_info (GstVideoInfo * info, int plane)
60 GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
61 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
62 @@ -410,19 +410,113 @@ _drm_fourcc_from_info (GstVideoInfo * info, int plane)
68 + * Variant of _drm_rgba_fourcc_from_info() that is used in case the GPU can
69 + * handle YUV formats directly (by using internal shaders, or hardwired
70 + * YUV->RGB conversion matrices etc.)
73 +_drm_direct_fourcc_from_info (GstVideoInfo * info)
75 + GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
77 + GST_DEBUG ("Getting DRM fourcc for %s", gst_video_format_to_string (format));
80 + case GST_VIDEO_FORMAT_YUY2:
81 + return DRM_FORMAT_YUYV;
83 + case GST_VIDEO_FORMAT_YVYU:
84 + return DRM_FORMAT_YVYU;
86 + case GST_VIDEO_FORMAT_UYVY:
87 + return DRM_FORMAT_UYVY;
89 + case GST_VIDEO_FORMAT_VYUY:
90 + return DRM_FORMAT_VYUY;
92 + case GST_VIDEO_FORMAT_AYUV:
93 + return DRM_FORMAT_AYUV;
95 + case GST_VIDEO_FORMAT_NV12:
96 + return DRM_FORMAT_NV12;
98 + case GST_VIDEO_FORMAT_NV21:
99 + return DRM_FORMAT_NV21;
101 + case GST_VIDEO_FORMAT_NV16:
102 + return DRM_FORMAT_NV16;
104 + case GST_VIDEO_FORMAT_NV61:
105 + return DRM_FORMAT_NV61;
107 + case GST_VIDEO_FORMAT_NV24:
108 + return DRM_FORMAT_NV24;
110 + case GST_VIDEO_FORMAT_YUV9:
111 + return DRM_FORMAT_YUV410;
113 + case GST_VIDEO_FORMAT_YVU9:
114 + return DRM_FORMAT_YVU410;
116 + case GST_VIDEO_FORMAT_Y41B:
117 + return DRM_FORMAT_YUV411;
119 + case GST_VIDEO_FORMAT_I420:
120 + return DRM_FORMAT_YUV420;
122 + case GST_VIDEO_FORMAT_YV12:
123 + return DRM_FORMAT_YVU420;
125 + case GST_VIDEO_FORMAT_Y42B:
126 + return DRM_FORMAT_YUV422;
128 + case GST_VIDEO_FORMAT_Y444:
129 + return DRM_FORMAT_YUV444;
131 + case GST_VIDEO_FORMAT_RGB16:
132 + case GST_VIDEO_FORMAT_BGR16:
133 + case GST_VIDEO_FORMAT_RGB:
134 + case GST_VIDEO_FORMAT_BGR:
135 + case GST_VIDEO_FORMAT_RGBA:
136 + case GST_VIDEO_FORMAT_RGBx:
137 + case GST_VIDEO_FORMAT_BGRA:
138 + case GST_VIDEO_FORMAT_BGRx:
139 + case GST_VIDEO_FORMAT_ARGB:
140 + case GST_VIDEO_FORMAT_xRGB:
141 + case GST_VIDEO_FORMAT_ABGR:
142 + case GST_VIDEO_FORMAT_xBGR:
143 + case GST_VIDEO_FORMAT_GRAY8:
144 + /* Use _drm_rgba_fourcc_from_info() as fallback for RGB formats */
145 + return _drm_rgba_fourcc_from_info (info, 0);
148 + GST_ERROR ("Unsupported format for DMABuf.");
154 - * gst_egl_image_from_dmabuf:
155 + * gst_egl_image_from_dmabuf_as_rgba_plane:
156 * @context: a #GstGLContext (must be an EGL context)
157 * @dmabuf: the DMA-Buf file descriptor
158 * @in_info: the #GstVideoInfo in @dmabuf
159 * @plane: the plane in @in_info to create and #GstEGLImage for
160 * @offset: the byte-offset in the data
162 + * Creates an EGL image that imports the dmabuf FD. The dmabuf data
163 + * is passed as RGBA data. Shaders later take this "RGBA" data and
164 + * convert it from its true format (described by in_info) to actual
165 + * RGBA output. For example, with I420, three EGL images are created,
166 + * one for each plane, each EGL image with a single-channel R format.
167 + * With NV12, two EGL images are created, one with R format, one
168 + * with RG format etc.
170 * Returns: a #GstEGLImage wrapping @dmabuf or %NULL on failure
173 -gst_egl_image_from_dmabuf (GstGLContext * context,
174 +gst_egl_image_from_dmabuf_as_rgba_plane (GstGLContext * context,
175 gint dmabuf, GstVideoInfo * in_info, gint plane, gsize offset)
178 @@ -432,7 +526,7 @@ gst_egl_image_from_dmabuf (GstGLContext * context,
182 - fourcc = _drm_fourcc_from_info (in_info, plane);
183 + fourcc = _drm_rgba_fourcc_from_info (in_info, plane);
184 format = gst_gl_format_from_video_info (context, in_info, plane);
186 GST_DEBUG ("fourcc %.4s (%d) plane %d (%dx%d)",
187 @@ -470,6 +564,134 @@ gst_egl_image_from_dmabuf (GstGLContext * context,
188 (GstEGLImageDestroyNotify) _destroy_egl_image);
192 + * gst_egl_image_from_dmabuf_direct:
193 + * @context: a #GstGLContext (must be an EGL context)
194 + * @buffer: the #GstBuffer containing DMA-Buf memory
195 + * @in_info: the #GstVideoInfo in @dmabuf
197 + * Creates an EGL image that imports the dmabuf FD. The dmabuf data
198 + * is passed directly as the format described in in_info. This is
199 + * useful if the hardware is capable of performing color space conversions
200 + * internally. The appropriate DRM format is picked, and the EGL image
201 + * is created with this DRM format.
203 + * Another notable difference to gst_egl_image_from_dmabuf_as_rgba_plane()
204 + * is that this function creates one EGL image for all planes, not just one.
206 + * Returns: a #GstEGLImage wrapping @dmabuf or %NULL on failure
209 +gst_egl_image_from_dmabuf_direct (GstGLContext * context,
210 + GstBuffer * buffer, GstVideoInfo * in_info)
212 +#define MAX_NUM_DMA_BUF_PLANES (3)
214 + guint mems_idx[MAX_NUM_DMA_BUF_PLANES];
215 + gsize mems_skip[MAX_NUM_DMA_BUF_PLANES];
216 + GstMemory *mems[MAX_NUM_DMA_BUF_PLANES];
218 + guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info);
219 + gint fourcc = _drm_direct_fourcc_from_info (in_info);
222 + /* Explanation of array length:
223 + * - 6 plane independent values are at the start (width, height, format FourCC)
224 + * - 6 values per plane, and there are up to MAX_NUM_DMA_BUF_PLANES planes
225 + * - 1 extra value for the EGL_NONE sentinel
227 + guintptr attribs[6 + 6 * (MAX_NUM_DMA_BUF_PLANES) + 1] = {
228 + EGL_WIDTH, GST_VIDEO_INFO_WIDTH (in_info),
229 + EGL_HEIGHT, GST_VIDEO_INFO_HEIGHT (in_info),
230 + EGL_LINUX_DRM_FOURCC_EXT, fourcc
233 + static const EGLint egl_dmabuf_plane_fd_attr[MAX_NUM_DMA_BUF_PLANES] = {
234 + EGL_DMA_BUF_PLANE0_FD_EXT,
235 + EGL_DMA_BUF_PLANE1_FD_EXT,
236 + EGL_DMA_BUF_PLANE2_FD_EXT,
238 + static const EGLint egl_dmabuf_plane_offset_attr[MAX_NUM_DMA_BUF_PLANES] = {
239 + EGL_DMA_BUF_PLANE0_OFFSET_EXT,
240 + EGL_DMA_BUF_PLANE1_OFFSET_EXT,
241 + EGL_DMA_BUF_PLANE2_OFFSET_EXT,
243 + static const EGLint egl_dmabuf_plane_pitch_attr[MAX_NUM_DMA_BUF_PLANES] = {
244 + EGL_DMA_BUF_PLANE0_PITCH_EXT,
245 + EGL_DMA_BUF_PLANE1_PITCH_EXT,
246 + EGL_DMA_BUF_PLANE2_PITCH_EXT,
249 + /* Make sure we never set up more than MAX_NUM_DMA_BUF_PLANES planes */
250 + if (G_UNLIKELY (n_planes > MAX_NUM_DMA_BUF_PLANES))
251 + n_planes = MAX_NUM_DMA_BUF_PLANES;
253 + GST_DEBUG ("Setting up EGL image attributes for %u plane(s)", n_planes);
255 + for (i = 0; i < n_planes; i++) {
258 + gsize offset, stride;
261 + plane_size = gst_gl_get_plane_data_size (in_info, NULL, i);
263 + /* In the buffer, find the memory block that corresponds to the current plane,
264 + * and note down the offset (which is needed for the EGLImage) and the index
265 + * of the memory block */
266 + if (!gst_buffer_find_memory (buffer, in_info->offset[i], plane_size,
267 + &mems_idx[i], &length, &mems_skip[i])) {
268 + GST_DEBUG ("Couldn't find memory for plane %d", i);
272 + /* We can't have more then one dmabuf per plane */
275 + ("There are multiple dmabufs for plane %d, which is unsupported", i);
279 + /* Get a pointer to the memory block we found earlier */
280 + mems[i] = gst_buffer_peek_memory (buffer, mems_idx[i]);
282 + /* And all memory found must be dmabuf */
283 + if (!gst_is_dmabuf_memory (mems[i])) {
284 + GST_DEBUG ("Plane %d memory isn't dmabuf", i);
288 + fd = gst_dmabuf_memory_get_fd (mems[i]);
289 + offset = mems[i]->offset + mems_skip[i];
290 + stride = GST_VIDEO_INFO_PLANE_STRIDE (in_info, i);
292 + /* Set up configuration for the i-th plane */
293 + attribs[6 + 6 * i + 0] = egl_dmabuf_plane_fd_attr[i];
294 + attribs[6 + 6 * i + 1] = fd;
295 + attribs[6 + 6 * i + 2] = egl_dmabuf_plane_offset_attr[i];
296 + attribs[6 + 6 * i + 3] = offset;
297 + attribs[6 + 6 * i + 4] = egl_dmabuf_plane_pitch_attr[i];
298 + attribs[6 + 6 * i + 5] = stride;
300 + GST_DEBUG ("Plane %d has FD %d offset %" G_GSIZE_FORMAT " stride %"
301 + G_GSIZE_FORMAT, i, fd, offset, stride);
304 + /* Add the EGL_NONE sentinel */
305 + attribs[6 + 6 * n_planes] = EGL_NONE;
307 + img = _gst_egl_image_create (context, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
309 + GST_WARNING ("eglCreateImage failed: %s",
310 + gst_egl_get_error_string (eglGetError ()));
314 + /* TODO: RGBA or RGB? */
315 + return gst_egl_image_new_wrapped (context, img, GST_GL_RGB, NULL,
316 + (GstEGLImageDestroyNotify) _destroy_egl_image);
320 gst_egl_image_export_dmabuf (GstEGLImage * image, int *fd, gint * stride,
322 diff --git a/gst-libs/gst/gl/egl/gsteglimage.h b/gst-libs/gst/gl/egl/gsteglimage.h
323 index aaebceccf..5a75bc4f9 100644
324 --- a/gst-libs/gst/gl/egl/gsteglimage.h
325 +++ b/gst-libs/gst/gl/egl/gsteglimage.h
326 @@ -83,11 +83,17 @@ GstEGLImage * gst_egl_image_from_texture (GstGLContext *
328 #if GST_GL_HAVE_DMABUF
330 -GstEGLImage * gst_egl_image_from_dmabuf (GstGLContext * context,
331 +GstEGLImage * gst_egl_image_from_dmabuf_as_rgba_plane (GstGLContext * context,
333 GstVideoInfo * in_info,
338 +GstEGLImage * gst_egl_image_from_dmabuf_direct (GstGLContext * context,
339 + GstBuffer * buffer,
340 + GstVideoInfo * in_info);
343 gboolean gst_egl_image_export_dmabuf (GstEGLImage *image, int *fd, gint *stride, gsize *offset);