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 {
46 gboolean create_display;
48 GArray *image_formats;
49 GArray *subpicture_formats;
58 /* Append GstVaapiImageFormat to formats array */
60 append_format(GArray *formats, GstVaapiImageFormat format)
62 g_array_append_val(formats, format);
65 /* Append VAImageFormats to formats array */
67 append_formats(GArray *formats, const VAImageFormat *va_formats, guint n)
69 GstVaapiImageFormat format;
70 gboolean has_YV12 = FALSE;
71 gboolean has_I420 = FALSE;
74 for (i = 0; i < n; i++) {
75 const VAImageFormat * const va_format = &va_formats[i];
77 format = gst_vaapi_image_format(va_format);
79 GST_DEBUG("unsupported format %" GST_FOURCC_FORMAT,
80 GST_FOURCC_ARGS(va_format->fourcc));
85 case GST_VAAPI_IMAGE_YV12:
88 case GST_VAAPI_IMAGE_I420:
94 append_format(formats, format);
97 /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
98 supported by the underlying driver */
99 if (has_YV12 && !has_I420)
100 append_format(formats, GST_VAAPI_IMAGE_I420);
101 else if (has_I420 && !has_YV12)
102 append_format(formats, GST_VAAPI_IMAGE_YV12);
105 /* Sort image formats. Prefer YUV formats first */
107 compare_yuv_formats(gconstpointer a, gconstpointer b)
109 const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
110 const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
112 const gboolean is_fmt1_yuv = gst_vaapi_image_format_is_yuv(fmt1);
113 const gboolean is_fmt2_yuv = gst_vaapi_image_format_is_yuv(fmt2);
115 if (is_fmt1_yuv != is_fmt2_yuv)
116 return is_fmt1_yuv ? -1 : 1;
118 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
119 (gint)gst_vaapi_image_format_get_score(fmt2));
122 /* Sort subpicture formats. Prefer RGB formats first */
124 compare_rgb_formats(gconstpointer a, gconstpointer b)
126 const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
127 const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
129 const gboolean is_fmt1_rgb = gst_vaapi_image_format_is_rgb(fmt1);
130 const gboolean is_fmt2_rgb = gst_vaapi_image_format_is_rgb(fmt2);
132 if (is_fmt1_rgb != is_fmt2_rgb)
133 return is_fmt1_rgb ? -1 : 1;
135 return ((gint)gst_vaapi_image_format_get_score(fmt1) -
136 (gint)gst_vaapi_image_format_get_score(fmt2));
139 /* Check if profiles array contains profile */
140 static inline gboolean
141 find_profile(GArray *profiles, VAProfile profile)
145 for (i = 0; i < profiles->len; i++)
146 if (g_array_index(profiles, VAProfile, i) == profile)
151 /* Check if formats array contains format */
152 static inline gboolean
153 find_format(GArray *formats, GstVaapiImageFormat format)
157 for (i = 0; i < formats->len; i++)
158 if (g_array_index(formats, GstVaapiImageFormat, i) == format)
163 /* Convert formats array to GstCaps */
165 get_caps(GArray *formats)
167 GstVaapiImageFormat format;
168 GstCaps *out_caps, *caps;
171 out_caps = gst_caps_new_empty();
175 for (i = 0; i < formats->len; i++) {
176 format = g_array_index(formats, GstVaapiImageFormat, i);
177 caps = gst_vaapi_image_format_get_caps(format);
179 gst_caps_append(out_caps, caps);
185 gst_vaapi_display_destroy(GstVaapiDisplay *display)
187 GstVaapiDisplayPrivate * const priv = display->priv;
189 if (priv->profiles) {
190 g_array_free(priv->profiles, TRUE);
191 priv->profiles = NULL;
194 if (priv->image_formats) {
195 g_array_free(priv->image_formats, TRUE);
196 priv->image_formats = NULL;
199 if (priv->subpicture_formats) {
200 g_array_free(priv->subpicture_formats, TRUE);
201 priv->subpicture_formats = NULL;
205 vaTerminate(priv->display);
206 priv->display = NULL;
209 if (priv->create_display) {
210 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
211 if (klass->close_display)
212 klass->close_display(display);
217 gst_vaapi_display_create(GstVaapiDisplay *display)
219 GstVaapiDisplayPrivate * const priv = display->priv;
220 gboolean has_errors = TRUE;
221 VAProfile *profiles = NULL;
222 VAImageFormat *formats = NULL;
223 unsigned int *flags = NULL;
224 gint i, n, major_version, minor_version;
227 if (!priv->display && priv->create_display) {
228 GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
229 if (klass->open_display && !klass->open_display(display))
231 if (klass->get_display)
232 priv->display = klass->get_display(display);
237 status = vaInitialize(priv->display, &major_version, &minor_version);
238 if (!vaapi_check_status(status, "vaInitialize()"))
240 GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
243 profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display));
246 status = vaQueryConfigProfiles(priv->display, profiles, &n);
247 if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
250 GST_DEBUG("%d profiles", n);
251 for (i = 0; i < n; i++)
252 GST_DEBUG(" %s", string_of_VAProfile(profiles[i]));
254 priv->profiles = g_array_new(FALSE, FALSE, sizeof(VAProfile));
257 g_array_append_vals(priv->profiles, profiles, n);
259 /* VA image formats */
260 formats = g_new(VAImageFormat, vaMaxNumImageFormats(priv->display));
263 status = vaQueryImageFormats(priv->display, formats, &n);
264 if (!vaapi_check_status(status, "vaQueryImageFormats()"))
267 GST_DEBUG("%d image formats", n);
268 for (i = 0; i < n; i++)
269 GST_DEBUG(" %s", string_of_FOURCC(formats[i].fourcc));
271 priv->image_formats =
272 g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
273 if (!priv->image_formats)
275 append_formats(priv->image_formats, formats, n);
276 g_array_sort(priv->image_formats, compare_yuv_formats);
278 /* VA subpicture formats */
279 n = vaMaxNumSubpictureFormats(priv->display);
280 formats = g_renew(VAImageFormat, formats, n);
281 flags = g_new(guint, n);
282 if (!formats || !flags)
284 status = vaQuerySubpictureFormats(priv->display, formats, flags, &n);
285 if (!vaapi_check_status(status, "vaQuerySubpictureFormats()"))
288 GST_DEBUG("%d subpicture formats", n);
289 for (i = 0; i < n; i++)
290 GST_DEBUG(" %s", string_of_FOURCC(formats[i].fourcc));
292 priv->subpicture_formats =
293 g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
294 if (!priv->subpicture_formats)
296 append_formats(priv->subpicture_formats, formats, n);
297 g_array_sort(priv->subpicture_formats, compare_rgb_formats);
308 gst_vaapi_display_lock_default(GstVaapiDisplay *display)
310 g_static_mutex_lock(&display->priv->mutex);
314 gst_vaapi_display_unlock_default(GstVaapiDisplay *display)
316 g_static_mutex_unlock(&display->priv->mutex);
320 gst_vaapi_display_finalize(GObject *object)
322 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
324 gst_vaapi_display_destroy(display);
326 G_OBJECT_CLASS(gst_vaapi_display_parent_class)->finalize(object);
330 gst_vaapi_display_set_property(
337 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
341 display->priv->display = g_value_get_pointer(value);
344 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
350 gst_vaapi_display_get_property(
357 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
361 g_value_set_pointer(value, gst_vaapi_display_get_display(display));
364 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
370 gst_vaapi_display_constructed(GObject *object)
372 GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
373 GObjectClass *parent_class;
375 display->priv->create_display = display->priv->display == NULL;
376 gst_vaapi_display_create(display);
378 parent_class = G_OBJECT_CLASS(gst_vaapi_display_parent_class);
379 if (parent_class->constructed)
380 parent_class->constructed(object);
384 gst_vaapi_display_class_init(GstVaapiDisplayClass *klass)
386 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
387 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
389 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi, "vaapi", 0, "VA-API helper");
391 g_type_class_add_private(klass, sizeof(GstVaapiDisplayPrivate));
393 object_class->finalize = gst_vaapi_display_finalize;
394 object_class->set_property = gst_vaapi_display_set_property;
395 object_class->get_property = gst_vaapi_display_get_property;
396 object_class->constructed = gst_vaapi_display_constructed;
398 dpy_class->lock_display = gst_vaapi_display_lock_default;
399 dpy_class->unlock_display = gst_vaapi_display_unlock_default;
401 g_object_class_install_property
404 g_param_spec_pointer("display",
407 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
411 gst_vaapi_display_init(GstVaapiDisplay *display)
413 GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display);
415 display->priv = priv;
416 priv->display = NULL;
417 priv->create_display = TRUE;
418 priv->profiles = NULL;
419 priv->image_formats = NULL;
420 priv->subpicture_formats = NULL;
422 g_static_mutex_init(&priv->mutex);
426 * gst_vaapi_display_new_with_display:
427 * @va_display: a #VADisplay
429 * Creates a new #GstVaapiDisplay, using @va_display as the VA
432 * Return value: the newly created #GstVaapiDisplay object
435 gst_vaapi_display_new_with_display(VADisplay va_display)
437 return g_object_new(GST_VAAPI_TYPE_DISPLAY,
438 "display", va_display,
443 * gst_vaapi_display_lock:
444 * @display: a #GstVaapiDisplay
446 * Locks @display. If @display is already locked by another thread,
447 * the current thread will block until @display is unlocked by the
451 gst_vaapi_display_lock(GstVaapiDisplay *display)
453 GstVaapiDisplayClass *klass;
455 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
457 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
458 if (klass->lock_display)
459 klass->lock_display(display);
463 * gst_vaapi_display_unlock:
464 * @display: a #GstVaapiDisplay
466 * Unlocks @display. If another thread is blocked in a
467 * gst_vaapi_display_lock() call for @display, it will be woken and
468 * can lock @display itself.
471 gst_vaapi_display_unlock(GstVaapiDisplay *display)
473 GstVaapiDisplayClass *klass;
475 g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
477 klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
478 if (klass->unlock_display)
479 klass->unlock_display(display);
483 * gst_vaapi_display_get_display:
484 * @display: a #GstVaapiDisplay
486 * Returns the #VADisplay bound to @display.
488 * Return value: the #VADisplay
491 gst_vaapi_display_get_display(GstVaapiDisplay *display)
493 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
495 return display->priv->display;
499 * gst_vaapi_display_has_profile:
500 * @display: a #GstVaapiDisplay
501 * @profile: a #VAProfile
503 * Returns whether VA @display supports @profile.
505 * Return value: %TRUE if VA @display supports @profile
508 gst_vaapi_display_has_profile(GstVaapiDisplay *display, VAProfile profile)
510 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
512 return find_profile(display->priv->profiles, profile);
516 * gst_vaapi_display_get_image_caps:
517 * @display: a #GstVaapiDisplay
519 * Gets the supported image formats for gst_vaapi_surface_get_image()
520 * or gst_vaapi_surface_put_image() as #GstCaps capabilities.
522 * Note that this method does not necessarily map image formats
523 * returned by vaQueryImageFormats(). The set of capabilities can be
524 * stripped down, if gstreamer-vaapi does not support the format, or
525 * expanded to cover compatible formats not exposed by the underlying
526 * driver. e.g. I420 can be supported even if the driver only exposes
529 * Return value: a newly allocated #GstCaps object, possibly empty
532 gst_vaapi_display_get_image_caps(GstVaapiDisplay *display)
534 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
536 return get_caps(display->priv->image_formats);
540 * gst_vaapi_display_has_image_format:
541 * @display: a #GstVaapiDisplay
542 * @format: a #GstVaapiFormat
544 * Returns whether VA @display supports @format image format.
546 * Return value: %TRUE if VA @display supports @format image format
549 gst_vaapi_display_has_image_format(
550 GstVaapiDisplay *display,
551 GstVaapiImageFormat format
554 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
555 g_return_val_if_fail(format, FALSE);
557 return find_format(display->priv->image_formats, format);
561 * gst_vaapi_display_get_subpicture_caps:
562 * @display: a #GstVaapiDisplay
564 * Gets the supported subpicture formats as #GstCaps capabilities.
566 * Note that this method does not necessarily map subpicture formats
567 * returned by vaQuerySubpictureFormats(). The set of capabilities can
568 * be stripped down if gstreamer-vaapi does not support the
569 * format. e.g. this is the case for paletted formats like IA44.
571 * Return value: a newly allocated #GstCaps object, possibly empty
574 gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display)
576 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
578 return get_caps(display->priv->subpicture_formats);
582 * gst_vaapi_display_has_subpicture_format:
583 * @display: a #GstVaapiDisplay
584 * @format: a #GstVaapiFormat
586 * Returns whether VA @display supports @format subpicture format.
588 * Return value: %TRUE if VA @display supports @format subpicture format
591 gst_vaapi_display_has_subpicture_format(
592 GstVaapiDisplay *display,
593 GstVaapiImageFormat format
596 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
597 g_return_val_if_fail(format, FALSE);
599 return find_format(display->priv->subpicture_formats, format);