1 /* GStreamer
2 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:gstcaps
22 * @title: GstCaps
23 * @short_description: Structure describing sets of media formats
24 * @see_also: #GstStructure, #GstMiniObject
25 *
26 * Caps (capabilities) are lightweight refcounted objects describing media types.
27 * They are composed of an array of #GstStructure.
28 *
29 * Caps are exposed on #GstPadTemplate to describe all possible types a
30 * given pad can handle. They are also stored in the #GstRegistry along with
31 * a description of the #GstElement.
32 *
33 * Caps are exposed on the element pads using the gst_pad_query_caps() pad
34 * function. This function describes the possible types that the pad can
35 * handle or produce at runtime.
36 *
37 * A #GstCaps can be constructed with the following code fragment:
38 * |[<!-- language="C" -->
39 * GstCaps *caps = gst_caps_new_simple ("video/x-raw",
40 * "format", G_TYPE_STRING, "I420",
41 * "framerate", GST_TYPE_FRACTION, 25, 1,
42 * "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
43 * "width", G_TYPE_INT, 320,
44 * "height", G_TYPE_INT, 240,
45 * NULL);
46 * ]|
47 *
48 * A #GstCaps is fixed when it has no properties with ranges or lists. Use
49 * gst_caps_is_fixed() to test for fixed caps. Fixed caps can be used in a
50 * caps event to notify downstream elements of the current media type.
51 *
52 * Various methods exist to work with the media types such as subtracting
53 * or intersecting.
54 *
55 * Be aware that the current #GstCaps / #GstStructure serialization into string
56 * has limited support for nested #GstCaps / #GstStructure fields. It can only
57 * support one level of nesting. Using more levels will lead to unexpected
58 * behavior when using serialization features, such as gst_caps_to_string() or
59 * gst_value_serialize() and their counterparts.
60 */
61
62 #ifdef HAVE_CONFIG_H
63 #include "config.h"
64 #endif
65 #include <string.h>
66 #include <signal.h>
67
68 #include "gst_private.h"
69 #include <gst/gst.h>
70 #include <gobject/gvaluecollector.h>
71
72 #define DEBUG_REFCOUNT
73
74 typedef struct _GstCapsArrayElement
75 {
76 GstStructure *structure;
77 GstCapsFeatures *features;
78 } GstCapsArrayElement;
79
80 typedef struct _GstCapsImpl
81 {
82 GstCaps caps;
83
84 GArray *array;
85 } GstCapsImpl;
86
87 #define GST_CAPS_ARRAY(c) (((GstCapsImpl *)(c))->array)
88
89 #define GST_CAPS_LEN(c) (GST_CAPS_ARRAY(c)->len)
90
91 #define IS_WRITABLE(caps) \
92 (GST_CAPS_REFCOUNT_VALUE (caps) == 1)
93
94 /* same as gst_caps_is_any () */
95 #define CAPS_IS_ANY(caps) \
96 (!!(GST_CAPS_FLAGS(caps) & GST_CAPS_FLAG_ANY))
97
98 /* same as gst_caps_is_empty () */
99 #define CAPS_IS_EMPTY(caps) \
100 (!CAPS_IS_ANY(caps) && CAPS_IS_EMPTY_SIMPLE(caps))
101
102 #define CAPS_IS_EMPTY_SIMPLE(caps) \
103 ((GST_CAPS_ARRAY (caps) == NULL) || (GST_CAPS_LEN (caps) == 0))
104
105 #define gst_caps_features_copy_conditional(f) ((f && (gst_caps_features_is_any (f) || !gst_caps_features_is_equal (f, GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))) ? gst_caps_features_copy (f) : NULL)
106
107 /* quick way to get a caps structure at an index without doing a type or array
108 * length check */
109 #define gst_caps_get_structure_unchecked(caps, index) \
110 (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).structure)
111 #define gst_caps_get_features_storage_unchecked(caps, index) \
112 (&g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).features)
113 #define gst_caps_get_features_unchecked(caps, index) \
114 (g_atomic_pointer_get (gst_caps_get_features_storage_unchecked (caps, index)))
115 /* quick way to append a structure without checking the args */
116 #define gst_caps_append_structure_unchecked(caps, s, f) G_STMT_START{\
117 GstCapsArrayElement __e={s, f}; \
118 if (gst_structure_set_parent_refcount (__e.structure, &GST_MINI_OBJECT_REFCOUNT(caps)) && \
119 (!__e.features || gst_caps_features_set_parent_refcount (__e.features, &GST_MINI_OBJECT_REFCOUNT(caps)))) \
120 g_array_append_val (GST_CAPS_ARRAY (caps), __e); \
121 }G_STMT_END
122
123 /* lock to protect multiple invocations of static caps to caps conversion */
124 G_LOCK_DEFINE_STATIC (static_caps_lock);
125
126 static void gst_caps_transform_to_string (const GValue * src_value,
127 GValue * dest_value);
128 static gboolean gst_caps_from_string_inplace (GstCaps * caps,
129 const gchar * string);
130
131 GType _gst_caps_type = 0;
132 GstCaps *_gst_caps_any;
133 GstCaps *_gst_caps_none;
134
135 GST_DEFINE_MINI_OBJECT_TYPE (GstCaps, gst_caps);
136
137 void
_priv_gst_caps_initialize(void)138 _priv_gst_caps_initialize (void)
139 {
140 _gst_caps_type = gst_caps_get_type ();
141
142 _gst_caps_any = gst_caps_new_any ();
143 _gst_caps_none = gst_caps_new_empty ();
144
145 g_value_register_transform_func (_gst_caps_type,
146 G_TYPE_STRING, gst_caps_transform_to_string);
147 }
148
149 void
_priv_gst_caps_cleanup(void)150 _priv_gst_caps_cleanup (void)
151 {
152 gst_caps_unref (_gst_caps_any);
153 _gst_caps_any = NULL;
154 gst_caps_unref (_gst_caps_none);
155 _gst_caps_none = NULL;
156 }
157
158 GstCapsFeatures *
__gst_caps_get_features_unchecked(const GstCaps * caps,guint idx)159 __gst_caps_get_features_unchecked (const GstCaps * caps, guint idx)
160 {
161 return gst_caps_get_features_unchecked (caps, idx);
162 }
163
164 static GstCaps *
_gst_caps_copy(const GstCaps * caps)165 _gst_caps_copy (const GstCaps * caps)
166 {
167 GstCaps *newcaps;
168 GstStructure *structure;
169 GstCapsFeatures *features;
170 guint i, n;
171
172 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
173
174 newcaps = gst_caps_new_empty ();
175 GST_CAPS_FLAGS (newcaps) = GST_CAPS_FLAGS (caps);
176 n = GST_CAPS_LEN (caps);
177
178 GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "doing copy %p -> %p", caps, newcaps);
179
180 for (i = 0; i < n; i++) {
181 structure = gst_caps_get_structure_unchecked (caps, i);
182 features = gst_caps_get_features_unchecked (caps, i);
183 gst_caps_append_structure_full (newcaps, gst_structure_copy (structure),
184 gst_caps_features_copy_conditional (features));
185 }
186
187 return newcaps;
188 }
189
190 /* creation/deletion */
191 static void
_gst_caps_free(GstCaps * caps)192 _gst_caps_free (GstCaps * caps)
193 {
194 GstStructure *structure;
195 GstCapsFeatures *features;
196 guint i, len;
197
198 /* The refcount must be 0, but since we're only called by gst_caps_unref,
199 * don't bother testing. */
200 len = GST_CAPS_LEN (caps);
201 /* This can be used to get statistics about caps sizes */
202 /*GST_CAT_INFO (GST_CAT_CAPS, "caps size: %d", len); */
203 for (i = 0; i < len; i++) {
204 structure = gst_caps_get_structure_unchecked (caps, i);
205 gst_structure_set_parent_refcount (structure, NULL);
206 gst_structure_free (structure);
207 features = gst_caps_get_features_unchecked (caps, i);
208 if (features) {
209 gst_caps_features_set_parent_refcount (features, NULL);
210 gst_caps_features_free (features);
211 }
212 }
213 g_array_free (GST_CAPS_ARRAY (caps), TRUE);
214
215 #ifdef DEBUG_REFCOUNT
216 GST_CAT_TRACE (GST_CAT_CAPS, "freeing caps %p", caps);
217 #endif
218
219 #ifdef USE_POISONING
220 memset (caps, 0xff, sizeof (GstCapsImpl));
221 #endif
222
223 g_slice_free1 (sizeof (GstCapsImpl), caps);
224 }
225
226 static void
gst_caps_init(GstCaps * caps)227 gst_caps_init (GstCaps * caps)
228 {
229 gst_mini_object_init (GST_MINI_OBJECT_CAST (caps), 0, _gst_caps_type,
230 (GstMiniObjectCopyFunction) _gst_caps_copy, NULL,
231 (GstMiniObjectFreeFunction) _gst_caps_free);
232
233 /* the 32 has been determined by logging caps sizes in _gst_caps_free
234 * but g_ptr_array uses 16 anyway if it expands once, so this does not help
235 * in practice
236 * GST_CAPS_ARRAY (caps) = g_ptr_array_sized_new (32);
237 */
238 GST_CAPS_ARRAY (caps) =
239 g_array_new (FALSE, TRUE, sizeof (GstCapsArrayElement));
240 }
241
242 /**
243 * gst_caps_new_empty:
244 *
245 * Creates a new #GstCaps that is empty. That is, the returned
246 * #GstCaps contains no media formats.
247 * The #GstCaps is guaranteed to be writable.
248 * Caller is responsible for unreffing the returned caps.
249 *
250 * Returns: (transfer full): the new #GstCaps
251 */
252 GstCaps *
gst_caps_new_empty(void)253 gst_caps_new_empty (void)
254 {
255 GstCaps *caps;
256
257 caps = (GstCaps *) g_slice_new (GstCapsImpl);
258
259 gst_caps_init (caps);
260
261 #ifdef DEBUG_REFCOUNT
262 GST_CAT_TRACE (GST_CAT_CAPS, "created caps %p", caps);
263 #endif
264
265 return caps;
266 }
267
268 /**
269 * gst_caps_new_any:
270 *
271 * Creates a new #GstCaps that indicates that it is compatible with
272 * any media format.
273 *
274 * Returns: (transfer full): the new #GstCaps
275 */
276 GstCaps *
gst_caps_new_any(void)277 gst_caps_new_any (void)
278 {
279 GstCaps *caps = gst_caps_new_empty ();
280
281 GST_CAPS_FLAG_SET (caps, GST_CAPS_FLAG_ANY);
282
283 return caps;
284 }
285
286 /**
287 * gst_caps_new_empty_simple:
288 * @media_type: the media type of the structure
289 *
290 * Creates a new #GstCaps that contains one #GstStructure with name
291 * @media_type.
292 * Caller is responsible for unreffing the returned caps.
293 *
294 * Returns: (transfer full): the new #GstCaps
295 */
296 GstCaps *
gst_caps_new_empty_simple(const char * media_type)297 gst_caps_new_empty_simple (const char *media_type)
298 {
299 GstCaps *caps;
300 GstStructure *structure;
301
302 caps = gst_caps_new_empty ();
303 structure = gst_structure_new_empty (media_type);
304 if (structure)
305 gst_caps_append_structure_unchecked (caps, structure, NULL);
306
307 return caps;
308 }
309
310 /**
311 * gst_caps_new_simple:
312 * @media_type: the media type of the structure
313 * @fieldname: first field to set
314 * @...: additional arguments
315 *
316 * Creates a new #GstCaps that contains one #GstStructure. The
317 * structure is defined by the arguments, which have the same format
318 * as gst_structure_new().
319 * Caller is responsible for unreffing the returned caps.
320 *
321 * Returns: (transfer full): the new #GstCaps
322 */
323 GstCaps *
gst_caps_new_simple(const char * media_type,const char * fieldname,...)324 gst_caps_new_simple (const char *media_type, const char *fieldname, ...)
325 {
326 GstCaps *caps;
327 GstStructure *structure;
328 va_list var_args;
329
330 caps = gst_caps_new_empty ();
331
332 va_start (var_args, fieldname);
333 structure = gst_structure_new_valist (media_type, fieldname, var_args);
334 va_end (var_args);
335
336 if (structure)
337 gst_caps_append_structure_unchecked (caps, structure, NULL);
338 else
339 gst_caps_replace (&caps, NULL);
340
341 return caps;
342 }
343
344 /**
345 * gst_caps_new_full:
346 * @struct1: the first structure to add
347 * @...: additional structures to add
348 *
349 * Creates a new #GstCaps and adds all the structures listed as
350 * arguments. The list must be %NULL-terminated. The structures
351 * are not copied; the returned #GstCaps owns the structures.
352 *
353 * Returns: (transfer full): the new #GstCaps
354 */
355 GstCaps *
gst_caps_new_full(GstStructure * struct1,...)356 gst_caps_new_full (GstStructure * struct1, ...)
357 {
358 GstCaps *caps;
359 va_list var_args;
360
361 va_start (var_args, struct1);
362 caps = gst_caps_new_full_valist (struct1, var_args);
363 va_end (var_args);
364
365 return caps;
366 }
367
368 /**
369 * gst_caps_new_full_valist:
370 * @structure: the first structure to add
371 * @var_args: additional structures to add
372 *
373 * Creates a new #GstCaps and adds all the structures listed as
374 * arguments. The list must be %NULL-terminated. The structures
375 * are not copied; the returned #GstCaps owns the structures.
376 *
377 * Returns: (transfer full): the new #GstCaps
378 */
379 GstCaps *
gst_caps_new_full_valist(GstStructure * structure,va_list var_args)380 gst_caps_new_full_valist (GstStructure * structure, va_list var_args)
381 {
382 GstCaps *caps;
383
384 caps = gst_caps_new_empty ();
385
386 while (structure) {
387 gst_caps_append_structure_unchecked (caps, structure, NULL);
388 structure = va_arg (var_args, GstStructure *);
389 }
390
391 return caps;
392 }
393
394 G_DEFINE_POINTER_TYPE (GstStaticCaps, gst_static_caps);
395
396 /**
397 * gst_static_caps_get:
398 * @static_caps: the #GstStaticCaps to convert
399 *
400 * Converts a #GstStaticCaps to a #GstCaps.
401 *
402 * Returns: (transfer full) (nullable): a pointer to the #GstCaps. Unref
403 * after usage. Since the core holds an additional ref to the
404 * returned caps, use gst_caps_make_writable() on the returned caps
405 * to modify it.
406 */
407 GstCaps *
gst_static_caps_get(GstStaticCaps * static_caps)408 gst_static_caps_get (GstStaticCaps * static_caps)
409 {
410 GstCaps **caps;
411
412 g_return_val_if_fail (static_caps != NULL, NULL);
413
414 caps = &static_caps->caps;
415
416 /* refcount is 0 when we need to convert */
417 if (G_UNLIKELY (*caps == NULL)) {
418 const char *string;
419
420 G_LOCK (static_caps_lock);
421 /* check if other thread already updated */
422 if (G_UNLIKELY (*caps != NULL))
423 goto done;
424
425 string = static_caps->string;
426
427 if (G_UNLIKELY (string == NULL))
428 goto no_string;
429
430 *caps = gst_caps_from_string (string);
431
432 /* convert to string */
433 if (G_UNLIKELY (*caps == NULL)) {
434 g_critical ("Could not convert static caps \"%s\"", string);
435 goto done;
436 }
437
438 /* Caps generated from static caps are usually leaked */
439 GST_MINI_OBJECT_FLAG_SET (*caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
440
441 GST_CAT_TRACE (GST_CAT_CAPS, "created %p from string %s", static_caps,
442 string);
443 done:
444 G_UNLOCK (static_caps_lock);
445 }
446 /* ref the caps, makes it not writable */
447 if (G_LIKELY (*caps != NULL))
448 gst_caps_ref (*caps);
449
450 return *caps;
451
452 /* ERRORS */
453 no_string:
454 {
455 G_UNLOCK (static_caps_lock);
456 g_warning ("static caps %p string is NULL", static_caps);
457 return NULL;
458 }
459 }
460
461 /**
462 * gst_static_caps_cleanup:
463 * @static_caps: the #GstStaticCaps to clean
464 *
465 * Clean up the cached caps contained in @static_caps.
466 */
467 void
gst_static_caps_cleanup(GstStaticCaps * static_caps)468 gst_static_caps_cleanup (GstStaticCaps * static_caps)
469 {
470 G_LOCK (static_caps_lock);
471 gst_caps_replace (&static_caps->caps, NULL);
472 G_UNLOCK (static_caps_lock);
473 }
474
475 /* manipulation */
476
477 static void
gst_caps_remove_and_get_structure_and_features(GstCaps * caps,guint idx,GstStructure ** s,GstCapsFeatures ** f)478 gst_caps_remove_and_get_structure_and_features (GstCaps * caps, guint idx,
479 GstStructure ** s, GstCapsFeatures ** f)
480 {
481 GstStructure *s_;
482 GstCapsFeatures *f_;
483
484 s_ = gst_caps_get_structure_unchecked (caps, idx);
485 f_ = gst_caps_get_features_unchecked (caps, idx);
486
487 /* don't use index_fast, gst_caps_simplify relies on the order */
488 g_array_remove_index (GST_CAPS_ARRAY (caps), idx);
489
490 gst_structure_set_parent_refcount (s_, NULL);
491 if (f_) {
492 gst_caps_features_set_parent_refcount (f_, NULL);
493 }
494
495 *s = s_;
496 *f = f_;
497 }
498
499 static GstStructure *
gst_caps_remove_and_get_structure(GstCaps * caps,guint idx)500 gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
501 {
502 GstStructure *s;
503 GstCapsFeatures *f;
504
505 gst_caps_remove_and_get_structure_and_features (caps, idx, &s, &f);
506
507 if (f)
508 gst_caps_features_free (f);
509
510 return s;
511 }
512
513 /**
514 * gst_caps_steal_structure:
515 * @caps: the #GstCaps to retrieve from
516 * @index: Index of the structure to retrieve
517 *
518 * Retrieves the structure with the given index from the list of structures
519 * contained in @caps. The caller becomes the owner of the returned structure.
520 *
521 * Returns: (transfer full) (nullable): a pointer to the #GstStructure
522 * corresponding to @index.
523 */
524 GstStructure *
gst_caps_steal_structure(GstCaps * caps,guint index)525 gst_caps_steal_structure (GstCaps * caps, guint index)
526 {
527 g_return_val_if_fail (caps != NULL, NULL);
528 g_return_val_if_fail (IS_WRITABLE (caps), NULL);
529
530 if (G_UNLIKELY (index >= GST_CAPS_LEN (caps)))
531 return NULL;
532
533 return gst_caps_remove_and_get_structure (caps, index);
534 }
535
536 /**
537 * gst_caps_append:
538 * @caps1: the #GstCaps that will be appended to
539 * @caps2: (transfer full): the #GstCaps to append
540 *
541 * Appends the structures contained in @caps2 to @caps1. The structures in
542 * @caps2 are not copied -- they are transferred to @caps1, and then @caps2 is
543 * freed. If either caps is ANY, the resulting caps will be ANY.
544 */
545 void
gst_caps_append(GstCaps * caps1,GstCaps * caps2)546 gst_caps_append (GstCaps * caps1, GstCaps * caps2)
547 {
548 GstStructure *structure;
549 GstCapsFeatures *features;
550 int i;
551
552 g_return_if_fail (GST_IS_CAPS (caps1));
553 g_return_if_fail (GST_IS_CAPS (caps2));
554 g_return_if_fail (IS_WRITABLE (caps1));
555
556 if (G_UNLIKELY (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2))) {
557 GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAG_ANY;
558 gst_caps_unref (caps2);
559 } else {
560 caps2 = gst_caps_make_writable (caps2);
561
562 for (i = GST_CAPS_LEN (caps2); i; i--) {
563 gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure,
564 &features);
565 gst_caps_append_structure_unchecked (caps1, structure, features);
566 }
567 gst_caps_unref (caps2); /* guaranteed to free it */
568 }
569 }
570
571 /**
572 * gst_caps_merge:
573 * @caps1: (transfer full): the #GstCaps that will take the new entries
574 * @caps2: (transfer full): the #GstCaps to merge in
575 *
576 * Appends the structures contained in @caps2 to @caps1 if they are not yet
577 * expressed by @caps1. The structures in @caps2 are not copied -- they are
578 * transferred to a writable copy of @caps1, and then @caps2 is freed.
579 * If either caps is ANY, the resulting caps will be ANY.
580 *
581 * Returns: (transfer full): the merged caps.
582 */
583 GstCaps *
gst_caps_merge(GstCaps * caps1,GstCaps * caps2)584 gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
585 {
586 GstStructure *structure;
587 GstCapsFeatures *features;
588 int i;
589 GstCaps *result;
590
591 g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
592 g_return_val_if_fail (GST_IS_CAPS (caps2), NULL);
593
594 if (G_UNLIKELY (CAPS_IS_ANY (caps1))) {
595 gst_caps_unref (caps2);
596 result = caps1;
597 } else if (G_UNLIKELY (CAPS_IS_ANY (caps2))) {
598 gst_caps_unref (caps1);
599 result = caps2;
600 } else {
601 caps2 = gst_caps_make_writable (caps2);
602
603 for (i = GST_CAPS_LEN (caps2); i; i--) {
604 gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure,
605 &features);
606 caps1 = gst_caps_merge_structure_full (caps1, structure, features);
607 }
608 gst_caps_unref (caps2);
609 result = caps1;
610
611 /* this is too naive
612 GstCaps *com = gst_caps_intersect (caps1, caps2);
613 GstCaps *add = gst_caps_subtract (caps2, com);
614
615 GST_DEBUG ("common : %d", gst_caps_get_size (com));
616 GST_DEBUG ("adding : %d", gst_caps_get_size (add));
617 gst_caps_append (caps1, add);
618 gst_caps_unref (com);
619 */
620 }
621
622 return result;
623 }
624
625 /**
626 * gst_caps_append_structure:
627 * @caps: the #GstCaps that will be appended to
628 * @structure: (transfer full): the #GstStructure to append
629 *
630 * Appends @structure to @caps. The structure is not copied; @caps
631 * becomes the owner of @structure.
632 */
633 void
gst_caps_append_structure(GstCaps * caps,GstStructure * structure)634 gst_caps_append_structure (GstCaps * caps, GstStructure * structure)
635 {
636 g_return_if_fail (GST_IS_CAPS (caps));
637 g_return_if_fail (IS_WRITABLE (caps));
638
639 if (G_LIKELY (structure)) {
640 gst_caps_append_structure_unchecked (caps, structure, NULL);
641 }
642 }
643
644 /**
645 * gst_caps_append_structure_full:
646 * @caps: the #GstCaps that will be appended to
647 * @structure: (transfer full): the #GstStructure to append
648 * @features: (transfer full) (allow-none): the #GstCapsFeatures to append
649 *
650 * Appends @structure with @features to @caps. The structure is not copied; @caps
651 * becomes the owner of @structure.
652 *
653 * Since: 1.2
654 */
655 void
gst_caps_append_structure_full(GstCaps * caps,GstStructure * structure,GstCapsFeatures * features)656 gst_caps_append_structure_full (GstCaps * caps, GstStructure * structure,
657 GstCapsFeatures * features)
658 {
659 g_return_if_fail (GST_IS_CAPS (caps));
660 g_return_if_fail (IS_WRITABLE (caps));
661
662 if (G_LIKELY (structure)) {
663 gst_caps_append_structure_unchecked (caps, structure, features);
664 }
665 }
666
667 /**
668 * gst_caps_remove_structure:
669 * @caps: the #GstCaps to remove from
670 * @idx: Index of the structure to remove
671 *
672 * removes the structure with the given index from the list of structures
673 * contained in @caps.
674 */
675 void
gst_caps_remove_structure(GstCaps * caps,guint idx)676 gst_caps_remove_structure (GstCaps * caps, guint idx)
677 {
678 GstStructure *structure;
679
680 g_return_if_fail (caps != NULL);
681 g_return_if_fail (idx <= gst_caps_get_size (caps));
682 g_return_if_fail (IS_WRITABLE (caps));
683
684 structure = gst_caps_remove_and_get_structure (caps, idx);
685 gst_structure_free (structure);
686 }
687
688 /**
689 * gst_caps_merge_structure:
690 * @caps: (transfer full): the #GstCaps to merge into
691 * @structure: (transfer full): the #GstStructure to merge
692 *
693 * Appends @structure to @caps if its not already expressed by @caps.
694 *
695 * Returns: (transfer full): the merged caps.
696 */
697 GstCaps *
gst_caps_merge_structure(GstCaps * caps,GstStructure * structure)698 gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
699 {
700 GstStructure *structure1;
701 GstCapsFeatures *features1;
702 int i;
703 gboolean unique = TRUE;
704
705 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
706
707 if (G_UNLIKELY (structure == NULL))
708 return caps;
709
710 /* check each structure */
711 for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
712 structure1 = gst_caps_get_structure_unchecked (caps, i);
713 features1 = gst_caps_get_features_unchecked (caps, i);
714 if (!features1)
715 features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
716
717 /* if structure is a subset of structure1 and the
718 * there are no existing features, then skip it */
719 if (gst_caps_features_is_equal (features1,
720 GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
721 && gst_structure_is_subset (structure, structure1)) {
722 unique = FALSE;
723 break;
724 }
725 }
726 if (unique) {
727 caps = gst_caps_make_writable (caps);
728 gst_caps_append_structure_unchecked (caps, structure, NULL);
729 } else {
730 gst_structure_free (structure);
731 }
732 return caps;
733 }
734
735 /**
736 * gst_caps_merge_structure_full:
737 * @caps: (transfer full): the #GstCaps to merge into
738 * @structure: (transfer full): the #GstStructure to merge
739 * @features: (transfer full) (allow-none): the #GstCapsFeatures to merge
740 *
741 * Appends @structure with @features to @caps if its not already expressed by @caps.
742 *
743 * Returns: (transfer full): the merged caps.
744 *
745 * Since: 1.2
746 */
747 GstCaps *
gst_caps_merge_structure_full(GstCaps * caps,GstStructure * structure,GstCapsFeatures * features)748 gst_caps_merge_structure_full (GstCaps * caps, GstStructure * structure,
749 GstCapsFeatures * features)
750 {
751 GstStructure *structure1;
752 GstCapsFeatures *features1, *features_tmp;
753 int i;
754 gboolean unique = TRUE;
755
756 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
757
758 if (G_UNLIKELY (structure == NULL))
759 return caps;
760
761 /* To make comparisons easier below */
762 features_tmp = features ? features : GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
763
764 /* check each structure */
765 for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
766 structure1 = gst_caps_get_structure_unchecked (caps, i);
767 features1 = gst_caps_get_features_unchecked (caps, i);
768 if (!features1)
769 features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
770 /* if structure is a subset of structure1 and the
771 * the features are a subset, then skip it */
772 /* FIXME: We only skip if none of the features are
773 * ANY and are still equal. That way all ANY structures
774 * show up in the caps and no non-ANY structures are
775 * swallowed by ANY structures
776 */
777 if (((!gst_caps_features_is_any (features_tmp)
778 || gst_caps_features_is_any (features1))
779 && gst_caps_features_is_equal (features_tmp, features1))
780 && gst_structure_is_subset (structure, structure1)) {
781 unique = FALSE;
782 break;
783 }
784 }
785 if (unique) {
786 caps = gst_caps_make_writable (caps);
787 gst_caps_append_structure_unchecked (caps, structure, features);
788 } else {
789 gst_structure_free (structure);
790 if (features)
791 gst_caps_features_free (features);
792 }
793 return caps;
794 }
795
796 /**
797 * gst_caps_get_size:
798 * @caps: a #GstCaps
799 *
800 * Gets the number of structures contained in @caps.
801 *
802 * Returns: the number of structures that @caps contains
803 */
804 guint
gst_caps_get_size(const GstCaps * caps)805 gst_caps_get_size (const GstCaps * caps)
806 {
807 g_return_val_if_fail (GST_IS_CAPS (caps), 0);
808
809 return GST_CAPS_LEN (caps);
810 }
811
812 /**
813 * gst_caps_get_structure:
814 * @caps: a #GstCaps
815 * @index: the index of the structure
816 *
817 * Finds the structure in @caps that has the index @index, and
818 * returns it.
819 *
820 * WARNING: This function takes a const GstCaps *, but returns a
821 * non-const GstStructure *. This is for programming convenience --
822 * the caller should be aware that structures inside a constant
823 * #GstCaps should not be modified. However, if you know the caps
824 * are writable, either because you have just copied them or made
825 * them writable with gst_caps_make_writable(), you may modify the
826 * structure returned in the usual way, e.g. with functions like
827 * gst_structure_set().
828 *
829 * You do not need to free or unref the structure returned, it
830 * belongs to the #GstCaps.
831 *
832 * Returns: (transfer none): a pointer to the #GstStructure corresponding
833 * to @index
834 */
835 GstStructure *
gst_caps_get_structure(const GstCaps * caps,guint index)836 gst_caps_get_structure (const GstCaps * caps, guint index)
837 {
838 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
839 g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL);
840
841 return gst_caps_get_structure_unchecked (caps, index);
842 }
843
844 /**
845 * gst_caps_get_features:
846 * @caps: a #GstCaps
847 * @index: the index of the structure
848 *
849 * Finds the features in @caps that has the index @index, and
850 * returns it.
851 *
852 * WARNING: This function takes a const GstCaps *, but returns a
853 * non-const GstCapsFeatures *. This is for programming convenience --
854 * the caller should be aware that structures inside a constant
855 * #GstCaps should not be modified. However, if you know the caps
856 * are writable, either because you have just copied them or made
857 * them writable with gst_caps_make_writable(), you may modify the
858 * features returned in the usual way, e.g. with functions like
859 * gst_caps_features_add().
860 *
861 * You do not need to free or unref the structure returned, it
862 * belongs to the #GstCaps.
863 *
864 * Returns: (transfer none) (nullable): a pointer to the #GstCapsFeatures
865 * corresponding to @index
866 *
867 * Since: 1.2
868 */
869 GstCapsFeatures *
gst_caps_get_features(const GstCaps * caps,guint index)870 gst_caps_get_features (const GstCaps * caps, guint index)
871 {
872 GstCapsFeatures *features;
873
874 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
875 g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL);
876
877 features = gst_caps_get_features_unchecked (caps, index);
878 if (!features) {
879 GstCapsFeatures **storage;
880
881 /* We have to do some atomic pointer magic here as the caps
882 * might not be writable and someone else calls this function
883 * at the very same time */
884 features = gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY);
885 gst_caps_features_set_parent_refcount (features, &GST_CAPS_REFCOUNT (caps));
886
887 storage = gst_caps_get_features_storage_unchecked (caps, index);
888 if (!g_atomic_pointer_compare_and_exchange (storage, NULL, features)) {
889 /* Someone did the same we just tried in the meantime */
890 gst_caps_features_set_parent_refcount (features, NULL);
891 gst_caps_features_free (features);
892
893 features = gst_caps_get_features_unchecked (caps, index);
894 g_assert (features != NULL);
895 }
896 }
897
898 return features;
899 }
900
901 /**
902 * gst_caps_set_features:
903 * @caps: a #GstCaps
904 * @index: the index of the structure
905 * @features: (allow-none) (transfer full): the #GstCapsFeatures to set
906 *
907 * Sets the #GstCapsFeatures @features for the structure at @index.
908 *
909 * Since: 1.2
910 */
911 void
gst_caps_set_features(GstCaps * caps,guint index,GstCapsFeatures * features)912 gst_caps_set_features (GstCaps * caps, guint index, GstCapsFeatures * features)
913 {
914 GstCapsFeatures **storage, *old;
915
916 g_return_if_fail (caps != NULL);
917 g_return_if_fail (index <= gst_caps_get_size (caps));
918 g_return_if_fail (IS_WRITABLE (caps));
919
920 storage = gst_caps_get_features_storage_unchecked (caps, index);
921 /* Not much problem here as caps are writable */
922 old = g_atomic_pointer_get (storage);
923 g_atomic_pointer_set (storage, features);
924
925 if (features)
926 gst_caps_features_set_parent_refcount (features, &GST_CAPS_REFCOUNT (caps));
927
928 if (old) {
929 gst_caps_features_set_parent_refcount (old, NULL);
930 gst_caps_features_free (old);
931 }
932 }
933
934 /**
935 * gst_caps_set_features_simple:
936 * @caps: a #GstCaps
937 * @features: (allow-none) (transfer full): the #GstCapsFeatures to set
938 *
939 * Sets the #GstCapsFeatures @features for all the structures of @caps.
940 *
941 * Since: 1.16
942 */
943 void
gst_caps_set_features_simple(GstCaps * caps,GstCapsFeatures * features)944 gst_caps_set_features_simple (GstCaps * caps, GstCapsFeatures * features)
945 {
946 guint i;
947 guint n;
948
949 g_return_if_fail (caps != NULL);
950 g_return_if_fail (IS_WRITABLE (caps));
951
952 n = gst_caps_get_size (caps);
953
954 for (i = 0; i < n; i++) {
955 GstCapsFeatures *f;
956
957 /* Transfer ownership of @features to the last structure */
958 if (features && i < n - 1)
959 f = gst_caps_features_copy (features);
960 else
961 f = features;
962
963 gst_caps_set_features (caps, i, f);
964 }
965 }
966
967 /**
968 * gst_caps_copy_nth:
969 * @caps: the #GstCaps to copy
970 * @nth: the nth structure to copy
971 *
972 * Creates a new #GstCaps and appends a copy of the nth structure
973 * contained in @caps.
974 *
975 * Returns: (transfer full): the new #GstCaps
976 *
977 * Since: 1.16
978 */
979 GstCaps *
gst_caps_copy_nth(const GstCaps * caps,guint nth)980 gst_caps_copy_nth (const GstCaps * caps, guint nth)
981 {
982 GstCaps *newcaps;
983 GstStructure *structure;
984 GstCapsFeatures *features;
985
986 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
987
988 newcaps = gst_caps_new_empty ();
989 GST_CAPS_FLAGS (newcaps) = GST_CAPS_FLAGS (caps);
990
991 if (G_LIKELY (GST_CAPS_LEN (caps) > nth)) {
992 structure = gst_caps_get_structure_unchecked (caps, nth);
993 features = gst_caps_get_features_unchecked (caps, nth);
994 gst_caps_append_structure_unchecked (newcaps,
995 gst_structure_copy (structure),
996 gst_caps_features_copy_conditional (features));
997 }
998
999 return newcaps;
1000 }
1001
1002 /**
1003 * gst_caps_truncate:
1004 * @caps: (transfer full): the #GstCaps to truncate
1005 *
1006 * Discard all but the first structure from @caps. Useful when
1007 * fixating.
1008 *
1009 * This function takes ownership of @caps and will call gst_caps_make_writable()
1010 * on it if necessary, so you must not use @caps afterwards unless you keep an
1011 * additional reference to it with gst_caps_ref().
1012 *
1013 * Returns: (transfer full): truncated caps
1014 */
1015 GstCaps *
gst_caps_truncate(GstCaps * caps)1016 gst_caps_truncate (GstCaps * caps)
1017 {
1018 gint i;
1019
1020 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
1021
1022 i = GST_CAPS_LEN (caps) - 1;
1023 if (i == 0)
1024 return caps;
1025
1026 caps = gst_caps_make_writable (caps);
1027 while (i > 0)
1028 gst_caps_remove_structure (caps, i--);
1029
1030 return caps;
1031 }
1032
1033 /**
1034 * gst_caps_set_value:
1035 * @caps: a writable caps
1036 * @field: name of the field to set
1037 * @value: value to set the field to
1038 *
1039 * Sets the given @field on all structures of @caps to the given @value.
1040 * This is a convenience function for calling gst_structure_set_value() on
1041 * all structures of @caps.
1042 **/
1043 void
gst_caps_set_value(GstCaps * caps,const char * field,const GValue * value)1044 gst_caps_set_value (GstCaps * caps, const char *field, const GValue * value)
1045 {
1046 guint i, len;
1047
1048 g_return_if_fail (GST_IS_CAPS (caps));
1049 g_return_if_fail (IS_WRITABLE (caps));
1050 g_return_if_fail (field != NULL);
1051 g_return_if_fail (G_IS_VALUE (value));
1052
1053 len = GST_CAPS_LEN (caps);
1054 for (i = 0; i < len; i++) {
1055 GstStructure *structure = gst_caps_get_structure_unchecked (caps, i);
1056 gst_structure_set_value (structure, field, value);
1057 }
1058 }
1059
1060 /**
1061 * gst_caps_set_simple_valist:
1062 * @caps: the #GstCaps to set
1063 * @field: first field to set
1064 * @varargs: additional parameters
1065 *
1066 * Sets fields in a #GstCaps. The arguments must be passed in the same
1067 * manner as gst_structure_set(), and be %NULL-terminated.
1068 */
1069 void
gst_caps_set_simple_valist(GstCaps * caps,const char * field,va_list varargs)1070 gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs)
1071 {
1072 GValue value = { 0, };
1073
1074 g_return_if_fail (GST_IS_CAPS (caps));
1075 g_return_if_fail (IS_WRITABLE (caps));
1076
1077 while (field) {
1078 GType type;
1079 char *err;
1080
1081 type = va_arg (varargs, GType);
1082
1083 G_VALUE_COLLECT_INIT (&value, type, varargs, 0, &err);
1084 if (G_UNLIKELY (err)) {
1085 g_critical ("%s", err);
1086 g_free (err);
1087 return;
1088 }
1089
1090 gst_caps_set_value (caps, field, &value);
1091
1092 g_value_unset (&value);
1093
1094 field = va_arg (varargs, const gchar *);
1095 }
1096 }
1097
1098 /**
1099 * gst_caps_set_simple:
1100 * @caps: the #GstCaps to set
1101 * @field: first field to set
1102 * @...: additional parameters
1103 *
1104 * Sets fields in a #GstCaps. The arguments must be passed in the same
1105 * manner as gst_structure_set(), and be %NULL-terminated.
1106 */
1107 void
gst_caps_set_simple(GstCaps * caps,const char * field,...)1108 gst_caps_set_simple (GstCaps * caps, const char *field, ...)
1109 {
1110 va_list var_args;
1111
1112 g_return_if_fail (GST_IS_CAPS (caps));
1113 g_return_if_fail (IS_WRITABLE (caps));
1114
1115 va_start (var_args, field);
1116 gst_caps_set_simple_valist (caps, field, var_args);
1117 va_end (var_args);
1118 }
1119
1120 /* tests */
1121
1122 /**
1123 * gst_caps_is_any:
1124 * @caps: the #GstCaps to test
1125 *
1126 * Determines if @caps represents any media format.
1127 *
1128 * Returns: %TRUE if @caps represents any format.
1129 */
1130 gboolean
gst_caps_is_any(const GstCaps * caps)1131 gst_caps_is_any (const GstCaps * caps)
1132 {
1133 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
1134
1135 return (CAPS_IS_ANY (caps));
1136 }
1137
1138 /**
1139 * gst_caps_is_empty:
1140 * @caps: the #GstCaps to test
1141 *
1142 * Determines if @caps represents no media formats.
1143 *
1144 * Returns: %TRUE if @caps represents no formats.
1145 */
1146 gboolean
gst_caps_is_empty(const GstCaps * caps)1147 gst_caps_is_empty (const GstCaps * caps)
1148 {
1149 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
1150
1151 if (CAPS_IS_ANY (caps))
1152 return FALSE;
1153
1154 return CAPS_IS_EMPTY_SIMPLE (caps);
1155 }
1156
1157 static gboolean
gst_caps_is_fixed_foreach(GQuark field_id,const GValue * value,gpointer unused)1158 gst_caps_is_fixed_foreach (GQuark field_id, const GValue * value,
1159 gpointer unused)
1160 {
1161 return gst_value_is_fixed (value);
1162 }
1163
1164 /**
1165 * gst_caps_is_fixed:
1166 * @caps: the #GstCaps to test
1167 *
1168 * Fixed #GstCaps describe exactly one format, that is, they have exactly
1169 * one structure, and each field in the structure describes a fixed type.
1170 * Examples of non-fixed types are GST_TYPE_INT_RANGE and GST_TYPE_LIST.
1171 *
1172 * Returns: %TRUE if @caps is fixed
1173 */
1174 gboolean
gst_caps_is_fixed(const GstCaps * caps)1175 gst_caps_is_fixed (const GstCaps * caps)
1176 {
1177 GstStructure *structure;
1178 GstCapsFeatures *features;
1179
1180 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
1181
1182 if (GST_CAPS_LEN (caps) != 1)
1183 return FALSE;
1184
1185 features = gst_caps_get_features_unchecked (caps, 0);
1186 if (features && gst_caps_features_is_any (features))
1187 return FALSE;
1188
1189 structure = gst_caps_get_structure_unchecked (caps, 0);
1190
1191 return gst_structure_foreach (structure, gst_caps_is_fixed_foreach, NULL);
1192 }
1193
1194 /**
1195 * gst_caps_is_equal_fixed:
1196 * @caps1: the #GstCaps to test
1197 * @caps2: the #GstCaps to test
1198 *
1199 * Tests if two #GstCaps are equal. This function only works on fixed
1200 * #GstCaps.
1201 *
1202 * Returns: %TRUE if the arguments represent the same format
1203 */
1204 gboolean
gst_caps_is_equal_fixed(const GstCaps * caps1,const GstCaps * caps2)1205 gst_caps_is_equal_fixed (const GstCaps * caps1, const GstCaps * caps2)
1206 {
1207 GstStructure *struct1, *struct2;
1208 GstCapsFeatures *features1, *features2;
1209
1210 g_return_val_if_fail (gst_caps_is_fixed (caps1), FALSE);
1211 g_return_val_if_fail (gst_caps_is_fixed (caps2), FALSE);
1212
1213 struct1 = gst_caps_get_structure_unchecked (caps1, 0);
1214 features1 = gst_caps_get_features_unchecked (caps1, 0);
1215 if (!features1)
1216 features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1217 struct2 = gst_caps_get_structure_unchecked (caps2, 0);
1218 features2 = gst_caps_get_features_unchecked (caps2, 0);
1219 if (!features2)
1220 features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1221
1222 return gst_structure_is_equal (struct1, struct2) &&
1223 gst_caps_features_is_equal (features1, features2);
1224 }
1225
1226 /**
1227 * gst_caps_is_always_compatible:
1228 * @caps1: the #GstCaps to test
1229 * @caps2: the #GstCaps to test
1230 *
1231 * A given #GstCaps structure is always compatible with another if
1232 * every media format that is in the first is also contained in the
1233 * second. That is, @caps1 is a subset of @caps2.
1234 *
1235 * Returns: %TRUE if @caps1 is a subset of @caps2.
1236 */
1237 gboolean
gst_caps_is_always_compatible(const GstCaps * caps1,const GstCaps * caps2)1238 gst_caps_is_always_compatible (const GstCaps * caps1, const GstCaps * caps2)
1239 {
1240 g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
1241 g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);
1242
1243 return gst_caps_is_subset (caps1, caps2);
1244 }
1245
1246 /**
1247 * gst_caps_is_subset:
1248 * @subset: a #GstCaps
1249 * @superset: a potentially greater #GstCaps
1250 *
1251 * Checks if all caps represented by @subset are also represented by @superset.
1252 *
1253 * Returns: %TRUE if @subset is a subset of @superset
1254 */
1255 gboolean
gst_caps_is_subset(const GstCaps * subset,const GstCaps * superset)1256 gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset)
1257 {
1258 GstStructure *s1, *s2;
1259 GstCapsFeatures *f1, *f2;
1260 gboolean ret = TRUE;
1261 gint i, j;
1262
1263 g_return_val_if_fail (subset != NULL, FALSE);
1264 g_return_val_if_fail (superset != NULL, FALSE);
1265
1266 if (CAPS_IS_EMPTY (subset) || CAPS_IS_ANY (superset))
1267 return TRUE;
1268 if (CAPS_IS_ANY (subset) || CAPS_IS_EMPTY (superset))
1269 return FALSE;
1270
1271 for (i = GST_CAPS_LEN (subset) - 1; i >= 0; i--) {
1272 for (j = GST_CAPS_LEN (superset) - 1; j >= 0; j--) {
1273 s1 = gst_caps_get_structure_unchecked (subset, i);
1274 f1 = gst_caps_get_features_unchecked (subset, i);
1275 if (!f1)
1276 f1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1277 s2 = gst_caps_get_structure_unchecked (superset, j);
1278 f2 = gst_caps_get_features_unchecked (superset, j);
1279 if (!f2)
1280 f2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1281 if ((!gst_caps_features_is_any (f1) || gst_caps_features_is_any (f2)) &&
1282 gst_caps_features_is_equal (f1, f2)
1283 && gst_structure_is_subset (s1, s2)) {
1284 /* If we found a superset, continue with the next
1285 * subset structure */
1286 break;
1287 }
1288 }
1289 /* If we found no superset for this subset structure
1290 * we return FALSE immediately */
1291 if (j == -1) {
1292 ret = FALSE;
1293 break;
1294 }
1295 }
1296
1297 return ret;
1298 }
1299
1300 /**
1301 * gst_caps_is_subset_structure:
1302 * @caps: a #GstCaps
1303 * @structure: a potential #GstStructure subset of @caps
1304 *
1305 * Checks if @structure is a subset of @caps. See gst_caps_is_subset()
1306 * for more information.
1307 *
1308 * Returns: %TRUE if @structure is a subset of @caps
1309 */
1310 gboolean
gst_caps_is_subset_structure(const GstCaps * caps,const GstStructure * structure)1311 gst_caps_is_subset_structure (const GstCaps * caps,
1312 const GstStructure * structure)
1313 {
1314 GstStructure *s;
1315 gint i;
1316
1317 g_return_val_if_fail (caps != NULL, FALSE);
1318 g_return_val_if_fail (structure != NULL, FALSE);
1319
1320 if (CAPS_IS_ANY (caps))
1321 return TRUE;
1322 if (CAPS_IS_EMPTY (caps))
1323 return FALSE;
1324
1325 for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
1326 s = gst_caps_get_structure_unchecked (caps, i);
1327 if (gst_structure_is_subset (structure, s)) {
1328 /* If we found a superset return TRUE */
1329 return TRUE;
1330 }
1331 }
1332
1333 return FALSE;
1334 }
1335
1336 /**
1337 * gst_caps_is_subset_structure_full:
1338 * @caps: a #GstCaps
1339 * @structure: a potential #GstStructure subset of @caps
1340 * @features: (allow-none): a #GstCapsFeatures for @structure
1341 *
1342 * Checks if @structure is a subset of @caps. See gst_caps_is_subset()
1343 * for more information.
1344 *
1345 * Returns: %TRUE if @structure is a subset of @caps
1346 *
1347 * Since: 1.2
1348 */
1349 gboolean
gst_caps_is_subset_structure_full(const GstCaps * caps,const GstStructure * structure,const GstCapsFeatures * features)1350 gst_caps_is_subset_structure_full (const GstCaps * caps,
1351 const GstStructure * structure, const GstCapsFeatures * features)
1352 {
1353 GstStructure *s;
1354 GstCapsFeatures *f;
1355 gint i;
1356
1357 g_return_val_if_fail (caps != NULL, FALSE);
1358 g_return_val_if_fail (structure != NULL, FALSE);
1359
1360 if (CAPS_IS_ANY (caps))
1361 return TRUE;
1362 if (CAPS_IS_EMPTY (caps))
1363 return FALSE;
1364
1365 if (!features)
1366 features = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1367
1368 for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
1369 s = gst_caps_get_structure_unchecked (caps, i);
1370 f = gst_caps_get_features_unchecked (caps, i);
1371 if (!f)
1372 f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1373 if ((!gst_caps_features_is_any (features) || gst_caps_features_is_any (f))
1374 && gst_caps_features_is_equal (features, f)
1375 && gst_structure_is_subset (structure, s)) {
1376 /* If we found a superset return TRUE */
1377 return TRUE;
1378 }
1379 }
1380
1381 return FALSE;
1382 }
1383
1384 /**
1385 * gst_caps_is_equal:
1386 * @caps1: a #GstCaps
1387 * @caps2: another #GstCaps
1388 *
1389 * Checks if the given caps represent the same set of caps.
1390 *
1391 * Returns: %TRUE if both caps are equal.
1392 */
1393 gboolean
gst_caps_is_equal(const GstCaps * caps1,const GstCaps * caps2)1394 gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2)
1395 {
1396 g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
1397 g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);
1398
1399 if (G_UNLIKELY (caps1 == caps2))
1400 return TRUE;
1401
1402 if (G_UNLIKELY (gst_caps_is_fixed (caps1) && gst_caps_is_fixed (caps2)))
1403 return gst_caps_is_equal_fixed (caps1, caps2);
1404
1405 return gst_caps_is_subset (caps1, caps2) && gst_caps_is_subset (caps2, caps1);
1406 }
1407
1408 /**
1409 * gst_caps_is_strictly_equal:
1410 * @caps1: a #GstCaps
1411 * @caps2: another #GstCaps
1412 *
1413 * Checks if the given caps are exactly the same set of caps.
1414 *
1415 * Returns: %TRUE if both caps are strictly equal.
1416 */
1417 gboolean
gst_caps_is_strictly_equal(const GstCaps * caps1,const GstCaps * caps2)1418 gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2)
1419 {
1420 int i;
1421 GstStructure *s1, *s2;
1422 GstCapsFeatures *f1, *f2;
1423
1424 g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
1425 g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);
1426
1427 if (G_UNLIKELY (caps1 == caps2))
1428 return TRUE;
1429
1430 if (GST_CAPS_LEN (caps1) != GST_CAPS_LEN (caps2))
1431 return FALSE;
1432
1433 for (i = 0; i < GST_CAPS_LEN (caps1); i++) {
1434 s1 = gst_caps_get_structure_unchecked (caps1, i);
1435 f1 = gst_caps_get_features_unchecked (caps1, i);
1436 if (!f1)
1437 f1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1438 s2 = gst_caps_get_structure_unchecked (caps2, i);
1439 f2 = gst_caps_get_features_unchecked (caps2, i);
1440 if (!f2)
1441 f2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1442
1443 if (gst_caps_features_is_any (f1) != gst_caps_features_is_any (f2) ||
1444 !gst_caps_features_is_equal (f1, f2) ||
1445 !gst_structure_is_equal (s1, s2))
1446 return FALSE;
1447 }
1448
1449 return TRUE;
1450 }
1451
1452 /* intersect operation */
1453
1454 /**
1455 * gst_caps_can_intersect:
1456 * @caps1: a #GstCaps to intersect
1457 * @caps2: a #GstCaps to intersect
1458 *
1459 * Tries intersecting @caps1 and @caps2 and reports whether the result would not
1460 * be empty
1461 *
1462 * Returns: %TRUE if intersection would be not empty
1463 */
1464 gboolean
gst_caps_can_intersect(const GstCaps * caps1,const GstCaps * caps2)1465 gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
1466 {
1467 guint64 i; /* index can be up to 2 * G_MAX_UINT */
1468 guint j, k, len1, len2;
1469 GstStructure *struct1;
1470 GstStructure *struct2;
1471 GstCapsFeatures *features1;
1472 GstCapsFeatures *features2;
1473
1474 g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
1475 g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);
1476
1477 /* caps are exactly the same pointers */
1478 if (G_UNLIKELY (caps1 == caps2))
1479 return TRUE;
1480
1481 /* empty caps on either side, return empty */
1482 if (G_UNLIKELY (CAPS_IS_EMPTY (caps1) || CAPS_IS_EMPTY (caps2)))
1483 return FALSE;
1484
1485 /* one of the caps is any */
1486 if (G_UNLIKELY (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2)))
1487 return TRUE;
1488
1489 /* run zigzag on top line then right line, this preserves the caps order
1490 * much better than a simple loop.
1491 *
1492 * This algorithm zigzags over the caps structures as demonstrated in
1493 * the following matrix:
1494 *
1495 * caps1 0 1 2 3
1496 * +------------- total distance: +-------------
1497 * | 1 2 4 7 0 | 0 1 2 3
1498 * caps2 | 3 5 8 10 1 | 1 2 3 4
1499 * | 6 9 11 12 2 | 2 3 4 5
1500 *
1501 * First we iterate over the caps1 structures (top line) intersecting
1502 * the structures diagonally down, then we iterate over the caps2
1503 * structures. The result is that the intersections are ordered based on the
1504 * sum of the indexes in the list.
1505 */
1506 len1 = GST_CAPS_LEN (caps1);
1507 len2 = GST_CAPS_LEN (caps2);
1508 for (i = 0; i < len1 + len2 - 1; i++) {
1509 /* superset index goes from 0 to superset->structs->len-1 */
1510 j = MIN (i, len1 - 1);
1511 /* subset index stays 0 until i reaches superset->structs->len, then it
1512 * counts up from 1 to subset->structs->len - 1 */
1513 k = (i > j) ? (i - j) : 0; /* MAX (0, i - j) */
1514 /* now run the diagonal line, end condition is the left or bottom
1515 * border */
1516 while (k < len2) {
1517 struct1 = gst_caps_get_structure_unchecked (caps1, j);
1518 features1 = gst_caps_get_features_unchecked (caps1, j);
1519 if (!features1)
1520 features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1521 struct2 = gst_caps_get_structure_unchecked (caps2, k);
1522 features2 = gst_caps_get_features_unchecked (caps2, k);
1523 if (!features2)
1524 features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1525 if (gst_caps_features_is_equal (features1, features2) &&
1526 gst_structure_can_intersect (struct1, struct2)) {
1527 return TRUE;
1528 }
1529 /* move down left */
1530 k++;
1531 if (G_UNLIKELY (j == 0))
1532 break; /* so we don't roll back to G_MAXUINT */
1533 j--;
1534 }
1535 }
1536
1537 return FALSE;
1538 }
1539
1540 static GstCaps *
gst_caps_intersect_zig_zag(GstCaps * caps1,GstCaps * caps2)1541 gst_caps_intersect_zig_zag (GstCaps * caps1, GstCaps * caps2)
1542 {
1543 guint64 i; /* index can be up to 2 * G_MAX_UINT */
1544 guint j, k, len1, len2;
1545 GstStructure *struct1;
1546 GstStructure *struct2;
1547 GstCapsFeatures *features1;
1548 GstCapsFeatures *features2;
1549 GstCaps *dest;
1550 GstStructure *istruct;
1551
1552 /* caps are exactly the same pointers, just copy one caps */
1553 if (G_UNLIKELY (caps1 == caps2))
1554 return gst_caps_ref (caps1);
1555
1556 /* empty caps on either side, return empty */
1557 if (G_UNLIKELY (CAPS_IS_EMPTY (caps1) || CAPS_IS_EMPTY (caps2)))
1558 return gst_caps_ref (GST_CAPS_NONE);
1559
1560 /* one of the caps is any, just copy the other caps */
1561 if (G_UNLIKELY (CAPS_IS_ANY (caps1)))
1562 return gst_caps_ref (caps2);
1563
1564 if (G_UNLIKELY (CAPS_IS_ANY (caps2)))
1565 return gst_caps_ref (caps1);
1566
1567 dest = gst_caps_new_empty ();
1568 /* run zigzag on top line then right line, this preserves the caps order
1569 * much better than a simple loop.
1570 *
1571 * This algorithm zigzags over the caps structures as demonstrated in
1572 * the following matrix:
1573 *
1574 * caps1
1575 * +-------------
1576 * | 1 2 4 7
1577 * caps2 | 3 5 8 10
1578 * | 6 9 11 12
1579 *
1580 * First we iterate over the caps1 structures (top line) intersecting
1581 * the structures diagonally down, then we iterate over the caps2
1582 * structures.
1583 */
1584 len1 = GST_CAPS_LEN (caps1);
1585 len2 = GST_CAPS_LEN (caps2);
1586 for (i = 0; i < len1 + len2 - 1; i++) {
1587 /* caps1 index goes from 0 to GST_CAPS_LEN (caps1)-1 */
1588 j = MIN (i, len1 - 1);
1589 /* caps2 index stays 0 until i reaches GST_CAPS_LEN (caps1), then it counts
1590 * up from 1 to GST_CAPS_LEN (caps2) - 1 */
1591 k = (i > j) ? (i - j) : 0; /* MAX (0, i - j) */
1592 /* now run the diagonal line, end condition is the left or bottom
1593 * border */
1594 while (k < len2) {
1595 struct1 = gst_caps_get_structure_unchecked (caps1, j);
1596 features1 = gst_caps_get_features_unchecked (caps1, j);
1597 if (!features1)
1598 features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1599 struct2 = gst_caps_get_structure_unchecked (caps2, k);
1600 features2 = gst_caps_get_features_unchecked (caps2, k);
1601 if (!features2)
1602 features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1603 if (gst_caps_features_is_equal (features1, features2)) {
1604 istruct = gst_structure_intersect (struct1, struct2);
1605 if (istruct) {
1606 if (gst_caps_features_is_any (features1))
1607 dest =
1608 gst_caps_merge_structure_full (dest, istruct,
1609 gst_caps_features_copy_conditional (features2));
1610 else
1611 dest =
1612 gst_caps_merge_structure_full (dest, istruct,
1613 gst_caps_features_copy_conditional (features1));
1614 }
1615 }
1616 /* move down left */
1617 k++;
1618 if (G_UNLIKELY (j == 0))
1619 break; /* so we don't roll back to G_MAXUINT */
1620 j--;
1621 }
1622 }
1623 return dest;
1624 }
1625
1626 /**
1627 * gst_caps_intersect_first:
1628 * @caps1: a #GstCaps to intersect
1629 * @caps2: a #GstCaps to intersect
1630 *
1631 * Creates a new #GstCaps that contains all the formats that are common
1632 * to both @caps1 and @caps2.
1633 *
1634 * Unlike @gst_caps_intersect, the returned caps will be ordered in a similar
1635 * fashion as @caps1.
1636 *
1637 * Returns: (transfer full): the new #GstCaps
1638 */
1639 static GstCaps *
gst_caps_intersect_first(GstCaps * caps1,GstCaps * caps2)1640 gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2)
1641 {
1642 guint i;
1643 guint j, len1, len2;
1644 GstStructure *struct1;
1645 GstStructure *struct2;
1646 GstCapsFeatures *features1;
1647 GstCapsFeatures *features2;
1648 GstCaps *dest;
1649 GstStructure *istruct;
1650
1651 /* caps are exactly the same pointers, just copy one caps */
1652 if (G_UNLIKELY (caps1 == caps2))
1653 return gst_caps_ref (caps1);
1654
1655 /* empty caps on either side, return empty */
1656 if (G_UNLIKELY (CAPS_IS_EMPTY (caps1) || CAPS_IS_EMPTY (caps2)))
1657 return gst_caps_ref (GST_CAPS_NONE);
1658
1659 /* one of the caps is any, just copy the other caps */
1660 if (G_UNLIKELY (CAPS_IS_ANY (caps1)))
1661 return gst_caps_ref (caps2);
1662
1663 if (G_UNLIKELY (CAPS_IS_ANY (caps2)))
1664 return gst_caps_ref (caps1);
1665
1666 dest = gst_caps_new_empty ();
1667 len1 = GST_CAPS_LEN (caps1);
1668 len2 = GST_CAPS_LEN (caps2);
1669 for (i = 0; i < len1; i++) {
1670 struct1 = gst_caps_get_structure_unchecked (caps1, i);
1671 features1 = gst_caps_get_features_unchecked (caps1, i);
1672 if (!features1)
1673 features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1674 for (j = 0; j < len2; j++) {
1675 struct2 = gst_caps_get_structure_unchecked (caps2, j);
1676 features2 = gst_caps_get_features_unchecked (caps2, j);
1677 if (!features2)
1678 features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1679 if (gst_caps_features_is_equal (features1, features2)) {
1680 istruct = gst_structure_intersect (struct1, struct2);
1681 if (istruct) {
1682 if (gst_caps_features_is_any (features1))
1683 dest =
1684 gst_caps_merge_structure_full (dest, istruct,
1685 gst_caps_features_copy_conditional (features2));
1686 else
1687 dest =
1688 gst_caps_merge_structure_full (dest, istruct,
1689 gst_caps_features_copy_conditional (features1));
1690 }
1691 }
1692 }
1693 }
1694
1695 return dest;
1696 }
1697
1698 /**
1699 * gst_caps_intersect_full:
1700 * @caps1: a #GstCaps to intersect
1701 * @caps2: a #GstCaps to intersect
1702 * @mode: The intersection algorithm/mode to use
1703 *
1704 * Creates a new #GstCaps that contains all the formats that are common
1705 * to both @caps1 and @caps2, the order is defined by the #GstCapsIntersectMode
1706 * used.
1707 *
1708 * Returns: (transfer full): the new #GstCaps
1709 */
1710 GstCaps *
gst_caps_intersect_full(GstCaps * caps1,GstCaps * caps2,GstCapsIntersectMode mode)1711 gst_caps_intersect_full (GstCaps * caps1, GstCaps * caps2,
1712 GstCapsIntersectMode mode)
1713 {
1714 g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
1715 g_return_val_if_fail (GST_IS_CAPS (caps2), NULL);
1716
1717 switch (mode) {
1718 case GST_CAPS_INTERSECT_FIRST:
1719 return gst_caps_intersect_first (caps1, caps2);
1720 default:
1721 g_warning ("Unknown caps intersect mode: %d", mode);
1722 /* fallthrough */
1723 case GST_CAPS_INTERSECT_ZIG_ZAG:
1724 return gst_caps_intersect_zig_zag (caps1, caps2);
1725 }
1726 }
1727
1728 /**
1729 * gst_caps_intersect:
1730 * @caps1: a #GstCaps to intersect
1731 * @caps2: a #GstCaps to intersect
1732 *
1733 * Creates a new #GstCaps that contains all the formats that are common
1734 * to both @caps1 and @caps2. Defaults to %GST_CAPS_INTERSECT_ZIG_ZAG mode.
1735 *
1736 * Returns: (transfer full): the new #GstCaps
1737 */
1738 GstCaps *
gst_caps_intersect(GstCaps * caps1,GstCaps * caps2)1739 gst_caps_intersect (GstCaps * caps1, GstCaps * caps2)
1740 {
1741 return gst_caps_intersect_full (caps1, caps2, GST_CAPS_INTERSECT_ZIG_ZAG);
1742 }
1743
1744 /* subtract operation */
1745
1746 typedef struct
1747 {
1748 const GstStructure *subtract_from;
1749 GSList *put_into;
1750 } SubtractionEntry;
1751
1752 static gboolean
gst_caps_structure_subtract_field(GQuark field_id,const GValue * value,gpointer user_data)1753 gst_caps_structure_subtract_field (GQuark field_id, const GValue * value,
1754 gpointer user_data)
1755 {
1756 SubtractionEntry *e = user_data;
1757 GValue subtraction = { 0, };
1758 const GValue *other;
1759 GstStructure *structure;
1760
1761 other = gst_structure_id_get_value (e->subtract_from, field_id);
1762
1763 if (!other) {
1764 return FALSE;
1765 }
1766
1767 if (!gst_value_subtract (&subtraction, other, value))
1768 return TRUE;
1769
1770 if (gst_value_compare (&subtraction, other) == GST_VALUE_EQUAL) {
1771 g_value_unset (&subtraction);
1772 return FALSE;
1773 } else {
1774 structure = gst_structure_copy (e->subtract_from);
1775 gst_structure_id_take_value (structure, field_id, &subtraction);
1776 e->put_into = g_slist_prepend (e->put_into, structure);
1777 return TRUE;
1778 }
1779 }
1780
1781 static gboolean
gst_caps_structure_subtract(GSList ** into,const GstStructure * minuend,const GstStructure * subtrahend)1782 gst_caps_structure_subtract (GSList ** into, const GstStructure * minuend,
1783 const GstStructure * subtrahend)
1784 {
1785 SubtractionEntry e;
1786 gboolean ret;
1787
1788 e.subtract_from = minuend;
1789 e.put_into = NULL;
1790 ret = gst_structure_foreach ((GstStructure *) subtrahend,
1791 gst_caps_structure_subtract_field, &e);
1792
1793 if (ret) {
1794 *into = e.put_into;
1795 } else {
1796 GSList *walk;
1797
1798 for (walk = e.put_into; walk; walk = g_slist_next (walk)) {
1799 gst_structure_free (walk->data);
1800 }
1801 g_slist_free (e.put_into);
1802 }
1803
1804 return ret;
1805 }
1806
1807 /**
1808 * gst_caps_subtract:
1809 * @minuend: #GstCaps to subtract from
1810 * @subtrahend: #GstCaps to subtract
1811 *
1812 * Subtracts the @subtrahend from the @minuend.
1813 * > This function does not work reliably if optional properties for caps
1814 * > are included on one caps and omitted on the other.
1815 *
1816 * Returns: (transfer full): the resulting caps
1817 */
1818 GstCaps *
gst_caps_subtract(GstCaps * minuend,GstCaps * subtrahend)1819 gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend)
1820 {
1821 guint i, j, sublen;
1822 GstStructure *min;
1823 GstStructure *sub;
1824 GstCapsFeatures *min_f, *sub_f;
1825 GstCaps *dest = NULL, *src;
1826
1827 g_return_val_if_fail (minuend != NULL, NULL);
1828 g_return_val_if_fail (subtrahend != NULL, NULL);
1829
1830 if (CAPS_IS_EMPTY (minuend) || CAPS_IS_ANY (subtrahend)) {
1831 return gst_caps_new_empty ();
1832 }
1833
1834 if (CAPS_IS_EMPTY_SIMPLE (subtrahend))
1835 return gst_caps_ref (minuend);
1836
1837 /* FIXME: Do we want this here or above?
1838 The reason we need this is that there is no definition about what
1839 ANY means for specific types, so it's not possible to reduce ANY partially
1840 You can only remove everything or nothing and that is done above.
1841 Note: there's a test that checks this behaviour. */
1842
1843 g_return_val_if_fail (!CAPS_IS_ANY (minuend), NULL);
1844 sublen = GST_CAPS_LEN (subtrahend);
1845 g_assert (sublen > 0);
1846
1847 src = _gst_caps_copy (minuend);
1848 for (i = 0; i < sublen; i++) {
1849 guint srclen;
1850
1851 sub = gst_caps_get_structure_unchecked (subtrahend, i);
1852 sub_f = gst_caps_get_features_unchecked (subtrahend, i);
1853 if (!sub_f)
1854 sub_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1855 if (dest) {
1856 gst_caps_unref (src);
1857 src = dest;
1858 }
1859 dest = gst_caps_new_empty ();
1860 srclen = GST_CAPS_LEN (src);
1861 for (j = 0; j < srclen; j++) {
1862 min = gst_caps_get_structure_unchecked (src, j);
1863 min_f = gst_caps_get_features_unchecked (src, j);
1864 if (!min_f)
1865 min_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
1866
1867 /* Same reason as above for ANY caps */
1868 g_return_val_if_fail (!gst_caps_features_is_any (min_f), NULL);
1869
1870 if (gst_structure_get_name_id (min) == gst_structure_get_name_id (sub) &&
1871 gst_caps_features_is_equal (min_f, sub_f)) {
1872 GSList *list;
1873
1874 if (gst_caps_structure_subtract (&list, min, sub)) {
1875 GSList *walk;
1876
1877 for (walk = list; walk; walk = g_slist_next (walk)) {
1878 gst_caps_append_structure_unchecked (dest,
1879 (GstStructure *) walk->data,
1880 gst_caps_features_copy_conditional (min_f));
1881 }
1882 g_slist_free (list);
1883 } else {
1884 gst_caps_append_structure_unchecked (dest, gst_structure_copy (min),
1885 gst_caps_features_copy_conditional (min_f));
1886 }
1887 } else {
1888 gst_caps_append_structure_unchecked (dest, gst_structure_copy (min),
1889 gst_caps_features_copy_conditional (min_f));
1890 }
1891 }
1892
1893 if (CAPS_IS_EMPTY_SIMPLE (dest)) {
1894 gst_caps_unref (src);
1895 return dest;
1896 }
1897 }
1898
1899 gst_caps_unref (src);
1900 dest = gst_caps_simplify (dest);
1901
1902 return dest;
1903 }
1904
1905 /* normalize/simplify operations */
1906
1907 typedef struct _NormalizeForeach
1908 {
1909 GstCaps *caps;
1910 GstStructure *structure;
1911 GstCapsFeatures *features;
1912 } NormalizeForeach;
1913
1914 static gboolean
gst_caps_normalize_foreach(GQuark field_id,const GValue * value,gpointer ptr)1915 gst_caps_normalize_foreach (GQuark field_id, const GValue * value, gpointer ptr)
1916 {
1917 NormalizeForeach *nf = (NormalizeForeach *) ptr;
1918 GValue val = { 0 };
1919 guint i;
1920
1921 if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
1922 guint len = gst_value_list_get_size (value);
1923
1924 for (i = 1; i < len; i++) {
1925 const GValue *v = gst_value_list_get_value (value, i);
1926 GstStructure *structure = gst_structure_copy (nf->structure);
1927
1928 gst_structure_id_set_value (structure, field_id, v);
1929 gst_caps_append_structure_unchecked (nf->caps, structure,
1930 gst_caps_features_copy_conditional (nf->features));
1931 }
1932
1933 gst_value_init_and_copy (&val, gst_value_list_get_value (value, 0));
1934 gst_structure_id_take_value (nf->structure, field_id, &val);
1935 return FALSE;
1936 }
1937
1938 return TRUE;
1939 }
1940
1941 /**
1942 * gst_caps_normalize:
1943 * @caps: (transfer full): a #GstCaps to normalize
1944 *
1945 * Returns a #GstCaps that represents the same set of formats as
1946 * @caps, but contains no lists. Each list is expanded into separate
1947 * @GstStructures.
1948 *
1949 * This function takes ownership of @caps and will call gst_caps_make_writable()
1950 * on it so you must not use @caps afterwards unless you keep an additional
1951 * reference to it with gst_caps_ref().
1952 *
1953 * Returns: (transfer full): the normalized #GstCaps
1954 */
1955 GstCaps *
gst_caps_normalize(GstCaps * caps)1956 gst_caps_normalize (GstCaps * caps)
1957 {
1958 NormalizeForeach nf;
1959 guint i;
1960
1961 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
1962
1963 caps = gst_caps_make_writable (caps);
1964 nf.caps = caps;
1965
1966 for (i = 0; i < gst_caps_get_size (nf.caps); i++) {
1967 nf.structure = gst_caps_get_structure_unchecked (nf.caps, i);
1968 nf.features = gst_caps_get_features_unchecked (nf.caps, i);
1969 while (!gst_structure_foreach (nf.structure,
1970 gst_caps_normalize_foreach, &nf));
1971 }
1972
1973 return nf.caps;
1974 }
1975
1976 static gint
gst_caps_compare_structures(gconstpointer one,gconstpointer two)1977 gst_caps_compare_structures (gconstpointer one, gconstpointer two)
1978 {
1979 gint ret;
1980 const GstStructure *struct1 = ((const GstCapsArrayElement *) one)->structure;
1981 const GstStructure *struct2 = ((const GstCapsArrayElement *) two)->structure;
1982
1983 /* FIXME: this orders alphabetically, but ordering the quarks might be faster
1984 So what's the best way? */
1985 ret = strcmp (gst_structure_get_name (struct1),
1986 gst_structure_get_name (struct2));
1987
1988 if (ret)
1989 return ret;
1990
1991 return gst_structure_n_fields (struct2) - gst_structure_n_fields (struct1);
1992 }
1993
1994 typedef struct
1995 {
1996 GQuark name;
1997 GValue value;
1998 GstStructure *compare;
1999 } UnionField;
2000
2001 static gboolean
gst_caps_structure_figure_out_union(GQuark field_id,const GValue * value,gpointer user_data)2002 gst_caps_structure_figure_out_union (GQuark field_id, const GValue * value,
2003 gpointer user_data)
2004 {
2005 UnionField *u = user_data;
2006 const GValue *val = gst_structure_id_get_value (u->compare, field_id);
2007
2008 if (!val) {
2009 if (u->name)
2010 g_value_unset (&u->value);
2011 return FALSE;
2012 }
2013
2014 if (gst_value_compare (val, value) == GST_VALUE_EQUAL)
2015 return TRUE;
2016
2017 if (u->name) {
2018 g_value_unset (&u->value);
2019 return FALSE;
2020 }
2021
2022 u->name = field_id;
2023 gst_value_union (&u->value, val, value);
2024
2025 return TRUE;
2026 }
2027
2028 static gboolean
gst_caps_structure_simplify(GstStructure ** result,GstStructure * simplify,GstStructure * compare)2029 gst_caps_structure_simplify (GstStructure ** result,
2030 GstStructure * simplify, GstStructure * compare)
2031 {
2032 GSList *list;
2033 UnionField field = { 0, {0,}, NULL };
2034
2035 /* try to subtract to get a real subset */
2036 if (gst_caps_structure_subtract (&list, simplify, compare)) {
2037 if (list == NULL) { /* no result */
2038 *result = NULL;
2039 return TRUE;
2040 } else if (list->next == NULL) { /* one result */
2041 *result = list->data;
2042 g_slist_free (list);
2043 return TRUE;
2044 } else { /* multiple results */
2045 g_slist_foreach (list, (GFunc) gst_structure_free, NULL);
2046 g_slist_free (list);
2047 list = NULL;
2048 }
2049 }
2050
2051 /* try to union both structs */
2052 field.compare = compare;
2053 if (gst_structure_foreach (simplify,
2054 gst_caps_structure_figure_out_union, &field)) {
2055 gboolean ret = FALSE;
2056
2057 /* now we know all of simplify's fields are the same in compare
2058 * but at most one field: field.name */
2059 if (G_IS_VALUE (&field.value)) {
2060 if (gst_structure_n_fields (simplify) == gst_structure_n_fields (compare)) {
2061 gst_structure_id_take_value (compare, field.name, &field.value);
2062 *result = NULL;
2063 ret = TRUE;
2064 } else {
2065 g_value_unset (&field.value);
2066 }
2067 } else
2068 if (gst_structure_n_fields (simplify) <=
2069 gst_structure_n_fields (compare)) {
2070 /* compare is just more specific, will be optimized away later */
2071 /* FIXME: do this here? */
2072 GST_LOG ("found a case that will be optimized later.");
2073 } else {
2074 gchar *one = gst_structure_to_string (simplify);
2075 gchar *two = gst_structure_to_string (compare);
2076
2077 GST_ERROR
2078 ("caps mismatch: structures %s and %s claim to be possible to unify, but aren't",
2079 one, two);
2080 g_free (one);
2081 g_free (two);
2082 }
2083 return ret;
2084 }
2085
2086 return FALSE;
2087 }
2088
2089 static void
gst_caps_switch_structures(GstCaps * caps,GstStructure * old,GstStructure * new,gint i)2090 gst_caps_switch_structures (GstCaps * caps, GstStructure * old,
2091 GstStructure * new, gint i)
2092 {
2093 gst_structure_set_parent_refcount (old, NULL);
2094 gst_structure_free (old);
2095 gst_structure_set_parent_refcount (new, &GST_CAPS_REFCOUNT (caps));
2096 g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, i).structure = new;
2097 }
2098
2099 /**
2100 * gst_caps_simplify:
2101 * @caps: (transfer full): a #GstCaps to simplify
2102 *
2103 * Converts the given @caps into a representation that represents the
2104 * same set of formats, but in a simpler form. Component structures that are
2105 * identical are merged. Component structures that have values that can be
2106 * merged are also merged.
2107 *
2108 * This function takes ownership of @caps and will call gst_caps_make_writable()
2109 * on it if necessary, so you must not use @caps afterwards unless you keep an
2110 * additional reference to it with gst_caps_ref().
2111 *
2112 * This method does not preserve the original order of @caps.
2113 *
2114 * Returns: (transfer full): The simplified caps.
2115 */
2116 GstCaps *
gst_caps_simplify(GstCaps * caps)2117 gst_caps_simplify (GstCaps * caps)
2118 {
2119 GstStructure *simplify, *compare, *result = NULL;
2120 GstCapsFeatures *simplify_f, *compare_f;
2121 gint i, j, start;
2122
2123 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
2124
2125 start = GST_CAPS_LEN (caps) - 1;
2126 /* one caps, already as simple as can be */
2127 if (start == 0)
2128 return caps;
2129
2130 caps = gst_caps_make_writable (caps);
2131
2132 g_array_sort (GST_CAPS_ARRAY (caps), gst_caps_compare_structures);
2133
2134 for (i = start; i >= 0; i--) {
2135 simplify = gst_caps_get_structure_unchecked (caps, i);
2136 simplify_f = gst_caps_get_features_unchecked (caps, i);
2137 if (!simplify_f)
2138 simplify_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
2139 compare = gst_caps_get_structure_unchecked (caps, start);
2140 compare_f = gst_caps_get_features_unchecked (caps, start);
2141 if (!compare_f)
2142 compare_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
2143 if (gst_structure_get_name_id (simplify) !=
2144 gst_structure_get_name_id (compare) ||
2145 !gst_caps_features_is_equal (simplify_f, compare_f))
2146 start = i;
2147 for (j = start; j >= 0; j--) {
2148 if (j == i)
2149 continue;
2150 compare = gst_caps_get_structure_unchecked (caps, j);
2151 compare_f = gst_caps_get_features_unchecked (caps, j);
2152 if (!compare_f)
2153 compare_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
2154 if (gst_structure_get_name_id (simplify) !=
2155 gst_structure_get_name_id (compare) ||
2156 !gst_caps_features_is_equal (simplify_f, compare_f)) {
2157 break;
2158 }
2159 if (gst_caps_structure_simplify (&result, simplify, compare)) {
2160 if (result) {
2161 gst_caps_switch_structures (caps, simplify, result, i);
2162 simplify = result;
2163 } else {
2164 gst_caps_remove_structure (caps, i);
2165 start--;
2166 break;
2167 }
2168 }
2169 }
2170 }
2171 return caps;
2172 }
2173
2174 /**
2175 * gst_caps_fixate:
2176 * @caps: (transfer full): a #GstCaps to fixate
2177 *
2178 * Modifies the given @caps into a representation with only fixed
2179 * values. First the caps will be truncated and then the first structure will be
2180 * fixated with gst_structure_fixate().
2181 *
2182 * This function takes ownership of @caps and will call gst_caps_make_writable()
2183 * on it so you must not use @caps afterwards unless you keep an additional
2184 * reference to it with gst_caps_ref().
2185 *
2186 * Returns: (transfer full): the fixated caps
2187 */
2188 GstCaps *
gst_caps_fixate(GstCaps * caps)2189 gst_caps_fixate (GstCaps * caps)
2190 {
2191 GstStructure *s;
2192 GstCapsFeatures *f;
2193
2194 g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
2195
2196 /* default fixation */
2197 caps = gst_caps_truncate (caps);
2198 caps = gst_caps_make_writable (caps);
2199 s = gst_caps_get_structure (caps, 0);
2200 gst_structure_fixate (s);
2201
2202 /* Set features to sysmem if they're still ANY */
2203 f = gst_caps_get_features_unchecked (caps, 0);
2204 if (f && gst_caps_features_is_any (f)) {
2205 f = gst_caps_features_new_empty ();
2206 gst_caps_set_features (caps, 0, f);
2207 }
2208
2209 return caps;
2210 }
2211
2212 /* utility */
2213
2214 /**
2215 * gst_caps_to_string:
2216 * @caps: a #GstCaps
2217 *
2218 * Converts @caps to a string representation. This string representation
2219 * can be converted back to a #GstCaps by gst_caps_from_string().
2220 *
2221 * For debugging purposes its easier to do something like this:
2222 * |[<!-- language="C" -->
2223 * GST_LOG ("caps are %" GST_PTR_FORMAT, caps);
2224 * ]|
2225 * This prints the caps in human readable form.
2226 *
2227 * The current implementation of serialization will lead to unexpected results
2228 * when there are nested #GstCaps / #GstStructure deeper than one level.
2229 *
2230 * Returns: (transfer full): a newly allocated string representing @caps.
2231 */
2232 gchar *
gst_caps_to_string(const GstCaps * caps)2233 gst_caps_to_string (const GstCaps * caps)
2234 {
2235 guint i, slen, clen;
2236 GString *s;
2237
2238 /* NOTE: This function is potentially called by the debug system,
2239 * so any calls to gst_log() (and GST_DEBUG(), GST_LOG(), etc.)
2240 * should be careful to avoid recursion. This includes any functions
2241 * called by gst_caps_to_string. In particular, calls should
2242 * not use the GST_PTR_FORMAT extension. */
2243
2244 if (caps == NULL) {
2245 return g_strdup ("NULL");
2246 }
2247 if (CAPS_IS_ANY (caps)) {
2248 return g_strdup ("ANY");
2249 }
2250 if (CAPS_IS_EMPTY_SIMPLE (caps)) {
2251 return g_strdup ("EMPTY");
2252 }
2253
2254 /* estimate a rough string length to avoid unnecessary reallocs in GString */
2255 slen = 0;
2256 clen = GST_CAPS_LEN (caps);
2257 for (i = 0; i < clen; i++) {
2258 GstCapsFeatures *f;
2259
2260 slen +=
2261 STRUCTURE_ESTIMATED_STRING_LEN (gst_caps_get_structure_unchecked
2262 (caps, i));
2263 f = gst_caps_get_features_unchecked (caps, i);
2264 if (f)
2265 slen += FEATURES_ESTIMATED_STRING_LEN (f);
2266 }
2267
2268 s = g_string_sized_new (slen);
2269 for (i = 0; i < clen; i++) {
2270 GstStructure *structure;
2271 GstCapsFeatures *features;
2272
2273 if (i > 0) {
2274 /* ';' is now added by gst_structure_to_string */
2275 g_string_append_c (s, ' ');
2276 }
2277
2278 structure = gst_caps_get_structure_unchecked (caps, i);
2279 features = gst_caps_get_features_unchecked (caps, i);
2280
2281 g_string_append (s, gst_structure_get_name (structure));
2282 if (features && (gst_caps_features_is_any (features)
2283 || !gst_caps_features_is_equal (features,
2284 GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))) {
2285 g_string_append_c (s, '(');
2286 priv_gst_caps_features_append_to_gstring (features, s);
2287 g_string_append_c (s, ')');
2288 }
2289 priv_gst_structure_append_to_gstring (structure, s);
2290 }
2291 if (s->len && s->str[s->len - 1] == ';') {
2292 /* remove latest ';' */
2293 s->str[--s->len] = '\0';
2294 }
2295 return g_string_free (s, FALSE);
2296 }
2297
2298 static gboolean
gst_caps_from_string_inplace(GstCaps * caps,const gchar * string)2299 gst_caps_from_string_inplace (GstCaps * caps, const gchar * string)
2300 {
2301 GstStructure *structure;
2302 gchar *s, *copy, *end, *next, save;
2303
2304 if (strcmp ("ANY", string) == 0) {
2305 GST_CAPS_FLAGS (caps) = GST_CAPS_FLAG_ANY;
2306 return TRUE;
2307 }
2308
2309 if (strcmp ("EMPTY", string) == 0 || strcmp ("NONE", string) == 0) {
2310 return TRUE;
2311 }
2312
2313 copy = s = g_strdup (string);
2314 do {
2315 GstCapsFeatures *features = NULL;
2316
2317 while (g_ascii_isspace (*s))
2318 s++;
2319 if (*s == '\0') {
2320 break;
2321 }
2322
2323 if (!priv_gst_structure_parse_name (s, &s, &end, &next)) {
2324 g_free (copy);
2325 return FALSE;
2326 }
2327
2328 save = *end;
2329 *end = '\0';
2330 structure = gst_structure_new_empty (s);
2331 *end = save;
2332
2333 if (structure == NULL) {
2334 g_free (copy);
2335 return FALSE;
2336 }
2337
2338 s = next;
2339
2340 if (*s == '\0') {
2341 goto append;
2342 }
2343
2344 if (*s == '(') {
2345 s++;
2346 end = s;
2347
2348 while (TRUE) {
2349 if (*end == '\0') {
2350 break;
2351 } else if (*end == ')') {
2352 break;
2353 } else {
2354 end++;
2355 }
2356 }
2357
2358 save = *end;
2359 *end = '\0';
2360 features = gst_caps_features_from_string (s);
2361 if (!features) {
2362 gst_structure_free (structure);
2363 g_free (copy);
2364 return FALSE;
2365 }
2366 *end = save;
2367 s = end;
2368 if (save == ')')
2369 s++;
2370 }
2371
2372 if (*s == '\0') {
2373 goto append;
2374 }
2375
2376 if (!priv_gst_structure_parse_fields (s, &s, structure)) {
2377 gst_structure_free (structure);
2378 if (features)
2379 gst_caps_features_free (features);
2380 g_free (copy);
2381 return FALSE;
2382 }
2383
2384 append:
2385 gst_caps_append_structure_unchecked (caps, structure, features);
2386 features = NULL;
2387 if (*s == '\0')
2388 break;
2389 } while (TRUE);
2390
2391 g_free (copy);
2392
2393 return TRUE;
2394 }
2395
2396 /**
2397 * gst_caps_from_string:
2398 * @string: a string to convert to #GstCaps
2399 *
2400 * Converts @caps from a string representation.
2401 *
2402 * The current implementation of serialization will lead to unexpected results
2403 * when there are nested #GstCaps / #GstStructure deeper than one level.
2404 *
2405 * Returns: (transfer full) (nullable): a newly allocated #GstCaps
2406 */
2407 GstCaps *
gst_caps_from_string(const gchar * string)2408 gst_caps_from_string (const gchar * string)
2409 {
2410 GstCaps *caps;
2411
2412 g_return_val_if_fail (string, FALSE);
2413
2414 caps = gst_caps_new_empty ();
2415 if (gst_caps_from_string_inplace (caps, string)) {
2416 return caps;
2417 } else {
2418 gst_caps_unref (caps);
2419 return NULL;
2420 }
2421 }
2422
2423 static void
gst_caps_transform_to_string(const GValue * src_value,GValue * dest_value)2424 gst_caps_transform_to_string (const GValue * src_value, GValue * dest_value)
2425 {
2426 g_return_if_fail (G_IS_VALUE (src_value));
2427 g_return_if_fail (G_IS_VALUE (dest_value));
2428 g_return_if_fail (G_VALUE_HOLDS (src_value, GST_TYPE_CAPS));
2429 g_return_if_fail (G_VALUE_HOLDS (dest_value, G_TYPE_STRING)
2430 || G_VALUE_HOLDS (dest_value, G_TYPE_POINTER));
2431
2432 g_value_take_string (dest_value,
2433 gst_caps_to_string (gst_value_get_caps (src_value)));
2434 }
2435
2436 /**
2437 * gst_caps_foreach:
2438 * @caps: a #GstCaps
2439 * @func: (scope call): a function to call for each field
2440 * @user_data: (closure): private data
2441 *
2442 * Calls the provided function once for each structure and caps feature in the
2443 * #GstCaps. The function must not modify the fields.
2444 * Also see gst_caps_map_in_place() and gst_caps_filter_and_map_in_place().
2445 *
2446 * Returns: %TRUE if the supplied function returns %TRUE for each call,
2447 * %FALSE otherwise.
2448 *
2449 * Since: 1.6
2450 */
2451 gboolean
gst_caps_foreach(const GstCaps * caps,GstCapsForeachFunc func,gpointer user_data)2452 gst_caps_foreach (const GstCaps * caps, GstCapsForeachFunc func,
2453 gpointer user_data)
2454 {
2455 guint i, n;
2456 GstCapsFeatures *features;
2457 GstStructure *structure;
2458 gboolean ret;
2459
2460 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
2461 g_return_val_if_fail (func != NULL, FALSE);
2462
2463 n = GST_CAPS_LEN (caps);
2464
2465 for (i = 0; i < n; i++) {
2466 features = gst_caps_get_features_unchecked (caps, i);
2467 structure = gst_caps_get_structure_unchecked (caps, i);
2468
2469 ret = func (features, structure, user_data);
2470 if (G_UNLIKELY (!ret))
2471 return FALSE;
2472 }
2473
2474 return TRUE;
2475 }
2476
2477 /**
2478 * gst_caps_map_in_place:
2479 * @caps: a #GstCaps
2480 * @func: (scope call): a function to call for each field
2481 * @user_data: (closure): private data
2482 *
2483 * Calls the provided function once for each structure and caps feature in the
2484 * #GstCaps. In contrast to gst_caps_foreach(), the function may modify but not
2485 * delete the structures and features. The caps must be mutable.
2486 *
2487 * Returns: %TRUE if the supplied function returns %TRUE for each call,
2488 * %FALSE otherwise.
2489 *
2490 * Since: 1.6
2491 */
2492 gboolean
gst_caps_map_in_place(GstCaps * caps,GstCapsMapFunc func,gpointer user_data)2493 gst_caps_map_in_place (GstCaps * caps, GstCapsMapFunc func, gpointer user_data)
2494 {
2495 guint i, n;
2496 GstCapsFeatures *features;
2497 GstStructure *structure;
2498 gboolean ret;
2499
2500 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
2501 g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
2502 g_return_val_if_fail (func != NULL, FALSE);
2503
2504 n = GST_CAPS_LEN (caps);
2505
2506 for (i = 0; i < n; i++) {
2507 features = gst_caps_get_features_unchecked (caps, i);
2508 structure = gst_caps_get_structure_unchecked (caps, i);
2509
2510 /* Provide sysmem features if there are none yet */
2511 if (!features) {
2512 features =
2513 gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY);
2514 gst_caps_set_features (caps, i, features);
2515 }
2516
2517 ret = func (features, structure, user_data);
2518 if (G_UNLIKELY (!ret))
2519 return FALSE;
2520 }
2521
2522 return TRUE;
2523 }
2524
2525 /**
2526 * gst_caps_filter_and_map_in_place:
2527 * @caps: a #GstCaps
2528 * @func: (scope call): a function to call for each field
2529 * @user_data: (closure): private data
2530 *
2531 * Calls the provided function once for each structure and caps feature in the
2532 * #GstCaps. In contrast to gst_caps_foreach(), the function may modify the
2533 * structure and features. In contrast to gst_caps_filter_and_map_in_place(),
2534 * the structure and features are removed from the caps if %FALSE is returned
2535 * from the function.
2536 * The caps must be mutable.
2537 *
2538 * Since: 1.6
2539 */
2540 void
gst_caps_filter_and_map_in_place(GstCaps * caps,GstCapsFilterMapFunc func,gpointer user_data)2541 gst_caps_filter_and_map_in_place (GstCaps * caps, GstCapsFilterMapFunc func,
2542 gpointer user_data)
2543 {
2544 guint i, n;
2545 GstCapsFeatures *features;
2546 GstStructure *structure;
2547 gboolean ret;
2548
2549 g_return_if_fail (GST_IS_CAPS (caps));
2550 g_return_if_fail (gst_caps_is_writable (caps));
2551 g_return_if_fail (func != NULL);
2552
2553 n = GST_CAPS_LEN (caps);
2554
2555 for (i = 0; i < n;) {
2556 features = gst_caps_get_features_unchecked (caps, i);
2557 structure = gst_caps_get_structure_unchecked (caps, i);
2558
2559 /* Provide sysmem features if there are none yet */
2560 if (!features) {
2561 features =
2562 gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY);
2563 gst_caps_set_features (caps, i, features);
2564 }
2565
2566 ret = func (features, structure, user_data);
2567 if (!ret) {
2568 GST_CAPS_ARRAY (caps) = g_array_remove_index (GST_CAPS_ARRAY (caps), i);
2569
2570 gst_structure_set_parent_refcount (structure, NULL);
2571 gst_structure_free (structure);
2572 if (features) {
2573 gst_caps_features_set_parent_refcount (features, NULL);
2574 gst_caps_features_free (features);
2575 }
2576
2577 n = GST_CAPS_LEN (caps);
2578 } else {
2579 i++;
2580 }
2581 }
2582 }
2583
2584 /**
2585 * gst_caps_copy:
2586 * @caps: a #GstCaps.
2587 *
2588 * Creates a new #GstCaps as a copy of the old @caps. The new caps will have a
2589 * refcount of 1, owned by the caller. The structures are copied as well.
2590 *
2591 * Note that this function is the semantic equivalent of a gst_caps_ref()
2592 * followed by a gst_caps_make_writable(). If you only want to hold on to a
2593 * reference to the data, you should use gst_caps_ref().
2594 *
2595 * When you are finished with the caps, call gst_caps_unref() on it.
2596 *
2597 * Returns: the new #GstCaps
2598 */
2599 GstCaps *(gst_caps_copy) (const GstCaps * caps)
2600 {
2601 return GST_CAPS (gst_mini_object_copy (GST_MINI_OBJECT_CAST (caps)));
2602 }
2603