c38334fc25d3874044e304d0af46a0d155e8dee2
[platform/upstream/gstreamer.git] / gst / vaapi / gstvaapipluginutil.c
1 /*
2  *  gstvaapipluginutil.h - VA-API plugin helpers
3  *
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>
8  *
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.
13  *
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.
18  *
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
23  */
24
25 #include "gstcompat.h"
26 #include "gstvaapivideocontext.h"
27 #if USE_DRM
28 # include <gst/vaapi/gstvaapidisplay_drm.h>
29 #endif
30 #if USE_X11
31 # include <gst/vaapi/gstvaapidisplay_x11.h>
32 #endif
33 #if USE_GLX
34 # include <gst/vaapi/gstvaapidisplay_glx.h>
35 #endif
36 #if USE_EGL
37 # include <gst/vaapi/gstvaapidisplay_egl.h>
38 #endif
39 #if USE_WAYLAND
40 # include <gst/vaapi/gstvaapidisplay_wayland.h>
41 #endif
42 #include "gstvaapipluginutil.h"
43 #include "gstvaapipluginbase.h"
44
45 /* Environment variable for disable driver white-list */
46 #define GST_VAAPI_ALL_DRIVERS_ENV "GST_VAAPI_ALL_DRIVERS"
47
48 typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFunc) (const gchar *);
49 typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFromHandleFunc) (gpointer);
50
51 typedef struct
52 {
53   const gchar *type_str;
54   GstVaapiDisplayType type;
55   GstVaapiDisplayCreateFunc create_display;
56   GstVaapiDisplayCreateFromHandleFunc create_display_from_handle;
57 } DisplayMap;
58
59 /* *INDENT-OFF* */
60 static const DisplayMap g_display_map[] = {
61 #if USE_WAYLAND
62   {"wayland",
63    GST_VAAPI_DISPLAY_TYPE_WAYLAND,
64    gst_vaapi_display_wayland_new,
65    (GstVaapiDisplayCreateFromHandleFunc)
66    gst_vaapi_display_wayland_new_with_display},
67 #endif
68 #if USE_GLX
69   {"glx",
70    GST_VAAPI_DISPLAY_TYPE_GLX,
71    gst_vaapi_display_glx_new,
72    (GstVaapiDisplayCreateFromHandleFunc)
73    gst_vaapi_display_glx_new_with_display},
74 #endif
75 #if USE_X11
76   {"x11",
77    GST_VAAPI_DISPLAY_TYPE_X11,
78    gst_vaapi_display_x11_new,
79    (GstVaapiDisplayCreateFromHandleFunc)
80    gst_vaapi_display_x11_new_with_display},
81 #endif
82 #if USE_DRM
83   {"drm",
84    GST_VAAPI_DISPLAY_TYPE_DRM,
85    gst_vaapi_display_drm_new},
86 #endif
87   {NULL,}
88 };
89 /* *INDENT-ON* */
90
91 static GstVaapiDisplay *
92 gst_vaapi_create_display (GstVaapiDisplayType display_type,
93     const gchar * display_name)
94 {
95   GstVaapiDisplay *display = NULL;
96   const DisplayMap *m;
97
98   for (m = g_display_map; m->type_str != NULL; m++) {
99     if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY && display_type != m->type)
100       continue;
101
102     display = m->create_display (display_name);
103     if (display || display_type != GST_VAAPI_DISPLAY_TYPE_ANY)
104       break;
105   }
106   return display;
107 }
108
109 #if USE_GST_GL_HELPERS
110 static GstVaapiDisplay *
111 gst_vaapi_create_display_from_handle (GstVaapiDisplayType display_type,
112     gpointer handle)
113 {
114   GstVaapiDisplay *display;
115   const DisplayMap *m;
116
117   if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY)
118     return NULL;
119
120   for (m = g_display_map; m->type_str != NULL; m++) {
121     if (m->type == display_type) {
122       display = m->create_display_from_handle ?
123           m->create_display_from_handle (handle) : NULL;
124       return display;
125     }
126   }
127   return NULL;
128 }
129 #endif
130
131 static GstVaapiDisplay *
132 gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object)
133 {
134 #if USE_GST_GL_HELPERS
135   GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object);
136   GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context);
137   gpointer native_display =
138       GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display));
139   GstGLPlatform platform = gst_gl_context_get_gl_platform (gl_context);
140   GstVaapiDisplay *display, *out_display;
141   GstVaapiDisplayType display_type;
142
143   switch (gst_gl_display_get_handle_type (gl_display)) {
144 #if USE_X11
145     case GST_GL_DISPLAY_TYPE_X11:
146 #if USE_GLX
147       if (platform == GST_GL_PLATFORM_GLX) {
148         display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
149         break;
150       }
151 #endif
152       display_type = GST_VAAPI_DISPLAY_TYPE_X11;
153       break;
154 #endif
155 #if USE_WAYLAND
156     case GST_GL_DISPLAY_TYPE_WAYLAND:
157       display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
158       break;
159 #endif
160     case GST_GL_DISPLAY_TYPE_ANY:{
161       /* Derive from the active window */
162       GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context);
163       const gchar *const gl_window_type = g_getenv ("GST_GL_WINDOW");
164
165       display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
166       if (!gl_window)
167         break;
168       native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window));
169
170       if (gl_window_type) {
171 #if USE_X11
172         if (!display_type && g_strcmp0 (gl_window_type, "x11") == 0)
173           display_type = GST_VAAPI_DISPLAY_TYPE_X11;
174 #endif
175 #if USE_WAYLAND
176         if (!display_type && g_strcmp0 (gl_window_type, "wayland") == 0)
177           display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
178 #endif
179       } else {
180 #if USE_X11 && GST_GL_HAVE_WINDOW_X11
181         if (!display_type)
182           display_type = GST_VAAPI_DISPLAY_TYPE_X11;
183 #elif USE_WAYLAND && GST_GL_HAVE_WINDOW_WAYLAND
184         if (!display_type)
185           display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
186 #endif
187       }
188       gst_object_unref (gl_window);
189       break;
190     }
191     default:
192       display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
193       break;
194   }
195   gst_object_unref (gl_display);
196
197   display = gst_vaapi_create_display_from_handle (display_type, native_display);
198   if (!display)
199     return NULL;
200
201   switch (platform) {
202 #if USE_EGL
203     case GST_GL_PLATFORM_EGL:{
204       guint gles_version;
205
206       switch (gst_gl_context_get_gl_api (gl_context)) {
207         case GST_GL_API_GLES1:
208           gles_version = 1;
209           goto create_egl_display;
210         case GST_GL_API_GLES2:
211           gles_version = 2;
212           goto create_egl_display;
213         case GST_GL_API_OPENGL:
214         case GST_GL_API_OPENGL3:
215           gles_version = 0;
216         create_egl_display:
217           out_display = gst_vaapi_display_egl_new (display, gles_version);
218           break;
219         default:
220           out_display = NULL;
221           break;
222       }
223       if (!out_display) {
224         gst_vaapi_display_unref (display);
225         return NULL;
226       }
227       gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (out_display),
228           GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context)));
229       break;
230     }
231 #endif
232     default:
233       out_display = gst_vaapi_display_ref (display);
234       break;
235   }
236   gst_vaapi_display_unref (display);
237   return out_display;
238 #endif
239   GST_ERROR ("unsupported GStreamer version %s", GST_API_VERSION_S);
240   return NULL;
241 }
242
243 static void
244 gst_vaapi_find_gl_context (GstElement * element)
245 {
246   GstObject *gl_context;
247   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
248
249   /* if the element is vaapisink or any vaapi encoder it doesn't need
250    * to know a GstGLContext in order to create an appropriate
251    * GstVaapiDisplay. Let's them to choose their own
252    * GstVaapiDisplay */
253   if (GST_IS_VIDEO_SINK (element) || GST_IS_VIDEO_ENCODER (element))
254     return;
255
256   gl_context = NULL;
257   if (!gst_vaapi_find_gl_local_context (element, &gl_context))
258     gl_context = gst_vaapi_plugin_base_create_gl_context (plugin);
259
260   if (gl_context) {
261     gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
262     gst_object_unref (gl_context);
263   }
264 }
265
266 gboolean
267 gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type)
268 {
269   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
270   GstVaapiDisplay *display = NULL;
271
272   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
273
274   if (gst_vaapi_video_context_prepare (element, &plugin->display)) {
275     /* Neighbour found and it updated the display */
276     if (gst_vaapi_plugin_base_has_display_type (plugin, type))
277       return TRUE;
278   }
279
280   /* Query for a local GstGL context. If it's found, it will be used
281    * to create the VA display */
282   if (!plugin->gl_context)
283     gst_vaapi_find_gl_context (element);
284
285   /* If no neighboor, or application not interested, use system default */
286   if (plugin->gl_context) {
287     display = gst_vaapi_create_display_from_gl_context (plugin->gl_context);
288     /* Cannot instantiate VA display based on GL context. Reset the
289      *  requested display type to ANY to try again */
290     if (!display)
291       gst_vaapi_plugin_base_set_display_type (plugin,
292           GST_VAAPI_DISPLAY_TYPE_ANY);
293   }
294   if (!display)
295     display = gst_vaapi_create_display (type, plugin->display_name);
296   if (!display)
297     return FALSE;
298
299   gst_vaapi_video_context_propagate (element, display);
300   gst_vaapi_display_unref (display);
301   return TRUE;
302 }
303
304 gboolean
305 gst_vaapi_handle_context_query (GstElement * element, GstQuery * query)
306 {
307   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
308   const gchar *type = NULL;
309   GstContext *context, *old_context;
310
311   g_return_val_if_fail (query != NULL, FALSE);
312
313 #if USE_GST_GL_HELPERS
314   if (plugin->gl_display && plugin->gl_context && plugin->gl_other_context) {
315     if (gst_gl_handle_context_query (element, query,
316             (GstGLDisplay *) plugin->gl_display,
317             (GstGLContext *) plugin->gl_context,
318             (GstGLContext *) plugin->gl_other_context))
319       return TRUE;
320   }
321 #endif
322
323   if (!plugin->display)
324     return FALSE;
325
326   if (!gst_query_parse_context_type (query, &type))
327     return FALSE;
328
329   if (g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME))
330     return FALSE;
331
332   gst_query_parse_context (query, &old_context);
333   if (old_context) {
334     context = gst_context_copy (old_context);
335     gst_vaapi_video_context_set_display (context, plugin->display);
336   } else {
337     context = gst_vaapi_video_context_new_with_display (plugin->display, FALSE);
338   }
339
340   gst_query_set_context (query, context);
341   gst_context_unref (context);
342
343   return TRUE;
344 }
345
346 gboolean
347 gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps)
348 {
349   GstStructure *structure;
350   const GValue *v_width, *v_height, *v_framerate, *v_par;
351   guint i, n_structures;
352
353   structure = gst_caps_get_structure (in_caps, 0);
354   v_width = gst_structure_get_value (structure, "width");
355   v_height = gst_structure_get_value (structure, "height");
356   v_framerate = gst_structure_get_value (structure, "framerate");
357   v_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
358   if (!v_width || !v_height)
359     return FALSE;
360
361   n_structures = gst_caps_get_size (out_caps);
362   for (i = 0; i < n_structures; i++) {
363     structure = gst_caps_get_structure (out_caps, i);
364     gst_structure_set_value (structure, "width", v_width);
365     gst_structure_set_value (structure, "height", v_height);
366     if (v_framerate)
367       gst_structure_set_value (structure, "framerate", v_framerate);
368     if (v_par)
369       gst_structure_set_value (structure, "pixel-aspect-ratio", v_par);
370   }
371   return TRUE;
372 }
373
374 gboolean
375 gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer)
376 {
377   GstVideoOverlayCompositionMeta *const cmeta =
378       gst_buffer_get_video_overlay_composition_meta (buffer);
379   GstVideoOverlayComposition *composition = NULL;
380
381   if (cmeta)
382     composition = cmeta->overlay;
383   return gst_vaapi_surface_set_subpictures_from_composition (surface,
384       composition, TRUE);
385 }
386
387 gboolean
388 gst_vaapi_value_set_format (GValue * value, GstVideoFormat format)
389 {
390   const gchar *str;
391
392   str = gst_video_format_to_string (format);
393   if (!str)
394     return FALSE;
395
396   g_value_init (value, G_TYPE_STRING);
397   g_value_set_string (value, str);
398   return TRUE;
399 }
400
401 gboolean
402 gst_vaapi_value_set_format_list (GValue * value, GArray * formats)
403 {
404   GValue v_format = G_VALUE_INIT;
405   guint i;
406
407   g_value_init (value, GST_TYPE_LIST);
408   for (i = 0; i < formats->len; i++) {
409     GstVideoFormat const format = g_array_index (formats, GstVideoFormat, i);
410
411     if (!gst_vaapi_value_set_format (&v_format, format))
412       continue;
413     gst_value_list_append_value (value, &v_format);
414     g_value_unset (&v_format);
415   }
416   return TRUE;
417 }
418
419 static void
420 set_video_template_caps (GstCaps * caps)
421 {
422   GstStructure *const structure = gst_caps_get_structure (caps, 0);
423
424   gst_structure_set (structure,
425       "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
426       "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
427       "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
428 }
429
430 GstCaps *
431 gst_vaapi_video_format_new_template_caps (GstVideoFormat format)
432 {
433   GstCaps *caps;
434
435   g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
436
437   caps = gst_caps_new_empty_simple ("video/x-raw");
438   if (!caps)
439     return NULL;
440
441   gst_caps_set_simple (caps,
442       "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
443   set_video_template_caps (caps);
444   return caps;
445 }
446
447 GstCaps *
448 gst_vaapi_video_format_new_template_caps_from_list (GArray * formats)
449 {
450   GValue v_formats = G_VALUE_INIT;
451   GstCaps *caps;
452
453   caps = gst_caps_new_empty_simple ("video/x-raw");
454   if (!caps)
455     return NULL;
456
457   if (!gst_vaapi_value_set_format_list (&v_formats, formats)) {
458     gst_caps_unref (caps);
459     return NULL;
460   }
461
462   gst_caps_set_value (caps, "format", &v_formats);
463   set_video_template_caps (caps);
464   g_value_unset (&v_formats);
465   return caps;
466 }
467
468 GstCaps *
469 gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format,
470     const gchar * features_string)
471 {
472   GstCapsFeatures *features;
473   GstCaps *caps;
474
475   caps = gst_vaapi_video_format_new_template_caps (format);
476   if (!caps)
477     return NULL;
478
479   features = gst_caps_features_new (features_string, NULL);
480   if (!features) {
481     gst_caps_unref (caps);
482     return NULL;
483   }
484   gst_caps_set_features (caps, 0, features);
485   return caps;
486 }
487
488 static GstVideoFormat
489 gst_vaapi_find_preferred_format (const GValue * format_list,
490     GstVideoFormat native_format)
491 {
492   const GValue *frmt;
493   GstVideoFormat out_format;
494   guint i;
495
496   /* if one format, that is the one */
497   if (G_VALUE_HOLDS_STRING (format_list))
498     return gst_video_format_from_string (g_value_get_string (format_list));
499
500   if (!GST_VALUE_HOLDS_LIST (format_list)) {
501     GST_ERROR ("negotiated caps do not have a valid format");
502     return GST_VIDEO_FORMAT_UNKNOWN;
503   }
504
505   if (native_format == GST_VIDEO_FORMAT_UNKNOWN
506       || native_format == GST_VIDEO_FORMAT_ENCODED) {
507     native_format = GST_VIDEO_FORMAT_NV12;      /* default VA format */
508   }
509
510   /* search our native format in the list */
511   for (i = 0; i < gst_value_list_get_size (format_list); i++) {
512     frmt = gst_value_list_get_value (format_list, i);
513     out_format = gst_video_format_from_string (g_value_get_string (frmt));
514
515     /* GStreamer do not handle encoded formats nicely. Try the next
516      * one. */
517     if (out_format == GST_VIDEO_FORMAT_ENCODED)
518       continue;
519
520     if (native_format == out_format)
521       return out_format;
522   }
523
524   /* just pick the first valid format in the list */
525   i = 0;
526   do {
527     frmt = gst_value_list_get_value (format_list, i++);
528     out_format = gst_video_format_from_string (g_value_get_string (frmt));
529   } while (out_format == GST_VIDEO_FORMAT_ENCODED);
530
531   return out_format;
532 }
533
534 GstVaapiCapsFeature
535 gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstCaps * allowed_caps,
536     GstVideoFormat * out_format_ptr)
537 {
538   GstVaapiCapsFeature feature = GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED;
539   guint i, j, num_structures;
540   GstCaps *out_caps, *caps = NULL;
541   static const guint feature_list[] = { GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE,
542     GST_VAAPI_CAPS_FEATURE_DMABUF,
543     GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META,
544     GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY,
545   };
546
547   out_caps = gst_pad_peer_query_caps (pad, allowed_caps);
548   if (!out_caps)
549     goto cleanup;
550
551   if (gst_caps_is_any (out_caps) || gst_caps_is_empty (out_caps))
552     goto cleanup;
553
554   feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
555   num_structures = gst_caps_get_size (out_caps);
556   for (i = 0; i < num_structures; i++) {
557     GstCapsFeatures *const features = gst_caps_get_features (out_caps, i);
558     GstStructure *const structure = gst_caps_get_structure (out_caps, i);
559
560     /* Skip ANY features, we need an exact match for correct evaluation */
561     if (gst_caps_features_is_any (features))
562       continue;
563
564     gst_caps_replace (&caps, NULL);
565     caps = gst_caps_new_full (gst_structure_copy (structure), NULL);
566     if (!caps)
567       continue;
568     gst_caps_set_features (caps, 0, gst_caps_features_copy (features));
569
570     for (j = 0; j < G_N_ELEMENTS (feature_list); j++) {
571       if (gst_vaapi_caps_feature_contains (caps, feature_list[j])
572           && feature < feature_list[j]) {
573         feature = feature_list[j];
574         break;
575       }
576     }
577
578     /* Stop at the first match, the caps should already be sorted out
579        by preference order from downstream elements */
580     if (feature != GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
581       break;
582   }
583
584   if (!caps)
585     goto cleanup;
586
587   if (out_format_ptr) {
588     GstVideoFormat out_format;
589     GstStructure *structure;
590     const GValue *format_list;
591
592     /* if the best feature is SystemMemory, we should use the first
593      * caps in the peer caps set, which is the preferred by
594      * downstream. */
595     if (feature == GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
596       gst_caps_replace (&caps, out_caps);
597
598     /* use the first caps, which is the preferred by downstream. */
599     structure = gst_caps_get_structure (caps, 0);
600     if (!structure)
601       goto cleanup;
602     format_list = gst_structure_get_value (structure, "format");
603     if (!format_list)
604       goto cleanup;
605     out_format = gst_vaapi_find_preferred_format (format_list, *out_format_ptr);
606     if (out_format == GST_VIDEO_FORMAT_UNKNOWN)
607       goto cleanup;
608
609     *out_format_ptr = out_format;
610   }
611
612 cleanup:
613   gst_caps_replace (&caps, NULL);
614   gst_caps_replace (&out_caps, NULL);
615   return feature;
616 }
617
618 const gchar *
619 gst_vaapi_caps_feature_to_string (GstVaapiCapsFeature feature)
620 {
621   const gchar *str;
622
623   switch (feature) {
624     case GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY:
625       str = GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY;
626       break;
627     case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
628       str = GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META;
629       break;
630     case GST_VAAPI_CAPS_FEATURE_DMABUF:
631       str = GST_CAPS_FEATURE_MEMORY_DMABUF;
632       break;
633     case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:
634       str = GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE;
635       break;
636     default:
637       str = NULL;
638       break;
639   }
640   return str;
641 }
642
643 gboolean
644 gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip)
645 {
646   GstVideoInterlaceMode mode;
647   const gchar *mode_str;
648
649   mode = vip ? GST_VIDEO_INFO_INTERLACE_MODE (vip) :
650       GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
651   switch (mode) {
652     case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
653       mode_str = "progressive";
654       break;
655     case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
656       mode_str = "interleaved";
657       break;
658     case GST_VIDEO_INTERLACE_MODE_MIXED:
659       mode_str = "mixed";
660       break;
661     default:
662       GST_ERROR ("unsupported `interlace-mode' %d", mode);
663       return FALSE;
664   }
665
666   gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, mode_str, NULL);
667   return TRUE;
668 }
669
670 static gboolean
671 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
672 {
673   guint i;
674
675   for (i = 0; i < gst_caps_get_size (caps); i++) {
676     GstCapsFeatures *const features = gst_caps_get_features (caps, i);
677     /* Skip ANY features, we need an exact match for correct evaluation */
678     if (gst_caps_features_is_any (features))
679       continue;
680     if (gst_caps_features_contains (features, feature))
681       return TRUE;
682   }
683
684   return FALSE;
685 }
686
687 gboolean
688 gst_vaapi_caps_feature_contains (const GstCaps * caps,
689     GstVaapiCapsFeature feature)
690 {
691   const gchar *feature_str;
692
693   g_return_val_if_fail (caps != NULL, FALSE);
694
695   feature_str = gst_vaapi_caps_feature_to_string (feature);
696   if (!feature_str)
697     return FALSE;
698
699   return _gst_caps_has_feature (caps, feature_str);
700 }
701
702 /* Checks whether the supplied caps contain VA surfaces */
703 gboolean
704 gst_caps_has_vaapi_surface (GstCaps * caps)
705 {
706   g_return_val_if_fail (caps != NULL, FALSE);
707
708   return _gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE);
709 }
710
711 gboolean
712 gst_caps_is_video_raw (GstCaps * caps)
713 {
714   GstStructure *structure;
715
716   g_return_val_if_fail (caps != NULL, FALSE);
717
718   if (!gst_caps_is_fixed (caps))
719     return FALSE;
720   if (!_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY))
721     return FALSE;
722   structure = gst_caps_get_structure (caps, 0);
723   return gst_structure_has_name (structure, "video/x-raw");
724 }
725
726 void
727 gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format,
728     guint width, guint height)
729 {
730   GstVideoInfo vi = *vip;
731
732   gst_video_info_set_format (vip, format, width, height);
733
734   GST_VIDEO_INFO_INTERLACE_MODE (vip) = GST_VIDEO_INFO_INTERLACE_MODE (&vi);
735   GST_VIDEO_FORMAT_INFO_FLAGS (vip) = GST_VIDEO_FORMAT_INFO_FLAGS (&vi);
736   GST_VIDEO_INFO_VIEWS (vip) = GST_VIDEO_INFO_VIEWS (&vi);
737   GST_VIDEO_INFO_PAR_N (vip) = GST_VIDEO_INFO_PAR_N (&vi);
738   GST_VIDEO_INFO_PAR_D (vip) = GST_VIDEO_INFO_PAR_D (&vi);
739   GST_VIDEO_INFO_FPS_N (vip) = GST_VIDEO_INFO_FPS_N (&vi);
740   GST_VIDEO_INFO_FPS_D (vip) = GST_VIDEO_INFO_FPS_D (&vi);
741   GST_VIDEO_INFO_MULTIVIEW_MODE (vip) = GST_VIDEO_INFO_MULTIVIEW_MODE (&vi);
742   GST_VIDEO_INFO_MULTIVIEW_FLAGS (vip) = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vi);
743 }
744
745 /**
746  * gst_video_info_changed:
747  * @old: old #GstVideoInfo
748  * @new: new #GstVideoInfo
749  *
750  * Compares @old and @new
751  *
752  * Returns: %TRUE if @old has different format/width/height than
753  * @new. Otherwise, %FALSE.
754  **/
755 gboolean
756 gst_video_info_changed (const GstVideoInfo * old, const GstVideoInfo * new)
757 {
758   if (GST_VIDEO_INFO_FORMAT (old) != GST_VIDEO_INFO_FORMAT (new))
759     return TRUE;
760   if (GST_VIDEO_INFO_WIDTH (old) != GST_VIDEO_INFO_WIDTH (new))
761     return TRUE;
762   if (GST_VIDEO_INFO_HEIGHT (old) != GST_VIDEO_INFO_HEIGHT (new))
763     return TRUE;
764   return FALSE;
765 }
766
767 /**
768  * gst_video_info_force_nv12_if_encoded:
769  * @vinfo: a #GstVideoInfo
770  *
771  * If the format of @vinfo is %GST_VIDEO_FORMAT_ENCODED it is changed
772  * to %GST_VIDEO_FORMAT_NV12.
773  **/
774 void
775 gst_video_info_force_nv12_if_encoded (GstVideoInfo * vinfo)
776 {
777   if (GST_VIDEO_INFO_FORMAT (vinfo) != GST_VIDEO_FORMAT_ENCODED)
778     return;
779   gst_video_info_set_format (vinfo, GST_VIDEO_FORMAT_NV12,
780       GST_VIDEO_INFO_WIDTH (vinfo), GST_VIDEO_INFO_HEIGHT (vinfo));
781 }
782
783 /**
784  * gst_vaapi_create_test_display:
785  *
786  * Creates a temporal #GstVaapiDisplay instance, just for testing the
787  * supported features.
788  *
789  * Returns: a new #GstVaapiDisplay instances. Free with
790  * gst_vaapi_display_unref () after use.
791  **/
792 GstVaapiDisplay *
793 gst_vaapi_create_test_display (void)
794 {
795   return gst_vaapi_create_display (GST_VAAPI_DISPLAY_TYPE_ANY, NULL);
796 }
797
798 /**
799  * gst_vaapi_driver_is_whitelisted:
800  * @display: a #GstVaapiDisplay
801  *
802  * Looks the VA-API driver vendors in an internal white-list.
803  *
804  * Returns: %TRUE if driver is in the white-list, otherwise %FALSE
805  **/
806 gboolean
807 gst_vaapi_driver_is_whitelisted (GstVaapiDisplay * display)
808 {
809   const gchar *vendor;
810   guint i;
811   static const gchar *whitelist[] = {
812     "Intel i965 driver",
813     "mesa gallium vaapi",
814     NULL
815   };
816
817   g_return_val_if_fail (display, FALSE);
818
819   if (g_getenv (GST_VAAPI_ALL_DRIVERS_ENV))
820     return TRUE;
821
822   vendor = gst_vaapi_display_get_vendor_string (display);
823   if (!vendor)
824     goto no_vendor;
825
826   for (i = 0; whitelist[i]; i++) {
827     if (g_ascii_strncasecmp (vendor, whitelist[i], strlen (whitelist[i])) == 0)
828       return TRUE;
829   }
830
831   GST_ERROR ("Unsupported VA driver: %s. Export environment variable "
832       GST_VAAPI_ALL_DRIVERS_ENV " to bypass", vendor);
833   return FALSE;
834
835   /* ERRORS */
836 no_vendor:
837   {
838     GST_WARNING ("no VA-API driver vendor description");
839     return FALSE;
840   }
841 }
842
843 /**
844  * gst_vaapi_codecs_has_codec:
845  * @codecs: a #GArray of #GstVaapiCodec
846  * @codec: a #GstVaapiCodec to find in @codec
847  *
848  * Search in the available @codecs for the specific @codec.
849  *
850  * Returns: %TRUE if @codec is in @codecs
851  **/
852 gboolean
853 gst_vaapi_codecs_has_codec (GArray * codecs, GstVaapiCodec codec)
854 {
855   guint i;
856   GstVaapiCodec c;
857
858   g_return_val_if_fail (codec, FALSE);
859
860   for (i = 0; i < codecs->len; i++) {
861     c = g_array_index (codecs, GstVaapiCodec, i);
862     if (c == codec)
863       return TRUE;
864   }
865   return FALSE;
866 }