2 * gstvaapisurface_egl.c - VA surface abstraction (EGL interop)
4 * Copyright (C) 2014 Intel Corporation
5 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
25 #include "gstvaapisurface_egl.h"
27 #include "gstvaapibufferproxy_priv.h"
28 #include "gstvaapicompat.h"
29 #include "gstvaapidisplay_egl_priv.h"
30 #include "gstvaapifilter.h"
31 #include "gstvaapiimage_priv.h"
32 #include "gstvaapisurface_drm.h"
33 #include "gstvaapisurface_priv.h"
36 #include <drm_fourcc.h>
38 #define DRM_FORMAT_MOD_LINEAR 0ULL
39 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
44 GstVaapiDisplayEGL *display;
46 GstVideoFormat format;
50 GstVaapiSurface *surface; /* result */
51 } CreateSurfaceWithEGLImageArgs;
53 static GstVaapiSurface *
54 do_create_surface_with_egl_image_unlocked (GstVaapiDisplayEGL * display,
55 EGLImageKHR image, GstVideoFormat format, guint width, guint height,
58 GstVaapiDisplay *const base_display = GST_VAAPI_DISPLAY_CAST (display);
59 EglContext *const ctx = GST_VAAPI_DISPLAY_EGL_CONTEXT (display);
62 if (!ctx || !(vtable = egl_context_get_vtable (ctx, FALSE)))
65 if ((mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM)
66 && vtable->has_EGL_MESA_drm_image) {
67 gsize size, offset[GST_VIDEO_MAX_PLANES] = { 0, };
68 gint name, stride[GST_VIDEO_MAX_PLANES] = { 0, };
70 /* EGL_MESA_drm_image extension */
71 if (!vtable->eglExportDRMImageMESA (ctx->display->base.handle.p, image,
72 &name, NULL, &stride[0]))
73 goto error_export_image_gem_buf;
75 size = height * stride[0];
77 * XXX: The below surface creation may fail on Intel due to:
78 * https://github.com/01org/intel-vaapi-driver/issues/222
79 * A permanent fix for that problem will be released in intel-vaapi-driver
80 * version 1.8.4 and later, and also in 1.8.3-1ubuntu1.
81 * However if you don't have that fix then a simple workaround is to
82 * uncomment this line of code:
83 * size = GST_ROUND_UP_32 (height) * stride[0];
86 return gst_vaapi_surface_new_with_gem_buf_handle (base_display, name, size,
87 format, width, height, offset, stride);
90 if ((mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME)
91 && vtable->has_EGL_MESA_image_dma_buf_export) {
92 int fourcc, num_planes, fd;
95 EGLuint64KHR modifier;
98 if (!vtable->eglExportDMABUFImageQueryMESA (ctx->display->base.handle.p,
99 image, &fourcc, &num_planes, &modifier))
100 goto error_export_dma_buf_image_query;
102 /* Don't allow multi-plane dmabufs */
104 goto error_bad_parameters;
106 /* FIXME: We don't support modifiers */
107 if (modifier != DRM_FORMAT_MOD_LINEAR && modifier != DRM_FORMAT_MOD_INVALID)
108 goto error_bad_parameters;
110 /* fix color format if needed */
111 if (fourcc == GST_MAKE_FOURCC ('A', 'B', '2', '4'))
112 format = gst_vaapi_video_format_from_va_fourcc (VA_FOURCC_RGBA);
113 else if (fourcc == GST_MAKE_FOURCC ('A', 'R', '2', '4'))
114 format = gst_vaapi_video_format_from_va_fourcc (VA_FOURCC_BGRA);
116 if (!vtable->eglExportDMABUFImageMESA (ctx->display->base.handle.p, image,
117 &fd, &stride, &offset))
118 goto error_export_dma_buf_image;
120 gst_video_info_set_format (&vi, format, width, height);
121 GST_VIDEO_INFO_PLANE_OFFSET (&vi, 0) = offset;
122 GST_VIDEO_INFO_PLANE_STRIDE (&vi, 0) = stride;
124 return gst_vaapi_surface_new_with_dma_buf_handle (base_display, fd, &vi);
126 #ifndef GST_DISABLE_GST_DEBUG
128 GString *str = g_string_new (NULL);
130 if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_VA)
131 g_string_append (str, "VA ");
132 if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_V4L2)
133 g_string_append (str, "V4L2 ");
134 if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR)
135 g_string_append (str, "PTR ");
136 #if VA_CHECK_VERSION(1,1,0)
137 if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)
138 g_string_append (str, "PRIME_2 ");
141 GST_ERROR ("missing EGL extensions for memory types: %s", str->str);
142 g_string_free (str, TRUE);
149 error_export_image_gem_buf:
151 GST_ERROR ("failed to export EGL image to GEM buffer");
154 error_export_dma_buf_image_query:
156 GST_ERROR ("failed to query EGL image for dmabuf export");
159 error_bad_parameters:
161 GST_ERROR ("multi-planed nor non-linear dmabufs are not supported");
164 error_export_dma_buf_image:
166 GST_ERROR ("missing EGL_MESA_image_dma_buf_export extension");
172 do_create_surface_with_egl_image (CreateSurfaceWithEGLImageArgs * args)
174 GST_VAAPI_DISPLAY_LOCK (args->display);
175 args->surface = do_create_surface_with_egl_image_unlocked (args->display,
176 args->image, args->format, args->width, args->height, args->mem_types);
177 GST_VAAPI_DISPLAY_UNLOCK (args->display);
180 // Creates VA surface with EGLImage buffer as backing storage (internal)
181 static inline GstVaapiSurface *
182 create_surface_with_egl_image (GstVaapiDisplayEGL * display, EGLImageKHR image,
183 GstVideoFormat format, guint width, guint height, guint mem_types)
185 CreateSurfaceWithEGLImageArgs args =
186 { display, image, format, width, height, mem_types };
188 if (!egl_context_run (GST_VAAPI_DISPLAY_EGL_CONTEXT (display),
189 (EglContextRunFunc) do_create_surface_with_egl_image, &args))
194 // Creates VA surface from an EGLImage buffer copy (internal)
195 static GstVaapiSurface *
196 create_surface_from_egl_image (GstVaapiDisplayEGL * display,
197 const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format,
198 guint width, guint height, guint flags)
200 GstVaapiDisplay *const base_display = GST_VAAPI_DISPLAY_CAST (display);
201 GstVaapiSurface *img_surface = NULL, *out_surface = NULL;
202 gboolean use_native_format = TRUE;
203 GstVaapiFilter *filter = NULL;
204 GstVaapiFilterStatus filter_status;
206 img_surface = create_surface_with_egl_image (display, image, format,
213 GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_ENCODED ||
214 GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_UNKNOWN;
216 if (GST_VIDEO_INFO_WIDTH (vip) && GST_VIDEO_INFO_HEIGHT (vip)) {
217 width = GST_VIDEO_INFO_WIDTH (vip);
218 height = GST_VIDEO_INFO_HEIGHT (vip);
222 if (use_native_format) {
223 out_surface = gst_vaapi_surface_new (base_display,
224 GST_VAAPI_CHROMA_TYPE_YUV420, width, height);
226 out_surface = gst_vaapi_surface_new_with_format (base_display,
227 GST_VIDEO_INFO_FORMAT (vip), width, height, 0);
230 goto error_create_surface;
232 filter = gst_vaapi_filter_new (base_display);
234 goto error_create_filter;
236 filter_status = gst_vaapi_filter_process (filter,
237 img_surface, out_surface, flags);
238 if (filter_status != GST_VAAPI_FILTER_STATUS_SUCCESS)
239 goto error_convert_surface;
241 gst_vaapi_surface_unref (img_surface);
242 gst_object_unref (filter);
246 error_create_surface:
247 GST_ERROR ("failed to create output surface format:%s size:%dx%d",
248 gst_vaapi_video_format_to_string (vip ? GST_VIDEO_INFO_FORMAT (vip) :
249 GST_VIDEO_FORMAT_ENCODED), width, height);
251 error_convert_surface:
252 GST_ERROR ("failed to transfer EGL image to VA surface (status = %d)",
256 GST_ERROR ("failed to create video processing filter");
259 gst_mini_object_replace ((GstMiniObject **) & img_surface, NULL);
260 gst_mini_object_replace ((GstMiniObject **) & out_surface, NULL);
261 gst_vaapi_filter_replace (&filter, NULL);
266 * gst_vaapi_surface_new_from_egl_image:
267 * @display: a #GstVaapiDisplay
268 * @vip: the desired (optional) #GstVideoInfo constraints
269 * @image: the EGL image to import
270 * @format: the EGL @image format
271 * @width: the EGL @image width in pixels
272 * @height: the EGL @image height in pixels
273 * @flags: postprocessing flags. See #GstVaapiSurfaceRenderFlags
275 * Creates a new #GstVaapiSurface with a copy of the EGL image
276 * contents. i.e. the input EGL @image can be disposed and the
277 * resulting VA surface would still be valid with the contents at the
278 * time this function was called.
280 * If @vip is %NULL, then the resulting VA surface will be created
281 * with the same video format and size as the original @image. If @vip
282 * is non-%NULL and the desired format is GST_VIDEO_FORMAT_ENCODED,
283 * then the resulting VA surface will have the best "native" HW
284 * format, usually NV12.
286 * Return value: the newly allocated #GstVaapiSurface object, or %NULL
287 * if creation from EGL image failed, or is not supported
290 gst_vaapi_surface_new_from_egl_image (GstVaapiDisplay * base_display,
291 const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format,
292 guint width, guint height, guint flags)
294 GstVaapiDisplayEGL *display;
296 g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (base_display), NULL);
297 g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
298 g_return_val_if_fail (width > 0, NULL);
299 g_return_val_if_fail (height > 0, NULL);
301 display = GST_VAAPI_DISPLAY_EGL (base_display);
302 if (!display || !GST_VAAPI_IS_DISPLAY_EGL (display))
303 goto error_invalid_display;
304 return create_surface_from_egl_image (display, vip, image, format,
305 width, height, flags);
308 error_invalid_display:
309 GST_ERROR ("invalid display (NULL or not of EGL class");
314 * gst_vaapi_surface_new_with_egl_image:
315 * @display: a #GstVaapiDisplay
316 * @image: the EGL image to import
317 * @format: the EGL @image format
318 * @width: the EGL @image width in pixels
319 * @height: the EGL @image height in pixels
320 * @mem_types: the supported memory types
322 * Creates a new #GstVaapiSurface bound to an external EGL image.
324 * The caller maintains the lifetime of the EGL image object. In
325 * particular, the EGL image shall not be destroyed before the last
326 * reference to the resulting VA surface is released.
328 * Return value: the newly allocated #GstVaapiSurface object, or %NULL
329 * if creation from EGL image failed, or is not supported
332 gst_vaapi_surface_new_with_egl_image (GstVaapiDisplay * base_display,
333 EGLImageKHR image, GstVideoFormat format, guint width, guint height,
336 GstVaapiDisplayEGL *display;
338 g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (base_display), NULL);
339 g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
340 g_return_val_if_fail (width > 0, NULL);
341 g_return_val_if_fail (height > 0, NULL);
343 display = GST_VAAPI_DISPLAY_EGL (base_display);
344 if (!display || !GST_VAAPI_IS_DISPLAY_EGL (display))
345 goto error_invalid_display;
346 return create_surface_with_egl_image (display, image, format, width, height,
350 error_invalid_display:
351 GST_ERROR ("invalid display (NULL or not of EGL class");