gst: add some performance logging
[platform/upstream/gstreamer.git] / gst / gstcaps.c
index 56ca30a..d40bd0f 100644 (file)
@@ -43,8 +43,8 @@
  *  <title>Creating caps</title>
  *  <programlisting>
  *  GstCaps *caps;
- *  caps = gst_caps_new_simple ("video/x-raw-yuv",
- *       "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
+ *  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,
 
 #define DEBUG_REFCOUNT
 
+typedef struct _GstCapsImpl
+{
+  GstCaps caps;
+
+  GPtrArray *array;
+} GstCapsImpl;
+
+#define GST_CAPS_ARRAY(c) (((GstCapsImpl *)(c))->array)
+
+#define GST_CAPS_LEN(c)   (GST_CAPS_ARRAY(c)->len)
+
 #define IS_WRITABLE(caps) \
   (GST_CAPS_REFCOUNT_VALUE (caps) == 1)
 
 /* 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)                            \
   (!CAPS_IS_ANY(caps) && CAPS_IS_EMPTY_SIMPLE(caps))
 
 #define CAPS_IS_EMPTY_SIMPLE(caps)                                     \
-  (((caps)->structs == NULL) || ((caps)->structs->len == 0))
+  ((GST_CAPS_ARRAY (caps) == NULL) || (GST_CAPS_LEN (caps) == 0))
 
 /* 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) \
-     ((GstStructure *)g_ptr_array_index ((caps)->structs, (index)))
+     ((GstStructure *)g_ptr_array_index (GST_CAPS_ARRAY (caps), (index)))
 /* quick way to append a structure without checking the args */
 #define gst_caps_append_structure_unchecked(caps, structure) G_STMT_START{\
   GstStructure *__s=structure;                                      \
   if (gst_structure_set_parent_refcount (__s, &GST_MINI_OBJECT_REFCOUNT(caps)))         \
-    g_ptr_array_add (caps->structs, __s);                             \
+    g_ptr_array_add (GST_CAPS_ARRAY (caps), __s);                             \
 }G_STMT_END
 
 /* lock to protect multiple invocations of static caps to caps conversion */
@@ -109,11 +120,18 @@ 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);
 
 void
-_gst_caps_initialize (void)
+_priv_gst_caps_initialize (void)
 {
-  _gst_caps_type = gst_mini_object_register ("GstCaps");
+  _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);
@@ -130,7 +148,10 @@ _gst_caps_copy (const GstCaps * caps)
 
   newcaps = gst_caps_new_empty ();
   GST_CAPS_FLAGS (newcaps) = GST_CAPS_FLAGS (caps);
-  n = caps->structs->len;
+  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);
@@ -149,7 +170,7 @@ _gst_caps_free (GstCaps * caps)
 
   /* The refcount must be 0, but since we're only called by gst_caps_unref,
    * don't bother testing. */
-  len = caps->structs->len;
+  len = GST_CAPS_LEN (caps);
   /* 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++) {
@@ -157,7 +178,7 @@ _gst_caps_free (GstCaps * caps)
     gst_structure_set_parent_refcount (structure, NULL);
     gst_structure_free (structure);
   }
-  g_ptr_array_free (caps->structs, TRUE);
+  g_ptr_array_free (GST_CAPS_ARRAY (caps), TRUE);
 
 #ifdef DEBUG_REFCOUNT
   GST_CAT_LOG (GST_CAT_CAPS, "freeing caps %p", caps);
@@ -177,9 +198,9 @@ 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
-   * caps->structs = g_ptr_array_sized_new (32);
+   * GST_CAPS_ARRAY (caps) = g_ptr_array_sized_new (32);
    */
-  caps->structs = g_ptr_array_new ();
+  GST_CAPS_ARRAY (caps) = g_ptr_array_new ();
 }
 
 /**
@@ -196,12 +217,12 @@ 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_LOG (GST_CAT_CAPS, "created caps %p", caps);
+  GST_CAT_TRACE (GST_CAT_CAPS, "created caps %p", caps);
 #endif
 
   return caps;
@@ -220,7 +241,31 @@ 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;
+}
+
+/**
+ * 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 ();
+  structure = gst_structure_new_empty (media_type);
+  if (structure)
+    gst_caps_append_structure_unchecked (caps, structure);
 
   return caps;
 }
@@ -309,54 +354,7 @@ gst_caps_new_full_valist (GstStructure * structure, va_list var_args)
   return caps;
 }
 
-/**
- * gst_caps_make_writable:
- * @caps: (transfer full): the #GstCaps to make writable
- *
- * Returns a writable copy of @caps.
- *
- * If there is only one reference count on @caps, the caller must be the owner,
- * and so this function will return the caps object unchanged. If on the other
- * hand there is more than one reference on the object, a new caps object will
- * be returned. The caller's reference on @caps will be removed, and instead the
- * caller will own a reference to the returned object.
- *
- * In short, this function unrefs the caps in the argument and refs the caps
- * that it returns. Don't access the argument after calling this function. See
- * also: gst_caps_ref().
- *
- * Returns: (transfer full): the same #GstCaps object.
- */
-GstCaps *
-gst_caps_make_writable (GstCaps * caps)
-{
-  GstCaps *copy;
-
-  g_return_val_if_fail (caps != NULL, NULL);
-
-  /* we are the only instance reffing this caps */
-  if (IS_WRITABLE (caps))
-    return caps;
-
-  /* else copy */
-  GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy caps");
-  copy = _gst_caps_copy (caps);
-  gst_caps_unref (caps);
-
-  return copy;
-}
-
-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:
@@ -371,20 +369,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;
@@ -392,31 +389,22 @@ gst_static_caps_get (GstStaticCaps * static_caps)
     if (G_UNLIKELY (string == NULL))
       goto no_string;
 
-    GST_CAT_LOG (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_caps_init (caps, sizeof (GstCaps));
-    /* now copy stuff over to the real caps. */
-    GST_CAPS_FLAGS (caps) = GST_CAPS_FLAGS (&temp);
-    caps->structs = temp.structs;
-
-    GST_CAT_LOG (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:
@@ -427,13 +415,27 @@ no_string:
   }
 }
 
+/**
+ * gst_static_caps_cleanup:
+ * @static_caps: the #GstStaticCaps to clean
+ *
+ * Clean up the cached caps contained in @static_caps.
+ */
+void
+gst_static_caps_cleanup (GstStaticCaps * static_caps)
+{
+  G_LOCK (static_caps_lock);
+  gst_caps_replace (&static_caps->caps, NULL);
+  G_UNLOCK (static_caps_lock);
+}
+
 /* manipulation */
 
 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 */
-  GstStructure *s = g_ptr_array_remove_index (caps->structs, idx);
+  GstStructure *s = g_ptr_array_remove_index (GST_CAPS_ARRAY (caps), idx);
 
   gst_structure_set_parent_refcount (s, NULL);
   return s;
@@ -458,7 +460,7 @@ gst_caps_steal_structure (GstCaps * caps, guint index)
   g_return_val_if_fail (caps != NULL, NULL);
   g_return_val_if_fail (IS_WRITABLE (caps), NULL);
 
-  if (G_UNLIKELY (index >= caps->structs->len))
+  if (G_UNLIKELY (index >= GST_CAPS_LEN (caps)))
     return NULL;
 
   return gst_caps_remove_and_get_structure (caps, index);
@@ -482,17 +484,18 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2)
   g_return_if_fail (GST_IS_CAPS (caps1));
   g_return_if_fail (GST_IS_CAPS (caps2));
   g_return_if_fail (IS_WRITABLE (caps1));
-  g_return_if_fail (IS_WRITABLE (caps2));
+
+  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 = caps2->structs->len - 1; i >= 0; i--) {
+    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAG_ANY;
+    for (i = GST_CAPS_LEN (caps2) - 1; i >= 0; i--) {
       structure = gst_caps_remove_and_get_structure (caps2, i);
       gst_structure_free (structure);
     }
   } else {
-    for (i = caps2->structs->len; i; i--) {
+    for (i = GST_CAPS_LEN (caps2); i; i--) {
       structure = gst_caps_remove_and_get_structure (caps2, 0);
       gst_caps_append_structure_unchecked (caps1, structure);
     }
@@ -521,21 +524,22 @@ gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
   g_return_if_fail (GST_IS_CAPS (caps1));
   g_return_if_fail (GST_IS_CAPS (caps2));
   g_return_if_fail (IS_WRITABLE (caps1));
-  g_return_if_fail (IS_WRITABLE (caps2));
+
+  caps2 = gst_caps_make_writable (caps2);
 
   if (G_UNLIKELY (CAPS_IS_ANY (caps1))) {
-    for (i = caps2->structs->len - 1; i >= 0; i--) {
+    for (i = GST_CAPS_LEN (caps2) - 1; i >= 0; i--) {
       structure = gst_caps_remove_and_get_structure (caps2, i);
       gst_structure_free (structure);
     }
   } else if (G_UNLIKELY (CAPS_IS_ANY (caps2))) {
-    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAGS_ANY;
-    for (i = caps1->structs->len - 1; i >= 0; i--) {
+    GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAG_ANY;
+    for (i = GST_CAPS_LEN (caps1) - 1; i >= 0; i--) {
       structure = gst_caps_remove_and_get_structure (caps1, i);
       gst_structure_free (structure);
     }
   } else {
-    for (i = caps2->structs->len; i; i--) {
+    for (i = GST_CAPS_LEN (caps2); i; i--) {
       structure = gst_caps_remove_and_get_structure (caps2, 0);
       gst_caps_merge_structure (caps1, structure);
     }
@@ -594,7 +598,7 @@ gst_caps_remove_structure (GstCaps * caps, guint idx)
 
 /**
  * gst_caps_merge_structure:
- * @caps: the #GstCaps that will the the new structure
+ * @caps: the #GstCaps that will the new structure
  * @structure: (transfer full): the #GstStructure to merge
  *
  * Appends @structure to @caps if its not already expressed by @caps.  The
@@ -612,7 +616,7 @@ gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
     gboolean unique = TRUE;
 
     /* check each structure */
-    for (i = caps->structs->len - 1; i >= 0; i--) {
+    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)) {
@@ -641,7 +645,7 @@ gst_caps_get_size (const GstCaps * caps)
 {
   g_return_val_if_fail (GST_IS_CAPS (caps), 0);
 
-  return caps->structs->len;
+  return GST_CAPS_LEN (caps);
 }
 
 /**
@@ -671,7 +675,7 @@ GstStructure *
 gst_caps_get_structure (const GstCaps * caps, guint index)
 {
   g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
-  g_return_val_if_fail (index < caps->structs->len, NULL);
+  g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL);
 
   return gst_caps_get_structure_unchecked (caps, index);
 }
@@ -697,7 +701,7 @@ gst_caps_copy_nth (const GstCaps * caps, guint nth)
   newcaps = gst_caps_new_empty ();
   GST_CAPS_FLAGS (newcaps) = GST_CAPS_FLAGS (caps);
 
-  if (G_LIKELY (caps->structs->len > nth)) {
+  if (G_LIKELY (GST_CAPS_LEN (caps) > nth)) {
     structure = gst_caps_get_structure_unchecked (caps, nth);
     gst_caps_append_structure_unchecked (newcaps,
         gst_structure_copy (structure));
@@ -721,7 +725,7 @@ gst_caps_truncate (GstCaps * caps)
   g_return_if_fail (GST_IS_CAPS (caps));
   g_return_if_fail (IS_WRITABLE (caps));
 
-  i = caps->structs->len - 1;
+  i = GST_CAPS_LEN (caps) - 1;
 
   while (i > 0)
     gst_caps_remove_structure (caps, i--);
@@ -749,7 +753,7 @@ gst_caps_set_value (GstCaps * caps, const char *field, const GValue * value)
   g_return_if_fail (field != NULL);
   g_return_if_fail (G_IS_VALUE (value));
 
-  len = caps->structs->len;
+  len = GST_CAPS_LEN (caps);
   for (i = 0; i < len; i++) {
     GstStructure *structure = gst_caps_get_structure_unchecked (caps, i);
     gst_structure_set_value (structure, field, value);
@@ -783,10 +787,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);
@@ -888,7 +888,7 @@ gst_caps_is_fixed (const GstCaps * caps)
 
   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
 
-  if (caps->structs->len != 1)
+  if (GST_CAPS_LEN (caps) != 1)
     return FALSE;
 
   structure = gst_caps_get_structure_unchecked (caps, 0);
@@ -966,8 +966,8 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset)
   if (CAPS_IS_ANY (subset) || CAPS_IS_EMPTY (superset))
     return FALSE;
 
-  for (i = subset->structs->len - 1; i >= 0; i--) {
-    for (j = superset->structs->len - 1; j >= 0; j--) {
+  for (i = GST_CAPS_LEN (subset) - 1; i >= 0; i--) {
+    for (j = GST_CAPS_LEN (superset) - 1; j >= 0; j--) {
       s1 = gst_caps_get_structure_unchecked (subset, i);
       s2 = gst_caps_get_structure_unchecked (superset, j);
       if (gst_structure_is_subset (s1, s2)) {
@@ -997,7 +997,7 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset)
  *
  * Returns: %TRUE if @structure is a subset of @caps
  *
- * Since: 0.10.35
+ * Since: 0.10.36
  */
 gboolean
 gst_caps_is_subset_structure (const GstCaps * caps,
@@ -1014,7 +1014,7 @@ gst_caps_is_subset_structure (const GstCaps * caps,
   if (CAPS_IS_EMPTY (caps))
     return FALSE;
 
-  for (i = caps->structs->len - 1; i >= 0; i--) {
+  for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
     s = gst_caps_get_structure_unchecked (caps, i);
     if (gst_structure_is_subset (structure, s)) {
       /* If we found a superset return TRUE */
@@ -1059,6 +1059,47 @@ gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2)
   return gst_caps_is_subset (caps1, caps2) && gst_caps_is_subset (caps2, caps1);
 }
 
+/**
+ * gst_caps_is_strictly_equal:
+ * @caps1: a #GstCaps
+ * @caps2: another #GstCaps
+ *
+ * Checks if the given caps are exactly the same set of caps.
+ *
+ * This function deals correctly with passing NULL for any of the caps.
+ *
+ * Returns: TRUE if both caps are strictly equal.
+ *
+ * Since: 0.10.36
+ */
+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 */
+  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;
+
+  for (i = 0; i < GST_CAPS_LEN (caps1); i++) {
+    if (!gst_structure_is_equal (gst_caps_get_structure_unchecked (caps1, i),
+            gst_caps_get_structure_unchecked (caps2, i)))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
 /* intersect operation */
 
 /**
@@ -1113,14 +1154,14 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
    * structures. The result is that the intersections are ordered based on the
    * sum of the indexes in the list.
    */
-  len1 = caps1->structs->len;
-  len2 = caps2->structs->len;
+  len1 = GST_CAPS_LEN (caps1);
+  len2 = GST_CAPS_LEN (caps2);
   for (i = 0; i < len1 + len2 - 1; i++) {
     /* superset index goes from 0 to sgst_caps_structure_intersectuperset->structs->len-1 */
     j = MIN (i, len1 - 1);
     /* subset index stays 0 until i reaches superset->structs->len, then it
      * counts up from 1 to subset->structs->len - 1 */
-    k = MAX (0, i - j);
+    k = (i > j) ? (i - j) : 0;  /* MAX (0, i - j) */
 
     /* now run the diagonal line, end condition is the left or bottom
      * border */
@@ -1184,14 +1225,14 @@ gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2)
    * the structures diagonally down, then we iterate over the caps2
    * structures.
    */
-  len1 = caps1->structs->len;
-  len2 = caps2->structs->len;
+  len1 = GST_CAPS_LEN (caps1);
+  len2 = GST_CAPS_LEN (caps2);
   for (i = 0; i < len1 + len2 - 1; i++) {
-    /* caps1 index goes from 0 to caps1->structs->len-1 */
+    /* caps1 index goes from 0 to GST_CAPS_LEN (caps1)-1 */
     j = MIN (i, len1 - 1);
-    /* caps2 index stays 0 until i reaches caps1->structs->len, then it counts
-     * up from 1 to caps2->structs->len - 1 */
-    k = MAX (0, i - j);
+    /* caps2 index stays 0 until i reaches GST_CAPS_LEN (caps1), then it counts
+     * up from 1 to GST_CAPS_LEN (caps2) - 1 */
+    k = (i > j) ? (i - j) : 0;  /* MAX (0, i - j) */
 
     /* now run the diagonal line, end condition is the left or bottom
      * border */
@@ -1228,7 +1269,7 @@ gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2)
 static GstCaps *
 gst_caps_intersect_first (const GstCaps * caps1, const GstCaps * caps2)
 {
-  guint64 i;                    /* index can be up to 2 * G_MAX_UINT */
+  guint i;
   guint j, len1, len2;
 
   GstStructure *struct1;
@@ -1252,8 +1293,8 @@ gst_caps_intersect_first (const GstCaps * caps1, const GstCaps * caps2)
 
   dest = gst_caps_new_empty ();
 
-  len1 = caps1->structs->len;
-  len2 = caps2->structs->len;
+  len1 = GST_CAPS_LEN (caps1);
+  len2 = GST_CAPS_LEN (caps2);
   for (i = 0; i < len1; i++) {
     struct1 = gst_caps_get_structure_unchecked (caps1, i);
     for (j = 0; j < len2; j++) {
@@ -1378,8 +1419,8 @@ gst_caps_structure_subtract (GSList ** into, const GstStructure * minuend,
 
 /**
  * gst_caps_subtract:
- * @minuend: #GstCaps to substract from
- * @subtrahend: #GstCaps to substract
+ * @minuend: #GstCaps to subtract from
+ * @subtrahend: #GstCaps to subtract
  *
  * Subtracts the @subtrahend from the @minuend.
  * <note>This function does not work reliably if optional properties for caps
@@ -1410,7 +1451,7 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
      You can only remove everything or nothing and that is done above.
      Note: there's a test that checks this behaviour. */
   g_return_val_if_fail (!CAPS_IS_ANY (minuend), NULL);
-  sublen = subtrahend->structs->len;
+  sublen = GST_CAPS_LEN (subtrahend);
   g_assert (sublen > 0);
 
   src = _gst_caps_copy (minuend);
@@ -1423,7 +1464,7 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
       src = dest;
     }
     dest = gst_caps_new_empty ();
-    srclen = src->structs->len;
+    srclen = GST_CAPS_LEN (src);
     for (j = 0; j < srclen; j++) {
       min = gst_caps_get_structure_unchecked (src, j);
       if (gst_structure_get_name_id (min) == gst_structure_get_name_id (sub)) {
@@ -1473,7 +1514,7 @@ gst_caps_structure_union (const GstStructure * struct1,
   if (struct1->name != struct2->name)
     return NULL;
 
-  dest = gst_structure_id_empty_new (struct1->name);
+  dest = gst_structure_new_id_empty (struct1->name);
 
   for (i = 0; i < struct1->fields->len; i++) {
     GValue dest_value = { 0 };
@@ -1715,7 +1756,7 @@ gst_caps_switch_structures (GstCaps * caps, GstStructure * old,
   gst_structure_set_parent_refcount (old, NULL);
   gst_structure_free (old);
   gst_structure_set_parent_refcount (new, &GST_CAPS_REFCOUNT (caps));
-  g_ptr_array_index (caps->structs, i) = new;
+  g_ptr_array_index (GST_CAPS_ARRAY (caps), i) = new;
 }
 
 /**
@@ -1742,10 +1783,10 @@ gst_caps_do_simplify (GstCaps * caps)
   if (gst_caps_get_size (caps) < 2)
     return FALSE;
 
-  g_ptr_array_sort (caps->structs, gst_caps_compare_structures);
+  g_ptr_array_sort (GST_CAPS_ARRAY (caps), gst_caps_compare_structures);
 
-  start = caps->structs->len - 1;
-  for (i = caps->structs->len - 1; i >= 0; i--) {
+  start = GST_CAPS_LEN (caps) - 1;
+  for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
     simplify = gst_caps_get_structure_unchecked (caps, i);
     if (gst_structure_get_name_id (simplify) !=
         gst_structure_get_name_id (gst_caps_get_structure_unchecked (caps,
@@ -1780,42 +1821,30 @@ gst_caps_do_simplify (GstCaps * caps)
   return TRUE;
 }
 
-/* utility */
-
 /**
- * gst_caps_replace:
- * @caps: (inout) (transfer full): a pointer to #GstCaps
- * @newcaps: a #GstCaps to replace *caps
- *
- * Replaces *caps with @newcaps.  Unrefs the #GstCaps in the location
- * pointed to by @caps, if applicable, then modifies @caps to point to
- * @newcaps. An additional ref on @newcaps is taken.
+ * gst_caps_fixate:
+ * @caps: a #GstCaps to fixate
  *
- * This function does not take any locks so you might want to lock
- * the object owning @caps pointer.
+ * Modifies the given @caps inplace 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.
  */
 void
-gst_caps_replace (GstCaps ** caps, GstCaps * newcaps)
+gst_caps_fixate (GstCaps * caps)
 {
-  GstCaps *oldcaps;
-
-  g_return_if_fail (caps != NULL);
-
-  oldcaps = *caps;
-
-  GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p, %p -> %p", caps, oldcaps, newcaps);
-
-  if (newcaps != oldcaps) {
-    if (newcaps)
-      gst_caps_ref (newcaps);
+  GstStructure *s;
 
-    *caps = newcaps;
+  g_return_if_fail (GST_IS_CAPS (caps));
+  g_return_if_fail (IS_WRITABLE (caps));
 
-    if (oldcaps)
-      gst_caps_unref (oldcaps);
-  }
+  /* default fixation */
+  gst_caps_truncate (caps);
+  s = gst_caps_get_structure (caps, 0);
+  gst_structure_fixate (s);
 }
 
+/* utility */
+
 /**
  * gst_caps_to_string:
  * @caps: a #GstCaps
@@ -1855,7 +1884,7 @@ gst_caps_to_string (const GstCaps * caps)
 
   /* estimate a rough string length to avoid unnecessary reallocs in GString */
   slen = 0;
-  clen = caps->structs->len;
+  clen = GST_CAPS_LEN (caps);
   for (i = 0; i < clen; i++) {
     slen +=
         STRUCTURE_ESTIMATED_STRING_LEN (gst_caps_get_structure_unchecked (caps,
@@ -1888,7 +1917,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) {
@@ -1952,6 +1981,6 @@ gst_caps_transform_to_string (const GValue * src_value, GValue * dest_value)
   g_return_if_fail (G_VALUE_HOLDS (dest_value, G_TYPE_STRING)
       || G_VALUE_HOLDS (dest_value, G_TYPE_POINTER));
 
-  dest_value->data[0].v_pointer =
-      gst_caps_to_string (src_value->data[0].v_pointer);
+  g_value_take_string (dest_value,
+      gst_caps_to_string (gst_value_get_caps (src_value)));
 }