va: Fix struct empty initialization syntax
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / va / gstvacaps.c
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/va/gstvavideoformat.h>
28 #include <va/va_drmcommon.h>
29
30 #include "gstvadisplay_priv.h"
31 #include "gstvaprofile.h"
32
33 GST_DEBUG_CATEGORY_EXTERN (gstva_debug);
34 #define GST_CAT_DEFAULT gstva_debug
35
36 static const guint va_rt_format_list[] = {
37 #define R(name) G_PASTE (VA_RT_FORMAT_, name)
38   R (YUV420),
39   R (YUV422),
40   R (YUV444),
41   R (YUV411),
42   R (YUV400),
43   R (YUV420_10),
44   R (YUV422_10),
45   R (YUV444_10),
46   R (YUV420_12),
47   R (YUV422_12),
48   R (YUV444_12),
49   R (YUV420_10BPP),
50   R (RGB16),
51   R (RGB32),
52   R (RGBP),
53   R (RGB32_10),
54   R (RGB32_10BPP),
55   R (PROTECTED),
56 #undef R
57 };
58
59 VASurfaceAttrib *
60 gst_va_get_surface_attribs (GstVaDisplay * display, VAConfigID config,
61     guint * attrib_count)
62 {
63   VADisplay dpy;
64   VASurfaceAttrib *attribs;
65   VAStatus status;
66
67   dpy = gst_va_display_get_va_dpy (display);
68
69   status = vaQuerySurfaceAttributes (dpy, config, NULL, attrib_count);
70   if (status != VA_STATUS_SUCCESS) {
71     GST_ERROR_OBJECT (display, "vaQuerySurfaceAttributes: %s",
72         vaErrorStr (status));
73     return NULL;
74   }
75
76   attribs = g_new (VASurfaceAttrib, *attrib_count);
77
78   status = vaQuerySurfaceAttributes (dpy, config, attribs, attrib_count);
79   if (status != VA_STATUS_SUCCESS) {
80     GST_ERROR_OBJECT (display, "vaQuerySurfaceAttributes: %s",
81         vaErrorStr (status));
82     goto bail;
83   }
84
85   return attribs;
86
87 bail:
88   g_free (attribs);
89   return NULL;
90 }
91
92 static inline void
93 _value_list_append_string (GValue * list, const gchar * str)
94 {
95   GValue item = G_VALUE_INIT;
96
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);
101 }
102
103 gboolean
104 gst_caps_set_format_array (GstCaps * caps, GArray * formats)
105 {
106   GstVideoFormat fmt;
107   GValue v_formats = G_VALUE_INIT;
108   const gchar *format;
109   guint i;
110
111   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
112   g_return_val_if_fail (formats, FALSE);
113
114   if (formats->len == 1) {
115     fmt = g_array_index (formats, GstVideoFormat, 0);
116     if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
117       return FALSE;
118     format = gst_video_format_to_string (fmt);
119     if (!format)
120       return FALSE;
121
122     g_value_init (&v_formats, G_TYPE_STRING);
123     g_value_set_string (&v_formats, format);
124   } else if (formats->len > 1) {
125
126     gst_value_list_init (&v_formats, formats->len);
127
128     for (i = 0; i < formats->len; i++) {
129       fmt = g_array_index (formats, GstVideoFormat, i);
130       if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
131         continue;
132       format = gst_video_format_to_string (fmt);
133       if (!format)
134         continue;
135
136       _value_list_append_string (&v_formats, format);
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 /* Fix raw frames ill reported by drivers.
149  *
150  * Mesa Gallium reports P010 and P016 for H264 encoder:
151  * https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19443
152  *
153  * Intel i965: reports I420 and YV12
154  * XXX: add issue or pr
155  */
156 static gboolean
157 fix_raw_formats (GstVaDisplay * display, VAConfigID config, GArray * formats)
158 {
159   VADisplay dpy;
160   VAStatus status;
161   VAProfile profile;
162   VAEntrypoint entrypoint;
163   VAConfigAttrib *attribs;
164   GstVideoFormat format;
165   int num;
166
167   if (!(GST_VA_DISPLAY_IS_IMPLEMENTATION (display, INTEL_I965) ||
168           GST_VA_DISPLAY_IS_IMPLEMENTATION (display, MESA_GALLIUM)))
169     return TRUE;
170
171   dpy = gst_va_display_get_va_dpy (display);
172   attribs = g_new (VAConfigAttrib, vaMaxNumConfigAttributes (dpy));
173   status = vaQueryConfigAttributes (dpy, config, &profile, &entrypoint, attribs,
174       &num);
175   g_free (attribs);
176
177   if (status != VA_STATUS_SUCCESS) {
178     GST_ERROR_OBJECT (display, "vaQueryConfigAttributes: %s",
179         vaErrorStr (status));
180     return FALSE;
181   }
182
183   if (gst_va_profile_codec (profile) != H264
184       || entrypoint != VAEntrypointEncSlice)
185     return TRUE;
186
187   formats = g_array_set_size (formats, 0);
188   format = GST_VIDEO_FORMAT_NV12;
189   g_array_append_val (formats, format);
190   return TRUE;
191 }
192
193 GstCaps *
194 gst_va_create_raw_caps_from_config (GstVaDisplay * display, VAConfigID config)
195 {
196   GArray *formats;
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;
204
205   attribs = gst_va_get_surface_attribs (display, config, &attrib_count);
206   if (!attribs)
207     return NULL;
208   formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
209
210   for (i = 0; i < attrib_count; i++) {
211     if (attribs[i].value.type != VAGenericValueTypeInteger)
212       continue;
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);
218         break;
219       case VASurfaceAttribMinWidth:
220         min_width = MAX (min_width, attribs[i].value.value.i);
221         break;
222       case VASurfaceAttribMaxWidth:
223         max_width = attribs[i].value.value.i;
224         break;
225       case VASurfaceAttribMinHeight:
226         min_height = MAX (min_height, attribs[i].value.value.i);
227         break;
228       case VASurfaceAttribMaxHeight:
229         max_height = attribs[i].value.value.i;
230         break;
231       case VASurfaceAttribMemoryType:
232         mem_type = attribs[i].value.value.i;
233         break;
234       default:
235         break;
236     }
237   }
238
239   /* if driver doesn't report surface formats for current
240    * chroma. Gallium AMD bug for 4:2:2 */
241   if (formats->len == 0)
242     goto bail;
243
244   if (!fix_raw_formats (display, config, formats))
245     goto bail;
246
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,
249       max_height, NULL);
250
251   if (!gst_caps_set_format_array (base_caps, formats)) {
252     gst_caps_unref (base_caps);
253     goto bail;
254   }
255
256   caps = gst_caps_new_empty ();
257
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);
263   }
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);
270   }
271
272   /* raw caps */
273   caps = gst_caps_merge (caps, gst_caps_copy (base_caps));
274
275   gst_caps_unref (base_caps);
276
277 bail:
278   g_array_unref (formats);
279   g_free (attribs);
280
281   return caps;
282 }
283
284 static GstCaps *
285 gst_va_create_raw_caps (GstVaDisplay * display, VAProfile profile,
286     VAEntrypoint entrypoint, guint rt_format)
287 {
288   GstCaps *caps;
289   VAConfigAttrib attrib = {
290     .type = VAConfigAttribRTFormat,
291     .value = rt_format,
292   };
293   VAConfigID config;
294   VADisplay dpy;
295   VAStatus status;
296
297   dpy = gst_va_display_get_va_dpy (display);
298
299   status = vaCreateConfig (dpy, profile, entrypoint, &attrib, 1, &config);
300   if (status != VA_STATUS_SUCCESS) {
301     GST_ERROR_OBJECT (display, "vaCreateConfig: %s", vaErrorStr (status));
302     return NULL;
303   }
304
305   caps = gst_va_create_raw_caps_from_config (display, config);
306
307   status = vaDestroyConfig (dpy, config);
308   if (status != VA_STATUS_SUCCESS) {
309     GST_ERROR_OBJECT (display, "vaDestroyConfig: %s", vaErrorStr (status));
310     return NULL;
311   }
312
313   return caps;
314 }
315
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)
322 {
323   guint i, fourcc, count;
324   gboolean found = FALSE;
325   VAConfigAttrib attrs = {
326     .type = VAConfigAttribRTFormat,
327     .value = rt_format,
328   };
329   VAConfigID config;
330   VADisplay dpy = gst_va_display_get_va_dpy (display);
331   VASurfaceAttrib *attr_list;
332   VAStatus status;
333
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");
337     return FALSE;
338   }
339   attr_list = gst_va_get_surface_attribs (display, config, &count);
340   if (!attr_list)
341     goto bail;
342
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
346    * RGBP. */
347   if (rt_format == VA_RT_FORMAT_RGB16 || rt_format == VA_RT_FORMAT_RGB32)
348     rt_format = VA_RT_FORMAT_RGBP;
349
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);
355       if (found)
356         break;
357     }
358   }
359   g_free (attr_list);
360
361 bail:
362   status = vaDestroyConfig (dpy, config);
363   if (status != VA_STATUS_SUCCESS)
364     GST_WARNING_OBJECT (display, "Failed to destroy JPEG config");
365
366   return found;
367 }
368
369 static void
370 _add_jpeg_fields (GstVaDisplay * display, GstCaps * caps, VAProfile profile,
371     VAEntrypoint entrypoint, guint32 rt_formats)
372 {
373   guint i, size;
374   GValue colorspace = G_VALUE_INIT, sampling = G_VALUE_INIT;
375   gboolean rgb, gray, yuv;
376
377   rgb = gray = yuv = FALSE;
378
379   gst_value_list_init (&colorspace, 3);
380   gst_value_list_init (&sampling, 3);
381
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]))
386         continue;
387
388 #define APPEND_YUV G_STMT_START \
389         if (!yuv) { _value_list_append_string (&colorspace, "sYUV"); yuv = TRUE; } \
390       G_STMT_END
391
392       switch (va_rt_format_list[i]) {
393         case VA_RT_FORMAT_YUV420:
394           APPEND_YUV;
395           _value_list_append_string (&sampling, "YCbCr-4:2:0");
396           break;
397         case VA_RT_FORMAT_YUV422:
398           APPEND_YUV;
399           _value_list_append_string (&sampling, "YCbCr-4:2:2");
400           break;
401         case VA_RT_FORMAT_YUV444:
402           APPEND_YUV;
403           _value_list_append_string (&sampling, "YCbCr-4:4:4");
404           break;
405         case VA_RT_FORMAT_YUV411:
406           APPEND_YUV;
407           _value_list_append_string (&sampling, "YCbCr-4:1:1");
408           break;
409         case VA_RT_FORMAT_YUV400:
410           if (!gray) {
411             _value_list_append_string (&colorspace, "GRAY");
412             _value_list_append_string (&sampling, "GRAYSCALE");
413             gray = TRUE;
414           }
415           break;
416         case VA_RT_FORMAT_RGBP:
417         case VA_RT_FORMAT_RGB16:
418         case VA_RT_FORMAT_RGB32:
419           if (!rgb) {
420             _value_list_append_string (&colorspace, "sRGB");
421             _value_list_append_string (&sampling, "RGB");
422             _value_list_append_string (&sampling, "BGR");
423             rgb = TRUE;
424           }
425           break;
426         default:
427           break;
428       }
429 #undef APPEND_YUV
430     }
431   }
432
433   size = gst_value_list_get_size (&colorspace);
434   if (size == 1) {
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);
439   }
440
441   size = gst_value_list_get_size (&sampling);
442   if (size == 1) {
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);
447   }
448
449   g_value_unset (&colorspace);
450   g_value_unset (&sampling);
451 }
452
453 GstCaps *
454 gst_va_create_coded_caps (GstVaDisplay * display, VAProfile profile,
455     VAEntrypoint entrypoint, guint32 * rt_formats_ptr)
456 {
457   GstCaps *caps;
458   /* *INDENT-OFF* */
459   VAConfigAttrib attribs[] = {
460     { .type = VAConfigAttribMaxPictureWidth, },
461     { .type = VAConfigAttribMaxPictureHeight, },
462     { .type = VAConfigAttribRTFormat, },
463   };
464   /* *INDENT-ON* */
465   VADisplay dpy;
466   VAStatus status;
467   guint32 value, rt_formats = 0;
468   gint i, max_width = -1, max_height = -1;
469
470   dpy = gst_va_display_get_va_dpy (display);
471
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));
477     return NULL;
478   }
479
480   for (i = 0; i < G_N_ELEMENTS (attribs); i++) {
481     value = attribs[i].value;
482     if (value == VA_ATTRIB_NOT_SUPPORTED)
483       continue;
484     switch (attribs[i].type) {
485       case VAConfigAttribMaxPictureHeight:
486         if (value <= G_MAXINT)
487           max_height = value;
488         break;
489       case VAConfigAttribMaxPictureWidth:
490         if (value <= G_MAXINT)
491           max_width = value;
492         break;
493       case VAConfigAttribRTFormat:
494         rt_formats = value;
495         break;
496       default:
497         break;
498     }
499   }
500
501   if (rt_formats_ptr)
502     *rt_formats_ptr = rt_formats;
503
504   caps = gst_va_profile_caps (profile);
505   if (!caps)
506     return NULL;
507
508   if (rt_formats > 0 && gst_va_profile_codec (profile) == JPEG)
509     _add_jpeg_fields (display, caps, profile, entrypoint, rt_formats);
510
511   if (max_width == -1 || max_height == -1)
512     return caps;
513
514   gst_caps_set_simple (caps, "width", GST_TYPE_INT_RANGE, 1, max_width,
515       "height", GST_TYPE_INT_RANGE, 1, max_height, NULL);
516
517   return caps;
518 }
519
520 static GstCaps *
521 _regroup_raw_caps (GstCaps * caps)
522 {
523   GstCaps *sys_caps, *va_caps, *dma_caps, *tmp;
524   guint size, i;
525
526   if (gst_caps_is_any (caps) || gst_caps_is_empty (caps))
527     return caps;
528
529   size = gst_caps_get_size (caps);
530   if (size <= 1)
531     return caps;
532
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++) {
538     GstCapsFeatures *ft;
539
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);
546     } else {
547       sys_caps = gst_caps_merge (sys_caps, tmp);
548     }
549   }
550
551   sys_caps = gst_caps_simplify (sys_caps);
552   va_caps = gst_caps_simplify (va_caps);
553   dma_caps = gst_caps_simplify (dma_caps);
554
555   va_caps = gst_caps_merge (va_caps, dma_caps);
556   va_caps = gst_caps_merge (va_caps, sys_caps);
557
558   gst_caps_unref (caps);
559
560   return va_caps;
561 }
562
563 gboolean
564 gst_va_caps_from_profiles (GstVaDisplay * display, GArray * profiles,
565     VAEntrypoint entrypoint, GstCaps ** codedcaps_ptr, GstCaps ** rawcaps_ptr)
566 {
567   GstCaps *codedcaps, *rawcaps;
568   VAProfile profile;
569   gboolean ret;
570   gint i, j, k;
571   guint32 rt_formats;
572   gint min_width = 1, max_width = G_MAXINT;
573   gint min_height = 1, max_height = G_MAXINT;
574
575   g_return_val_if_fail (GST_IS_VA_DISPLAY (display), FALSE);
576   g_return_val_if_fail (profiles, FALSE);
577
578   codedcaps = gst_caps_new_empty ();
579   rawcaps = gst_caps_new_empty ();
580
581   for (i = 0; i < profiles->len; i++) {
582     GstCaps *profile_codedcaps;
583
584     profile = g_array_index (profiles, VAProfile, i);
585     profile_codedcaps = gst_va_create_coded_caps (display, profile, entrypoint,
586         &rt_formats);
587     if (!profile_codedcaps)
588       continue;
589
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]);
594
595         if (!profile_rawcaps)
596           continue;
597
598         /* fetch width and height ranges */
599         {
600           guint num_structures = gst_caps_get_size (profile_rawcaps);
601
602           for (k = 0; k < num_structures; k++) {
603             GstStructure *st = gst_caps_get_structure (profile_rawcaps, k);
604             if (!st)
605               continue;
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");
610
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));
615             }
616           }
617         }
618
619         rawcaps = gst_caps_merge (rawcaps, profile_rawcaps);
620       }
621     }
622
623     /* check frame size range was specified otherwise use the one used
624      * by the rawcaps */
625     {
626       guint num_structures = gst_caps_get_size (profile_codedcaps);
627
628       for (k = 0; k < num_structures; k++) {
629         GstStructure *st = gst_caps_get_structure (profile_codedcaps, k);
630         if (!st)
631           continue;
632         if (!gst_structure_has_field (st, "width"))
633           gst_structure_set (st, "width", GST_TYPE_INT_RANGE, min_width,
634               max_width, NULL);
635         if (!gst_structure_has_field (st, "height"))
636           gst_structure_set (st, "height", GST_TYPE_INT_RANGE, min_height,
637               max_height, NULL);
638       }
639     }
640
641     codedcaps = gst_caps_merge (codedcaps, profile_codedcaps);
642   }
643
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);
648
649   if ((ret = codedcaps && rawcaps)) {
650     rawcaps = _regroup_raw_caps (rawcaps);
651     codedcaps = gst_caps_simplify (codedcaps);
652
653     if (rawcaps_ptr)
654       *rawcaps_ptr = gst_caps_ref (rawcaps);
655     if (codedcaps_ptr)
656       *codedcaps_ptr = gst_caps_ref (codedcaps);
657   }
658
659   if (codedcaps)
660     gst_caps_unref (codedcaps);
661   if (rawcaps)
662     gst_caps_unref (rawcaps);
663
664   return ret;
665 }
666
667 static inline gboolean
668 _caps_is (GstCaps * caps, const gchar * feature)
669 {
670   GstCapsFeatures *features;
671
672   if (!gst_caps_is_fixed (caps))
673     return FALSE;
674
675   features = gst_caps_get_features (caps, 0);
676   return gst_caps_features_contains (features, feature);
677 }
678
679 gboolean
680 gst_caps_is_dmabuf (GstCaps * caps)
681 {
682   return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_DMABUF);
683 }
684
685 gboolean
686 gst_caps_is_vamemory (GstCaps * caps)
687 {
688   return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_VA);
689 }
690
691 gboolean
692 gst_caps_is_raw (GstCaps * caps)
693 {
694   return _caps_is (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
695 }