gstcaps.c 70.3 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
/**
 * SECTION:gstcaps
22
 * @title: GstCaps
23
 * @short_description: Structure describing sets of media formats
Wim Taymans's avatar
Wim Taymans committed
24
 * @see_also: #GstStructure, #GstMiniObject
25
 *
Wim Taymans's avatar
Wim Taymans committed
26
 * Caps (capabilities) are lightweight refcounted objects describing media types.
27 28 29
 * They are composed of an array of #GstStructure.
 *
 * Caps are exposed on #GstPadTemplate to describe all possible types a
30 31
 * given pad can handle. They are also stored in the #GstRegistry along with
 * a description of the #GstElement.
32
 *
Wim Taymans's avatar
Wim Taymans committed
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
Stefan Kost's avatar
Stefan Kost committed
35
 * handle or produce at runtime.
36 37
 *
 * A #GstCaps can be constructed with the following code fragment:
38
 * |[<!-- language="C" -->
39 40 41 42 43 44 45 46
 *   GstCaps *caps = gst_caps_new_simple ("video/x-raw",
 *      "format", G_TYPE_STRING, "I420",
 *      "framerate", GST_TYPE_FRACTION, 25, 1,
 *      "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
 *      "width", G_TYPE_INT, 320,
 *      "height", G_TYPE_INT, 240,
 *      NULL);
 * ]|
47 48
 *
 * A #GstCaps is fixed when it has no properties with ranges or lists. Use
Wim Taymans's avatar
Wim Taymans committed
49 50
 * 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.
51
 *
Stefan Kost's avatar
Stefan Kost committed
52
 * Various methods exist to work with the media types such as subtracting
53 54
 * or intersecting.
 *
55 56 57 58 59
 * Be aware that the current #GstCaps / #GstStructure serialization into string
 * has limited support for nested #GstCaps / #GstStructure fields. It can only
 * support one level of nesting. Using more levels will lead to unexpected
 * behavior when using serialization features, such as gst_caps_to_string() or
 * gst_value_serialize() and their counterparts.
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
     (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).structure)
111 112
#define gst_caps_get_features_storage_unchecked(caps, index) \
     (&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 117 118 119 120
#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);                             \
121
}G_STMT_END
122

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

126 127 128 129
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);
130

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

135
GST_DEFINE_MINI_OBJECT_TYPE (GstCaps, gst_caps);
Wim Taymans's avatar
Wim Taymans committed
136

Wim Taymans's avatar
Wim Taymans committed
137
void
138
_priv_gst_caps_initialize (void)
David Schleef's avatar
David Schleef committed
139
{
Wim Taymans's avatar
Wim Taymans committed
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

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

149 150 151 152 153 154 155 156 157
void
_priv_gst_caps_cleanup (void)
{
  gst_caps_unref (_gst_caps_any);
  _gst_caps_any = NULL;
  gst_caps_unref (_gst_caps_none);
  _gst_caps_none = NULL;
}

158 159 160 161 162 163
GstCapsFeatures *
__gst_caps_get_features_unchecked (const GstCaps * caps, guint idx)
{
  return gst_caps_get_features_unchecked (caps, idx);
}

164 165 166 167 168
static GstCaps *
_gst_caps_copy (const GstCaps * caps)
{
  GstCaps *newcaps;
  GstStructure *structure;
169
  GstCapsFeatures *features;
170 171 172 173 174 175
  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);
176
  n = GST_CAPS_LEN (caps);
177 178 179

  GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, caps, "doing copy %p -> %p",
      caps, newcaps);
180 181 182

  for (i = 0; i < n; i++) {
    structure = gst_caps_get_structure_unchecked (caps, i);
183 184 185
    features = gst_caps_get_features_unchecked (caps, i);
    gst_caps_append_structure_full (newcaps, gst_structure_copy (structure),
        gst_caps_features_copy_conditional (features));
186 187 188 189 190
  }

  return newcaps;
}

David Schleef's avatar
David Schleef committed
191
/* creation/deletion */
192 193 194 195
static void
_gst_caps_free (GstCaps * caps)
{
  GstStructure *structure;
196
  GstCapsFeatures *features;
197 198 199 200
  guint i, len;

  /* The refcount must be 0, but since we're only called by gst_caps_unref,
   * don't bother testing. */
201
  len = GST_CAPS_LEN (caps);
202 203 204
  /* 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++) {
205
    structure = gst_caps_get_structure_unchecked (caps, i);
206 207
    gst_structure_set_parent_refcount (structure, NULL);
    gst_structure_free (structure);
208 209 210 211 212
    features = gst_caps_get_features_unchecked (caps, i);
    if (features) {
      gst_caps_features_set_parent_refcount (features, NULL);
      gst_caps_features_free (features);
    }
213
  }
214
  g_array_free (GST_CAPS_ARRAY (caps), TRUE);
215 216

#ifdef DEBUG_REFCOUNT
217
  GST_CAT_TRACE (GST_CAT_CAPS, "freeing caps %p", caps);
218
#endif
219
  g_slice_free1 (sizeof (GstCapsImpl), caps);
220
}
221

Wim Taymans's avatar
Wim Taymans committed
222
static void
223
gst_caps_init (GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
224
{
225
  gst_mini_object_init (GST_MINI_OBJECT_CAST (caps), 0, _gst_caps_type,
226 227
      (GstMiniObjectCopyFunction) _gst_caps_copy, NULL,
      (GstMiniObjectFreeFunction) _gst_caps_free);
Wim Taymans's avatar
Wim Taymans committed
228 229 230

  /* 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
231
   * in practice
232
   * GST_CAPS_ARRAY (caps) = g_ptr_array_sized_new (32);
Wim Taymans's avatar
Wim Taymans committed
233
   */
234 235
  GST_CAPS_ARRAY (caps) =
      g_array_new (FALSE, TRUE, sizeof (GstCapsArrayElement));
Wim Taymans's avatar
Wim Taymans committed
236 237
}

238 239 240 241 242
/**
 * gst_caps_new_empty:
 *
 * Creates a new #GstCaps that is empty.  That is, the returned
 * #GstCaps contains no media formats.
243
 * The #GstCaps is guaranteed to be writable.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
244
 * Caller is responsible for unreffing the returned caps.
245
 *
246
 * Returns: (transfer full): the new #GstCaps
247
 */
248 249
GstCaps *
gst_caps_new_empty (void)
David Schleef's avatar
David Schleef committed
250
{
251 252
  GstCaps *caps;

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

255
  gst_caps_init (caps);
David Schleef's avatar
David Schleef committed
256

257
#ifdef DEBUG_REFCOUNT
258
  GST_CAT_TRACE (GST_CAT_CAPS, "created caps %p", caps);
259 260
#endif

David Schleef's avatar
David Schleef committed
261 262 263
  return caps;
}

264
/**
265
 * gst_caps_new_any:
266 267 268 269
 *
 * Creates a new #GstCaps that indicates that it is compatible with
 * any media format.
 *
270
 * Returns: (transfer full): the new #GstCaps
271
 */
272 273
GstCaps *
gst_caps_new_any (void)
David Schleef's avatar
David Schleef committed
274
{
275
  GstCaps *caps = gst_caps_new_empty ();
David Schleef's avatar
David Schleef committed
276

Wim Taymans's avatar
Wim Taymans committed
277
  GST_CAPS_FLAG_SET (caps, GST_CAPS_FLAG_ANY);
David Schleef's avatar
David Schleef committed
278 279 280 281

  return caps;
}

Wim Taymans's avatar
Wim Taymans committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
/**
 * 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
299
  structure = gst_structure_new_empty (media_type);
Wim Taymans's avatar
Wim Taymans committed
300
  if (structure)
301
    gst_caps_append_structure_unchecked (caps, structure, NULL);
Wim Taymans's avatar
Wim Taymans committed
302 303 304 305

  return caps;
}

306 307 308
/**
 * gst_caps_new_simple:
 * @media_type: the media type of the structure
309
 * @fieldname: first field to set
310 311 312 313
 * @...: additional arguments
 *
 * Creates a new #GstCaps that contains one #GstStructure.  The
 * structure is defined by the arguments, which have the same format
314
 * as gst_structure_new().
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
315
 * Caller is responsible for unreffing the returned caps.
316
 *
317
 * Returns: (transfer full): the new #GstCaps
318
 */
319
GstCaps *
320
gst_caps_new_simple (const char *media_type, const char *fieldname, ...)
David Schleef's avatar
David Schleef committed
321
{
David Schleef's avatar
David Schleef committed
322
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
323 324 325
  GstStructure *structure;
  va_list var_args;

326
  caps = gst_caps_new_empty ();
David Schleef's avatar
David Schleef committed
327 328 329 330 331

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

332
  if (structure)
333
    gst_caps_append_structure_unchecked (caps, structure, NULL);
334 335
  else
    gst_caps_replace (&caps, NULL);
336

David Schleef's avatar
David Schleef committed
337 338 339
  return caps;
}

340 341 342 343 344 345
/**
 * 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
346
 * arguments.  The list must be %NULL-terminated.  The structures
347 348
 * are not copied; the returned #GstCaps owns the structures.
 *
349
 * Returns: (transfer full): the new #GstCaps
350
 */
351
GstCaps *
352
gst_caps_new_full (GstStructure * struct1, ...)
David Schleef's avatar
David Schleef committed
353
{
David Schleef's avatar
David Schleef committed
354
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
355 356 357
  va_list var_args;

  va_start (var_args, struct1);
David Schleef's avatar
David Schleef committed
358
  caps = gst_caps_new_full_valist (struct1, var_args);
David Schleef's avatar
David Schleef committed
359 360 361 362 363
  va_end (var_args);

  return caps;
}

364 365
/**
 * gst_caps_new_full_valist:
366
 * @structure: the first structure to add
367 368 369
 * @var_args: additional structures to add
 *
 * Creates a new #GstCaps and adds all the structures listed as
370
 * arguments.  The list must be %NULL-terminated.  The structures
371 372
 * are not copied; the returned #GstCaps owns the structures.
 *
373
 * Returns: (transfer full): the new #GstCaps
374
 */
375
GstCaps *
376
gst_caps_new_full_valist (GstStructure * structure, va_list var_args)
David Schleef's avatar
David Schleef committed
377
{
David Schleef's avatar
David Schleef committed
378
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
379

380
  caps = gst_caps_new_empty ();
David Schleef's avatar
David Schleef committed
381

382
  while (structure) {
383
    gst_caps_append_structure_unchecked (caps, structure, NULL);
David Schleef's avatar
David Schleef committed
384
    structure = va_arg (var_args, GstStructure *);
David Schleef's avatar
David Schleef committed
385 386 387 388 389
  }

  return caps;
}

390
G_DEFINE_POINTER_TYPE (GstStaticCaps, gst_static_caps);
391

392 393 394 395 396 397
/**
 * gst_static_caps_get:
 * @static_caps: the #GstStaticCaps to convert
 *
 * Converts a #GstStaticCaps to a #GstCaps.
 *
398 399 400
 * 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.
401
 */
402
GstCaps *
403
gst_static_caps_get (GstStaticCaps * static_caps)
David Schleef's avatar
David Schleef committed
404
{
405
  GstCaps **caps;
406 407 408

  g_return_val_if_fail (static_caps != NULL, NULL);

409
  caps = &static_caps->caps;
David Schleef's avatar
David Schleef committed
410

411
  /* refcount is 0 when we need to convert */
412
  if (G_UNLIKELY (*caps == NULL)) {
413 414 415 416
    const char *string;

    G_LOCK (static_caps_lock);
    /* check if other thread already updated */
417
    if (G_UNLIKELY (*caps != NULL))
418 419 420 421 422
      goto done;

    string = static_caps->string;

    if (G_UNLIKELY (string == NULL))
423
      goto no_string;
424

425
    *caps = gst_caps_from_string (string);
David Schleef's avatar
David Schleef committed
426

427
    /* convert to string */
428
    if (G_UNLIKELY (*caps == NULL)) {
429
      g_critical ("Could not convert static caps \"%s\"", string);
430 431 432 433 434
      goto done;
    }

    /* Caps generated from static caps are usually leaked */
    GST_MINI_OBJECT_FLAG_SET (*caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
435

Wim Taymans's avatar
Wim Taymans committed
436 437
    GST_CAT_TRACE (GST_CAT_CAPS, "created %p from string %s", static_caps,
        string);
438 439
  done:
    G_UNLOCK (static_caps_lock);
David Schleef's avatar
David Schleef committed
440
  }
441
  /* ref the caps, makes it not writable */
442 443
  if (G_LIKELY (*caps != NULL))
    gst_caps_ref (*caps);
David Schleef's avatar
David Schleef committed
444

445
  return *caps;
446 447 448 449

  /* ERRORS */
no_string:
  {
450 451
    G_UNLOCK (static_caps_lock);
    g_warning ("static caps %p string is NULL", static_caps);
452 453
    return NULL;
  }
David Schleef's avatar
David Schleef committed
454 455
}

456 457
/**
 * gst_static_caps_cleanup:
458
 * @static_caps: the #GstStaticCaps to clean
459
 *
460
 * Clean up the cached caps contained in @static_caps.
461 462 463 464
 */
void
gst_static_caps_cleanup (GstStaticCaps * static_caps)
{
465 466 467
  G_LOCK (static_caps_lock);
  gst_caps_replace (&static_caps->caps, NULL);
  G_UNLOCK (static_caps_lock);
468 469
}

David Schleef's avatar
David Schleef committed
470
/* manipulation */
471

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
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_;
}

494 495 496
static GstStructure *
gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
{
497 498 499 500 501 502 503
  GstStructure *s;
  GstCapsFeatures *f;

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

  if (f)
    gst_caps_features_free (f);
504 505 506 507

  return s;
}

508 509 510
/**
 * gst_caps_steal_structure:
 * @caps: the #GstCaps to retrieve from
511
 * @index: Index of the structure to retrieve
512
 *
Fabrizio (Misto) Milo's avatar
Fabrizio (Misto) Milo committed
513
 * Retrieves the structure with the given index from the list of structures
514 515
 * contained in @caps. The caller becomes the owner of the returned structure.
 *
516 517
 * Returns: (transfer full): a pointer to the #GstStructure corresponding
 *     to @index.
518 519
 */
GstStructure *
520
gst_caps_steal_structure (GstCaps * caps, guint index)
521 522 523 524
{
  g_return_val_if_fail (caps != NULL, NULL);
  g_return_val_if_fail (IS_WRITABLE (caps), NULL);

525
  if (G_UNLIKELY (index >= GST_CAPS_LEN (caps)))
526 527
    return NULL;

528
  return gst_caps_remove_and_get_structure (caps, index);
529 530
}

531 532 533
/**
 * gst_caps_append:
 * @caps1: the #GstCaps that will be appended to
534
 * @caps2: (transfer full): the #GstCaps to append
535
 *
536 537 538
 * 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.
539
 */
540
void
541
gst_caps_append (GstCaps * caps1, GstCaps * caps2)
David Schleef's avatar
David Schleef committed
542 543
{
  GstStructure *structure;
544
  GstCapsFeatures *features;
545
  int i;
546

547 548
  g_return_if_fail (GST_IS_CAPS (caps1));
  g_return_if_fail (GST_IS_CAPS (caps2));
549
  g_return_if_fail (IS_WRITABLE (caps1));
550

551
  if (G_UNLIKELY (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2))) {
Wim Taymans's avatar
Wim Taymans committed
552
    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAG_ANY;
553
    gst_caps_unref (caps2);
554
  } else {
555 556
    caps2 = gst_caps_make_writable (caps2);

557
    for (i = GST_CAPS_LEN (caps2); i; i--) {
558 559 560
      gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure,
          &features);
      gst_caps_append_structure_unchecked (caps1, structure, features);
561
    }
562
    gst_caps_unref (caps2);     /* guaranteed to free it */
David Schleef's avatar
David Schleef committed
563 564 565
  }
}

566 567
/**
 * gst_caps_merge:
568
 * @caps1: (transfer full): the #GstCaps that will take the new entries
569
 * @caps2: (transfer full): the #GstCaps to merge in
570
 *
571 572
 * 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
573
 * transferred to a writable copy of @caps1, and then @caps2 is freed.
574
 * If either caps is ANY, the resulting caps will be ANY.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
575
 *
576
 * Returns: (transfer full): the merged caps.
577
 */
578
GstCaps *
579 580 581
gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
{
  GstStructure *structure;
582
  GstCapsFeatures *features;
583
  int i;
584
  GstCaps *result;
585

586 587
  g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
  g_return_val_if_fail (GST_IS_CAPS (caps2), NULL);
588

589
  if (G_UNLIKELY (CAPS_IS_ANY (caps1))) {
590 591
    gst_caps_unref (caps2);
    result = caps1;
592
  } else if (G_UNLIKELY (CAPS_IS_ANY (caps2))) {
593 594
    gst_caps_unref (caps1);
    result = caps2;
595
  } else {
596 597
    caps2 = gst_caps_make_writable (caps2);

598
    for (i = GST_CAPS_LEN (caps2); i; i--) {
599 600 601
      gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure,
          &features);
      caps1 = gst_caps_merge_structure_full (caps1, structure, features);
602
    }
603 604 605
    gst_caps_unref (caps2);
    result = caps1;

606 607 608
    /* this is too naive
       GstCaps *com = gst_caps_intersect (caps1, caps2);
       GstCaps *add = gst_caps_subtract (caps2, com);
609 610 611

       GST_DEBUG ("common : %d", gst_caps_get_size (com));
       GST_DEBUG ("adding : %d", gst_caps_get_size (add));
612 613
       gst_caps_append (caps1, add);
       gst_caps_unref (com);
614 615
     */
  }
616 617

  return result;
618 619
}

620 621 622
/**
 * gst_caps_append_structure:
 * @caps: the #GstCaps that will be appended to
623
 * @structure: (transfer full): the #GstStructure to append
624
 *
625
 * Appends @structure to @caps.  The structure is not copied; @caps
626 627
 * becomes the owner of @structure.
 */
628
void
629
gst_caps_append_structure (GstCaps * caps, GstStructure * structure)
David Schleef's avatar
David Schleef committed
630
{
631
  g_return_if_fail (GST_IS_CAPS (caps));
632
  g_return_if_fail (IS_WRITABLE (caps));
David Schleef's avatar
David Schleef committed
633

634
  if (G_LIKELY (structure)) {
635 636 637 638 639 640 641 642 643 644 645 646
    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.
647 648
 *
 * Since: 1.2
649 650 651 652 653 654 655 656 657 658
 */
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
659 660 661
  }
}

662
/**
663 664 665 666
 * gst_caps_remove_structure:
 * @caps: the #GstCaps to remove from
 * @idx: Index of the structure to remove
 *
667
 * removes the structure with the given index from the list of structures
668 669 670 671 672 673 674 675 676
 * 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));
677
  g_return_if_fail (IS_WRITABLE (caps));
678 679 680 681 682

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

683 684
/**
 * gst_caps_merge_structure:
685
 * @caps: (transfer full): the #GstCaps to merge into
686
 * @structure: (transfer full): the #GstStructure to merge
687
 *
688 689 690
 * Appends @structure to @caps if its not already expressed by @caps.
 *
 * Returns: (transfer full): the merged caps.
691
 */
692
GstCaps *
693
gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
694
{
Wim Taymans's avatar
Wim Taymans committed
695
  GstStructure *structure1;
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
  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 */
714 715 716
    if (gst_caps_features_is_equal (features1,
            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
        && gst_structure_is_subset (structure, structure1)) {
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
      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.
739 740
 *
 * Since: 1.2
741 742 743 744 745 746 747
 */
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
748 749 750
  int i;
  gboolean unique = TRUE;

751
  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
752

Wim Taymans's avatar
Wim Taymans committed
753 754 755
  if (G_UNLIKELY (structure == NULL))
    return caps;

756 757 758
  /* To make comparisons easier below */
  features_tmp = features ? features : GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;

Wim Taymans's avatar
Wim Taymans committed
759 760 761
  /* check each structure */
  for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
    structure1 = gst_caps_get_structure_unchecked (caps, i);
762 763 764 765 766
    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 */
767 768 769 770 771 772 773 774 775
    /* 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
776 777
      unique = FALSE;
      break;
778 779
    }
  }
Wim Taymans's avatar
Wim Taymans committed
780 781
  if (unique) {
    caps = gst_caps_make_writable (caps);
782
    gst_caps_append_structure_unchecked (caps, structure, features);
Wim Taymans's avatar
Wim Taymans committed
783 784
  } else {
    gst_structure_free (structure);
785 786
    if (features)
      gst_caps_features_free (features);
Wim Taymans's avatar
Wim Taymans committed
787
  }
788
  return caps;
789 790
}

791
/**
792
 * gst_caps_get_size:
793 794
 * @caps: a #GstCaps
 *
795 796
 * Gets the number of structures contained in @caps.
 *
797 798
 * Returns: the number of structures that @caps contains
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
799
guint
800
gst_caps_get_size (const GstCaps * caps)
David Schleef's avatar
David Schleef committed
801
{
802
  g_return_val_if_fail (GST_IS_CAPS (caps), 0);
David Schleef's avatar
David Schleef committed
803

804
  return GST_CAPS_LEN (caps);
David Schleef's avatar
David Schleef committed
805 806
}

807 808 809 810 811
/**
 * gst_caps_get_structure:
 * @caps: a #GstCaps
 * @index: the index of the structure
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
812
 * Finds the structure in @caps that has the index @index, and
813 814 815 816 817
 * 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
818 819 820 821
 * #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
822
 * gst_structure_set().
823 824 825
 *
 * You do not need to free or unref the structure returned, it
 * belongs to the #GstCaps.
826
 *
827 828
 * Returns: (transfer none): a pointer to the #GstStructure corresponding
 *     to @index
829
 */
830
GstStructure *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
831
gst_caps_get_structure (const GstCaps * caps, guint index)
David Schleef's avatar
David Schleef committed
832
{
833
  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
834
  g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL);
David Schleef's avatar
David Schleef committed
835

836
  return gst_caps_get_structure_unchecked (caps, index);
David Schleef's avatar
David Schleef committed
837 838
}

839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
/**
 * 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
861 862
 *
 * Since: 1.2
863 864 865 866 867 868 869 870 871 872
 */
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);
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
  if (!features) {
    GstCapsFeatures **storage;

    /* We have to do some atomic pointer magic here as the caps
     * might not be writable and someone else calls this function
     * at the very same time */
    features = gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY);
    gst_caps_features_set_parent_refcount (features, &GST_CAPS_REFCOUNT (caps));

    storage = gst_caps_get_features_storage_unchecked (caps, index);
    if (!g_atomic_pointer_compare_and_exchange (storage, NULL, features)) {
      /* Someone did the same we just tried in the meantime */
      gst_caps_features_set_parent_refcount (features, NULL);
      gst_caps_features_free (features);

      features = gst_caps_get_features_unchecked (caps, index);
      g_assert (features != NULL);
    }
  }
892 893 894 895 896 897 898 899

  return features;
}

/**
 * gst_caps_set_features:
 * @caps: a #GstCaps
 * @index: the index of the structure
900
 * @features: (allow-none) (transfer full): the #GstCapsFeatures to set
901 902
 *
 * Sets the #GstCapsFeatures @features for the structure at @index.
903 904
 *
 * Since: 1.2
905 906 907 908 909 910 911 912 913 914
 */
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));

915 916 917 918
  storage = gst_caps_get_features_storage_unchecked (caps, index);
  /* Not much problem here as caps are writable */
  old = g_atomic_pointer_get (storage);
  g_atomic_pointer_set (storage, features);
919 920 921 922

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

923 924
  if (old) {
    gst_caps_features_set_parent_refcount (old, NULL);
925
    gst_caps_features_free (old);
926
  }
927 928
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
929 930
/**
 * gst_caps_copy_nth:
931
 * @caps: the #GstCaps to copy
932
 * @nth: the nth structure to copy
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
933
 *
934
 * Creates a new #GstCaps and appends a copy of the nth structure
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
935 936
 * contained in @caps.
 *
937
 * Returns: (transfer full): the new #GstCaps
938
 */
939
GstCaps *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
940
gst_caps_copy_nth (const GstCaps * caps, guint nth)
David Schleef's avatar
David Schleef committed
941
{
David Schleef's avatar
David Schleef committed
942
  GstCaps *newcaps;
David Schleef's avatar
David Schleef committed
943
  GstStructure *structure;
944
  GstCapsFeatures *features;
David Schleef's avatar
David Schleef committed
945

946
  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
David Schleef's avatar
David Schleef committed
947

948
  newcaps = gst_caps_new_empty ();