2 * gstvaapidisplay.c - VA display abstraction
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2013 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"
35 #include "gstvaapiversion.h"
38 #include "gstvaapidebug.h"
40 GST_DEBUG_CATEGORY(gst_debug_vaapi);
42 G_DEFINE_TYPE(GstVaapiDisplay, gst_vaapi_display, G_TYPE_OBJECT)
44 typedef struct _GstVaapiConfig GstVaapiConfig;
45 struct _GstVaapiConfig {
46 GstVaapiProfile profile;
47 GstVaapiEntrypoint entrypoint;
50 typedef struct _GstVaapiProperty GstVaapiProperty;
51 struct _GstVaapiProperty {
53 VADisplayAttribute attribute;
57 typedef struct _GstVaapiFormatInfo GstVaapiFormatInfo;
58 struct _GstVaapiFormatInfo {
59 GstVaapiImageFormat format;
63 #define DEFAULT_RENDER_MODE GST_VAAPI_RENDER_MODE_TEXTURE
64 #define DEFAULT_ROTATION GST_VAAPI_ROTATION_0
83 static GstVaapiDisplayCache *g_display_cache = NULL;
85 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
88 get_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint *value);
91 set_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint value);
94 get_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat *v);
97 set_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat v);
100 libgstvaapi_init_once(void)
102 static gsize g_once = FALSE;
104 if (!g_once_init_enter(&g_once))
107 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi, "vaapi", 0, "VA-API helper");
109 /* Dump gstreamer-vaapi version for debugging purposes */
110 GST_INFO("gstreamer-vaapi version %s", GST_VAAPI_VERSION_ID);
112 g_once_init_leave(&g_once, TRUE);
115 static inline GstVaapiDisplayCache *
116 get_display_cache(void)
118 if (!g_display_cache)
119 g_display_cache = gst_vaapi_display_cache_new();
120 return g_display_cache;
123 GstVaapiDisplayCache *
124 gst_vaapi_display_get_cache(void)
126 return get_display_cache();
130 free_display_cache(void)
132 if (!g_display_cache)
134 if (gst_vaapi_display_cache_get_size(g_display_cache) > 0)
136 gst_vaapi_display_cache_free(g_display_cache);
137 g_display_cache = NULL;
140 /* GstVaapiDisplayType enumerations */
142 gst_vaapi_display_type_get_type(void)
144 static GType g_type = 0;
146 static const GEnumValue display_types[] = {
147 { GST_VAAPI_DISPLAY_TYPE_ANY,
148 "Auto detection", "any" },
150 { GST_VAAPI_DISPLAY_TYPE_X11,
151 "VA/X11 display", "x11" },
154 { GST_VAAPI_DISPLAY_TYPE_GLX,
155 "VA/GLX display", "glx" },
158 { GST_VAAPI_DISPLAY_TYPE_WAYLAND,
159 "VA/Wayland display", "wayland" },
162 { GST_VAAPI_DISPLAY_TYPE_DRM,
163 "VA/DRM display", "drm" },
169 g_type = g_enum_register_static("GstVaapiDisplayType", display_types);
173 /* Append GstVaapiImageFormat to formats array */
175 append_format(GArray *formats, GstVaapiImageFormat format, guint flags)
177 GstVaapiFormatInfo fi;
181 g_array_append_val(formats, fi);
184 /* Append VAImageFormats to formats array */
186 append_formats(GArray *formats, const VAImageFormat *va_formats,
187 guint *flags, guint n)
189 GstVaapiImageFormat format;
190 const GstVaapiFormatInfo *YV12_fip = NULL;
191 const GstVaapiFormatInfo *I420_fip = NULL;
194 for (i = 0; i < n; i++) {
195 const VAImageFormat * const va_format = &va_formats[i];
196 const GstVaapiFormatInfo **fipp;
198 format = gst_vaapi_image_format(va_format);
200 GST_DEBUG("unsupported format %" GST_FOURCC_FORMAT,
201 GST_FOURCC_ARGS(va_format->fourcc));
204 append_format(formats, format, flags ? flags[i] : 0);
207 case GST_VAAPI_IMAGE_YV12:
210 case GST_VAAPI_IMAGE_I420:
218 *fipp = &g_array_index(formats, GstVaapiFormatInfo,
222 /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
223 supported by the underlying driver */
224 if (YV12_fip && !I420_fip)
225 append_format(formats, GST_VAAPI_IMAGE_I420, YV12_fip->flags);
226 else if (I420_fip && !YV12_fip)
227 append_format(formats, GST_VAAPI_IMAGE_YV12, I420_fip->flags);
230 /* Sort image formats. Prefer YUV formats first */
232 compare_yuv_formats(gconstpointer a, gconstpointer b)
234 const GstVaapiImageFormat fmt1 = ((GstVaapiFormatInfo *)a)->format;
235 const GstVaapiImageFormat fmt2 = ((GstVaapiFormatInfo *)b)->format;
237 const gboolean is_fmt1_yuv = gst_vaapi_image_format_is_yuv(fmt1);
238 const gboolean is_fmt2_yuv = gst_vaapi_image_format_is_yuv(fmt2);
240 if (is_fmt1_yuv != is_fmt2_yuv)
241 return is_fmt1_yuv ? -1 : 1;
243 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
244 (gint)gst_vaapi_image_format_get_score(fmt2));
247 /* Sort subpicture formats. Prefer RGB formats first */
249 compare_rgb_formats(gconstpointer a, gconstpointer b)
251 const GstVaapiImageFormat fmt1 = ((GstVaapiFormatInfo *)a)->format;
252 const GstVaapiImageFormat fmt2 = ((GstVaapiFormatInfo *)b)->format;
254 const gboolean is_fmt1_rgb = gst_vaapi_image_format_is_rgb(fmt1);
255 const gboolean is_fmt2_rgb = gst_vaapi_image_format_is_rgb(fmt2);
257 if (is_fmt1_rgb != is_fmt2_rgb)
258 return is_fmt1_rgb ? -1 : 1;
260 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
261 (gint)gst_vaapi_image_format_get_score(fmt2));
264 /* Check if configs array contains profile at entrypoint */
265 static inline gboolean
268 GstVaapiProfile profile,
269 GstVaapiEntrypoint entrypoint
272 GstVaapiConfig *config;
278 for (i = 0; i < configs->len; i++) {
279 config = &g_array_index(configs, GstVaapiConfig, i);
280 if (config->profile == profile && config->entrypoint == entrypoint)
286 /* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */
288 append_h263_config(GArray *configs)
290 GstVaapiConfig *config, tmp_config;
291 GstVaapiConfig *mpeg4_simple_config = NULL;
292 GstVaapiConfig *h263_baseline_config = NULL;
295 if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE)
301 for (i = 0; i < configs->len; i++) {
302 config = &g_array_index(configs, GstVaapiConfig, i);
303 if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE)
304 mpeg4_simple_config = config;
305 else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE)
306 h263_baseline_config = config;
309 if (mpeg4_simple_config && !h263_baseline_config) {
310 tmp_config = *mpeg4_simple_config;
311 tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE;
312 g_array_append_val(configs, tmp_config);
316 /* Convert configs array to profiles as GstCaps */
318 get_profile_caps(GArray *configs)
320 GstVaapiConfig *config;
321 GstCaps *out_caps, *caps;
327 out_caps = gst_caps_new_empty();
331 for (i = 0; i < configs->len; i++) {
332 config = &g_array_index(configs, GstVaapiConfig, i);
333 caps = gst_vaapi_profile_get_caps(config->profile);
335 gst_caps_merge(out_caps, caps);
340 /* Find format info */
341 static const GstVaapiFormatInfo *
342 find_format_info(GArray *formats, GstVaapiImageFormat format)
344 const GstVaapiFormatInfo *fip;
347 for (i = 0; i < formats->len; i++) {
348 fip = &g_array_index(formats, GstVaapiFormatInfo, i);
349 if (fip->format == format)
355 /* Check if formats array contains format */
356 static inline gboolean
357 find_format(GArray *formats, GstVaapiImageFormat format)
359 return find_format_info(formats, format) != NULL;
362 /* Convert formats array to GstCaps */
364 get_format_caps(GArray *formats)
366 const GstVaapiFormatInfo *fip;
367 GstCaps *out_caps, *caps;
370 out_caps = gst_caps_new_empty();
374 for (i = 0; i < formats->len; i++) {
375 fip = &g_array_index(formats, GstVaapiFormatInfo, i);
376 caps = gst_vaapi_image_format_get_caps(fip->format);
378 gst_caps_append(out_caps, caps);
383 /* Find display attribute */
384 static const GstVaapiProperty *
385 find_property(GArray *properties, const gchar *name)
387 GstVaapiProperty *prop;
393 for (i = 0; i < properties->len; i++) {
394 prop = &g_array_index(properties, GstVaapiProperty, i);
395 if (strcmp(prop->name, name) == 0)
402 static const GstVaapiProperty *
403 find_property_by_type(GArray *properties, VADisplayAttribType type)
405 GstVaapiProperty *prop;
408 for (i = 0; i < properties->len; i++) {
409 prop = &g_array_index(properties, GstVaapiProperty, i);
410 if (prop->attribute.type == type)
417 static inline const GstVaapiProperty *
418 find_property_by_pspec(GstVaapiDisplay *display, GParamSpec *pspec)
420 return find_property(display->priv->properties, pspec->name);
424 gst_vaapi_display_calculate_pixel_aspect_ratio(GstVaapiDisplay *display)
426 GstVaapiDisplayPrivate * const priv = display->priv;
427 gdouble ratio, delta;
428 gint i, j, index, windex;
430 static const gint par[][2] = {
431 {1, 1}, /* regular screen */
432 {16, 15}, /* PAL TV */
433 {11, 10}, /* 525 line Rec.601 video */
434 {54, 59}, /* 625 line Rec.601 video */
435 {64, 45}, /* 1280x1024 on 16:9 display */
436 {5, 3}, /* 1280x1024 on 4:3 display */
437 {4, 3} /* 800x600 on 16:9 display */
440 /* First, calculate the "real" ratio based on the X values;
441 * which is the "physical" w/h divided by the w/h in pixels of the
443 if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm)
446 ratio = (gdouble)(priv->width_mm * priv->height) /
447 (priv->height_mm * priv->width);
448 GST_DEBUG("calculated pixel aspect ratio: %f", ratio);
450 /* Now, find the one from par[][2] with the lowest delta to the real one */
451 #define DELTA(idx, w) (ABS(ratio - ((gdouble)par[idx][w] / par[idx][!(w)])))
456 for (i = 1; i < G_N_ELEMENTS(par); i++) {
457 for (j = 0; j < 2; j++) {
458 const gdouble this_delta = DELTA(i, j);
459 if (this_delta < delta) {
468 priv->par_n = par[index][windex];
469 priv->par_d = par[index][windex ^ 1];
473 gst_vaapi_display_destroy(GstVaapiDisplay *display)
475 GstVaapiDisplayPrivate * const priv = display->priv;
477 if (priv->decoders) {
478 g_array_free(priv->decoders, TRUE);
479 priv->decoders = NULL;
482 if (priv->encoders) {
483 g_array_free(priv->encoders, TRUE);
484 priv->encoders = NULL;
487 if (priv->image_formats) {
488 g_array_free(priv->image_formats, TRUE);
489 priv->image_formats = NULL;
492 if (priv->subpicture_formats) {
493 g_array_free(priv->subpicture_formats, TRUE);
494 priv->subpicture_formats = NULL;
497 if (priv->properties) {
498 g_array_free(priv->properties, TRUE);
499 priv->properties = NULL;
504 vaTerminate(priv->display);
505 priv->display = NULL;
508 if (priv->create_display) {
509 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
510 if (klass->close_display)
511 klass->close_display(display);
514 g_clear_object(&priv->parent);
516 if (g_display_cache) {
517 gst_vaapi_display_cache_remove(get_display_cache(), display);
518 free_display_cache();
523 gst_vaapi_display_create(GstVaapiDisplay *display)
525 GstVaapiDisplayPrivate * const priv = display->priv;
526 GstVaapiDisplayCache *cache;
527 gboolean has_errors = TRUE;
528 VADisplayAttribute *display_attrs = NULL;
529 VAProfile *profiles = NULL;
530 VAEntrypoint *entrypoints = NULL;
531 VAImageFormat *formats = NULL;
532 unsigned int *flags = NULL;
533 gint i, j, n, num_entrypoints, major_version, minor_version;
535 GstVaapiDisplayInfo info;
536 const GstVaapiDisplayInfo *cached_info = NULL;
538 memset(&info, 0, sizeof(info));
539 info.display = display;
540 info.display_type = priv->display_type;
543 info.va_display = priv->display;
544 else if (priv->create_display) {
545 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
546 if (klass->open_display && !klass->open_display(display))
548 if (!klass->get_display || !klass->get_display(display, &info))
550 priv->display = info.va_display;
551 priv->display_type = info.display_type;
553 klass->get_size(display, &priv->width, &priv->height);
554 if (klass->get_size_mm)
555 klass->get_size_mm(display, &priv->width_mm, &priv->height_mm);
556 gst_vaapi_display_calculate_pixel_aspect_ratio(display);
561 cache = get_display_cache();
564 cached_info = gst_vaapi_display_cache_lookup_by_va_display(
569 g_clear_object(&priv->parent);
570 priv->parent = g_object_ref(cached_info->display);
571 priv->display_type = cached_info->display_type;
575 status = vaInitialize(priv->display, &major_version, &minor_version);
576 if (!vaapi_check_status(status, "vaInitialize()"))
578 GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
582 profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display));
585 entrypoints = g_new(VAEntrypoint, vaMaxNumEntrypoints(priv->display));
588 status = vaQueryConfigProfiles(priv->display, profiles, &n);
589 if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
592 GST_DEBUG("%d profiles", n);
593 for (i = 0; i < n; i++) {
594 #if VA_CHECK_VERSION(0,34,0)
595 /* Introduced in VA/VPP API */
596 if (profiles[i] == VAProfileNone)
599 GST_DEBUG(" %s", string_of_VAProfile(profiles[i]));
602 priv->decoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig));
605 priv->encoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig));
609 for (i = 0; i < n; i++) {
610 GstVaapiConfig config;
612 config.profile = gst_vaapi_profile(profiles[i]);
616 status = vaQueryConfigEntrypoints(
619 entrypoints, &num_entrypoints
621 if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()"))
624 for (j = 0; j < num_entrypoints; j++) {
625 config.entrypoint = gst_vaapi_entrypoint(entrypoints[j]);
626 switch (config.entrypoint) {
627 case GST_VAAPI_ENTRYPOINT_VLD:
628 case GST_VAAPI_ENTRYPOINT_IDCT:
629 case GST_VAAPI_ENTRYPOINT_MOCO:
630 g_array_append_val(priv->decoders, config);
632 case GST_VAAPI_ENTRYPOINT_SLICE_ENCODE:
633 g_array_append_val(priv->encoders, config);
638 append_h263_config(priv->decoders);
640 /* VA display attributes */
642 g_new(VADisplayAttribute, vaMaxNumDisplayAttributes(priv->display));
646 n = 0; /* XXX: workaround old GMA500 bug */
647 status = vaQueryDisplayAttributes(priv->display, display_attrs, &n);
648 if (!vaapi_check_status(status, "vaQueryDisplayAttributes()"))
651 priv->properties = g_array_new(FALSE, FALSE, sizeof(GstVaapiProperty));
652 if (!priv->properties)
655 GST_DEBUG("%d display attributes", n);
656 for (i = 0; i < n; i++) {
657 VADisplayAttribute * const attr = &display_attrs[i];
658 GstVaapiProperty prop;
661 GST_DEBUG(" %s", string_of_VADisplayAttributeType(attr->type));
663 switch (attr->type) {
664 #if !VA_CHECK_VERSION(0,34,0)
665 case VADisplayAttribDirectSurface:
666 prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
669 case VADisplayAttribRenderMode:
670 prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
672 case VADisplayAttribRotation:
673 prop.name = GST_VAAPI_DISPLAY_PROP_ROTATION;
675 case VADisplayAttribHue:
676 prop.name = GST_VAAPI_DISPLAY_PROP_HUE;
678 case VADisplayAttribSaturation:
679 prop.name = GST_VAAPI_DISPLAY_PROP_SATURATION;
681 case VADisplayAttribBrightness:
682 prop.name = GST_VAAPI_DISPLAY_PROP_BRIGHTNESS;
684 case VADisplayAttribContrast:
685 prop.name = GST_VAAPI_DISPLAY_PROP_CONTRAST;
694 /* Assume the attribute is really supported if we can get the
695 * actual and current value */
696 if (!get_attribute(display, attr->type, &value))
699 /* Some drivers (e.g. EMGD) have completely random initial
701 if (value < attr->min_value || value > attr->max_value)
704 prop.attribute = *attr;
705 prop.old_value = value;
706 g_array_append_val(priv->properties, prop);
709 /* VA image formats */
710 formats = g_new(VAImageFormat, vaMaxNumImageFormats(priv->display));
713 status = vaQueryImageFormats(priv->display, formats, &n);
714 if (!vaapi_check_status(status, "vaQueryImageFormats()"))
717 GST_DEBUG("%d image formats", n);
718 for (i = 0; i < n; i++)
719 GST_DEBUG(" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc));
721 priv->image_formats =
722 g_array_new(FALSE, FALSE, sizeof(GstVaapiFormatInfo));
723 if (!priv->image_formats)
725 append_formats(priv->image_formats, formats, NULL, n);
726 g_array_sort(priv->image_formats, compare_yuv_formats);
728 /* VA subpicture formats */
729 n = vaMaxNumSubpictureFormats(priv->display);
730 formats = g_renew(VAImageFormat, formats, n);
731 flags = g_new(guint, n);
732 if (!formats || !flags)
734 status = vaQuerySubpictureFormats(priv->display, formats, flags, (guint *)&n);
735 if (!vaapi_check_status(status, "vaQuerySubpictureFormats()"))
738 GST_DEBUG("%d subpicture formats", n);
739 for (i = 0; i < n; i++) {
740 GST_DEBUG(" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc));
741 flags[i] = to_GstVaapiSubpictureFlags(flags[i]);
744 priv->subpicture_formats =
745 g_array_new(FALSE, FALSE, sizeof(GstVaapiFormatInfo));
746 if (!priv->subpicture_formats)
748 append_formats(priv->subpicture_formats, formats, flags, n);
749 g_array_sort(priv->subpicture_formats, compare_rgb_formats);
752 if (!gst_vaapi_display_cache_add(cache, &info))
758 g_free(display_attrs);
767 gst_vaapi_display_lock_default(GstVaapiDisplay *display)
769 GstVaapiDisplayPrivate *priv = display->priv;
772 priv = priv->parent->priv;
773 g_rec_mutex_lock(&priv->mutex);
777 gst_vaapi_display_unlock_default(GstVaapiDisplay *display)
779 GstVaapiDisplayPrivate *priv = display->priv;
782 priv = priv->parent->priv;
783 g_rec_mutex_unlock(&priv->mutex);
787 gst_vaapi_display_finalize(GObject *object)
789 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
791 gst_vaapi_display_destroy(display);
793 g_rec_mutex_clear(&display->priv->mutex);
795 G_OBJECT_CLASS(gst_vaapi_display_parent_class)->finalize(object);
799 gst_vaapi_display_set_property(
806 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
810 display->priv->display = g_value_get_pointer(value);
812 case PROP_DISPLAY_TYPE:
813 display->priv->display_type = g_value_get_enum(value);
815 case PROP_RENDER_MODE:
816 gst_vaapi_display_set_render_mode(display, g_value_get_enum(value));
819 gst_vaapi_display_set_rotation(display, g_value_get_enum(value));
822 case PROP_SATURATION:
823 case PROP_BRIGHTNESS:
825 set_color_balance(display, prop_id, g_value_get_float(value));
828 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
834 gst_vaapi_display_get_property(
841 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
845 g_value_set_pointer(value, gst_vaapi_display_get_display(display));
847 case PROP_DISPLAY_TYPE:
848 g_value_set_enum(value, gst_vaapi_display_get_display_type(display));
851 g_value_set_uint(value, gst_vaapi_display_get_width(display));
854 g_value_set_uint(value, gst_vaapi_display_get_height(display));
856 case PROP_RENDER_MODE: {
857 GstVaapiRenderMode mode;
858 if (!gst_vaapi_display_get_render_mode(display, &mode))
859 mode = DEFAULT_RENDER_MODE;
860 g_value_set_enum(value, mode);
864 g_value_set_enum(value, gst_vaapi_display_get_rotation(display));
867 case PROP_SATURATION:
868 case PROP_BRIGHTNESS:
869 case PROP_CONTRAST: {
871 if (!get_color_balance(display, prop_id, &v))
872 v = G_PARAM_SPEC_FLOAT(pspec)->default_value;
873 g_value_set_float(value, v);
877 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
883 gst_vaapi_display_constructed(GObject *object)
885 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
886 GObjectClass *parent_class;
888 display->priv->create_display = display->priv->display == NULL;
889 if (!gst_vaapi_display_create(display))
890 gst_vaapi_display_destroy(display);
892 parent_class = G_OBJECT_CLASS(gst_vaapi_display_parent_class);
893 if (parent_class->constructed)
894 parent_class->constructed(object);
898 gst_vaapi_display_class_init(GstVaapiDisplayClass *klass)
900 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
901 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
903 libgstvaapi_init_once();
905 g_type_class_add_private(klass, sizeof(GstVaapiDisplayPrivate));
907 object_class->finalize = gst_vaapi_display_finalize;
908 object_class->set_property = gst_vaapi_display_set_property;
909 object_class->get_property = gst_vaapi_display_get_property;
910 object_class->constructed = gst_vaapi_display_constructed;
912 dpy_class->lock = gst_vaapi_display_lock_default;
913 dpy_class->unlock = gst_vaapi_display_unlock_default;
915 g_properties[PROP_DISPLAY] =
916 g_param_spec_pointer("display",
919 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
921 g_properties[PROP_DISPLAY_TYPE] =
922 g_param_spec_enum("display-type",
925 GST_VAAPI_TYPE_DISPLAY_TYPE,
926 GST_VAAPI_DISPLAY_TYPE_ANY,
927 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
929 g_properties[PROP_WIDTH] =
930 g_param_spec_uint("width",
936 g_properties[PROP_HEIGHT] =
937 g_param_spec_uint("height",
939 "The display height",
944 * GstVaapiDisplay:render-mode:
946 * The VA display rendering mode, expressed as a #GstVaapiRenderMode.
948 g_properties[PROP_RENDER_MODE] =
949 g_param_spec_enum(GST_VAAPI_DISPLAY_PROP_RENDER_MODE,
951 "The display rendering mode",
952 GST_VAAPI_TYPE_RENDER_MODE,
957 * GstVaapiDisplay:rotation:
959 * The VA display rotation mode, expressed as a #GstVaapiRotation.
961 g_properties[PROP_ROTATION] =
962 g_param_spec_enum(GST_VAAPI_DISPLAY_PROP_ROTATION,
964 "The display rotation mode",
965 GST_VAAPI_TYPE_ROTATION,
970 * GstVaapiDisplay:hue:
972 * The VA display hue, expressed as a float value. Range is -180.0
973 * to 180.0. Default value is 0.0 and represents no modification.
975 g_properties[PROP_HUE] =
976 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_HUE,
978 "The display hue value",
983 * GstVaapiDisplay:saturation:
985 * The VA display saturation, expressed as a float value. Range is
986 * 0.0 to 2.0. Default value is 1.0 and represents no modification.
988 g_properties[PROP_SATURATION] =
989 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_SATURATION,
991 "The display saturation value",
996 * GstVaapiDisplay:brightness:
998 * The VA display brightness, expressed as a float value. Range is
999 * -1.0 to 1.0. Default value is 0.0 and represents no modification.
1001 g_properties[PROP_BRIGHTNESS] =
1002 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_BRIGHTNESS,
1004 "The display brightness value",
1009 * GstVaapiDisplay:contrast:
1011 * The VA display contrast, expressed as a float value. Range is
1012 * 0.0 to 2.0. Default value is 1.0 and represents no modification.
1014 g_properties[PROP_CONTRAST] =
1015 g_param_spec_float(GST_VAAPI_DISPLAY_PROP_CONTRAST,
1017 "The display contrast value",
1021 g_object_class_install_properties(object_class, N_PROPERTIES, g_properties);
1025 gst_vaapi_display_init(GstVaapiDisplay *display)
1027 GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display);
1029 display->priv = priv;
1030 priv->parent = NULL;
1031 priv->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
1032 priv->display = NULL;
1036 priv->height_mm = 0;
1039 priv->decoders = NULL;
1040 priv->encoders = NULL;
1041 priv->image_formats = NULL;
1042 priv->subpicture_formats = NULL;
1043 priv->properties = NULL;
1044 priv->create_display = TRUE;
1046 g_rec_mutex_init(&priv->mutex);
1050 * gst_vaapi_display_new_with_display:
1051 * @va_display: a #VADisplay
1053 * Creates a new #GstVaapiDisplay, using @va_display as the VA
1056 * Return value: the newly created #GstVaapiDisplay object
1059 gst_vaapi_display_new_with_display(VADisplay va_display)
1061 GstVaapiDisplayCache * const cache = get_display_cache();
1062 const GstVaapiDisplayInfo *info;
1064 g_return_val_if_fail(va_display != NULL, NULL);
1065 g_return_val_if_fail(cache != NULL, NULL);
1067 info = gst_vaapi_display_cache_lookup_by_va_display(cache, va_display);
1069 return g_object_ref(info->display);
1071 return g_object_new(GST_VAAPI_TYPE_DISPLAY,
1072 "display", va_display,
1077 * gst_vaapi_display_lock:
1078 * @display: a #GstVaapiDisplay
1080 * Locks @display. If @display is already locked by another thread,
1081 * the current thread will block until @display is unlocked by the
1085 gst_vaapi_display_lock(GstVaapiDisplay *display)
1087 GstVaapiDisplayClass *klass;
1089 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1091 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1093 klass->lock(display);
1097 * gst_vaapi_display_unlock:
1098 * @display: a #GstVaapiDisplay
1100 * Unlocks @display. If another thread is blocked in a
1101 * gst_vaapi_display_lock() call for @display, it will be woken and
1102 * can lock @display itself.
1105 gst_vaapi_display_unlock(GstVaapiDisplay *display)
1107 GstVaapiDisplayClass *klass;
1109 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1111 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1113 klass->unlock(display);
1117 * gst_vaapi_display_sync:
1118 * @display: a #GstVaapiDisplay
1120 * Flushes any requests queued for the windowing system and waits until
1121 * all requests have been handled. This is often used for making sure
1122 * that the display is synchronized with the current state of the program.
1124 * This is most useful for X11. On windowing systems where requests are
1125 * handled synchronously, this function will do nothing.
1128 gst_vaapi_display_sync(GstVaapiDisplay *display)
1130 GstVaapiDisplayClass *klass;
1132 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1134 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1136 klass->sync(display);
1137 else if (klass->flush)
1138 klass->flush(display);
1142 * gst_vaapi_display_flush:
1143 * @display: a #GstVaapiDisplay
1145 * Flushes any requests queued for the windowing system.
1147 * This is most useful for X11. On windowing systems where requests
1148 * are handled synchronously, this function will do nothing.
1151 gst_vaapi_display_flush(GstVaapiDisplay *display)
1153 GstVaapiDisplayClass *klass;
1155 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1157 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
1159 klass->flush(display);
1163 * gst_vaapi_display_get_display:
1164 * @display: a #GstVaapiDisplay
1166 * Returns the #GstVaapiDisplayType bound to @display.
1168 * Return value: the #GstVaapiDisplayType
1171 gst_vaapi_display_get_display_type(GstVaapiDisplay *display)
1173 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display),
1174 GST_VAAPI_DISPLAY_TYPE_ANY);
1176 return display->priv->display_type;
1180 * gst_vaapi_display_get_display:
1181 * @display: a #GstVaapiDisplay
1183 * Returns the #VADisplay bound to @display.
1185 * Return value: the #VADisplay
1188 gst_vaapi_display_get_display(GstVaapiDisplay *display)
1190 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1192 return display->priv->display;
1196 * gst_vaapi_display_get_width:
1197 * @display: a #GstVaapiDisplay
1199 * Retrieves the width of a #GstVaapiDisplay.
1201 * Return value: the width of the @display, in pixels
1204 gst_vaapi_display_get_width(GstVaapiDisplay *display)
1206 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
1208 return display->priv->width;
1212 * gst_vaapi_display_get_height:
1213 * @display: a #GstVaapiDisplay
1215 * Retrieves the height of a #GstVaapiDisplay
1217 * Return value: the height of the @display, in pixels
1220 gst_vaapi_display_get_height(GstVaapiDisplay *display)
1222 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
1224 return display->priv->height;
1228 * gst_vaapi_display_get_size:
1229 * @display: a #GstVaapiDisplay
1230 * @pwidth: return location for the width, or %NULL
1231 * @pheight: return location for the height, or %NULL
1233 * Retrieves the dimensions of a #GstVaapiDisplay.
1236 gst_vaapi_display_get_size(GstVaapiDisplay *display, guint *pwidth, guint *pheight)
1238 g_return_if_fail(GST_VAAPI_DISPLAY(display));
1241 *pwidth = display->priv->width;
1244 *pheight = display->priv->height;
1248 * gst_vaapi_display_get_pixel_aspect_ratio:
1249 * @display: a #GstVaapiDisplay
1250 * @par_n: return location for the numerator of pixel aspect ratio, or %NULL
1251 * @par_d: return location for the denominator of pixel aspect ratio, or %NULL
1253 * Retrieves the pixel aspect ratio of a #GstVaapiDisplay.
1256 gst_vaapi_display_get_pixel_aspect_ratio(
1257 GstVaapiDisplay *display,
1262 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
1265 *par_n = display->priv->par_n;
1268 *par_d = display->priv->par_d;
1272 * gst_vaapi_display_get_decode_caps:
1273 * @display: a #GstVaapiDisplay
1275 * Gets the supported profiles for decoding as #GstCaps capabilities.
1277 * Return value: a newly allocated #GstCaps object, possibly empty
1280 gst_vaapi_display_get_decode_caps(GstVaapiDisplay *display)
1282 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1284 return get_profile_caps(display->priv->decoders);
1288 * gst_vaapi_display_has_decoder:
1289 * @display: a #GstVaapiDisplay
1290 * @profile: a #VAProfile
1291 * @entrypoint: a #GstVaaiEntrypoint
1293 * Returns whether VA @display supports @profile for decoding at the
1294 * specified @entrypoint.
1296 * Return value: %TRUE if VA @display supports @profile for decoding.
1299 gst_vaapi_display_has_decoder(
1300 GstVaapiDisplay *display,
1301 GstVaapiProfile profile,
1302 GstVaapiEntrypoint entrypoint
1305 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1307 return find_config(display->priv->decoders, profile, entrypoint);
1311 * gst_vaapi_display_get_encode_caps:
1312 * @display: a #GstVaapiDisplay
1314 * Gets the supported profiles for decoding as #GstCaps capabilities.
1316 * Return value: a newly allocated #GstCaps object, possibly empty
1319 gst_vaapi_display_get_encode_caps(GstVaapiDisplay *display)
1321 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1323 return get_profile_caps(display->priv->encoders);
1327 * gst_vaapi_display_has_encoder:
1328 * @display: a #GstVaapiDisplay
1329 * @profile: a #VAProfile
1330 * @entrypoint: a #GstVaapiEntrypoint
1332 * Returns whether VA @display supports @profile for encoding at the
1333 * specified @entrypoint.
1335 * Return value: %TRUE if VA @display supports @profile for encoding.
1338 gst_vaapi_display_has_encoder(
1339 GstVaapiDisplay *display,
1340 GstVaapiProfile profile,
1341 GstVaapiEntrypoint entrypoint
1344 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1346 return find_config(display->priv->encoders, profile, entrypoint);
1350 * gst_vaapi_display_get_image_caps:
1351 * @display: a #GstVaapiDisplay
1353 * Gets the supported image formats for gst_vaapi_surface_get_image()
1354 * or gst_vaapi_surface_put_image() as #GstCaps capabilities.
1356 * Note that this method does not necessarily map image formats
1357 * returned by vaQueryImageFormats(). The set of capabilities can be
1358 * stripped down, if gstreamer-vaapi does not support the format, or
1359 * expanded to cover compatible formats not exposed by the underlying
1360 * driver. e.g. I420 can be supported even if the driver only exposes
1363 * Return value: a newly allocated #GstCaps object, possibly empty
1366 gst_vaapi_display_get_image_caps(GstVaapiDisplay *display)
1368 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1370 return get_format_caps(display->priv->image_formats);
1374 * gst_vaapi_display_has_image_format:
1375 * @display: a #GstVaapiDisplay
1376 * @format: a #GstVaapiFormat
1378 * Returns whether VA @display supports @format image format.
1380 * Return value: %TRUE if VA @display supports @format image format
1383 gst_vaapi_display_has_image_format(
1384 GstVaapiDisplay *display,
1385 GstVaapiImageFormat format
1388 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1389 g_return_val_if_fail(format, FALSE);
1391 if (find_format(display->priv->image_formats, format))
1394 /* XXX: try subpicture formats since some drivers could report a
1395 * set of VA image formats that is not a superset of the set of VA
1396 * subpicture formats
1398 return find_format(display->priv->subpicture_formats, format);
1402 * gst_vaapi_display_get_subpicture_caps:
1403 * @display: a #GstVaapiDisplay
1405 * Gets the supported subpicture formats as #GstCaps capabilities.
1407 * Note that this method does not necessarily map subpicture formats
1408 * returned by vaQuerySubpictureFormats(). The set of capabilities can
1409 * be stripped down if gstreamer-vaapi does not support the
1410 * format. e.g. this is the case for paletted formats like IA44.
1412 * Return value: a newly allocated #GstCaps object, possibly empty
1415 gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display)
1417 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1419 return get_format_caps(display->priv->subpicture_formats);
1423 * gst_vaapi_display_has_subpicture_format:
1424 * @display: a #GstVaapiDisplay
1425 * @format: a #GstVaapiFormat
1426 * @flags_ptr: pointer to #GstVaapiSubpictureFlags, or zero
1428 * Returns whether VA @display supports @format subpicture format with
1429 * the supplied @flags.
1431 * Return value: %TRUE if VA @display supports @format subpicture format
1434 gst_vaapi_display_has_subpicture_format(
1435 GstVaapiDisplay *display,
1436 GstVaapiImageFormat format,
1440 const GstVaapiFormatInfo *fip;
1442 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1443 g_return_val_if_fail(format, FALSE);
1445 fip = find_format_info(display->priv->subpicture_formats, format);
1450 *flags_ptr = fip->flags;
1455 * gst_vaapi_display_has_property:
1456 * @display: a #GstVaapiDisplay
1457 * @name: the property name to check
1459 * Returns whether VA @display supports the requested property. The
1460 * check is performed against the property @name. So, the client
1461 * application may perform this check only once and cache this
1464 * Return value: %TRUE if VA @display supports property @name
1467 gst_vaapi_display_has_property(GstVaapiDisplay *display, const gchar *name)
1469 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1470 g_return_val_if_fail(name, FALSE);
1472 return find_property(display->priv->properties, name) != NULL;
1476 get_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint *value)
1478 VADisplayAttribute attr;
1482 attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
1483 status = vaGetDisplayAttributes(display->priv->display, &attr, 1);
1484 if (!vaapi_check_status(status, "vaGetDisplayAttributes()"))
1486 *value = attr.value;
1491 set_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint value)
1493 VADisplayAttribute attr;
1498 attr.flags = VA_DISPLAY_ATTRIB_SETTABLE;
1499 status = vaSetDisplayAttributes(display->priv->display, &attr, 1);
1500 if (!vaapi_check_status(status, "vaSetDisplayAttributes()"))
1506 get_render_mode_VADisplayAttribRenderMode(
1507 GstVaapiDisplay *display,
1508 GstVaapiRenderMode *pmode
1511 gint modes, devices;
1513 if (!get_attribute(display, VADisplayAttribRenderDevice, &devices))
1517 if (!get_attribute(display, VADisplayAttribRenderMode, &modes))
1520 /* Favor "overlay" mode since it is the most restrictive one */
1521 if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY|VA_RENDER_MODE_EXTERNAL_OVERLAY))
1522 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1524 *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1529 get_render_mode_VADisplayAttribDirectSurface(
1530 GstVaapiDisplay *display,
1531 GstVaapiRenderMode *pmode
1534 #if VA_CHECK_VERSION(0,34,0)
1535 /* VADisplayAttribDirectsurface was removed in VA-API >= 0.34.0 */
1538 gint direct_surface;
1540 if (!get_attribute(display, VADisplayAttribDirectSurface, &direct_surface))
1543 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1545 *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1551 get_render_mode_default(
1552 GstVaapiDisplay *display,
1553 GstVaapiRenderMode *pmode
1556 switch (display->priv->display_type) {
1558 case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
1559 /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */
1560 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1564 case GST_VAAPI_DISPLAY_TYPE_DRM:
1565 /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */
1566 *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1570 /* This includes VA/X11 and VA/GLX modes */
1571 *pmode = DEFAULT_RENDER_MODE;
1578 * gst_vaapi_display_get_render_mode:
1579 * @display: a #GstVaapiDisplay
1580 * @pmode: return location for the VA @display rendering mode
1582 * Returns the current VA @display rendering mode.
1584 * Return value: %TRUE if VA @display rendering mode could be determined
1587 gst_vaapi_display_get_render_mode(
1588 GstVaapiDisplay *display,
1589 GstVaapiRenderMode *pmode
1592 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1594 /* Try with render-mode attribute */
1595 if (get_render_mode_VADisplayAttribRenderMode(display, pmode))
1598 /* Try with direct-surface attribute */
1599 if (get_render_mode_VADisplayAttribDirectSurface(display, pmode))
1602 /* Default: determine from the display type */
1603 return get_render_mode_default(display, pmode);
1607 * gst_vaapi_display_set_render_mode:
1608 * @display: a #GstVaapiDisplay
1609 * @mode: the #GstVaapiRenderMode to set
1611 * Sets the VA @display rendering mode to the supplied @mode. This
1612 * function returns %FALSE if the rendering mode could not be set,
1613 * e.g. run-time switching rendering mode is not supported.
1615 * Return value: %TRUE if VA @display rendering @mode could be changed
1616 * to the requested value
1619 gst_vaapi_display_set_render_mode(
1620 GstVaapiDisplay *display,
1621 GstVaapiRenderMode mode
1624 gint modes, devices;
1626 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1628 if (!get_attribute(display, VADisplayAttribRenderDevice, &devices))
1633 case GST_VAAPI_RENDER_MODE_OVERLAY:
1634 if (devices & VA_RENDER_DEVICE_LOCAL)
1635 modes |= VA_RENDER_MODE_LOCAL_OVERLAY;
1636 if (devices & VA_RENDER_DEVICE_EXTERNAL)
1637 modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY;
1639 case GST_VAAPI_RENDER_MODE_TEXTURE:
1640 if (devices & VA_RENDER_DEVICE_LOCAL)
1641 modes |= VA_RENDER_MODE_LOCAL_GPU;
1642 if (devices & VA_RENDER_DEVICE_EXTERNAL)
1643 modes |= VA_RENDER_MODE_EXTERNAL_GPU;
1648 if (!set_attribute(display, VADisplayAttribRenderMode, modes))
1651 g_object_notify_by_pspec(G_OBJECT(display), g_properties[PROP_RENDER_MODE]);
1656 * gst_vaapi_display_get_rotation:
1657 * @display: a #GstVaapiDisplay
1659 * Returns the current VA @display rotation angle. If the VA driver
1660 * does not support "rotation" display attribute, then the display is
1661 * assumed to be un-rotated.
1663 * Return value: the current #GstVaapiRotation value
1666 gst_vaapi_display_get_rotation(GstVaapiDisplay *display)
1670 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), DEFAULT_ROTATION);
1672 if (!get_attribute(display, VADisplayAttribRotation, &value))
1673 value = VA_ROTATION_NONE;
1674 return to_GstVaapiRotation(value);
1678 * gst_vaapi_display_set_rotation:
1679 * @display: a #GstVaapiDisplay
1680 * @rotation: the #GstVaapiRotation value to set
1682 * Sets the VA @display rotation angle to the supplied @rotation
1683 * value. This function returns %FALSE if the rotation angle could not
1684 * be set, e.g. the VA driver does not allow to change the display
1687 * Return value: %TRUE if VA @display rotation angle could be changed
1688 * to the requested value
1691 gst_vaapi_display_set_rotation(
1692 GstVaapiDisplay *display,
1693 GstVaapiRotation rotation
1698 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
1700 value = from_GstVaapiRotation(rotation);
1701 if (!set_attribute(display, VADisplayAttribRotation, value))
1704 g_object_notify_by_pspec(G_OBJECT(display), g_properties[PROP_ROTATION]);
1708 /* Get color balance attributes */
1710 get_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat *v)
1712 GParamSpecFloat * const pspec = G_PARAM_SPEC_FLOAT(g_properties[prop_id]);
1713 const GstVaapiProperty *prop;
1714 const VADisplayAttribute *attr;
1721 prop = find_property_by_pspec(display, &pspec->parent_instance);
1724 attr = &prop->attribute;
1726 if (!get_attribute(display, attr->type, &value))
1729 /* Scale wrt. the medium ("default") value */
1730 out_value = pspec->default_value;
1731 if (value > attr->value)
1732 out_value += ((gfloat)(value - attr->value) /
1733 (attr->max_value - attr->value) *
1734 (pspec->maximum - pspec->default_value));
1735 else if (value < attr->value)
1736 out_value -= ((gfloat)(attr->value - value) /
1737 (attr->value - attr->min_value) *
1738 (pspec->default_value - pspec->minimum));
1743 /* Set color balance attribute */
1745 set_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat v)
1747 GParamSpecFloat * const pspec = G_PARAM_SPEC_FLOAT(g_properties[prop_id]);
1748 const GstVaapiProperty *prop;
1749 const VADisplayAttribute *attr;
1755 prop = find_property_by_pspec(display, &pspec->parent_instance);
1758 attr = &prop->attribute;
1760 /* Scale wrt. the medium ("default") value */
1761 value = attr->value;
1762 if (v > pspec->default_value)
1763 value += ((v - pspec->default_value) /
1764 (pspec->maximum - pspec->default_value) *
1765 (attr->max_value - attr->value));
1766 else if (v < pspec->default_value)
1767 value -= ((pspec->default_value - v) /
1768 (pspec->default_value - pspec->minimum) *
1769 (attr->value - attr->min_value));
1770 if (!set_attribute(display, attr->type, value))
1773 g_object_notify_by_pspec(G_OBJECT(display), g_properties[prop_id]);