2 * Copyright (C) 2020 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
25 #include "gstvacaps.h"
27 #include <gst/va/gstvavideoformat.h>
28 #include <va/va_drmcommon.h>
30 #include "gstvadisplay_priv.h"
31 #include "gstvaprofile.h"
33 GST_DEBUG_CATEGORY_EXTERN (gstva_debug);
34 #define GST_CAT_DEFAULT gstva_debug
36 static const guint va_rt_format_list[] = {
37 #define R(name) G_PASTE (VA_RT_FORMAT_, name)
60 gst_va_get_surface_attribs (GstVaDisplay * display, VAConfigID config,
64 VASurfaceAttrib *attribs;
67 dpy = gst_va_display_get_va_dpy (display);
69 status = vaQuerySurfaceAttributes (dpy, config, NULL, attrib_count);
70 if (status != VA_STATUS_SUCCESS) {
71 GST_ERROR_OBJECT (display, "vaQuerySurfaceAttributes: %s",
76 attribs = g_new (VASurfaceAttrib, *attrib_count);
78 status = vaQuerySurfaceAttributes (dpy, config, attribs, attrib_count);
79 if (status != VA_STATUS_SUCCESS) {
80 GST_ERROR_OBJECT (display, "vaQuerySurfaceAttributes: %s",
93 _value_list_append_string (GValue * list, const gchar * str)
95 GValue item = G_VALUE_INIT;
97 g_value_init (&item, G_TYPE_STRING);
98 g_value_set_string (&item, str);
99 gst_value_list_append_value (list, &item);
100 g_value_unset (&item);
104 gst_caps_set_format_array (GstCaps * caps, GArray * formats)
107 GValue v_formats = G_VALUE_INIT;
111 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
112 g_return_val_if_fail (formats, FALSE);
114 if (formats->len == 1) {
115 fmt = g_array_index (formats, GstVideoFormat, 0);
116 if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
118 format = gst_video_format_to_string (fmt);
122 g_value_init (&v_formats, G_TYPE_STRING);
123 g_value_set_string (&v_formats, format);
124 } else if (formats->len > 1) {
126 gst_value_list_init (&v_formats, formats->len);
128 for (i = 0; i < formats->len; i++) {
129 fmt = g_array_index (formats, GstVideoFormat, i);
130 if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
132 format = gst_video_format_to_string (fmt);
136 _value_list_append_string (&v_formats, format);
142 gst_caps_set_value (caps, "format", &v_formats);
143 g_value_unset (&v_formats);
148 /* Fix raw frames ill reported by drivers.
150 * Mesa Gallium reports P010 and P016 for H264 encoder:
151 * https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19443
153 * Intel i965: reports I420 and YV12
154 * XXX: add issue or pr
157 fix_raw_formats (GstVaDisplay * display, VAConfigID config, GArray * formats)
162 VAEntrypoint entrypoint;
163 VAConfigAttrib *attribs;
164 GstVideoFormat format;
167 if (!(GST_VA_DISPLAY_IS_IMPLEMENTATION (display, INTEL_I965) ||
168 GST_VA_DISPLAY_IS_IMPLEMENTATION (display, MESA_GALLIUM)))
171 dpy = gst_va_display_get_va_dpy (display);
172 attribs = g_new (VAConfigAttrib, vaMaxNumConfigAttributes (dpy));
173 status = vaQueryConfigAttributes (dpy, config, &profile, &entrypoint, attribs,
177 if (status != VA_STATUS_SUCCESS) {
178 GST_ERROR_OBJECT (display, "vaQueryConfigAttributes: %s",
179 vaErrorStr (status));
183 if (gst_va_profile_codec (profile) != H264
184 || entrypoint != VAEntrypointEncSlice)
187 formats = g_array_set_size (formats, 0);
188 format = GST_VIDEO_FORMAT_NV12;
189 g_array_append_val (formats, format);
194 gst_va_create_raw_caps_from_config (GstVaDisplay * display, VAConfigID config)
197 GstCaps *caps = NULL, *base_caps, *feature_caps;
198 GstCapsFeatures *features;
199 GstVideoFormat format;
200 VASurfaceAttrib *attribs;
201 guint i, attrib_count, mem_type = 0;
202 gint min_width = 1, max_width = G_MAXINT;
203 gint min_height = 1, max_height = G_MAXINT;
205 attribs = gst_va_get_surface_attribs (display, config, &attrib_count);
208 formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
210 for (i = 0; i < attrib_count; i++) {
211 if (attribs[i].value.type != VAGenericValueTypeInteger)
213 switch (attribs[i].type) {
214 case VASurfaceAttribPixelFormat:
215 format = gst_va_video_format_from_va_fourcc (attribs[i].value.value.i);
216 if (format != GST_VIDEO_FORMAT_UNKNOWN)
217 g_array_append_val (formats, format);
219 case VASurfaceAttribMinWidth:
220 min_width = MAX (min_width, attribs[i].value.value.i);
222 case VASurfaceAttribMaxWidth:
223 max_width = attribs[i].value.value.i;
225 case VASurfaceAttribMinHeight:
226 min_height = MAX (min_height, attribs[i].value.value.i);
228 case VASurfaceAttribMaxHeight:
229 max_height = attribs[i].value.value.i;
231 case VASurfaceAttribMemoryType:
232 mem_type = attribs[i].value.value.i;
239 /* if driver doesn't report surface formats for current
240 * chroma. Gallium AMD bug for 4:2:2 */
241 if (formats->len == 0)
244 if (!fix_raw_formats (display, config, formats))
247 base_caps = gst_caps_new_simple ("video/x-raw", "width", GST_TYPE_INT_RANGE,
248 min_width, max_width, "height", GST_TYPE_INT_RANGE, min_height,
251 if (!gst_caps_set_format_array (base_caps, formats)) {
252 gst_caps_unref (base_caps);
256 caps = gst_caps_new_empty ();
258 if (mem_type & VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
259 feature_caps = gst_caps_copy (base_caps);
260 features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA);
261 gst_caps_set_features_simple (feature_caps, features);
262 caps = gst_caps_merge (caps, feature_caps);
264 if (mem_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
265 || mem_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) {
266 feature_caps = gst_caps_copy (base_caps);
267 features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF);
268 gst_caps_set_features_simple (feature_caps, features);
269 caps = gst_caps_merge (caps, feature_caps);
273 caps = gst_caps_merge (caps, gst_caps_copy (base_caps));
275 gst_caps_unref (base_caps);
278 g_array_unref (formats);
285 gst_va_create_raw_caps (GstVaDisplay * display, VAProfile profile,
286 VAEntrypoint entrypoint, guint rt_format)
289 VAConfigAttrib attrib = {
290 .type = VAConfigAttribRTFormat,
297 dpy = gst_va_display_get_va_dpy (display);
299 status = vaCreateConfig (dpy, profile, entrypoint, &attrib, 1, &config);
300 if (status != VA_STATUS_SUCCESS) {
301 GST_ERROR_OBJECT (display, "vaCreateConfig: %s", vaErrorStr (status));
305 caps = gst_va_create_raw_caps_from_config (display, config);
307 status = vaDestroyConfig (dpy, config);
308 if (status != VA_STATUS_SUCCESS) {
309 GST_ERROR_OBJECT (display, "vaDestroyConfig: %s", vaErrorStr (status));
316 /* the purpose of this function is to find broken configurations in
317 * JPEG decoders: if the driver doesn't expose a pixel format for a
318 * config with a specific sampling, that sampling is not valid */
319 static inline gboolean
320 _config_has_pixel_formats (GstVaDisplay * display, VAProfile profile,
321 VAEntrypoint entrypoint, guint32 rt_format)
323 guint i, fourcc, count;
324 gboolean found = FALSE;
325 VAConfigAttrib attrs = {
326 .type = VAConfigAttribRTFormat,
330 VADisplay dpy = gst_va_display_get_va_dpy (display);
331 VASurfaceAttrib *attr_list;
334 status = vaCreateConfig (dpy, profile, entrypoint, &attrs, 1, &config);
335 if (status != VA_STATUS_SUCCESS) {
336 GST_ERROR_OBJECT (display, "Failed to create JPEG config");
339 attr_list = gst_va_get_surface_attribs (display, config, &count);
343 /* XXX: JPEG decoders handle RGB16 and RGB32 chromas, but they use
344 * RGBP pixel format, which its chroma is RGBP (not 16 nor 32). So
345 * if the requested chroma is 16 or 32 it's locally overloaded as
347 if (rt_format == VA_RT_FORMAT_RGB16 || rt_format == VA_RT_FORMAT_RGB32)
348 rt_format = VA_RT_FORMAT_RGBP;
350 for (i = 0; i < count; i++) {
351 if (attr_list[i].type == VASurfaceAttribPixelFormat) {
352 fourcc = attr_list[i].value.value.i;
353 /* ignore pixel formats without requested chroma */
354 found = (gst_va_chroma_from_va_fourcc (fourcc) == rt_format);
362 status = vaDestroyConfig (dpy, config);
363 if (status != VA_STATUS_SUCCESS)
364 GST_WARNING_OBJECT (display, "Failed to destroy JPEG config");
370 _add_jpeg_fields (GstVaDisplay * display, GstCaps * caps, VAProfile profile,
371 VAEntrypoint entrypoint, guint32 rt_formats)
374 GValue colorspace = G_VALUE_INIT, sampling = G_VALUE_INIT;
375 gboolean rgb, gray, yuv;
377 rgb = gray = yuv = FALSE;
379 gst_value_list_init (&colorspace, 3);
380 gst_value_list_init (&sampling, 3);
382 for (i = 0; rt_formats && i < G_N_ELEMENTS (va_rt_format_list); i++) {
383 if (rt_formats & va_rt_format_list[i]) {
384 if (!_config_has_pixel_formats (display, profile, entrypoint,
385 va_rt_format_list[i]))
388 #define APPEND_YUV G_STMT_START \
389 if (!yuv) { _value_list_append_string (&colorspace, "sYUV"); yuv = TRUE; } \
392 switch (va_rt_format_list[i]) {
393 case VA_RT_FORMAT_YUV420:
395 _value_list_append_string (&sampling, "YCbCr-4:2:0");
397 case VA_RT_FORMAT_YUV422:
399 _value_list_append_string (&sampling, "YCbCr-4:2:2");
401 case VA_RT_FORMAT_YUV444:
403 _value_list_append_string (&sampling, "YCbCr-4:4:4");
405 case VA_RT_FORMAT_YUV411:
407 _value_list_append_string (&sampling, "YCbCr-4:1:1");
409 case VA_RT_FORMAT_YUV400:
411 _value_list_append_string (&colorspace, "GRAY");
412 _value_list_append_string (&sampling, "GRAYSCALE");
416 case VA_RT_FORMAT_RGBP:
417 case VA_RT_FORMAT_RGB16:
418 case VA_RT_FORMAT_RGB32:
420 _value_list_append_string (&colorspace, "sRGB");
421 _value_list_append_string (&sampling, "RGB");
422 _value_list_append_string (&sampling, "BGR");
433 size = gst_value_list_get_size (&colorspace);
435 gst_caps_set_value (caps, "colorspace",
436 gst_value_list_get_value (&colorspace, 0));
437 } else if (size > 1) {
438 gst_caps_set_value (caps, "colorspace", &colorspace);
441 size = gst_value_list_get_size (&sampling);
443 gst_caps_set_value (caps, "sampling",
444 gst_value_list_get_value (&sampling, 0));
445 } else if (size > 1) {
446 gst_caps_set_value (caps, "sampling", &sampling);
449 g_value_unset (&colorspace);
450 g_value_unset (&sampling);
454 gst_va_create_coded_caps (GstVaDisplay * display, VAProfile profile,
455 VAEntrypoint entrypoint, guint32 * rt_formats_ptr)
459 VAConfigAttrib attribs[] = {
460 { .type = VAConfigAttribMaxPictureWidth, },
461 { .type = VAConfigAttribMaxPictureHeight, },
462 { .type = VAConfigAttribRTFormat, },
467 guint32 value, rt_formats = 0;
468 gint i, max_width = -1, max_height = -1;
470 dpy = gst_va_display_get_va_dpy (display);
472 status = vaGetConfigAttributes (dpy, profile, entrypoint, attribs,
473 G_N_ELEMENTS (attribs));
474 if (status != VA_STATUS_SUCCESS) {
475 GST_ERROR_OBJECT (display, "vaGetConfigAttributes: %s",
476 vaErrorStr (status));
480 for (i = 0; i < G_N_ELEMENTS (attribs); i++) {
481 value = attribs[i].value;
482 if (value == VA_ATTRIB_NOT_SUPPORTED)
484 switch (attribs[i].type) {
485 case VAConfigAttribMaxPictureHeight:
486 if (value <= G_MAXINT)
489 case VAConfigAttribMaxPictureWidth:
490 if (value <= G_MAXINT)
493 case VAConfigAttribRTFormat:
502 *rt_formats_ptr = rt_formats;
504 caps = gst_va_profile_caps (profile);
508 if (rt_formats > 0 && gst_va_profile_codec (profile) == JPEG)
509 _add_jpeg_fields (display, caps, profile, entrypoint, rt_formats);
511 if (max_width == -1 || max_height == -1)
514 gst_caps_set_simple (caps, "width", GST_TYPE_INT_RANGE, 1, max_width,
515 "height", GST_TYPE_INT_RANGE, 1, max_height, NULL);
521 _regroup_raw_caps (GstCaps * caps)
523 GstCaps *sys_caps, *va_caps, *dma_caps, *tmp;
526 if (gst_caps_is_any (caps) || gst_caps_is_empty (caps))
529 size = gst_caps_get_size (caps);
533 /* We need to simplify caps by features. */
534 sys_caps = gst_caps_new_empty ();
535 va_caps = gst_caps_new_empty ();
536 dma_caps = gst_caps_new_empty ();
537 for (i = 0; i < size; i++) {
540 tmp = gst_caps_copy_nth (caps, i);
541 ft = gst_caps_get_features (tmp, 0);
542 if (gst_caps_features_contains (ft, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
543 dma_caps = gst_caps_merge (dma_caps, tmp);
544 } else if (gst_caps_features_contains (ft, GST_CAPS_FEATURE_MEMORY_VA)) {
545 va_caps = gst_caps_merge (va_caps, tmp);
547 sys_caps = gst_caps_merge (sys_caps, tmp);
551 sys_caps = gst_caps_simplify (sys_caps);
552 va_caps = gst_caps_simplify (va_caps);
553 dma_caps = gst_caps_simplify (dma_caps);
555 va_caps = gst_caps_merge (va_caps, dma_caps);
556 va_caps = gst_caps_merge (va_caps, sys_caps);
558 gst_caps_unref (caps);
564 gst_va_caps_from_profiles (GstVaDisplay * display, GArray * profiles,
565 VAEntrypoint entrypoint, GstCaps ** codedcaps_ptr, GstCaps ** rawcaps_ptr)
567 GstCaps *codedcaps, *rawcaps;
572 gint min_width = 1, max_width = G_MAXINT;
573 gint min_height = 1, max_height = G_MAXINT;
575 g_return_val_if_fail (GST_IS_VA_DISPLAY (display), FALSE);
576 g_return_val_if_fail (profiles, FALSE);
578 codedcaps = gst_caps_new_empty ();
579 rawcaps = gst_caps_new_empty ();
581 for (i = 0; i < profiles->len; i++) {
582 GstCaps *profile_codedcaps;
584 profile = g_array_index (profiles, VAProfile, i);
585 profile_codedcaps = gst_va_create_coded_caps (display, profile, entrypoint,
587 if (!profile_codedcaps)
590 for (j = 0; rt_formats && j < G_N_ELEMENTS (va_rt_format_list); j++) {
591 if (rt_formats & va_rt_format_list[j]) {
592 GstCaps *profile_rawcaps = gst_va_create_raw_caps (display, profile,
593 entrypoint, va_rt_format_list[j]);
595 if (!profile_rawcaps)
598 /* fetch width and height ranges */
600 guint num_structures = gst_caps_get_size (profile_rawcaps);
602 for (k = 0; k < num_structures; k++) {
603 GstStructure *st = gst_caps_get_structure (profile_rawcaps, k);
606 if (gst_structure_has_field (st, "width")
607 && gst_structure_has_field (st, "height")) {
608 const GValue *w = gst_structure_get_value (st, "width");
609 const GValue *h = gst_structure_get_value (st, "height");
611 min_width = MAX (min_width, gst_value_get_int_range_min (w));
612 max_width = MIN (max_width, gst_value_get_int_range_max (w));
613 min_height = MAX (min_height, gst_value_get_int_range_min (h));
614 max_height = MIN (max_height, gst_value_get_int_range_max (h));
619 rawcaps = gst_caps_merge (rawcaps, profile_rawcaps);
623 /* check frame size range was specified otherwise use the one used
626 guint num_structures = gst_caps_get_size (profile_codedcaps);
628 for (k = 0; k < num_structures; k++) {
629 GstStructure *st = gst_caps_get_structure (profile_codedcaps, k);
632 if (!gst_structure_has_field (st, "width"))
633 gst_structure_set (st, "width", GST_TYPE_INT_RANGE, min_width,
635 if (!gst_structure_has_field (st, "height"))
636 gst_structure_set (st, "height", GST_TYPE_INT_RANGE, min_height,
641 codedcaps = gst_caps_merge (codedcaps, profile_codedcaps);
644 if (gst_caps_is_empty (rawcaps))
645 gst_caps_replace (&rawcaps, NULL);
646 if (gst_caps_is_empty (codedcaps))
647 gst_caps_replace (&codedcaps, NULL);
649 if ((ret = codedcaps && rawcaps)) {
650 rawcaps = _regroup_raw_caps (rawcaps);
651 codedcaps = gst_caps_simplify (codedcaps);
654 *rawcaps_ptr = gst_caps_ref (rawcaps);
656 *codedcaps_ptr = gst_caps_ref (codedcaps);
660 gst_caps_unref (codedcaps);
662 gst_caps_unref (rawcaps);
667 static inline gboolean
668 _caps_is (GstCaps * caps, const gchar * feature)
670 GstCapsFeatures *features;
672 if (!gst_caps_is_fixed (caps))
675 features = gst_caps_get_features (caps, 0);
676 return gst_caps_features_contains (features, feature);
680 gst_caps_is_dmabuf (GstCaps * caps)
682 return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_DMABUF);
686 gst_caps_is_vamemory (GstCaps * caps)
688 return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_VA);
692 gst_caps_is_raw (GstCaps * caps)
694 return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);