3c74826928333a537d6f934d2a721a6c8bfeb1a4
[platform/upstream/gstreamer.git] / gst-libs / gst / vaapi / gstvaapidisplay.c
1 /*
2  *  gstvaapidisplay.c - VA display abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2013 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
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 /**
26  * SECTION:gstvaapidisplay
27  * @short_description: VA display abstraction
28  */
29
30 #include "sysdeps.h"
31 #include <string.h>
32 #include "gstvaapiutils.h"
33 #include "gstvaapivalue.h"
34 #include "gstvaapidisplay.h"
35 #include "gstvaapitexturemap.h"
36 #include "gstvaapidisplay_priv.h"
37 #include "gstvaapiworkarounds.h"
38
39 /* Debug category for all vaapi libs */
40 GST_DEBUG_CATEGORY (gst_debug_vaapi);
41
42 /* Debug category for VaapiDisplay */
43 GST_DEBUG_CATEGORY (gst_debug_vaapi_display);
44 #define GST_CAT_DEFAULT gst_debug_vaapi_display
45
46 #define _do_init \
47     G_ADD_PRIVATE (GstVaapiDisplay); \
48     GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_display, \
49         "vaapidisplay", 0, "VA-API Display");
50
51 G_DEFINE_TYPE_WITH_CODE (GstVaapiDisplay, gst_vaapi_display, GST_TYPE_OBJECT,
52     _do_init);
53
54 /* Ensure those symbols are actually defined in the resulting libraries */
55 #undef gst_vaapi_display_ref
56 #undef gst_vaapi_display_unref
57 #undef gst_vaapi_display_replace
58
59 typedef struct _GstVaapiConfig GstVaapiConfig;
60 struct _GstVaapiConfig
61 {
62   GstVaapiProfile profile;
63   GstVaapiEntrypoint entrypoint;
64 };
65
66 typedef struct _GstVaapiProperty GstVaapiProperty;
67 struct _GstVaapiProperty
68 {
69   const gchar *name;
70   VADisplayAttribute attribute;
71   gint old_value;
72 };
73
74 typedef struct _GstVaapiFormatInfo GstVaapiFormatInfo;
75 struct _GstVaapiFormatInfo
76 {
77   GstVideoFormat format;
78   guint flags;
79 };
80
81 #define DEFAULT_RENDER_MODE     GST_VAAPI_RENDER_MODE_TEXTURE
82 #define DEFAULT_ROTATION        GST_VAAPI_ROTATION_0
83
84 enum
85 {
86   PROP_0,
87
88   PROP_RENDER_MODE,
89   PROP_ROTATION,
90   PROP_HUE,
91   PROP_SATURATION,
92   PROP_BRIGHTNESS,
93   PROP_CONTRAST,
94
95   N_PROPERTIES
96 };
97
98 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
99
100 static void gst_vaapi_display_properties_init (void);
101
102 static gboolean
103 get_attribute (GstVaapiDisplay * display, VADisplayAttribType type,
104     gint * value);
105
106 static gboolean
107 set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value);
108
109 static gboolean
110 get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v);
111
112 static gboolean
113 set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v);
114
115 static void
116 libgstvaapi_init_once (void)
117 {
118   static gsize g_once = FALSE;
119
120   if (!g_once_init_enter (&g_once))
121     return;
122
123   GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi, "vaapi", 0, "VA-API helper");
124
125   gst_vaapi_display_properties_init ();
126
127   g_once_init_leave (&g_once, TRUE);
128 }
129
130 /* GstVaapiDisplayType enumerations */
131 GType
132 gst_vaapi_display_type_get_type (void)
133 {
134   static GType g_type = 0;
135
136   static const GEnumValue display_types[] = {
137     {GST_VAAPI_DISPLAY_TYPE_ANY,
138         "Auto detection", "any"},
139 #if USE_X11
140     {GST_VAAPI_DISPLAY_TYPE_X11,
141         "VA/X11 display", "x11"},
142 #endif
143 #if USE_GLX
144     {GST_VAAPI_DISPLAY_TYPE_GLX,
145         "VA/GLX display", "glx"},
146 #endif
147 #if USE_EGL
148     {GST_VAAPI_DISPLAY_TYPE_EGL,
149         "VA/EGL display", "egl"},
150 #endif
151 #if USE_WAYLAND
152     {GST_VAAPI_DISPLAY_TYPE_WAYLAND,
153         "VA/Wayland display", "wayland"},
154 #endif
155 #if USE_DRM
156     {GST_VAAPI_DISPLAY_TYPE_DRM,
157         "VA/DRM display", "drm"},
158 #endif
159     {0, NULL, NULL},
160   };
161
162   if (!g_type)
163     g_type = g_enum_register_static ("GstVaapiDisplayType", display_types);
164   return g_type;
165 }
166
167 /**
168  * gst_vaapi_display_type_is_compatible:
169  * @type1: the #GstVaapiDisplayType to test
170  * @type2: the reference #GstVaapiDisplayType
171  *
172  * Compares whether #GstVaapiDisplay @type1 is compatible with @type2.
173  * That is, if @type2 is in "any" category, or derived from @type1.
174  *
175  * Returns: %TRUE if @type1 is compatible with @type2, %FALSE otherwise.
176  */
177 gboolean
178 gst_vaapi_display_type_is_compatible (GstVaapiDisplayType type1,
179     GstVaapiDisplayType type2)
180 {
181   if (type1 == type2)
182     return TRUE;
183
184   switch (type1) {
185     case GST_VAAPI_DISPLAY_TYPE_GLX:
186       if (type2 == GST_VAAPI_DISPLAY_TYPE_X11)
187         return TRUE;
188       break;
189     default:
190       break;
191   }
192   return type2 == GST_VAAPI_DISPLAY_TYPE_ANY;
193 }
194
195 /* Append GstVideoFormat to formats array */
196 static inline void
197 append_format (GArray * formats, GstVideoFormat format, guint flags)
198 {
199   GstVaapiFormatInfo fi;
200
201   fi.format = format;
202   fi.flags = flags;
203   g_array_append_val (formats, fi);
204 }
205
206 /* Append VAImageFormats to formats array */
207 static void
208 append_formats (GArray * formats, const VAImageFormat * va_formats,
209     guint * flags, guint n)
210 {
211   GstVideoFormat format;
212   const GstVaapiFormatInfo *YV12_fip = NULL;
213   const GstVaapiFormatInfo *I420_fip = NULL;
214   guint i;
215
216   for (i = 0; i < n; i++) {
217     const VAImageFormat *const va_format = &va_formats[i];
218     const GstVaapiFormatInfo **fipp;
219
220     format = gst_vaapi_video_format_from_va_format (va_format);
221     if (format == GST_VIDEO_FORMAT_UNKNOWN) {
222       GST_DEBUG ("unsupported format %" GST_FOURCC_FORMAT,
223           GST_FOURCC_ARGS (va_format->fourcc));
224       continue;
225     }
226     append_format (formats, format, flags ? flags[i] : 0);
227
228     switch (format) {
229       case GST_VIDEO_FORMAT_YV12:
230         fipp = &YV12_fip;
231         break;
232       case GST_VIDEO_FORMAT_I420:
233         fipp = &I420_fip;
234         break;
235       default:
236         fipp = NULL;
237         break;
238     }
239     if (fipp)
240       *fipp = &g_array_index (formats, GstVaapiFormatInfo, formats->len - 1);
241   }
242
243   /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
244      supported by the underlying driver */
245   if (YV12_fip && !I420_fip)
246     append_format (formats, GST_VIDEO_FORMAT_I420, YV12_fip->flags);
247   else if (I420_fip && !YV12_fip)
248     append_format (formats, GST_VIDEO_FORMAT_YV12, I420_fip->flags);
249 }
250
251 /* Sort image formats. Prefer YUV formats first */
252 static gint
253 compare_yuv_formats (gconstpointer a, gconstpointer b)
254 {
255   const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format;
256   const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format;
257
258   const gboolean is_fmt1_yuv = gst_vaapi_video_format_is_yuv (fmt1);
259   const gboolean is_fmt2_yuv = gst_vaapi_video_format_is_yuv (fmt2);
260
261   if (is_fmt1_yuv != is_fmt2_yuv)
262     return is_fmt1_yuv ? -1 : 1;
263
264   return ((gint) gst_vaapi_video_format_get_score (fmt1) -
265       (gint) gst_vaapi_video_format_get_score (fmt2));
266 }
267
268 /* Sort subpicture formats. Prefer RGB formats first */
269 static gint
270 compare_rgb_formats (gconstpointer a, gconstpointer b)
271 {
272   const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format;
273   const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format;
274
275   const gboolean is_fmt1_rgb = gst_vaapi_video_format_is_rgb (fmt1);
276   const gboolean is_fmt2_rgb = gst_vaapi_video_format_is_rgb (fmt2);
277
278   if (is_fmt1_rgb != is_fmt2_rgb)
279     return is_fmt1_rgb ? -1 : 1;
280
281   return ((gint) gst_vaapi_video_format_get_score (fmt1) -
282       (gint) gst_vaapi_video_format_get_score (fmt2));
283 }
284
285 /* Check if configs array contains profile at entrypoint */
286 static inline gboolean
287 find_config (GArray * configs,
288     GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
289 {
290   GstVaapiConfig *config;
291   guint i;
292
293   if (!configs)
294     return FALSE;
295
296   for (i = 0; i < configs->len; i++) {
297     config = &g_array_index (configs, GstVaapiConfig, i);
298     if (config->profile == profile && config->entrypoint == entrypoint)
299       return TRUE;
300   }
301   return FALSE;
302 }
303
304 /* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */
305 static void
306 append_h263_config (GArray * configs)
307 {
308   GstVaapiConfig *config, tmp_config;
309   GstVaapiConfig *mpeg4_simple_config = NULL;
310   GstVaapiConfig *h263_baseline_config = NULL;
311   guint i;
312
313   if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE)
314     return;
315
316   if (!configs)
317     return;
318
319   for (i = 0; i < configs->len; i++) {
320     config = &g_array_index (configs, GstVaapiConfig, i);
321     if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE)
322       mpeg4_simple_config = config;
323     else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE)
324       h263_baseline_config = config;
325   }
326
327   if (mpeg4_simple_config && !h263_baseline_config) {
328     tmp_config = *mpeg4_simple_config;
329     tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE;
330     g_array_append_val (configs, tmp_config);
331   }
332 }
333
334 /* Sort profiles. Group per codec */
335 static gint
336 compare_profiles (gconstpointer a, gconstpointer b)
337 {
338   const GstVaapiConfig *const config1 = (GstVaapiConfig *) a;
339   const GstVaapiConfig *const config2 = (GstVaapiConfig *) b;
340
341   if (config1->profile == config2->profile)
342     return config1->entrypoint - config2->entrypoint;
343
344   return config1->profile - config2->profile;
345 }
346
347 /* Convert configs array to profiles as GstCaps */
348 static GArray *
349 get_profiles (GArray * configs)
350 {
351   GstVaapiConfig *config;
352   GArray *out_profiles;
353   guint i;
354
355   if (!configs)
356     return NULL;
357
358   out_profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile));
359   if (!out_profiles)
360     return NULL;
361
362   for (i = 0; i < configs->len; i++) {
363     config = &g_array_index (configs, GstVaapiConfig, i);
364     g_array_append_val (out_profiles, config->profile);
365   }
366   return out_profiles;
367 }
368
369 /* Find format info */
370 static const GstVaapiFormatInfo *
371 find_format_info (GArray * formats, GstVideoFormat format)
372 {
373   const GstVaapiFormatInfo *fip;
374   guint i;
375
376   for (i = 0; i < formats->len; i++) {
377     fip = &g_array_index (formats, GstVaapiFormatInfo, i);
378     if (fip->format == format)
379       return fip;
380   }
381   return NULL;
382 }
383
384 /* Check if formats array contains format */
385 static inline gboolean
386 find_format (GArray * formats, GstVideoFormat format)
387 {
388   return find_format_info (formats, format) != NULL;
389 }
390
391 /* Convert formats array to GstCaps */
392 static GArray *
393 get_formats (GArray * formats)
394 {
395   const GstVaapiFormatInfo *fip;
396   GArray *out_formats;
397   guint i;
398
399   out_formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
400   if (!out_formats)
401     return NULL;
402
403   for (i = 0; i < formats->len; i++) {
404     fip = &g_array_index (formats, GstVaapiFormatInfo, i);
405     g_array_append_val (out_formats, fip->format);
406   }
407   return out_formats;
408 }
409
410 /* Find display attribute */
411 static const GstVaapiProperty *
412 find_property (GArray * properties, const gchar * name)
413 {
414   GstVaapiProperty *prop;
415   guint i;
416
417   if (!name)
418     return NULL;
419
420   for (i = 0; i < properties->len; i++) {
421     prop = &g_array_index (properties, GstVaapiProperty, i);
422     if (strcmp (prop->name, name) == 0)
423       return prop;
424   }
425   return NULL;
426 }
427
428 #if 0
429 static const GstVaapiProperty *
430 find_property_by_type (GArray * properties, VADisplayAttribType type)
431 {
432   GstVaapiProperty *prop;
433   guint i;
434
435   for (i = 0; i < properties->len; i++) {
436     prop = &g_array_index (properties, GstVaapiProperty, i);
437     if (prop->attribute.type == type)
438       return prop;
439   }
440   return NULL;
441 }
442 #endif
443
444 static inline const GstVaapiProperty *
445 find_property_by_pspec (GstVaapiDisplay * display, GParamSpec * pspec)
446 {
447   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
448
449   return find_property (priv->properties, pspec->name);
450 }
451
452 static guint
453 find_property_id (const gchar * name)
454 {
455   typedef struct
456   {
457     const gchar *name;
458     guint id;
459   } property_map;
460
461   static const property_map g_property_map[] = {
462     {GST_VAAPI_DISPLAY_PROP_RENDER_MODE, PROP_RENDER_MODE},
463     {GST_VAAPI_DISPLAY_PROP_ROTATION, PROP_ROTATION},
464     {GST_VAAPI_DISPLAY_PROP_HUE, PROP_HUE},
465     {GST_VAAPI_DISPLAY_PROP_SATURATION, PROP_SATURATION},
466     {GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, PROP_BRIGHTNESS},
467     {GST_VAAPI_DISPLAY_PROP_CONTRAST, PROP_CONTRAST},
468     {NULL,}
469   };
470
471   const property_map *m;
472   for (m = g_property_map; m->name != NULL; m++) {
473     if (strcmp (m->name, name) == 0)
474       return m->id;
475   }
476   return 0;
477 }
478
479 /* Initialize VA profiles (decoders, encoders) */
480 static gboolean
481 ensure_profiles (GstVaapiDisplay * display)
482 {
483   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
484   VAProfile *profiles = NULL;
485   VAEntrypoint *entrypoints = NULL;
486   gint i, j, n, num_entrypoints;
487   VAStatus status;
488   gboolean success = FALSE;
489
490   if (priv->has_profiles)
491     return TRUE;
492
493   priv->decoders = g_array_new (FALSE, FALSE, sizeof (GstVaapiConfig));
494   if (!priv->decoders)
495     goto cleanup;
496   priv->encoders = g_array_new (FALSE, FALSE, sizeof (GstVaapiConfig));
497   if (!priv->encoders)
498     goto cleanup;
499   priv->has_profiles = TRUE;
500
501   /* VA profiles */
502   profiles = g_new (VAProfile, vaMaxNumProfiles (priv->display));
503   if (!profiles)
504     goto cleanup;
505   entrypoints = g_new (VAEntrypoint, vaMaxNumEntrypoints (priv->display));
506   if (!entrypoints)
507     goto cleanup;
508
509   n = 0;
510   status = vaQueryConfigProfiles (priv->display, profiles, &n);
511   if (!vaapi_check_status (status, "vaQueryConfigProfiles()"))
512     goto cleanup;
513
514   GST_DEBUG ("%d profiles", n);
515   for (i = 0; i < n; i++) {
516 #if VA_CHECK_VERSION(0,34,0)
517     /* Introduced in VA/VPP API */
518     if (profiles[i] == VAProfileNone)
519       continue;
520 #endif
521     GST_DEBUG ("  %s", string_of_VAProfile (profiles[i]));
522   }
523
524   for (i = 0; i < n; i++) {
525     GstVaapiConfig config;
526
527     config.profile = gst_vaapi_profile (profiles[i]);
528     if (!config.profile)
529       continue;
530
531     status = vaQueryConfigEntrypoints (priv->display,
532         profiles[i], entrypoints, &num_entrypoints);
533     if (!vaapi_check_status (status, "vaQueryConfigEntrypoints()"))
534       continue;
535
536     for (j = 0; j < num_entrypoints; j++) {
537       config.entrypoint = gst_vaapi_entrypoint (entrypoints[j]);
538       switch (config.entrypoint) {
539         case GST_VAAPI_ENTRYPOINT_VLD:
540         case GST_VAAPI_ENTRYPOINT_IDCT:
541         case GST_VAAPI_ENTRYPOINT_MOCO:
542           g_array_append_val (priv->decoders, config);
543           break;
544         case GST_VAAPI_ENTRYPOINT_SLICE_ENCODE:
545         case GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE:
546         case GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP:
547           g_array_append_val (priv->encoders, config);
548           break;
549       }
550     }
551   }
552   append_h263_config (priv->decoders);
553
554   g_array_sort (priv->decoders, compare_profiles);
555   g_array_sort (priv->encoders, compare_profiles);
556
557   /* Video processing API */
558 #if USE_VA_VPP
559   status = vaQueryConfigEntrypoints (priv->display, VAProfileNone,
560       entrypoints, &num_entrypoints);
561   if (vaapi_check_status (status, "vaQueryEntrypoints() [VAProfileNone]")) {
562     for (j = 0; j < num_entrypoints; j++) {
563       if (entrypoints[j] == VAEntrypointVideoProc)
564         priv->has_vpp = TRUE;
565     }
566   }
567 #endif
568   success = TRUE;
569
570 cleanup:
571   g_free (profiles);
572   g_free (entrypoints);
573   return success;
574 }
575
576 /* Initialize VA display attributes */
577 static gboolean
578 ensure_properties (GstVaapiDisplay * display)
579 {
580   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
581   VADisplayAttribute *display_attrs = NULL;
582   VAStatus status;
583   gint i, n;
584   gboolean success = FALSE;
585
586   if (priv->properties)
587     return TRUE;
588
589   priv->properties = g_array_new (FALSE, FALSE, sizeof (GstVaapiProperty));
590   if (!priv->properties)
591     goto cleanup;
592
593   /* VA display attributes */
594   display_attrs =
595       g_new (VADisplayAttribute, vaMaxNumDisplayAttributes (priv->display));
596   if (!display_attrs)
597     goto cleanup;
598
599   n = 0;
600   status = vaQueryDisplayAttributes (priv->display, display_attrs, &n);
601   if (!vaapi_check_status (status, "vaQueryDisplayAttributes()"))
602     goto cleanup;
603
604   GST_DEBUG ("%d display attributes", n);
605   for (i = 0; i < n; i++) {
606     VADisplayAttribute *const attr = &display_attrs[i];
607     GstVaapiProperty prop;
608     gint value;
609
610     GST_DEBUG ("  %s", string_of_VADisplayAttributeType (attr->type));
611
612     switch (attr->type) {
613 #if !VA_CHECK_VERSION(0,34,0)
614       case VADisplayAttribDirectSurface:
615         prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
616         break;
617 #endif
618       case VADisplayAttribRenderMode:
619         prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
620         break;
621       case VADisplayAttribRotation:
622         prop.name = GST_VAAPI_DISPLAY_PROP_ROTATION;
623         break;
624       case VADisplayAttribHue:
625         prop.name = GST_VAAPI_DISPLAY_PROP_HUE;
626         break;
627       case VADisplayAttribSaturation:
628         prop.name = GST_VAAPI_DISPLAY_PROP_SATURATION;
629         break;
630       case VADisplayAttribBrightness:
631         prop.name = GST_VAAPI_DISPLAY_PROP_BRIGHTNESS;
632         break;
633       case VADisplayAttribContrast:
634         prop.name = GST_VAAPI_DISPLAY_PROP_CONTRAST;
635         break;
636       default:
637         prop.name = NULL;
638         break;
639     }
640     if (!prop.name)
641       continue;
642
643     /* Assume the attribute is really supported if we can get the
644      * actual and current value */
645     if (!get_attribute (display, attr->type, &value))
646       continue;
647
648     /* Some drivers (e.g. EMGD) have completely random initial
649      * values */
650     if (value < attr->min_value || value > attr->max_value)
651       continue;
652
653     prop.attribute = *attr;
654     prop.old_value = value;
655     g_array_append_val (priv->properties, prop);
656   }
657   success = TRUE;
658
659 cleanup:
660   g_free (display_attrs);
661   return success;
662 }
663
664 /* Initialize VA image formats */
665 static gboolean
666 ensure_image_formats (GstVaapiDisplay * display)
667 {
668   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
669   VAImageFormat *formats = NULL;
670   VAStatus status;
671   gint i, n;
672   gboolean success = FALSE;
673
674   if (priv->image_formats)
675     return TRUE;
676
677   priv->image_formats = g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo));
678   if (!priv->image_formats)
679     goto cleanup;
680
681   /* VA image formats */
682   formats = g_new (VAImageFormat, vaMaxNumImageFormats (priv->display));
683   if (!formats)
684     goto cleanup;
685
686   n = 0;
687   status = vaQueryImageFormats (priv->display, formats, &n);
688   if (!vaapi_check_status (status, "vaQueryImageFormats()"))
689     goto cleanup;
690
691   GST_DEBUG ("%d image formats", n);
692   for (i = 0; i < n; i++)
693     GST_DEBUG ("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc));
694
695   append_formats (priv->image_formats, formats, NULL, n);
696   g_array_sort (priv->image_formats, compare_yuv_formats);
697   success = TRUE;
698
699 cleanup:
700   g_free (formats);
701   return success;
702 }
703
704 /* Initialize VA subpicture formats */
705 static gboolean
706 ensure_subpicture_formats (GstVaapiDisplay * display)
707 {
708   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
709   VAImageFormat *formats = NULL;
710   unsigned int *flags = NULL;
711   VAStatus status;
712   guint i, n;
713   gboolean success = FALSE;
714
715   if (priv->subpicture_formats)
716     return TRUE;
717
718   priv->subpicture_formats =
719       g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo));
720   if (!priv->subpicture_formats)
721     goto cleanup;
722
723   /* VA subpicture formats */
724   n = vaMaxNumSubpictureFormats (priv->display);
725   formats = g_new (VAImageFormat, n);
726   if (!formats)
727     goto cleanup;
728   flags = g_new (guint, n);
729   if (!flags)
730     goto cleanup;
731
732   n = 0;
733   status = vaQuerySubpictureFormats (priv->display, formats, flags, &n);
734   if (!vaapi_check_status (status, "vaQuerySubpictureFormats()"))
735     goto cleanup;
736
737   GST_DEBUG ("%d subpicture formats", n);
738   for (i = 0; i < n; i++) {
739     GST_DEBUG ("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc));
740     flags[i] = to_GstVaapiSubpictureFlags (flags[i]);
741   }
742
743   append_formats (priv->subpicture_formats, formats, flags, n);
744   g_array_sort (priv->subpicture_formats, compare_rgb_formats);
745   success = TRUE;
746
747 cleanup:
748   g_free (formats);
749   g_free (flags);
750   return success;
751 }
752
753 static void
754 gst_vaapi_display_calculate_pixel_aspect_ratio (GstVaapiDisplay * display)
755 {
756   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
757   gdouble ratio, delta;
758   gint i, j, index, windex;
759
760   static const gint par[][2] = {
761     {1, 1},                     /* regular screen            */
762     {16, 15},                   /* PAL TV                    */
763     {11, 10},                   /* 525 line Rec.601 video    */
764     {54, 59},                   /* 625 line Rec.601 video    */
765     {64, 45},                   /* 1280x1024 on 16:9 display */
766     {5, 3},                     /* 1280x1024 on  4:3 display */
767     {4, 3}                      /*  800x600  on 16:9 display */
768   };
769
770   /* First, calculate the "real" ratio based on the X values;
771    * which is the "physical" w/h divided by the w/h in pixels of the
772    * display */
773   if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm)
774     ratio = 1.0;
775   else
776     ratio = (gdouble) (priv->width_mm * priv->height) /
777         (priv->height_mm * priv->width);
778   GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
779
780   /* Now, find the one from par[][2] with the lowest delta to the real one */
781 #define DELTA(idx, w) (ABS(ratio - ((gdouble)par[idx][w] / par[idx][!(w)])))
782   delta = DELTA (0, 0);
783   index = 0;
784   windex = 0;
785
786   for (i = 1; i < G_N_ELEMENTS (par); i++) {
787     for (j = 0; j < 2; j++) {
788       const gdouble this_delta = DELTA (i, j);
789       if (this_delta < delta) {
790         index = i;
791         windex = j;
792         delta = this_delta;
793       }
794     }
795   }
796 #undef DELTA
797
798   priv->par_n = par[index][windex];
799   priv->par_d = par[index][windex ^ 1];
800 }
801
802 static void
803 gst_vaapi_display_destroy (GstVaapiDisplay * display)
804 {
805   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
806
807   if (priv->decoders) {
808     g_array_free (priv->decoders, TRUE);
809     priv->decoders = NULL;
810   }
811
812   if (priv->encoders) {
813     g_array_free (priv->encoders, TRUE);
814     priv->encoders = NULL;
815   }
816
817   if (priv->image_formats) {
818     g_array_free (priv->image_formats, TRUE);
819     priv->image_formats = NULL;
820   }
821
822   if (priv->subpicture_formats) {
823     g_array_free (priv->subpicture_formats, TRUE);
824     priv->subpicture_formats = NULL;
825   }
826
827   if (priv->properties) {
828     g_array_free (priv->properties, TRUE);
829     priv->properties = NULL;
830   }
831
832   if (priv->display) {
833     if (!priv->parent)
834       vaTerminate (priv->display);
835     priv->display = NULL;
836   }
837
838   if (!priv->use_foreign_display) {
839     GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
840     if (klass->close_display)
841       klass->close_display (display);
842   }
843
844   g_free (priv->display_name);
845   priv->display_name = NULL;
846
847   g_free (priv->vendor_string);
848   priv->vendor_string = NULL;
849
850   gst_vaapi_display_replace_internal (&priv->parent, NULL);
851 }
852
853 static gboolean
854 gst_vaapi_display_create_unlocked (GstVaapiDisplay * display,
855     GstVaapiDisplayInitType init_type, gpointer init_value)
856 {
857   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
858   const GstVaapiDisplayClass *const klass =
859       GST_VAAPI_DISPLAY_GET_CLASS (display);
860   GstVaapiDisplayInfo info;
861
862   memset (&info, 0, sizeof (info));
863   info.display = display;
864   info.display_type = priv->display_type;
865
866   switch (init_type) {
867     case GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY:
868       info.va_display = init_value;
869       priv->display = init_value;
870       priv->use_foreign_display = TRUE;
871       break;
872     case GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME:
873       if (klass->open_display && !klass->open_display (display, init_value))
874         return FALSE;
875       goto create_display;
876     case GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY:
877       if (klass->bind_display && !klass->bind_display (display, init_value))
878         return FALSE;
879       // fall-through
880     create_display:
881       if (!klass->get_display || !klass->get_display (display, &info))
882         return FALSE;
883       priv->display = info.va_display;
884       priv->display_type = info.display_type;
885       priv->native_display = info.native_display;
886       if (klass->get_size)
887         klass->get_size (display, &priv->width, &priv->height);
888       if (klass->get_size_mm)
889         klass->get_size_mm (display, &priv->width_mm, &priv->height_mm);
890       gst_vaapi_display_calculate_pixel_aspect_ratio (display);
891       break;
892   }
893   if (!priv->display)
894     return FALSE;
895
896   if (!priv->parent) {
897     if (!vaapi_initialize (priv->display))
898       return FALSE;
899   }
900
901   GST_INFO_OBJECT (display, "new display addr=%p", display);
902   g_free (priv->display_name);
903   priv->display_name = g_strdup (info.display_name);
904   return TRUE;
905 }
906
907 static gboolean
908 gst_vaapi_display_create (GstVaapiDisplay * display,
909     GstVaapiDisplayInitType init_type, gpointer init_value)
910 {
911   return gst_vaapi_display_create_unlocked (display, init_type, init_value);
912 }
913
914 static void
915 gst_vaapi_display_lock_default (GstVaapiDisplay * display)
916 {
917   GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
918
919   if (priv->parent)
920     priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
921   g_rec_mutex_lock (&priv->mutex);
922 }
923
924 static void
925 gst_vaapi_display_unlock_default (GstVaapiDisplay * display)
926 {
927   GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
928
929   if (priv->parent)
930     priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
931   g_rec_mutex_unlock (&priv->mutex);
932 }
933
934 static void
935 gst_vaapi_display_init (GstVaapiDisplay * display)
936 {
937   GstVaapiDisplayPrivate *const priv =
938       gst_vaapi_display_get_instance_private (display);
939
940   display->priv = priv;
941   priv->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
942   priv->par_n = 1;
943   priv->par_d = 1;
944
945   g_rec_mutex_init (&priv->mutex);
946 }
947
948 static void
949 gst_vaapi_display_finalize (GObject * object)
950 {
951   GstVaapiDisplay *const display = GST_VAAPI_DISPLAY (object);
952   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
953
954   gst_vaapi_display_destroy (display);
955   g_rec_mutex_clear (&priv->mutex);
956
957   G_OBJECT_CLASS (gst_vaapi_display_parent_class)->finalize (object);
958 }
959
960 void
961 gst_vaapi_display_class_init (GstVaapiDisplayClass * klass)
962 {
963   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
964
965   libgstvaapi_init_once ();
966
967   object_class->finalize = gst_vaapi_display_finalize;
968   klass->lock = gst_vaapi_display_lock_default;
969   klass->unlock = gst_vaapi_display_unlock_default;
970 }
971
972 static void
973 gst_vaapi_display_properties_init (void)
974 {
975   /**
976    * GstVaapiDisplay:render-mode:
977    *
978    * The VA display rendering mode, expressed as a #GstVaapiRenderMode.
979    */
980   g_properties[PROP_RENDER_MODE] =
981       g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_RENDER_MODE,
982       "render mode",
983       "The display rendering mode",
984       GST_VAAPI_TYPE_RENDER_MODE, DEFAULT_RENDER_MODE, G_PARAM_READWRITE);
985
986   /**
987    * GstVaapiDisplay:rotation:
988    *
989    * The VA display rotation mode, expressed as a #GstVaapiRotation.
990    */
991   g_properties[PROP_ROTATION] =
992       g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_ROTATION,
993       "rotation",
994       "The display rotation mode",
995       GST_VAAPI_TYPE_ROTATION, DEFAULT_ROTATION, G_PARAM_READWRITE);
996
997   /**
998    * GstVaapiDisplay:hue:
999    *
1000    * The VA display hue, expressed as a float value. Range is -180.0
1001    * to 180.0. Default value is 0.0 and represents no modification.
1002    */
1003   g_properties[PROP_HUE] =
1004       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_HUE,
1005       "hue", "The display hue value", -180.0, 180.0, 0.0, G_PARAM_READWRITE);
1006
1007   /**
1008    * GstVaapiDisplay:saturation:
1009    *
1010    * The VA display saturation, expressed as a float value. Range is
1011    * 0.0 to 2.0. Default value is 1.0 and represents no modification.
1012    */
1013   g_properties[PROP_SATURATION] =
1014       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_SATURATION,
1015       "saturation",
1016       "The display saturation value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
1017
1018   /**
1019    * GstVaapiDisplay:brightness:
1020    *
1021    * The VA display brightness, expressed as a float value. Range is
1022    * -1.0 to 1.0. Default value is 0.0 and represents no modification.
1023    */
1024   g_properties[PROP_BRIGHTNESS] =
1025       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_BRIGHTNESS,
1026       "brightness",
1027       "The display brightness value", -1.0, 1.0, 0.0, G_PARAM_READWRITE);
1028
1029   /**
1030    * GstVaapiDisplay:contrast:
1031    *
1032    * The VA display contrast, expressed as a float value. Range is 0.0
1033    * to 2.0. Default value is 1.0 and represents no modification.
1034    */
1035   g_properties[PROP_CONTRAST] =
1036       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_CONTRAST,
1037       "contrast",
1038       "The display contrast value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
1039 }
1040
1041 GstVaapiDisplay *
1042 gst_vaapi_display_new (GstVaapiDisplay * display,
1043     GstVaapiDisplayInitType init_type, gpointer init_value)
1044 {
1045   g_return_val_if_fail (display != NULL, NULL);
1046
1047   if (!gst_vaapi_display_create (display, init_type, init_value))
1048     goto error;
1049   return display;
1050
1051   /* ERRORS */
1052 error:
1053   {
1054     gst_vaapi_display_unref_internal (display);
1055     return NULL;
1056   }
1057 }
1058
1059 /**
1060  * gst_vaapi_display_new_with_display:
1061  * @va_display: a #VADisplay
1062  *
1063  * Creates a new #GstVaapiDisplay, using @va_display as the VA
1064  * display.
1065  *
1066  * Return value: the newly created #GstVaapiDisplay object
1067  */
1068 GstVaapiDisplay *
1069 gst_vaapi_display_new_with_display (VADisplay va_display)
1070 {
1071   return gst_vaapi_display_new (g_object_new (GST_TYPE_VAAPI_DISPLAY, NULL),
1072       GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, va_display);
1073 }
1074
1075 /**
1076  * gst_vaapi_display_ref:
1077  * @display: a #GstVaapiDisplay
1078  *
1079  * Atomically increases the reference count of the given @display by one.
1080  *
1081  * Returns: The same @display argument
1082  */
1083 GstVaapiDisplay *
1084 gst_vaapi_display_ref (GstVaapiDisplay * display)
1085 {
1086   return gst_vaapi_display_ref_internal (display);
1087 }
1088
1089 /**
1090  * gst_vaapi_display_unref:
1091  * @display: a #GstVaapiDisplay
1092  *
1093  * Atomically decreases the reference count of the @display by one. If
1094  * the reference count reaches zero, the display will be free'd.
1095  */
1096 void
1097 gst_vaapi_display_unref (GstVaapiDisplay * display)
1098 {
1099   gst_vaapi_display_unref_internal (display);
1100 }
1101
1102 /**
1103  * gst_vaapi_display_replace:
1104  * @old_display_ptr: a pointer to a #GstVaapiDisplay
1105  * @new_display: a #GstVaapiDisplay
1106  *
1107  * Atomically replaces the display display held in @old_display_ptr
1108  * with @new_display. This means that @old_display_ptr shall reference
1109  * a valid display. However, @new_display can be NULL.
1110  */
1111 void
1112 gst_vaapi_display_replace (GstVaapiDisplay ** old_display_ptr,
1113     GstVaapiDisplay * new_display)
1114 {
1115   gst_vaapi_display_replace_internal (old_display_ptr, new_display);
1116 }
1117
1118 /**
1119  * gst_vaapi_display_lock:
1120  * @display: a #GstVaapiDisplay
1121  *
1122  * Locks @display. If @display is already locked by another thread,
1123  * the current thread will block until @display is unlocked by the
1124  * other thread.
1125  */
1126 void
1127 gst_vaapi_display_lock (GstVaapiDisplay * display)
1128 {
1129   GstVaapiDisplayClass *klass;
1130
1131   g_return_if_fail (display != NULL);
1132
1133   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1134   if (klass->lock)
1135     klass->lock (display);
1136 }
1137
1138 /**
1139  * gst_vaapi_display_unlock:
1140  * @display: a #GstVaapiDisplay
1141  *
1142  * Unlocks @display. If another thread is blocked in a
1143  * gst_vaapi_display_lock() call for @display, it will be woken and
1144  * can lock @display itself.
1145  */
1146 void
1147 gst_vaapi_display_unlock (GstVaapiDisplay * display)
1148 {
1149   GstVaapiDisplayClass *klass;
1150
1151   g_return_if_fail (display != NULL);
1152
1153   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1154   if (klass->unlock)
1155     klass->unlock (display);
1156 }
1157
1158 /**
1159  * gst_vaapi_display_sync:
1160  * @display: a #GstVaapiDisplay
1161  *
1162  * Flushes any requests queued for the windowing system and waits until
1163  * all requests have been handled. This is often used for making sure
1164  * that the display is synchronized with the current state of the program.
1165  *
1166  * This is most useful for X11. On windowing systems where requests are
1167  * handled synchronously, this function will do nothing.
1168  */
1169 void
1170 gst_vaapi_display_sync (GstVaapiDisplay * display)
1171 {
1172   GstVaapiDisplayClass *klass;
1173
1174   g_return_if_fail (display != NULL);
1175
1176   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1177   if (klass->sync)
1178     klass->sync (display);
1179   else if (klass->flush)
1180     klass->flush (display);
1181 }
1182
1183 /**
1184  * gst_vaapi_display_flush:
1185  * @display: a #GstVaapiDisplay
1186  *
1187  * Flushes any requests queued for the windowing system.
1188  *
1189  * This is most useful for X11. On windowing systems where requests
1190  * are handled synchronously, this function will do nothing.
1191  */
1192 void
1193 gst_vaapi_display_flush (GstVaapiDisplay * display)
1194 {
1195   GstVaapiDisplayClass *klass;
1196
1197   g_return_if_fail (display != NULL);
1198
1199   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1200   if (klass->flush)
1201     klass->flush (display);
1202 }
1203
1204 /**
1205  * gst_vaapi_display_get_class_type:
1206  * @display: a #GstVaapiDisplay
1207  *
1208  * Returns the #GstVaapiDisplayType of @display. This is the type of
1209  * the object, thus the associated class, not the type of the VA
1210  * display.
1211  *
1212  * Return value: the #GstVaapiDisplayType
1213  */
1214 GstVaapiDisplayType
1215 gst_vaapi_display_get_class_type (GstVaapiDisplay * display)
1216 {
1217   g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
1218
1219   return GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display);
1220 }
1221
1222 /**
1223  * gst_vaapi_display_get_display_type:
1224  * @display: a #GstVaapiDisplay
1225  *
1226  * Returns the #GstVaapiDisplayType of the VA display bound to
1227  * @display. This is not the type of the @display object.
1228  *
1229  * Return value: the #GstVaapiDisplayType
1230  */
1231 GstVaapiDisplayType
1232 gst_vaapi_display_get_display_type (GstVaapiDisplay * display)
1233 {
1234   g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
1235
1236   return GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display);
1237 }
1238
1239 /**
1240  * gst_vaapi_display_get_display_type:
1241  * @display: a #GstVaapiDisplay
1242  *
1243  * Returns the @display name.
1244  *
1245  * Return value: the display name
1246  */
1247 const gchar *
1248 gst_vaapi_display_get_display_name (GstVaapiDisplay * display)
1249 {
1250   g_return_val_if_fail (display != NULL, NULL);
1251
1252   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display_name;
1253 }
1254
1255 /**
1256  * gst_vaapi_display_get_display:
1257  * @display: a #GstVaapiDisplay
1258  *
1259  * Returns the #VADisplay bound to @display.
1260  *
1261  * Return value: the #VADisplay
1262  */
1263 VADisplay
1264 gst_vaapi_display_get_display (GstVaapiDisplay * display)
1265 {
1266   g_return_val_if_fail (display != NULL, NULL);
1267
1268   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display;
1269 }
1270
1271 /**
1272  * gst_vaapi_display_get_width:
1273  * @display: a #GstVaapiDisplay
1274  *
1275  * Retrieves the width of a #GstVaapiDisplay.
1276  *
1277  * Return value: the width of the @display, in pixels
1278  */
1279 guint
1280 gst_vaapi_display_get_width (GstVaapiDisplay * display)
1281 {
1282   g_return_val_if_fail (display != NULL, 0);
1283
1284   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
1285 }
1286
1287 /**
1288  * gst_vaapi_display_get_height:
1289  * @display: a #GstVaapiDisplay
1290  *
1291  * Retrieves the height of a #GstVaapiDisplay
1292  *
1293  * Return value: the height of the @display, in pixels
1294  */
1295 guint
1296 gst_vaapi_display_get_height (GstVaapiDisplay * display)
1297 {
1298   g_return_val_if_fail (display != NULL, 0);
1299
1300   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
1301 }
1302
1303 /**
1304  * gst_vaapi_display_get_size:
1305  * @display: a #GstVaapiDisplay
1306  * @pwidth: return location for the width, or %NULL
1307  * @pheight: return location for the height, or %NULL
1308  *
1309  * Retrieves the dimensions of a #GstVaapiDisplay.
1310  */
1311 void
1312 gst_vaapi_display_get_size (GstVaapiDisplay * display, guint * pwidth,
1313     guint * pheight)
1314 {
1315   g_return_if_fail (GST_VAAPI_DISPLAY (display));
1316
1317   if (pwidth)
1318     *pwidth = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
1319
1320   if (pheight)
1321     *pheight = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
1322 }
1323
1324 /**
1325  * gst_vaapi_display_get_pixel_aspect_ratio:
1326  * @display: a #GstVaapiDisplay
1327  * @par_n: return location for the numerator of pixel aspect ratio, or %NULL
1328  * @par_d: return location for the denominator of pixel aspect ratio, or %NULL
1329  *
1330  * Retrieves the pixel aspect ratio of a #GstVaapiDisplay.
1331  */
1332 void
1333 gst_vaapi_display_get_pixel_aspect_ratio (GstVaapiDisplay * display,
1334     guint * par_n, guint * par_d)
1335 {
1336   g_return_if_fail (display != NULL);
1337
1338   if (par_n)
1339     *par_n = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_n;
1340
1341   if (par_d)
1342     *par_d = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_d;
1343 }
1344
1345 /**
1346  * gst_vaapi_display_has_video_processing:
1347  * @display: a #GstVaapiDisplay
1348  *
1349  * Checks whether the underlying VA driver implementation supports
1350  * video processing (VPP) acceleration.
1351  *
1352  * Returns: %TRUE if some VPP features are available
1353  */
1354 gboolean
1355 gst_vaapi_display_has_video_processing (GstVaapiDisplay * display)
1356 {
1357   g_return_val_if_fail (display != NULL, FALSE);
1358
1359   if (!ensure_profiles (display))
1360     return FALSE;
1361   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->has_vpp;
1362 }
1363
1364 /**
1365  * gst_vaapi_display_get_decode_profiles:
1366  * @display: a #GstVaapiDisplay
1367  *
1368  * Gets the supported profiles for decoding. The caller owns an extra
1369  * reference to the resulting array of #GstVaapiProfile elements, so
1370  * it shall be released with g_array_unref() after usage.
1371  *
1372  * Return value: a newly allocated #GArray, or %NULL or error or if
1373  *   decoding is not supported at all
1374  */
1375 GArray *
1376 gst_vaapi_display_get_decode_profiles (GstVaapiDisplay * display)
1377 {
1378   g_return_val_if_fail (display != NULL, NULL);
1379
1380   if (!ensure_profiles (display))
1381     return NULL;
1382   return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders);
1383 }
1384
1385 /**
1386  * gst_vaapi_display_has_decoder:
1387  * @display: a #GstVaapiDisplay
1388  * @profile: a #VAProfile
1389  * @entrypoint: a #GstVaaiEntrypoint
1390  *
1391  * Returns whether VA @display supports @profile for decoding at the
1392  * specified @entrypoint.
1393  *
1394  * Return value: %TRUE if VA @display supports @profile for decoding.
1395  */
1396 gboolean
1397 gst_vaapi_display_has_decoder (GstVaapiDisplay * display,
1398     GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
1399 {
1400   g_return_val_if_fail (display != NULL, FALSE);
1401
1402   if (!ensure_profiles (display))
1403     return FALSE;
1404   return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders,
1405       profile, entrypoint);
1406 }
1407
1408 /**
1409  * gst_vaapi_display_get_encode_profiles:
1410  * @display: a #GstVaapiDisplay
1411  *
1412  * Gets the supported profiles for encoding. The caller owns an extra
1413  * reference to the resulting array of #GstVaapiProfile elements, so
1414  * it shall be released with g_array_unref() after usage.
1415  *
1416  * Return value: a newly allocated #GArray, or %NULL or error or if
1417  *   encoding is not supported at all
1418  */
1419 GArray *
1420 gst_vaapi_display_get_encode_profiles (GstVaapiDisplay * display)
1421 {
1422   g_return_val_if_fail (display != NULL, NULL);
1423
1424   if (!ensure_profiles (display))
1425     return NULL;
1426   return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders);
1427 }
1428
1429 /**
1430  * gst_vaapi_display_has_encoder:
1431  * @display: a #GstVaapiDisplay
1432  * @profile: a #VAProfile
1433  * @entrypoint: a #GstVaapiEntrypoint
1434  *
1435  * Returns whether VA @display supports @profile for encoding at the
1436  * specified @entrypoint.
1437  *
1438  * Return value: %TRUE if VA @display supports @profile for encoding.
1439  */
1440 gboolean
1441 gst_vaapi_display_has_encoder (GstVaapiDisplay * display,
1442     GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
1443 {
1444   g_return_val_if_fail (display != NULL, FALSE);
1445
1446   if (!ensure_profiles (display))
1447     return FALSE;
1448   return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders,
1449       profile, entrypoint);
1450 }
1451
1452 /**
1453  * gst_vaapi_display_get_image_formats:
1454  * @display: a #GstVaapiDisplay
1455  *
1456  * Gets the supported image formats for gst_vaapi_surface_get_image()
1457  * or gst_vaapi_surface_put_image().
1458  *
1459  * Note that this method does not necessarily map image formats
1460  * returned by vaQueryImageFormats(). The set of capabilities can be
1461  * stripped down, if gstreamer-vaapi does not support the format, or
1462  * expanded to cover compatible formats not exposed by the underlying
1463  * driver. e.g. I420 can be supported even if the driver only exposes
1464  * YV12.
1465  *
1466  * Note: the caller owns an extra reference to the resulting array of
1467  * #GstVideoFormat elements, so it shall be released with
1468  * g_array_unref() after usage.
1469  *
1470  * Return value: a newly allocated #GArray, or %NULL on error or if
1471  *   the set is empty
1472  */
1473 GArray *
1474 gst_vaapi_display_get_image_formats (GstVaapiDisplay * display)
1475 {
1476   g_return_val_if_fail (display != NULL, NULL);
1477
1478   if (!ensure_image_formats (display))
1479     return NULL;
1480   return get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->image_formats);
1481 }
1482
1483 /**
1484  * gst_vaapi_display_has_image_format:
1485  * @display: a #GstVaapiDisplay
1486  * @format: a #GstVideoFormat
1487  *
1488  * Returns whether VA @display supports @format image format.
1489  *
1490  * Return value: %TRUE if VA @display supports @format image format
1491  */
1492 gboolean
1493 gst_vaapi_display_has_image_format (GstVaapiDisplay * display,
1494     GstVideoFormat format)
1495 {
1496   GstVaapiDisplayPrivate *priv;
1497
1498   g_return_val_if_fail (display != NULL, FALSE);
1499   g_return_val_if_fail (format, FALSE);
1500
1501   priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1502
1503   if (!ensure_image_formats (display))
1504     return FALSE;
1505   if (find_format (priv->image_formats, format))
1506     return TRUE;
1507
1508   /* XXX: try subpicture formats since some drivers could report a
1509    * set of VA image formats that is not a superset of the set of VA
1510    * subpicture formats
1511    */
1512   if (!ensure_subpicture_formats (display))
1513     return FALSE;
1514   return find_format (priv->subpicture_formats, format);
1515 }
1516
1517 /**
1518  * gst_vaapi_display_get_subpicture_formats:
1519  * @display: a #GstVaapiDisplay
1520  *
1521  * Gets the supported subpicture formats.
1522  *
1523  * Note that this method does not necessarily map subpicture formats
1524  * returned by vaQuerySubpictureFormats(). The set of capabilities can
1525  * be stripped down if gstreamer-vaapi does not support the
1526  * format. e.g. this is the case for paletted formats like IA44.
1527  *
1528  * Note: the caller owns an extra reference to the resulting array of
1529  * #GstVideoFormat elements, so it shall be released with
1530  * g_array_unref() after usage.
1531  *
1532  * Return value: a newly allocated #GArray, or %NULL on error of if
1533  *   the set is empty
1534  */
1535 GArray *
1536 gst_vaapi_display_get_subpicture_formats (GstVaapiDisplay * display)
1537 {
1538   g_return_val_if_fail (display != NULL, NULL);
1539
1540   if (!ensure_subpicture_formats (display))
1541     return NULL;
1542   return
1543       get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->subpicture_formats);
1544 }
1545
1546 /**
1547  * gst_vaapi_display_has_subpicture_format:
1548  * @display: a #GstVaapiDisplay
1549  * @format: a #GstVideoFormat
1550  * @flags_ptr: pointer to #GstVaapiSubpictureFlags, or zero
1551  *
1552  * Returns whether VA @display supports @format subpicture format with
1553  * the supplied @flags.
1554  *
1555  * Return value: %TRUE if VA @display supports @format subpicture format
1556  */
1557 gboolean
1558 gst_vaapi_display_has_subpicture_format (GstVaapiDisplay * display,
1559     GstVideoFormat format, guint * flags_ptr)
1560 {
1561   GstVaapiDisplayPrivate *priv;
1562   const GstVaapiFormatInfo *fip;
1563
1564   g_return_val_if_fail (display != NULL, FALSE);
1565   g_return_val_if_fail (format, FALSE);
1566
1567   priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1568
1569   if (!ensure_subpicture_formats (display))
1570     return FALSE;
1571
1572   fip = find_format_info (priv->subpicture_formats, format);
1573   if (!fip)
1574     return FALSE;
1575
1576   if (flags_ptr)
1577     *flags_ptr = fip->flags;
1578   return TRUE;
1579 }
1580
1581 /**
1582  * gst_vaapi_display_has_property:
1583  * @display: a #GstVaapiDisplay
1584  * @name: the property name to check
1585  *
1586  * Returns whether VA @display supports the requested property. The
1587  * check is performed against the property @name. So, the client
1588  * application may perform this check only once and cache this
1589  * information.
1590  *
1591  * Return value: %TRUE if VA @display supports property @name
1592  */
1593 gboolean
1594 gst_vaapi_display_has_property (GstVaapiDisplay * display, const gchar * name)
1595 {
1596   g_return_val_if_fail (display != NULL, FALSE);
1597   g_return_val_if_fail (name, FALSE);
1598
1599   if (!ensure_properties (display))
1600     return FALSE;
1601   return find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties,
1602       name) != NULL;
1603 }
1604
1605 gboolean
1606 gst_vaapi_display_get_property (GstVaapiDisplay * display, const gchar * name,
1607     GValue * out_value)
1608 {
1609   const GstVaapiProperty *prop;
1610
1611   g_return_val_if_fail (display != NULL, FALSE);
1612   g_return_val_if_fail (name != NULL, FALSE);
1613   g_return_val_if_fail (out_value != NULL, FALSE);
1614
1615   if (!ensure_properties (display))
1616     return FALSE;
1617
1618   prop =
1619       find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties, name);
1620   if (!prop)
1621     return FALSE;
1622
1623   switch (prop->attribute.type) {
1624     case VADisplayAttribRenderMode:{
1625       GstVaapiRenderMode mode;
1626       if (!gst_vaapi_display_get_render_mode (display, &mode))
1627         return FALSE;
1628       g_value_init (out_value, GST_VAAPI_TYPE_RENDER_MODE);
1629       g_value_set_enum (out_value, mode);
1630       break;
1631     }
1632     case VADisplayAttribRotation:{
1633       GstVaapiRotation rotation;
1634       rotation = gst_vaapi_display_get_rotation (display);
1635       g_value_init (out_value, GST_VAAPI_TYPE_ROTATION);
1636       g_value_set_enum (out_value, rotation);
1637       break;
1638     }
1639     case VADisplayAttribHue:
1640     case VADisplayAttribSaturation:
1641     case VADisplayAttribBrightness:
1642     case VADisplayAttribContrast:{
1643       gfloat value;
1644       if (!get_color_balance (display, find_property_id (name), &value))
1645         return FALSE;
1646       g_value_init (out_value, G_TYPE_FLOAT);
1647       g_value_set_float (out_value, value);
1648       break;
1649     }
1650     default:
1651       GST_WARNING ("unsupported property '%s'", name);
1652       return FALSE;
1653   }
1654   return TRUE;
1655 }
1656
1657 gboolean
1658 gst_vaapi_display_set_property (GstVaapiDisplay * display, const gchar * name,
1659     const GValue * value)
1660 {
1661   const GstVaapiProperty *prop;
1662
1663   g_return_val_if_fail (display != NULL, FALSE);
1664   g_return_val_if_fail (name != NULL, FALSE);
1665   g_return_val_if_fail (value != NULL, FALSE);
1666
1667   if (!ensure_properties (display))
1668     return FALSE;
1669
1670   prop =
1671       find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties, name);
1672   if (!prop)
1673     return FALSE;
1674
1675   switch (prop->attribute.type) {
1676     case VADisplayAttribRenderMode:{
1677       GstVaapiRenderMode mode;
1678       if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_RENDER_MODE))
1679         return FALSE;
1680       mode = g_value_get_enum (value);
1681       return gst_vaapi_display_set_render_mode (display, mode);
1682     }
1683     case VADisplayAttribRotation:{
1684       GstVaapiRotation rotation;
1685       if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_ROTATION))
1686         return FALSE;
1687       rotation = g_value_get_enum (value);
1688       return gst_vaapi_display_set_rotation (display, rotation);
1689     }
1690     case VADisplayAttribHue:
1691     case VADisplayAttribSaturation:
1692     case VADisplayAttribBrightness:
1693     case VADisplayAttribContrast:{
1694       gfloat v;
1695       if (!G_VALUE_HOLDS (value, G_TYPE_FLOAT))
1696         return FALSE;
1697       v = g_value_get_float (value);
1698       return set_color_balance (display, find_property_id (name), v);
1699     }
1700     default:
1701       break;
1702   }
1703
1704   GST_WARNING ("unsupported property '%s'", name);
1705   return FALSE;
1706 }
1707
1708 static gboolean
1709 get_attribute (GstVaapiDisplay * display, VADisplayAttribType type,
1710     gint * value)
1711 {
1712   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1713   VADisplayAttribute attr = { 0, };
1714   VAStatus status;
1715
1716   attr.type = type;
1717   attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
1718   status = vaGetDisplayAttributes (priv->display, &attr, 1);
1719   if (!vaapi_check_status (status, "vaGetDisplayAttributes()"))
1720     return FALSE;
1721   *value = attr.value;
1722   return TRUE;
1723 }
1724
1725 static gboolean
1726 set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value)
1727 {
1728   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1729   VADisplayAttribute attr = { 0, };
1730   VAStatus status;
1731
1732   attr.type = type;
1733   attr.value = value;
1734   attr.flags = VA_DISPLAY_ATTRIB_SETTABLE;
1735   status = vaSetDisplayAttributes (priv->display, &attr, 1);
1736   if (!vaapi_check_status (status, "vaSetDisplayAttributes()"))
1737     return FALSE;
1738   return TRUE;
1739 }
1740
1741 static gboolean
1742 get_render_mode_VADisplayAttribRenderMode (GstVaapiDisplay * display,
1743     GstVaapiRenderMode * pmode)
1744 {
1745   gint modes, devices;
1746
1747   if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
1748     return FALSE;
1749   if (!devices)
1750     return FALSE;
1751   if (!get_attribute (display, VADisplayAttribRenderMode, &modes))
1752     return FALSE;
1753
1754   /* Favor "overlay" mode since it is the most restrictive one */
1755   if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY | VA_RENDER_MODE_EXTERNAL_OVERLAY))
1756     *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1757   else
1758     *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1759   return TRUE;
1760 }
1761
1762 static gboolean
1763 get_render_mode_VADisplayAttribDirectSurface (GstVaapiDisplay * display,
1764     GstVaapiRenderMode * pmode)
1765 {
1766 #if VA_CHECK_VERSION(0,34,0)
1767   /* VADisplayAttribDirectsurface was removed in VA-API >= 0.34.0 */
1768   return FALSE;
1769 #else
1770   gint direct_surface;
1771
1772   if (!get_attribute (display, VADisplayAttribDirectSurface, &direct_surface))
1773     return FALSE;
1774   if (direct_surface)
1775     *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1776   else
1777     *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1778   return TRUE;
1779 #endif
1780 }
1781
1782 static gboolean
1783 get_render_mode_default (GstVaapiDisplay * display, GstVaapiRenderMode * pmode)
1784 {
1785   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1786
1787   switch (priv->display_type) {
1788 #if USE_WAYLAND
1789     case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
1790       /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */
1791       *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1792       break;
1793 #endif
1794 #if USE_DRM
1795     case GST_VAAPI_DISPLAY_TYPE_DRM:
1796       /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */
1797       *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1798       break;
1799 #endif
1800     default:
1801       /* This includes VA/X11 and VA/GLX modes */
1802       *pmode = DEFAULT_RENDER_MODE;
1803       break;
1804   }
1805   return TRUE;
1806 }
1807
1808 /**
1809  * gst_vaapi_display_get_render_mode:
1810  * @display: a #GstVaapiDisplay
1811  * @pmode: return location for the VA @display rendering mode
1812  *
1813  * Returns the current VA @display rendering mode.
1814  *
1815  * Return value: %TRUE if VA @display rendering mode could be determined
1816  */
1817 gboolean
1818 gst_vaapi_display_get_render_mode (GstVaapiDisplay * display,
1819     GstVaapiRenderMode * pmode)
1820 {
1821   g_return_val_if_fail (display != NULL, FALSE);
1822
1823   /* Try with render-mode attribute */
1824   if (get_render_mode_VADisplayAttribRenderMode (display, pmode))
1825     return TRUE;
1826
1827   /* Try with direct-surface attribute */
1828   if (get_render_mode_VADisplayAttribDirectSurface (display, pmode))
1829     return TRUE;
1830
1831   /* Default: determine from the display type */
1832   return get_render_mode_default (display, pmode);
1833 }
1834
1835 /**
1836  * gst_vaapi_display_set_render_mode:
1837  * @display: a #GstVaapiDisplay
1838  * @mode: the #GstVaapiRenderMode to set
1839  *
1840  * Sets the VA @display rendering mode to the supplied @mode. This
1841  * function returns %FALSE if the rendering mode could not be set,
1842  * e.g. run-time switching rendering mode is not supported.
1843  *
1844  * Return value: %TRUE if VA @display rendering @mode could be changed
1845  *   to the requested value
1846  */
1847 gboolean
1848 gst_vaapi_display_set_render_mode (GstVaapiDisplay * display,
1849     GstVaapiRenderMode mode)
1850 {
1851   gint modes, devices;
1852
1853   g_return_val_if_fail (display != NULL, FALSE);
1854
1855   if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
1856     return FALSE;
1857
1858   modes = 0;
1859   switch (mode) {
1860     case GST_VAAPI_RENDER_MODE_OVERLAY:
1861       if (devices & VA_RENDER_DEVICE_LOCAL)
1862         modes |= VA_RENDER_MODE_LOCAL_OVERLAY;
1863       if (devices & VA_RENDER_DEVICE_EXTERNAL)
1864         modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY;
1865       break;
1866     case GST_VAAPI_RENDER_MODE_TEXTURE:
1867       if (devices & VA_RENDER_DEVICE_LOCAL)
1868         modes |= VA_RENDER_MODE_LOCAL_GPU;
1869       if (devices & VA_RENDER_DEVICE_EXTERNAL)
1870         modes |= VA_RENDER_MODE_EXTERNAL_GPU;
1871       break;
1872   }
1873   if (!modes)
1874     return FALSE;
1875   if (!set_attribute (display, VADisplayAttribRenderMode, modes))
1876     return FALSE;
1877   return TRUE;
1878 }
1879
1880 /**
1881  * gst_vaapi_display_get_rotation:
1882  * @display: a #GstVaapiDisplay
1883  *
1884  * Returns the current VA @display rotation angle. If the VA driver
1885  * does not support "rotation" display attribute, then the display is
1886  * assumed to be un-rotated.
1887  *
1888  * Return value: the current #GstVaapiRotation value
1889  */
1890 GstVaapiRotation
1891 gst_vaapi_display_get_rotation (GstVaapiDisplay * display)
1892 {
1893   gint value;
1894
1895   g_return_val_if_fail (display != NULL, DEFAULT_ROTATION);
1896
1897   if (!get_attribute (display, VADisplayAttribRotation, &value))
1898     value = VA_ROTATION_NONE;
1899   return to_GstVaapiRotation (value);
1900 }
1901
1902 /**
1903  * gst_vaapi_display_set_rotation:
1904  * @display: a #GstVaapiDisplay
1905  * @rotation: the #GstVaapiRotation value to set
1906  *
1907  * Sets the VA @display rotation angle to the supplied @rotation
1908  * value. This function returns %FALSE if the rotation angle could not
1909  * be set, e.g. the VA driver does not allow to change the display
1910  * rotation angle.
1911  *
1912  * Return value: %TRUE if VA @display rotation angle could be changed
1913  *   to the requested value
1914  */
1915 gboolean
1916 gst_vaapi_display_set_rotation (GstVaapiDisplay * display,
1917     GstVaapiRotation rotation)
1918 {
1919   guint value;
1920
1921   g_return_val_if_fail (display != NULL, FALSE);
1922
1923   value = from_GstVaapiRotation (rotation);
1924   if (!set_attribute (display, VADisplayAttribRotation, value))
1925     return FALSE;
1926   return TRUE;
1927 }
1928
1929 /* Get color balance attributes */
1930 static gboolean
1931 get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v)
1932 {
1933   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
1934   const GstVaapiProperty *prop;
1935   const VADisplayAttribute *attr;
1936   gfloat out_value;
1937   gint value;
1938
1939   if (!ensure_properties (display))
1940     return FALSE;
1941
1942   if (!pspec)
1943     return FALSE;
1944
1945   prop = find_property_by_pspec (display, &pspec->parent_instance);
1946   if (!prop)
1947     return FALSE;
1948   attr = &prop->attribute;
1949
1950   if (!get_attribute (display, attr->type, &value))
1951     return FALSE;
1952
1953   /* Scale wrt. the medium ("default") value */
1954   out_value = pspec->default_value;
1955   if (value > attr->value)
1956     out_value += ((gfloat) (value - attr->value) /
1957         (attr->max_value - attr->value) *
1958         (pspec->maximum - pspec->default_value));
1959   else if (value < attr->value)
1960     out_value -= ((gfloat) (attr->value - value) /
1961         (attr->value - attr->min_value) *
1962         (pspec->default_value - pspec->minimum));
1963   *v = out_value;
1964   return TRUE;
1965 }
1966
1967 /* Set color balance attribute */
1968 static gboolean
1969 set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v)
1970 {
1971   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
1972   const GstVaapiProperty *prop;
1973   const VADisplayAttribute *attr;
1974   gint value;
1975
1976   if (!ensure_properties (display))
1977     return FALSE;
1978
1979   if (!pspec)
1980     return FALSE;
1981
1982   prop = find_property_by_pspec (display, &pspec->parent_instance);
1983   if (!prop)
1984     return FALSE;
1985   attr = &prop->attribute;
1986
1987   /* Scale wrt. the medium ("default") value */
1988   value = attr->value;
1989   if (v > pspec->default_value)
1990     value += ((v - pspec->default_value) /
1991         (pspec->maximum - pspec->default_value) *
1992         (attr->max_value - attr->value));
1993   else if (v < pspec->default_value)
1994     value -= ((pspec->default_value - v) /
1995         (pspec->default_value - pspec->minimum) *
1996         (attr->value - attr->min_value));
1997   if (!set_attribute (display, attr->type, value))
1998     return FALSE;
1999   return TRUE;
2000 }
2001
2002 /* Ensures the VA driver vendor string was copied */
2003 static gboolean
2004 ensure_vendor_string (GstVaapiDisplay * display)
2005 {
2006   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
2007   const gchar *vendor_string;
2008
2009   GST_VAAPI_DISPLAY_LOCK (display);
2010   if (!priv->vendor_string) {
2011     vendor_string = vaQueryVendorString (priv->display);
2012     if (vendor_string)
2013       priv->vendor_string = g_strdup (vendor_string);
2014   }
2015   GST_VAAPI_DISPLAY_UNLOCK (display);
2016   return priv->vendor_string != NULL;
2017 }
2018
2019 /**
2020  * gst_vaapi_display_get_vendor_string:
2021  * @display: a #GstVaapiDisplay
2022  *
2023  * Returns the VA driver vendor string attached to the supplied VA @display.
2024  * The @display owns the vendor string, do *not* de-allocate it.
2025  *
2026  * This function is thread safe.
2027  *
2028  * Return value: the current #GstVaapiRotation value
2029  */
2030 const gchar *
2031 gst_vaapi_display_get_vendor_string (GstVaapiDisplay * display)
2032 {
2033   g_return_val_if_fail (display != NULL, NULL);
2034
2035   if (!ensure_vendor_string (display))
2036     return NULL;
2037   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->vendor_string;
2038 }
2039
2040 /**
2041  * gst_vaapi_display_has_opengl:
2042  * @display: a #GstVaapiDisplay
2043  *
2044  * Returns wether the @display that was created does support OpenGL
2045  * context to be attached.
2046  *
2047  * This function is thread safe.
2048  *
2049  * Return value: %TRUE if the @display supports OpenGL context, %FALSE
2050  *   otherwise
2051  */
2052 gboolean
2053 gst_vaapi_display_has_opengl (GstVaapiDisplay * display)
2054 {
2055   GstVaapiDisplayClass *klass;
2056
2057   g_return_val_if_fail (display != NULL, FALSE);
2058
2059   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
2060   return (klass->display_type == GST_VAAPI_DISPLAY_TYPE_GLX ||
2061       klass->display_type == GST_VAAPI_DISPLAY_TYPE_EGL);
2062 }
2063
2064 /**
2065  * gst_vaapi_display_reset_texture_map:
2066  * @display: a #GstVaapiDisplay
2067  *
2068  * Reset the internal #GstVaapiTextureMap if available.
2069  *
2070  * This function is thread safe.
2071  */
2072 void
2073 gst_vaapi_display_reset_texture_map (GstVaapiDisplay * display)
2074 {
2075   GstVaapiDisplayClass *klass;
2076   GstVaapiTextureMap *map;
2077
2078   g_return_if_fail (display != NULL);
2079
2080   if (!gst_vaapi_display_has_opengl (display))
2081     return;
2082   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
2083   if (!klass->get_texture_map)
2084     return;
2085   if ((map = klass->get_texture_map (display)))
2086     gst_vaapi_texture_map_reset (map);
2087 }