a6c0f76635b7e2151c1fc2fb3894a98bb37783dc
[profile/ivi/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidisplay.c
1 /*
2  *  gstvaapidisplay.c - VA display abstraction
3  *
4  *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
5  *
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.
10  *
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.
15  *
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
19  */
20
21 /**
22  * SECTION:gst-vaapi-display
23  * @short_description:
24  */
25
26 #include "config.h"
27 #include "gstvaapiutils.h"
28 #include "gstvaapidisplay.h"
29 #include <va/va_backend.h>
30
31 #define DEBUG 1
32 #include "gstvaapidebug.h"
33
34 GST_DEBUG_CATEGORY(gst_debug_vaapi);
35
36 G_DEFINE_TYPE(GstVaapiDisplay, gst_vaapi_display, G_TYPE_OBJECT);
37
38 #define GST_VAAPI_DISPLAY_GET_PRIVATE(obj)                      \
39     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
40                                  GST_VAAPI_TYPE_DISPLAY,        \
41                                  GstVaapiDisplayPrivate))
42
43 struct _GstVaapiDisplayPrivate {
44     GStaticMutex        mutex;
45     VADisplay           display;
46     gboolean            create_display;
47     GArray             *profiles;
48     GArray             *image_formats;
49     GArray             *subpicture_formats;
50 };
51
52 enum {
53     PROP_0,
54
55     PROP_DISPLAY
56 };
57
58 /* Append GstVaapiImageFormat to formats array */
59 static inline void
60 append_format(GArray *formats, GstVaapiImageFormat format)
61 {
62     g_array_append_val(formats, format);
63 }
64
65 /* Append VAImageFormats to formats array */
66 static void
67 append_formats(GArray *formats, const VAImageFormat *va_formats, guint n)
68 {
69     GstVaapiImageFormat format;
70     gboolean has_YV12 = FALSE;
71     gboolean has_I420 = FALSE;
72     guint i;
73
74     for (i = 0; i < n; i++) {
75         const VAImageFormat * const va_format = &va_formats[i];
76
77         format = gst_vaapi_image_format(va_format);
78         if (!format) {
79             GST_DEBUG("unsupported format %" GST_FOURCC_FORMAT,
80                       GST_FOURCC_ARGS(va_format->fourcc));
81             continue;
82         }
83
84         switch (format) {
85         case GST_VAAPI_IMAGE_YV12:
86             has_YV12 = TRUE;
87             break;
88         case GST_VAAPI_IMAGE_I420:
89             has_I420 = TRUE;
90             break;
91         default:
92             break;
93         }
94         append_format(formats, format);
95     }
96
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);
103 }
104
105 /* Sort image formats. Prefer YUV formats first */
106 static gint
107 compare_yuv_formats(gconstpointer a, gconstpointer b)
108 {
109     const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
110     const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
111
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);
114
115     if (is_fmt1_yuv != is_fmt2_yuv)
116         return is_fmt1_yuv ? -1 : 1;
117
118     return ((gint)gst_vaapi_image_format_get_score(fmt1) -
119             (gint)gst_vaapi_image_format_get_score(fmt2));
120 }
121
122 /* Sort subpicture formats. Prefer RGB formats first */
123 static gint
124 compare_rgb_formats(gconstpointer a, gconstpointer b)
125 {
126     const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a;
127     const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b;
128
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);
131
132     if (is_fmt1_rgb != is_fmt2_rgb)
133         return is_fmt1_rgb ? -1 : 1;
134
135     return ((gint)gst_vaapi_image_format_get_score(fmt1) -
136             (gint)gst_vaapi_image_format_get_score(fmt2));
137 }
138
139 /* Check if profiles array contains profile */
140 static inline gboolean
141 find_profile(GArray *profiles, VAProfile profile)
142 {
143     guint i;
144
145     for (i = 0; i < profiles->len; i++)
146         if (g_array_index(profiles, VAProfile, i) == profile)
147             return TRUE;
148     return FALSE;
149 }
150
151 /* Check if formats array contains format */
152 static inline gboolean
153 find_format(GArray *formats, GstVaapiImageFormat format)
154 {
155     guint i;
156
157     for (i = 0; i < formats->len; i++)
158         if (g_array_index(formats, GstVaapiImageFormat, i) == format)
159             return TRUE;
160     return FALSE;
161 }
162
163 /* Convert formats array to GstCaps */
164 static GstCaps *
165 get_caps(GArray *formats)
166 {
167     GstVaapiImageFormat format;
168     GstCaps *out_caps, *caps;
169     guint i;
170
171     out_caps = gst_caps_new_empty();
172     if (!out_caps)
173         return NULL;
174
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);
178         if (caps)
179             gst_caps_append(out_caps, caps);
180     }
181     return out_caps;
182 }
183
184 static void
185 gst_vaapi_display_destroy(GstVaapiDisplay *display)
186 {
187     GstVaapiDisplayPrivate * const priv = display->priv;
188
189     if (priv->profiles) {
190         g_array_free(priv->profiles, TRUE);
191         priv->profiles = NULL;
192     }
193
194     if (priv->image_formats) {
195         g_array_free(priv->image_formats, TRUE);
196         priv->image_formats = NULL;
197     }
198
199     if (priv->subpicture_formats) {
200         g_array_free(priv->subpicture_formats, TRUE);
201         priv->subpicture_formats = NULL;
202     }
203
204     if (priv->display) {
205         vaTerminate(priv->display);
206         priv->display = NULL;
207     }
208
209     if (priv->create_display) {
210         GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
211         if (klass->close_display)
212             klass->close_display(display);
213     }
214 }
215
216 static gboolean
217 gst_vaapi_display_create(GstVaapiDisplay *display)
218 {
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;
225     VAStatus            status;
226
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))
230             return FALSE;
231         if (klass->get_display)
232             priv->display = klass->get_display(display);
233     }
234     if (!priv->display)
235         return FALSE;
236
237     status = vaInitialize(priv->display, &major_version, &minor_version);
238     if (!vaapi_check_status(status, "vaInitialize()"))
239         goto end;
240     GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
241
242     /* VA profiles */
243     profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display));
244     if (!profiles)
245         goto end;
246     status = vaQueryConfigProfiles(priv->display, profiles, &n);
247     if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
248         goto end;
249
250     GST_DEBUG("%d profiles", n);
251     for (i = 0; i < n; i++)
252         GST_DEBUG("  %s", string_of_VAProfile(profiles[i]));
253
254     priv->profiles = g_array_new(FALSE, FALSE, sizeof(VAProfile));
255     if (!priv->profiles)
256         goto end;
257     g_array_append_vals(priv->profiles, profiles, n);
258
259     /* VA image formats */
260     formats = g_new(VAImageFormat, vaMaxNumImageFormats(priv->display));
261     if (!formats)
262         goto end;
263     status = vaQueryImageFormats(priv->display, formats, &n);
264     if (!vaapi_check_status(status, "vaQueryImageFormats()"))
265         goto end;
266
267     GST_DEBUG("%d image formats", n);
268     for (i = 0; i < n; i++)
269         GST_DEBUG("  %s", string_of_FOURCC(formats[i].fourcc));
270
271     priv->image_formats =
272         g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
273     if (!priv->image_formats)
274         goto end;
275     append_formats(priv->image_formats, formats, n);
276     g_array_sort(priv->image_formats, compare_yuv_formats);
277
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)
283         goto end;
284     status = vaQuerySubpictureFormats(priv->display, formats, flags, &n);
285     if (!vaapi_check_status(status, "vaQuerySubpictureFormats()"))
286         goto end;
287
288     GST_DEBUG("%d subpicture formats", n);
289     for (i = 0; i < n; i++)
290         GST_DEBUG("  %s", string_of_FOURCC(formats[i].fourcc));
291
292     priv->subpicture_formats =
293         g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat));
294     if (!priv->subpicture_formats)
295         goto end;
296     append_formats(priv->subpicture_formats, formats, n);
297     g_array_sort(priv->subpicture_formats, compare_rgb_formats);
298
299     has_errors = FALSE;
300 end:
301     g_free(profiles);
302     g_free(formats);
303     g_free(flags);
304     return !has_errors;
305 }
306
307 static void
308 gst_vaapi_display_lock_default(GstVaapiDisplay *display)
309 {
310     g_static_mutex_lock(&display->priv->mutex);
311 }
312
313 static void
314 gst_vaapi_display_unlock_default(GstVaapiDisplay *display)
315 {
316     g_static_mutex_unlock(&display->priv->mutex);
317 }
318
319 static void
320 gst_vaapi_display_finalize(GObject *object)
321 {
322     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
323
324     gst_vaapi_display_destroy(display);
325
326     G_OBJECT_CLASS(gst_vaapi_display_parent_class)->finalize(object);
327 }
328
329 static void
330 gst_vaapi_display_set_property(
331     GObject      *object,
332     guint         prop_id,
333     const GValue *value,
334     GParamSpec   *pspec
335 )
336 {
337     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
338
339     switch (prop_id) {
340     case PROP_DISPLAY:
341         display->priv->display = g_value_get_pointer(value);
342         break;
343     default:
344         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
345         break;
346     }
347 }
348
349 static void
350 gst_vaapi_display_get_property(
351     GObject    *object,
352     guint       prop_id,
353     GValue     *value,
354     GParamSpec *pspec
355 )
356 {
357     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
358
359     switch (prop_id) {
360     case PROP_DISPLAY:
361         g_value_set_pointer(value, gst_vaapi_display_get_display(display));
362         break;
363     default:
364         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
365         break;
366     }
367 }
368
369 static void
370 gst_vaapi_display_constructed(GObject *object)
371 {
372     GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object);
373     GObjectClass *parent_class;
374
375     display->priv->create_display = display->priv->display == NULL;
376     gst_vaapi_display_create(display);
377
378     parent_class = G_OBJECT_CLASS(gst_vaapi_display_parent_class);
379     if (parent_class->constructed)
380         parent_class->constructed(object);
381 }
382
383 static void
384 gst_vaapi_display_class_init(GstVaapiDisplayClass *klass)
385 {
386     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
387     GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
388
389     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi, "vaapi", 0, "VA-API helper");
390
391     g_type_class_add_private(klass, sizeof(GstVaapiDisplayPrivate));
392
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;
397
398     dpy_class->lock_display     = gst_vaapi_display_lock_default;
399     dpy_class->unlock_display   = gst_vaapi_display_unlock_default;
400
401     g_object_class_install_property
402         (object_class,
403          PROP_DISPLAY,
404          g_param_spec_pointer("display",
405                               "VA display",
406                               "VA display",
407                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
408 }
409
410 static void
411 gst_vaapi_display_init(GstVaapiDisplay *display)
412 {
413     GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display);
414
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;
421
422     g_static_mutex_init(&priv->mutex);
423 }
424
425 /**
426  * gst_vaapi_display_new_with_display:
427  * @va_display: a #VADisplay
428  *
429  * Creates a new #GstVaapiDisplay, using @va_display as the VA
430  * display.
431  *
432  * Return value: the newly created #GstVaapiDisplay object
433  */
434 GstVaapiDisplay *
435 gst_vaapi_display_new_with_display(VADisplay va_display)
436 {
437     return g_object_new(GST_VAAPI_TYPE_DISPLAY,
438                         "display", va_display,
439                         NULL);
440 }
441
442 /**
443  * gst_vaapi_display_lock:
444  * @display: a #GstVaapiDisplay
445  *
446  * Locks @display. If @display is already locked by another thread,
447  * the current thread will block until @display is unlocked by the
448  * other thread.
449  */
450 void
451 gst_vaapi_display_lock(GstVaapiDisplay *display)
452 {
453     GstVaapiDisplayClass *klass;
454
455     g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
456
457     klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
458     if (klass->lock_display)
459         klass->lock_display(display);
460 }
461
462 /**
463  * gst_vaapi_display_unlock:
464  * @display: a #GstVaapiDisplay
465  *
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.
469  */
470 void
471 gst_vaapi_display_unlock(GstVaapiDisplay *display)
472 {
473     GstVaapiDisplayClass *klass;
474
475     g_return_if_fail(GST_VAAPI_IS_DISPLAY(display));
476
477     klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
478     if (klass->unlock_display)
479         klass->unlock_display(display);
480 }
481
482 /**
483  * gst_vaapi_display_get_display:
484  * @display: a #GstVaapiDisplay
485  *
486  * Returns the #VADisplay bound to @display.
487  *
488  * Return value: the #VADisplay
489  */
490 VADisplay
491 gst_vaapi_display_get_display(GstVaapiDisplay *display)
492 {
493     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
494
495     return display->priv->display;
496 }
497
498 /**
499  * gst_vaapi_display_has_profile:
500  * @display: a #GstVaapiDisplay
501  * @profile: a #VAProfile
502  *
503  * Returns whether VA @display supports @profile.
504  *
505  * Return value: %TRUE if VA @display supports @profile
506  */
507 gboolean
508 gst_vaapi_display_has_profile(GstVaapiDisplay *display, VAProfile profile)
509 {
510     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
511
512     return find_profile(display->priv->profiles, profile);
513 }
514
515 /**
516  * gst_vaapi_display_get_image_caps:
517  * @display: a #GstVaapiDisplay
518  *
519  * Gets the supported image formats for gst_vaapi_surface_get_image()
520  * or gst_vaapi_surface_put_image() as #GstCaps capabilities.
521  *
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
527  * YV12.
528  *
529  * Return value: a newly allocated #GstCaps object, possibly empty
530  */
531 GstCaps *
532 gst_vaapi_display_get_image_caps(GstVaapiDisplay *display)
533 {
534     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
535
536     return get_caps(display->priv->image_formats);
537 }
538
539 /**
540  * gst_vaapi_display_has_image_format:
541  * @display: a #GstVaapiDisplay
542  * @format: a #GstVaapiFormat
543  *
544  * Returns whether VA @display supports @format image format.
545  *
546  * Return value: %TRUE if VA @display supports @format image format
547  */
548 gboolean
549 gst_vaapi_display_has_image_format(
550     GstVaapiDisplay    *display,
551     GstVaapiImageFormat format
552 )
553 {
554     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
555     g_return_val_if_fail(format, FALSE);
556
557     return find_format(display->priv->image_formats, format);
558 }
559
560 /**
561  * gst_vaapi_display_get_subpicture_caps:
562  * @display: a #GstVaapiDisplay
563  *
564  * Gets the supported subpicture formats as #GstCaps capabilities.
565  *
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.
570  *
571  * Return value: a newly allocated #GstCaps object, possibly empty
572  */
573 GstCaps *
574 gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display)
575 {
576     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
577
578     return get_caps(display->priv->subpicture_formats);
579 }
580
581 /**
582  * gst_vaapi_display_has_subpicture_format:
583  * @display: a #GstVaapiDisplay
584  * @format: a #GstVaapiFormat
585  *
586  * Returns whether VA @display supports @format subpicture format.
587  *
588  * Return value: %TRUE if VA @display supports @format subpicture format
589  */
590 gboolean
591 gst_vaapi_display_has_subpicture_format(
592     GstVaapiDisplay    *display,
593     GstVaapiImageFormat format
594 )
595 {
596     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
597     g_return_val_if_fail(format, FALSE);
598
599     return find_format(display->priv->subpicture_formats, format);
600 }