libs: display: pass display info when foreign display
[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 data)
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     .display = display,
862     .display_type = priv->display_type,
863   };
864
865   switch (init_type) {
866     case GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY:{
867       GstVaapiDisplayInfo *p_info = data;
868
869       info.va_display = p_info->va_display;
870       info.display_type = p_info->display_type;
871       priv->display = p_info->va_display;
872       priv->use_foreign_display = TRUE;
873
874       if (!klass->bind_display)
875         break;
876
877       data = p_info->native_display;
878       goto bind_display;
879     }
880     case GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME:
881       if (klass->open_display && !klass->open_display (display, data))
882         return FALSE;
883       goto create_display;
884     case GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY:
885     bind_display:
886       if (klass->bind_display && !klass->bind_display (display, data))
887         return FALSE;
888       // fall-through
889     create_display:
890       if (!klass->get_display || !klass->get_display (display, &info))
891         return FALSE;
892       priv->display = info.va_display;
893       priv->display_type = info.display_type;
894       priv->native_display = info.native_display;
895       if (klass->get_size)
896         klass->get_size (display, &priv->width, &priv->height);
897       if (klass->get_size_mm)
898         klass->get_size_mm (display, &priv->width_mm, &priv->height_mm);
899       gst_vaapi_display_calculate_pixel_aspect_ratio (display);
900       break;
901   }
902   if (!priv->display)
903     return FALSE;
904
905   if (!priv->parent) {
906     if (!vaapi_initialize (priv->display))
907       return FALSE;
908   }
909
910   GST_INFO_OBJECT (display, "new display addr=%p", display);
911   g_free (priv->display_name);
912   priv->display_name = g_strdup (info.display_name);
913   return TRUE;
914 }
915
916 static gboolean
917 gst_vaapi_display_create (GstVaapiDisplay * display,
918     GstVaapiDisplayInitType init_type, gpointer init_value)
919 {
920   return gst_vaapi_display_create_unlocked (display, init_type, init_value);
921 }
922
923 static void
924 gst_vaapi_display_lock_default (GstVaapiDisplay * display)
925 {
926   GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
927
928   if (priv->parent)
929     priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
930   g_rec_mutex_lock (&priv->mutex);
931 }
932
933 static void
934 gst_vaapi_display_unlock_default (GstVaapiDisplay * display)
935 {
936   GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
937
938   if (priv->parent)
939     priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
940   g_rec_mutex_unlock (&priv->mutex);
941 }
942
943 static void
944 gst_vaapi_display_init (GstVaapiDisplay * display)
945 {
946   GstVaapiDisplayPrivate *const priv =
947       gst_vaapi_display_get_instance_private (display);
948
949   display->priv = priv;
950   priv->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
951   priv->par_n = 1;
952   priv->par_d = 1;
953
954   g_rec_mutex_init (&priv->mutex);
955 }
956
957 static void
958 gst_vaapi_display_finalize (GObject * object)
959 {
960   GstVaapiDisplay *const display = GST_VAAPI_DISPLAY (object);
961   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
962
963   gst_vaapi_display_destroy (display);
964   g_rec_mutex_clear (&priv->mutex);
965
966   G_OBJECT_CLASS (gst_vaapi_display_parent_class)->finalize (object);
967 }
968
969 void
970 gst_vaapi_display_class_init (GstVaapiDisplayClass * klass)
971 {
972   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
973
974   libgstvaapi_init_once ();
975
976   object_class->finalize = gst_vaapi_display_finalize;
977   klass->lock = gst_vaapi_display_lock_default;
978   klass->unlock = gst_vaapi_display_unlock_default;
979 }
980
981 static void
982 gst_vaapi_display_properties_init (void)
983 {
984   /**
985    * GstVaapiDisplay:render-mode:
986    *
987    * The VA display rendering mode, expressed as a #GstVaapiRenderMode.
988    */
989   g_properties[PROP_RENDER_MODE] =
990       g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_RENDER_MODE,
991       "render mode",
992       "The display rendering mode",
993       GST_VAAPI_TYPE_RENDER_MODE, DEFAULT_RENDER_MODE, G_PARAM_READWRITE);
994
995   /**
996    * GstVaapiDisplay:rotation:
997    *
998    * The VA display rotation mode, expressed as a #GstVaapiRotation.
999    */
1000   g_properties[PROP_ROTATION] =
1001       g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_ROTATION,
1002       "rotation",
1003       "The display rotation mode",
1004       GST_VAAPI_TYPE_ROTATION, DEFAULT_ROTATION, G_PARAM_READWRITE);
1005
1006   /**
1007    * GstVaapiDisplay:hue:
1008    *
1009    * The VA display hue, expressed as a float value. Range is -180.0
1010    * to 180.0. Default value is 0.0 and represents no modification.
1011    */
1012   g_properties[PROP_HUE] =
1013       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_HUE,
1014       "hue", "The display hue value", -180.0, 180.0, 0.0, G_PARAM_READWRITE);
1015
1016   /**
1017    * GstVaapiDisplay:saturation:
1018    *
1019    * The VA display saturation, expressed as a float value. Range is
1020    * 0.0 to 2.0. Default value is 1.0 and represents no modification.
1021    */
1022   g_properties[PROP_SATURATION] =
1023       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_SATURATION,
1024       "saturation",
1025       "The display saturation value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
1026
1027   /**
1028    * GstVaapiDisplay:brightness:
1029    *
1030    * The VA display brightness, expressed as a float value. Range is
1031    * -1.0 to 1.0. Default value is 0.0 and represents no modification.
1032    */
1033   g_properties[PROP_BRIGHTNESS] =
1034       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_BRIGHTNESS,
1035       "brightness",
1036       "The display brightness value", -1.0, 1.0, 0.0, G_PARAM_READWRITE);
1037
1038   /**
1039    * GstVaapiDisplay:contrast:
1040    *
1041    * The VA display contrast, expressed as a float value. Range is 0.0
1042    * to 2.0. Default value is 1.0 and represents no modification.
1043    */
1044   g_properties[PROP_CONTRAST] =
1045       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_CONTRAST,
1046       "contrast",
1047       "The display contrast value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
1048 }
1049
1050 GstVaapiDisplay *
1051 gst_vaapi_display_new (GstVaapiDisplay * display,
1052     GstVaapiDisplayInitType init_type, gpointer init_value)
1053 {
1054   g_return_val_if_fail (display != NULL, NULL);
1055
1056   if (!gst_vaapi_display_create (display, init_type, init_value))
1057     goto error;
1058   return display;
1059
1060   /* ERRORS */
1061 error:
1062   {
1063     gst_vaapi_display_unref_internal (display);
1064     return NULL;
1065   }
1066 }
1067
1068 /**
1069  * gst_vaapi_display_new_with_display:
1070  * @va_display: a #VADisplay
1071  *
1072  * Creates a new #GstVaapiDisplay, using @va_display as the VA
1073  * display.
1074  *
1075  * Return value: the newly created #GstVaapiDisplay object
1076  */
1077 GstVaapiDisplay *
1078 gst_vaapi_display_new_with_display (VADisplay va_display)
1079 {
1080   GstVaapiDisplayInfo info = {
1081     .va_display = va_display,
1082     .display_type = GST_VAAPI_DISPLAY_TYPE_ANY,
1083   };
1084
1085   return gst_vaapi_display_new (g_object_new (GST_TYPE_VAAPI_DISPLAY, NULL),
1086       GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info);
1087 }
1088
1089 /**
1090  * gst_vaapi_display_ref:
1091  * @display: a #GstVaapiDisplay
1092  *
1093  * Atomically increases the reference count of the given @display by one.
1094  *
1095  * Returns: The same @display argument
1096  */
1097 GstVaapiDisplay *
1098 gst_vaapi_display_ref (GstVaapiDisplay * display)
1099 {
1100   return gst_vaapi_display_ref_internal (display);
1101 }
1102
1103 /**
1104  * gst_vaapi_display_unref:
1105  * @display: a #GstVaapiDisplay
1106  *
1107  * Atomically decreases the reference count of the @display by one. If
1108  * the reference count reaches zero, the display will be free'd.
1109  */
1110 void
1111 gst_vaapi_display_unref (GstVaapiDisplay * display)
1112 {
1113   gst_vaapi_display_unref_internal (display);
1114 }
1115
1116 /**
1117  * gst_vaapi_display_replace:
1118  * @old_display_ptr: a pointer to a #GstVaapiDisplay
1119  * @new_display: a #GstVaapiDisplay
1120  *
1121  * Atomically replaces the display display held in @old_display_ptr
1122  * with @new_display. This means that @old_display_ptr shall reference
1123  * a valid display. However, @new_display can be NULL.
1124  */
1125 void
1126 gst_vaapi_display_replace (GstVaapiDisplay ** old_display_ptr,
1127     GstVaapiDisplay * new_display)
1128 {
1129   gst_vaapi_display_replace_internal (old_display_ptr, new_display);
1130 }
1131
1132 /**
1133  * gst_vaapi_display_lock:
1134  * @display: a #GstVaapiDisplay
1135  *
1136  * Locks @display. If @display is already locked by another thread,
1137  * the current thread will block until @display is unlocked by the
1138  * other thread.
1139  */
1140 void
1141 gst_vaapi_display_lock (GstVaapiDisplay * display)
1142 {
1143   GstVaapiDisplayClass *klass;
1144
1145   g_return_if_fail (display != NULL);
1146
1147   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1148   if (klass->lock)
1149     klass->lock (display);
1150 }
1151
1152 /**
1153  * gst_vaapi_display_unlock:
1154  * @display: a #GstVaapiDisplay
1155  *
1156  * Unlocks @display. If another thread is blocked in a
1157  * gst_vaapi_display_lock() call for @display, it will be woken and
1158  * can lock @display itself.
1159  */
1160 void
1161 gst_vaapi_display_unlock (GstVaapiDisplay * display)
1162 {
1163   GstVaapiDisplayClass *klass;
1164
1165   g_return_if_fail (display != NULL);
1166
1167   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1168   if (klass->unlock)
1169     klass->unlock (display);
1170 }
1171
1172 /**
1173  * gst_vaapi_display_sync:
1174  * @display: a #GstVaapiDisplay
1175  *
1176  * Flushes any requests queued for the windowing system and waits until
1177  * all requests have been handled. This is often used for making sure
1178  * that the display is synchronized with the current state of the program.
1179  *
1180  * This is most useful for X11. On windowing systems where requests are
1181  * handled synchronously, this function will do nothing.
1182  */
1183 void
1184 gst_vaapi_display_sync (GstVaapiDisplay * display)
1185 {
1186   GstVaapiDisplayClass *klass;
1187
1188   g_return_if_fail (display != NULL);
1189
1190   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1191   if (klass->sync)
1192     klass->sync (display);
1193   else if (klass->flush)
1194     klass->flush (display);
1195 }
1196
1197 /**
1198  * gst_vaapi_display_flush:
1199  * @display: a #GstVaapiDisplay
1200  *
1201  * Flushes any requests queued for the windowing system.
1202  *
1203  * This is most useful for X11. On windowing systems where requests
1204  * are handled synchronously, this function will do nothing.
1205  */
1206 void
1207 gst_vaapi_display_flush (GstVaapiDisplay * display)
1208 {
1209   GstVaapiDisplayClass *klass;
1210
1211   g_return_if_fail (display != NULL);
1212
1213   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1214   if (klass->flush)
1215     klass->flush (display);
1216 }
1217
1218 /**
1219  * gst_vaapi_display_get_class_type:
1220  * @display: a #GstVaapiDisplay
1221  *
1222  * Returns the #GstVaapiDisplayType of @display. This is the type of
1223  * the object, thus the associated class, not the type of the VA
1224  * display.
1225  *
1226  * Return value: the #GstVaapiDisplayType
1227  */
1228 GstVaapiDisplayType
1229 gst_vaapi_display_get_class_type (GstVaapiDisplay * display)
1230 {
1231   g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
1232
1233   return GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display);
1234 }
1235
1236 /**
1237  * gst_vaapi_display_get_display_type:
1238  * @display: a #GstVaapiDisplay
1239  *
1240  * Returns the #GstVaapiDisplayType of the VA display bound to
1241  * @display. This is not the type of the @display object.
1242  *
1243  * Return value: the #GstVaapiDisplayType
1244  */
1245 GstVaapiDisplayType
1246 gst_vaapi_display_get_display_type (GstVaapiDisplay * display)
1247 {
1248   g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
1249
1250   return GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display);
1251 }
1252
1253 /**
1254  * gst_vaapi_display_get_display_type:
1255  * @display: a #GstVaapiDisplay
1256  *
1257  * Returns the @display name.
1258  *
1259  * Return value: the display name
1260  */
1261 const gchar *
1262 gst_vaapi_display_get_display_name (GstVaapiDisplay * display)
1263 {
1264   g_return_val_if_fail (display != NULL, NULL);
1265
1266   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display_name;
1267 }
1268
1269 /**
1270  * gst_vaapi_display_get_display:
1271  * @display: a #GstVaapiDisplay
1272  *
1273  * Returns the #VADisplay bound to @display.
1274  *
1275  * Return value: the #VADisplay
1276  */
1277 VADisplay
1278 gst_vaapi_display_get_display (GstVaapiDisplay * display)
1279 {
1280   g_return_val_if_fail (display != NULL, NULL);
1281
1282   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display;
1283 }
1284
1285 /**
1286  * gst_vaapi_display_get_width:
1287  * @display: a #GstVaapiDisplay
1288  *
1289  * Retrieves the width of a #GstVaapiDisplay.
1290  *
1291  * Return value: the width of the @display, in pixels
1292  */
1293 guint
1294 gst_vaapi_display_get_width (GstVaapiDisplay * display)
1295 {
1296   g_return_val_if_fail (display != NULL, 0);
1297
1298   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
1299 }
1300
1301 /**
1302  * gst_vaapi_display_get_height:
1303  * @display: a #GstVaapiDisplay
1304  *
1305  * Retrieves the height of a #GstVaapiDisplay
1306  *
1307  * Return value: the height of the @display, in pixels
1308  */
1309 guint
1310 gst_vaapi_display_get_height (GstVaapiDisplay * display)
1311 {
1312   g_return_val_if_fail (display != NULL, 0);
1313
1314   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
1315 }
1316
1317 /**
1318  * gst_vaapi_display_get_size:
1319  * @display: a #GstVaapiDisplay
1320  * @pwidth: return location for the width, or %NULL
1321  * @pheight: return location for the height, or %NULL
1322  *
1323  * Retrieves the dimensions of a #GstVaapiDisplay.
1324  */
1325 void
1326 gst_vaapi_display_get_size (GstVaapiDisplay * display, guint * pwidth,
1327     guint * pheight)
1328 {
1329   g_return_if_fail (GST_VAAPI_DISPLAY (display));
1330
1331   if (pwidth)
1332     *pwidth = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
1333
1334   if (pheight)
1335     *pheight = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
1336 }
1337
1338 /**
1339  * gst_vaapi_display_get_pixel_aspect_ratio:
1340  * @display: a #GstVaapiDisplay
1341  * @par_n: return location for the numerator of pixel aspect ratio, or %NULL
1342  * @par_d: return location for the denominator of pixel aspect ratio, or %NULL
1343  *
1344  * Retrieves the pixel aspect ratio of a #GstVaapiDisplay.
1345  */
1346 void
1347 gst_vaapi_display_get_pixel_aspect_ratio (GstVaapiDisplay * display,
1348     guint * par_n, guint * par_d)
1349 {
1350   g_return_if_fail (display != NULL);
1351
1352   if (par_n)
1353     *par_n = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_n;
1354
1355   if (par_d)
1356     *par_d = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_d;
1357 }
1358
1359 /**
1360  * gst_vaapi_display_has_video_processing:
1361  * @display: a #GstVaapiDisplay
1362  *
1363  * Checks whether the underlying VA driver implementation supports
1364  * video processing (VPP) acceleration.
1365  *
1366  * Returns: %TRUE if some VPP features are available
1367  */
1368 gboolean
1369 gst_vaapi_display_has_video_processing (GstVaapiDisplay * display)
1370 {
1371   g_return_val_if_fail (display != NULL, FALSE);
1372
1373   if (!ensure_profiles (display))
1374     return FALSE;
1375   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->has_vpp;
1376 }
1377
1378 /**
1379  * gst_vaapi_display_get_decode_profiles:
1380  * @display: a #GstVaapiDisplay
1381  *
1382  * Gets the supported profiles for decoding. The caller owns an extra
1383  * reference to the resulting array of #GstVaapiProfile elements, so
1384  * it shall be released with g_array_unref() after usage.
1385  *
1386  * Return value: a newly allocated #GArray, or %NULL or error or if
1387  *   decoding is not supported at all
1388  */
1389 GArray *
1390 gst_vaapi_display_get_decode_profiles (GstVaapiDisplay * display)
1391 {
1392   g_return_val_if_fail (display != NULL, NULL);
1393
1394   if (!ensure_profiles (display))
1395     return NULL;
1396   return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders);
1397 }
1398
1399 /**
1400  * gst_vaapi_display_has_decoder:
1401  * @display: a #GstVaapiDisplay
1402  * @profile: a #VAProfile
1403  * @entrypoint: a #GstVaaiEntrypoint
1404  *
1405  * Returns whether VA @display supports @profile for decoding at the
1406  * specified @entrypoint.
1407  *
1408  * Return value: %TRUE if VA @display supports @profile for decoding.
1409  */
1410 gboolean
1411 gst_vaapi_display_has_decoder (GstVaapiDisplay * display,
1412     GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
1413 {
1414   g_return_val_if_fail (display != NULL, FALSE);
1415
1416   if (!ensure_profiles (display))
1417     return FALSE;
1418   return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders,
1419       profile, entrypoint);
1420 }
1421
1422 /**
1423  * gst_vaapi_display_get_encode_profiles:
1424  * @display: a #GstVaapiDisplay
1425  *
1426  * Gets the supported profiles for encoding. The caller owns an extra
1427  * reference to the resulting array of #GstVaapiProfile elements, so
1428  * it shall be released with g_array_unref() after usage.
1429  *
1430  * Return value: a newly allocated #GArray, or %NULL or error or if
1431  *   encoding is not supported at all
1432  */
1433 GArray *
1434 gst_vaapi_display_get_encode_profiles (GstVaapiDisplay * display)
1435 {
1436   g_return_val_if_fail (display != NULL, NULL);
1437
1438   if (!ensure_profiles (display))
1439     return NULL;
1440   return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders);
1441 }
1442
1443 /**
1444  * gst_vaapi_display_has_encoder:
1445  * @display: a #GstVaapiDisplay
1446  * @profile: a #VAProfile
1447  * @entrypoint: a #GstVaapiEntrypoint
1448  *
1449  * Returns whether VA @display supports @profile for encoding at the
1450  * specified @entrypoint.
1451  *
1452  * Return value: %TRUE if VA @display supports @profile for encoding.
1453  */
1454 gboolean
1455 gst_vaapi_display_has_encoder (GstVaapiDisplay * display,
1456     GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
1457 {
1458   g_return_val_if_fail (display != NULL, FALSE);
1459
1460   if (!ensure_profiles (display))
1461     return FALSE;
1462   return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders,
1463       profile, entrypoint);
1464 }
1465
1466 /**
1467  * gst_vaapi_display_get_image_formats:
1468  * @display: a #GstVaapiDisplay
1469  *
1470  * Gets the supported image formats for gst_vaapi_surface_get_image()
1471  * or gst_vaapi_surface_put_image().
1472  *
1473  * Note that this method does not necessarily map image formats
1474  * returned by vaQueryImageFormats(). The set of capabilities can be
1475  * stripped down, if gstreamer-vaapi does not support the format, or
1476  * expanded to cover compatible formats not exposed by the underlying
1477  * driver. e.g. I420 can be supported even if the driver only exposes
1478  * YV12.
1479  *
1480  * Note: the caller owns an extra reference to the resulting array of
1481  * #GstVideoFormat elements, so it shall be released with
1482  * g_array_unref() after usage.
1483  *
1484  * Return value: a newly allocated #GArray, or %NULL on error or if
1485  *   the set is empty
1486  */
1487 GArray *
1488 gst_vaapi_display_get_image_formats (GstVaapiDisplay * display)
1489 {
1490   g_return_val_if_fail (display != NULL, NULL);
1491
1492   if (!ensure_image_formats (display))
1493     return NULL;
1494   return get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->image_formats);
1495 }
1496
1497 /**
1498  * gst_vaapi_display_has_image_format:
1499  * @display: a #GstVaapiDisplay
1500  * @format: a #GstVideoFormat
1501  *
1502  * Returns whether VA @display supports @format image format.
1503  *
1504  * Return value: %TRUE if VA @display supports @format image format
1505  */
1506 gboolean
1507 gst_vaapi_display_has_image_format (GstVaapiDisplay * display,
1508     GstVideoFormat format)
1509 {
1510   GstVaapiDisplayPrivate *priv;
1511
1512   g_return_val_if_fail (display != NULL, FALSE);
1513   g_return_val_if_fail (format, FALSE);
1514
1515   priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1516
1517   if (!ensure_image_formats (display))
1518     return FALSE;
1519   if (find_format (priv->image_formats, format))
1520     return TRUE;
1521
1522   /* XXX: try subpicture formats since some drivers could report a
1523    * set of VA image formats that is not a superset of the set of VA
1524    * subpicture formats
1525    */
1526   if (!ensure_subpicture_formats (display))
1527     return FALSE;
1528   return find_format (priv->subpicture_formats, format);
1529 }
1530
1531 /**
1532  * gst_vaapi_display_get_subpicture_formats:
1533  * @display: a #GstVaapiDisplay
1534  *
1535  * Gets the supported subpicture formats.
1536  *
1537  * Note that this method does not necessarily map subpicture formats
1538  * returned by vaQuerySubpictureFormats(). The set of capabilities can
1539  * be stripped down if gstreamer-vaapi does not support the
1540  * format. e.g. this is the case for paletted formats like IA44.
1541  *
1542  * Note: the caller owns an extra reference to the resulting array of
1543  * #GstVideoFormat elements, so it shall be released with
1544  * g_array_unref() after usage.
1545  *
1546  * Return value: a newly allocated #GArray, or %NULL on error of if
1547  *   the set is empty
1548  */
1549 GArray *
1550 gst_vaapi_display_get_subpicture_formats (GstVaapiDisplay * display)
1551 {
1552   g_return_val_if_fail (display != NULL, NULL);
1553
1554   if (!ensure_subpicture_formats (display))
1555     return NULL;
1556   return
1557       get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->subpicture_formats);
1558 }
1559
1560 /**
1561  * gst_vaapi_display_has_subpicture_format:
1562  * @display: a #GstVaapiDisplay
1563  * @format: a #GstVideoFormat
1564  * @flags_ptr: pointer to #GstVaapiSubpictureFlags, or zero
1565  *
1566  * Returns whether VA @display supports @format subpicture format with
1567  * the supplied @flags.
1568  *
1569  * Return value: %TRUE if VA @display supports @format subpicture format
1570  */
1571 gboolean
1572 gst_vaapi_display_has_subpicture_format (GstVaapiDisplay * display,
1573     GstVideoFormat format, guint * flags_ptr)
1574 {
1575   GstVaapiDisplayPrivate *priv;
1576   const GstVaapiFormatInfo *fip;
1577
1578   g_return_val_if_fail (display != NULL, FALSE);
1579   g_return_val_if_fail (format, FALSE);
1580
1581   priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1582
1583   if (!ensure_subpicture_formats (display))
1584     return FALSE;
1585
1586   fip = find_format_info (priv->subpicture_formats, format);
1587   if (!fip)
1588     return FALSE;
1589
1590   if (flags_ptr)
1591     *flags_ptr = fip->flags;
1592   return TRUE;
1593 }
1594
1595 /**
1596  * gst_vaapi_display_has_property:
1597  * @display: a #GstVaapiDisplay
1598  * @name: the property name to check
1599  *
1600  * Returns whether VA @display supports the requested property. The
1601  * check is performed against the property @name. So, the client
1602  * application may perform this check only once and cache this
1603  * information.
1604  *
1605  * Return value: %TRUE if VA @display supports property @name
1606  */
1607 gboolean
1608 gst_vaapi_display_has_property (GstVaapiDisplay * display, const gchar * name)
1609 {
1610   g_return_val_if_fail (display != NULL, FALSE);
1611   g_return_val_if_fail (name, FALSE);
1612
1613   if (!ensure_properties (display))
1614     return FALSE;
1615   return find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties,
1616       name) != NULL;
1617 }
1618
1619 gboolean
1620 gst_vaapi_display_get_property (GstVaapiDisplay * display, const gchar * name,
1621     GValue * out_value)
1622 {
1623   const GstVaapiProperty *prop;
1624
1625   g_return_val_if_fail (display != NULL, FALSE);
1626   g_return_val_if_fail (name != NULL, FALSE);
1627   g_return_val_if_fail (out_value != NULL, FALSE);
1628
1629   if (!ensure_properties (display))
1630     return FALSE;
1631
1632   prop =
1633       find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties, name);
1634   if (!prop)
1635     return FALSE;
1636
1637   switch (prop->attribute.type) {
1638     case VADisplayAttribRenderMode:{
1639       GstVaapiRenderMode mode;
1640       if (!gst_vaapi_display_get_render_mode (display, &mode))
1641         return FALSE;
1642       g_value_init (out_value, GST_VAAPI_TYPE_RENDER_MODE);
1643       g_value_set_enum (out_value, mode);
1644       break;
1645     }
1646     case VADisplayAttribRotation:{
1647       GstVaapiRotation rotation;
1648       rotation = gst_vaapi_display_get_rotation (display);
1649       g_value_init (out_value, GST_VAAPI_TYPE_ROTATION);
1650       g_value_set_enum (out_value, rotation);
1651       break;
1652     }
1653     case VADisplayAttribHue:
1654     case VADisplayAttribSaturation:
1655     case VADisplayAttribBrightness:
1656     case VADisplayAttribContrast:{
1657       gfloat value;
1658       if (!get_color_balance (display, find_property_id (name), &value))
1659         return FALSE;
1660       g_value_init (out_value, G_TYPE_FLOAT);
1661       g_value_set_float (out_value, value);
1662       break;
1663     }
1664     default:
1665       GST_WARNING ("unsupported property '%s'", name);
1666       return FALSE;
1667   }
1668   return TRUE;
1669 }
1670
1671 gboolean
1672 gst_vaapi_display_set_property (GstVaapiDisplay * display, const gchar * name,
1673     const GValue * value)
1674 {
1675   const GstVaapiProperty *prop;
1676
1677   g_return_val_if_fail (display != NULL, FALSE);
1678   g_return_val_if_fail (name != NULL, FALSE);
1679   g_return_val_if_fail (value != NULL, FALSE);
1680
1681   if (!ensure_properties (display))
1682     return FALSE;
1683
1684   prop =
1685       find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties, name);
1686   if (!prop)
1687     return FALSE;
1688
1689   switch (prop->attribute.type) {
1690     case VADisplayAttribRenderMode:{
1691       GstVaapiRenderMode mode;
1692       if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_RENDER_MODE))
1693         return FALSE;
1694       mode = g_value_get_enum (value);
1695       return gst_vaapi_display_set_render_mode (display, mode);
1696     }
1697     case VADisplayAttribRotation:{
1698       GstVaapiRotation rotation;
1699       if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_ROTATION))
1700         return FALSE;
1701       rotation = g_value_get_enum (value);
1702       return gst_vaapi_display_set_rotation (display, rotation);
1703     }
1704     case VADisplayAttribHue:
1705     case VADisplayAttribSaturation:
1706     case VADisplayAttribBrightness:
1707     case VADisplayAttribContrast:{
1708       gfloat v;
1709       if (!G_VALUE_HOLDS (value, G_TYPE_FLOAT))
1710         return FALSE;
1711       v = g_value_get_float (value);
1712       return set_color_balance (display, find_property_id (name), v);
1713     }
1714     default:
1715       break;
1716   }
1717
1718   GST_WARNING ("unsupported property '%s'", name);
1719   return FALSE;
1720 }
1721
1722 static gboolean
1723 get_attribute (GstVaapiDisplay * display, VADisplayAttribType type,
1724     gint * value)
1725 {
1726   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1727   VADisplayAttribute attr = { 0, };
1728   VAStatus status;
1729
1730   attr.type = type;
1731   attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
1732   status = vaGetDisplayAttributes (priv->display, &attr, 1);
1733   if (!vaapi_check_status (status, "vaGetDisplayAttributes()"))
1734     return FALSE;
1735   *value = attr.value;
1736   return TRUE;
1737 }
1738
1739 static gboolean
1740 set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value)
1741 {
1742   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1743   VADisplayAttribute attr = { 0, };
1744   VAStatus status;
1745
1746   attr.type = type;
1747   attr.value = value;
1748   attr.flags = VA_DISPLAY_ATTRIB_SETTABLE;
1749   status = vaSetDisplayAttributes (priv->display, &attr, 1);
1750   if (!vaapi_check_status (status, "vaSetDisplayAttributes()"))
1751     return FALSE;
1752   return TRUE;
1753 }
1754
1755 static gboolean
1756 get_render_mode_VADisplayAttribRenderMode (GstVaapiDisplay * display,
1757     GstVaapiRenderMode * pmode)
1758 {
1759   gint modes, devices;
1760
1761   if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
1762     return FALSE;
1763   if (!devices)
1764     return FALSE;
1765   if (!get_attribute (display, VADisplayAttribRenderMode, &modes))
1766     return FALSE;
1767
1768   /* Favor "overlay" mode since it is the most restrictive one */
1769   if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY | VA_RENDER_MODE_EXTERNAL_OVERLAY))
1770     *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1771   else
1772     *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1773   return TRUE;
1774 }
1775
1776 static gboolean
1777 get_render_mode_VADisplayAttribDirectSurface (GstVaapiDisplay * display,
1778     GstVaapiRenderMode * pmode)
1779 {
1780 #if VA_CHECK_VERSION(0,34,0)
1781   /* VADisplayAttribDirectsurface was removed in VA-API >= 0.34.0 */
1782   return FALSE;
1783 #else
1784   gint direct_surface;
1785
1786   if (!get_attribute (display, VADisplayAttribDirectSurface, &direct_surface))
1787     return FALSE;
1788   if (direct_surface)
1789     *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1790   else
1791     *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1792   return TRUE;
1793 #endif
1794 }
1795
1796 static gboolean
1797 get_render_mode_default (GstVaapiDisplay * display, GstVaapiRenderMode * pmode)
1798 {
1799   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1800
1801   switch (priv->display_type) {
1802 #if USE_WAYLAND
1803     case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
1804       /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */
1805       *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1806       break;
1807 #endif
1808 #if USE_DRM
1809     case GST_VAAPI_DISPLAY_TYPE_DRM:
1810       /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */
1811       *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1812       break;
1813 #endif
1814     default:
1815       /* This includes VA/X11 and VA/GLX modes */
1816       *pmode = DEFAULT_RENDER_MODE;
1817       break;
1818   }
1819   return TRUE;
1820 }
1821
1822 /**
1823  * gst_vaapi_display_get_render_mode:
1824  * @display: a #GstVaapiDisplay
1825  * @pmode: return location for the VA @display rendering mode
1826  *
1827  * Returns the current VA @display rendering mode.
1828  *
1829  * Return value: %TRUE if VA @display rendering mode could be determined
1830  */
1831 gboolean
1832 gst_vaapi_display_get_render_mode (GstVaapiDisplay * display,
1833     GstVaapiRenderMode * pmode)
1834 {
1835   g_return_val_if_fail (display != NULL, FALSE);
1836
1837   /* Try with render-mode attribute */
1838   if (get_render_mode_VADisplayAttribRenderMode (display, pmode))
1839     return TRUE;
1840
1841   /* Try with direct-surface attribute */
1842   if (get_render_mode_VADisplayAttribDirectSurface (display, pmode))
1843     return TRUE;
1844
1845   /* Default: determine from the display type */
1846   return get_render_mode_default (display, pmode);
1847 }
1848
1849 /**
1850  * gst_vaapi_display_set_render_mode:
1851  * @display: a #GstVaapiDisplay
1852  * @mode: the #GstVaapiRenderMode to set
1853  *
1854  * Sets the VA @display rendering mode to the supplied @mode. This
1855  * function returns %FALSE if the rendering mode could not be set,
1856  * e.g. run-time switching rendering mode is not supported.
1857  *
1858  * Return value: %TRUE if VA @display rendering @mode could be changed
1859  *   to the requested value
1860  */
1861 gboolean
1862 gst_vaapi_display_set_render_mode (GstVaapiDisplay * display,
1863     GstVaapiRenderMode mode)
1864 {
1865   gint modes, devices;
1866
1867   g_return_val_if_fail (display != NULL, FALSE);
1868
1869   if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
1870     return FALSE;
1871
1872   modes = 0;
1873   switch (mode) {
1874     case GST_VAAPI_RENDER_MODE_OVERLAY:
1875       if (devices & VA_RENDER_DEVICE_LOCAL)
1876         modes |= VA_RENDER_MODE_LOCAL_OVERLAY;
1877       if (devices & VA_RENDER_DEVICE_EXTERNAL)
1878         modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY;
1879       break;
1880     case GST_VAAPI_RENDER_MODE_TEXTURE:
1881       if (devices & VA_RENDER_DEVICE_LOCAL)
1882         modes |= VA_RENDER_MODE_LOCAL_GPU;
1883       if (devices & VA_RENDER_DEVICE_EXTERNAL)
1884         modes |= VA_RENDER_MODE_EXTERNAL_GPU;
1885       break;
1886   }
1887   if (!modes)
1888     return FALSE;
1889   if (!set_attribute (display, VADisplayAttribRenderMode, modes))
1890     return FALSE;
1891   return TRUE;
1892 }
1893
1894 /**
1895  * gst_vaapi_display_get_rotation:
1896  * @display: a #GstVaapiDisplay
1897  *
1898  * Returns the current VA @display rotation angle. If the VA driver
1899  * does not support "rotation" display attribute, then the display is
1900  * assumed to be un-rotated.
1901  *
1902  * Return value: the current #GstVaapiRotation value
1903  */
1904 GstVaapiRotation
1905 gst_vaapi_display_get_rotation (GstVaapiDisplay * display)
1906 {
1907   gint value;
1908
1909   g_return_val_if_fail (display != NULL, DEFAULT_ROTATION);
1910
1911   if (!get_attribute (display, VADisplayAttribRotation, &value))
1912     value = VA_ROTATION_NONE;
1913   return to_GstVaapiRotation (value);
1914 }
1915
1916 /**
1917  * gst_vaapi_display_set_rotation:
1918  * @display: a #GstVaapiDisplay
1919  * @rotation: the #GstVaapiRotation value to set
1920  *
1921  * Sets the VA @display rotation angle to the supplied @rotation
1922  * value. This function returns %FALSE if the rotation angle could not
1923  * be set, e.g. the VA driver does not allow to change the display
1924  * rotation angle.
1925  *
1926  * Return value: %TRUE if VA @display rotation angle could be changed
1927  *   to the requested value
1928  */
1929 gboolean
1930 gst_vaapi_display_set_rotation (GstVaapiDisplay * display,
1931     GstVaapiRotation rotation)
1932 {
1933   guint value;
1934
1935   g_return_val_if_fail (display != NULL, FALSE);
1936
1937   value = from_GstVaapiRotation (rotation);
1938   if (!set_attribute (display, VADisplayAttribRotation, value))
1939     return FALSE;
1940   return TRUE;
1941 }
1942
1943 /* Get color balance attributes */
1944 static gboolean
1945 get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v)
1946 {
1947   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
1948   const GstVaapiProperty *prop;
1949   const VADisplayAttribute *attr;
1950   gfloat out_value;
1951   gint value;
1952
1953   if (!ensure_properties (display))
1954     return FALSE;
1955
1956   if (!pspec)
1957     return FALSE;
1958
1959   prop = find_property_by_pspec (display, &pspec->parent_instance);
1960   if (!prop)
1961     return FALSE;
1962   attr = &prop->attribute;
1963
1964   if (!get_attribute (display, attr->type, &value))
1965     return FALSE;
1966
1967   /* Scale wrt. the medium ("default") value */
1968   out_value = pspec->default_value;
1969   if (value > attr->value)
1970     out_value += ((gfloat) (value - attr->value) /
1971         (attr->max_value - attr->value) *
1972         (pspec->maximum - pspec->default_value));
1973   else if (value < attr->value)
1974     out_value -= ((gfloat) (attr->value - value) /
1975         (attr->value - attr->min_value) *
1976         (pspec->default_value - pspec->minimum));
1977   *v = out_value;
1978   return TRUE;
1979 }
1980
1981 /* Set color balance attribute */
1982 static gboolean
1983 set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v)
1984 {
1985   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
1986   const GstVaapiProperty *prop;
1987   const VADisplayAttribute *attr;
1988   gint value;
1989
1990   if (!ensure_properties (display))
1991     return FALSE;
1992
1993   if (!pspec)
1994     return FALSE;
1995
1996   prop = find_property_by_pspec (display, &pspec->parent_instance);
1997   if (!prop)
1998     return FALSE;
1999   attr = &prop->attribute;
2000
2001   /* Scale wrt. the medium ("default") value */
2002   value = attr->value;
2003   if (v > pspec->default_value)
2004     value += ((v - pspec->default_value) /
2005         (pspec->maximum - pspec->default_value) *
2006         (attr->max_value - attr->value));
2007   else if (v < pspec->default_value)
2008     value -= ((pspec->default_value - v) /
2009         (pspec->default_value - pspec->minimum) *
2010         (attr->value - attr->min_value));
2011   if (!set_attribute (display, attr->type, value))
2012     return FALSE;
2013   return TRUE;
2014 }
2015
2016 /* Ensures the VA driver vendor string was copied */
2017 static gboolean
2018 ensure_vendor_string (GstVaapiDisplay * display)
2019 {
2020   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
2021   const gchar *vendor_string;
2022
2023   GST_VAAPI_DISPLAY_LOCK (display);
2024   if (!priv->vendor_string) {
2025     vendor_string = vaQueryVendorString (priv->display);
2026     if (vendor_string)
2027       priv->vendor_string = g_strdup (vendor_string);
2028   }
2029   GST_VAAPI_DISPLAY_UNLOCK (display);
2030   return priv->vendor_string != NULL;
2031 }
2032
2033 /**
2034  * gst_vaapi_display_get_vendor_string:
2035  * @display: a #GstVaapiDisplay
2036  *
2037  * Returns the VA driver vendor string attached to the supplied VA @display.
2038  * The @display owns the vendor string, do *not* de-allocate it.
2039  *
2040  * This function is thread safe.
2041  *
2042  * Return value: the current #GstVaapiRotation value
2043  */
2044 const gchar *
2045 gst_vaapi_display_get_vendor_string (GstVaapiDisplay * display)
2046 {
2047   g_return_val_if_fail (display != NULL, NULL);
2048
2049   if (!ensure_vendor_string (display))
2050     return NULL;
2051   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->vendor_string;
2052 }
2053
2054 /**
2055  * gst_vaapi_display_has_opengl:
2056  * @display: a #GstVaapiDisplay
2057  *
2058  * Returns wether the @display that was created does support OpenGL
2059  * context to be attached.
2060  *
2061  * This function is thread safe.
2062  *
2063  * Return value: %TRUE if the @display supports OpenGL context, %FALSE
2064  *   otherwise
2065  */
2066 gboolean
2067 gst_vaapi_display_has_opengl (GstVaapiDisplay * display)
2068 {
2069   GstVaapiDisplayClass *klass;
2070
2071   g_return_val_if_fail (display != NULL, FALSE);
2072
2073   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
2074   return (klass->display_type == GST_VAAPI_DISPLAY_TYPE_GLX ||
2075       klass->display_type == GST_VAAPI_DISPLAY_TYPE_EGL);
2076 }
2077
2078 /**
2079  * gst_vaapi_display_reset_texture_map:
2080  * @display: a #GstVaapiDisplay
2081  *
2082  * Reset the internal #GstVaapiTextureMap if available.
2083  *
2084  * This function is thread safe.
2085  */
2086 void
2087 gst_vaapi_display_reset_texture_map (GstVaapiDisplay * display)
2088 {
2089   GstVaapiDisplayClass *klass;
2090   GstVaapiTextureMap *map;
2091
2092   g_return_if_fail (display != NULL);
2093
2094   if (!gst_vaapi_display_has_opengl (display))
2095     return;
2096   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
2097   if (!klass->get_texture_map)
2098     return;
2099   if ((map = klass->get_texture_map (display)))
2100     gst_vaapi_texture_map_reset (map);
2101 }