• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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