2 * gstvaapidisplay.c - VA display abstraction
4 * gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 * SECTION:gst-vaapi-display
27 #include "gstvaapiutils.h"
28 #include "gstvaapidisplay.h"
29 #include <va/va_backend.h>
32 #include "gstvaapidebug.h"
34 GST_DEBUG_CATEGORY(gst_debug_vaapi);
36 G_DEFINE_TYPE(GstVaapiDisplay, gst_vaapi_display, G_TYPE_OBJECT);
38 #define GST_VAAPI_DISPLAY_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
40 GST_VAAPI_TYPE_DISPLAY, \
41 GstVaapiDisplayPrivate))
43 struct _GstVaapiDisplayPrivate {
48 gboolean create_display;
50 GArray *image_formats;
51 GArray *subpicture_formats;
62 /* Append GstVaapiImageFormat to formats array */
64 append_format(GArray *formats, GstVaapiImageFormat format)
66 g_array_append_val(formats, format);
69 /* Append VAImageFormats to formats array */
71 append_formats(GArray *formats, const VAImageFormat *va_formats, guint n)
73 GstVaapiImageFormat format;
74 gboolean has_YV12 = FALSE;
75 gboolean has_I420 = FALSE;
78 for (i = 0; i < n; i++) {
79 const VAImageFormat * const va_format = &va_formats[i];
81 format = gst_vaapi_image_format(va_format);
83 GST_DEBUG("unsupported format %" GST_FOURCC_FORMAT,
84 GST_FOURCC_ARGS(va_format->fourcc));
89 case GST_VAAPI_IMAGE_YV12:
92 case GST_VAAPI_IMAGE_I420:
98 append_format(formats, format);
101 /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
102 supported by the underlying driver */
103 if (has_YV12 && !has_I420)
104 append_format(formats, GST_VAAPI_IMAGE_I420);
105 else if (has_I420 && !has_YV12)
106 append_format(formats, GST_VAAPI_IMAGE_YV12);
109 /* Sort image formats. Prefer YUV formats first */
111 compare_yuv_formats(gconstpointer a, gconstpointer b)
113 const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
114 const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
116 const gboolean is_fmt1_yuv = gst_vaapi_image_format_is_yuv(fmt1);
117 const gboolean is_fmt2_yuv = gst_vaapi_image_format_is_yuv(fmt2);
119 if (is_fmt1_yuv != is_fmt2_yuv)
120 return is_fmt1_yuv ? -1 : 1;
122 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
123 (gint)gst_vaapi_image_format_get_score(fmt2));
126 /* Sort subpicture formats. Prefer RGB formats first */
128 compare_rgb_formats(gconstpointer a, gconstpointer b)
130 const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
131 const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
133 const gboolean is_fmt1_rgb = gst_vaapi_image_format_is_rgb(fmt1);
134 const gboolean is_fmt2_rgb = gst_vaapi_image_format_is_rgb(fmt2);
136 if (is_fmt1_rgb != is_fmt2_rgb)
137 return is_fmt1_rgb ? -1 : 1;
139 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
140 (gint)gst_vaapi_image_format_get_score(fmt2));
143 /* Check if profiles array contains profile */
144 static inline gboolean
145 find_profile(GArray *profiles, VAProfile profile)
149 for (i = 0; i < profiles->len; i++)
150 if (g_array_index(profiles, VAProfile, i) == profile)
155 /* Check if formats array contains format */
156 static inline gboolean
157 find_format(GArray *formats, GstVaapiImageFormat format)
161 for (i = 0; i < formats->len; i++)
162 if (g_array_index(formats, GstVaapiImageFormat, i) == format)
167 /* Convert formats array to GstCaps */
169 get_caps(GArray *formats)
171 GstVaapiImageFormat format;
172 GstCaps *out_caps, *caps;
175 out_caps = gst_caps_new_empty();
179 for (i = 0; i < formats->len; i++) {
180 format = g_array_index(formats, GstVaapiImageFormat, i);
181 caps = gst_vaapi_image_format_get_caps(format);
183 gst_caps_append(out_caps, caps);
189 gst_vaapi_display_destroy(GstVaapiDisplay *display)
191 GstVaapiDisplayPrivate * const priv = display->priv;
193 if (priv->profiles) {
194 g_array_free(priv->profiles, TRUE);
195 priv->profiles = NULL;
198 if (priv->image_formats) {
199 g_array_free(priv->image_formats, TRUE);
200 priv->image_formats = NULL;
203 if (priv->subpicture_formats) {
204 g_array_free(priv->subpicture_formats, TRUE);
205 priv->subpicture_formats = NULL;
209 vaTerminate(priv->display);
210 priv->display = NULL;
213 if (priv->create_display) {
214 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
215 if (klass->close_display)
216 klass->close_display(display);
221 gst_vaapi_display_create(GstVaapiDisplay *display)
223 GstVaapiDisplayPrivate * const priv = display->priv;
224 gboolean has_errors = TRUE;
225 VAProfile *profiles = NULL;
226 VAImageFormat *formats = NULL;
227 unsigned int *flags = NULL;
228 gint i, n, major_version, minor_version;
231 if (!priv->display && priv->create_display) {
232 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
233 if (klass->open_display && !klass->open_display(display))
235 if (klass->get_display)
236 priv->display = klass->get_display(display);
238 klass->get_size(display, &priv->width, &priv->height);
243 status = vaInitialize(priv->display, &major_version, &minor_version);
244 if (!vaapi_check_status(status, "vaInitialize()"))
246 GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
249 profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display));
252 status = vaQueryConfigProfiles(priv->display, profiles, &n);
253 if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
256 GST_DEBUG("%d profiles", n);
257 for (i = 0; i < n; i++)
258 GST_DEBUG(" %s", string_of_VAProfile(profiles[i]));
260 priv->profiles = g_array_new(FALSE, FALSE, sizeof(VAProfile));
263 g_array_append_vals(priv->profiles, profiles, n);
265 /* VA image formats */
266 formats = g_new(VAImageFormat, vaMaxNumImageFormats(priv->display));
269 status = vaQueryImageFormats(priv->display, formats, &n);
270 if (!vaapi_check_status(status, "vaQueryImageFormats()"))
273 GST_DEBUG("%d image formats", n);
274 for (i = 0; i < n; i++)
275 GST_DEBUG(" %s", string_of_FOURCC(formats[i].fourcc));
277 priv->image_formats =
278 g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
279 if (!priv->image_formats)
281 append_formats(priv->image_formats, formats, n);
282 g_array_sort(priv->image_formats, compare_yuv_formats);
284 /* VA subpicture formats */
285 n = vaMaxNumSubpictureFormats(priv->display);
286 formats = g_renew(VAImageFormat, formats, n);
287 flags = g_new(guint, n);
288 if (!formats || !flags)
290 status = vaQuerySubpictureFormats(priv->display, formats, flags, &n);
291 if (!vaapi_check_status(status, "vaQuerySubpictureFormats()"))
294 GST_DEBUG("%d subpicture formats", n);
295 for (i = 0; i < n; i++)
296 GST_DEBUG(" %s", string_of_FOURCC(formats[i].fourcc));
298 priv->subpicture_formats =
299 g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
300 if (!priv->subpicture_formats)
302 append_formats(priv->subpicture_formats, formats, n);
303 g_array_sort(priv->subpicture_formats, compare_rgb_formats);
314 gst_vaapi_display_lock_default(GstVaapiDisplay *display)
316 g_static_mutex_lock(&display->priv->mutex);
320 gst_vaapi_display_unlock_default(GstVaapiDisplay *display)
322 g_static_mutex_unlock(&display->priv->mutex);
326 gst_vaapi_display_finalize(GObject *object)
328 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
330 gst_vaapi_display_destroy(display);
332 G_OBJECT_CLASS(gst_vaapi_display_parent_class)->finalize(object);
336 gst_vaapi_display_set_property(
343 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
347 display->priv->display = g_value_get_pointer(value);
350 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
356 gst_vaapi_display_get_property(
363 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
367 g_value_set_pointer(value, gst_vaapi_display_get_display(display));
370 g_value_set_uint(value, gst_vaapi_display_get_width(display));
373 g_value_set_uint(value, gst_vaapi_display_get_height(display));
376 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
382 gst_vaapi_display_constructed(GObject *object)
384 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
385 GObjectClass *parent_class;
387 display->priv->create_display = display->priv->display == NULL;
388 gst_vaapi_display_create(display);
390 parent_class = G_OBJECT_CLASS(gst_vaapi_display_parent_class);
391 if (parent_class->constructed)
392 parent_class->constructed(object);
396 gst_vaapi_display_class_init(GstVaapiDisplayClass *klass)
398 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
399 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
401 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi, "vaapi", 0, "VA-API helper");
403 g_type_class_add_private(klass, sizeof(GstVaapiDisplayPrivate));
405 object_class->finalize = gst_vaapi_display_finalize;
406 object_class->set_property = gst_vaapi_display_set_property;
407 object_class->get_property = gst_vaapi_display_get_property;
408 object_class->constructed = gst_vaapi_display_constructed;
410 dpy_class->lock_display = gst_vaapi_display_lock_default;
411 dpy_class->unlock_display = gst_vaapi_display_unlock_default;
413 g_object_class_install_property
416 g_param_spec_pointer("display",
419 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
421 g_object_class_install_property
424 g_param_spec_uint("width",
430 g_object_class_install_property
433 g_param_spec_uint("height",
435 "The display height",
441 gst_vaapi_display_init(GstVaapiDisplay *display)
443 GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display);
445 display->priv = priv;
446 priv->display = NULL;
449 priv->create_display = TRUE;
450 priv->profiles = NULL;
451 priv->image_formats = NULL;
452 priv->subpicture_formats = NULL;
454 g_static_mutex_init(&priv->mutex);
458 * gst_vaapi_display_new_with_display:
459 * @va_display: a #VADisplay
461 * Creates a new #GstVaapiDisplay, using @va_display as the VA
464 * Return value: the newly created #GstVaapiDisplay object
467 gst_vaapi_display_new_with_display(VADisplay va_display)
469 return g_object_new(GST_VAAPI_TYPE_DISPLAY,
470 "display", va_display,
475 * gst_vaapi_display_lock:
476 * @display: a #GstVaapiDisplay
478 * Locks @display. If @display is already locked by another thread,
479 * the current thread will block until @display is unlocked by the
483 gst_vaapi_display_lock(GstVaapiDisplay *display)
485 GstVaapiDisplayClass *klass;
487 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
489 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
490 if (klass->lock_display)
491 klass->lock_display(display);
495 * gst_vaapi_display_unlock:
496 * @display: a #GstVaapiDisplay
498 * Unlocks @display. If another thread is blocked in a
499 * gst_vaapi_display_lock() call for @display, it will be woken and
500 * can lock @display itself.
503 gst_vaapi_display_unlock(GstVaapiDisplay *display)
505 GstVaapiDisplayClass *klass;
507 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
509 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
510 if (klass->unlock_display)
511 klass->unlock_display(display);
515 * gst_vaapi_display_get_display:
516 * @display: a #GstVaapiDisplay
518 * Returns the #VADisplay bound to @display.
520 * Return value: the #VADisplay
523 gst_vaapi_display_get_display(GstVaapiDisplay *display)
525 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
527 return display->priv->display;
531 * gst_vaapi_display_get_width:
532 * @display: a #GstVaapiDisplay
534 * Retrieves the width of a #GstVaapiDisplay.
536 * Return value: the width of the @display, in pixels
539 gst_vaapi_display_get_width(GstVaapiDisplay *display)
541 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
543 return display->priv->width;
547 * gst_vaapi_display_get_height:
548 * @display: a #GstVaapiDisplay
550 * Retrieves the height of a #GstVaapiDisplay
552 * Return value: the height of the @display, in pixels
555 gst_vaapi_display_get_height(GstVaapiDisplay *display)
557 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0);
559 return display->priv->height;
563 * gst_vaapi_display_get_size:
564 * @display: a #GstVaapiDisplay
565 * @pwidth: (out) (allow-none): return location for the width, or %NULL
566 * @pheight: (out) (allow-none): return location for the height, or %NULL
568 * Retrieves the dimensions of a #GstVaapiDisplay.
571 gst_vaapi_display_get_size(GstVaapiDisplay *display, guint *pwidth, guint *pheight)
573 g_return_if_fail(GST_VAAPI_DISPLAY(display));
576 *pwidth = display->priv->width;
579 *pheight = display->priv->height;
583 * gst_vaapi_display_has_profile:
584 * @display: a #GstVaapiDisplay
585 * @profile: a #VAProfile
587 * Returns whether VA @display supports @profile.
589 * Return value: %TRUE if VA @display supports @profile
592 gst_vaapi_display_has_profile(GstVaapiDisplay *display, VAProfile profile)
594 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
596 return find_profile(display->priv->profiles, profile);
600 * gst_vaapi_display_get_image_caps:
601 * @display: a #GstVaapiDisplay
603 * Gets the supported image formats for gst_vaapi_surface_get_image()
604 * or gst_vaapi_surface_put_image() as #GstCaps capabilities.
606 * Note that this method does not necessarily map image formats
607 * returned by vaQueryImageFormats(). The set of capabilities can be
608 * stripped down, if gstreamer-vaapi does not support the format, or
609 * expanded to cover compatible formats not exposed by the underlying
610 * driver. e.g. I420 can be supported even if the driver only exposes
613 * Return value: a newly allocated #GstCaps object, possibly empty
616 gst_vaapi_display_get_image_caps(GstVaapiDisplay *display)
618 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
620 return get_caps(display->priv->image_formats);
624 * gst_vaapi_display_has_image_format:
625 * @display: a #GstVaapiDisplay
626 * @format: a #GstVaapiFormat
628 * Returns whether VA @display supports @format image format.
630 * Return value: %TRUE if VA @display supports @format image format
633 gst_vaapi_display_has_image_format(
634 GstVaapiDisplay *display,
635 GstVaapiImageFormat format
638 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
639 g_return_val_if_fail(format, FALSE);
641 return find_format(display->priv->image_formats, format);
645 * gst_vaapi_display_get_subpicture_caps:
646 * @display: a #GstVaapiDisplay
648 * Gets the supported subpicture formats as #GstCaps capabilities.
650 * Note that this method does not necessarily map subpicture formats
651 * returned by vaQuerySubpictureFormats(). The set of capabilities can
652 * be stripped down if gstreamer-vaapi does not support the
653 * format. e.g. this is the case for paletted formats like IA44.
655 * Return value: a newly allocated #GstCaps object, possibly empty
658 gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display)
660 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
662 return get_caps(display->priv->subpicture_formats);
666 * gst_vaapi_display_has_subpicture_format:
667 * @display: a #GstVaapiDisplay
668 * @format: a #GstVaapiFormat
670 * Returns whether VA @display supports @format subpicture format.
672 * Return value: %TRUE if VA @display supports @format subpicture format
675 gst_vaapi_display_has_subpicture_format(
676 GstVaapiDisplay *display,
677 GstVaapiImageFormat format
680 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
681 g_return_val_if_fail(format, FALSE);
683 return find_format(display->priv->subpicture_formats, format);