check/gst/gstvalue.c: Added subtract checks.
authorWim Taymans <wim.taymans@gmail.com>
Tue, 16 Aug 2005 09:42:50 +0000 (09:42 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 16 Aug 2005 09:42:50 +0000 (09:42 +0000)
Original commit message from CVS:
* check/gst/gstvalue.c: (GST_START_TEST), (gst_value_suite):
Added subtract checks.

* docs/design/part-events.txt:
Some more docs about newsegment

* gst/gstbin.c: (gst_bin_change_state), (bin_bus_handler):
Fix FIXME

* gst/gstcaps.c: (gst_caps_to_string):
Add comments, cleanups.

* gst/gstelement.c: (gst_element_save_thyself):
cleanups

* gst/gstvalue.c: (gst_value_collect_int_range),
(gst_string_unwrap), (gst_value_union_int_int_range),
(gst_value_union_int_range_int_range),
(gst_value_intersect_int_int_range),
(gst_value_intersect_int_range_int_range),
(gst_value_intersect_double_double_range),
(gst_value_intersect_double_range_double_range),
(gst_value_intersect_list), (gst_value_subtract_int_int_range),
(gst_value_subtract_int_range_int),
(gst_value_subtract_double_range_double),
(gst_value_subtract_double_range_double_range),
(gst_value_subtract_from_list), (gst_value_subtract_list),
(gst_value_can_compare), (gst_value_compare_fraction):
Cleanups, add comments, remove unneeded asserts.

ChangeLog
check/gst/gstvalue.c
docs/design/part-events.txt
gst/gstbin.c
gst/gstcaps.c
gst/gstelement.c
gst/gstvalue.c
tests/check/gst/gstvalue.c

index 6f86ff6..7516eb8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2005-08-16  Wim Taymans  <wim@fluendo.com>
+
+       * check/gst/gstvalue.c: (GST_START_TEST), (gst_value_suite):
+       Added subtract checks.
+
+       * docs/design/part-events.txt:
+       Some more docs about newsegment
+
+       * gst/gstbin.c: (gst_bin_change_state), (bin_bus_handler):
+       Fix FIXME
+
+       * gst/gstcaps.c: (gst_caps_to_string):
+       Add comments, cleanups.
+       
+       * gst/gstelement.c: (gst_element_save_thyself):
+       cleanups
+       
+       * gst/gstvalue.c: (gst_value_collect_int_range),
+       (gst_string_unwrap), (gst_value_union_int_int_range),
+       (gst_value_union_int_range_int_range),
+       (gst_value_intersect_int_int_range),
+       (gst_value_intersect_int_range_int_range),
+       (gst_value_intersect_double_double_range),
+       (gst_value_intersect_double_range_double_range),
+       (gst_value_intersect_list), (gst_value_subtract_int_int_range),
+       (gst_value_subtract_int_range_int),
+       (gst_value_subtract_double_range_double),
+       (gst_value_subtract_double_range_double_range),
+       (gst_value_subtract_from_list), (gst_value_subtract_list),
+       (gst_value_can_compare), (gst_value_compare_fraction):
+       Cleanups, add comments, remove unneeded asserts.
+
 2005-08-15  Thomas Vander Stichele  <thomas at apestaart dot org>
 
        * tools/gst-launch.c: (event_loop):
index 7a6fcdb..4dc3dae 100644 (file)
@@ -411,9 +411,9 @@ GST_START_TEST (test_value_intersect)
   g_value_init (&src1, G_TYPE_INT);
   g_value_set_int (&src1, 10);
   g_value_init (&src2, G_TYPE_INT);
-  g_value_set_int (&src1, 20);
+  g_value_set_int (&src2, 20);
   ret = gst_value_intersect (&dest, &src1, &src2);
-  fail_unless (ret == 0);
+  fail_unless (ret == FALSE);
   g_value_unset (&src1);
   g_value_unset (&src2);
 
@@ -436,6 +436,489 @@ GST_START_TEST (test_value_intersect)
 
 GST_END_TEST;
 
+
+GST_START_TEST (test_value_subtract_int)
+{
+  GValue dest = { 0 };
+  GValue src1 = { 0 };
+  GValue src2 = { 0 };
+  const GValue *tmp;
+  gboolean ret;
+
+  /*  int <-> int 
+   */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 10);
+  g_value_init (&src2, G_TYPE_INT);
+  g_value_set_int (&src2, 20);
+  /* subtract as in sets, result is 10 */
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* same values, yields empty set */
+  ret = gst_value_subtract (&dest, &src1, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  int <-> int_range 
+   */
+
+  /* would yield an empty set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 10);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 0, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should create a list of two ranges. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 0);
+  fail_unless (gst_value_get_int_range_max (tmp) == 9);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 11);
+  fail_unless (gst_value_get_int_range_max (tmp) == 20);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 1, empty set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 10);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should create a new range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 11);
+  fail_unless (gst_value_get_int_range_max (&dest) == 20);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 2, empty set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should create a new range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 19);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* case 3, valid set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 0);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (G_VALUE_HOLDS_INT (&dest) == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* and the other way around, should keep the range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 20);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  int_range <-> int_range 
+   */
+
+  /* same range, empty set */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* non overlapping ranges */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 30, 40);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 20);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 30);
+  fail_unless (gst_value_get_int_range_max (&dest) == 40);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* completely overlapping ranges */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 30);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 21);
+  fail_unless (gst_value_get_int_range_max (&dest) == 30);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* partially overlapping ranges */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 15, 30);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 14);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 21);
+  fail_unless (gst_value_get_int_range_max (&dest) == 30);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole { int_range, int_range } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 15, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 10);
+  fail_unless (gst_value_get_int_range_max (tmp) == 14);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 21);
+  fail_unless (gst_value_get_int_range_max (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole, { int, int } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 11, 29);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 10);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole, { int, int_range } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 11, 28);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 10);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 29);
+  fail_unless (gst_value_get_int_range_max (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole, { int_range, int } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 12, 29);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 10);
+  fail_unless (gst_value_get_int_range_max (tmp) == 11);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_value_subtract_double)
+{
+  GValue dest = { 0 };
+  GValue src1 = { 0 };
+  GValue src2 = { 0 };
+  const GValue *tmp;
+  gboolean ret;
+
+  /*  double <-> double 
+   */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 10.0);
+  g_value_init (&src2, G_TYPE_DOUBLE);
+  g_value_set_double (&src2, 20.0);
+  /* subtract as in sets, result is 10 */
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* same values, yields empty set */
+  ret = gst_value_subtract (&dest, &src1, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  double <-> double_range 
+   */
+
+  /* would yield an empty set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 10.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 0.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, we cannot create open ranges
+   * so the result is the range again */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 0.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 1, empty set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 10.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should keep same range as
+   * we don't have open ranges. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 2, empty set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should keep same range as
+   * we don't have open ranges. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* case 3, valid set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 0.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (G_VALUE_HOLDS_DOUBLE (&dest) == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* and the other way around, should keep the range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  double_range <-> double_range 
+   */
+
+  /* same range, empty set */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* non overlapping ranges */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 30.0, 40.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 30.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 40.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* completely overlapping ranges */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 30.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 20.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 30.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* partially overlapping ranges */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 15.0, 30.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 15.0);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 20.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 30.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole { double_range, double_range } */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 30.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 15.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_double_range_min (tmp) == 10.0);
+  fail_unless (gst_value_get_double_range_max (tmp) == 15.0);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_double_range_min (tmp) == 20.0);
+  fail_unless (gst_value_get_double_range_max (tmp) == 30.0);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+}
+
+GST_END_TEST;
+
 Suite *
 gst_value_suite (void)
 {
@@ -453,6 +936,9 @@ gst_value_suite (void)
   tcase_add_test (tc_chain, test_deserialize_string);
   tcase_add_test (tc_chain, test_value_compare);
   tcase_add_test (tc_chain, test_value_intersect);
+  tcase_add_test (tc_chain, test_value_subtract_int);
+  tcase_add_test (tc_chain, test_value_subtract_double);
+
   return s;
 }
 
index ed671f4..bc7eef5 100644 (file)
@@ -122,6 +122,11 @@ Buffers should be clipped within the range indicated by the newsegment event
 start and stop values. Sinks are allowed to drop buffers with timestamps out
 of the indicated newsegment range.
 
+If a newsegment arrives at an element not preceeded by a flush event, the 
+streamtime of the pipeline will not be reset to 0 so any element that syncs
+to the clock must use the stop times of the previous newsegment events to
+make the buffer timestamps increasing.
+
 
 SEEK
 ----
index 5ffd72c..bbb9c8e 100644 (file)
@@ -1175,9 +1175,9 @@ restart:
 
     GST_LOCK (bin);
     if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
-      /* FIXME: we reffed some children already, are we leaking refcounts
-       * in that case ? */
       GST_INFO_OBJECT (bin, "bin->children_cookie changed, restarting");
+      /* restart will unref the children in the queues so that we don't
+       * leak refcounts. */
       goto restart;
     }
     children = g_list_next (children);
@@ -1439,14 +1439,12 @@ gst_bin_send_event (GstElement * element, GstEvent * event)
   return res;
 }
 
-/* FIXME, make me threadsafe */
 static GstBusSyncReply
 bin_bus_handler (GstBus * bus, GstMessage * message, GstBin * bin)
 {
   GST_DEBUG_OBJECT (bin, "[msg %p] handling child message of type %d",
       message, GST_MESSAGE_TYPE (message));
-  /* we don't want messages from the streaming thread while we're doing the
-   * state change. We do want them from the state change functions. */
+
   switch (GST_MESSAGE_TYPE (message)) {
     case GST_MESSAGE_EOS:{
       gchar *name = gst_object_get_name (GST_MESSAGE_SRC (message));
@@ -1454,10 +1452,12 @@ bin_bus_handler (GstBus * bus, GstMessage * message, GstBin * bin)
       GST_DEBUG_OBJECT (bin, "got EOS message from %s", name);
       g_free (name);
 
+      /* collect all eos messages from the children */
       GST_LOCK (bin->child_bus);
       bin->eosed = g_list_prepend (bin->eosed, GST_MESSAGE_SRC (message));
       GST_UNLOCK (bin->child_bus);
 
+      /* if we are completely EOS, we forward an EOS message */
       if (is_eos (bin)) {
         GST_DEBUG_OBJECT (bin, "all sinks posted EOS");
         gst_element_post_message (GST_ELEMENT (bin),
index e77442d..6a78b2a 100644 (file)
@@ -1525,9 +1525,7 @@ gchar *
 gst_caps_to_string (const GstCaps * caps)
 {
   int i;
-  GstStructure *structure;
   GString *s;
-  char *sstr;
 
   /* NOTE:  This function is potentially called by the debug system,
    * so any calls to gst_log() (and GST_DEBUG(), GST_LOG(), etc.)
@@ -1535,8 +1533,6 @@ gst_caps_to_string (const GstCaps * caps)
    * called by gst_caps_to_string.  In particular, calls should
    * not use the GST_PTR_FORMAT extension.  */
 
-  /* FIXME does this leak? */
-
   if (caps == NULL) {
     return g_strdup ("NULL");
   }
@@ -1546,16 +1542,16 @@ gst_caps_to_string (const GstCaps * caps)
   if (gst_caps_is_empty (caps)) {
     return g_strdup ("EMPTY");
   }
+
   s = g_string_new ("");
-  structure = gst_caps_get_structure (caps, 0);
-  sstr = gst_structure_to_string (structure);
-  g_string_append (s, sstr);
-  g_free (sstr);
+  for (i = 0; i < caps->structs->len; i++) {
+    GstStructure *structure;
+    char *sstr;
 
-  for (i = 1; i < caps->structs->len; i++) {
-    structure = gst_caps_get_structure (caps, i);
+    if (i > 0)
+      g_string_append (s, "; ");
 
-    g_string_append (s, "; ");
+    structure = gst_caps_get_structure (caps, i);
     sstr = gst_structure_to_string (structure);
     g_string_append (s, sstr);
     g_free (sstr);
index a37e841..6d1ccc1 100644 (file)
@@ -2122,10 +2122,6 @@ gst_element_save_thyself (GstObject * object, xmlNodePtr parent)
         (xmlChar *) GST_PLUGIN_FEATURE (factory)->name);
   }
 
-/* FIXME: what is this? */
-/*  if (element->manager) */
-/*    xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
-
   /* params */
   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
 
index aa3ad01..3c01829 100644 (file)
@@ -578,7 +578,6 @@ static gchar *
 gst_value_collect_int_range (GValue * value, guint n_collect_values,
     GTypeCValue * collect_values, guint collect_flags)
 {
-  /* FIXME */
   value->data[0].v_int = collect_values[0].v_int;
   value->data[1].v_int = collect_values[1].v_int;
 
@@ -1347,8 +1346,17 @@ gst_string_wrap (const char *s)
   return d;
 }
 
-/* FIXME: wouldn't it be nice if this function
- * were documented ? Alphabet spaghetti is easier to digest.
+/* 
+ * This function takes a string delimited with double quotes (")
+ * and unescapes any \xxx octal numbers.
+ *
+ * If sequences of \y are found where y is not in the range of
+ * 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.
+ *
+ * the input string must be \0 terminated.
  */
 static char *
 gst_string_unwrap (const gchar * s)
@@ -1356,44 +1364,65 @@ gst_string_unwrap (const gchar * s)
   gchar *ret;
   gchar *read, *write;
 
+  /* NULL string returns NULL */
   if (s == NULL)
     return NULL;
 
+  /* strings not starting with " are invalid */
+  if (*s != '"')
+    return NULL;
+
+  /* make copy of original string to hold the result. This
+   * string will always be smaller than the original */
   ret = g_strdup (s);
   read = ret;
   write = ret;
 
-  if (*read++ != '"')
-    goto beach;
+  /* need to move to the next position as we parsed the " */
+  read++;
 
   while (*read) {
     if (GST_ASCII_IS_STRING (*read)) {
+      /* normal chars are just copied */
       *write++ = *read++;
     } else if (*read == '"') {
+      /* quote marks end of string */
       break;
     } else if (*read == '\\') {
+      /* got an escape char, move to next position to read a tripplet
+       * of octal numbers */
       read++;
-      if (*read >= '0' && *read <= '7') {
+      /* is the next char a possible first octal number? */
+      if (*read >= '0' && *read <= '3') {
+        /* parse other 2 numbers, if one of them is not in the range of
+         * an octal number, we error. We also catch the case where a zero
+         * byte is found here. */
         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
           goto beach;
 
+        /* now convert the octal number to a byte again. */
         *write++ = ((read[0] - '0') << 6) +
             ((read[1] - '0') << 3) + (read[2] - '0');
+
         read += 3;
       } else {
         /* if we run into a \0 here, we definately won't get a quote later */
         if (*read == 0)
           goto beach;
 
+        /* else copy \X sequence */
         *write++ = *read++;
       }
     } else {
+      /* weird character, error */
       goto beach;
     }
   }
+  /* if the string is not ending in " and zero terminated, we error */
   if (*read != '"' || read[1] != '\0')
     goto beach;
 
+  /* null terminate result string and return */
   *write++ = '\0';
   return ret;
 
@@ -1597,15 +1626,11 @@ static gboolean
 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
     const GValue * src2)
 {
-  g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_INT, FALSE);
-  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
-
   if (src2->data[0].v_int <= src1->data[0].v_int &&
       src2->data[1].v_int >= src1->data[0].v_int) {
     gst_value_init_and_copy (dest, src2);
     return TRUE;
   }
-
   return FALSE;
 }
 
@@ -1616,9 +1641,6 @@ gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
   int min;
   int max;
 
-  g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_INT_RANGE, FALSE);
-  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
-
   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
 
@@ -1641,9 +1663,6 @@ static gboolean
 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
     const GValue * src2)
 {
-  g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_INT, FALSE);
-  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
-
   if (src2->data[0].v_int <= src1->data[0].v_int &&
       src2->data[1].v_int >= src1->data[0].v_int) {
     gst_value_init_and_copy (dest, src1);
@@ -1660,9 +1679,6 @@ gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
   int min;
   int max;
 
-  g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_INT_RANGE, FALSE);
-  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
-
   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
 
@@ -1684,9 +1700,6 @@ static gboolean
 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
     const GValue * src2)
 {
-  g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_DOUBLE, FALSE);
-  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
-
   if (src2->data[0].v_double <= src1->data[0].v_double &&
       src2->data[1].v_double >= src1->data[0].v_double) {
     gst_value_init_and_copy (dest, src1);
@@ -1703,9 +1716,6 @@ gst_value_intersect_double_range_double_range (GValue * dest,
   double min;
   double max;
 
-  g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_DOUBLE_RANGE, FALSE);
-  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
-
   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
 
@@ -1731,8 +1741,6 @@ gst_value_intersect_list (GValue * dest, const GValue * value1,
   GValue intersection = { 0, };
   gboolean ret = FALSE;
 
-  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value1), FALSE);
-
   size = gst_value_list_get_size (value1);
   for (i = 0; i < size; i++) {
     const GValue *cur = gst_value_list_get_value (value1, i);
@@ -1797,13 +1805,18 @@ gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
   int max = gst_value_get_int_range_max (subtrahend);
   int val = g_value_get_int (minuend);
 
+  /* subtracting a range from an int only works if the int is not in the
+   * range */
   if (val < min || val > max) {
+    /* and the result is the int */
     gst_value_init_and_copy (dest, minuend);
     return TRUE;
   }
   return FALSE;
 }
 
+/* creates a new int range based on input values. 
+ */
 static gboolean
 gst_value_create_new_range (GValue * dest, int min1, int max1, int min2,
     int max2)
@@ -1858,14 +1871,17 @@ gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
 
   g_return_val_if_fail (min < max, FALSE);
 
+  /* value is outside of the range, return range unchanged */
   if (val < min || val > max) {
     gst_value_init_and_copy (dest, minuend);
     return TRUE;
   } else {
+    /* max must be MAXINT too as val <= max */
     if (val == G_MAXINT) {
       max--;
       val--;
     }
+    /* min must be MININT too as val >= max */
     if (val == G_MININT) {
       min++;
       val++;
@@ -1915,7 +1931,8 @@ static gboolean
 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
     const GValue * subtrahend)
 {
-  /* FIXME! */
+  /* since we don't have open ranges, we cannot create a hole in
+   * a double range. We return the original range */
   gst_value_init_and_copy (dest, minuend);
   return TRUE;
 }
@@ -1924,7 +1941,7 @@ static gboolean
 gst_value_subtract_double_range_double_range (GValue * dest,
     const GValue * minuend, const GValue * subtrahend)
 {
-  /* FIXME! */
+  /* since we don't have open ranges, we have to approximate */
   /* done like with ints */
   double min1 = gst_value_get_double_range_min (minuend);
   double max2 = gst_value_get_double_range_max (minuend);
@@ -1972,8 +1989,6 @@ gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
   GValue subtraction = { 0, };
   gboolean ret = FALSE;
 
-  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (minuend), FALSE);
-
   size = gst_value_list_get_size (minuend);
   for (i = 0; i < size; i++) {
     const GValue *cur = gst_value_list_get_value (minuend, i);
@@ -2014,8 +2029,6 @@ gst_value_subtract_list (GValue * dest, const GValue * minuend,
   GValue data[2] = { {0,}, {0,} };
   GValue *subtraction = &data[0], *result = &data[1];
 
-  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (subtrahend), FALSE);
-
   gst_value_init_and_copy (result, minuend);
   size = gst_value_list_get_size (subtrahend);
   for (i = 0; i < size; i++) {
@@ -2059,6 +2072,7 @@ gst_value_can_compare (const GValue * value1, const GValue * value2)
 
   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
     return FALSE;
+
   for (i = 0; i < gst_value_table->len; i++) {
     table = &g_array_index (gst_value_table, GstValueTable, i);
     if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
@@ -2924,14 +2938,11 @@ gst_value_transform_fraction_double (const GValue * src_value,
 static int
 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
 {
-  /* FIXME: maybe we should make this more mathematically correct instead
-   * of approximating with gdoubles */
-
   gint n1, n2;
   gint d1, d2;
 
-  gdouble new_num_1;
-  gdouble new_num_2;
+  gint64 new_num_1;
+  gint64 new_num_2;
 
   n1 = value1->data[0].v_int;
   n2 = value2->data[0].v_int;
@@ -2942,12 +2953,14 @@ gst_value_compare_fraction (const GValue * value1, const GValue * value2)
   if (n1 == n2 && d1 == d2)
     return GST_VALUE_EQUAL;
 
-  new_num_1 = n1 * d2;
-  new_num_2 = n2 * d1;
+  /* extend to 64 bits */
+  new_num_1 = ((gint64) n1) * d2;
+  new_num_2 = ((gint64) n2) * d1;
   if (new_num_1 < new_num_2)
     return GST_VALUE_LESS_THAN;
   if (new_num_1 > new_num_2)
     return GST_VALUE_GREATER_THAN;
+
   g_assert_not_reached ();
   return GST_VALUE_UNORDERED;
 }
index 7a6fcdb..4dc3dae 100644 (file)
@@ -411,9 +411,9 @@ GST_START_TEST (test_value_intersect)
   g_value_init (&src1, G_TYPE_INT);
   g_value_set_int (&src1, 10);
   g_value_init (&src2, G_TYPE_INT);
-  g_value_set_int (&src1, 20);
+  g_value_set_int (&src2, 20);
   ret = gst_value_intersect (&dest, &src1, &src2);
-  fail_unless (ret == 0);
+  fail_unless (ret == FALSE);
   g_value_unset (&src1);
   g_value_unset (&src2);
 
@@ -436,6 +436,489 @@ GST_START_TEST (test_value_intersect)
 
 GST_END_TEST;
 
+
+GST_START_TEST (test_value_subtract_int)
+{
+  GValue dest = { 0 };
+  GValue src1 = { 0 };
+  GValue src2 = { 0 };
+  const GValue *tmp;
+  gboolean ret;
+
+  /*  int <-> int 
+   */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 10);
+  g_value_init (&src2, G_TYPE_INT);
+  g_value_set_int (&src2, 20);
+  /* subtract as in sets, result is 10 */
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* same values, yields empty set */
+  ret = gst_value_subtract (&dest, &src1, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  int <-> int_range 
+   */
+
+  /* would yield an empty set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 10);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 0, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should create a list of two ranges. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 0);
+  fail_unless (gst_value_get_int_range_max (tmp) == 9);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 11);
+  fail_unless (gst_value_get_int_range_max (tmp) == 20);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 1, empty set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 10);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should create a new range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 11);
+  fail_unless (gst_value_get_int_range_max (&dest) == 20);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 2, empty set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should create a new range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 19);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* case 3, valid set */
+  g_value_init (&src1, G_TYPE_INT);
+  g_value_set_int (&src1, 0);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (G_VALUE_HOLDS_INT (&dest) == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* and the other way around, should keep the range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 20);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  int_range <-> int_range 
+   */
+
+  /* same range, empty set */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* non overlapping ranges */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 30, 40);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 20);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 30);
+  fail_unless (gst_value_get_int_range_max (&dest) == 40);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* completely overlapping ranges */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 10, 30);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 21);
+  fail_unless (gst_value_get_int_range_max (&dest) == 30);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* partially overlapping ranges */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 20);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 15, 30);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 10);
+  fail_unless (gst_value_get_int_range_max (&dest) == 14);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_int_range_min (&dest) == 21);
+  fail_unless (gst_value_get_int_range_max (&dest) == 30);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole { int_range, int_range } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 15, 20);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 10);
+  fail_unless (gst_value_get_int_range_max (tmp) == 14);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 21);
+  fail_unless (gst_value_get_int_range_max (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole, { int, int } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 11, 29);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 10);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole, { int, int_range } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 11, 28);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 10);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 29);
+  fail_unless (gst_value_get_int_range_max (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole, { int_range, int } */
+  g_value_init (&src1, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src1, 10, 30);
+  g_value_init (&src2, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (&src2, 12, 29);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_int_range_min (tmp) == 10);
+  fail_unless (gst_value_get_int_range_max (tmp) == 11);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (G_VALUE_HOLDS_INT (tmp) == TRUE);
+  fail_unless (g_value_get_int (tmp) == 30);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_value_subtract_double)
+{
+  GValue dest = { 0 };
+  GValue src1 = { 0 };
+  GValue src2 = { 0 };
+  const GValue *tmp;
+  gboolean ret;
+
+  /*  double <-> double 
+   */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 10.0);
+  g_value_init (&src2, G_TYPE_DOUBLE);
+  g_value_set_double (&src2, 20.0);
+  /* subtract as in sets, result is 10 */
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* same values, yields empty set */
+  ret = gst_value_subtract (&dest, &src1, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  double <-> double_range 
+   */
+
+  /* would yield an empty set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 10.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 0.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, we cannot create open ranges
+   * so the result is the range again */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 0.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 1, empty set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 10.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should keep same range as
+   * we don't have open ranges. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* border case 2, empty set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+
+  /* and the other way around, should keep same range as
+   * we don't have open ranges. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* case 3, valid set */
+  g_value_init (&src1, G_TYPE_DOUBLE);
+  g_value_set_double (&src1, 0.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (G_VALUE_HOLDS_DOUBLE (&dest) == TRUE);
+  fail_unless (gst_value_compare (&dest, &src1) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* and the other way around, should keep the range. */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /*  double_range <-> double_range 
+   */
+
+  /* same range, empty set */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* non overlapping ranges */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 30.0, 40.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 20.0);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 30.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 40.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* completely overlapping ranges */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 10.0, 30.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == FALSE);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 20.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 30.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* partially overlapping ranges */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 20.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 15.0, 30.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 10.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 15.0);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (&dest) == TRUE);
+  fail_unless (gst_value_get_double_range_min (&dest) == 20.0);
+  fail_unless (gst_value_get_double_range_max (&dest) == 30.0);
+  g_value_unset (&dest);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+
+  /* create a hole { double_range, double_range } */
+  g_value_init (&src1, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src1, 10.0, 30.0);
+  g_value_init (&src2, GST_TYPE_DOUBLE_RANGE);
+  gst_value_set_double_range (&src2, 15.0, 20.0);
+  ret = gst_value_subtract (&dest, &src1, &src2);
+  fail_unless (ret == TRUE);
+  fail_unless (GST_VALUE_HOLDS_LIST (&dest) == TRUE);
+  tmp = gst_value_list_get_value (&dest, 0);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_double_range_min (tmp) == 10.0);
+  fail_unless (gst_value_get_double_range_max (tmp) == 15.0);
+  tmp = gst_value_list_get_value (&dest, 1);
+  fail_unless (GST_VALUE_HOLDS_DOUBLE_RANGE (tmp) == TRUE);
+  fail_unless (gst_value_get_double_range_min (tmp) == 20.0);
+  fail_unless (gst_value_get_double_range_max (tmp) == 30.0);
+  g_value_unset (&dest);
+  /* the other way */
+  ret = gst_value_subtract (&dest, &src2, &src1);
+  fail_unless (ret == FALSE);
+  g_value_unset (&src1);
+  g_value_unset (&src2);
+}
+
+GST_END_TEST;
+
 Suite *
 gst_value_suite (void)
 {
@@ -453,6 +936,9 @@ gst_value_suite (void)
   tcase_add_test (tc_chain, test_deserialize_string);
   tcase_add_test (tc_chain, test_value_compare);
   tcase_add_test (tc_chain, test_value_intersect);
+  tcase_add_test (tc_chain, test_value_subtract_int);
+  tcase_add_test (tc_chain, test_value_subtract_double);
+
   return s;
 }