1 /* GStreamer
2 * Copyright (C) 2020 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
4 *
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.
9 *
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.
14 *
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.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstvacaps.h"
26
27 #include <gst/allocators/allocators.h>
28
29 #include <va/va_drmcommon.h>
30
31 #include "gstvadisplay_priv.h"
32 #include "gstvaprofile.h"
33 #include "gstvavideoformat.h"
34
35 GST_DEBUG_CATEGORY_EXTERN (gstva_debug);
36 #define GST_CAT_DEFAULT gstva_debug
37
38 static const guint va_rt_format_list[] = {
39 #define R(name) G_PASTE (VA_RT_FORMAT_, name)
40 R (YUV420),
41 R (YUV422),
42 R (YUV444),
43 R (YUV411),
44 R (YUV400),
45 R (YUV420_10),
46 R (YUV422_10),
47 R (YUV444_10),
48 R (YUV420_12),
49 R (YUV422_12),
50 R (YUV444_12),
51 R (YUV420_10BPP),
52 R (RGB16),
53 R (RGB32),
54 R (RGBP),
55 R (RGB32_10),
56 R (RGB32_10BPP),
57 R (PROTECTED),
58 #undef R
59 };
60
61 VASurfaceAttrib *
gst_va_get_surface_attribs(GstVaDisplay * display,VAConfigID config,guint * attrib_count)62 gst_va_get_surface_attribs (GstVaDisplay * display, VAConfigID config,
63 guint * attrib_count)
64 {
65 VADisplay dpy;
66 VASurfaceAttrib *attribs;
67 VAStatus status;
68
69 dpy = gst_va_display_get_va_dpy (display);
70
71 gst_va_display_lock (display);
72 status = vaQuerySurfaceAttributes (dpy, config, NULL, attrib_count);
73 gst_va_display_unlock (display);
74 if (status != VA_STATUS_SUCCESS) {
75 GST_ERROR_OBJECT (display, "vaQuerySurfaceAttributes: %s",
76 vaErrorStr (status));
77 return NULL;
78 }
79
80 attribs = g_new (VASurfaceAttrib, *attrib_count);
81
82 gst_va_display_lock (display);
83 status = vaQuerySurfaceAttributes (dpy, config, attribs, attrib_count);
84 gst_va_display_unlock (display);
85 if (status != VA_STATUS_SUCCESS) {
86 GST_ERROR_OBJECT (display, "vaQuerySurfaceAttributes: %s",
87 vaErrorStr (status));
88 goto bail;
89 }
90
91 return attribs;
92
93 bail:
94 g_free (attribs);
95 return NULL;
96 }
97
98 gboolean
gst_caps_set_format_array(GstCaps * caps,GArray * formats)99 gst_caps_set_format_array (GstCaps * caps, GArray * formats)
100 {
101 GstVideoFormat fmt;
102 GValue v_formats = G_VALUE_INIT;
103 const gchar *format;
104 guint i;
105
106 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
107 g_return_val_if_fail (formats, FALSE);
108
109 if (formats->len == 1) {
110 fmt = g_array_index (formats, GstVideoFormat, 0);
111 if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
112 return FALSE;
113 format = gst_video_format_to_string (fmt);
114 if (!format)
115 return FALSE;
116
117 g_value_init (&v_formats, G_TYPE_STRING);
118 g_value_set_string (&v_formats, format);
119 } else if (formats->len > 1) {
120
121 gst_value_list_init (&v_formats, formats->len);
122
123 for (i = 0; i < formats->len; i++) {
124 GValue item = G_VALUE_INIT;
125
126 fmt = g_array_index (formats, GstVideoFormat, i);
127 if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
128 continue;
129 format = gst_video_format_to_string (fmt);
130 if (!format)
131 continue;
132
133 g_value_init (&item, G_TYPE_STRING);
134 g_value_set_string (&item, format);
135 gst_value_list_append_value (&v_formats, &item);
136 g_value_unset (&item);
137 }
138 } else {
139 return FALSE;
140 }
141
142 gst_caps_set_value (caps, "format", &v_formats);
143 g_value_unset (&v_formats);
144
145 return TRUE;
146 }
147
148 GstCaps *
gst_va_create_raw_caps_from_config(GstVaDisplay * display,VAConfigID config)149 gst_va_create_raw_caps_from_config (GstVaDisplay * display, VAConfigID config)
150 {
151 GArray *formats;
152 GstCaps *caps = NULL, *base_caps, *feature_caps;
153 GstCapsFeatures *features;
154 GstVideoFormat format;
155 VASurfaceAttrib *attribs;
156 guint i, attrib_count, mem_type = 0;
157 gint min_width = 1, max_width = G_MAXINT;
158 gint min_height = 1, max_height = G_MAXINT;
159
160 attribs = gst_va_get_surface_attribs (display, config, &attrib_count);
161 if (!attribs)
162 return NULL;
163 formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
164
165 for (i = 0; i < attrib_count; i++) {
166 if (attribs[i].value.type != VAGenericValueTypeInteger)
167 continue;
168 switch (attribs[i].type) {
169 case VASurfaceAttribPixelFormat:
170 format = gst_va_video_format_from_va_fourcc (attribs[i].value.value.i);
171 if (format != GST_VIDEO_FORMAT_UNKNOWN)
172 g_array_append_val (formats, format);
173 break;
174 case VASurfaceAttribMinWidth:
175 min_width = MAX (min_width, attribs[i].value.value.i);
176 break;
177 case VASurfaceAttribMaxWidth:
178 max_width = attribs[i].value.value.i;
179 break;
180 case VASurfaceAttribMinHeight:
181 min_height = MAX (min_height, attribs[i].value.value.i);
182 break;
183 case VASurfaceAttribMaxHeight:
184 max_height = attribs[i].value.value.i;
185 break;
186 case VASurfaceAttribMemoryType:
187 mem_type = attribs[i].value.value.i;
188 break;
189 default:
190 break;
191 }
192 }
193
194 /* if driver doesn't report surface formats for current
195 * chroma. Gallium AMD bug for 4:2:2 */
196 if (formats->len == 0)
197 goto bail;
198
199 base_caps = gst_caps_new_simple ("video/x-raw", "width", GST_TYPE_INT_RANGE,
200 min_width, max_width, "height", GST_TYPE_INT_RANGE, min_height,
201 max_height, NULL);
202
203 if (!gst_caps_set_format_array (base_caps, formats)) {
204 gst_caps_unref (base_caps);
205 goto bail;
206 }
207
208 caps = gst_caps_new_empty ();
209
210 if (mem_type & VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
211 feature_caps = gst_caps_copy (base_caps);
212 features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA);
213 gst_caps_set_features_simple (feature_caps, features);
214 caps = gst_caps_merge (caps, feature_caps);
215 }
216 if (mem_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
217 || mem_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) {
218 feature_caps = gst_caps_copy (base_caps);
219 features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF);
220 gst_caps_set_features_simple (feature_caps, features);
221 caps = gst_caps_merge (caps, feature_caps);
222 }
223
224 /* raw caps */
225 caps = gst_caps_merge (caps, gst_caps_copy (base_caps));
226
227 gst_caps_unref (base_caps);
228
229 bail:
230 g_array_unref (formats);
231 g_free (attribs);
232
233 return caps;
234 }
235
236 static GstCaps *
gst_va_create_raw_caps(GstVaDisplay * display,VAProfile profile,VAEntrypoint entrypoint,guint rt_format)237 gst_va_create_raw_caps (GstVaDisplay * display, VAProfile profile,
238 VAEntrypoint entrypoint, guint rt_format)
239 {
240 GstCaps *caps;
241 VAConfigAttrib attrib = {
242 .type = VAConfigAttribRTFormat,
243 .value = rt_format,
244 };
245 VAConfigID config;
246 VADisplay dpy;
247 VAStatus status;
248
249 dpy = gst_va_display_get_va_dpy (display);
250
251 gst_va_display_lock (display);
252 status = vaCreateConfig (dpy, profile, entrypoint, &attrib, 1, &config);
253 gst_va_display_unlock (display);
254 if (status != VA_STATUS_SUCCESS) {
255 GST_ERROR_OBJECT (display, "vaCreateConfig: %s", vaErrorStr (status));
256 return NULL;
257 }
258
259 caps = gst_va_create_raw_caps_from_config (display, config);
260
261 gst_va_display_lock (display);
262 status = vaDestroyConfig (dpy, config);
263 gst_va_display_unlock (display);
264 if (status != VA_STATUS_SUCCESS) {
265 GST_ERROR_OBJECT (display, "vaDestroyConfig: %s", vaErrorStr (status));
266 return NULL;
267 }
268
269 return caps;
270 }
271
272 static GstCaps *
gst_va_create_coded_caps(GstVaDisplay * display,VAProfile profile,VAEntrypoint entrypoint,guint32 * rt_formats_ptr)273 gst_va_create_coded_caps (GstVaDisplay * display, VAProfile profile,
274 VAEntrypoint entrypoint, guint32 * rt_formats_ptr)
275 {
276 GstCaps *caps;
277 VAConfigAttrib attribs[] = {
278 {.type = VAConfigAttribMaxPictureWidth,},
279 {.type = VAConfigAttribMaxPictureHeight,},
280 {.type = VAConfigAttribRTFormat,},
281 };
282 VADisplay dpy;
283 VAStatus status;
284 guint32 value, rt_formats = 0;
285 gint i, max_width = -1, max_height = -1;
286
287 dpy = gst_va_display_get_va_dpy (display);
288
289 gst_va_display_lock (display);
290 status = vaGetConfigAttributes (dpy, profile, entrypoint, attribs,
291 G_N_ELEMENTS (attribs));
292 gst_va_display_unlock (display);
293 if (status != VA_STATUS_SUCCESS) {
294 GST_ERROR_OBJECT (display, "vaGetConfigAttributes: %s",
295 vaErrorStr (status));
296 return NULL;
297 }
298
299 for (i = 0; i < G_N_ELEMENTS (attribs); i++) {
300 value = attribs[i].value;
301 if (value == VA_ATTRIB_NOT_SUPPORTED)
302 continue;
303 switch (attribs[i].type) {
304 case VAConfigAttribMaxPictureHeight:
305 if (value <= G_MAXINT)
306 max_height = value;
307 break;
308 case VAConfigAttribMaxPictureWidth:
309 if (value <= G_MAXINT)
310 max_width = value;
311 break;
312 case VAConfigAttribRTFormat:
313 rt_formats = value;
314 break;
315 default:
316 break;
317 }
318 }
319
320 if (rt_formats_ptr)
321 *rt_formats_ptr = rt_formats;
322
323 caps = gst_va_profile_caps (profile);
324 if (!caps)
325 return NULL;
326
327 if (max_width == -1 || max_height == -1)
328 return caps;
329
330 gst_caps_set_simple (caps, "width", GST_TYPE_INT_RANGE, 1, max_width,
331 "height", GST_TYPE_INT_RANGE, 1, max_height, NULL);
332
333 return caps;
334 }
335
336 static GstCaps *
_regroup_raw_caps(GstCaps * caps)337 _regroup_raw_caps (GstCaps * caps)
338 {
339 GstCaps *sys_caps, *va_caps, *dma_caps, *tmp;
340 guint size, i;
341
342 if (gst_caps_is_any (caps) || gst_caps_is_empty (caps))
343 return caps;
344
345 size = gst_caps_get_size (caps);
346 if (size <= 1)
347 return caps;
348
349 /* We need to simplify caps by features. */
350 sys_caps = gst_caps_new_empty ();
351 va_caps = gst_caps_new_empty ();
352 dma_caps = gst_caps_new_empty ();
353 for (i = 0; i < size; i++) {
354 GstCapsFeatures *ft;
355
356 tmp = gst_caps_copy_nth (caps, i);
357 ft = gst_caps_get_features (tmp, 0);
358 if (gst_caps_features_contains (ft, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
359 dma_caps = gst_caps_merge (dma_caps, tmp);
360 } else if (gst_caps_features_contains (ft, GST_CAPS_FEATURE_MEMORY_VA)) {
361 va_caps = gst_caps_merge (va_caps, tmp);
362 } else {
363 sys_caps = gst_caps_merge (sys_caps, tmp);
364 }
365 }
366
367 sys_caps = gst_caps_simplify (sys_caps);
368 va_caps = gst_caps_simplify (va_caps);
369 dma_caps = gst_caps_simplify (dma_caps);
370
371 sys_caps = gst_caps_merge (sys_caps, va_caps);
372 sys_caps = gst_caps_merge (sys_caps, dma_caps);
373
374 gst_caps_unref (caps);
375
376 return sys_caps;
377 }
378
379 gboolean
gst_va_caps_from_profiles(GstVaDisplay * display,GArray * profiles,VAEntrypoint entrypoint,GstCaps ** codedcaps_ptr,GstCaps ** rawcaps_ptr)380 gst_va_caps_from_profiles (GstVaDisplay * display, GArray * profiles,
381 VAEntrypoint entrypoint, GstCaps ** codedcaps_ptr, GstCaps ** rawcaps_ptr)
382 {
383 GstCaps *codedcaps, *rawcaps;
384 VAProfile profile;
385 gboolean ret;
386 gint i, j, k;
387 guint32 rt_formats;
388 gint min_width = 1, max_width = G_MAXINT;
389 gint min_height = 1, max_height = G_MAXINT;
390
391 g_return_val_if_fail (GST_IS_VA_DISPLAY (display), FALSE);
392 g_return_val_if_fail (profiles, FALSE);
393
394 codedcaps = gst_caps_new_empty ();
395 rawcaps = gst_caps_new_empty ();
396
397 for (i = 0; i < profiles->len; i++) {
398 GstCaps *profile_codedcaps;
399
400 profile = g_array_index (profiles, VAProfile, i);
401 profile_codedcaps = gst_va_create_coded_caps (display, profile, entrypoint,
402 &rt_formats);
403 if (!profile_codedcaps)
404 continue;
405
406 for (j = 0; rt_formats && j < G_N_ELEMENTS (va_rt_format_list); j++) {
407 if (rt_formats & va_rt_format_list[j]) {
408 GstCaps *profile_rawcaps = gst_va_create_raw_caps (display, profile,
409 entrypoint, va_rt_format_list[j]);
410
411 if (!profile_rawcaps)
412 continue;
413
414 /* fetch width and height ranges */
415 {
416 guint num_structures = gst_caps_get_size (profile_rawcaps);
417
418 for (k = 0; k < num_structures; k++) {
419 GstStructure *st = gst_caps_get_structure (profile_rawcaps, k);
420 if (!st)
421 continue;
422 if (gst_structure_has_field (st, "width")
423 && gst_structure_has_field (st, "height")) {
424 const GValue *w = gst_structure_get_value (st, "width");
425 const GValue *h = gst_structure_get_value (st, "height");
426
427 min_width = MAX (min_width, gst_value_get_int_range_min (w));
428 max_width = MIN (max_width, gst_value_get_int_range_max (w));
429 min_height = MAX (min_height, gst_value_get_int_range_min (h));
430 max_height = MIN (max_height, gst_value_get_int_range_max (h));
431 }
432 }
433 }
434
435 rawcaps = gst_caps_merge (rawcaps, profile_rawcaps);
436 }
437 }
438
439 /* check frame size range was specified otherwise use the one used
440 * by the rawcaps */
441 {
442 guint num_structures = gst_caps_get_size (profile_codedcaps);
443
444 for (k = 0; k < num_structures; k++) {
445 GstStructure *st = gst_caps_get_structure (profile_codedcaps, k);
446 if (!st)
447 continue;
448 if (!gst_structure_has_field (st, "width"))
449 gst_structure_set (st, "width", GST_TYPE_INT_RANGE, min_width,
450 max_width, NULL);
451 if (!gst_structure_has_field (st, "height"))
452 gst_structure_set (st, "height", GST_TYPE_INT_RANGE, min_height,
453 max_height, NULL);
454 }
455 }
456
457 codedcaps = gst_caps_merge (codedcaps, profile_codedcaps);
458 }
459
460 if (gst_caps_is_empty (rawcaps))
461 gst_caps_replace (&rawcaps, NULL);
462 if (gst_caps_is_empty (codedcaps))
463 gst_caps_replace (&codedcaps, NULL);
464
465 if ((ret = codedcaps && rawcaps)) {
466 rawcaps = _regroup_raw_caps (rawcaps);
467 codedcaps = gst_caps_simplify (codedcaps);
468
469 if (rawcaps_ptr)
470 *rawcaps_ptr = gst_caps_ref (rawcaps);
471 if (codedcaps_ptr)
472 *codedcaps_ptr = gst_caps_ref (codedcaps);
473 }
474
475 if (codedcaps)
476 gst_caps_unref (codedcaps);
477 if (rawcaps)
478 gst_caps_unref (rawcaps);
479
480 return ret;
481 }
482
483 static inline gboolean
_caps_is(GstCaps * caps,const gchar * feature)484 _caps_is (GstCaps * caps, const gchar * feature)
485 {
486 GstCapsFeatures *features;
487
488 if (!gst_caps_is_fixed (caps))
489 return FALSE;
490
491 features = gst_caps_get_features (caps, 0);
492 return gst_caps_features_contains (features, feature);
493 }
494
495 gboolean
gst_caps_is_dmabuf(GstCaps * caps)496 gst_caps_is_dmabuf (GstCaps * caps)
497 {
498 return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_DMABUF);
499 }
500
501 gboolean
gst_caps_is_vamemory(GstCaps * caps)502 gst_caps_is_vamemory (GstCaps * caps)
503 {
504 return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_VA);
505 }
506
507 gboolean
gst_caps_is_raw(GstCaps * caps)508 gst_caps_is_raw (GstCaps * caps)
509 {
510 return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
511 }
512