gstcaps.c 63.4 KB
Newer Older
David Schleef's avatar
David Schleef committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* GStreamer
 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
16
17
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
David Schleef's avatar
David Schleef committed
18
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
19

20
21
22
/**
 * SECTION:gstcaps
 * @short_description: Structure describing sets of media formats
Wim Taymans's avatar
Wim Taymans committed
23
 * @see_also: #GstStructure, #GstMiniObject
24
 *
Wim Taymans's avatar
Wim Taymans committed
25
 * Caps (capabilities) are lightweight refcounted objects describing media types.
26
27
28
 * They are composed of an array of #GstStructure.
 *
 * Caps are exposed on #GstPadTemplate to describe all possible types a
29
30
 * given pad can handle. They are also stored in the #GstRegistry along with
 * a description of the #GstElement.
31
 *
Wim Taymans's avatar
Wim Taymans committed
32
 * Caps are exposed on the element pads using the gst_pad_query_caps() pad
33
 * function. This function describes the possible types that the pad can
Stefan Kost's avatar
Stefan Kost committed
34
 * handle or produce at runtime.
35
36
37
38
39
40
41
 *
 * A #GstCaps can be constructed with the following code fragment:
 *
 * <example>
 *  <title>Creating caps</title>
 *  <programlisting>
 *  GstCaps *caps;
Wim Taymans's avatar
Wim Taymans committed
42
 *  caps = gst_caps_new_simple ("video/x-raw",
43
 *       "format", G_TYPE_STRING, "I420",
44
 *       "framerate", GST_TYPE_FRACTION, 25, 1,
45
 *       "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
46
47
 *       "width", G_TYPE_INT, 320,
 *       "height", G_TYPE_INT, 240,
48
49
50
51
52
 *       NULL);
 *  </programlisting>
 * </example>
 *
 * A #GstCaps is fixed when it has no properties with ranges or lists. Use
Wim Taymans's avatar
Wim Taymans committed
53
54
 * gst_caps_is_fixed() to test for fixed caps. Fixed caps can be used in a
 * caps event to notify downstream elements of the current media type.
55
 *
Stefan Kost's avatar
Stefan Kost committed
56
 * Various methods exist to work with the media types such as subtracting
57
58
 * or intersecting.
 *
Wim Taymans's avatar
Wim Taymans committed
59
 * Last reviewed on 2011-03-28 (0.11.3)
60
 */
David Schleef's avatar
David Schleef committed
61
62
63
64
65

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
66
#include <signal.h>
David Schleef's avatar
David Schleef committed
67

68
#include "gst_private.h"
69
#include <gst/gst.h>
Benjamin Otte's avatar
Benjamin Otte committed
70
#include <gobject/gvaluecollector.h>
71

72
#define DEBUG_REFCOUNT
73

74
75
76
77
78
79
typedef struct _GstCapsArrayElement
{
  GstStructure *structure;
  GstCapsFeatures *features;
} GstCapsArrayElement;

80
81
82
83
typedef struct _GstCapsImpl
{
  GstCaps caps;

84
  GArray *array;
85
} GstCapsImpl;
86

87
#define GST_CAPS_ARRAY(c) (((GstCapsImpl *)(c))->array)
88
89
90

#define GST_CAPS_LEN(c)   (GST_CAPS_ARRAY(c)->len)

91
#define IS_WRITABLE(caps) \
92
  (GST_CAPS_REFCOUNT_VALUE (caps) == 1)
93

94
95
/* same as gst_caps_is_any () */
#define CAPS_IS_ANY(caps)				\
96
  (!!(GST_CAPS_FLAGS(caps) & GST_CAPS_FLAG_ANY))
97
98
99
100
101
102

/* same as gst_caps_is_empty () */
#define CAPS_IS_EMPTY(caps)				\
  (!CAPS_IS_ANY(caps) && CAPS_IS_EMPTY_SIMPLE(caps))

#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
108
109
/* quick way to get a caps structure at an index without doing a type or array
 * length check */
#define gst_caps_get_structure_unchecked(caps, index) \
110
111
112
     (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).structure)
#define gst_caps_get_features_unchecked(caps, index) \
     (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).features)
113
/* quick way to append a structure without checking the args */
114
115
116
117
118
#define gst_caps_append_structure_unchecked(caps, s, f) G_STMT_START{\
  GstCapsArrayElement __e={s, f};                                      \
  if (gst_structure_set_parent_refcount (__e.structure, &GST_MINI_OBJECT_REFCOUNT(caps)) && \
      (!__e.features || gst_caps_features_set_parent_refcount (__e.features, &GST_MINI_OBJECT_REFCOUNT(caps))))         \
    g_array_append_val (GST_CAPS_ARRAY (caps), __e);                             \
119
}G_STMT_END
120

121
122
123
/* lock to protect multiple invocations of static caps to caps conversion */
G_LOCK_DEFINE_STATIC (static_caps_lock);

124
125
126
127
static void gst_caps_transform_to_string (const GValue * src_value,
    GValue * dest_value);
static gboolean gst_caps_from_string_inplace (GstCaps * caps,
    const gchar * string);
128

Wim Taymans's avatar
Wim Taymans committed
129
GType _gst_caps_type = 0;
130
GstCaps *_gst_caps_any;
131
GstCaps *_gst_caps_none;
Wim Taymans's avatar
Wim Taymans committed
132

133
GST_DEFINE_MINI_OBJECT_TYPE (GstCaps, gst_caps);
Wim Taymans's avatar
Wim Taymans committed
134

Wim Taymans's avatar
Wim Taymans committed
135
void
136
_priv_gst_caps_initialize (void)
David Schleef's avatar
David Schleef committed
137
{
Wim Taymans's avatar
Wim Taymans committed
138
  _gst_caps_type = gst_caps_get_type ();
139

140
  _gst_caps_any = gst_caps_new_any ();
141
  _gst_caps_none = gst_caps_new_empty ();
142

Wim Taymans's avatar
Wim Taymans committed
143
144
  g_value_register_transform_func (_gst_caps_type,
      G_TYPE_STRING, gst_caps_transform_to_string);
David Schleef's avatar
David Schleef committed
145
146
}

147
148
149
150
151
static GstCaps *
_gst_caps_copy (const GstCaps * caps)
{
  GstCaps *newcaps;
  GstStructure *structure;
152
  GstCapsFeatures *features;
153
154
155
156
157
158
  guint i, n;

  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);

  newcaps = gst_caps_new_empty ();
  GST_CAPS_FLAGS (newcaps) = GST_CAPS_FLAGS (caps);
159
  n = GST_CAPS_LEN (caps);
160
161
162

  GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, caps, "doing copy %p -> %p",
      caps, newcaps);
163
164
165

  for (i = 0; i < n; i++) {
    structure = gst_caps_get_structure_unchecked (caps, i);
166
167
168
    features = gst_caps_get_features_unchecked (caps, i);
    gst_caps_append_structure_full (newcaps, gst_structure_copy (structure),
        gst_caps_features_copy_conditional (features));
169
170
171
172
173
  }

  return newcaps;
}

David Schleef's avatar
David Schleef committed
174
/* creation/deletion */
175
176
177
178
static void
_gst_caps_free (GstCaps * caps)
{
  GstStructure *structure;
179
  GstCapsFeatures *features;
180
181
182
183
  guint i, len;

  /* The refcount must be 0, but since we're only called by gst_caps_unref,
   * don't bother testing. */
184
  len = GST_CAPS_LEN (caps);
185
186
187
  /* This can be used to get statistics about caps sizes */
  /*GST_CAT_INFO (GST_CAT_CAPS, "caps size: %d", len); */
  for (i = 0; i < len; i++) {
188
    structure = gst_caps_get_structure_unchecked (caps, i);
189
190
    gst_structure_set_parent_refcount (structure, NULL);
    gst_structure_free (structure);
191
192
193
194
195
    features = gst_caps_get_features_unchecked (caps, i);
    if (features) {
      gst_caps_features_set_parent_refcount (features, NULL);
      gst_caps_features_free (features);
    }
196
  }
197
  g_array_free (GST_CAPS_ARRAY (caps), TRUE);
198
199

#ifdef DEBUG_REFCOUNT
200
  GST_CAT_TRACE (GST_CAT_CAPS, "freeing caps %p", caps);
201
#endif
202
  g_slice_free1 (sizeof (GstCapsImpl), caps);
203
}
204

Wim Taymans's avatar
Wim Taymans committed
205
static void
206
gst_caps_init (GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
207
{
208
  gst_mini_object_init (GST_MINI_OBJECT_CAST (caps), 0, _gst_caps_type,
209
210
      (GstMiniObjectCopyFunction) _gst_caps_copy, NULL,
      (GstMiniObjectFreeFunction) _gst_caps_free);
Wim Taymans's avatar
Wim Taymans committed
211
212
213

  /* the 32 has been determined by logging caps sizes in _gst_caps_free
   * but g_ptr_array uses 16 anyway if it expands once, so this does not help
Fabrizio (Misto) Milo's avatar
Fabrizio (Misto) Milo committed
214
   * in practice
215
   * GST_CAPS_ARRAY (caps) = g_ptr_array_sized_new (32);
Wim Taymans's avatar
Wim Taymans committed
216
   */
217
218
  GST_CAPS_ARRAY (caps) =
      g_array_new (FALSE, TRUE, sizeof (GstCapsArrayElement));
Wim Taymans's avatar
Wim Taymans committed
219
220
}

221
222
223
224
225
/**
 * gst_caps_new_empty:
 *
 * Creates a new #GstCaps that is empty.  That is, the returned
 * #GstCaps contains no media formats.
226
 * The #GstCaps is guaranteed to be writable.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
227
 * Caller is responsible for unreffing the returned caps.
228
 *
229
 * Returns: (transfer full): the new #GstCaps
230
 */
231
232
GstCaps *
gst_caps_new_empty (void)
David Schleef's avatar
David Schleef committed
233
{
234
235
  GstCaps *caps;

Sebastian Dröge's avatar
Sebastian Dröge committed
236
  caps = (GstCaps *) g_slice_new (GstCapsImpl);
David Schleef's avatar
David Schleef committed
237

238
  gst_caps_init (caps);
David Schleef's avatar
David Schleef committed
239

240
#ifdef DEBUG_REFCOUNT
241
  GST_CAT_TRACE (GST_CAT_CAPS, "created caps %p", caps);
242
243
#endif

David Schleef's avatar
David Schleef committed
244
245
246
  return caps;
}

247
/**
248
 * gst_caps_new_any:
249
250
251
252
 *
 * Creates a new #GstCaps that indicates that it is compatible with
 * any media format.
 *
253
 * Returns: (transfer full): the new #GstCaps
254
 */
255
256
GstCaps *
gst_caps_new_any (void)
David Schleef's avatar
David Schleef committed
257
{
258
  GstCaps *caps = gst_caps_new_empty ();
David Schleef's avatar
David Schleef committed
259

Wim Taymans's avatar
Wim Taymans committed
260
  GST_CAPS_FLAG_SET (caps, GST_CAPS_FLAG_ANY);
David Schleef's avatar
David Schleef committed
261
262
263
264

  return caps;
}

Wim Taymans's avatar
Wim Taymans committed
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/**
 * gst_caps_new_empty_simple:
 * @media_type: the media type of the structure
 *
 * Creates a new #GstCaps that contains one #GstStructure with name
 * @media_type.
 * Caller is responsible for unreffing the returned caps.
 *
 * Returns: (transfer full): the new #GstCaps
 */
GstCaps *
gst_caps_new_empty_simple (const char *media_type)
{
  GstCaps *caps;
  GstStructure *structure;

  caps = gst_caps_new_empty ();
Wim Taymans's avatar
Wim Taymans committed
282
  structure = gst_structure_new_empty (media_type);
Wim Taymans's avatar
Wim Taymans committed
283
  if (structure)
284
    gst_caps_append_structure_unchecked (caps, structure, NULL);
Wim Taymans's avatar
Wim Taymans committed
285
286
287
288

  return caps;
}

289
290
291
/**
 * gst_caps_new_simple:
 * @media_type: the media type of the structure
292
 * @fieldname: first field to set
293
294
295
296
 * @...: additional arguments
 *
 * Creates a new #GstCaps that contains one #GstStructure.  The
 * structure is defined by the arguments, which have the same format
297
 * as gst_structure_new().
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
298
 * Caller is responsible for unreffing the returned caps.
299
 *
300
 * Returns: (transfer full): the new #GstCaps
301
 */
302
GstCaps *
303
gst_caps_new_simple (const char *media_type, const char *fieldname, ...)
David Schleef's avatar
David Schleef committed
304
{
David Schleef's avatar
David Schleef committed
305
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
306
307
308
  GstStructure *structure;
  va_list var_args;

309
  caps = gst_caps_new_empty ();
David Schleef's avatar
David Schleef committed
310
311
312
313
314

  va_start (var_args, fieldname);
  structure = gst_structure_new_valist (media_type, fieldname, var_args);
  va_end (var_args);

315
  if (structure)
316
    gst_caps_append_structure_unchecked (caps, structure, NULL);
317
318
  else
    gst_caps_replace (&caps, NULL);
319

David Schleef's avatar
David Schleef committed
320
321
322
  return caps;
}

323
324
325
326
327
328
329
330
331
/**
 * gst_caps_new_full:
 * @struct1: the first structure to add
 * @...: additional structures to add
 *
 * Creates a new #GstCaps and adds all the structures listed as
 * arguments.  The list must be NULL-terminated.  The structures
 * are not copied; the returned #GstCaps owns the structures.
 *
332
 * Returns: (transfer full): the new #GstCaps
333
 */
334
GstCaps *
335
gst_caps_new_full (GstStructure * struct1, ...)
David Schleef's avatar
David Schleef committed
336
{
David Schleef's avatar
David Schleef committed
337
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
338
339
340
  va_list var_args;

  va_start (var_args, struct1);
David Schleef's avatar
David Schleef committed
341
  caps = gst_caps_new_full_valist (struct1, var_args);
David Schleef's avatar
David Schleef committed
342
343
344
345
346
  va_end (var_args);

  return caps;
}

347
348
/**
 * gst_caps_new_full_valist:
349
 * @structure: the first structure to add
350
351
352
353
354
355
 * @var_args: additional structures to add
 *
 * Creates a new #GstCaps and adds all the structures listed as
 * arguments.  The list must be NULL-terminated.  The structures
 * are not copied; the returned #GstCaps owns the structures.
 *
356
 * Returns: (transfer full): the new #GstCaps
357
 */
358
GstCaps *
359
gst_caps_new_full_valist (GstStructure * structure, va_list var_args)
David Schleef's avatar
David Schleef committed
360
{
David Schleef's avatar
David Schleef committed
361
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
362

363
  caps = gst_caps_new_empty ();
David Schleef's avatar
David Schleef committed
364

365
  while (structure) {
366
    gst_caps_append_structure_unchecked (caps, structure, NULL);
David Schleef's avatar
David Schleef committed
367
    structure = va_arg (var_args, GstStructure *);
David Schleef's avatar
David Schleef committed
368
369
370
371
372
  }

  return caps;
}

373
G_DEFINE_POINTER_TYPE (GstStaticCaps, gst_static_caps);
374

375
376
377
378
379
380
/**
 * gst_static_caps_get:
 * @static_caps: the #GstStaticCaps to convert
 *
 * Converts a #GstStaticCaps to a #GstCaps.
 *
381
382
383
 * Returns: (transfer full): a pointer to the #GstCaps. Unref after usage.
 *     Since the core holds an additional ref to the returned caps,
 *     use gst_caps_make_writable() on the returned caps to modify it.
384
 */
385
GstCaps *
386
gst_static_caps_get (GstStaticCaps * static_caps)
David Schleef's avatar
David Schleef committed
387
{
388
  GstCaps **caps;
389
390
391

  g_return_val_if_fail (static_caps != NULL, NULL);

392
  caps = &static_caps->caps;
David Schleef's avatar
David Schleef committed
393

394
  /* refcount is 0 when we need to convert */
395
  if (G_UNLIKELY (*caps == NULL)) {
396
397
398
399
    const char *string;

    G_LOCK (static_caps_lock);
    /* check if other thread already updated */
400
    if (G_UNLIKELY (*caps != NULL))
401
402
403
404
405
      goto done;

    string = static_caps->string;

    if (G_UNLIKELY (string == NULL))
406
      goto no_string;
407

408
    *caps = gst_caps_from_string (string);
David Schleef's avatar
David Schleef committed
409

410
    /* convert to string */
411
    if (G_UNLIKELY (*caps == NULL))
412
413
      g_critical ("Could not convert static caps \"%s\"", string);

Wim Taymans's avatar
Wim Taymans committed
414
415
    GST_CAT_TRACE (GST_CAT_CAPS, "created %p from string %s", static_caps,
        string);
416
417
  done:
    G_UNLOCK (static_caps_lock);
David Schleef's avatar
David Schleef committed
418
  }
419
  /* ref the caps, makes it not writable */
420
421
  if (G_LIKELY (*caps != NULL))
    gst_caps_ref (*caps);
David Schleef's avatar
David Schleef committed
422

423
  return *caps;
424
425
426
427

  /* ERRORS */
no_string:
  {
428
429
    G_UNLOCK (static_caps_lock);
    g_warning ("static caps %p string is NULL", static_caps);
430
431
    return NULL;
  }
David Schleef's avatar
David Schleef committed
432
433
}

434
435
/**
 * gst_static_caps_cleanup:
436
 * @static_caps: the #GstStaticCaps to clean
437
 *
438
 * Clean up the cached caps contained in @static_caps.
439
440
441
442
 */
void
gst_static_caps_cleanup (GstStaticCaps * static_caps)
{
443
444
445
  G_LOCK (static_caps_lock);
  gst_caps_replace (&static_caps->caps, NULL);
  G_UNLOCK (static_caps_lock);
446
447
}

David Schleef's avatar
David Schleef committed
448
/* manipulation */
449

450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
static void
gst_caps_remove_and_get_structure_and_features (GstCaps * caps, guint idx,
    GstStructure ** s, GstCapsFeatures ** f)
{
  GstStructure *s_;
  GstCapsFeatures *f_;

  s_ = gst_caps_get_structure_unchecked (caps, idx);
  f_ = gst_caps_get_features_unchecked (caps, idx);

  /* don't use index_fast, gst_caps_simplify relies on the order */
  g_array_remove_index (GST_CAPS_ARRAY (caps), idx);

  gst_structure_set_parent_refcount (s_, NULL);
  if (f_) {
    gst_caps_features_set_parent_refcount (f_, NULL);
  }

  *s = s_;
  *f = f_;
}

472
473
474
static GstStructure *
gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
{
475
476
477
478
479
480
481
  GstStructure *s;
  GstCapsFeatures *f;

  gst_caps_remove_and_get_structure_and_features (caps, idx, &s, &f);

  if (f)
    gst_caps_features_free (f);
482
483
484
485

  return s;
}

486
487


488
489
490
/**
 * gst_caps_steal_structure:
 * @caps: the #GstCaps to retrieve from
491
 * @index: Index of the structure to retrieve
492
 *
Fabrizio (Misto) Milo's avatar
Fabrizio (Misto) Milo committed
493
 * Retrieves the structure with the given index from the list of structures
494
495
 * contained in @caps. The caller becomes the owner of the returned structure.
 *
496
497
 * Returns: (transfer full): a pointer to the #GstStructure corresponding
 *     to @index.
498
499
 */
GstStructure *
500
gst_caps_steal_structure (GstCaps * caps, guint index)
501
502
503
504
{
  g_return_val_if_fail (caps != NULL, NULL);
  g_return_val_if_fail (IS_WRITABLE (caps), NULL);

505
  if (G_UNLIKELY (index >= GST_CAPS_LEN (caps)))
506
507
    return NULL;

508
  return gst_caps_remove_and_get_structure (caps, index);
509
510
}

511
512
513
/**
 * gst_caps_append:
 * @caps1: the #GstCaps that will be appended to
514
 * @caps2: (transfer full): the #GstCaps to append
515
 *
516
517
518
 * Appends the structures contained in @caps2 to @caps1. The structures in
 * @caps2 are not copied -- they are transferred to @caps1, and then @caps2 is
 * freed. If either caps is ANY, the resulting caps will be ANY.
519
 */
520
void
521
gst_caps_append (GstCaps * caps1, GstCaps * caps2)
David Schleef's avatar
David Schleef committed
522
523
{
  GstStructure *structure;
524
  GstCapsFeatures *features;
525
  int i;
526

527
528
  g_return_if_fail (GST_IS_CAPS (caps1));
  g_return_if_fail (GST_IS_CAPS (caps2));
529
  g_return_if_fail (IS_WRITABLE (caps1));
530

531
  if (G_UNLIKELY (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2))) {
Wim Taymans's avatar
Wim Taymans committed
532
    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAG_ANY;
533
    gst_caps_unref (caps2);
534
  } else {
535
536
    caps2 = gst_caps_make_writable (caps2);

537
    for (i = GST_CAPS_LEN (caps2); i; i--) {
538
539
540
      gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure,
          &features);
      gst_caps_append_structure_unchecked (caps1, structure, features);
541
    }
542
    gst_caps_unref (caps2);     /* guaranteed to free it */
David Schleef's avatar
David Schleef committed
543
544
545
  }
}

546
547
/**
 * gst_caps_merge:
548
 * @caps1: (transfer full): the #GstCaps that will take the new entries
549
 * @caps2: (transfer full): the #GstCaps to merge in
550
 *
551
552
 * Appends the structures contained in @caps2 to @caps1 if they are not yet
 * expressed by @caps1. The structures in @caps2 are not copied -- they are
553
 * transferred to a writable copy of @caps1, and then @caps2 is freed.
554
 * If either caps is ANY, the resulting caps will be ANY.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
555
 *
556
 * Returns: (transfer full): the merged caps.
557
 */
558
GstCaps *
559
560
561
gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
{
  GstStructure *structure;
562
  GstCapsFeatures *features;
563
  int i;
564
  GstCaps *result;
565

566
567
  g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
  g_return_val_if_fail (GST_IS_CAPS (caps2), NULL);
568

569
  if (G_UNLIKELY (CAPS_IS_ANY (caps1))) {
570
571
    gst_caps_unref (caps2);
    result = caps1;
572
  } else if (G_UNLIKELY (CAPS_IS_ANY (caps2))) {
573
574
    gst_caps_unref (caps1);
    result = caps2;
575
  } else {
576
577
    caps2 = gst_caps_make_writable (caps2);

578
    for (i = GST_CAPS_LEN (caps2); i; i--) {
579
580
581
      gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure,
          &features);
      caps1 = gst_caps_merge_structure_full (caps1, structure, features);
582
    }
583
584
585
    gst_caps_unref (caps2);
    result = caps1;

586
587
588
    /* this is too naive
       GstCaps *com = gst_caps_intersect (caps1, caps2);
       GstCaps *add = gst_caps_subtract (caps2, com);
589
590
591

       GST_DEBUG ("common : %d", gst_caps_get_size (com));
       GST_DEBUG ("adding : %d", gst_caps_get_size (add));
592
593
       gst_caps_append (caps1, add);
       gst_caps_unref (com);
594
595
     */
  }
596
597

  return result;
598
599
}

600
601
602
/**
 * gst_caps_append_structure:
 * @caps: the #GstCaps that will be appended to
603
 * @structure: (transfer full): the #GstStructure to append
604
 *
605
 * Appends @structure to @caps.  The structure is not copied; @caps
606
607
 * becomes the owner of @structure.
 */
608
void
609
gst_caps_append_structure (GstCaps * caps, GstStructure * structure)
David Schleef's avatar
David Schleef committed
610
{
611
  g_return_if_fail (GST_IS_CAPS (caps));
612
  g_return_if_fail (IS_WRITABLE (caps));
David Schleef's avatar
David Schleef committed
613

614
  if (G_LIKELY (structure)) {
615
616
617
618
619
620
621
622
623
624
625
626
    gst_caps_append_structure_unchecked (caps, structure, NULL);
  }
}

/**
 * gst_caps_append_structure_full:
 * @caps: the #GstCaps that will be appended to
 * @structure: (transfer full): the #GstStructure to append
 * @features: (transfer full) (allow-none): the #GstCapsFeatures to append
 *
 * Appends @structure with @features to @caps.  The structure is not copied; @caps
 * becomes the owner of @structure.
627
628
 *
 * Since: 1.2
629
630
631
632
633
634
635
636
637
638
 */
void
gst_caps_append_structure_full (GstCaps * caps, GstStructure * structure,
    GstCapsFeatures * features)
{
  g_return_if_fail (GST_IS_CAPS (caps));
  g_return_if_fail (IS_WRITABLE (caps));

  if (G_LIKELY (structure)) {
    gst_caps_append_structure_unchecked (caps, structure, features);
David Schleef's avatar
David Schleef committed
639
640
641
  }
}

642
/**
643
644
645
646
 * gst_caps_remove_structure:
 * @caps: the #GstCaps to remove from
 * @idx: Index of the structure to remove
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
647
 * removes the stucture with the given index from the list of structures
648
649
650
651
652
653
654
655
656
 * contained in @caps.
 */
void
gst_caps_remove_structure (GstCaps * caps, guint idx)
{
  GstStructure *structure;

  g_return_if_fail (caps != NULL);
  g_return_if_fail (idx <= gst_caps_get_size (caps));
657
  g_return_if_fail (IS_WRITABLE (caps));
658
659
660
661
662

  structure = gst_caps_remove_and_get_structure (caps, idx);
  gst_structure_free (structure);
}

663
664
/**
 * gst_caps_merge_structure:
665
 * @caps: (transfer full): the #GstCaps to merge into
666
 * @structure: (transfer full): the #GstStructure to merge
667
 *
668
669
670
 * Appends @structure to @caps if its not already expressed by @caps.
 *
 * Returns: (transfer full): the merged caps.
671
 */
672
GstCaps *
673
gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
674
{
Wim Taymans's avatar
Wim Taymans committed
675
  GstStructure *structure1;
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
  GstCapsFeatures *features1;
  int i;
  gboolean unique = TRUE;

  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);

  if (G_UNLIKELY (structure == NULL))
    return caps;

  /* check each structure */
  for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
    structure1 = gst_caps_get_structure_unchecked (caps, i);
    features1 = gst_caps_get_features_unchecked (caps, i);
    if (!features1)
      features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;

    /* if structure is a subset of structure1 and the
     * there are no existing features, then skip it */
694
695
696
    if (gst_caps_features_is_equal (features1,
            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
        && gst_structure_is_subset (structure, structure1)) {
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
      unique = FALSE;
      break;
    }
  }
  if (unique) {
    caps = gst_caps_make_writable (caps);
    gst_caps_append_structure_unchecked (caps, structure, NULL);
  } else {
    gst_structure_free (structure);
  }
  return caps;
}

/**
 * gst_caps_merge_structure_full:
 * @caps: (transfer full): the #GstCaps to merge into
 * @structure: (transfer full): the #GstStructure to merge
 * @features: (transfer full) (allow-none): the #GstCapsFeatures to merge
 *
 * Appends @structure with @features to @caps if its not already expressed by @caps.
 *
 * Returns: (transfer full): the merged caps.
719
720
 *
 * Since: 1.2
721
722
723
724
725
726
727
 */
GstCaps *
gst_caps_merge_structure_full (GstCaps * caps, GstStructure * structure,
    GstCapsFeatures * features)
{
  GstStructure *structure1;
  GstCapsFeatures *features1, *features_tmp;
Wim Taymans's avatar
Wim Taymans committed
728
729
730
  int i;
  gboolean unique = TRUE;

731
  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
732

Wim Taymans's avatar
Wim Taymans committed
733
734
735
  if (G_UNLIKELY (structure == NULL))
    return caps;

736
737
738
  /* To make comparisons easier below */
  features_tmp = features ? features : GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;

Wim Taymans's avatar
Wim Taymans committed
739
740
741
  /* check each structure */
  for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
    structure1 = gst_caps_get_structure_unchecked (caps, i);
742
743
744
745
746
    features1 = gst_caps_get_features_unchecked (caps, i);
    if (!features1)
      features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
    /* if structure is a subset of structure1 and the
     * the features are a subset, then skip it */
747
748
749
750
751
752
753
754
755
    /* FIXME: We only skip if none of the features are
     * ANY and are still equal. That way all ANY structures
     * show up in the caps and no non-ANY structures are
     * swallowed by ANY structures
     */
    if (((!gst_caps_features_is_any (features_tmp)
                || gst_caps_features_is_any (features1))
            && gst_caps_features_is_equal (features_tmp, features1))
        && gst_structure_is_subset (structure, structure1)) {
Wim Taymans's avatar
Wim Taymans committed
756
757
      unique = FALSE;
      break;
758
759
    }
  }
Wim Taymans's avatar
Wim Taymans committed
760
761
  if (unique) {
    caps = gst_caps_make_writable (caps);
762
    gst_caps_append_structure_unchecked (caps, structure, features);
Wim Taymans's avatar
Wim Taymans committed
763
764
  } else {
    gst_structure_free (structure);
765
766
    if (features)
      gst_caps_features_free (features);
Wim Taymans's avatar
Wim Taymans committed
767
  }
768
  return caps;
769
770
}

771
/**
772
 * gst_caps_get_size:
773
774
 * @caps: a #GstCaps
 *
775
776
 * Gets the number of structures contained in @caps.
 *
777
778
 * Returns: the number of structures that @caps contains
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
779
guint
780
gst_caps_get_size (const GstCaps * caps)
David Schleef's avatar
David Schleef committed
781
{
782
  g_return_val_if_fail (GST_IS_CAPS (caps), 0);
David Schleef's avatar
David Schleef committed
783

784
  return GST_CAPS_LEN (caps);
David Schleef's avatar
David Schleef committed
785
786
}

787
788
789
790
791
/**
 * gst_caps_get_structure:
 * @caps: a #GstCaps
 * @index: the index of the structure
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
792
 * Finds the structure in @caps that has the index @index, and
793
794
795
796
797
 * returns it.
 *
 * WARNING: This function takes a const GstCaps *, but returns a
 * non-const GstStructure *.  This is for programming convenience --
 * the caller should be aware that structures inside a constant
798
799
800
801
 * #GstCaps should not be modified. However, if you know the caps
 * are writable, either because you have just copied them or made
 * them writable with gst_caps_make_writable(), you may modify the
 * structure returned in the usual way, e.g. with functions like
Stefan Kost's avatar
Stefan Kost committed
802
 * gst_structure_set().
803
804
805
 *
 * You do not need to free or unref the structure returned, it
 * belongs to the #GstCaps.
806
 *
807
808
 * Returns: (transfer none): a pointer to the #GstStructure corresponding
 *     to @index
809
 */
810
GstStructure *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
811
gst_caps_get_structure (const GstCaps * caps, guint index)
David Schleef's avatar
David Schleef committed
812
{
813
  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
814
  g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL);
David Schleef's avatar
David Schleef committed
815

816
  return gst_caps_get_structure_unchecked (caps, index);
David Schleef's avatar
David Schleef committed
817
818
}

819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
/**
 * gst_caps_get_features:
 * @caps: a #GstCaps
 * @index: the index of the structure
 *
 * Finds the features in @caps that has the index @index, and
 * returns it.
 *
 * WARNING: This function takes a const GstCaps *, but returns a
 * non-const GstCapsFeatures *.  This is for programming convenience --
 * the caller should be aware that structures inside a constant
 * #GstCaps should not be modified. However, if you know the caps
 * are writable, either because you have just copied them or made
 * them writable with gst_caps_make_writable(), you may modify the
 * features returned in the usual way, e.g. with functions like
 * gst_caps_features_add().
 *
 * You do not need to free or unref the structure returned, it
 * belongs to the #GstCaps.
 *
 * Returns: (transfer none): a pointer to the #GstCapsFeatures corresponding
 *     to @index
841
842
 *
 * Since: 1.2
843
844
845
846
847
848
849
850
851
852
853
 */
GstCapsFeatures *
gst_caps_get_features (const GstCaps * caps, guint index)
{
  GstCapsFeatures *features;

  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
  g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL);

  features = gst_caps_get_features_unchecked (caps, index);
  if (!features)
854
    features = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
855
856
857
858
859
860
861
862
863
864
865

  return features;
}

/**
 * gst_caps_set_features:
 * @caps: a #GstCaps
 * @index: the index of the structure
 * @features: (allow-none) (transfer full): the #GstFeatures to set
 *
 * Sets the #GstCapsFeatures @features for the structure at @index.
866
867
 *
 * Since: 1.2
868
869
870
871
872
873
874
875
876
877
878
879
880
 */
void
gst_caps_set_features (GstCaps * caps, guint index, GstCapsFeatures * features)
{
  GstCapsFeatures **storage, *old;

  g_return_if_fail (caps != NULL);
  g_return_if_fail (index <= gst_caps_get_size (caps));
  g_return_if_fail (IS_WRITABLE (caps));

  storage = &gst_caps_get_features_unchecked (caps, index);
  old = *storage;
  *storage = features;
881
882
883
884

  if (features)
    gst_caps_features_set_parent_refcount (features, &GST_CAPS_REFCOUNT (caps));

885
886
  if (old) {
    gst_caps_features_set_parent_refcount (old, NULL);
887
    gst_caps_features_free (old);
888
  }
889
890
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
891
892
/**
 * gst_caps_copy_nth:
893
 * @caps: the #GstCaps to copy
894
 * @nth: the nth structure to copy
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
895
 *
896
 * Creates a new #GstCaps and appends a copy of the nth structure
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
897
898
 * contained in @caps.
 *
899
 * Returns: (transfer full): the new #GstCaps
900
 */
901
GstCaps *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
902
gst_caps_copy_nth (const GstCaps * caps, guint nth)
David Schleef's avatar
David Schleef committed
903
{
David Schleef's avatar
David Schleef committed
904
  GstCaps *newcaps;
David Schleef's avatar
David Schleef committed
905
  GstStructure *structure;
906
  GstCapsFeatures *features;
David Schleef's avatar
David Schleef committed
907

908
  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
David Schleef's avatar
David Schleef committed
909

910
  newcaps = gst_caps_new_empty ();
911
  GST_CAPS_FLAGS (newcaps) = GST_CAPS_FLAGS (caps);
David Schleef's avatar
David Schleef committed
912

913
  if (G_LIKELY (GST_CAPS_LEN (caps) > nth)) {
914
    structure = gst_caps_get_structure_unchecked (caps, nth);
915
    features = gst_caps_get_features_unchecked (caps, nth);
916
    gst_caps_append_structure_unchecked (newcaps,
917
918
        gst_structure_copy (structure),
        gst_caps_features_copy_conditional (features));
David Schleef's avatar
David Schleef committed
919
920
921
922
923
  }

  return newcaps;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
924
925
/**
 * gst_caps_truncate:
926
927
928
929
 * @caps: (transfer full): the #GstCaps to truncate
 *
 * Discard all but the first structure from @caps. Useful when
 * fixating.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
930
 *
931
 * Returns: (transfer full): truncated caps
932
 */
933
GstCaps *
934
935
936
937
gst_caps_truncate (GstCaps * caps)
{
  gint i;

938
  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
939

940
  i = GST_CAPS_LEN (caps) - 1;
941
942
  if (i == 0)
    return caps;
943

944
  caps = gst_caps_make_writable (caps);
945
946
  while (i > 0)
    gst_caps_remove_structure (caps, i--);
947
948

  return caps;
949
950
}

951
/**
Benjamin Otte's avatar
Benjamin Otte committed
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
 * gst_caps_set_value:
 * @caps: a writable caps
 * @field: name of the field to set
 * @value: value to set the field to
 *
 * Sets the given @field on all structures of @caps to the given @value.
 * This is a convenience function for calling gst_structure_set_value() on
 * all structures of @caps.
 **/
void
gst_caps_set_value (GstCaps * caps, const char *field, const GValue * value)
{
  guint i, len;

  g_return_if_fail (GST_IS_CAPS (caps));
  g_return_if_fail (IS_WRITABLE (caps));
  g_return_if_fail (field != NULL);
  g_return_if_fail (G_IS_VALUE (value));

971
  len = GST_CAPS_LEN (caps);
Benjamin Otte's avatar
Benjamin Otte committed
972
973
974
975
976
977
978
979
  for (i = 0; i < len; i++) {
    GstStructure *structure = gst_caps_get_structure_unchecked (caps, i);
    gst_structure_set_value (structure, field, value);
  }
}

/**
 * gst_caps_set_simple_valist:
980
 * @caps: the #GstCaps to set
981
 * @field: first field to set
Benjamin Otte's avatar
Benjamin Otte committed
982
 * @varargs: additional parameters
983
 *
Benjamin Otte's avatar
Benjamin Otte committed
984
 * Sets fields in a #GstCaps.  The arguments must be passed in the same
985
 * manner as gst_structure_set(), and be NULL-terminated.
986
 */
987
void
Benjamin Otte's avatar
Benjamin Otte committed
988
gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs)
David Schleef's avatar
David Schleef committed
989
{
Benjamin Otte's avatar
Benjamin Otte committed
990
  GValue value = { 0, };
David Schleef's avatar
David Schleef committed
991

992
  g_return_if_fail (GST_IS_CAPS (caps));
993
  g_return_if_fail (IS_WRITABLE (caps));
David Schleef's avatar
David Schleef committed
994

Benjamin Otte's avatar
Benjamin Otte committed
995
996
997
  while (field) {
    GType type;
    char *err;
David Schleef's avatar
David Schleef committed
998

Benjamin Otte's avatar
Benjamin Otte committed
999
1000
    type = va_arg (varargs, GType);

1001
    G_VALUE_COLLECT_INIT (&value, type, varargs, 0, &err);
Benjamin Otte's avatar
Benjamin Otte committed
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
    if (G_UNLIKELY (err)) {
      g_critical ("%s", err);
      return;
    }

    gst_caps_set_value (caps, field, &value);

    g_value_unset (&value);

    field = va_arg (varargs, const gchar *);
  }
David Schleef's avatar
David Schleef committed
1013
1014
}

1015
/**
Benjamin Otte's avatar
Benjamin Otte committed
1016
1017
 * gst_caps_set_simple:
 * @caps: the #GstCaps to set
1018
 * @field: first field to set
Benjamin Otte's avatar
Benjamin Otte committed
1019
 * @...: additional parameters
1020
 *