2 * gstvaapipluginutil.h - VA-API plugin helpers
4 * Copyright (C) 2011-2014 Intel Corporation
5 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
6 * Copyright (C) 2011 Collabora
7 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
25 #include "gstcompat.h"
26 #include "gstvaapivideocontext.h"
28 # include <gst/vaapi/gstvaapidisplay_drm.h>
31 # include <gst/vaapi/gstvaapidisplay_x11.h>
34 # include <gst/vaapi/gstvaapidisplay_glx.h>
37 # include <gst/vaapi/gstvaapidisplay_egl.h>
40 # include <gst/vaapi/gstvaapidisplay_wayland.h>
42 #include "gstvaapipluginutil.h"
43 #include "gstvaapipluginbase.h"
45 typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFunc) (const gchar *);
46 typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFromHandleFunc) (gpointer);
50 const gchar *type_str;
51 GstVaapiDisplayType type;
52 GstVaapiDisplayCreateFunc create_display;
53 GstVaapiDisplayCreateFromHandleFunc create_display_from_handle;
57 static const DisplayMap g_display_map[] = {
60 GST_VAAPI_DISPLAY_TYPE_WAYLAND,
61 gst_vaapi_display_wayland_new,
62 (GstVaapiDisplayCreateFromHandleFunc)
63 gst_vaapi_display_wayland_new_with_display},
67 GST_VAAPI_DISPLAY_TYPE_GLX,
68 gst_vaapi_display_glx_new,
69 (GstVaapiDisplayCreateFromHandleFunc)
70 gst_vaapi_display_glx_new_with_display},
74 GST_VAAPI_DISPLAY_TYPE_X11,
75 gst_vaapi_display_x11_new,
76 (GstVaapiDisplayCreateFromHandleFunc)
77 gst_vaapi_display_x11_new_with_display},
81 GST_VAAPI_DISPLAY_TYPE_DRM,
82 gst_vaapi_display_drm_new},
88 static GstVaapiDisplay *
89 gst_vaapi_create_display (GstVaapiDisplayType display_type,
90 const gchar * display_name)
92 GstVaapiDisplay *display = NULL;
95 for (m = g_display_map; m->type_str != NULL; m++) {
96 if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY && display_type != m->type)
99 display = m->create_display (display_name);
100 if (display || display_type != GST_VAAPI_DISPLAY_TYPE_ANY)
106 static GstVaapiDisplay *
107 gst_vaapi_create_display_from_handle (GstVaapiDisplayType display_type,
110 GstVaapiDisplay *display;
113 if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY)
116 for (m = g_display_map; m->type_str != NULL; m++) {
117 if (m->type == display_type) {
118 display = m->create_display_from_handle ?
119 m->create_display_from_handle (handle) : NULL;
126 static GstVaapiDisplay *
127 gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object)
129 #if USE_GST_GL_HELPERS
130 GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object);
131 GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context);
132 gpointer native_display =
133 GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display));
134 GstVaapiDisplay *display, *out_display;
135 GstVaapiDisplayType display_type;
137 switch (gst_gl_display_get_handle_type (gl_display)) {
139 case GST_GL_DISPLAY_TYPE_X11:
140 display_type = GST_VAAPI_DISPLAY_TYPE_X11;
144 case GST_GL_DISPLAY_TYPE_WAYLAND:
145 display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
148 case GST_GL_DISPLAY_TYPE_ANY:{
149 /* Derive from the active window */
150 GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context);
151 const gchar *const gl_window_type = g_getenv ("GST_GL_WINDOW");
153 display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
156 native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window));
158 if (gl_window_type) {
160 if (!display_type && g_strcmp0 (gl_window_type, "x11") == 0)
161 display_type = GST_VAAPI_DISPLAY_TYPE_X11;
164 if (!display_type && g_strcmp0 (gl_window_type, "wayland") == 0)
165 display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
169 if (!display_type && GST_GL_HAVE_WINDOW_X11)
170 display_type = GST_VAAPI_DISPLAY_TYPE_X11;
173 if (!display_type && GST_GL_HAVE_WINDOW_WAYLAND)
174 display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
180 display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
186 display = gst_vaapi_create_display_from_handle (display_type, native_display);
190 switch (gst_gl_context_get_gl_platform (gl_context)) {
192 case GST_GL_PLATFORM_EGL:{
195 switch (gst_gl_context_get_gl_api (gl_context)) {
196 case GST_GL_API_GLES1:
198 goto create_egl_display;
199 case GST_GL_API_GLES2:
201 goto create_egl_display;
202 case GST_GL_API_OPENGL:
203 case GST_GL_API_OPENGL3:
206 out_display = gst_vaapi_display_egl_new (display, gles_version);
214 gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (out_display),
215 GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context)));
220 out_display = gst_vaapi_display_ref (display);
223 gst_vaapi_display_unref (display);
226 GST_ERROR ("unsupported GStreamer version %s", GST_API_VERSION_S);
231 gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type)
233 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
234 GstVaapiDisplay *display;
236 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
238 gst_vaapi_video_context_prepare (element);
240 /* Neighbour found and it updated the display */
241 if (gst_vaapi_plugin_base_has_display_type (plugin, type))
244 /* If no neighboor, or application not interested, use system default */
245 if (plugin->gl_context)
246 display = gst_vaapi_create_display_from_gl_context (plugin->gl_context);
248 display = gst_vaapi_create_display (type, plugin->display_name);
252 gst_vaapi_video_context_propagate (element, display);
253 GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE (plugin, display);
254 gst_vaapi_display_unref (display);
259 gst_vaapi_reply_to_query (GstQuery * query, GstVaapiDisplay * display)
261 const gchar *type = NULL;
264 if (GST_QUERY_TYPE (query) != GST_QUERY_CONTEXT)
270 if (!gst_query_parse_context_type (query, &type))
273 if (g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME))
276 context = gst_vaapi_video_context_new_with_display (display, FALSE);
277 gst_query_set_context (query, context);
278 gst_context_unref (context);
284 gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps)
286 GstStructure *structure;
287 const GValue *v_width, *v_height, *v_framerate, *v_par;
288 guint i, n_structures;
290 structure = gst_caps_get_structure (in_caps, 0);
291 v_width = gst_structure_get_value (structure, "width");
292 v_height = gst_structure_get_value (structure, "height");
293 v_framerate = gst_structure_get_value (structure, "framerate");
294 v_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
295 if (!v_width || !v_height)
298 n_structures = gst_caps_get_size (out_caps);
299 for (i = 0; i < n_structures; i++) {
300 structure = gst_caps_get_structure (out_caps, i);
301 gst_structure_set_value (structure, "width", v_width);
302 gst_structure_set_value (structure, "height", v_height);
304 gst_structure_set_value (structure, "framerate", v_framerate);
306 gst_structure_set_value (structure, "pixel-aspect-ratio", v_par);
312 gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer)
314 GstVideoOverlayCompositionMeta *const cmeta =
315 gst_buffer_get_video_overlay_composition_meta (buffer);
316 GstVideoOverlayComposition *composition = NULL;
319 composition = cmeta->overlay;
320 return gst_vaapi_surface_set_subpictures_from_composition (surface,
325 gst_vaapi_value_set_format (GValue * value, GstVideoFormat format)
329 str = gst_video_format_to_string (format);
333 g_value_init (value, G_TYPE_STRING);
334 g_value_set_string (value, str);
339 gst_vaapi_value_set_format_list (GValue * value, GArray * formats)
341 GValue v_format = G_VALUE_INIT;
344 g_value_init (value, GST_TYPE_LIST);
345 for (i = 0; i < formats->len; i++) {
346 GstVideoFormat const format = g_array_index (formats, GstVideoFormat, i);
348 if (!gst_vaapi_value_set_format (&v_format, format))
350 gst_value_list_append_value (value, &v_format);
351 g_value_unset (&v_format);
357 set_video_template_caps (GstCaps * caps)
359 GstStructure *const structure = gst_caps_get_structure (caps, 0);
361 gst_structure_set (structure,
362 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
363 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
364 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
365 "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
369 gst_vaapi_video_format_new_template_caps (GstVideoFormat format)
373 g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
375 caps = gst_caps_new_empty_simple ("video/x-raw");
379 gst_caps_set_simple (caps,
380 "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
381 set_video_template_caps (caps);
386 gst_vaapi_video_format_new_template_caps_from_list (GArray * formats)
388 GValue v_formats = G_VALUE_INIT;
391 caps = gst_caps_new_empty_simple ("video/x-raw");
395 if (!gst_vaapi_value_set_format_list (&v_formats, formats)) {
396 gst_caps_unref (caps);
400 gst_caps_set_value (caps, "format", &v_formats);
401 set_video_template_caps (caps);
402 g_value_unset (&v_formats);
407 gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format,
408 const gchar * features_string)
412 caps = gst_vaapi_video_format_new_template_caps (format);
416 GstCapsFeatures *const features =
417 gst_caps_features_new (features_string, NULL);
419 gst_caps_unref (caps);
422 gst_caps_set_features (caps, 0, features);
427 new_gl_texture_upload_meta_caps (void)
430 gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
431 (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
436 gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstVideoFormat format,
437 GstVideoFormat * out_format_ptr)
439 GstVaapiCapsFeature feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
440 guint i, num_structures;
441 GstCaps *caps = NULL;
442 GstCaps *gl_texture_upload_caps = NULL;
443 GstCaps *sysmem_caps = NULL;
444 GstCaps *vaapi_caps = NULL;
445 GstCaps *out_caps, *templ;
446 GstVideoFormat out_format;
448 templ = gst_pad_get_pad_template_caps (pad);
449 out_caps = gst_pad_peer_query_caps (pad, templ);
450 gst_caps_unref (templ);
452 feature = GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED;
456 out_format = format == GST_VIDEO_FORMAT_ENCODED ?
457 GST_VIDEO_FORMAT_I420 : format;
459 gl_texture_upload_caps = new_gl_texture_upload_meta_caps ();
460 if (!gl_texture_upload_caps)
464 gst_vaapi_video_format_new_template_caps_with_features (out_format,
465 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE);
470 gst_vaapi_video_format_new_template_caps_with_features (out_format,
471 GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
475 num_structures = gst_caps_get_size (out_caps);
476 for (i = 0; i < num_structures; i++) {
477 GstCapsFeatures *const features = gst_caps_get_features (out_caps, i);
478 GstStructure *const structure = gst_caps_get_structure (out_caps, i);
480 #if GST_CHECK_VERSION(1,3,0)
481 /* Skip ANY features, we need an exact match for correct evaluation */
482 if (gst_caps_features_is_any (features))
486 caps = gst_caps_new_full (gst_structure_copy (structure), NULL);
489 gst_caps_set_features (caps, 0, gst_caps_features_copy (features));
491 if (gst_caps_can_intersect (caps, vaapi_caps) &&
492 feature < GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
493 feature = GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE;
494 else if (gst_caps_can_intersect (caps, gl_texture_upload_caps) &&
495 feature < GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)
496 feature = GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META;
497 else if (gst_caps_can_intersect (caps, sysmem_caps) &&
498 feature < GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
499 feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
500 gst_caps_replace (&caps, NULL);
502 #if GST_CHECK_VERSION(1,3,0)
503 /* Stop at the first match, the caps should already be sorted out
504 by preference order from downstream elements */
505 if (feature != GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
510 if (out_format_ptr) {
511 if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META) {
512 GstStructure *structure;
514 out_format = GST_VIDEO_FORMAT_UNKNOWN;
516 caps = gst_caps_intersect_full (out_caps, gl_texture_upload_caps,
517 GST_CAPS_INTERSECT_FIRST);
520 structure = gst_caps_get_structure (caps, 0);
523 if (!gst_structure_get (structure, "format", G_TYPE_STRING,
526 out_format = gst_video_format_from_string (format_str);
532 *out_format_ptr = out_format;
536 gst_caps_replace (&gl_texture_upload_caps, NULL);
537 gst_caps_replace (&sysmem_caps, NULL);
538 gst_caps_replace (&vaapi_caps, NULL);
539 gst_caps_replace (&caps, NULL);
540 gst_caps_replace (&out_caps, NULL);
545 gst_vaapi_caps_feature_to_string (GstVaapiCapsFeature feature)
550 case GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY:
551 str = GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY;
553 case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
554 str = GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META;
556 case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:
557 str = GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE;
567 gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip)
569 GstVideoInterlaceMode mode;
570 const gchar *mode_str;
572 mode = vip ? GST_VIDEO_INFO_INTERLACE_MODE (vip) :
573 GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
575 case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
576 mode_str = "progressive";
578 case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
579 mode_str = "interleaved";
581 case GST_VIDEO_INTERLACE_MODE_MIXED:
585 GST_ERROR ("unsupported `interlace-mode' %d", mode);
589 gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, mode_str, NULL);
593 /* Checks whether the supplied caps contain VA surfaces */
595 gst_caps_has_vaapi_surface (GstCaps * caps)
597 gboolean found_caps = FALSE;
598 guint i, num_structures;
600 g_return_val_if_fail (caps != NULL, FALSE);
602 num_structures = gst_caps_get_size (caps);
603 if (num_structures < 1)
606 for (i = 0; i < num_structures && !found_caps; i++) {
607 GstCapsFeatures *const features = gst_caps_get_features (caps, i);
609 #if GST_CHECK_VERSION(1,3,0)
610 /* Skip ANY features, we need an exact match for correct evaluation */
611 if (gst_caps_features_is_any (features))
615 found_caps = gst_caps_features_contains (features,
616 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE);
622 gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format,
623 guint width, guint height)
625 GstVideoInfo vi = *vip;
627 gst_video_info_set_format (vip, format, width, height);
629 vip->interlace_mode = vi.interlace_mode;
630 vip->flags = vi.flags;
631 vip->views = vi.views;
632 vip->par_n = vi.par_n;
633 vip->par_d = vi.par_d;
634 vip->fps_n = vi.fps_n;
635 vip->fps_d = vi.fps_d;
639 * gst_vaapi_create_test_display:
641 * Creates a temporal #GstVaapiDisplay instance, just for testing the
642 * supported features.
644 * Returns: a new #GstVaapiDisplay instances. Free with
645 * gst_vaapi_display_unref () after use.
648 gst_vaapi_create_test_display ()
650 return gst_vaapi_create_display (GST_VAAPI_DISPLAY_TYPE_ANY, NULL);