caps: spelling fixes
[platform/upstream/gstreamer.git] / gst / gstcaps.c
index 2f99a93..57f8ae6 100644 (file)
@@ -20,9 +20,9 @@
 /**
  * SECTION:gstcaps
  * @short_description: Structure describing sets of media formats
- * @see_also: #GstStructure
+ * @see_also: #GstStructure, #GstMiniObject
  *
- * Caps (capabilities) are lighweight refcounted objects describing media types.
+ * Caps (capabilities) are lightweight refcounted objects describing media types.
  * They are composed of an array of #GstStructure.
  *
  * Caps are exposed on #GstPadTemplate to describe all possible types a
  * function. This function describes the possible types that the pad can
  * handle or produce at runtime.
  *
- * Caps are also attached to buffers to describe to content of the data
- * pointed to by the buffer with gst_buffer_set_caps(). Caps attached to
- * a #GstBuffer allow for format negotiation upstream and downstream.
- *
  * A #GstCaps can be constructed with the following code fragment:
  *
  * <example>
@@ -44,7 +40,7 @@
  *  <programlisting>
  *  GstCaps *caps;
  *  caps = gst_caps_new_simple ("video/x-raw",
- *       "format", G_TYPE_STRING, "I420"),
+ *       "format", G_TYPE_STRING, "I420",
  *       "framerate", GST_TYPE_FRACTION, 25, 1,
  *       "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
  *       "width", G_TYPE_INT, 320,
  * </example>
  *
  * A #GstCaps is fixed when it has no properties with ranges or lists. Use
- * gst_caps_is_fixed() to test for fixed caps. Only fixed caps can be
- * set on a #GstPad or #GstBuffer.
+ * 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.
  *
  * Various methods exist to work with the media types such as subtracting
  * or intersecting.
  *
- * Last reviewed on 2007-02-13 (0.10.10)
+ * Last reviewed on 2011-03-28 (0.11.3)
  */
 
 #ifdef HAVE_CONFIG_H
 
 #define DEBUG_REFCOUNT
 
+typedef struct _GstCapsImpl
+{
+  GstCaps caps;
+
+  GPtrArray *array;
+} GstCapsImpl;
 
-#define GST_CAPS_ARRAY(c) ((GPtrArray *)((c)->priv))
+#define GST_CAPS_ARRAY(c) (((GstCapsImpl *)(c))->array)
 
 #define GST_CAPS_LEN(c)   (GST_CAPS_ARRAY(c)->len)
 
@@ -85,7 +87,7 @@
 
 /* same as gst_caps_is_any () */
 #define CAPS_IS_ANY(caps)                              \
-  (GST_CAPS_FLAGS(caps) & GST_CAPS_FLAGS_ANY)
+  (GST_CAPS_FLAGS(caps) & GST_CAPS_FLAG_ANY)
 
 /* same as gst_caps_is_empty () */
 #define CAPS_IS_EMPTY(caps)                            \
@@ -114,6 +116,8 @@ static gboolean gst_caps_from_string_inplace (GstCaps * caps,
     const gchar * string);
 
 GType _gst_caps_type = 0;
+GstCaps *_gst_caps_any;
+GstCaps *_gst_caps_none;
 
 GST_DEFINE_MINI_OBJECT_TYPE (GstCaps, gst_caps);
 
@@ -122,6 +126,9 @@ _priv_gst_caps_initialize (void)
 {
   _gst_caps_type = gst_caps_get_type ();
 
+  _gst_caps_any = gst_caps_new_any ();
+  _gst_caps_none = gst_caps_new_empty ();
+
   g_value_register_transform_func (_gst_caps_type,
       G_TYPE_STRING, gst_caps_transform_to_string);
 }
@@ -139,6 +146,9 @@ _gst_caps_copy (const GstCaps * caps)
   GST_CAPS_FLAGS (newcaps) = GST_CAPS_FLAGS (caps);
   n = GST_CAPS_LEN (caps);
 
+  GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, caps, "doing copy %p -> %p",
+      caps, newcaps);
+
   for (i = 0; i < n; i++) {
     structure = gst_caps_get_structure_unchecked (caps, i);
     gst_caps_append_structure (newcaps, gst_structure_copy (structure));
@@ -183,10 +193,10 @@ gst_caps_init (GstCaps * caps, gsize size)
 
   /* 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
-   * in practise
+   * in practice
    * GST_CAPS_ARRAY (caps) = g_ptr_array_sized_new (32);
    */
-  caps->priv = g_ptr_array_new ();
+  GST_CAPS_ARRAY (caps) = g_ptr_array_new ();
 }
 
 /**
@@ -194,6 +204,7 @@ gst_caps_init (GstCaps * caps, gsize size)
  *
  * Creates a new #GstCaps that is empty.  That is, the returned
  * #GstCaps contains no media formats.
+ * The #GstCaps is guaranteed to be writable.
  * Caller is responsible for unreffing the returned caps.
  *
  * Returns: (transfer full): the new #GstCaps
@@ -203,9 +214,9 @@ gst_caps_new_empty (void)
 {
   GstCaps *caps;
 
-  caps = g_slice_new (GstCaps);
+  caps = (GstCaps *) g_slice_new (GstCapsImpl);
 
-  gst_caps_init (caps, sizeof (GstCaps));
+  gst_caps_init (caps, sizeof (GstCapsImpl));
 
 #ifdef DEBUG_REFCOUNT
   GST_CAT_TRACE (GST_CAT_CAPS, "created caps %p", caps);
@@ -227,7 +238,7 @@ gst_caps_new_any (void)
 {
   GstCaps *caps = gst_caps_new_empty ();
 
-  GST_CAPS_FLAG_SET (caps, GST_CAPS_FLAGS_ANY);
+  GST_CAPS_FLAG_SET (caps, GST_CAPS_FLAG_ANY);
 
   return caps;
 }
@@ -340,17 +351,7 @@ gst_caps_new_full_valist (GstStructure * structure, va_list var_args)
   return caps;
 }
 
-GType
-gst_static_caps_get_type (void)
-{
-  static GType staticcaps_type = 0;
-
-  if (G_UNLIKELY (staticcaps_type == 0)) {
-    staticcaps_type = g_pointer_type_register_static ("GstStaticCaps");
-  }
-  return staticcaps_type;
-}
-
+G_DEFINE_POINTER_TYPE (GstStaticCaps, gst_static_caps);
 
 /**
  * gst_static_caps_get:
@@ -365,20 +366,19 @@ gst_static_caps_get_type (void)
 GstCaps *
 gst_static_caps_get (GstStaticCaps * static_caps)
 {
-  GstCaps *caps;
+  GstCaps **caps;
 
   g_return_val_if_fail (static_caps != NULL, NULL);
 
-  caps = (GstCaps *) static_caps;
+  caps = &static_caps->caps;
 
   /* refcount is 0 when we need to convert */
-  if (G_UNLIKELY (GST_CAPS_REFCOUNT_VALUE (caps) == 0)) {
+  if (G_UNLIKELY (*caps == NULL)) {
     const char *string;
-    GstCaps temp;
 
     G_LOCK (static_caps_lock);
     /* check if other thread already updated */
-    if (G_UNLIKELY (GST_CAPS_REFCOUNT_VALUE (caps) > 0))
+    if (G_UNLIKELY (*caps != NULL))
       goto done;
 
     string = static_caps->string;
@@ -386,30 +386,22 @@ gst_static_caps_get (GstStaticCaps * static_caps)
     if (G_UNLIKELY (string == NULL))
       goto no_string;
 
-    GST_CAT_TRACE (GST_CAT_CAPS, "creating %p", static_caps);
-
-    /* we construct the caps on the stack, then copy over the struct into our
-     * real caps, refcount last. We do this because we must leave the refcount
-     * of the result caps to 0 so that other threads don't run away with the
-     * caps while we are constructing it. */
-    gst_caps_init (&temp, sizeof (GstCaps));
+    *caps = gst_caps_from_string (string);
 
     /* convert to string */
-    if (G_UNLIKELY (!gst_caps_from_string_inplace (&temp, string)))
+    if (G_UNLIKELY (*caps == NULL))
       g_critical ("Could not convert static caps \"%s\"", string);
 
-    GST_MINI_OBJECT_REFCOUNT (&temp) = 0;
-    memcpy (caps, &temp, sizeof (GstCaps));
-    gst_caps_ref (caps);
-
-    GST_CAT_TRACE (GST_CAT_CAPS, "created %p", static_caps);
+    GST_CAT_TRACE (GST_CAT_CAPS, "created %p from string %s", static_caps,
+        string);
   done:
     G_UNLOCK (static_caps_lock);
   }
   /* ref the caps, makes it not writable */
-  gst_caps_ref (caps);
+  if (G_LIKELY (*caps != NULL))
+    gst_caps_ref (*caps);
 
-  return caps;
+  return *caps;
 
   /* ERRORS */
 no_string:
@@ -422,30 +414,16 @@ no_string:
 
 /**
  * gst_static_caps_cleanup:
- * @static_caps: the #GstStaticCaps to convert
+ * @static_caps: the #GstStaticCaps to clean
  *
- * Clean up the caps contained in @static_caps when the refcount is 0.
+ * Clean up the cached caps contained in @static_caps.
  */
 void
 gst_static_caps_cleanup (GstStaticCaps * static_caps)
 {
-  GstCaps *caps = (GstCaps *) static_caps;
-
-  /* FIXME: this is not threadsafe */
-  if (GST_CAPS_REFCOUNT_VALUE (caps) == 1) {
-    GstStructure *structure;
-    guint i, clen;
-
-    clen = GST_CAPS_LEN (caps);
-
-    for (i = 0; i < clen; i++) {
-      structure = (GstStructure *) gst_caps_get_structure (caps, i);
-      gst_structure_set_parent_refcount (structure, NULL);
-      gst_structure_free (structure);
-    }
-    g_ptr_array_free (GST_CAPS_ARRAY (caps), TRUE);
-    GST_CAPS_REFCOUNT (caps) = 0;
-  }
+  G_LOCK (static_caps_lock);
+  gst_caps_replace (&static_caps->caps, NULL);
+  G_UNLOCK (static_caps_lock);
 }
 
 /* manipulation */
@@ -453,7 +431,7 @@ gst_static_caps_cleanup (GstStaticCaps * static_caps)
 static GstStructure *
 gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
 {
-  /* don't use index_fast, gst_caps_do_simplify relies on the order */
+  /* don't use index_fast, gst_caps_simplify relies on the order */
   GstStructure *s = g_ptr_array_remove_index (GST_CAPS_ARRAY (caps), idx);
 
   gst_structure_set_parent_refcount (s, NULL);
@@ -465,7 +443,7 @@ gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
  * @caps: the #GstCaps to retrieve from
  * @index: Index of the structure to retrieve
  *
- * Retrieves the stucture with the given index from the list of structures
+ * Retrieves the structure with the given index from the list of structures
  * contained in @caps. The caller becomes the owner of the returned structure.
  *
  * Returns: (transfer full): a pointer to the #GstStructure corresponding
@@ -504,64 +482,60 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2)
   g_return_if_fail (GST_IS_CAPS (caps2));
   g_return_if_fail (IS_WRITABLE (caps1));
 
-  caps2 = gst_caps_make_writable (caps2);
-
   if (G_UNLIKELY (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2))) {
-    /* FIXME: this leaks */
-    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAGS_ANY;
-    for (i = GST_CAPS_LEN (caps2) - 1; i >= 0; i--) {
-      structure = gst_caps_remove_and_get_structure (caps2, i);
-      gst_structure_free (structure);
-    }
+    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAG_ANY;
+    gst_caps_unref (caps2);
   } else {
+    caps2 = gst_caps_make_writable (caps2);
+
     for (i = GST_CAPS_LEN (caps2); i; i--) {
       structure = gst_caps_remove_and_get_structure (caps2, 0);
       gst_caps_append_structure_unchecked (caps1, structure);
     }
+    gst_caps_unref (caps2);     /* guaranteed to free it */
   }
-  gst_caps_unref (caps2);       /* guaranteed to free it */
 }
 
 /**
  * gst_caps_merge:
- * @caps1: the #GstCaps that will take the new entries
+ * @caps1: (transfer full): the #GstCaps that will take the new entries
  * @caps2: (transfer full): the #GstCaps to merge in
  *
  * 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
- * transferred to @caps1, and then @caps2 is freed.
+ * transferred to a writable copy of @caps1, and then @caps2 is freed.
  * If either caps is ANY, the resulting caps will be ANY.
  *
+ * Returns: (transfer full): the merged caps.
+ *
  * Since: 0.10.10
  */
-void
+GstCaps *
 gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
 {
   GstStructure *structure;
   int i;
+  GstCaps *result;
 
-  g_return_if_fail (GST_IS_CAPS (caps1));
-  g_return_if_fail (GST_IS_CAPS (caps2));
-  g_return_if_fail (IS_WRITABLE (caps1));
-
-  caps2 = gst_caps_make_writable (caps2);
+  g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
+  g_return_val_if_fail (GST_IS_CAPS (caps2), NULL);
 
   if (G_UNLIKELY (CAPS_IS_ANY (caps1))) {
-    for (i = GST_CAPS_LEN (caps2) - 1; i >= 0; i--) {
-      structure = gst_caps_remove_and_get_structure (caps2, i);
-      gst_structure_free (structure);
-    }
+    gst_caps_unref (caps2);
+    result = caps1;
   } else if (G_UNLIKELY (CAPS_IS_ANY (caps2))) {
-    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAGS_ANY;
-    for (i = GST_CAPS_LEN (caps1) - 1; i >= 0; i--) {
-      structure = gst_caps_remove_and_get_structure (caps1, i);
-      gst_structure_free (structure);
-    }
+    gst_caps_unref (caps1);
+    result = caps2;
   } else {
+    caps2 = gst_caps_make_writable (caps2);
+
     for (i = GST_CAPS_LEN (caps2); i; i--) {
       structure = gst_caps_remove_and_get_structure (caps2, 0);
-      gst_caps_merge_structure (caps1, structure);
+      caps1 = gst_caps_merge_structure (caps1, structure);
     }
+    gst_caps_unref (caps2);
+    result = caps1;
+
     /* this is too naive
        GstCaps *com = gst_caps_intersect (caps1, caps2);
        GstCaps *add = gst_caps_subtract (caps2, com);
@@ -572,7 +546,8 @@ gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
        gst_caps_unref (com);
      */
   }
-  gst_caps_unref (caps2);       /* guaranteed to free it */
+
+  return result;
 }
 
 /**
@@ -617,38 +592,41 @@ gst_caps_remove_structure (GstCaps * caps, guint idx)
 
 /**
  * gst_caps_merge_structure:
- * @caps: the #GstCaps that will the new structure
+ * @caps: (transfer full): the #GstCaps to merge into
  * @structure: (transfer full): the #GstStructure to merge
  *
- * Appends @structure to @caps if its not already expressed by @caps.  The
- * structure is not copied; @caps becomes the owner of @structure.
+ * Appends @structure to @caps if its not already expressed by @caps.
+ *
+ * Returns: (transfer full): the merged caps.
  */
-void
+GstCaps *
 gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
 {
-  g_return_if_fail (GST_IS_CAPS (caps));
-  g_return_if_fail (IS_WRITABLE (caps));
+  GstStructure *structure1;
+  int i;
+  gboolean unique = TRUE;
 
-  if (G_LIKELY (structure)) {
-    GstStructure *structure1;
-    int i;
-    gboolean unique = TRUE;
-
-    /* check each structure */
-    for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
-      structure1 = gst_caps_get_structure_unchecked (caps, i);
-      /* if structure is a subset of structure1, then skip it */
-      if (gst_structure_is_subset (structure, structure1)) {
-        unique = FALSE;
-        break;
-      }
-    }
-    if (unique) {
-      gst_caps_append_structure_unchecked (caps, structure);
-    } else {
-      gst_structure_free (structure);
+  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);
+    /* if structure is a subset of structure1, then skip it */
+    if (gst_structure_is_subset (structure, structure1)) {
+      unique = FALSE;
+      break;
     }
   }
+  if (unique) {
+    caps = gst_caps_make_writable (caps);
+    gst_caps_append_structure_unchecked (caps, structure);
+  } else {
+    gst_structure_free (structure);
+  }
+  return caps;
 }
 
 /**
@@ -731,23 +709,29 @@ gst_caps_copy_nth (const GstCaps * caps, guint nth)
 
 /**
  * gst_caps_truncate:
- * @caps: the #GstCaps to truncate
+ * @caps: (transfer full): the #GstCaps to truncate
  *
- * Destructively discard all but the first structure from @caps. Useful when
- * fixating. @caps must be writable.
+ * Discard all but the first structure from @caps. Useful when
+ * fixating.
+ *
+ * Returns: (transfer full): truncated caps
  */
-void
+GstCaps *
 gst_caps_truncate (GstCaps * caps)
 {
   gint i;
 
-  g_return_if_fail (GST_IS_CAPS (caps));
-  g_return_if_fail (IS_WRITABLE (caps));
+  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
 
   i = GST_CAPS_LEN (caps) - 1;
+  if (i == 0)
+    return caps;
 
+  caps = gst_caps_make_writable (caps);
   while (i > 0)
     gst_caps_remove_structure (caps, i--);
+
+  return caps;
 }
 
 /**
@@ -806,10 +790,6 @@ gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs)
 
     type = va_arg (varargs, GType);
 
-    if (G_UNLIKELY (type == G_TYPE_DATE)) {
-      g_warning ("Don't use G_TYPE_DATE, use GST_TYPE_DATE instead\n");
-      type = GST_TYPE_DATE;
-    }
     G_VALUE_COLLECT_INIT (&value, type, varargs, 0, &err);
     if (G_UNLIKELY (err)) {
       g_critical ("%s", err);
@@ -1064,18 +1044,12 @@ gst_caps_is_subset_structure (const GstCaps * caps,
 gboolean
 gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2)
 {
-  /* FIXME 0.11: NULL pointers are no valid Caps but indicate an error
-   * So there should be an assertion that caps1 and caps2 != NULL */
+  g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
+  g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);
 
-  /* NULL <-> NULL is allowed here */
   if (G_UNLIKELY (caps1 == caps2))
     return TRUE;
 
-  /* one of them NULL => they are different (can't be both NULL because
-   * we checked that above) */
-  if (G_UNLIKELY (caps1 == NULL || caps2 == NULL))
-    return FALSE;
-
   if (G_UNLIKELY (gst_caps_is_fixed (caps1) && gst_caps_is_fixed (caps2)))
     return gst_caps_is_equal_fixed (caps1, caps2);
 
@@ -1099,18 +1073,13 @@ gboolean
 gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2)
 {
   int i;
-  /* FIXME 0.11: NULL pointers are no valid Caps but indicate an error
-   * So there should be an assertion that caps1 and caps2 != NULL */
 
-  /* NULL <-> NULL is allowed here */
+  g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
+  g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);
+
   if (G_UNLIKELY (caps1 == caps2))
     return TRUE;
 
-  /* one of them NULL => they are different (can't be both NULL because
-   * we checked that above) */
-  if (G_UNLIKELY (caps1 == NULL || caps2 == NULL))
-    return FALSE;
-
   if (GST_CAPS_LEN (caps1) != GST_CAPS_LEN (caps2))
     return FALSE;
 
@@ -1164,7 +1133,7 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
    * much better than a simple loop.
    *
    * This algorithm zigzags over the caps structures as demonstrated in
-   * the folowing matrix:
+   * the following matrix:
    *
    *          caps1                              0  1  2  3
    *       +-------------     total distance:  +-------------
@@ -1206,7 +1175,7 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
 }
 
 static GstCaps *
-gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2)
+gst_caps_intersect_zig_zag (GstCaps * caps1, GstCaps * caps2)
 {
   guint64 i;                    /* index can be up to 2 * G_MAX_UINT */
   guint j, k, len1, len2;
@@ -1218,17 +1187,17 @@ gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2)
 
   /* caps are exactly the same pointers, just copy one caps */
   if (G_UNLIKELY (caps1 == caps2))
-    return _gst_caps_copy (caps1);
+    return gst_caps_ref (caps1);
 
   /* empty caps on either side, return empty */
   if (G_UNLIKELY (CAPS_IS_EMPTY (caps1) || CAPS_IS_EMPTY (caps2)))
-    return gst_caps_new_empty ();
+    return gst_caps_ref (GST_CAPS_NONE);
 
   /* one of the caps is any, just copy the other caps */
   if (G_UNLIKELY (CAPS_IS_ANY (caps1)))
-    return _gst_caps_copy (caps2);
+    return gst_caps_ref (caps2);
   if (G_UNLIKELY (CAPS_IS_ANY (caps2)))
-    return _gst_caps_copy (caps1);
+    return gst_caps_ref (caps1);
 
   dest = gst_caps_new_empty ();
 
@@ -1236,7 +1205,7 @@ gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2)
    * much better than a simple loop.
    *
    * This algorithm zigzags over the caps structures as demonstrated in
-   * the folowing matrix:
+   * the following matrix:
    *
    *          caps1
    *       +-------------
@@ -1265,7 +1234,7 @@ gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2)
 
       istruct = gst_structure_intersect (struct1, struct2);
 
-      gst_caps_merge_structure (dest, istruct);
+      dest = gst_caps_merge_structure (dest, istruct);
       /* move down left */
       k++;
       if (G_UNLIKELY (j == 0))
@@ -1290,7 +1259,7 @@ gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2)
  * Returns: the new #GstCaps
  */
 static GstCaps *
-gst_caps_intersect_first (const GstCaps * caps1, const GstCaps * caps2)
+gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2)
 {
   guint i;
   guint j, len1, len2;
@@ -1302,17 +1271,17 @@ gst_caps_intersect_first (const GstCaps * caps1, const GstCaps * caps2)
 
   /* caps are exactly the same pointers, just copy one caps */
   if (G_UNLIKELY (caps1 == caps2))
-    return gst_caps_copy (caps1);
+    return gst_caps_ref (caps1);
 
   /* empty caps on either side, return empty */
   if (G_UNLIKELY (CAPS_IS_EMPTY (caps1) || CAPS_IS_EMPTY (caps2)))
-    return gst_caps_new_empty ();
+    return gst_caps_ref (GST_CAPS_NONE);
 
   /* one of the caps is any, just copy the other caps */
   if (G_UNLIKELY (CAPS_IS_ANY (caps1)))
-    return gst_caps_copy (caps2);
+    return gst_caps_ref (caps2);
   if (G_UNLIKELY (CAPS_IS_ANY (caps2)))
-    return gst_caps_copy (caps1);
+    return gst_caps_ref (caps1);
 
   dest = gst_caps_new_empty ();
 
@@ -1324,7 +1293,7 @@ gst_caps_intersect_first (const GstCaps * caps1, const GstCaps * caps2)
       struct2 = gst_caps_get_structure_unchecked (caps2, j);
       istruct = gst_structure_intersect (struct1, struct2);
       if (istruct)
-        gst_caps_merge_structure (dest, istruct);
+        dest = gst_caps_merge_structure (dest, istruct);
     }
   }
 
@@ -1345,7 +1314,7 @@ gst_caps_intersect_first (const GstCaps * caps1, const GstCaps * caps2)
  * Since: 0.10.33
  */
 GstCaps *
-gst_caps_intersect_full (const GstCaps * caps1, const GstCaps * caps2,
+gst_caps_intersect_full (GstCaps * caps1, GstCaps * caps2,
     GstCapsIntersectMode mode)
 {
   g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
@@ -1373,7 +1342,7 @@ gst_caps_intersect_full (const GstCaps * caps1, const GstCaps * caps2,
  * Returns: the new #GstCaps
  */
 GstCaps *
-gst_caps_intersect (const GstCaps * caps1, const GstCaps * caps2)
+gst_caps_intersect (GstCaps * caps1, GstCaps * caps2)
 {
   return gst_caps_intersect_full (caps1, caps2, GST_CAPS_INTERSECT_ZIG_ZAG);
 }
@@ -1452,7 +1421,7 @@ gst_caps_structure_subtract (GSList ** into, const GstStructure * minuend,
  * Returns: the resulting caps
  */
 GstCaps *
-gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
+gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend)
 {
   guint i, j, sublen;
   GstStructure *min;
@@ -1466,7 +1435,7 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
     return gst_caps_new_empty ();
   }
   if (CAPS_IS_EMPTY_SIMPLE (subtrahend))
-    return _gst_caps_copy (minuend);
+    return gst_caps_ref (minuend);
 
   /* FIXME: Do we want this here or above?
      The reason we need this is that there is no definition about what
@@ -1515,89 +1484,10 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
   }
 
   gst_caps_unref (src);
-  gst_caps_do_simplify (dest);
+  dest = gst_caps_simplify (dest);
   return dest;
 }
 
-/* union operation */
-
-#if 0
-static GstStructure *
-gst_caps_structure_union (const GstStructure * struct1,
-    const GstStructure * struct2)
-{
-  int i;
-  GstStructure *dest;
-  const GstStructureField *field1;
-  const GstStructureField *field2;
-  int ret;
-
-  /* FIXME this doesn't actually work */
-
-  if (struct1->name != struct2->name)
-    return NULL;
-
-  dest = gst_structure_new_id_empty (struct1->name);
-
-  for (i = 0; i < struct1->fields->len; i++) {
-    GValue dest_value = { 0 };
-
-    field1 = GST_STRUCTURE_FIELD (struct1, i);
-    field2 = gst_structure_id_get_field (struct2, field1->name);
-
-    if (field2 == NULL) {
-      continue;
-    } else {
-      if (gst_value_union (&dest_value, &field1->value, &field2->value)) {
-        gst_structure_set_value (dest, g_quark_to_string (field1->name),
-            &dest_value);
-      } else {
-        ret = gst_value_compare (&field1->value, &field2->value);
-      }
-    }
-  }
-
-  return dest;
-}
-#endif
-
-/**
- * gst_caps_union:
- * @caps1: a #GstCaps to union
- * @caps2: a #GstCaps to union
- *
- * Creates a new #GstCaps that contains all the formats that are in
- * either @caps1 and @caps2.
- *
- * Returns: the new #GstCaps
- */
-GstCaps *
-gst_caps_union (const GstCaps * caps1, const GstCaps * caps2)
-{
-  GstCaps *dest1;
-  GstCaps *dest2;
-
-  /* NULL pointers are no correct GstCaps */
-  g_return_val_if_fail (caps1 != NULL, NULL);
-  g_return_val_if_fail (caps2 != NULL, NULL);
-
-  if (CAPS_IS_EMPTY (caps1))
-    return _gst_caps_copy (caps2);
-
-  if (CAPS_IS_EMPTY (caps2))
-    return _gst_caps_copy (caps1);
-
-  if (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2))
-    return gst_caps_new_any ();
-
-  dest1 = _gst_caps_copy (caps1);
-  dest2 = _gst_caps_copy (caps2);
-  gst_caps_append (dest1, dest2);
-
-  gst_caps_do_simplify (dest1);
-  return dest1;
-}
-
 /* normalize/simplify operations */
 
 typedef struct _NormalizeForeach
@@ -1635,34 +1525,36 @@ gst_caps_normalize_foreach (GQuark field_id, const GValue * value, gpointer ptr)
 
 /**
  * gst_caps_normalize:
- * @caps: a #GstCaps to normalize
+ * @caps: (transfer full): a #GstCaps to normalize
  *
- * Creates a new #GstCaps that represents the same set of formats as
+ * Returns a #GstCaps that represents the same set of formats as
  * @caps, but contains no lists.  Each list is expanded into separate
  * @GstStructures.
  *
- * Returns: the new #GstCaps
+ * This function takes ownership of @caps.
+ *
+ * Returns: (transfer full): the normalized #GstCaps
  */
 GstCaps *
-gst_caps_normalize (const GstCaps * caps)
+gst_caps_normalize (GstCaps * caps)
 {
   NormalizeForeach nf;
-  GstCaps *newcaps;
   guint i;
 
   g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
 
-  newcaps = _gst_caps_copy (caps);
-  nf.caps = newcaps;
+  caps = gst_caps_make_writable (caps);
+
+  nf.caps = caps;
 
-  for (i = 0; i < gst_caps_get_size (newcaps); i++) {
-    nf.structure = gst_caps_get_structure_unchecked (newcaps, i);
+  for (i = 0; i < gst_caps_get_size (nf.caps); i++) {
+    nf.structure = gst_caps_get_structure_unchecked (nf.caps, i);
 
     while (!gst_structure_foreach (nf.structure,
             gst_caps_normalize_foreach, &nf));
   }
 
-  return newcaps;
+  return nf.caps;
 }
 
 static gint
@@ -1715,7 +1607,7 @@ gst_caps_structure_figure_out_union (GQuark field_id, const GValue * value,
 
 static gboolean
 gst_caps_structure_simplify (GstStructure ** result,
-    const GstStructure * simplify, GstStructure * compare)
+    GstStructure * simplify, GstStructure * compare)
 {
   GSList *list;
   UnionField field = { 0, {0,}, NULL };
@@ -1738,7 +1630,7 @@ gst_caps_structure_simplify (GstStructure ** result,
 
   /* try to union both structs */
   field.compare = compare;
-  if (gst_structure_foreach ((GstStructure *) simplify,
+  if (gst_structure_foreach (simplify,
           gst_caps_structure_figure_out_union, &field)) {
     gboolean ret = FALSE;
 
@@ -1783,37 +1675,40 @@ gst_caps_switch_structures (GstCaps * caps, GstStructure * old,
 }
 
 /**
- * gst_caps_do_simplify:
- * @caps: a #GstCaps to simplify
+ * gst_caps_simplify:
+ * @caps: (transfer full): a #GstCaps to simplify
  *
- * Modifies the given @caps inplace into a representation that represents the
+ * Converts the given @caps into a representation that represents the
  * same set of formats, but in a simpler form.  Component structures that are
  * identical are merged.  Component structures that have values that can be
  * merged are also merged.
  *
- * Returns: TRUE, if the caps could be simplified
+ * This method does not preserve the original order of @caps.
+ *
+ * Returns: The simplified caps.
  */
-gboolean
-gst_caps_do_simplify (GstCaps * caps)
+GstCaps *
+gst_caps_simplify (GstCaps * caps)
 {
   GstStructure *simplify, *compare, *result = NULL;
   gint i, j, start;
-  gboolean changed = FALSE;
 
-  g_return_val_if_fail (caps != NULL, FALSE);
-  g_return_val_if_fail (IS_WRITABLE (caps), FALSE);
+  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
 
-  if (gst_caps_get_size (caps) < 2)
-    return FALSE;
+  start = GST_CAPS_LEN (caps) - 1;
+  /* one caps, already as simple as can be */
+  if (start == 0)
+    return caps;
+
+  caps = gst_caps_make_writable (caps);
 
   g_ptr_array_sort (GST_CAPS_ARRAY (caps), gst_caps_compare_structures);
 
-  start = GST_CAPS_LEN (caps) - 1;
-  for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
+  for (i = start; i >= 0; i--) {
     simplify = gst_caps_get_structure_unchecked (caps, i);
+    compare = gst_caps_get_structure_unchecked (caps, start);
     if (gst_structure_get_name_id (simplify) !=
-        gst_structure_get_name_id (gst_caps_get_structure_unchecked (caps,
-                start)))
+        gst_structure_get_name_id (compare))
       start = i;
     for (j = start; j >= 0; j--) {
       if (j == i)
@@ -1832,38 +1727,36 @@ gst_caps_do_simplify (GstCaps * caps)
           start--;
           break;
         }
-        changed = TRUE;
       }
     }
   }
-
-  if (!changed)
-    return FALSE;
-
-  /* gst_caps_do_simplify (caps); */
-  return TRUE;
+  return caps;
 }
 
 /**
  * gst_caps_fixate:
- * @caps: a #GstCaps to fixate
+ * @caps: (transfer full): a #GstCaps to fixate
  *
- * Modifies the given @caps inplace into a representation with only fixed
+ * Modifies the given @caps into a representation with only fixed
  * values. First the caps will be truncated and then the first structure will be
- * fixated with gst_structure_fixate(). @caps should be writable.
+ * fixated with gst_structure_fixate().
+ *
+ * Returns: (transfer full): the fixated caps
  */
-void
+GstCaps *
 gst_caps_fixate (GstCaps * caps)
 {
   GstStructure *s;
 
-  g_return_if_fail (GST_IS_CAPS (caps));
-  g_return_if_fail (IS_WRITABLE (caps));
+  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
 
   /* default fixation */
-  gst_caps_truncate (caps);
+  caps = gst_caps_truncate (caps);
+  caps = gst_caps_make_writable (caps);
   s = gst_caps_get_structure (caps, 0);
   gst_structure_fixate (s);
+
+  return caps;
 }
 
 /* utility */
@@ -1879,7 +1772,7 @@ gst_caps_fixate (GstCaps * caps)
  * |[
  * GST_LOG ("caps are %" GST_PTR_FORMAT, caps);
  * ]|
- * This prints the caps in human readble form.
+ * This prints the caps in human readable form.
  *
  * Returns: (transfer full): a newly allocated string representing @caps.
  */
@@ -1940,7 +1833,7 @@ gst_caps_from_string_inplace (GstCaps * caps, const gchar * string)
   gchar *s;
 
   if (strcmp ("ANY", string) == 0) {
-    GST_CAPS_FLAGS (caps) = GST_CAPS_FLAGS_ANY;
+    GST_CAPS_FLAGS (caps) = GST_CAPS_FLAG_ANY;
     return TRUE;
   }
   if (strcmp ("EMPTY", string) == 0) {