Fix build without X11.
[profile/ivi/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidisplay.c
1 /*
2  *  gstvaapidisplay.c - VA display abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011-2012 Intel Corporation
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22
23 /**
24  * SECTION:gstvaapidisplay
25  * @short_description: VA display abstraction
26  */
27
28 #include "sysdeps.h"
29 #include <string.h>
30 #include "gstvaapiutils.h"
31 #include "gstvaapidisplay.h"
32 #include "gstvaapidisplay_priv.h"
33 #include "gstvaapiworkarounds.h"
34
35 #define DEBUG 1
36 #include "gstvaapidebug.h"
37
38 GST_DEBUG_CATEGORY(gst_debug_vaapi);
39
40 G_DEFINE_TYPE(GstVaapiDisplay, gst_vaapi_display, G_TYPE_OBJECT);
41
42 typedef struct _GstVaapiConfig GstVaapiConfig;
43 struct _GstVaapiConfig {
44     GstVaapiProfile     profile;
45     GstVaapiEntrypoint  entrypoint;
46 };
47
48 enum {
49     PROP_0,
50
51     PROP_DISPLAY,
52     PROP_DISPLAY_TYPE,
53     PROP_WIDTH,
54     PROP_HEIGHT
55 };
56
57 static GstVaapiDisplayCache *g_display_cache = NULL;
58
59 static inline GstVaapiDisplayCache *
60 get_display_cache(void)
61 {
62     if (!g_display_cache)
63         g_display_cache = gst_vaapi_display_cache_new();
64     return g_display_cache;
65 }
66
67 GstVaapiDisplayCache *
68 gst_vaapi_display_get_cache(void)
69 {
70     return get_display_cache();
71 }
72
73 static void
74 free_display_cache(void)
75 {
76     if (!g_display_cache)
77         return;
78     if (gst_vaapi_display_cache_get_size(g_display_cache) > 0)
79         return;
80     gst_vaapi_display_cache_free(g_display_cache);
81     g_display_cache = NULL;
82 }
83
84 /* GstVaapiDisplayType enumerations */
85 GType
86 gst_vaapi_display_type_get_type(void)
87 {
88     static GType g_type = 0;
89
90     static const GEnumValue display_types[] = {
91         { GST_VAAPI_DISPLAY_TYPE_ANY,
92           "Auto detection", "any" },
93 #if USE_X11
94         { GST_VAAPI_DISPLAY_TYPE_X11,
95           "VA/X11 display", "x11" },
96 #endif
97 #if USE_GLX
98         { GST_VAAPI_DISPLAY_TYPE_GLX,
99           "VA/GLX display", "glx" },
100 #endif
101 #if USE_WAYLAND
102         { GST_VAAPI_DISPLAY_TYPE_WAYLAND,
103           "VA/Wayland display", "wayland" },
104 #endif
105         { 0, NULL, NULL },
106     };
107
108     if (!g_type)
109         g_type = g_enum_register_static("GstVaapiDisplayType", display_types);
110     return g_type;
111 }
112
113 /* Append GstVaapiImageFormat to formats array */
114 static inline void
115 append_format(GArray *formats, GstVaapiImageFormat format)
116 {
117     g_array_append_val(formats, format);
118 }
119
120 /* Append VAImageFormats to formats array */
121 static void
122 append_formats(GArray *formats, const VAImageFormat *va_formats, guint n)
123 {
124     GstVaapiImageFormat format;
125     gboolean has_YV12 = FALSE;
126     gboolean has_I420 = FALSE;
127     guint i;
128
129     for (i = 0; i < n; i++) {
130         const VAImageFormat * const va_format = &va_formats[i];
131
132         format = gst_vaapi_image_format(va_format);
133         if (!format) {
134             GST_DEBUG("unsupported format %" GST_FOURCC_FORMAT,
135                       GST_FOURCC_ARGS(va_format->fourcc));
136             continue;
137         }
138
139         switch (format) {
140         case GST_VAAPI_IMAGE_YV12:
141             has_YV12 = TRUE;
142             break;
143         case GST_VAAPI_IMAGE_I420:
144             has_I420 = TRUE;
145             break;
146         default:
147             break;
148         }
149         append_format(formats, format);
150     }
151
152     /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
153        supported by the underlying driver */
154     if (has_YV12 && !has_I420)
155         append_format(formats, GST_VAAPI_IMAGE_I420);
156     else if (has_I420 && !has_YV12)
157         append_format(formats, GST_VAAPI_IMAGE_YV12);
158 }
159
160 /* Sort image formats. Prefer YUV formats first */
161 static gint
162 compare_yuv_formats(gconstpointer a, gconstpointer b)
163 {
164     const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
165     const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
166
167     const gboolean is_fmt1_yuv = gst_vaapi_image_format_is_yuv(fmt1);
168     const gboolean is_fmt2_yuv = gst_vaapi_image_format_is_yuv(fmt2);
169
170     if (is_fmt1_yuv != is_fmt2_yuv)
171         return is_fmt1_yuv ? -1 : 1;
172
173     return ((gint)gst_vaapi_image_format_get_score(fmt1) -
174             (gint)gst_vaapi_image_format_get_score(fmt2));
175 }
176
177 /* Sort subpicture formats. Prefer RGB formats first */
178 static gint
179 compare_rgb_formats(gconstpointer a, gconstpointer b)
180 {
181     const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
182     const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
183
184     const gboolean is_fmt1_rgb = gst_vaapi_image_format_is_rgb(fmt1);
185     const gboolean is_fmt2_rgb = gst_vaapi_image_format_is_rgb(fmt2);
186
187     if (is_fmt1_rgb != is_fmt2_rgb)
188         return is_fmt1_rgb ? -1 : 1;
189
190     return ((gint)gst_vaapi_image_format_get_score(fmt1) -
191             (gint)gst_vaapi_image_format_get_score(fmt2));
192 }
193
194 /* Check if configs array contains profile at entrypoint */
195 static inline gboolean
196 find_config(
197     GArray             *configs,
198     GstVaapiProfile     profile,
199     GstVaapiEntrypoint  entrypoint
200 )
201 {
202     GstVaapiConfig *config;
203     guint i;
204
205     if (!configs)
206         return FALSE;
207
208     for (i = 0; i < configs->len; i++) {
209         config = &g_array_index(configs, GstVaapiConfig, i);
210         if (config->profile == profile && config->entrypoint == entrypoint)
211             return TRUE;
212     }
213     return FALSE;
214 }
215
216 /* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */
217 static void
218 append_h263_config(GArray *configs)
219 {
220     GstVaapiConfig *config, tmp_config;
221     GstVaapiConfig *mpeg4_simple_config = NULL;
222     GstVaapiConfig *h263_baseline_config = NULL;
223     guint i;
224
225     if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE)
226         return;
227
228     if (!configs)
229         return;
230
231     for (i = 0; i < configs->len; i++) {
232         config = &g_array_index(configs, GstVaapiConfig, i);
233         if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE)
234             mpeg4_simple_config = config;
235         else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE)
236             h263_baseline_config = config;
237     }
238
239     if (mpeg4_simple_config && !h263_baseline_config) {
240         tmp_config = *mpeg4_simple_config;
241         tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE;
242         g_array_append_val(configs, tmp_config);
243     }
244 }
245
246 /* Convert configs array to profiles as GstCaps */
247 static GstCaps *
248 get_profile_caps(GArray *configs)
249 {
250     GstVaapiConfig *config;
251     GstCaps *out_caps, *caps;
252     guint i;
253
254     if (!configs)
255         return NULL;
256
257     out_caps = gst_caps_new_empty();
258     if (!out_caps)
259         return NULL;
260
261     for (i = 0; i < configs->len; i++) {
262         config = &g_array_index(configs, GstVaapiConfig, i);
263         caps   = gst_vaapi_profile_get_caps(config->profile);
264         if (caps)
265             gst_caps_merge(out_caps, caps);
266     }
267     return out_caps;
268 }
269
270 /* Check if formats array contains format */
271 static inline gboolean
272 find_format(GArray *formats, GstVaapiImageFormat format)
273 {
274     guint i;
275
276     for (i = 0; i < formats->len; i++)
277         if (g_array_index(formats, GstVaapiImageFormat, i) == format)
278             return TRUE;
279     return FALSE;
280 }
281
282 /* Convert formats array to GstCaps */
283 static GstCaps *
284 get_format_caps(GArray *formats)
285 {
286     GstVaapiImageFormat format;
287     GstCaps *out_caps, *caps;
288     guint i;
289
290     out_caps = gst_caps_new_empty();
291     if (!out_caps)
292         return NULL;
293
294     for (i = 0; i < formats->len; i++) {
295         format = g_array_index(formats, GstVaapiImageFormat, i);
296         caps   = gst_vaapi_image_format_get_caps(format);
297         if (caps)
298             gst_caps_append(out_caps, caps);
299     }
300     return out_caps;
301 }
302
303 static void
304 gst_vaapi_display_calculate_pixel_aspect_ratio(GstVaapiDisplay *display)
305 {
306     GstVaapiDisplayPrivate * const priv = display->priv;
307     gdouble ratio, delta;
308     gint i, index;
309
310     static const gint par[][2] = {
311         {1, 1},         /* regular screen            */
312         {16, 15},       /* PAL TV                    */
313         {11, 10},       /* 525 line Rec.601 video    */
314         {54, 59},       /* 625 line Rec.601 video    */
315         {64, 45},       /* 1280x1024 on 16:9 display */
316         {5, 3},         /* 1280x1024 on  4:3 display */
317         {4, 3}          /*  800x600  on 16:9 display */
318     };
319
320     /* First, calculate the "real" ratio based on the X values;
321      * which is the "physical" w/h divided by the w/h in pixels of the
322      * display */
323     if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm)
324         ratio = 1.0;
325     else
326         ratio = (gdouble)(priv->width_mm * priv->height) /
327             (priv->height_mm * priv->width);
328     GST_DEBUG("calculated pixel aspect ratio: %f", ratio);
329
330     /* Now, find the one from par[][2] with the lowest delta to the real one */
331 #define DELTA(idx) (ABS(ratio - ((gdouble)par[idx][0] / par[idx][1])))
332     delta = DELTA(0);
333     index = 0;
334
335     for (i = 1; i < G_N_ELEMENTS(par); i++) {
336         const gdouble this_delta = DELTA(i);
337         if (this_delta < delta) {
338             index = i;
339             delta = this_delta;
340         }
341     }
342 #undef DELTA
343
344     priv->par_n = par[index][0];
345     priv->par_d = par[index][1];
346 }
347
348 static void
349 gst_vaapi_display_destroy(GstVaapiDisplay *display)
350 {
351     GstVaapiDisplayPrivate * const priv = display->priv;
352
353     if (priv->decoders) {
354         g_array_free(priv->decoders, TRUE);
355         priv->decoders = NULL;
356     }
357
358     if (priv->encoders) {
359         g_array_free(priv->encoders, TRUE);
360         priv->encoders = NULL;
361     }
362
363     if (priv->image_formats) {
364         g_array_free(priv->image_formats, TRUE);
365         priv->image_formats = NULL;
366     }
367
368     if (priv->subpicture_formats) {
369         g_array_free(priv->subpicture_formats, TRUE);
370         priv->subpicture_formats = NULL;
371     }
372
373     if (priv->display) {
374         if (!priv->parent)
375             vaTerminate(priv->display);
376         priv->display = NULL;
377     }
378
379     if (priv->create_display) {
380         GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
381         if (klass->close_display)
382             klass->close_display(display);
383     }
384
385     g_clear_object(&priv->parent);
386
387     if (g_display_cache) {
388         gst_vaapi_display_cache_remove(get_display_cache(), display);
389         free_display_cache();
390     }
391 }
392
393 static gboolean
394 gst_vaapi_display_create(GstVaapiDisplay *display)
395 {
396     GstVaapiDisplayPrivate * const priv = display->priv;
397     GstVaapiDisplayCache *cache;
398     gboolean            has_errors      = TRUE;
399     VAProfile          *profiles        = NULL;
400     VAEntrypoint       *entrypoints     = NULL;
401     VAImageFormat      *formats         = NULL;
402     unsigned int       *flags           = NULL;
403     gint                i, j, n, num_entrypoints, major_version, minor_version;
404     VAStatus            status;
405     GstVaapiDisplayInfo info;
406     const GstVaapiDisplayInfo *cached_info = NULL;
407
408     memset(&info, 0, sizeof(info));
409     info.display = display;
410     info.display_type = priv->display_type;
411
412     if (priv->display)
413         info.va_display = priv->display;
414     else if (priv->create_display) {
415         GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
416         if (klass->open_display && !klass->open_display(display))
417             return FALSE;
418         if (!klass->get_display || !klass->get_display(display, &info))
419             return FALSE;
420         priv->display = info.va_display;
421         priv->display_type = info.display_type;
422         if (klass->get_size)
423             klass->get_size(display, &priv->width, &priv->height);
424         if (klass->get_size_mm)
425             klass->get_size_mm(display, &priv->width_mm, &priv->height_mm);
426         gst_vaapi_display_calculate_pixel_aspect_ratio(display);
427     }
428     if (!priv->display)
429         return FALSE;
430
431     cache = get_display_cache();
432     if (!cache)
433         return FALSE;
434     cached_info = gst_vaapi_display_cache_lookup_by_va_display(
435         cache,
436         info.va_display
437     );
438     if (cached_info) {
439         g_clear_object(&priv->parent);
440         priv->parent = g_object_ref(cached_info->display);
441         priv->display_type = cached_info->display_type;
442     }
443
444     if (!priv->parent) {
445         status = vaInitialize(priv->display, &major_version, &minor_version);
446         if (!vaapi_check_status(status, "vaInitialize()"))
447             goto end;
448         GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
449     }
450
451     /* VA profiles */
452     profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display));
453     if (!profiles)
454         goto end;
455     entrypoints = g_new(VAEntrypoint, vaMaxNumEntrypoints(priv->display));
456     if (!entrypoints)
457         goto end;
458     status = vaQueryConfigProfiles(priv->display, profiles, &n);
459     if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
460         goto end;
461
462     GST_DEBUG("%d profiles", n);
463     for (i = 0; i < n; i++)
464         GST_DEBUG("  %s", string_of_VAProfile(profiles[i]));
465
466     priv->decoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig));
467     if (!priv->decoders)
468         goto end;
469     priv->encoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig));
470     if (!priv->encoders)
471         goto end;
472
473     for (i = 0; i < n; i++) {
474         GstVaapiConfig config;
475
476         config.profile = gst_vaapi_profile(profiles[i]);
477         if (!config.profile)
478             continue;
479
480         status = vaQueryConfigEntrypoints(
481             priv->display,
482             profiles[i],
483             entrypoints, &num_entrypoints
484         );
485         if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()"))
486             continue;
487
488         for (j = 0; j < num_entrypoints; j++) {
489             config.entrypoint = gst_vaapi_entrypoint(entrypoints[j]);
490             switch (config.entrypoint) {
491             case GST_VAAPI_ENTRYPOINT_VLD:
492             case GST_VAAPI_ENTRYPOINT_IDCT:
493             case GST_VAAPI_ENTRYPOINT_MOCO:
494                 g_array_append_val(priv->decoders, config);
495                 break;
496             case GST_VAAPI_ENTRYPOINT_SLICE_ENCODE:
497                 g_array_append_val(priv->encoders, config);
498                 break;
499             }
500         }
501     }
502     append_h263_config(priv->decoders);
503
504     /* VA image formats */
505     formats = g_new(VAImageFormat, vaMaxNumImageFormats(priv->display));
506     if (!formats)
507         goto end;
508     status = vaQueryImageFormats(priv->display, formats, &n);
509     if (!vaapi_check_status(status, "vaQueryImageFormats()"))
510         goto end;
511
512     GST_DEBUG("%d image formats", n);
513     for (i = 0; i < n; i++)
514         GST_DEBUG("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc));
515
516     priv->image_formats =
517         g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
518     if (!priv->image_formats)
519         goto end;
520     append_formats(priv->image_formats, formats, n);
521     g_array_sort(priv->image_formats, compare_yuv_formats);
522
523     /* VA subpicture formats */
524     n = vaMaxNumSubpictureFormats(priv->display);
525     formats = g_renew(VAImageFormat, formats, n);
526     flags   = g_new(guint, n);
527     if (!formats || !flags)
528         goto end;
529     status = vaQuerySubpictureFormats(priv->display, formats, flags, (guint *)&n);
530     if (!vaapi_check_status(status, "vaQuerySubpictureFormats()"))
531         goto end;
532
533     GST_DEBUG("%d subpicture formats", n);
534     for (i = 0; i < n; i++)
535         GST_DEBUG("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc));
536
537     priv->subpicture_formats =
538         g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
539     if (!priv->subpicture_formats)
540         goto end;
541     append_formats(priv->subpicture_formats, formats, n);
542     g_array_sort(priv->subpicture_formats, compare_rgb_formats);
543
544     if (!cached_info) {
545         if (!gst_vaapi_display_cache_add(cache, &info))
546             goto end;
547     }
548
549     has_errors = FALSE;
550 end:
551     g_free(profiles);
552     g_free(entrypoints);
553     g_free(formats);
554     g_free(flags);
555     return !has_errors;
556 }
557
558 static void
559 gst_vaapi_display_lock_default(GstVaapiDisplay *display)
560 {
561     GstVaapiDisplayPrivate *priv = display->priv;
562
563     if (priv->parent)
564         priv = priv->parent->priv;
565     g_static_rec_mutex_lock(&priv->mutex);
566 }
567
568 static void
569 gst_vaapi_display_unlock_default(GstVaapiDisplay *display)
570 {
571     GstVaapiDisplayPrivate *priv = display->priv;
572
573     if (priv->parent)
574         priv = priv->parent->priv;
575     g_static_rec_mutex_unlock(&priv->mutex);
576 }
577
578 static void
579 gst_vaapi_display_finalize(GObject *object)
580 {
581     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
582
583     gst_vaapi_display_destroy(display);
584
585     g_static_rec_mutex_free(&display->priv->mutex);
586
587     G_OBJECT_CLASS(gst_vaapi_display_parent_class)->finalize(object);
588 }
589
590 static void
591 gst_vaapi_display_set_property(
592     GObject      *object,
593     guint         prop_id,
594     const GValue *value,
595     GParamSpec   *pspec
596 )
597 {
598     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
599
600     switch (prop_id) {
601     case PROP_DISPLAY:
602         display->priv->display = g_value_get_pointer(value);
603         break;
604     case PROP_DISPLAY_TYPE:
605         display->priv->display_type = g_value_get_enum(value);
606         break;
607     default:
608         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
609         break;
610     }
611 }
612
613 static void
614 gst_vaapi_display_get_property(
615     GObject    *object,
616     guint       prop_id,
617     GValue     *value,
618     GParamSpec *pspec
619 )
620 {
621     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
622
623     switch (prop_id) {
624     case PROP_DISPLAY:
625         g_value_set_pointer(value, gst_vaapi_display_get_display(display));
626         break;
627     case PROP_DISPLAY_TYPE:
628         g_value_set_enum(value, gst_vaapi_display_get_display_type(display));
629         break;
630     case PROP_WIDTH:
631         g_value_set_uint(value, gst_vaapi_display_get_width(display));
632         break;
633     case PROP_HEIGHT:
634         g_value_set_uint(value, gst_vaapi_display_get_height(display));
635         break;
636     default:
637         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
638         break;
639     }
640 }
641
642 static void
643 gst_vaapi_display_constructed(GObject *object)
644 {
645     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
646     GObjectClass *parent_class;
647
648     display->priv->create_display = display->priv->display == NULL;
649     if (!gst_vaapi_display_create(display))
650         gst_vaapi_display_destroy(display);
651
652     parent_class = G_OBJECT_CLASS(gst_vaapi_display_parent_class);
653     if (parent_class->constructed)
654         parent_class->constructed(object);
655 }
656
657 static void
658 gst_vaapi_display_class_init(GstVaapiDisplayClass *klass)
659 {
660     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
661     GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
662
663     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi, "vaapi", 0, "VA-API helper");
664
665     g_type_class_add_private(klass, sizeof(GstVaapiDisplayPrivate));
666
667     object_class->finalize      = gst_vaapi_display_finalize;
668     object_class->set_property  = gst_vaapi_display_set_property;
669     object_class->get_property  = gst_vaapi_display_get_property;
670     object_class->constructed   = gst_vaapi_display_constructed;
671
672     dpy_class->lock             = gst_vaapi_display_lock_default;
673     dpy_class->unlock           = gst_vaapi_display_unlock_default;
674
675     g_object_class_install_property
676         (object_class,
677          PROP_DISPLAY,
678          g_param_spec_pointer("display",
679                               "VA display",
680                               "VA display",
681                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
682
683     g_object_class_install_property
684         (object_class,
685          PROP_DISPLAY_TYPE,
686          g_param_spec_enum("display-type",
687                            "VA display type",
688                            "VA display type",
689                            GST_VAAPI_TYPE_DISPLAY_TYPE,
690                            GST_VAAPI_DISPLAY_TYPE_ANY,
691                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
692
693     g_object_class_install_property
694         (object_class,
695          PROP_WIDTH,
696          g_param_spec_uint("width",
697                            "Width",
698                            "The display width",
699                            1, G_MAXUINT32, 1,
700                            G_PARAM_READABLE));
701
702     g_object_class_install_property
703         (object_class,
704          PROP_HEIGHT,
705          g_param_spec_uint("height",
706                            "height",
707                            "The display height",
708                            1, G_MAXUINT32, 1,
709                            G_PARAM_READABLE));
710 }
711
712 static void
713 gst_vaapi_display_init(GstVaapiDisplay *display)
714 {
715     GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display);
716
717     display->priv               = priv;
718     priv->parent                = NULL;
719     priv->display_type          = GST_VAAPI_DISPLAY_TYPE_ANY;
720     priv->display               = NULL;
721     priv->width                 = 0;
722     priv->height                = 0;
723     priv->width_mm              = 0;
724     priv->height_mm             = 0;
725     priv->par_n                 = 1;
726     priv->par_d                 = 1;
727     priv->decoders              = NULL;
728     priv->encoders              = NULL;
729     priv->image_formats         = NULL;
730     priv->subpicture_formats    = NULL;
731     priv->create_display        = TRUE;
732
733     g_static_rec_mutex_init(&priv->mutex);
734 }
735
736 /**
737  * gst_vaapi_display_new_with_display:
738  * @va_display: a #VADisplay
739  *
740  * Creates a new #GstVaapiDisplay, using @va_display as the VA
741  * display.
742  *
743  * Return value: the newly created #GstVaapiDisplay object
744  */
745 GstVaapiDisplay *
746 gst_vaapi_display_new_with_display(VADisplay va_display)
747 {
748     GstVaapiDisplayCache * const cache = get_display_cache();
749     const GstVaapiDisplayInfo *info;
750
751     g_return_val_if_fail(va_display != NULL, NULL);
752     g_return_val_if_fail(cache != NULL, NULL);
753
754     info = gst_vaapi_display_cache_lookup_by_va_display(cache, va_display);
755     if (info)
756         return g_object_ref(info->display);
757
758     return g_object_new(GST_VAAPI_TYPE_DISPLAY,
759                         "display", va_display,
760                         NULL);
761 }
762
763 /**
764  * gst_vaapi_display_lock:
765  * @display: a #GstVaapiDisplay
766  *
767  * Locks @display. If @display is already locked by another thread,
768  * the current thread will block until @display is unlocked by the
769  * other thread.
770  */
771 void
772 gst_vaapi_display_lock(GstVaapiDisplay *display)
773 {
774     GstVaapiDisplayClass *klass;
775
776     g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
777
778     klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
779     if (klass->lock)
780         klass->lock(display);
781 }
782
783 /**
784  * gst_vaapi_display_unlock:
785  * @display: a #GstVaapiDisplay
786  *
787  * Unlocks @display. If another thread is blocked in a
788  * gst_vaapi_display_lock() call for @display, it will be woken and
789  * can lock @display itself.
790  */
791 void
792 gst_vaapi_display_unlock(GstVaapiDisplay *display)
793 {
794     GstVaapiDisplayClass *klass;
795
796     g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
797
798     klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
799     if (klass->unlock)
800         klass->unlock(display);
801 }
802
803 /**
804  * gst_vaapi_display_sync:
805  * @display: a #GstVaapiDisplay
806  *
807  * Flushes any requests queued for the windowing system and waits until
808  * all requests have been handled. This is often used for making sure
809  * that the display is synchronized with the current state of the program.
810  *
811  * This is most useful for X11. On windowing systems where requests are
812  * handled synchronously, this function will do nothing.
813  */
814 void
815 gst_vaapi_display_sync(GstVaapiDisplay *display)
816 {
817     GstVaapiDisplayClass *klass;
818
819     g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
820
821     klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
822     if (klass->sync)
823         klass->sync(display);
824     else if (klass->flush)
825         klass->flush(display);
826 }
827
828 /**
829  * gst_vaapi_display_flush:
830  * @display: a #GstVaapiDisplay
831  *
832  * Flushes any requests queued for the windowing system.
833  *
834  * This is most useful for X11. On windowing systems where requests
835  * are handled synchronously, this function will do nothing.
836  */
837 void
838 gst_vaapi_display_flush(GstVaapiDisplay *display)
839 {
840     GstVaapiDisplayClass *klass;
841
842     g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
843
844     klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
845     if (klass->flush)
846         klass->flush(display);
847 }
848
849 /**
850  * gst_vaapi_display_get_display:
851  * @display: a #GstVaapiDisplay
852  *
853  * Returns the #GstVaapiDisplayType bound to @display.
854  *
855  * Return value: the #GstVaapiDisplayType
856  */
857 GstVaapiDisplayType
858 gst_vaapi_display_get_display_type(GstVaapiDisplay *display)
859 {
860     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display),
861                          GST_VAAPI_DISPLAY_TYPE_ANY);
862
863     return display->priv->display_type;
864 }
865
866 /**
867  * gst_vaapi_display_get_display:
868  * @display: a #GstVaapiDisplay
869  *
870  * Returns the #VADisplay bound to @display.
871  *
872  * Return value: the #VADisplay
873  */
874 VADisplay
875 gst_vaapi_display_get_display(GstVaapiDisplay *display)
876 {
877     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
878
879     return display->priv->display;
880 }
881
882 /**
883  * gst_vaapi_display_get_width:
884  * @display: a #GstVaapiDisplay
885  *
886  * Retrieves the width of a #GstVaapiDisplay.
887  *
888  * Return value: the width of the @display, in pixels
889  */
890 guint
891 gst_vaapi_display_get_width(GstVaapiDisplay *display)
892 {
893     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
894
895     return display->priv->width;
896 }
897
898 /**
899  * gst_vaapi_display_get_height:
900  * @display: a #GstVaapiDisplay
901  *
902  * Retrieves the height of a #GstVaapiDisplay
903  *
904  * Return value: the height of the @display, in pixels
905  */
906 guint
907 gst_vaapi_display_get_height(GstVaapiDisplay *display)
908 {
909     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
910
911     return display->priv->height;
912 }
913
914 /**
915  * gst_vaapi_display_get_size:
916  * @display: a #GstVaapiDisplay
917  * @pwidth: return location for the width, or %NULL
918  * @pheight: return location for the height, or %NULL
919  *
920  * Retrieves the dimensions of a #GstVaapiDisplay.
921  */
922 void
923 gst_vaapi_display_get_size(GstVaapiDisplay *display, guint *pwidth, guint *pheight)
924 {
925     g_return_if_fail(GST_VAAPI_DISPLAY(display));
926
927     if (pwidth)
928         *pwidth = display->priv->width;
929
930     if (pheight)
931         *pheight = display->priv->height;
932 }
933
934 /**
935  * gst_vaapi_display_get_pixel_aspect_ratio:
936  * @display: a #GstVaapiDisplay
937  * @par_n: return location for the numerator of pixel aspect ratio, or %NULL
938  * @par_d: return location for the denominator of pixel aspect ratio, or %NULL
939  *
940  * Retrieves the pixel aspect ratio of a #GstVaapiDisplay.
941  */
942 void
943 gst_vaapi_display_get_pixel_aspect_ratio(
944     GstVaapiDisplay *display,
945     guint           *par_n,
946     guint           *par_d
947 )
948 {
949     g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
950
951     if (par_n)
952         *par_n = display->priv->par_n;
953
954     if (par_d)
955         *par_d = display->priv->par_d;
956 }
957
958 /**
959  * gst_vaapi_display_get_decode_caps:
960  * @display: a #GstVaapiDisplay
961  *
962  * Gets the supported profiles for decoding as #GstCaps capabilities.
963  *
964  * Return value: a newly allocated #GstCaps object, possibly empty
965  */
966 GstCaps *
967 gst_vaapi_display_get_decode_caps(GstVaapiDisplay *display)
968 {
969     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
970
971     return get_profile_caps(display->priv->decoders);
972 }
973
974 /**
975  * gst_vaapi_display_has_decoder:
976  * @display: a #GstVaapiDisplay
977  * @profile: a #VAProfile
978  * @entrypoint: a #GstVaaiEntrypoint
979  *
980  * Returns whether VA @display supports @profile for decoding at the
981  * specified @entrypoint.
982  *
983  * Return value: %TRUE if VA @display supports @profile for decoding.
984  */
985 gboolean
986 gst_vaapi_display_has_decoder(
987     GstVaapiDisplay    *display,
988     GstVaapiProfile     profile,
989     GstVaapiEntrypoint  entrypoint
990 )
991 {
992     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
993
994     return find_config(display->priv->decoders, profile, entrypoint);
995 }
996
997 /**
998  * gst_vaapi_display_get_encode_caps:
999  * @display: a #GstVaapiDisplay
1000  *
1001  * Gets the supported profiles for decoding as #GstCaps capabilities.
1002  *
1003  * Return value: a newly allocated #GstCaps object, possibly empty
1004  */
1005 GstCaps *
1006 gst_vaapi_display_get_encode_caps(GstVaapiDisplay *display)
1007 {
1008     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1009
1010     return get_profile_caps(display->priv->encoders);
1011 }
1012
1013 /**
1014  * gst_vaapi_display_has_encoder:
1015  * @display: a #GstVaapiDisplay
1016  * @profile: a #VAProfile
1017  * @entrypoint: a #GstVaapiEntrypoint
1018  *
1019  * Returns whether VA @display supports @profile for encoding at the
1020  * specified @entrypoint.
1021  *
1022  * Return value: %TRUE if VA @display supports @profile for encoding.
1023  */
1024 gboolean
1025 gst_vaapi_display_has_encoder(
1026     GstVaapiDisplay    *display,
1027     GstVaapiProfile     profile,
1028     GstVaapiEntrypoint  entrypoint
1029 )
1030 {
1031     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1032
1033     return find_config(display->priv->encoders, profile, entrypoint);
1034 }
1035
1036 /**
1037  * gst_vaapi_display_get_image_caps:
1038  * @display: a #GstVaapiDisplay
1039  *
1040  * Gets the supported image formats for gst_vaapi_surface_get_image()
1041  * or gst_vaapi_surface_put_image() as #GstCaps capabilities.
1042  *
1043  * Note that this method does not necessarily map image formats
1044  * returned by vaQueryImageFormats(). The set of capabilities can be
1045  * stripped down, if gstreamer-vaapi does not support the format, or
1046  * expanded to cover compatible formats not exposed by the underlying
1047  * driver. e.g. I420 can be supported even if the driver only exposes
1048  * YV12.
1049  *
1050  * Return value: a newly allocated #GstCaps object, possibly empty
1051  */
1052 GstCaps *
1053 gst_vaapi_display_get_image_caps(GstVaapiDisplay *display)
1054 {
1055     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1056
1057     return get_format_caps(display->priv->image_formats);
1058 }
1059
1060 /**
1061  * gst_vaapi_display_has_image_format:
1062  * @display: a #GstVaapiDisplay
1063  * @format: a #GstVaapiFormat
1064  *
1065  * Returns whether VA @display supports @format image format.
1066  *
1067  * Return value: %TRUE if VA @display supports @format image format
1068  */
1069 gboolean
1070 gst_vaapi_display_has_image_format(
1071     GstVaapiDisplay    *display,
1072     GstVaapiImageFormat format
1073 )
1074 {
1075     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1076     g_return_val_if_fail(format, FALSE);
1077
1078     if (find_format(display->priv->image_formats, format))
1079         return TRUE;
1080
1081     /* XXX: try subpicture formats since some drivers could report a
1082      * set of VA image formats that is not a superset of the set of VA
1083      * subpicture formats
1084      */
1085     return find_format(display->priv->subpicture_formats, format);
1086 }
1087
1088 /**
1089  * gst_vaapi_display_get_subpicture_caps:
1090  * @display: a #GstVaapiDisplay
1091  *
1092  * Gets the supported subpicture formats as #GstCaps capabilities.
1093  *
1094  * Note that this method does not necessarily map subpicture formats
1095  * returned by vaQuerySubpictureFormats(). The set of capabilities can
1096  * be stripped down if gstreamer-vaapi does not support the
1097  * format. e.g. this is the case for paletted formats like IA44.
1098  *
1099  * Return value: a newly allocated #GstCaps object, possibly empty
1100  */
1101 GstCaps *
1102 gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display)
1103 {
1104     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1105
1106     return get_format_caps(display->priv->subpicture_formats);
1107 }
1108
1109 /**
1110  * gst_vaapi_display_has_subpicture_format:
1111  * @display: a #GstVaapiDisplay
1112  * @format: a #GstVaapiFormat
1113  *
1114  * Returns whether VA @display supports @format subpicture format.
1115  *
1116  * Return value: %TRUE if VA @display supports @format subpicture format
1117  */
1118 gboolean
1119 gst_vaapi_display_has_subpicture_format(
1120     GstVaapiDisplay    *display,
1121     GstVaapiImageFormat format
1122 )
1123 {
1124     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1125     g_return_val_if_fail(format, FALSE);
1126
1127     return find_format(display->priv->subpicture_formats, format);
1128 }