Merge branch 'move_subdir_editing-services' into tizen_gst_1.19.2_mono
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst-libs / gst / vaapi / gstvaapisurface_egl.c
1 /*
2  *  gstvaapisurface_egl.c - VA surface abstraction (EGL interop)
3  *
4  *  Copyright (C) 2014 Intel Corporation
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
6  *
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.
11  *
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.
16  *
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
21  */
22
23 #include "sysdeps.h"
24
25 #include "gstvaapisurface_egl.h"
26
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"
34
35 #if USE_DRM
36 #include <drm_fourcc.h>
37 #else
38 #define DRM_FORMAT_MOD_LINEAR 0ULL
39 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
40 #endif
41
42 typedef struct
43 {
44   GstVaapiDisplayEGL *display;
45   EGLImageKHR image;
46   GstVideoFormat format;
47   guint width;
48   guint height;
49   guint mem_types;
50   GstVaapiSurface *surface;     /* result */
51 } CreateSurfaceWithEGLImageArgs;
52
53 static GstVaapiSurface *
54 do_create_surface_with_egl_image_unlocked (GstVaapiDisplayEGL * display,
55     EGLImageKHR image, GstVideoFormat format, guint width, guint height,
56     guint mem_types)
57 {
58   GstVaapiDisplay *const base_display = GST_VAAPI_DISPLAY_CAST (display);
59   EglContext *const ctx = GST_VAAPI_DISPLAY_EGL_CONTEXT (display);
60   EglVTable *vtable;
61
62   if (!ctx || !(vtable = egl_context_get_vtable (ctx, FALSE)))
63     return NULL;
64
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, };
69
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;
74
75     size = height * stride[0];
76     /*
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];
84      */
85
86     return gst_vaapi_surface_new_with_gem_buf_handle (base_display, name, size,
87         format, width, height, offset, stride);
88   }
89
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;
93     EGLint offset = 0;
94     EGLint stride = 0;
95     EGLuint64KHR modifier;
96     GstVideoInfo vi;
97
98     if (!vtable->eglExportDMABUFImageQueryMESA (ctx->display->base.handle.p,
99             image, &fourcc, &num_planes, &modifier))
100       goto error_export_dma_buf_image_query;
101
102     /* Don't allow multi-plane dmabufs */
103     if (num_planes != 1)
104       goto error_bad_parameters;
105
106     /* FIXME: We don't support modifiers */
107     if (modifier != DRM_FORMAT_MOD_LINEAR && modifier != DRM_FORMAT_MOD_INVALID)
108       goto error_bad_parameters;
109
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);
115
116     if (!vtable->eglExportDMABUFImageMESA (ctx->display->base.handle.p, image,
117             &fd, &stride, &offset))
118       goto error_export_dma_buf_image;
119
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;
123
124     return gst_vaapi_surface_new_with_dma_buf_handle (base_display, fd, &vi);
125   }
126 #ifndef GST_DISABLE_GST_DEBUG
127   {
128     GString *str = g_string_new (NULL);
129
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 ");
139 #endif
140
141     GST_ERROR ("missing EGL extensions for memory types: %s", str->str);
142     g_string_free (str, TRUE);
143   }
144 #endif
145
146   return NULL;
147
148   /* ERRORS */
149 error_export_image_gem_buf:
150   {
151     GST_ERROR ("failed to export EGL image to GEM buffer");
152     return NULL;
153   }
154 error_export_dma_buf_image_query:
155   {
156     GST_ERROR ("failed to query EGL image for dmabuf export");
157     return NULL;
158   }
159 error_bad_parameters:
160   {
161     GST_ERROR ("multi-planed nor non-linear dmabufs are not supported");
162     return NULL;
163   }
164 error_export_dma_buf_image:
165   {
166     GST_ERROR ("missing EGL_MESA_image_dma_buf_export extension");
167     return NULL;
168   }
169 }
170
171 static void
172 do_create_surface_with_egl_image (CreateSurfaceWithEGLImageArgs * args)
173 {
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);
178 }
179
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)
184 {
185   CreateSurfaceWithEGLImageArgs args =
186       { display, image, format, width, height, mem_types };
187
188   if (!egl_context_run (GST_VAAPI_DISPLAY_EGL_CONTEXT (display),
189           (EglContextRunFunc) do_create_surface_with_egl_image, &args))
190     return NULL;
191   return args.surface;
192 }
193
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)
199 {
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;
205
206   img_surface = create_surface_with_egl_image (display, image, format,
207       width, height, 0);
208   if (!img_surface)
209     return NULL;
210
211   if (vip) {
212     use_native_format =
213         GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_ENCODED ||
214         GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_UNKNOWN;
215
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);
219     }
220   }
221
222   if (use_native_format) {
223     out_surface = gst_vaapi_surface_new (base_display,
224         GST_VAAPI_CHROMA_TYPE_YUV420, width, height);
225   } else {
226     out_surface = gst_vaapi_surface_new_with_format (base_display,
227         GST_VIDEO_INFO_FORMAT (vip), width, height, 0);
228   }
229   if (!out_surface)
230     goto error_create_surface;
231
232   filter = gst_vaapi_filter_new (base_display);
233   if (!filter)
234     goto error_create_filter;
235
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;
240
241   gst_vaapi_surface_unref (img_surface);
242   gst_object_unref (filter);
243   return out_surface;
244
245   /* ERRORS */
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);
250   goto error_cleanup;
251 error_convert_surface:
252   GST_ERROR ("failed to transfer EGL image to VA surface (status = %d)",
253       filter_status);
254   goto error_cleanup;
255 error_create_filter:
256   GST_ERROR ("failed to create video processing filter");
257   // fall-through
258 error_cleanup:
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);
262   return NULL;
263 }
264
265 /**
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
274  *
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.
279  *
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.
285  *
286  * Return value: the newly allocated #GstVaapiSurface object, or %NULL
287  *   if creation from EGL image failed, or is not supported
288  */
289 GstVaapiSurface *
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)
293 {
294   GstVaapiDisplayEGL *display;
295
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);
300
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);
306
307   /* ERRORS */
308 error_invalid_display:
309   GST_ERROR ("invalid display (NULL or not of EGL class");
310   return NULL;
311 }
312
313 /**
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
321  *
322  * Creates a new #GstVaapiSurface bound to an external EGL image.
323  *
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.
327  *
328  * Return value: the newly allocated #GstVaapiSurface object, or %NULL
329  *   if creation from EGL image failed, or is not supported
330  */
331 GstVaapiSurface *
332 gst_vaapi_surface_new_with_egl_image (GstVaapiDisplay * base_display,
333     EGLImageKHR image, GstVideoFormat format, guint width, guint height,
334     guint mem_types)
335 {
336   GstVaapiDisplayEGL *display;
337
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);
342
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,
347       mem_types);
348
349   /* ERRORS */
350 error_invalid_display:
351   GST_ERROR ("invalid display (NULL or not of EGL class");
352   return NULL;
353 }