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