docs: convert NULL, TRUE, and FALSE to %NULL, %TRUE, and %FALSE
[platform/upstream/gstreamer.git] / gst / gstvalue.c
index 67f6090..a38cce0 100644 (file)
@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 /**
@@ -26,8 +26,6 @@
  *
  * Note that operations on the same #GValue from multiple threads may lead to
  * undefined behaviour.
- *
- * Last reviewed on 2008-03-11 (0.10.18)
  */
 
 #ifdef HAVE_CONFIG_H
 #include <gobject/gvaluecollector.h>
 #include "gstutils.h"
 
+/* GstValueUnionFunc:
+ * @dest: a #GValue for the result
+ * @value1: a #GValue operand
+ * @value2: a #GValue operand
+ *
+ * Used by gst_value_union() to perform unification for a specific #GValue
+ * type. Register a new implementation with gst_value_register_union_func().
+ *
+ * Returns: %TRUE if a union was successful
+ */
+typedef gboolean (*GstValueUnionFunc) (GValue * dest,
+    const GValue * value1, const GValue * value2);
+
+/* GstValueIntersectFunc:
+ * @dest: (out caller-allocates): a #GValue for the result
+ * @value1: a #GValue operand
+ * @value2: a #GValue operand
+ *
+ * Used by gst_value_intersect() to perform intersection for a specific #GValue
+ * type. If the intersection is non-empty, the result is
+ * placed in @dest and %TRUE is returned.  If the intersection is
+ * empty, @dest is unmodified and %FALSE is returned.
+ * Register a new implementation with gst_value_register_intersect_func().
+ *
+ * Returns: %TRUE if the values can intersect
+ */
+typedef gboolean (*GstValueIntersectFunc) (GValue * dest,
+    const GValue * value1, const GValue * value2);
+
+/* GstValueSubtractFunc:
+ * @dest: (out caller-allocates): a #GValue for the result
+ * @minuend: a #GValue operand
+ * @subtrahend: a #GValue operand
+ *
+ * Used by gst_value_subtract() to perform subtraction for a specific #GValue
+ * type. Register a new implementation with gst_value_register_subtract_func().
+ *
+ * Returns: %TRUE if the subtraction is not empty
+ */
+typedef gboolean (*GstValueSubtractFunc) (GValue * dest,
+    const GValue * minuend, const GValue * subtrahend);
+
+static void gst_value_register_union_func (GType type1,
+    GType type2, GstValueUnionFunc func);
+static void gst_value_register_intersect_func (GType type1,
+    GType type2, GstValueIntersectFunc func);
+static void gst_value_register_subtract_func (GType minuend_type,
+    GType subtrahend_type, GstValueSubtractFunc func);
+
 typedef struct _GstValueUnionInfo GstValueUnionInfo;
 struct _GstValueUnionInfo
 {
@@ -95,6 +142,12 @@ static gchar *gst_string_wrap (const gchar * s);
 static gchar *gst_string_take_and_wrap (gchar * s);
 static gchar *gst_string_unwrap (const gchar * s);
 
+static void gst_value_move (GValue * dest, GValue * src);
+static void _gst_value_list_append_and_take_value (GValue * value,
+    GValue * append_value);
+static void _gst_value_array_append_and_take_value (GValue * value,
+    GValue * append_value);
+
 static inline GstValueTable *
 gst_value_hash_lookup_type (GType type)
 {
@@ -137,10 +190,15 @@ gst_value_serialize_any_list (const GValue * value, const gchar * begin,
   for (i = 0; i < alen; i++) {
     v = &g_array_index (array, GValue, i);
     s_val = gst_value_serialize (v);
-    g_string_append (s, s_val);
-    g_free (s_val);
-    if (i < alen - 1) {
-      g_string_append_len (s, ", ", 2);
+    if (s_val != NULL) {
+      g_string_append (s, s_val);
+      g_free (s_val);
+      if (i < alen - 1) {
+        g_string_append_len (s, ", ", 2);
+      }
+    } else {
+      GST_WARNING ("Could not serialize list/array value of type '%s'",
+          G_VALUE_TYPE_NAME (v));
     }
   }
   g_string_append (s, end);
@@ -353,10 +411,37 @@ gst_value_list_or_array_are_compatible (const GValue * value1,
   return FALSE;
 }
 
+static inline void
+_gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
+{
+  g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
+  memset (append_value, 0, sizeof (GValue));
+}
+
+/**
+ * gst_value_list_append_and_take_value:
+ * @value: a #GValue of type #GST_TYPE_LIST
+ * @append_value: (transfer full): the value to append
+ *
+ * Appends @append_value to the GstValueList in @value.
+ *
+ * Since: 1.2
+ */
+void
+gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
+{
+  g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
+  g_return_if_fail (G_IS_VALUE (append_value));
+  g_return_if_fail (gst_value_list_or_array_are_compatible (value,
+          append_value));
+
+  _gst_value_list_append_and_take_value (value, append_value);
+}
+
 /**
  * gst_value_list_append_value:
  * @value: a #GValue of type #GST_TYPE_LIST
- * @append_value: the value to append
+ * @append_value: (transfer none): the value to append
  *
  * Appends @append_value to the GstValueList in @value.
  */
@@ -458,8 +543,6 @@ gst_value_list_concat (GValue * dest, const GValue * value1,
  * The result will be put into @dest and will either be a list that will not
  * contain any duplicates, or a non-list type (if @value1 and @value2
  * were equal).
- *
- * Since: 0.10.32
  */
 void
 gst_value_list_merge (GValue * dest, const GValue * value1,
@@ -607,6 +690,33 @@ gst_value_array_append_value (GValue * value, const GValue * append_value)
   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
 }
 
+static inline void
+_gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
+{
+  g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
+  memset (append_value, 0, sizeof (GValue));
+}
+
+/**
+ * gst_value_array_append_and_take_value:
+ * @value: a #GValue of type #GST_TYPE_ARRAY
+ * @append_value: (transfer full): the value to append
+ *
+ * Appends @append_value to the GstValueArray in @value.
+ *
+ * Since: 1.2
+ */
+void
+gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
+{
+  g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
+  g_return_if_fail (G_IS_VALUE (append_value));
+  g_return_if_fail (gst_value_list_or_array_are_compatible (value,
+          append_value));
+
+  _gst_value_array_append_and_take_value (value, append_value);
+}
+
 /**
  * gst_value_array_prepend_value:
  * @value: a #GValue of type #GST_TYPE_ARRAY
@@ -940,7 +1050,7 @@ gst_value_get_int_range_min (const GValue * value)
  *
  * Gets the maximum of the range specified by @value.
  *
- * Returns: the maxumum of the range
+ * Returns: the maximum of the range
  */
 gint
 gst_value_get_int_range_max (const GValue * value)
@@ -999,8 +1109,8 @@ gst_value_compare_int_range (const GValue * value1, const GValue * value2)
      and bounds lie on the same value */
   if (n1 > 1) {
     if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) &&
-        INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) &&
-        INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2)) {
+        INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2) &&
+        INT_RANGE_MAX (value1) == INT_RANGE_MAX (value2)) {
       return GST_VALUE_EQUAL;
     }
     return GST_VALUE_UNORDERED;
@@ -1140,8 +1250,6 @@ gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values,
  * @step: the step of the range
  *
  * Sets @value to the range specified by @start, @end and @step.
- *
- * Since: 0.11.0
  */
 void
 gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end,
@@ -1165,8 +1273,6 @@ gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end,
  * @end: the end of the range
  *
  * Sets @value to the range specified by @start and @end.
- *
- * Since: 0.10.31
  */
 void
 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
@@ -1181,8 +1287,6 @@ gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
  * Gets the minimum of the range specified by @value.
  *
  * Returns: the minimum of the range
- *
- * Since: 0.10.31
  */
 gint64
 gst_value_get_int64_range_min (const GValue * value)
@@ -1198,9 +1302,7 @@ gst_value_get_int64_range_min (const GValue * value)
  *
  * Gets the maximum of the range specified by @value.
  *
- * Returns: the maxumum of the range
- *
- * Since: 0.10.31
+ * Returns: the maximum of the range
  */
 gint64
 gst_value_get_int64_range_max (const GValue * value)
@@ -1217,8 +1319,6 @@ gst_value_get_int64_range_max (const GValue * value)
  * Gets the step of the range specified by @value.
  *
  * Returns: the step of the range
- *
- * Since: 0.11.0
  */
 gint64
 gst_value_get_int64_range_step (const GValue * value)
@@ -1264,8 +1364,8 @@ gst_value_compare_int64_range (const GValue * value1, const GValue * value2)
      and bounds lie on the same value */
   if (n1 > 1) {
     if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) &&
-        INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) &&
-        INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2)) {
+        INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2) &&
+        INT64_RANGE_MAX (value1) == INT64_RANGE_MAX (value2)) {
       return GST_VALUE_EQUAL;
     }
     return GST_VALUE_UNORDERED;
@@ -1393,7 +1493,7 @@ gst_value_get_double_range_min (const GValue * value)
  *
  * Gets the maximum of the range specified by @value.
  *
- * Returns: the maxumum of the range
+ * Returns: the maximum of the range
  */
 gdouble
 gst_value_get_double_range_max (const GValue * value)
@@ -1420,7 +1520,7 @@ static gint
 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
 {
   if (value2->data[0].v_double == value1->data[0].v_double &&
-      value2->data[0].v_double == value1->data[0].v_double)
+      value2->data[1].v_double == value1->data[1].v_double)
     return GST_VALUE_EQUAL;
   return GST_VALUE_UNORDERED;
 }
@@ -1770,12 +1870,22 @@ gst_value_get_caps (const GValue * value)
   return (GstCaps *) g_value_get_boxed (value);
 }
 
+static gint
+gst_value_compare_caps (const GValue * value1, const GValue * value2)
+{
+  GstCaps *caps1 = GST_CAPS (gst_value_get_caps (value1));
+  GstCaps *caps2 = GST_CAPS (gst_value_get_caps (value2));
+
+  if (gst_caps_is_equal (caps1, caps2))
+    return GST_VALUE_EQUAL;
+  return GST_VALUE_UNORDERED;
+}
+
 static gchar *
 gst_value_serialize_caps (const GValue * value)
 {
   GstCaps *caps = g_value_get_boxed (value);
-
-  return gst_caps_to_string (caps);
+  return gst_string_take_and_wrap (gst_caps_to_string (caps));
 }
 
 static gboolean
@@ -1783,7 +1893,17 @@ gst_value_deserialize_caps (GValue * dest, const gchar * s)
 {
   GstCaps *caps;
 
-  caps = gst_caps_from_string (s);
+  if (*s != '"') {
+    caps = gst_caps_from_string (s);
+  } else {
+    gchar *str = gst_string_unwrap (s);
+
+    if (G_UNLIKELY (!str))
+      return FALSE;
+
+    caps = gst_caps_from_string (str);
+    g_free (str);
+  }
 
   if (caps) {
     g_value_take_boxed (dest, caps);
@@ -1792,6 +1912,78 @@ gst_value_deserialize_caps (GValue * dest, const gchar * s)
   return FALSE;
 }
 
+/**************
+ * GstSegment *
+ **************/
+
+static gchar *
+gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
+{
+  GstSegment *seg = g_value_get_boxed (value);
+  gchar *t, *res;
+  GstStructure *s;
+
+  s = gst_structure_new ("GstSegment",
+      "flags", GST_TYPE_SEGMENT_FLAGS, seg->flags,
+      "rate", G_TYPE_DOUBLE, seg->rate,
+      "applied-rate", G_TYPE_DOUBLE, seg->applied_rate,
+      "format", GST_TYPE_FORMAT, seg->format,
+      "base", G_TYPE_UINT64, seg->base,
+      "offset", G_TYPE_UINT64, seg->offset,
+      "start", G_TYPE_UINT64, seg->start,
+      "stop", G_TYPE_UINT64, seg->stop,
+      "time", G_TYPE_UINT64, seg->time,
+      "position", G_TYPE_UINT64, seg->position,
+      "duration", G_TYPE_UINT64, seg->duration, NULL);
+  t = gst_structure_to_string (s);
+  if (escape) {
+    res = g_strdup_printf ("\"%s\"", t);
+    g_free (t);
+  } else {
+    res = t;
+  }
+  gst_structure_free (s);
+
+  return res;
+}
+
+static gchar *
+gst_value_serialize_segment (const GValue * value)
+{
+  return gst_value_serialize_segment_internal (value, TRUE);
+}
+
+static gboolean
+gst_value_deserialize_segment (GValue * dest, const gchar * s)
+{
+  GstStructure *str;
+  GstSegment seg;
+  gboolean res;
+
+  str = gst_structure_from_string (s, NULL);
+  if (str == NULL)
+    return FALSE;
+
+  res = gst_structure_get (str,
+      "flags", GST_TYPE_SEGMENT_FLAGS, &seg.flags,
+      "rate", G_TYPE_DOUBLE, &seg.rate,
+      "applied-rate", G_TYPE_DOUBLE, &seg.applied_rate,
+      "format", GST_TYPE_FORMAT, &seg.format,
+      "base", G_TYPE_UINT64, &seg.base,
+      "offset", G_TYPE_UINT64, &seg.offset,
+      "start", G_TYPE_UINT64, &seg.start,
+      "stop", G_TYPE_UINT64, &seg.stop,
+      "time", G_TYPE_UINT64, &seg.time,
+      "position", G_TYPE_UINT64, &seg.position,
+      "duration", G_TYPE_UINT64, &seg.duration, NULL);
+  gst_structure_free (str);
+
+  if (res)
+    g_value_set_boxed (dest, &seg);
+
+  return res;
+}
+
 /****************
  * GstStructure *
  ****************/
@@ -1802,8 +1994,6 @@ gst_value_deserialize_caps (GValue * dest, const gchar * s)
  * @structure: the structure to set the value to
  *
  * Sets the contents of @value to @structure.  The actual
- *
- * Since: 0.10.15
  */
 void
 gst_value_set_structure (GValue * value, const GstStructure * structure)
@@ -1822,8 +2012,6 @@ gst_value_set_structure (GValue * value, const GstStructure * structure)
  * Gets the contents of @value.
  *
  * Returns: (transfer none): the contents of @value
- *
- * Since: 0.10.15
  */
 const GstStructure *
 gst_value_get_structure (const GValue * value)
@@ -1866,18 +2054,126 @@ gst_value_deserialize_structure (GValue * dest, const gchar * s)
   return FALSE;
 }
 
+/*******************
+ * GstCapsFeatures *
+ *******************/
+
+/**
+ * gst_value_set_caps_features:
+ * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
+ * @features: the features to set the value to
+ *
+ * Sets the contents of @value to @features.
+ */
+void
+gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
+{
+  g_return_if_fail (G_IS_VALUE (value));
+  g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
+  g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
+
+  g_value_set_boxed (value, features);
+}
+
+/**
+ * gst_value_get_caps_features:
+ * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
+ *
+ * Gets the contents of @value.
+ *
+ * Returns: (transfer none): the contents of @value
+ */
+const GstCapsFeatures *
+gst_value_get_caps_features (const GValue * value)
+{
+  g_return_val_if_fail (G_IS_VALUE (value), NULL);
+  g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
+
+  return (GstCapsFeatures *) g_value_get_boxed (value);
+}
+
+static gchar *
+gst_value_serialize_caps_features (const GValue * value)
+{
+  GstCapsFeatures *features = g_value_get_boxed (value);
+
+  return gst_string_take_and_wrap (gst_caps_features_to_string (features));
+}
+
+static gboolean
+gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
+{
+  GstCapsFeatures *features;
+
+  if (*s != '"') {
+    features = gst_caps_features_from_string (s);
+  } else {
+    gchar *str = gst_string_unwrap (s);
+
+    if (G_UNLIKELY (!str))
+      return FALSE;
+
+    features = gst_caps_features_from_string (str);
+    g_free (str);
+  }
+
+  if (G_LIKELY (features)) {
+    g_value_take_boxed (dest, features);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**************
+ * GstTagList *
+ **************/
+
+static gboolean
+gst_value_deserialize_tag_list (GValue * dest, const gchar * s)
+{
+  GstTagList *taglist;
+
+  if (*s != '"') {
+    taglist = gst_tag_list_new_from_string (s);
+  } else {
+    gchar *str = gst_string_unwrap (s);
+
+    if (G_UNLIKELY (!str))
+      return FALSE;
+
+    taglist = gst_tag_list_new_from_string (str);
+    g_free (str);
+  }
+
+  if (G_LIKELY (taglist != NULL)) {
+    g_value_take_boxed (dest, taglist);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gchar *
+gst_value_serialize_tag_list (const GValue * value)
+{
+  GstTagList *taglist = g_value_get_boxed (value);
+
+  return gst_string_take_and_wrap (gst_tag_list_to_string (taglist));
+}
+
+
 /*************
  * GstBuffer *
  *************/
 
 static gint
-gst_value_compare_buffer (const GValue * value1, const GValue * value2)
+compare_buffer (GstBuffer * buf1, GstBuffer * buf2)
 {
-  GstBuffer *buf1 = gst_value_get_buffer (value1);
-  GstBuffer *buf2 = gst_value_get_buffer (value2);
   gsize size1, size2;
   GstMapInfo info1, info2;
-  gint result = GST_VALUE_UNORDERED;
+  gint result, mret;
+
+  if (buf1 == buf2)
+    return GST_VALUE_EQUAL;
 
   size1 = gst_buffer_get_size (buf1);
   size2 = gst_buffer_get_size (buf2);
@@ -1892,19 +2188,33 @@ gst_value_compare_buffer (const GValue * value1, const GValue * value2)
     return GST_VALUE_UNORDERED;
 
   if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
-    gst_buffer_unmap (buf1, &info2);
+    gst_buffer_unmap (buf1, &info1);
     return GST_VALUE_UNORDERED;
   }
 
-  if (memcmp (info1.data, info2.data, info1.size) == 0)
+  mret = memcmp (info1.data, info2.data, info1.size);
+  if (mret == 0)
     result = GST_VALUE_EQUAL;
+  else if (mret < 0)
+    result = GST_VALUE_LESS_THAN;
+  else
+    result = GST_VALUE_GREATER_THAN;
 
-  gst_buffer_unmap (buf2, &info1);
-  gst_buffer_unmap (buf1, &info2);
+  gst_buffer_unmap (buf1, &info1);
+  gst_buffer_unmap (buf2, &info2);
 
   return result;
 }
 
+static gint
+gst_value_compare_buffer (const GValue * value1, const GValue * value2)
+{
+  GstBuffer *buf1 = gst_value_get_buffer (value1);
+  GstBuffer *buf2 = gst_value_get_buffer (value2);
+
+  return compare_buffer (buf1, buf2);
+}
+
 static gchar *
 gst_value_serialize_buffer (const GValue * value)
 {
@@ -1948,7 +2258,7 @@ gst_value_deserialize_buffer (GValue * dest, const gchar * s)
   if (len & 1)
     goto wrong_length;
 
-  buffer = gst_buffer_new_allocate (NULL, len / 2, 0);
+  buffer = gst_buffer_new_allocate (NULL, len / 2, NULL);
   if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
     goto map_failed;
   data = info.data;
@@ -1986,6 +2296,163 @@ wrong_char:
   }
 }
 
+/*************
+ * GstSample *
+ *************/
+
+/* This function is mostly used for comparing image/buffer tags in taglists */
+static gint
+gst_value_compare_sample (const GValue * value1, const GValue * value2)
+{
+  GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1));
+  GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2));
+
+  /* FIXME: should we take into account anything else such as caps? */
+  return compare_buffer (buf1, buf2);
+}
+
+static gchar *
+gst_value_serialize_sample (const GValue * value)
+{
+  const GstStructure *info_structure;
+  GstSegment *segment;
+  GstBuffer *buffer;
+  GstCaps *caps;
+  GstSample *sample;
+  GValue val = { 0, };
+  gchar *info_str, *caps_str, *tmp;
+  gchar *buf_str, *seg_str, *s;
+
+  sample = g_value_get_boxed (value);
+
+  buffer = gst_sample_get_buffer (sample);
+  if (buffer) {
+    g_value_init (&val, GST_TYPE_BUFFER);
+    g_value_set_boxed (&val, buffer);
+    buf_str = gst_value_serialize_buffer (&val);
+    g_value_unset (&val);
+  } else {
+    buf_str = g_strdup ("None");
+  }
+
+  caps = gst_sample_get_caps (sample);
+  if (caps) {
+    tmp = gst_caps_to_string (caps);
+    caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
+    g_strdelimit (caps_str, "=", '_');
+    g_free (tmp);
+  } else {
+    caps_str = g_strdup ("None");
+  }
+
+  segment = gst_sample_get_segment (sample);
+  if (segment) {
+    g_value_init (&val, GST_TYPE_SEGMENT);
+    g_value_set_boxed (&val, segment);
+    tmp = gst_value_serialize_segment_internal (&val, FALSE);
+    seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
+    g_strdelimit (seg_str, "=", '_');
+    g_free (tmp);
+    g_value_unset (&val);
+  } else {
+    seg_str = g_strdup ("None");
+  }
+
+  info_structure = gst_sample_get_info (sample);
+  if (info_structure) {
+    tmp = gst_structure_to_string (info_structure);
+    info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
+    g_strdelimit (info_str, "=", '_');
+    g_free (tmp);
+  } else {
+    info_str = g_strdup ("None");
+  }
+
+  s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
+  g_free (buf_str);
+  g_free (caps_str);
+  g_free (seg_str);
+  g_free (info_str);
+
+  return s;
+}
+
+static gboolean
+gst_value_deserialize_sample (GValue * dest, const gchar * s)
+{
+  GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
+  GstStructure *info;
+  GstSample *sample;
+  GstCaps *caps;
+  gboolean ret = FALSE;
+  gchar **fields;
+  gsize outlen;
+  gint len;
+
+  GST_TRACE ("deserialize '%s'", s);
+
+  fields = g_strsplit (s, ":", -1);
+  len = g_strv_length (fields);
+  if (len != 4)
+    goto wrong_length;
+
+  g_value_init (&bval, GST_TYPE_BUFFER);
+  g_value_init (&sval, GST_TYPE_SEGMENT);
+
+  if (!gst_value_deserialize_buffer (&bval, fields[0]))
+    goto fail;
+
+  if (strcmp (fields[1], "None") != 0) {
+    g_strdelimit (fields[1], "_", '=');
+    g_base64_decode_inplace (fields[1], &outlen);
+    GST_TRACE ("caps    : %s", fields[1]);
+    caps = gst_caps_from_string (fields[1]);
+    if (caps == NULL)
+      goto fail;
+  } else {
+    caps = NULL;
+  }
+
+  if (strcmp (fields[2], "None") != 0) {
+    g_strdelimit (fields[2], "_", '=');
+    g_base64_decode_inplace (fields[2], &outlen);
+    GST_TRACE ("segment : %s", fields[2]);
+    if (!gst_value_deserialize_segment (&sval, fields[2]))
+      goto fail;
+  }
+
+  if (strcmp (fields[3], "None") != 0) {
+    g_strdelimit (fields[3], "_", '=');
+    g_base64_decode_inplace (fields[3], &outlen);
+    GST_TRACE ("info    : %s", fields[3]);
+    info = gst_structure_from_string (fields[3], NULL);
+    if (info == NULL)
+      goto fail;
+  } else {
+    info = NULL;
+  }
+
+  sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
+      g_value_get_boxed (&sval), info);
+
+  g_value_take_boxed (dest, sample);
+
+  if (caps)
+    gst_caps_unref (caps);
+
+  ret = TRUE;
+
+fail:
+
+  g_value_unset (&bval);
+  g_value_unset (&sval);
+
+wrong_length:
+
+  g_strfreev (fields);
+
+  return ret;
+}
 
 /***********
  * boolean *
@@ -2063,7 +2530,7 @@ gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
 {
   gboolean ret = FALSE;
   gchar *end;
-  gint64 mask = -1;
+  guint64 mask = ~0;
 
   errno = 0;
   *to = g_ascii_strtoull (s, &end, 0);
@@ -2426,7 +2893,7 @@ gst_string_take_and_wrap (gchar * s)
  * 0->3, y is copied unescaped.
  *
  * If \xyy is found where x is an octal number but y is not, an
- * error is encountered and NULL is returned.
+ * error is encountered and %NULL is returned.
  *
  * the input string must be \0 terminated.
  */
@@ -2624,16 +3091,20 @@ gst_value_deserialize_enum (GValue * dest, const gchar * s)
     found = gst_iterator_find_custom (iter,
         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
 
-    g_return_val_if_fail (found, FALSE);
-    format_def = g_value_get_pointer (&res);
-    g_return_val_if_fail (format_def != NULL, FALSE);
-    g_value_set_enum (dest, (gint) format_def->value);
-    g_value_unset (&res);
+    if (found) {
+      format_def = g_value_get_pointer (&res);
+      g_return_val_if_fail (format_def != NULL, FALSE);
+      g_value_set_enum (dest, (gint) format_def->value);
+      g_value_unset (&res);
+    }
     gst_iterator_free (iter);
-    return TRUE;
+    return found;
   }
 
-  g_return_val_if_fail (en, FALSE);
+  /* enum name/nick not found */
+  if (en == NULL)
+    return FALSE;
+
   g_value_set_enum (dest, en->value);
   return TRUE;
 }
@@ -2683,7 +3154,10 @@ gst_value_serialize_flags (const GValue * value)
   /* if no flags are set, try to serialize to the _NONE string */
   if (!flags) {
     fl = g_flags_get_first_value (klass, flags);
-    return g_strdup (fl->value_name);
+    if (fl)
+      return g_strdup (fl->value_name);
+    else
+      return g_strdup ("0");
   }
 
   /* some flags are set, so serialize one by one */
@@ -2812,6 +3286,15 @@ gst_value_is_subset_int64_range_int64_range (const GValue * value1,
   return TRUE;
 }
 
+/**
+ * gst_value_is_subset:
+ * @value1: a #GValue
+ * @value2: a #GValue
+ *
+ * Check that @value1 is a subset of @value2.
+ *
+ * Return: %TRUE is @value1 is a subset of @value2
+ */
 gboolean
 gst_value_is_subset (const GValue * value1, const GValue * value2)
 {
@@ -3032,13 +3515,16 @@ gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
   return FALSE;
 }
 
+#define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
+#define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
+
 static gboolean
 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
     const GValue * src2)
 {
-  if (INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2) <= src1->data[0].v_int &&
-      INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2) >= src1->data[0].v_int &&
-      src1->data[0].v_int % INT64_RANGE_STEP (src2) == 0) {
+  if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
+      INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
+      src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
     if (dest)
       gst_value_init_and_copy (dest, src1);
     return TRUE;
@@ -3156,19 +3642,18 @@ gst_value_intersect_list (GValue * dest, const GValue * value1,
     if (gst_value_intersect (&intersection, cur, value2)) {
       /* append value */
       if (!ret) {
-        gst_value_init_and_copy (dest, &intersection);
+        gst_value_move (dest, &intersection);
         ret = TRUE;
       } else if (GST_VALUE_HOLDS_LIST (dest)) {
-        gst_value_list_append_value (dest, &intersection);
+        _gst_value_list_append_and_take_value (dest, &intersection);
       } else {
-        GValue temp = { 0, };
+        GValue temp;
 
-        gst_value_init_and_copy (&temp, dest);
-        g_value_unset (dest);
-        gst_value_list_concat (dest, &temp, &intersection);
+        gst_value_move (&temp, dest);
+        gst_value_list_merge (dest, &temp, &intersection);
         g_value_unset (&temp);
+        g_value_unset (&intersection);
       }
-      g_value_unset (&intersection);
     }
   }
 
@@ -3207,8 +3692,7 @@ gst_value_intersect_array (GValue * dest, const GValue * src1,
       g_value_unset (dest);
       return FALSE;
     }
-    gst_value_array_append_value (dest, &val);
-    g_value_unset (&val);
+    _gst_value_array_append_and_take_value (dest, &val);
   }
 
   return TRUE;
@@ -3307,6 +3791,9 @@ gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
   gint step = gst_value_get_int_range_step (subtrahend);
   gint val = g_value_get_int (minuend);
 
+  if (step == 0)
+    return FALSE;
+
   /* subtracting a range from an int only works if the int is not in the
    * range */
   if (val < min || val > max || val % step) {
@@ -3384,6 +3871,9 @@ gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
 
   g_return_val_if_fail (min < max, FALSE);
 
+  if (step == 0)
+    return FALSE;
+
   /* value is outside of the range, return range unchanged */
   if (val < min || val > max || val % step) {
     if (dest)
@@ -3425,6 +3915,9 @@ gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
   }
   step = step1;
 
+  if (step == 0)
+    return FALSE;
+
   if (max2 >= max1 && min2 <= min1) {
     return FALSE;
   } else if (max2 >= max1) {
@@ -3448,6 +3941,8 @@ gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
   gint64 step = gst_value_get_int64_range_step (subtrahend);
   gint64 val = g_value_get_int64 (minuend);
 
+  if (step == 0)
+    return FALSE;
   /* subtracting a range from an int64 only works if the int64 is not in the
    * range */
   if (val < min || val > max || val % step) {
@@ -3525,6 +4020,9 @@ gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
 
   g_return_val_if_fail (min < max, FALSE);
 
+  if (step == 0)
+    return FALSE;
+
   /* value is outside of the range, return range unchanged */
   if (val < min || val > max || val % step) {
     if (dest)
@@ -3565,6 +4063,10 @@ gst_value_subtract_int64_range_int64_range (GValue * dest,
     g_assert (FALSE);
     return FALSE;
   }
+
+  if (step1 == 0)
+    return FALSE;
+
   step = step1;
 
   if (max2 >= max1 && min2 <= min1) {
@@ -3681,20 +4183,19 @@ gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
 
     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
       if (!ret) {
-        gst_value_init_and_copy (dest, &subtraction);
+        gst_value_move (dest, &subtraction);
         ret = TRUE;
       } else if (G_VALUE_HOLDS (dest, ltype)
           && !G_VALUE_HOLDS (&subtraction, ltype)) {
-        gst_value_list_append_value (dest, &subtraction);
+        _gst_value_list_append_and_take_value (dest, &subtraction);
       } else {
-        GValue temp = { 0, };
+        GValue temp;
 
-        gst_value_init_and_copy (&temp, dest);
-        g_value_unset (dest);
+        gst_value_move (&temp, dest);
         gst_value_list_concat (dest, &temp, &subtraction);
         g_value_unset (&temp);
+        g_value_unset (&subtraction);
       }
-      g_value_unset (&subtraction);
     }
   }
   return ret;
@@ -3724,9 +4225,11 @@ gst_value_subtract_list (GValue * dest, const GValue * minuend,
       return FALSE;
     }
   }
-  if (dest)
-    gst_value_init_and_copy (dest, result);
-  g_value_unset (result);
+  if (dest) {
+    gst_value_move (dest, result);
+  } else {
+    g_value_unset (result);
+  }
   return TRUE;
 }
 
@@ -3884,7 +4387,7 @@ gst_value_get_compare_func (const GValue * value1)
  *
  * Determines if @value1 and @value2 can be compared.
  *
- * Returns: TRUE if the values can be compared
+ * Returns: %TRUE if the values can be compared
  */
 gboolean
 gst_value_can_compare (const GValue * value1, const GValue * value2)
@@ -3921,6 +4424,8 @@ gst_value_list_equals_range (const GValue * list, const GValue * value)
     const gint rmin = gst_value_get_int_range_min (value);
     const gint rmax = gst_value_get_int_range_max (value);
     const gint rstep = gst_value_get_int_range_step (value);
+    if (rstep == 0)
+      return FALSE;
     /* note: this will overflow for min 0 and max INT_MAX, but this
        would only be equal to a list of INT_MAX elements, which seems
        very unlikely */
@@ -3938,6 +4443,8 @@ gst_value_list_equals_range (const GValue * list, const GValue * value)
     const gint64 rmax = gst_value_get_int64_range_max (value);
     const gint64 rstep = gst_value_get_int64_range_step (value);
     GST_DEBUG ("List/range of int64s");
+    if (rstep == 0)
+      return FALSE;
     if (list_size != rmax / rstep - rmin / rstep + 1)
       return FALSE;
     for (n = 0; n < list_size; ++n) {
@@ -3979,24 +4486,51 @@ gst_value_compare (const GValue * value1, const GValue * value2)
      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
   ltype = gst_value_list_get_type ();
   if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype)) {
+    gint i, n, ret;
 
     if (gst_value_list_equals_range (value1, value2)) {
       return GST_VALUE_EQUAL;
-    } else if (gst_value_list_get_size (value1) == 1) {
+    }
+
+    n = gst_value_list_get_size (value1);
+    if (n == 0)
+      return GST_VALUE_UNORDERED;
+
+    for (i = 0; i < n; i++) {
       const GValue *elt;
 
-      elt = gst_value_list_get_value (value1, 0);
-      return gst_value_compare (elt, value2);
+      elt = gst_value_list_get_value (value1, i);
+      ret = gst_value_compare (elt, value2);
+      if (ret != GST_VALUE_EQUAL && n == 1)
+        return ret;
+      else if (ret != GST_VALUE_EQUAL)
+        return GST_VALUE_UNORDERED;
     }
+
+    return GST_VALUE_EQUAL;
   } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype)) {
+    gint i, n, ret;
+
     if (gst_value_list_equals_range (value2, value1)) {
       return GST_VALUE_EQUAL;
-    } else if (gst_value_list_get_size (value2) == 1) {
+    }
+
+    n = gst_value_list_get_size (value2);
+    if (n == 0)
+      return GST_VALUE_UNORDERED;
+
+    for (i = 0; i < n; i++) {
       const GValue *elt;
 
-      elt = gst_value_list_get_value (value2, 0);
-      return gst_value_compare (elt, value1);
+      elt = gst_value_list_get_value (value2, i);
+      ret = gst_value_compare (elt, value1);
+      if (ret != GST_VALUE_EQUAL && n == 1)
+        return ret;
+      else if (ret != GST_VALUE_EQUAL)
+        return GST_VALUE_UNORDERED;
     }
+
+    return GST_VALUE_EQUAL;
   }
 
   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
@@ -4045,13 +4579,13 @@ gst_value_compare_with_func (const GValue * value1, const GValue * value2,
  *
  * Determines if @value1 and @value2 can be non-trivially unioned.
  * Any two values can be trivially unioned by adding both of them
- * to a GstValueList.  However, certain types have the possibility
+ * to a #GstValueList.  However, certain types have the possibility
  * to be unioned in a simpler way.  For example, an integer range
  * and an integer can be unioned if the integer is a subset of the
  * integer range.  If there is the possibility that two values can
- * be unioned, this function returns TRUE.
+ * be unioned, this function returns %TRUE.
  *
- * Returns: TRUE if there is a function allowing the two values to
+ * Returns: %TRUE if there is a function allowing the two values to
  * be unioned.
  */
 gboolean
@@ -4086,7 +4620,7 @@ gst_value_can_union (const GValue * value1, const GValue * value2)
  *
  * Creates a GValue corresponding to the union of @value1 and @value2.
  *
- * Returns: TRUE if the union suceeded.
+ * Returns: %TRUE if the union succeeded.
  */
 gboolean
 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
@@ -4119,8 +4653,7 @@ gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
   return TRUE;
 }
 
-/**
- * gst_value_register_union_func: (skip)
+/* gst_value_register_union_func: (skip)
  * @type1: a type to union
  * @type2: another type to union
  * @func: a function that implements creating a union between the two types
@@ -4132,7 +4665,7 @@ gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
  * started, as gst_value_register_union_func() is not thread-safe and cannot
  * be used at the same time as gst_value_union() or gst_value_can_union().
  */
-void
+static void
 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
 {
   GstValueUnionInfo union_info;
@@ -4153,10 +4686,9 @@ gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
  *
  * Determines if intersecting two values will produce a valid result.
  * Two values will produce a valid intersection if they have the same
- * type, or if there is a method (registered by
- * gst_value_register_intersect_func()) to calculate the intersection.
+ * type.
  *
- * Returns: TRUE if the values can intersect
+ * Returns: %TRUE if the values can intersect
  */
 gboolean
 gst_value_can_intersect (const GValue * value1, const GValue * value2)
@@ -4198,16 +4730,16 @@ gst_value_can_intersect (const GValue * value1, const GValue * value2)
 /**
  * gst_value_intersect:
  * @dest: (out caller-allocates) (transfer full): a uninitialized #GValue that will hold the calculated
- * intersection value. May be NULL if the resulting set if not needed.
+ * intersection value. May be %NULL if the resulting set if not needed.
  * @value1: a value to intersect
  * @value2: another value to intersect
  *
  * Calculates the intersection of two values.  If the values have
  * a non-empty intersection, the value representing the intersection
- * is placed in @dest, unless NULL.  If the intersection is non-empty,
+ * is placed in @dest, unless %NULL.  If the intersection is non-empty,
  * @dest is not modified.
  *
- * Returns: TRUE if the intersection is non-empty
+ * Returns: %TRUE if the intersection is non-empty
  */
 gboolean
 gst_value_intersect (GValue * dest, const GValue * value1,
@@ -4253,8 +4785,7 @@ gst_value_intersect (GValue * dest, const GValue * value1,
 
 
 
-/**
- * gst_value_register_intersect_func: (skip)
+/* gst_value_register_intersect_func: (skip)
  * @type1: the first type to intersect
  * @type2: the second type to intersect
  * @func: the intersection function
@@ -4267,7 +4798,7 @@ gst_value_intersect (GValue * dest, const GValue * value1,
  * cannot be used at the same time as gst_value_intersect() or
  * gst_value_can_intersect().
  */
-void
+static void
 gst_value_register_intersect_func (GType type1, GType type2,
     GstValueIntersectFunc func)
 {
@@ -4286,7 +4817,7 @@ gst_value_register_intersect_func (GType type1, GType type2,
 /**
  * gst_value_subtract:
  * @dest: (out caller-allocates): the destination value for the result if the
- *     subtraction is not empty. May be NULL, in which case the resulting set
+ *     subtraction is not empty. May be %NULL, in which case the resulting set
  *     will not be computed, which can give a fair speedup.
  * @minuend: the value to subtract from
  * @subtrahend: the value to subtract
@@ -4356,7 +4887,7 @@ gst_value_subtract (GValue * dest, const GValue * minuend,
  *
  * Checks if it's possible to subtract @subtrahend from @minuend.
  *
- * Returns: TRUE if a subtraction is possible
+ * Returns: %TRUE if a subtraction is possible
  */
 gboolean
 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
@@ -4387,8 +4918,7 @@ gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
   return gst_value_can_compare (minuend, subtrahend);
 }
 
-/**
- * gst_value_register_subtract_func: (skip)
+/* gst_value_register_subtract_func: (skip)
  * @minuend_type: type of the minuend
  * @subtrahend_type: type of the subtrahend
  * @func: function to use
@@ -4400,17 +4930,14 @@ gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
  * started, as gst_value_register_subtract_func() is not thread-safe and
  * cannot be used at the same time as gst_value_subtract().
  */
-void
+static void
 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
     GstValueSubtractFunc func)
 {
   GstValueSubtractInfo info;
 
-  /* one type must be unfixed, other subtractions can be done as comparisons,
-   * special case: bitmasks */
-  if (minuend_type != GST_TYPE_BITMASK)
-    g_return_if_fail (!gst_type_is_fixed (minuend_type)
-        || !gst_type_is_fixed (subtrahend_type));
+  g_return_if_fail (!gst_type_is_fixed (minuend_type)
+      || !gst_type_is_fixed (subtrahend_type));
 
   info.minuend = minuend_type;
   info.subtrahend = subtrahend_type;
@@ -4462,6 +4989,17 @@ gst_value_init_and_copy (GValue * dest, const GValue * src)
   g_value_copy (src, dest);
 }
 
+/* move src into dest and clear src */
+static void
+gst_value_move (GValue * dest, GValue * src)
+{
+  g_assert (G_IS_VALUE (src));
+  g_assert (dest != NULL);
+
+  *dest = *src;
+  memset (src, 0, sizeof (GValue));
+}
+
 /**
  * gst_value_serialize:
  * @value: a #GValue to serialize
@@ -4471,7 +5009,7 @@ gst_value_init_and_copy (GValue * dest, const GValue * src)
  *
  * Free-function: g_free
  *
- * Returns: (transfer full): the serialization for @value or NULL if none exists
+ * Returns: (transfer full): the serialization for @value or %NULL if none exists
  */
 gchar *
 gst_value_serialize (const GValue * value)
@@ -4520,9 +5058,9 @@ gst_value_serialize (const GValue * value)
  * @src: string to deserialize
  *
  * Tries to deserialize a string into the type specified by the given GValue.
- * If the operation succeeds, TRUE is returned, FALSE otherwise.
+ * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
  *
- * Returns: TRUE on success
+ * Returns: %TRUE on success
  */
 gboolean
 gst_value_deserialize (GValue * dest, const gchar * src)
@@ -4604,9 +5142,9 @@ gst_value_is_fixed (const GValue * value)
  * Fixate @src into a new value @dest.
  * For ranges, the first element is taken. For lists and arrays, the
  * first item is fixated and returned.
- * If @src is already fixed, this function returns FALSE.
+ * If @src is already fixed, this function returns %FALSE.
  *
- * Returns: true if @dest contains a fixated version of @src.
+ * Returns: %TRUE if @dest contains a fixated version of @src.
  */
 gboolean
 gst_value_fixate (GValue * dest, const GValue * src)
@@ -4631,9 +5169,11 @@ gst_value_fixate (GValue * dest, const GValue * src)
 
     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
 
-    if (!gst_value_fixate (dest, &temp))
-      gst_value_init_and_copy (dest, &temp);
-    g_value_unset (&temp);
+    if (!gst_value_fixate (dest, &temp)) {
+      gst_value_move (dest, &temp);
+    } else {
+      g_value_unset (&temp);
+    }
   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
     gboolean res = FALSE;
     guint n, len;
@@ -4648,8 +5188,7 @@ gst_value_fixate (GValue * dest, const GValue * src)
         gst_value_init_and_copy (&kid, orig_kid);
       else
         res = TRUE;
-      gst_value_array_append_value (dest, &kid);
-      g_value_unset (&kid);
+      _gst_value_array_append_and_take_value (dest, &kid);
     }
 
     if (!res)
@@ -4809,7 +5348,7 @@ gst_value_get_fraction_denominator (const GValue * value)
  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
  * @product to the product of the two fractions.
  *
- * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
+ * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
  */
 gboolean
 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
@@ -4843,7 +5382,7 @@ gst_value_fraction_multiply (GValue * product, const GValue * factor1,
  *
  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
  *
- * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
+ * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
  */
 gboolean
 gst_value_fraction_subtract (GValue * dest,
@@ -5094,7 +5633,6 @@ gst_value_compare_date_time (const GValue * value1, const GValue * value2)
 {
   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
-  gint ret;
 
   if (date1 == date2)
     return GST_VALUE_EQUAL;
@@ -5106,64 +5644,37 @@ gst_value_compare_date_time (const GValue * value1, const GValue * value2)
     return GST_VALUE_LESS_THAN;
   }
 
-  ret = priv_gst_date_time_compare (date1, date2);
-
-  if (ret == 0)
-    return GST_VALUE_EQUAL;
-  else if (ret < 0)
-    return GST_VALUE_LESS_THAN;
-  else
-    return GST_VALUE_GREATER_THAN;
+  /* returns GST_VALUE_* */
+  return __gst_date_time_compare (date1, date2);
 }
 
 static gchar *
 gst_value_serialize_date_time (const GValue * val)
 {
   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
-  gfloat offset;
-  gint tzhour, tzminute;
 
   if (date == NULL)
     return g_strdup ("null");
 
-  offset = gst_date_time_get_time_zone_offset (date);
-
-  tzhour = (gint) ABS (offset);
-  tzminute = (gint) ((ABS (offset) - tzhour) * 60);
-
-  return g_strdup_printf ("\"%04d-%02d-%02dT%02d:%02d:%02d.%06d"
-      "%c%02d%02d\"", gst_date_time_get_year (date),
-      gst_date_time_get_month (date), gst_date_time_get_day (date),
-      gst_date_time_get_hour (date), gst_date_time_get_minute (date),
-      gst_date_time_get_second (date), gst_date_time_get_microsecond (date),
-      offset >= 0 ? '+' : '-', tzhour, tzminute);
+  return __gst_date_time_serialize (date, TRUE);
 }
 
 static gboolean
 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
 {
-  gint year, month, day, hour, minute, second, usecond;
-  gchar signal;
-  gint offset = 0;
-  gfloat tzoffset = 0;
-  gint ret;
+  GstDateTime *datetime;
 
   if (!s || strcmp (s, "null") == 0) {
     return FALSE;
   }
 
-  ret = sscanf (s, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%c%04d",
-      &year, &month, &day, &hour, &minute, &second, &usecond, &signal, &offset);
-  if (ret >= 9) {
-    tzoffset = (offset / 100) + ((offset % 100) / 60.0);
-    if (signal == '-')
-      tzoffset = -tzoffset;
-  } else
-    return FALSE;
-
-  g_value_take_boxed (dest, gst_date_time_new (tzoffset, year, month, day, hour,
-          minute, second + (usecond / 1000000.0)));
-  return TRUE;
+  datetime = gst_date_time_new_from_iso8601_string (s);
+  if (datetime != NULL) {
+    g_value_take_boxed (dest, datetime);
+    return TRUE;
+  }
+  GST_WARNING ("Failed to deserialize date time string '%s'", s);
+  return FALSE;
 }
 
 static void
@@ -5226,7 +5737,7 @@ gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
 
 /**
  * gst_value_set_bitmask:
- * @value: a GValue initialized to #GST_TYPE_FRACTION
+ * @value: a GValue initialized to #GST_TYPE_BITMASK
  * @bitmask: the bitmask
  *
  * Sets @value to the bitmask specified by @bitmask.
@@ -5241,7 +5752,7 @@ gst_value_set_bitmask (GValue * value, guint64 bitmask)
 
 /**
  * gst_value_get_bitmask:
- * @value: a GValue initialized to #GST_TYPE_FRACTION
+ * @value: a GValue initialized to #GST_TYPE_BITMASK
  *
  * Gets the bitmask specified by @value.
  *
@@ -5315,65 +5826,58 @@ gst_value_transform_bitmask_uint64 (const GValue * src_value,
   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
 }
 
-static gboolean
-gst_value_intersect_bitmask_bitmask (GValue * dest, const GValue * src1,
-    const GValue * src2)
+static gint
+gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
 {
-  guint64 s1, s2;
+  guint64 v1, v2;
 
-  s1 = gst_value_get_bitmask (src1);
-  s2 = gst_value_get_bitmask (src2);
+  v1 = value1->data[0].v_uint64;
+  v2 = value2->data[0].v_uint64;
 
-  if (dest) {
-    g_value_init (dest, GST_TYPE_BITMASK);
-    gst_value_set_bitmask (dest, s1 & s2);
-  }
+  if (v1 == v2)
+    return GST_VALUE_EQUAL;
 
-  return TRUE;
+  return GST_VALUE_UNORDERED;
 }
 
-static gboolean
-gst_value_union_bitmask_bitmask (GValue * dest, const GValue * src1,
-    const GValue * src2)
+
+/***********************
+ * GstAllocationParams *
+ ***********************/
+static gint
+gst_value_compare_allocation_params (const GValue * value1,
+    const GValue * value2)
 {
-  guint64 s1, s2;
+  GstAllocationParams *v1, *v2;
 
-  s1 = gst_value_get_bitmask (src1);
-  s2 = gst_value_get_bitmask (src2);
+  v1 = value1->data[0].v_pointer;
+  v2 = value2->data[0].v_pointer;
 
-  g_value_init (dest, GST_TYPE_BITMASK);
-  gst_value_set_bitmask (dest, s1 | s2);
+  if (v1 == NULL && v1 == v2)
+    return GST_VALUE_EQUAL;
 
-  return TRUE;
-}
+  if (v1 == NULL || v2 == NULL)
+    return GST_VALUE_UNORDERED;
 
-static gboolean
-gst_value_subtract_bitmask_bitmask (GValue * dest,
-    const GValue * minuend, const GValue * subtrahend)
-{
-  guint64 m, s, r;
+  if (v1->flags == v2->flags && v1->align == v2->align &&
+      v1->prefix == v2->prefix && v1->padding == v2->padding)
+    return GST_VALUE_EQUAL;
 
-  g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (minuend), FALSE);
-  g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (subtrahend), FALSE);
+  return GST_VALUE_UNORDERED;
+}
 
-  m = minuend->data[0].v_uint64;
-  s = subtrahend->data[0].v_uint64;
-  r = m & (~s);
 
-  if (dest) {
-    g_value_init (dest, GST_TYPE_BITMASK);
-    gst_value_set_bitmask (dest, r);
-  }
-  return (r != 0);
-}
+/************
+ * GObject *
+ ************/
 
 static gint
-gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
+gst_value_compare_object (const GValue * value1, const GValue * value2)
 {
-  guint64 v1, v2;
+  gpointer v1, v2;
 
-  v1 = value1->data[0].v_uint64;
-  v2 = value2->data[0].v_uint64;
+  v1 = value1->data[0].v_pointer;
+  v2 = value2->data[0].v_pointer;
 
   if (v1 == v2)
     return GST_VALUE_EQUAL;
@@ -5541,6 +6045,25 @@ static const GTypeValueTable _gst_bitmask_value_table = {
 
 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
 
+GType
+gst_g_thread_get_type (void)
+{
+#if GLIB_CHECK_VERSION(2,35,3)
+  return G_TYPE_THREAD;
+#else
+  static volatile gsize type_id = 0;
+
+  if (g_once_init_enter (&type_id)) {
+    GType tmp =
+        g_boxed_type_register_static (g_intern_static_string ("GstGThread"),
+        (GBoxedCopyFunc) g_thread_ref,
+        (GBoxedFreeFunc) g_thread_unref);
+    g_once_init_leave (&type_id, tmp);
+  }
+
+  return type_id;
+#endif
+}
 
 void
 _priv_gst_value_initialize (void)
@@ -5652,6 +6175,17 @@ _priv_gst_value_initialize (void)
   {
     static GstValueTable gst_value = {
       0,
+      gst_value_compare_sample,
+      gst_value_serialize_sample,
+      gst_value_deserialize_sample,
+    };
+
+    gst_value.type = GST_TYPE_SAMPLE;
+    gst_value_register (&gst_value);
+  }
+  {
+    static GstValueTable gst_value = {
+      0,
       gst_value_compare_fraction,
       gst_value_serialize_fraction,
       gst_value_deserialize_fraction,
@@ -5663,7 +6197,7 @@ _priv_gst_value_initialize (void)
   {
     static GstValueTable gst_value = {
       0,
-      NULL,
+      gst_value_compare_caps,
       gst_value_serialize_caps,
       gst_value_deserialize_caps,
     };
@@ -5675,6 +6209,17 @@ _priv_gst_value_initialize (void)
     static GstValueTable gst_value = {
       0,
       NULL,
+      gst_value_serialize_segment,
+      gst_value_deserialize_segment,
+    };
+
+    gst_value.type = GST_TYPE_SEGMENT;
+    gst_value_register (&gst_value);
+  }
+  {
+    static GstValueTable gst_value = {
+      0,
+      NULL,
       gst_value_serialize_structure,
       gst_value_deserialize_structure,
     };
@@ -5685,6 +6230,28 @@ _priv_gst_value_initialize (void)
   {
     static GstValueTable gst_value = {
       0,
+      NULL,
+      gst_value_serialize_caps_features,
+      gst_value_deserialize_caps_features,
+    };
+
+    gst_value.type = GST_TYPE_CAPS_FEATURES;
+    gst_value_register (&gst_value);
+  }
+  {
+    static GstValueTable gst_value = {
+      0,
+      NULL,
+      gst_value_serialize_tag_list,
+      gst_value_deserialize_tag_list,
+    };
+
+    gst_value.type = GST_TYPE_TAG_LIST;
+    gst_value_register (&gst_value);
+  }
+  {
+    static GstValueTable gst_value = {
+      0,
       gst_value_compare_date,
       gst_value_serialize_date,
       gst_value_deserialize_date,
@@ -5717,6 +6284,30 @@ _priv_gst_value_initialize (void)
     gst_value_register (&gst_value);
   }
 
+  {
+    static GstValueTable gst_value = {
+      0,
+      gst_value_compare_allocation_params,
+      NULL,
+      NULL,
+    };
+
+    gst_value.type = gst_allocation_params_get_type ();
+    gst_value_register (&gst_value);
+  }
+
+  {
+    static GstValueTable gst_value = {
+      0,
+      gst_value_compare_object,
+      NULL,
+      NULL,
+    };
+
+    gst_value.type = G_TYPE_OBJECT;
+    gst_value_register (&gst_value);
+  }
+
   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
 
@@ -5795,8 +6386,6 @@ _priv_gst_value_initialize (void)
   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
       GST_TYPE_FRACTION_RANGE,
       gst_value_intersect_fraction_range_fraction_range);
-  gst_value_register_intersect_func (GST_TYPE_BITMASK,
-      GST_TYPE_BITMASK, gst_value_intersect_bitmask_bitmask);
 
   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
       gst_value_subtract_int_int_range);
@@ -5823,8 +6412,6 @@ _priv_gst_value_initialize (void)
   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
       GST_TYPE_FRACTION_RANGE,
       gst_value_subtract_fraction_range_fraction_range);
-  gst_value_register_subtract_func (GST_TYPE_BITMASK,
-      GST_TYPE_BITMASK, gst_value_subtract_bitmask_bitmask);
 
   /* see bug #317246, #64994, #65041 */
   {
@@ -5837,8 +6424,6 @@ _priv_gst_value_initialize (void)
       gst_value_union_int_int_range);
   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
       gst_value_union_int_range_int_range);
-  gst_value_register_union_func (GST_TYPE_BITMASK,
-      GST_TYPE_BITMASK, gst_value_union_bitmask_bitmask);
 
 #if 0
   /* Implement these if needed */