2 * gstvaapidisplay.c - VA display abstraction
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2012 Intel Corporation
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.
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.
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
24 * SECTION:gstvaapidisplay
25 * @short_description: VA display abstraction
30 #include "gstvaapiutils.h"
31 #include "gstvaapivalue.h"
32 #include "gstvaapidisplay.h"
33 #include "gstvaapidisplay_priv.h"
34 #include "gstvaapiworkarounds.h"
37 #include "gstvaapidebug.h"
39 GST_DEBUG_CATEGORY(gst_debug_vaapi);
41 G_DEFINE_TYPE(GstVaapiDisplay, gst_vaapi_display, G_TYPE_OBJECT)
43 typedef struct _GstVaapiConfig GstVaapiConfig;
44 struct _GstVaapiConfig {
45 GstVaapiProfile profile;
46 GstVaapiEntrypoint entrypoint;
49 typedef struct _GstVaapiProperty GstVaapiProperty;
50 struct _GstVaapiProperty {
52 VADisplayAttribute attribute;
56 #define DEFAULT_RENDER_MODE GST_VAAPI_RENDER_MODE_TEXTURE
57 #define DEFAULT_ROTATION GST_VAAPI_ROTATION_0
76 static GstVaapiDisplayCache *g_display_cache = NULL;
78 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
81 get_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint *value);
84 set_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint value);
87 get_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat *v);
90 set_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat v);
92 static inline GstVaapiDisplayCache *
93 get_display_cache(void)
96 g_display_cache = gst_vaapi_display_cache_new();
97 return g_display_cache;
100 GstVaapiDisplayCache *
101 gst_vaapi_display_get_cache(void)
103 return get_display_cache();
107 free_display_cache(void)
109 if (!g_display_cache)
111 if (gst_vaapi_display_cache_get_size(g_display_cache) > 0)
113 gst_vaapi_display_cache_free(g_display_cache);
114 g_display_cache = NULL;
117 /* GstVaapiDisplayType enumerations */
119 gst_vaapi_display_type_get_type(void)
121 static GType g_type = 0;
123 static const GEnumValue display_types[] = {
124 { GST_VAAPI_DISPLAY_TYPE_ANY,
125 "Auto detection", "any" },
127 { GST_VAAPI_DISPLAY_TYPE_X11,
128 "VA/X11 display", "x11" },
131 { GST_VAAPI_DISPLAY_TYPE_GLX,
132 "VA/GLX display", "glx" },
135 { GST_VAAPI_DISPLAY_TYPE_WAYLAND,
136 "VA/Wayland display", "wayland" },
139 { GST_VAAPI_DISPLAY_TYPE_DRM,
140 "VA/DRM display", "drm" },
146 g_type = g_enum_register_static("GstVaapiDisplayType", display_types);
150 /* Append GstVaapiImageFormat to formats array */
152 append_format(GArray *formats, GstVaapiImageFormat format)
154 g_array_append_val(formats, format);
157 /* Append VAImageFormats to formats array */
159 append_formats(GArray *formats, const VAImageFormat *va_formats, guint n)
161 GstVaapiImageFormat format;
162 gboolean has_YV12 = FALSE;
163 gboolean has_I420 = FALSE;
166 for (i = 0; i < n; i++) {
167 const VAImageFormat * const va_format = &va_formats[i];
169 format = gst_vaapi_image_format(va_format);
171 GST_DEBUG("unsupported format %" GST_FOURCC_FORMAT,
172 GST_FOURCC_ARGS(va_format->fourcc));
177 case GST_VAAPI_IMAGE_YV12:
180 case GST_VAAPI_IMAGE_I420:
186 append_format(formats, format);
189 /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
190 supported by the underlying driver */
191 if (has_YV12 && !has_I420)
192 append_format(formats, GST_VAAPI_IMAGE_I420);
193 else if (has_I420 && !has_YV12)
194 append_format(formats, GST_VAAPI_IMAGE_YV12);
197 /* Sort image formats. Prefer YUV formats first */
199 compare_yuv_formats(gconstpointer a, gconstpointer b)
201 const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
202 const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
204 const gboolean is_fmt1_yuv = gst_vaapi_image_format_is_yuv(fmt1);
205 const gboolean is_fmt2_yuv = gst_vaapi_image_format_is_yuv(fmt2);
207 if (is_fmt1_yuv != is_fmt2_yuv)
208 return is_fmt1_yuv ? -1 : 1;
210 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
211 (gint)gst_vaapi_image_format_get_score(fmt2));
214 /* Sort subpicture formats. Prefer RGB formats first */
216 compare_rgb_formats(gconstpointer a, gconstpointer b)
218 const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
219 const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
221 const gboolean is_fmt1_rgb = gst_vaapi_image_format_is_rgb(fmt1);
222 const gboolean is_fmt2_rgb = gst_vaapi_image_format_is_rgb(fmt2);
224 if (is_fmt1_rgb != is_fmt2_rgb)
225 return is_fmt1_rgb ? -1 : 1;
227 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
228 (gint)gst_vaapi_image_format_get_score(fmt2));
231 /* Check if configs array contains profile at entrypoint */
232 static inline gboolean
235 GstVaapiProfile profile,
236 GstVaapiEntrypoint entrypoint
239 GstVaapiConfig *config;
245 for (i = 0; i < configs->len; i++) {
246 config = &g_array_index(configs, GstVaapiConfig, i);
247 if (config->profile == profile && config->entrypoint == entrypoint)
253 /* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */
255 append_h263_config(GArray *configs)
257 GstVaapiConfig *config, tmp_config;
258 GstVaapiConfig *mpeg4_simple_config = NULL;
259 GstVaapiConfig *h263_baseline_config = NULL;
262 if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE)
268 for (i = 0; i < configs->len; i++) {
269 config = &g_array_index(configs, GstVaapiConfig, i);
270 if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE)
271 mpeg4_simple_config = config;
272 else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE)
273 h263_baseline_config = config;
276 if (mpeg4_simple_config && !h263_baseline_config) {
277 tmp_config = *mpeg4_simple_config;
278 tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE;
279 g_array_append_val(configs, tmp_config);
283 /* Convert configs array to profiles as GstCaps */
285 get_profile_caps(GArray *configs)
287 GstVaapiConfig *config;
288 GstCaps *out_caps, *caps;
294 out_caps = gst_caps_new_empty();
298 for (i = 0; i < configs->len; i++) {
299 config = &g_array_index(configs, GstVaapiConfig, i);
300 caps = gst_vaapi_profile_get_caps(config->profile);
302 gst_caps_merge(out_caps, caps);
307 /* Check if formats array contains format */
308 static inline gboolean
309 find_format(GArray *formats, GstVaapiImageFormat format)
313 for (i = 0; i < formats->len; i++)
314 if (g_array_index(formats, GstVaapiImageFormat, i) == format)
319 /* Convert formats array to GstCaps */
321 get_format_caps(GArray *formats)
323 GstVaapiImageFormat format;
324 GstCaps *out_caps, *caps;
327 out_caps = gst_caps_new_empty();
331 for (i = 0; i < formats->len; i++) {
332 format = g_array_index(formats, GstVaapiImageFormat, i);
333 caps = gst_vaapi_image_format_get_caps(format);
335 gst_caps_append(out_caps, caps);
340 /* Find display attribute */
341 static const GstVaapiProperty *
342 find_property(GArray *properties, const gchar *name)
344 GstVaapiProperty *prop;
350 for (i = 0; i < properties->len; i++) {
351 prop = &g_array_index(properties, GstVaapiProperty, i);
352 if (strcmp(prop->name, name) == 0)
359 static const GstVaapiProperty *
360 find_property_by_type(GArray *properties, VADisplayAttribType type)
362 GstVaapiProperty *prop;
365 for (i = 0; i < properties->len; i++) {
366 prop = &g_array_index(properties, GstVaapiProperty, i);
367 if (prop->attribute.type == type)
374 static inline const GstVaapiProperty *
375 find_property_by_pspec(GstVaapiDisplay *display, GParamSpec *pspec)
377 return find_property(display->priv->properties, pspec->name);
381 gst_vaapi_display_calculate_pixel_aspect_ratio(GstVaapiDisplay *display)
383 GstVaapiDisplayPrivate * const priv = display->priv;
384 gdouble ratio, delta;
385 gint i, j, index, windex;
387 static const gint par[][2] = {
388 {1, 1}, /* regular screen */
389 {16, 15}, /* PAL TV */
390 {11, 10}, /* 525 line Rec.601 video */
391 {54, 59}, /* 625 line Rec.601 video */
392 {64, 45}, /* 1280x1024 on 16:9 display */
393 {5, 3}, /* 1280x1024 on 4:3 display */
394 {4, 3} /* 800x600 on 16:9 display */
397 /* First, calculate the "real" ratio based on the X values;
398 * which is the "physical" w/h divided by the w/h in pixels of the
400 if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm)
403 ratio = (gdouble)(priv->width_mm * priv->height) /
404 (priv->height_mm * priv->width);
405 GST_DEBUG("calculated pixel aspect ratio: %f", ratio);
407 /* Now, find the one from par[][2] with the lowest delta to the real one */
408 #define DELTA(idx, w) (ABS(ratio - ((gdouble)par[idx][w] / par[idx][!(w)])))
413 for (i = 1; i < G_N_ELEMENTS(par); i++) {
414 for (j = 0; j < 2; j++) {
415 const gdouble this_delta = DELTA(i, j);
416 if (this_delta < delta) {
425 priv->par_n = par[index][windex];
426 priv->par_d = par[index][windex ^ 1];
430 gst_vaapi_display_destroy(GstVaapiDisplay *display)
432 GstVaapiDisplayPrivate * const priv = display->priv;
434 if (priv->decoders) {
435 g_array_free(priv->decoders, TRUE);
436 priv->decoders = NULL;
439 if (priv->encoders) {
440 g_array_free(priv->encoders, TRUE);
441 priv->encoders = NULL;
444 if (priv->image_formats) {
445 g_array_free(priv->image_formats, TRUE);
446 priv->image_formats = NULL;
449 if (priv->subpicture_formats) {
450 g_array_free(priv->subpicture_formats, TRUE);
451 priv->subpicture_formats = NULL;
454 if (priv->properties) {
455 g_array_free(priv->properties, TRUE);
456 priv->properties = NULL;
461 vaTerminate(priv->display);
462 priv->display = NULL;
465 if (priv->create_display) {
466 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
467 if (klass->close_display)
468 klass->close_display(display);
471 g_clear_object(&priv->parent);
473 if (g_display_cache) {
474 gst_vaapi_display_cache_remove(get_display_cache(), display);
475 free_display_cache();
480 gst_vaapi_display_create(GstVaapiDisplay *display)
482 GstVaapiDisplayPrivate * const priv = display->priv;
483 GstVaapiDisplayCache *cache;
484 gboolean has_errors = TRUE;
485 VADisplayAttribute *display_attrs = NULL;
486 VAProfile *profiles = NULL;
487 VAEntrypoint *entrypoints = NULL;
488 VAImageFormat *formats = NULL;
489 unsigned int *flags = NULL;
490 gint i, j, n, num_entrypoints, major_version, minor_version;
492 GstVaapiDisplayInfo info;
493 const GstVaapiDisplayInfo *cached_info = NULL;
495 memset(&info, 0, sizeof(info));
496 info.display = display;
497 info.display_type = priv->display_type;
500 info.va_display = priv->display;
501 else if (priv->create_display) {
502 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
503 if (klass->open_display && !klass->open_display(display))
505 if (!klass->get_display || !klass->get_display(display, &info))
507 priv->display = info.va_display;
508 priv->display_type = info.display_type;
510 klass->get_size(display, &priv->width, &priv->height);
511 if (klass->get_size_mm)
512 klass->get_size_mm(display, &priv->width_mm, &priv->height_mm);
513 gst_vaapi_display_calculate_pixel_aspect_ratio(display);
518 cache = get_display_cache();
521 cached_info = gst_vaapi_display_cache_lookup_by_va_display(
526 g_clear_object(&priv->parent);
527 priv->parent = g_object_ref(cached_info->display);
528 priv->display_type = cached_info->display_type;
532 status = vaInitialize(priv->display, &major_version, &minor_version);
533 if (!vaapi_check_status(status, "vaInitialize()"))
535 GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
539 profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display));
542 entrypoints = g_new(VAEntrypoint, vaMaxNumEntrypoints(priv->display));
545 status = vaQueryConfigProfiles(priv->display, profiles, &n);
546 if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
549 GST_DEBUG("%d profiles", n);
550 for (i = 0; i < n; i++) {
551 #if VA_CHECK_VERSION(0,34,0)
552 /* Introduced in VA/VPP API */
553 if (profiles[i] == VAProfileNone)
556 GST_DEBUG(" %s", string_of_VAProfile(profiles[i]));
559 priv->decoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig));
562 priv->encoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig));
566 for (i = 0; i < n; i++) {
567 GstVaapiConfig config;
569 config.profile = gst_vaapi_profile(profiles[i]);
573 status = vaQueryConfigEntrypoints(
576 entrypoints, &num_entrypoints
578 if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()"))
581 for (j = 0; j < num_entrypoints; j++) {
582 config.entrypoint = gst_vaapi_entrypoint(entrypoints[j]);
583 switch (config.entrypoint) {
584 case GST_VAAPI_ENTRYPOINT_VLD:
585 case GST_VAAPI_ENTRYPOINT_IDCT:
586 case GST_VAAPI_ENTRYPOINT_MOCO:
587 g_array_append_val(priv->decoders, config);
589 case GST_VAAPI_ENTRYPOINT_SLICE_ENCODE:
590 g_array_append_val(priv->encoders, config);
595 append_h263_config(priv->decoders);
597 /* VA display attributes */
599 g_new(VADisplayAttribute, vaMaxNumDisplayAttributes(priv->display));
603 n = 0; /* XXX: workaround old GMA500 bug */
604 status = vaQueryDisplayAttributes(priv->display, display_attrs, &n);
605 if (!vaapi_check_status(status, "vaQueryDisplayAttributes()"))
608 priv->properties = g_array_new(FALSE, FALSE, sizeof(GstVaapiProperty));
609 if (!priv->properties)
612 GST_DEBUG("%d display attributes", n);
613 for (i = 0; i < n; i++) {
614 VADisplayAttribute * const attr = &display_attrs[i];
615 GstVaapiProperty prop;
618 GST_DEBUG(" %s", string_of_VADisplayAttributeType(attr->type));
620 switch (attr->type) {
621 #if !VA_CHECK_VERSION(0,34,0)
622 case VADisplayAttribDirectSurface:
623 prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
626 case VADisplayAttribRenderMode:
627 prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
629 case VADisplayAttribRotation:
630 prop.name = GST_VAAPI_DISPLAY_PROP_ROTATION;
632 case VADisplayAttribHue:
633 prop.name = GST_VAAPI_DISPLAY_PROP_HUE;
635 case VADisplayAttribSaturation:
636 prop.name = GST_VAAPI_DISPLAY_PROP_SATURATION;
638 case VADisplayAttribBrightness:
639 prop.name = GST_VAAPI_DISPLAY_PROP_BRIGHTNESS;
641 case VADisplayAttribContrast:
642 prop.name = GST_VAAPI_DISPLAY_PROP_CONTRAST;
651 /* Assume the attribute is really supported if we can get the
652 * actual and current value */
653 if (!get_attribute(display, attr->type, &value))
656 /* Some drivers (e.g. EMGD) have completely random initial
658 if (value < attr->min_value || value > attr->max_value)
661 prop.attribute = *attr;
662 prop.old_value = value;
663 g_array_append_val(priv->properties, prop);
666 /* VA image formats */
667 formats = g_new(VAImageFormat, vaMaxNumImageFormats(priv->display));
670 status = vaQueryImageFormats(priv->display, formats, &n);
671 if (!vaapi_check_status(status, "vaQueryImageFormats()"))
674 GST_DEBUG("%d image formats", n);
675 for (i = 0; i < n; i++)
676 GST_DEBUG(" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc));
678 priv->image_formats =
679 g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
680 if (!priv->image_formats)
682 append_formats(priv->image_formats, formats, n);
683 g_array_sort(priv->image_formats, compare_yuv_formats);
685 /* VA subpicture formats */
686 n = vaMaxNumSubpictureFormats(priv->display);
687 formats = g_renew(VAImageFormat, formats, n);
688 flags = g_new(guint, n);
689 if (!formats || !flags)
691 status = vaQuerySubpictureFormats(priv->display, formats, flags, (guint *)&n);
692 if (!vaapi_check_status(status, "vaQuerySubpictureFormats()"))
695 GST_DEBUG("%d subpicture formats", n);
696 for (i = 0; i < n; i++)
697 GST_DEBUG(" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc));
699 priv->subpicture_formats =
700 g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
701 if (!priv->subpicture_formats)
703 append_formats(priv->subpicture_formats, formats, n);
704 g_array_sort(priv->subpicture_formats, compare_rgb_formats);
707 if (!gst_vaapi_display_cache_add(cache, &info))
713 g_free(display_attrs);
722 gst_vaapi_display_lock_default(GstVaapiDisplay *display)
724 GstVaapiDisplayPrivate *priv = display->priv;
727 priv = priv->parent->priv;
728 g_static_rec_mutex_lock(&priv->mutex);
732 gst_vaapi_display_unlock_default(GstVaapiDisplay *display)
734 GstVaapiDisplayPrivate *priv = display->priv;
737 priv = priv->parent->priv;
738 g_static_rec_mutex_unlock(&priv->mutex);
742 gst_vaapi_display_finalize(GObject *object)
744 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
746 gst_vaapi_display_destroy(display);
748 g_static_rec_mutex_free(&display->priv->mutex);
750 G_OBJECT_CLASS(gst_vaapi_display_parent_class)->finalize(object);
754 gst_vaapi_display_set_property(
761 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
765 display->priv->display = g_value_get_pointer(value);
767 case PROP_DISPLAY_TYPE:
768 display->priv->display_type = g_value_get_enum(value);
770 case PROP_RENDER_MODE:
771 gst_vaapi_display_set_render_mode(display, g_value_get_enum(value));
774 gst_vaapi_display_set_rotation(display, g_value_get_enum(value));
777 case PROP_SATURATION:
778 case PROP_BRIGHTNESS:
780 set_color_balance(display, prop_id, g_value_get_float(value));
783 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
789 gst_vaapi_display_get_property(
796 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
800 g_value_set_pointer(value, gst_vaapi_display_get_display(display));
802 case PROP_DISPLAY_TYPE:
803 g_value_set_enum(value, gst_vaapi_display_get_display_type(display));
806 g_value_set_uint(value, gst_vaapi_display_get_width(display));
809 g_value_set_uint(value, gst_vaapi_display_get_height(display));
811 case PROP_RENDER_MODE: {
812 GstVaapiRenderMode mode;
813 if (!gst_vaapi_display_get_render_mode(display, &mode))
814 mode = DEFAULT_RENDER_MODE;
815 g_value_set_enum(value, mode);
819 g_value_set_enum(value, gst_vaapi_display_get_rotation(display));
822 case PROP_SATURATION:
823 case PROP_BRIGHTNESS:
824 case PROP_CONTRAST: {
826 if (!get_color_balance(display, prop_id, &v))
827 v = G_PARAM_SPEC_FLOAT(pspec)->default_value;
828 g_value_set_float(value, v);
832 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
838 gst_vaapi_display_constructed(GObject *object)
840 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
841 GObjectClass *parent_class;
843 display->priv->create_display = display->priv->display == NULL;
844 if (!gst_vaapi_display_create(display))
845 gst_vaapi_display_destroy(display);
847 parent_class = G_OBJECT_CLASS(gst_vaapi_display_parent_class);
848 if (parent_class->constructed)
849 parent_class->constructed(object);
853 gst_vaapi_display_class_init(GstVaapiDisplayClass *klass)
855 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
856 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
858 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi, "vaapi", 0, "VA-API helper");
860 g_type_class_add_private(klass, sizeof(GstVaapiDisplayPrivate));
862 object_class->finalize = gst_vaapi_display_finalize;
863 object_class->set_property = gst_vaapi_display_set_property;
864 object_class->get_property = gst_vaapi_display_get_property;
865 object_class->constructed = gst_vaapi_display_constructed;
867 dpy_class->lock = gst_vaapi_display_lock_default;
868 dpy_class->unlock = gst_vaapi_display_unlock_default;
870 g_properties[PROP_DISPLAY] =
871 g_param_spec_pointer("display",
874 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
876 g_properties[PROP_DISPLAY_TYPE] =
877 g_param_spec_enum("display-type",
880 GST_VAAPI_TYPE_DISPLAY_TYPE,
881 GST_VAAPI_DISPLAY_TYPE_ANY,
882 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
884 g_properties[PROP_WIDTH] =
885 g_param_spec_uint("width",
891 g_properties[PROP_HEIGHT] =
892 g_param_spec_uint("height",
894 "The display height",
899 * GstVaapiDisplay:render-mode:
901 * The VA display rendering mode, expressed as a #GstVaapiRenderMode.
903 g_properties[PROP_RENDER_MODE] =
904 g_param_spec_enum(GST_VAAPI_DISPLAY_PROP_RENDER_MODE,
906 "The display rendering mode",
907 GST_VAAPI_TYPE_RENDER_MODE,
912 * GstVaapiDisplay:rotation:
914 * The VA display rotation mode, expressed as a #GstVaapiRotation.
916 g_properties[PROP_ROTATION] =
917 g_param_spec_enum(GST_VAAPI_DISPLAY_PROP_ROTATION,
919 "The display rotation mode",
920 GST_VAAPI_TYPE_ROTATION,
925 * GstVaapiDisplay:hue:
927 * The VA display hue, expressed as a float value. Range is -180.0
928 * to 180.0. Default value is 0.0 and represents no modification.
930 g_properties[PROP_HUE] =
931 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_HUE,
933 "The display hue value",
938 * GstVaapiDisplay:saturation:
940 * The VA display saturation, expressed as a float value. Range is
941 * 0.0 to 2.0. Default value is 1.0 and represents no modification.
943 g_properties[PROP_SATURATION] =
944 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_SATURATION,
946 "The display saturation value",
951 * GstVaapiDisplay:brightness:
953 * The VA display brightness, expressed as a float value. Range is
954 * -1.0 to 1.0. Default value is 0.0 and represents no modification.
956 g_properties[PROP_BRIGHTNESS] =
957 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_BRIGHTNESS,
959 "The display brightness value",
964 * GstVaapiDisplay:contrast:
966 * The VA display contrast, expressed as a float value. Range is
967 * 0.0 to 2.0. Default value is 1.0 and represents no modification.
969 g_properties[PROP_CONTRAST] =
970 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_CONTRAST,
972 "The display contrast value",
976 g_object_class_install_properties(object_class, N_PROPERTIES, g_properties);
980 gst_vaapi_display_init(GstVaapiDisplay *display)
982 GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display);
984 display->priv = priv;
986 priv->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
987 priv->display = NULL;
994 priv->decoders = NULL;
995 priv->encoders = NULL;
996 priv->image_formats = NULL;
997 priv->subpicture_formats = NULL;
998 priv->properties = NULL;
999 priv->create_display = TRUE;
1001 g_static_rec_mutex_init(&priv->mutex);
1005 * gst_vaapi_display_new_with_display:
1006 * @va_display: a #VADisplay
1008 * Creates a new #GstVaapiDisplay, using @va_display as the VA
1011 * Return value: the newly created #GstVaapiDisplay object
1014 gst_vaapi_display_new_with_display(VADisplay va_display)
1016 GstVaapiDisplayCache * const cache = get_display_cache();
1017 const GstVaapiDisplayInfo *info;
1019 g_return_val_if_fail(va_display != NULL, NULL);
1020 g_return_val_if_fail(cache != NULL, NULL);
1022 info = gst_vaapi_display_cache_lookup_by_va_display(cache, va_display);
1024 return g_object_ref(info->display);
1026 return g_object_new(GST_VAAPI_TYPE_DISPLAY,
1027 "display", va_display,
1032 * gst_vaapi_display_lock:
1033 * @display: a #GstVaapiDisplay
1035 * Locks @display. If @display is already locked by another thread,
1036 * the current thread will block until @display is unlocked by the
1040 gst_vaapi_display_lock(GstVaapiDisplay *display)
1042 GstVaapiDisplayClass *klass;
1044 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1046 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1048 klass->lock(display);
1052 * gst_vaapi_display_unlock:
1053 * @display: a #GstVaapiDisplay
1055 * Unlocks @display. If another thread is blocked in a
1056 * gst_vaapi_display_lock() call for @display, it will be woken and
1057 * can lock @display itself.
1060 gst_vaapi_display_unlock(GstVaapiDisplay *display)
1062 GstVaapiDisplayClass *klass;
1064 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1066 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1068 klass->unlock(display);
1072 * gst_vaapi_display_sync:
1073 * @display: a #GstVaapiDisplay
1075 * Flushes any requests queued for the windowing system and waits until
1076 * all requests have been handled. This is often used for making sure
1077 * that the display is synchronized with the current state of the program.
1079 * This is most useful for X11. On windowing systems where requests are
1080 * handled synchronously, this function will do nothing.
1083 gst_vaapi_display_sync(GstVaapiDisplay *display)
1085 GstVaapiDisplayClass *klass;
1087 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1089 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1091 klass->sync(display);
1092 else if (klass->flush)
1093 klass->flush(display);
1097 * gst_vaapi_display_flush:
1098 * @display: a #GstVaapiDisplay
1100 * Flushes any requests queued for the windowing system.
1102 * This is most useful for X11. On windowing systems where requests
1103 * are handled synchronously, this function will do nothing.
1106 gst_vaapi_display_flush(GstVaapiDisplay *display)
1108 GstVaapiDisplayClass *klass;
1110 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1112 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1114 klass->flush(display);
1118 * gst_vaapi_display_get_display:
1119 * @display: a #GstVaapiDisplay
1121 * Returns the #GstVaapiDisplayType bound to @display.
1123 * Return value: the #GstVaapiDisplayType
1126 gst_vaapi_display_get_display_type(GstVaapiDisplay *display)
1128 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display),
1129 GST_VAAPI_DISPLAY_TYPE_ANY);
1131 return display->priv->display_type;
1135 * gst_vaapi_display_get_display:
1136 * @display: a #GstVaapiDisplay
1138 * Returns the #VADisplay bound to @display.
1140 * Return value: the #VADisplay
1143 gst_vaapi_display_get_display(GstVaapiDisplay *display)
1145 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1147 return display->priv->display;
1151 * gst_vaapi_display_get_width:
1152 * @display: a #GstVaapiDisplay
1154 * Retrieves the width of a #GstVaapiDisplay.
1156 * Return value: the width of the @display, in pixels
1159 gst_vaapi_display_get_width(GstVaapiDisplay *display)
1161 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
1163 return display->priv->width;
1167 * gst_vaapi_display_get_height:
1168 * @display: a #GstVaapiDisplay
1170 * Retrieves the height of a #GstVaapiDisplay
1172 * Return value: the height of the @display, in pixels
1175 gst_vaapi_display_get_height(GstVaapiDisplay *display)
1177 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
1179 return display->priv->height;
1183 * gst_vaapi_display_get_size:
1184 * @display: a #GstVaapiDisplay
1185 * @pwidth: return location for the width, or %NULL
1186 * @pheight: return location for the height, or %NULL
1188 * Retrieves the dimensions of a #GstVaapiDisplay.
1191 gst_vaapi_display_get_size(GstVaapiDisplay *display, guint *pwidth, guint *pheight)
1193 g_return_if_fail(GST_VAAPI_DISPLAY(display));
1196 *pwidth = display->priv->width;
1199 *pheight = display->priv->height;
1203 * gst_vaapi_display_get_pixel_aspect_ratio:
1204 * @display: a #GstVaapiDisplay
1205 * @par_n: return location for the numerator of pixel aspect ratio, or %NULL
1206 * @par_d: return location for the denominator of pixel aspect ratio, or %NULL
1208 * Retrieves the pixel aspect ratio of a #GstVaapiDisplay.
1211 gst_vaapi_display_get_pixel_aspect_ratio(
1212 GstVaapiDisplay *display,
1217 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1220 *par_n = display->priv->par_n;
1223 *par_d = display->priv->par_d;
1227 * gst_vaapi_display_get_decode_caps:
1228 * @display: a #GstVaapiDisplay
1230 * Gets the supported profiles for decoding as #GstCaps capabilities.
1232 * Return value: a newly allocated #GstCaps object, possibly empty
1235 gst_vaapi_display_get_decode_caps(GstVaapiDisplay *display)
1237 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1239 return get_profile_caps(display->priv->decoders);
1243 * gst_vaapi_display_has_decoder:
1244 * @display: a #GstVaapiDisplay
1245 * @profile: a #VAProfile
1246 * @entrypoint: a #GstVaaiEntrypoint
1248 * Returns whether VA @display supports @profile for decoding at the
1249 * specified @entrypoint.
1251 * Return value: %TRUE if VA @display supports @profile for decoding.
1254 gst_vaapi_display_has_decoder(
1255 GstVaapiDisplay *display,
1256 GstVaapiProfile profile,
1257 GstVaapiEntrypoint entrypoint
1260 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1262 return find_config(display->priv->decoders, profile, entrypoint);
1266 * gst_vaapi_display_get_encode_caps:
1267 * @display: a #GstVaapiDisplay
1269 * Gets the supported profiles for decoding as #GstCaps capabilities.
1271 * Return value: a newly allocated #GstCaps object, possibly empty
1274 gst_vaapi_display_get_encode_caps(GstVaapiDisplay *display)
1276 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1278 return get_profile_caps(display->priv->encoders);
1282 * gst_vaapi_display_has_encoder:
1283 * @display: a #GstVaapiDisplay
1284 * @profile: a #VAProfile
1285 * @entrypoint: a #GstVaapiEntrypoint
1287 * Returns whether VA @display supports @profile for encoding at the
1288 * specified @entrypoint.
1290 * Return value: %TRUE if VA @display supports @profile for encoding.
1293 gst_vaapi_display_has_encoder(
1294 GstVaapiDisplay *display,
1295 GstVaapiProfile profile,
1296 GstVaapiEntrypoint entrypoint
1299 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1301 return find_config(display->priv->encoders, profile, entrypoint);
1305 * gst_vaapi_display_get_image_caps:
1306 * @display: a #GstVaapiDisplay
1308 * Gets the supported image formats for gst_vaapi_surface_get_image()
1309 * or gst_vaapi_surface_put_image() as #GstCaps capabilities.
1311 * Note that this method does not necessarily map image formats
1312 * returned by vaQueryImageFormats(). The set of capabilities can be
1313 * stripped down, if gstreamer-vaapi does not support the format, or
1314 * expanded to cover compatible formats not exposed by the underlying
1315 * driver. e.g. I420 can be supported even if the driver only exposes
1318 * Return value: a newly allocated #GstCaps object, possibly empty
1321 gst_vaapi_display_get_image_caps(GstVaapiDisplay *display)
1323 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1325 return get_format_caps(display->priv->image_formats);
1329 * gst_vaapi_display_has_image_format:
1330 * @display: a #GstVaapiDisplay
1331 * @format: a #GstVaapiFormat
1333 * Returns whether VA @display supports @format image format.
1335 * Return value: %TRUE if VA @display supports @format image format
1338 gst_vaapi_display_has_image_format(
1339 GstVaapiDisplay *display,
1340 GstVaapiImageFormat format
1343 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1344 g_return_val_if_fail(format, FALSE);
1346 if (find_format(display->priv->image_formats, format))
1349 /* XXX: try subpicture formats since some drivers could report a
1350 * set of VA image formats that is not a superset of the set of VA
1351 * subpicture formats
1353 return find_format(display->priv->subpicture_formats, format);
1357 * gst_vaapi_display_get_subpicture_caps:
1358 * @display: a #GstVaapiDisplay
1360 * Gets the supported subpicture formats as #GstCaps capabilities.
1362 * Note that this method does not necessarily map subpicture formats
1363 * returned by vaQuerySubpictureFormats(). The set of capabilities can
1364 * be stripped down if gstreamer-vaapi does not support the
1365 * format. e.g. this is the case for paletted formats like IA44.
1367 * Return value: a newly allocated #GstCaps object, possibly empty
1370 gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display)
1372 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1374 return get_format_caps(display->priv->subpicture_formats);
1378 * gst_vaapi_display_has_subpicture_format:
1379 * @display: a #GstVaapiDisplay
1380 * @format: a #GstVaapiFormat
1382 * Returns whether VA @display supports @format subpicture format.
1384 * Return value: %TRUE if VA @display supports @format subpicture format
1387 gst_vaapi_display_has_subpicture_format(
1388 GstVaapiDisplay *display,
1389 GstVaapiImageFormat format
1392 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1393 g_return_val_if_fail(format, FALSE);
1395 return find_format(display->priv->subpicture_formats, format);
1399 * gst_vaapi_display_has_property:
1400 * @display: a #GstVaapiDisplay
1401 * @name: the property name to check
1403 * Returns whether VA @display supports the requested property. The
1404 * check is performed against the property @name. So, the client
1405 * application may perform this check only once and cache this
1408 * Return value: %TRUE if VA @display supports property @name
1411 gst_vaapi_display_has_property(GstVaapiDisplay *display, const gchar *name)
1413 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1414 g_return_val_if_fail(name, FALSE);
1416 return find_property(display->priv->properties, name) != NULL;
1420 get_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint *value)
1422 VADisplayAttribute attr;
1426 attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
1427 status = vaGetDisplayAttributes(display->priv->display, &attr, 1);
1428 if (!vaapi_check_status(status, "vaGetDisplayAttributes()"))
1430 *value = attr.value;
1435 set_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint value)
1437 VADisplayAttribute attr;
1442 attr.flags = VA_DISPLAY_ATTRIB_SETTABLE;
1443 status = vaSetDisplayAttributes(display->priv->display, &attr, 1);
1444 if (!vaapi_check_status(status, "vaSetDisplayAttributes()"))
1450 get_render_mode_VADisplayAttribRenderMode(
1451 GstVaapiDisplay *display,
1452 GstVaapiRenderMode *pmode
1455 gint modes, devices;
1457 if (!get_attribute(display, VADisplayAttribRenderDevice, &devices))
1461 if (!get_attribute(display, VADisplayAttribRenderMode, &modes))
1464 /* Favor "overlay" mode since it is the most restrictive one */
1465 if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY|VA_RENDER_MODE_EXTERNAL_OVERLAY))
1466 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1468 *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1473 get_render_mode_VADisplayAttribDirectSurface(
1474 GstVaapiDisplay *display,
1475 GstVaapiRenderMode *pmode
1478 #if VA_CHECK_VERSION(0,34,0)
1479 /* VADisplayAttribDirectsurface was removed in VA-API >= 0.34.0 */
1482 gint direct_surface;
1484 if (!get_attribute(display, VADisplayAttribDirectSurface, &direct_surface))
1487 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1489 *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1495 get_render_mode_default(
1496 GstVaapiDisplay *display,
1497 GstVaapiRenderMode *pmode
1500 switch (display->priv->display_type) {
1502 case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
1503 /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */
1504 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1508 case GST_VAAPI_DISPLAY_TYPE_DRM:
1509 /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */
1510 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1514 /* This includes VA/X11 and VA/GLX modes */
1515 *pmode = DEFAULT_RENDER_MODE;
1522 * gst_vaapi_display_get_render_mode:
1523 * @display: a #GstVaapiDisplay
1524 * @pmode: return location for the VA @display rendering mode
1526 * Returns the current VA @display rendering mode.
1528 * Return value: %TRUE if VA @display rendering mode could be determined
1531 gst_vaapi_display_get_render_mode(
1532 GstVaapiDisplay *display,
1533 GstVaapiRenderMode *pmode
1536 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1538 /* Try with render-mode attribute */
1539 if (get_render_mode_VADisplayAttribRenderMode(display, pmode))
1542 /* Try with direct-surface attribute */
1543 if (get_render_mode_VADisplayAttribDirectSurface(display, pmode))
1546 /* Default: determine from the display type */
1547 return get_render_mode_default(display, pmode);
1551 * gst_vaapi_display_set_render_mode:
1552 * @display: a #GstVaapiDisplay
1553 * @mode: the #GstVaapiRenderMode to set
1555 * Sets the VA @display rendering mode to the supplied @mode. This
1556 * function returns %FALSE if the rendering mode could not be set,
1557 * e.g. run-time switching rendering mode is not supported.
1559 * Return value: %TRUE if VA @display rendering @mode could be changed
1560 * to the requested value
1563 gst_vaapi_display_set_render_mode(
1564 GstVaapiDisplay *display,
1565 GstVaapiRenderMode mode
1568 gint modes, devices;
1570 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1572 if (!get_attribute(display, VADisplayAttribRenderDevice, &devices))
1577 case GST_VAAPI_RENDER_MODE_OVERLAY:
1578 if (devices & VA_RENDER_DEVICE_LOCAL)
1579 modes |= VA_RENDER_MODE_LOCAL_OVERLAY;
1580 if (devices & VA_RENDER_DEVICE_EXTERNAL)
1581 modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY;
1583 case GST_VAAPI_RENDER_MODE_TEXTURE:
1584 if (devices & VA_RENDER_DEVICE_LOCAL)
1585 modes |= VA_RENDER_MODE_LOCAL_GPU;
1586 if (devices & VA_RENDER_DEVICE_EXTERNAL)
1587 modes |= VA_RENDER_MODE_EXTERNAL_GPU;
1592 if (!set_attribute(display, VADisplayAttribRenderMode, modes))
1595 g_object_notify_by_pspec(G_OBJECT(display), g_properties[PROP_RENDER_MODE]);
1600 * gst_vaapi_display_get_rotation:
1601 * @display: a #GstVaapiDisplay
1603 * Returns the current VA @display rotation angle. If the VA driver
1604 * does not support "rotation" display attribute, then the display is
1605 * assumed to be un-rotated.
1607 * Return value: the current #GstVaapiRotation value
1610 gst_vaapi_display_get_rotation(GstVaapiDisplay *display)
1614 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), DEFAULT_ROTATION);
1616 if (!get_attribute(display, VADisplayAttribRotation, &value))
1617 value = VA_ROTATION_NONE;
1618 return to_GstVaapiRotation(value);
1622 * gst_vaapi_display_set_rotation:
1623 * @display: a #GstVaapiDisplay
1624 * @rotation: the #GstVaapiRotation value to set
1626 * Sets the VA @display rotation angle to the supplied @rotation
1627 * value. This function returns %FALSE if the rotation angle could not
1628 * be set, e.g. the VA driver does not allow to change the display
1631 * Return value: %TRUE if VA @display rotation angle could be changed
1632 * to the requested value
1635 gst_vaapi_display_set_rotation(
1636 GstVaapiDisplay *display,
1637 GstVaapiRotation rotation
1642 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1644 value = from_GstVaapiRotation(rotation);
1645 if (!set_attribute(display, VADisplayAttribRotation, value))
1648 g_object_notify_by_pspec(G_OBJECT(display), g_properties[PROP_ROTATION]);
1652 /* Get color balance attributes */
1654 get_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat *v)
1656 GParamSpecFloat * const pspec = G_PARAM_SPEC_FLOAT(g_properties[prop_id]);
1657 const GstVaapiProperty *prop;
1658 const VADisplayAttribute *attr;
1665 prop = find_property_by_pspec(display, &pspec->parent_instance);
1668 attr = &prop->attribute;
1670 if (!get_attribute(display, attr->type, &value))
1673 /* Scale wrt. the medium ("default") value */
1674 out_value = pspec->default_value;
1675 if (value > attr->value)
1676 out_value += ((gfloat)(value - attr->value) /
1677 (attr->max_value - attr->value) *
1678 (pspec->maximum - pspec->default_value));
1679 else if (value < attr->value)
1680 out_value -= ((gfloat)(attr->value - value) /
1681 (attr->value - attr->min_value) *
1682 (pspec->default_value - pspec->minimum));
1687 /* Set color balance attribute */
1689 set_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat v)
1691 GParamSpecFloat * const pspec = G_PARAM_SPEC_FLOAT(g_properties[prop_id]);
1692 const GstVaapiProperty *prop;
1693 const VADisplayAttribute *attr;
1699 prop = find_property_by_pspec(display, &pspec->parent_instance);
1702 attr = &prop->attribute;
1704 /* Scale wrt. the medium ("default") value */
1705 value = attr->value;
1706 if (v > pspec->default_value)
1707 value += ((v - pspec->default_value) /
1708 (pspec->maximum - pspec->default_value) *
1709 (attr->max_value - attr->value));
1710 else if (v < pspec->default_value)
1711 value -= ((pspec->default_value - v) /
1712 (pspec->default_value - pspec->minimum) *
1713 (attr->value - attr->min_value));
1714 if (!set_attribute(display, attr->type, value))
1717 g_object_notify_by_pspec(G_OBJECT(display), g_properties[prop_id]);