3 * Copyright (C) 2012 Collabora Ltd.
4 * @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * Copyright (C) 2014 Julien Isorce <julien.isorce@gmail.com>
6 * Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 * @short_description: EGLImage abstraction
28 * @see_also: #GstGLMemoryEGL, #GstGLContext
30 * #GstEGLImage represents and holds an #EGLImage handle.
32 * A #GstEGLImage can be created from a dmabuf with gst_egl_image_from_dmabuf(),
33 * or gst_egl_image_from_dmabuf_direct(), or #GstGLMemoryEGL provides a
34 * #GstAllocator to allocate #EGLImage's bound to and OpenGL texture.
41 #include "gsteglimage.h"
45 #include <gst/gl/gstglfeature.h>
46 #include <gst/gl/gstglmemory.h>
48 #include "gst/gl/egl/gstegl.h"
49 #include "gst/gl/egl/gstglcontext_egl.h"
50 #include "gst/gl/egl/gstgldisplay_egl.h"
52 #if GST_GL_HAVE_DMABUF
53 #include <gst/allocators/gstdmabuf.h>
54 #include <libdrm/drm_fourcc.h>
57 #define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ')
60 #ifndef DRM_FORMAT_RG88
61 #define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8')
64 #ifndef DRM_FORMAT_GR88
65 #define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8')
68 #ifndef DRM_FORMAT_NV24
69 #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4')
73 #ifndef EGL_LINUX_DMA_BUF_EXT
74 #define EGL_LINUX_DMA_BUF_EXT 0x3270
77 #ifndef EGL_LINUX_DRM_FOURCC_EXT
78 #define EGL_LINUX_DRM_FOURCC_EXT 0x3271
81 #ifndef EGL_DMA_BUF_PLANE0_FD_EXT
82 #define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
85 #ifndef EGL_DMA_BUF_PLANE0_OFFSET_EXT
86 #define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
89 #ifndef EGL_DMA_BUF_PLANE0_PITCH_EXT
90 #define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
93 #ifndef EGL_DMA_BUF_PLANE1_FD_EXT
94 #define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
97 #ifndef EGL_DMA_BUF_PLANE1_OFFSET_EXT
98 #define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
101 #ifndef EGL_DMA_BUF_PLANE1_PITCH_EXT
102 #define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
105 #ifndef EGL_DMA_BUF_PLANE2_FD_EXT
106 #define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
109 #ifndef EGL_DMA_BUF_PLANE2_OFFSET_EXT
110 #define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
113 #ifndef EGL_DMA_BUF_PLANE2_PITCH_EXT
114 #define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
117 #ifndef DRM_FORMAT_MOD_LINEAR
118 #define DRM_FORMAT_MOD_LINEAR 0ULL
121 #ifndef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT
122 #define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
125 #ifndef EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT
126 #define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
129 #ifndef EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT
130 #define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
133 #ifndef EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT
134 #define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
137 #ifndef EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT
138 #define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
141 #ifndef EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT
142 #define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
145 #ifndef EGL_ITU_REC601_EXT
146 #define EGL_ITU_REC601_EXT 0x327F
149 #ifndef EGL_ITU_REC709_EXT
150 #define EGL_ITU_REC709_EXT 0x3280
153 #ifndef EGL_ITU_REC2020_EXT
154 #define EGL_ITU_REC2020_EXT 0x3281
157 #ifndef EGL_SAMPLE_RANGE_HINT_EXT
158 #define EGL_SAMPLE_RANGE_HINT_EXT 0x327C
161 #ifndef EGL_YUV_COLOR_SPACE_HINT_EXT
162 #define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B
165 #ifndef EGL_YUV_FULL_RANGE_EXT
166 #define EGL_YUV_FULL_RANGE_EXT 0x3282
169 #ifndef EGL_YUV_NARROW_RANGE_EXT
170 #define EGL_YUV_NARROW_RANGE_EXT 0x3283
173 #if !GST_GL_HAVE_EGLUINT64KHR
174 typedef khronos_uint64_t EGLuint64KHR;
177 GST_DEFINE_MINI_OBJECT_TYPE (GstEGLImage, gst_egl_image);
179 #ifndef GST_DISABLE_GST_DEBUG
180 #define GST_CAT_DEFAULT gst_egl_image_ensure_debug_category()
182 static GstDebugCategory *
183 gst_egl_image_ensure_debug_category (void)
185 static gsize cat_gonce = 0;
187 if (g_once_init_enter (&cat_gonce)) {
188 GstDebugCategory *cat = NULL;
190 GST_DEBUG_CATEGORY_INIT (cat, "gleglimage", 0, "EGLImage wrapper");
192 g_once_init_leave (&cat_gonce, (gsize) cat);
195 return (GstDebugCategory *) cat_gonce;
197 #endif /* GST_DISABLE_GST_DEBUG */
200 * gst_egl_image_get_image:
201 * @image: a #GstEGLImage
203 * Returns: the #EGLImageKHR of @image
206 gst_egl_image_get_image (GstEGLImage * image)
208 g_return_val_if_fail (GST_IS_EGL_IMAGE (image), EGL_NO_IMAGE_KHR);
214 _gst_egl_image_free_thread (GstGLContext * context, GstEGLImage * image)
216 if (image->destroy_notify)
217 image->destroy_notify (image, image->destroy_data);
221 _gst_egl_image_free (GstMiniObject * object)
223 GstEGLImage *image = GST_EGL_IMAGE (object);
225 if (image->context) {
226 gst_gl_context_thread_add (GST_GL_CONTEXT (image->context),
227 (GstGLContextThreadFunc) _gst_egl_image_free_thread, image);
228 gst_object_unref (image->context);
232 static GstMiniObject *
233 _gst_egl_image_copy (GstMiniObject * obj)
235 return gst_mini_object_ref (obj);
239 * gst_egl_image_new_wrapped:
240 * @context: a #GstGLContext (must be an EGL context)
241 * @image: the image to wrap
242 * @format: the #GstGLFormat
243 * @user_data: user data
244 * @user_data_destroy: (destroy user_data): called when @user_data is no longer needed
246 * Returns: a new #GstEGLImage wrapping @image
249 gst_egl_image_new_wrapped (GstGLContext * context, gpointer image,
250 GstGLFormat format, gpointer user_data,
251 GstEGLImageDestroyNotify user_data_destroy)
253 GstEGLImage *img = NULL;
255 g_return_val_if_fail (context != NULL, NULL);
256 g_return_val_if_fail ((gst_gl_context_get_gl_platform (context) &
257 GST_GL_PLATFORM_EGL) != 0, NULL);
258 g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
260 img = g_new0 (GstEGLImage, 1);
261 gst_mini_object_init (GST_MINI_OBJECT_CAST (img), 0, GST_TYPE_EGL_IMAGE,
262 (GstMiniObjectCopyFunction) _gst_egl_image_copy, NULL,
263 (GstMiniObjectFreeFunction) _gst_egl_image_free);
265 img->context = gst_object_ref (context);
267 img->format = format;
269 img->destroy_data = user_data;
270 img->destroy_notify = user_data_destroy;
276 _gst_egl_image_create (GstGLContext * context, guint target,
277 EGLClientBuffer buffer, guintptr * attribs)
279 EGLDisplay egl_display = EGL_DEFAULT_DISPLAY;
280 EGLContext egl_context = EGL_NO_CONTEXT;
281 EGLImageKHR img = EGL_NO_IMAGE_KHR;
282 GstGLDisplayEGL *display_egl;
283 gint plat_major, plat_minor;
284 guint attrib_len = 0;
286 gst_gl_context_get_gl_platform_version (context, &plat_major, &plat_minor);
288 display_egl = gst_gl_display_egl_from_gl_display (context->display);
290 GST_WARNING_OBJECT (context, "Failed to retrieve GstGLDisplayEGL from %"
291 GST_PTR_FORMAT, context->display);
292 return EGL_NO_IMAGE_KHR;
295 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (display_egl));
296 gst_object_unref (display_egl);
298 if (target != EGL_LINUX_DMA_BUF_EXT)
299 egl_context = (EGLContext) gst_gl_context_get_gl_context (context);
302 while (attribs[attrib_len++] != EGL_NONE) {
304 #ifdef EGL_VERSION_1_5
305 if (GST_GL_CHECK_GL_VERSION (plat_major, plat_minor, 1, 5)) {
306 EGLImageKHR (*gst_eglCreateImage) (EGLDisplay dpy, EGLContext ctx,
307 EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list);
308 EGLAttrib *egl_attribs = NULL;
311 gst_eglCreateImage = gst_gl_context_get_proc_address (context,
313 if (!gst_eglCreateImage) {
314 GST_ERROR_OBJECT (context, "\"eglCreateImage\" not exposed by the "
315 "implementation as required by EGL >= 1.5");
316 return EGL_NO_IMAGE_KHR;
320 egl_attribs = g_new0 (EGLAttrib, attrib_len);
321 for (i = 0; i < attrib_len; i++)
322 egl_attribs[i] = (EGLAttrib) attribs[i];
325 img = gst_eglCreateImage (egl_display, egl_context, target, buffer,
328 g_free (egl_attribs);
332 EGLImageKHR (*gst_eglCreateImageKHR) (EGLDisplay dpy, EGLContext ctx,
333 EGLenum target, EGLClientBuffer buffer, const EGLint * attrib_list);
334 EGLint *egl_attribs = NULL;
337 gst_eglCreateImageKHR = gst_gl_context_get_proc_address (context,
338 "eglCreateImageKHR");
339 if (!gst_eglCreateImageKHR) {
340 GST_WARNING_OBJECT (context, "\"eglCreateImageKHR\" not exposed by the "
342 return EGL_NO_IMAGE_KHR;
346 egl_attribs = g_new0 (EGLint, attrib_len);
347 for (i = 0; i < attrib_len; i++)
348 egl_attribs[i] = (EGLint) attribs[i];
351 img = gst_eglCreateImageKHR (egl_display, egl_context, target, buffer,
354 g_free (egl_attribs);
361 _gst_egl_image_destroy (GstGLContext * context, EGLImageKHR image)
363 EGLBoolean (*gst_eglDestroyImage) (EGLDisplay dpy, EGLImageKHR image);
364 EGLDisplay egl_display = EGL_DEFAULT_DISPLAY;
365 GstGLDisplayEGL *display_egl;
367 gst_eglDestroyImage = gst_gl_context_get_proc_address (context,
369 if (!gst_eglDestroyImage) {
370 gst_eglDestroyImage = gst_gl_context_get_proc_address (context,
371 "eglDestroyImageKHR");
372 if (!gst_eglDestroyImage) {
373 GST_ERROR_OBJECT (context, "\"eglDestroyImage\" not exposed by the "
379 display_egl = gst_gl_display_egl_from_gl_display (context->display);
381 GST_WARNING_OBJECT (context, "Failed to retrieve GstGLDisplayEGL from %"
382 GST_PTR_FORMAT, context->display);
386 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (display_egl));
387 gst_object_unref (display_egl);
389 if (!gst_eglDestroyImage (egl_display, image))
390 GST_WARNING_OBJECT (context, "eglDestroyImage failed");
394 _destroy_egl_image (GstEGLImage * image, gpointer user_data)
396 _gst_egl_image_destroy (image->context, image->image);
400 * gst_egl_image_from_texture:
401 * @context: a #GstGLContext (must be an EGL context)
402 * @gl_mem: a #GstGLMemory
403 * @attribs: additional attributes to add to the eglCreateImage() call.
405 * Returns: (transfer full): a #GstEGLImage wrapping @gl_mem or %NULL on failure
408 gst_egl_image_from_texture (GstGLContext * context, GstGLMemory * gl_mem,
414 if (gl_mem->tex_target != GST_GL_TEXTURE_TARGET_2D) {
415 GST_FIXME_OBJECT (context, "Only know how to create EGLImage's from 2D "
420 egl_target = EGL_GL_TEXTURE_2D_KHR;
422 img = _gst_egl_image_create (context, egl_target,
423 (EGLClientBuffer) (guintptr) gl_mem->tex_id, attribs);
427 return gst_egl_image_new_wrapped (context, img, gl_mem->tex_format, NULL,
428 (GstEGLImageDestroyNotify) _destroy_egl_image);
431 #if GST_GL_HAVE_DMABUF
433 * GStreamer format descriptions differ from DRM formats as the representation
434 * is relative to a register, hence in native endianness. To reduce the driver
435 * requirement, we only import with a subset of texture formats and use
436 * shaders to convert. This way we avoid having to use external texture
440 _drm_rgba_fourcc_from_info (GstVideoInfo * info, int plane,
441 GstGLFormat * out_format)
443 GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
444 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
445 const gint rgba_fourcc = DRM_FORMAT_ABGR8888;
446 const gint rgb_fourcc = DRM_FORMAT_BGR888;
447 const gint rg_fourcc = DRM_FORMAT_GR88;
449 const gint rgba_fourcc = DRM_FORMAT_RGBA8888;
450 const gint rgb_fourcc = DRM_FORMAT_RGB888;
451 const gint rg_fourcc = DRM_FORMAT_RG88;
454 GST_DEBUG ("Getting DRM fourcc for %s plane %i",
455 gst_video_format_to_string (format), plane);
458 case GST_VIDEO_FORMAT_RGB16:
459 case GST_VIDEO_FORMAT_BGR16:
460 *out_format = GST_GL_RGB565;
461 return DRM_FORMAT_RGB565;
463 case GST_VIDEO_FORMAT_RGB:
464 case GST_VIDEO_FORMAT_BGR:
465 *out_format = GST_GL_RGB;
468 case GST_VIDEO_FORMAT_RGBA:
469 case GST_VIDEO_FORMAT_RGBx:
470 case GST_VIDEO_FORMAT_BGRA:
471 case GST_VIDEO_FORMAT_BGRx:
472 case GST_VIDEO_FORMAT_ARGB:
473 case GST_VIDEO_FORMAT_xRGB:
474 case GST_VIDEO_FORMAT_ABGR:
475 case GST_VIDEO_FORMAT_xBGR:
476 case GST_VIDEO_FORMAT_AYUV:
477 *out_format = GST_GL_RGBA;
480 case GST_VIDEO_FORMAT_GRAY8:
481 *out_format = GST_GL_RED;
482 return DRM_FORMAT_R8;
484 case GST_VIDEO_FORMAT_YUY2:
485 case GST_VIDEO_FORMAT_UYVY:
486 case GST_VIDEO_FORMAT_GRAY16_LE:
487 case GST_VIDEO_FORMAT_GRAY16_BE:
488 *out_format = GST_GL_RG;
491 case GST_VIDEO_FORMAT_NV12:
492 case GST_VIDEO_FORMAT_NV21:
493 *out_format = plane == 0 ? GST_GL_RED : GST_GL_RG;
494 return plane == 0 ? DRM_FORMAT_R8 : rg_fourcc;
496 case GST_VIDEO_FORMAT_I420:
497 case GST_VIDEO_FORMAT_YV12:
498 case GST_VIDEO_FORMAT_Y41B:
499 case GST_VIDEO_FORMAT_Y42B:
500 case GST_VIDEO_FORMAT_Y444:
501 *out_format = GST_GL_RED;
502 return DRM_FORMAT_R8;
505 GST_ERROR ("Unsupported format for DMABuf.");
511 * gst_egl_image_from_dmabuf:
512 * @context: a #GstGLContext (must be an EGL context)
513 * @dmabuf: the DMA-Buf file descriptor
514 * @in_info: the #GstVideoInfo in @dmabuf
515 * @plane: the plane in @in_info to create and #GstEGLImage for
516 * @offset: the byte-offset in the data
518 * Creates an EGL image that imports the dmabuf FD. The dmabuf data
519 * is passed as RGBA data. Shaders later take this "RGBA" data and
520 * convert it from its true format (described by in_info) to actual
521 * RGBA output. For example, with I420, three EGL images are created,
522 * one for each plane, each EGL image with a single-channel R format.
523 * With NV12, two EGL images are created, one with R format, one
524 * with RG format etc.
526 * Returns: a #GstEGLImage wrapping @dmabuf or %NULL on failure
529 gst_egl_image_from_dmabuf (GstGLContext * context,
530 gint dmabuf, GstVideoInfo * in_info, gint plane, gsize offset)
532 GstGLFormat format = 0;
533 guintptr attribs[13];
539 fourcc = _drm_rgba_fourcc_from_info (in_info, plane, &format);
540 GST_DEBUG ("fourcc %.4s (%d) plane %d (%dx%d)",
541 (char *) &fourcc, fourcc, plane,
542 GST_VIDEO_INFO_COMP_WIDTH (in_info, plane),
543 GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane));
545 attribs[atti++] = EGL_WIDTH;
546 attribs[atti++] = GST_VIDEO_INFO_COMP_WIDTH (in_info, plane);
547 attribs[atti++] = EGL_HEIGHT;
548 attribs[atti++] = GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane);
549 attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
550 attribs[atti++] = fourcc;
551 attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
552 attribs[atti++] = dmabuf;
553 attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
554 attribs[atti++] = offset;
555 attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
556 attribs[atti++] = GST_VIDEO_INFO_PLANE_STRIDE (in_info, plane);
557 attribs[atti] = EGL_NONE;
558 g_assert (atti == G_N_ELEMENTS (attribs) - 1);
560 for (i = 0; i < atti; i++)
561 GST_LOG ("attr %i: %" G_GINTPTR_FORMAT, i, attribs[i]);
563 img = _gst_egl_image_create (context, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
565 GST_WARNING ("eglCreateImage failed: %s",
566 gst_egl_get_error_string (eglGetError ()));
570 return gst_egl_image_new_wrapped (context, img, format, NULL,
571 (GstEGLImageDestroyNotify) _destroy_egl_image);
575 * Variant of _drm_rgba_fourcc_from_info() that is used in case the GPU can
576 * handle YUV formats directly (by using internal shaders, or hardwired
577 * YUV->RGB conversion matrices etc.)
580 _drm_direct_fourcc_from_info (GstVideoInfo * info)
582 GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
584 GST_DEBUG ("Getting DRM fourcc for %s", gst_video_format_to_string (format));
587 case GST_VIDEO_FORMAT_YUY2:
588 return DRM_FORMAT_YUYV;
590 case GST_VIDEO_FORMAT_YVYU:
591 return DRM_FORMAT_YVYU;
593 case GST_VIDEO_FORMAT_UYVY:
594 return DRM_FORMAT_UYVY;
596 case GST_VIDEO_FORMAT_VYUY:
597 return DRM_FORMAT_VYUY;
599 case GST_VIDEO_FORMAT_AYUV:
600 return DRM_FORMAT_AYUV;
602 case GST_VIDEO_FORMAT_NV12:
603 return DRM_FORMAT_NV12;
605 case GST_VIDEO_FORMAT_NV21:
606 return DRM_FORMAT_NV21;
608 case GST_VIDEO_FORMAT_NV16:
609 return DRM_FORMAT_NV16;
611 case GST_VIDEO_FORMAT_NV61:
612 return DRM_FORMAT_NV61;
614 case GST_VIDEO_FORMAT_NV24:
615 return DRM_FORMAT_NV24;
617 case GST_VIDEO_FORMAT_YUV9:
618 return DRM_FORMAT_YUV410;
620 case GST_VIDEO_FORMAT_YVU9:
621 return DRM_FORMAT_YVU410;
623 case GST_VIDEO_FORMAT_Y41B:
624 return DRM_FORMAT_YUV411;
626 case GST_VIDEO_FORMAT_I420:
627 return DRM_FORMAT_YUV420;
629 case GST_VIDEO_FORMAT_YV12:
630 return DRM_FORMAT_YVU420;
632 case GST_VIDEO_FORMAT_Y42B:
633 return DRM_FORMAT_YUV422;
635 case GST_VIDEO_FORMAT_Y444:
636 return DRM_FORMAT_YUV444;
638 case GST_VIDEO_FORMAT_RGB16:
639 return DRM_FORMAT_RGB565;
641 case GST_VIDEO_FORMAT_BGR16:
642 return DRM_FORMAT_BGR565;
644 case GST_VIDEO_FORMAT_RGBA:
645 return DRM_FORMAT_ABGR8888;
647 case GST_VIDEO_FORMAT_RGBx:
648 return DRM_FORMAT_XBGR8888;
650 case GST_VIDEO_FORMAT_BGRA:
651 return DRM_FORMAT_ARGB8888;
653 case GST_VIDEO_FORMAT_BGRx:
654 return DRM_FORMAT_XRGB8888;
656 case GST_VIDEO_FORMAT_ARGB:
657 return DRM_FORMAT_BGRA8888;
659 case GST_VIDEO_FORMAT_xRGB:
660 return DRM_FORMAT_BGRX8888;
662 case GST_VIDEO_FORMAT_ABGR:
663 return DRM_FORMAT_RGBA8888;
665 case GST_VIDEO_FORMAT_xBGR:
666 return DRM_FORMAT_RGBX8888;
669 GST_INFO ("Unsupported format for direct DMABuf.");
675 _gst_egl_image_check_dmabuf_direct (GstGLContext * context, int fourcc)
677 EGLDisplay egl_display = EGL_DEFAULT_DISPLAY;
678 GstGLDisplayEGL *display_egl;
681 EGLuint64KHR *modifiers;
682 EGLBoolean *external_only;
687 EGLBoolean (*gst_eglQueryDmaBufFormatsEXT) (EGLDisplay dpy,
688 EGLint max_formats, EGLint * formats, EGLint * num_formats);
689 EGLBoolean (*gst_eglQueryDmaBufModifiersEXT) (EGLDisplay dpy,
690 int format, int max_modifiers, EGLuint64KHR * modifiers,
691 EGLBoolean * external_only, int *num_modifiers);
693 gst_eglQueryDmaBufFormatsEXT =
694 gst_gl_context_get_proc_address (context, "eglQueryDmaBufFormatsEXT");
695 gst_eglQueryDmaBufModifiersEXT =
696 gst_gl_context_get_proc_address (context, "eglQueryDmaBufModifiersEXT");
698 if (!gst_eglQueryDmaBufFormatsEXT || !gst_eglQueryDmaBufModifiersEXT)
701 display_egl = gst_gl_display_egl_from_gl_display (context->display);
703 GST_WARNING_OBJECT (context,
704 "Failed to retrieve GstGLDisplayEGL from %" GST_PTR_FORMAT,
709 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (display_egl));
710 gst_object_unref (display_egl);
712 ret = gst_eglQueryDmaBufFormatsEXT (egl_display, 0, NULL, &num_formats);
713 if (!ret || num_formats == 0)
716 formats = g_new (EGLint, num_formats);
718 ret = gst_eglQueryDmaBufFormatsEXT (egl_display, num_formats, formats,
720 if (!ret || num_formats == 0) {
725 for (i = 0; i < num_formats; i++) {
726 if (formats[i] == fourcc)
730 if (i == num_formats) {
731 GST_DEBUG ("driver does not support importing fourcc %" GST_FOURCC_FORMAT,
732 GST_FOURCC_ARGS (fourcc));
736 ret = gst_eglQueryDmaBufModifiersEXT (egl_display, fourcc, 0, NULL, NULL,
738 if (!ret || num_modifiers == 0) {
739 GST_DEBUG ("driver does not report modifiers for fourcc %"
740 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
744 modifiers = g_new (EGLuint64KHR, num_modifiers);
745 external_only = g_new (EGLBoolean, num_modifiers);
747 ret = gst_eglQueryDmaBufModifiersEXT (egl_display, fourcc, num_modifiers,
748 modifiers, external_only, &num_modifiers);
749 if (!ret || num_modifiers == 0) {
751 g_free (external_only);
755 for (i = 0; i < num_modifiers; ++i) {
756 if (modifiers[i] == DRM_FORMAT_MOD_LINEAR) {
757 if (external_only[i]) {
758 GST_DEBUG ("driver only supports external import of fourcc %"
759 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
761 ret = !external_only[i];
763 g_free (external_only);
767 GST_DEBUG ("driver only supports non-linear import of fourcc %"
768 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
770 g_free (external_only);
775 * gst_egl_image_from_dmabuf_direct:
776 * @context: a #GstGLContext (must be an EGL context)
777 * @fd: Array of DMABuf file descriptors
778 * @offset: Array of offsets, relative to the DMABuf
779 * @in_info: the #GstVideoInfo
781 * Creates an EGL image that imports the dmabuf FD. The dmabuf data
782 * is passed directly as the format described in in_info. This is
783 * useful if the hardware is capable of performing color space conversions
784 * internally. The appropriate DRM format is picked, and the EGL image
785 * is created with this DRM format.
787 * Another notable difference to gst_egl_image_from_dmabuf()
788 * is that this function creates one EGL image for all planes, not one for
791 * Returns: a #GstEGLImage wrapping @dmabuf or %NULL on failure
794 gst_egl_image_from_dmabuf_direct (GstGLContext * context,
795 gint * fd, gsize * offset, GstVideoInfo * in_info)
799 guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info);
802 gboolean with_modifiers;
804 /* Explanation of array length:
805 * - 6 plane independent values are at the start (width, height, format FourCC)
806 * - 10 values per plane, and there are up to MAX_NUM_DMA_BUF_PLANES planes
807 * - 4 values for color space and range
808 * - 1 extra value for the EGL_NONE sentinel
810 guintptr attribs[41]; /* 6 + 10 * 3 + 4 + 1 */
813 fourcc = _drm_direct_fourcc_from_info (in_info);
817 if (!_gst_egl_image_check_dmabuf_direct (context, fourcc))
820 with_modifiers = gst_gl_context_check_feature (context,
821 "EGL_EXT_image_dma_buf_import_with_modifiers");
823 /* EGL DMABuf importation supports a maximum of 3 planes */
824 if (G_UNLIKELY (n_planes > 3))
827 attribs[atti++] = EGL_WIDTH;
828 attribs[atti++] = GST_VIDEO_INFO_WIDTH (in_info);
829 attribs[atti++] = EGL_HEIGHT;
830 attribs[atti++] = GST_VIDEO_INFO_HEIGHT (in_info);
831 attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
832 attribs[atti++] = fourcc;
836 attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
837 attribs[atti++] = fd[0];
838 attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
839 attribs[atti++] = offset[0];
840 attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
841 attribs[atti++] = in_info->stride[0];
842 if (with_modifiers) {
843 attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
844 attribs[atti++] = DRM_FORMAT_MOD_LINEAR & 0xffffffff;
845 attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
846 attribs[atti++] = (DRM_FORMAT_MOD_LINEAR >> 32) & 0xffffffff;
852 attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
853 attribs[atti++] = fd[1];
854 attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
855 attribs[atti++] = offset[1];
856 attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
857 attribs[atti++] = in_info->stride[1];
858 if (with_modifiers) {
859 attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
860 attribs[atti++] = DRM_FORMAT_MOD_LINEAR & 0xffffffff;
861 attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
862 attribs[atti++] = (DRM_FORMAT_MOD_LINEAR >> 32) & 0xffffffff;
868 attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
869 attribs[atti++] = fd[2];
870 attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
871 attribs[atti++] = offset[2];
872 attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
873 attribs[atti++] = in_info->stride[2];
874 if (with_modifiers) {
875 attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
876 attribs[atti++] = DRM_FORMAT_MOD_LINEAR & 0xffffffff;
877 attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
878 attribs[atti++] = (DRM_FORMAT_MOD_LINEAR >> 32) & 0xffffffff;
883 uint32_t color_space;
884 switch (in_info->colorimetry.matrix) {
885 case GST_VIDEO_COLOR_MATRIX_BT601:
886 color_space = EGL_ITU_REC601_EXT;
888 case GST_VIDEO_COLOR_MATRIX_BT709:
889 color_space = EGL_ITU_REC709_EXT;
891 case GST_VIDEO_COLOR_MATRIX_BT2020:
892 color_space = EGL_ITU_REC2020_EXT;
898 if (color_space != 0) {
899 attribs[atti++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
900 attribs[atti++] = color_space;
906 switch (in_info->colorimetry.range) {
907 case GST_VIDEO_COLOR_RANGE_0_255:
908 range = EGL_YUV_FULL_RANGE_EXT;
910 case GST_VIDEO_COLOR_RANGE_16_235:
911 range = EGL_YUV_NARROW_RANGE_EXT;
918 attribs[atti++] = EGL_SAMPLE_RANGE_HINT_EXT;
919 attribs[atti++] = range;
923 /* Add the EGL_NONE sentinel */
924 attribs[atti] = EGL_NONE;
925 g_assert (atti <= G_N_ELEMENTS (attribs) - 1);
927 for (i = 0; i < atti; i++)
928 GST_LOG ("attr %i: %" G_GINTPTR_FORMAT, i, attribs[i]);
930 img = _gst_egl_image_create (context, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
932 GST_WARNING ("eglCreateImage failed: %s",
933 gst_egl_get_error_string (eglGetError ()));
937 return gst_egl_image_new_wrapped (context, img, GST_GL_RGBA, NULL,
938 (GstEGLImageDestroyNotify) _destroy_egl_image);
942 gst_egl_image_export_dmabuf (GstEGLImage * image, int *fd, gint * stride,
945 EGLBoolean (*gst_eglExportDMABUFImageQueryMESA) (EGLDisplay dpy,
946 EGLImageKHR image, int *fourcc, int *num_planes,
947 EGLuint64KHR * modifiers);
948 EGLBoolean (*gst_eglExportDMABUFImageMESA) (EGLDisplay dpy, EGLImageKHR image,
949 int *fds, EGLint * strides, EGLint * offsets);
950 GstGLDisplayEGL *display_egl;
951 EGLDisplay egl_display = EGL_DEFAULT_DISPLAY;
954 EGLint egl_stride = 0;
955 EGLint egl_offset = 0;
957 gst_eglExportDMABUFImageQueryMESA =
958 gst_gl_context_get_proc_address (image->context,
959 "eglExportDMABUFImageQueryMESA");
960 gst_eglExportDMABUFImageMESA =
961 gst_gl_context_get_proc_address (image->context,
962 "eglExportDMABUFImageMESA");
964 if (!gst_eglExportDMABUFImageQueryMESA || !gst_eglExportDMABUFImageMESA)
968 (GstGLDisplayEGL *) gst_gl_display_egl_from_gl_display (image->
971 GST_WARNING_OBJECT (image->context,
972 "Failed to retrieve GstGLDisplayEGL from %" GST_PTR_FORMAT,
973 image->context->display);
977 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (display_egl));
978 gst_object_unref (display_egl);
980 if (!gst_eglExportDMABUFImageQueryMESA (egl_display, image->image,
981 NULL, &num_planes, NULL))
984 /* Don't allow multi-plane dmabufs */
988 if (!gst_eglExportDMABUFImageMESA (egl_display, image->image, &egl_fd,
989 &egl_stride, &egl_offset))
993 *stride = egl_stride;
994 *offset = egl_offset;
999 #endif /* GST_GL_HAVE_DMABUF */