1 /* GStreamer
   2  * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Library General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Library General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Library General Public
  15  * License along with this library; if not, write to the
  16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
  17  * Boston, MA 02110-1301, USA.
  18  */
  19 
  20 /**
  21  * SECTION:gstvalue
  22  * @short_description: GValue implementations specific
  23  * to GStreamer
  24  *
  25  * GValue implementations specific to GStreamer.
  26  *
  27  * Note that operations on the same #GValue from multiple threads may lead to
  28  * undefined behaviour.
  29  */
  30 
  31 #ifdef HAVE_CONFIG_H
  32 #include "config.h"
  33 #endif
  34 #include <math.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 #include <ctype.h>
  39 
  40 #include "gst_private.h"
  41 #include "glib-compat-private.h"
  42 #include <gst/gst.h>
  43 #include <gobject/gvaluecollector.h>
  44 #include "gstutils.h"
  45 
  46 /* GstValueUnionFunc:
  47  * @dest: a #GValue for the result
  48  * @value1: a #GValue operand
  49  * @value2: a #GValue operand
  50  *
  51  * Used by gst_value_union() to perform unification for a specific #GValue
  52  * type. Register a new implementation with gst_value_register_union_func().
  53  *
  54  * Returns: %TRUE if a union was successful
  55  */
  56 typedef gboolean (*GstValueUnionFunc) (GValue * dest,
  57     const GValue * value1, const GValue * value2);
  58 
  59 /* GstValueIntersectFunc:
  60  * @dest: (out caller-allocates): a #GValue for the result
  61  * @value1: a #GValue operand
  62  * @value2: a #GValue operand
  63  *
  64  * Used by gst_value_intersect() to perform intersection for a specific #GValue
  65  * type. If the intersection is non-empty, the result is
  66  * placed in @dest and %TRUE is returned.  If the intersection is
  67  * empty, @dest is unmodified and %FALSE is returned.
  68  * Register a new implementation with gst_value_register_intersect_func().
  69  *
  70  * Returns: %TRUE if the values can intersect
  71  */
  72 typedef gboolean (*GstValueIntersectFunc) (GValue * dest,
  73     const GValue * value1, const GValue * value2);
  74 
  75 /* GstValueSubtractFunc:
  76  * @dest: (out caller-allocates): a #GValue for the result
  77  * @minuend: a #GValue operand
  78  * @subtrahend: a #GValue operand
  79  *
  80  * Used by gst_value_subtract() to perform subtraction for a specific #GValue
  81  * type. Register a new implementation with gst_value_register_subtract_func().
  82  *
  83  * Returns: %TRUE if the subtraction is not empty
  84  */
  85 typedef gboolean (*GstValueSubtractFunc) (GValue * dest,
  86     const GValue * minuend, const GValue * subtrahend);
  87 
  88 static void gst_value_register_union_func (GType type1,
  89     GType type2, GstValueUnionFunc func);
  90 static void gst_value_register_intersect_func (GType type1,
  91     GType type2, GstValueIntersectFunc func);
  92 static void gst_value_register_subtract_func (GType minuend_type,
  93     GType subtrahend_type, GstValueSubtractFunc func);
  94 
  95 typedef struct _GstValueUnionInfo GstValueUnionInfo;
  96 struct _GstValueUnionInfo
  97 {
  98   GType type1;
  99   GType type2;
 100   GstValueUnionFunc func;
 101 };
 102 
 103 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
 104 struct _GstValueIntersectInfo
 105 {
 106   GType type1;
 107   GType type2;
 108   GstValueIntersectFunc func;
 109 };
 110 
 111 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
 112 struct _GstValueSubtractInfo
 113 {
 114   GType minuend;
 115   GType subtrahend;
 116   GstValueSubtractFunc func;
 117 };
 118 
 119 #define FUNDAMENTAL_TYPE_ID_MAX \
 120     (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT)
 121 #define FUNDAMENTAL_TYPE_ID(type) \
 122     ((type) >> G_TYPE_FUNDAMENTAL_SHIFT)
 123 
 124 #define VALUE_LIST_ARRAY(v) ((GArray *) (v)->data[0].v_pointer)
 125 #define VALUE_LIST_SIZE(v) (VALUE_LIST_ARRAY(v)->len)
 126 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &g_array_index (VALUE_LIST_ARRAY(v), GValue, (index)))
 127 
 128 static GArray *gst_value_table;
 129 static GHashTable *gst_value_hash;
 130 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1];
 131 static GArray *gst_value_union_funcs;
 132 static GArray *gst_value_intersect_funcs;
 133 static GArray *gst_value_subtract_funcs;
 134 
 135 /* Forward declarations */
 136 static gchar *gst_value_serialize_fraction (const GValue * value);
 137 
 138 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
 139 static gint gst_value_compare_with_func (const GValue * value1,
 140     const GValue * value2, GstValueCompareFunc compare);
 141 
 142 static gchar *gst_string_wrap (const gchar * s);
 143 static gchar *gst_string_take_and_wrap (gchar * s);
 144 static gchar *gst_string_unwrap (const gchar * s);
 145 
 146 static void gst_value_move (GValue * dest, GValue * src);
 147 static void _gst_value_list_append_and_take_value (GValue * value,
 148     GValue * append_value);
 149 static void _gst_value_array_append_and_take_value (GValue * value,
 150     GValue * append_value);
 151 
 152 static inline GstValueTable *
 153 gst_value_hash_lookup_type (GType type)
 154 {
 155   if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type)))
 156     return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)];
 157   else
 158     return g_hash_table_lookup (gst_value_hash, (gpointer) type);
 159 }
 160 
 161 static void
 162 gst_value_hash_add_type (GType type, const GstValueTable * table)
 163 {
 164   if (G_TYPE_IS_FUNDAMENTAL (type))
 165     gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table;
 166 
 167   g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table);
 168 }
 169 
 170 /********
 171  * list *
 172  ********/
 173 
 174 /* two helper functions to serialize/stringify any type of list
 175  * regular lists are done with { }, arrays with < >
 176  */
 177 static gchar *
 178 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
 179     const gchar * end)
 180 {
 181   guint i;
 182   GArray *array = value->data[0].v_pointer;
 183   GString *s;
 184   GValue *v;
 185   gchar *s_val;
 186   guint alen = array->len;
 187 
 188   /* estimate minimum string length to minimise re-allocs in GString */
 189   s = g_string_sized_new (2 + (6 * alen) + 2);
 190   g_string_append (s, begin);
 191   for (i = 0; i < alen; i++) {
 192     v = &g_array_index (array, GValue, i);
 193     s_val = gst_value_serialize (v);
 194     if (s_val != NULL) {
 195     g_string_append (s, s_val);
 196     g_free (s_val);
 197     if (i < alen - 1) {
 198       g_string_append_len (s, ", ", 2);
 199     }
 200     } else {
 201       GST_WARNING ("Could not serialize list/array value of type '%s'",
 202           G_VALUE_TYPE_NAME (v));
 203   }
 204   }
 205   g_string_append (s, end);
 206   return g_string_free (s, FALSE);
 207 }
 208 
 209 static void
 210 gst_value_transform_any_list_string (const GValue * src_value,
 211     GValue * dest_value, const gchar * begin, const gchar * end)
 212 {
 213   GValue *list_value;
 214   GArray *array;
 215   GString *s;
 216   guint i;
 217   gchar *list_s;
 218   guint alen;
 219 
 220   array = src_value->data[0].v_pointer;
 221   alen = array->len;
 222 
 223   /* estimate minimum string length to minimise re-allocs in GString */
 224   s = g_string_sized_new (2 + (10 * alen) + 2);
 225   g_string_append (s, begin);
 226   for (i = 0; i < alen; i++) {
 227     list_value = &g_array_index (array, GValue, i);
 228 
 229     if (i != 0) {
 230       g_string_append_len (s, ", ", 2);
 231     }
 232     list_s = g_strdup_value_contents (list_value);
 233     g_string_append (s, list_s);
 234     g_free (list_s);
 235   }
 236   g_string_append (s, end);
 237 
 238   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
 239 }
 240 
 241 /*
 242  * helper function to see if a type is fixed. Is used internally here and
 243  * there. Do not export, since it doesn't work for types where the content
 244  * decides the fixedness (e.g. GST_TYPE_ARRAY).
 245  */
 246 static gboolean
 247 gst_type_is_fixed (GType type)
 248 {
 249   /* the basic int, string, double types */
 250   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
 251     return TRUE;
 252   }
 253   /* our fundamental types that are certainly not fixed */
 254   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
 255       type == GST_TYPE_INT64_RANGE ||
 256       type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE) {
 257     return FALSE;
 258   }
 259   /* other (boxed) types that are fixed */
 260   if (type == GST_TYPE_BUFFER) {
 261     return TRUE;
 262   }
 263   /* heavy checks */
 264   if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <=
 265       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
 266     return TRUE;
 267   }
 268 
 269   return FALSE;
 270 }
 271 
 272 /* GValue functions usable for both regular lists and arrays */
 273 static void
 274 gst_value_init_list_or_array (GValue * value)
 275 {
 276   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
 277 }
 278 
 279 static GArray *
 280 copy_garray_of_gstvalue (const GArray * src)
 281 {
 282   GArray *dest;
 283   guint i, len;
 284 
 285   len = src->len;
 286   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), len);
 287   g_array_set_size (dest, len);
 288   for (i = 0; i < len; i++) {
 289     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
 290         &g_array_index (src, GValue, i));
 291   }
 292 
 293   return dest;
 294 }
 295 
 296 static void
 297 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
 298 {
 299   dest_value->data[0].v_pointer =
 300       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
 301 }
 302 
 303 static void
 304 gst_value_free_list_or_array (GValue * value)
 305 {
 306   guint i, len;
 307   GArray *src = (GArray *) value->data[0].v_pointer;
 308   len = src->len;
 309 
 310   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
 311     for (i = 0; i < len; i++) {
 312       g_value_unset (&g_array_index (src, GValue, i));
 313     }
 314     g_array_free (src, TRUE);
 315   }
 316 }
 317 
 318 static gpointer
 319 gst_value_list_or_array_peek_pointer (const GValue * value)
 320 {
 321   return value->data[0].v_pointer;
 322 }
 323 
 324 static gchar *
 325 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
 326     GTypeCValue * collect_values, guint collect_flags)
 327 {
 328   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
 329     value->data[0].v_pointer = collect_values[0].v_pointer;
 330     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
 331   } else {
 332     value->data[0].v_pointer =
 333         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
 334   }
 335   return NULL;
 336 }
 337 
 338 static gchar *
 339 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
 340     GTypeCValue * collect_values, guint collect_flags)
 341 {
 342   GArray **dest = collect_values[0].v_pointer;
 343 
 344   if (!dest)
 345     return g_strdup_printf ("value location for `%s' passed as NULL",
 346         G_VALUE_TYPE_NAME (value));
 347   if (!value->data[0].v_pointer)
 348     return g_strdup_printf ("invalid value given for `%s'",
 349         G_VALUE_TYPE_NAME (value));
 350   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
 351     *dest = (GArray *) value->data[0].v_pointer;
 352   } else {
 353     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
 354   }
 355   return NULL;
 356 }
 357 
 358 static gboolean
 359 gst_value_list_or_array_get_basic_type (const GValue * value, GType * type)
 360 {
 361   if (G_UNLIKELY (value == NULL))
 362     return FALSE;
 363 
 364   if (GST_VALUE_HOLDS_LIST (value)) {
 365     if (VALUE_LIST_SIZE (value) == 0)
 366       return FALSE;
 367     return gst_value_list_or_array_get_basic_type (VALUE_LIST_GET_VALUE (value,
 368             0), type);
 369   }
 370   if (GST_VALUE_HOLDS_ARRAY (value)) {
 371     const GArray *array = (const GArray *) value->data[0].v_pointer;
 372     if (array->len == 0)
 373       return FALSE;
 374     return gst_value_list_or_array_get_basic_type (&g_array_index (array,
 375             GValue, 0), type);
 376   }
 377 
 378   *type = G_VALUE_TYPE (value);
 379 
 380   return TRUE;
 381 }
 382 
 383 #define IS_RANGE_COMPAT(type1,type2,t1,t2) \
 384   (((t1) == (type1) && (t2) == (type2)) || ((t2) == (type1) && (t1) == (type2)))
 385 
 386 static gboolean
 387 gst_value_list_or_array_are_compatible (const GValue * value1,
 388     const GValue * value2)
 389 {
 390   GType basic_type1, basic_type2;
 391 
 392   /* empty or same type is OK */
 393   if (!gst_value_list_or_array_get_basic_type (value1, &basic_type1) ||
 394       !gst_value_list_or_array_get_basic_type (value2, &basic_type2) ||
 395       basic_type1 == basic_type2)
 396     return TRUE;
 397 
 398   /* ranges are distinct types for each bound type... */
 399   if (IS_RANGE_COMPAT (G_TYPE_INT, GST_TYPE_INT_RANGE, basic_type1,
 400           basic_type2))
 401     return TRUE;
 402   if (IS_RANGE_COMPAT (G_TYPE_INT64, GST_TYPE_INT64_RANGE, basic_type1,
 403           basic_type2))
 404     return TRUE;
 405   if (IS_RANGE_COMPAT (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, basic_type1,
 406           basic_type2))
 407     return TRUE;
 408   if (IS_RANGE_COMPAT (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, basic_type1,
 409           basic_type2))
 410     return TRUE;
 411 
 412   return FALSE;
 413 }
 414 
 415 static inline void
 416 _gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
 417 {
 418   g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
 419   memset (append_value, 0, sizeof (GValue));
 420 }
 421 
 422 /**
 423  * gst_value_list_append_and_take_value:
 424  * @value: a #GValue of type #GST_TYPE_LIST
 425  * @append_value: (transfer full): the value to append
 426  *
 427  * Appends @append_value to the GstValueList in @value.
 428  *
 429  * Since: 1.2
 430  */
 431 void
 432 gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
 433 {
 434   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
 435   g_return_if_fail (G_IS_VALUE (append_value));
 436   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
 437           append_value));
 438 
 439   _gst_value_list_append_and_take_value (value, append_value);
 440 }
 441 
 442 /**
 443  * gst_value_list_append_value:
 444  * @value: a #GValue of type #GST_TYPE_LIST
 445  * @append_value: (transfer none): the value to append
 446  *
 447  * Appends @append_value to the GstValueList in @value.
 448  */
 449 void
 450 gst_value_list_append_value (GValue * value, const GValue * append_value)
 451 {
 452   GValue val = { 0, };
 453 
 454   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
 455   g_return_if_fail (G_IS_VALUE (append_value));
 456   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
 457           append_value));
 458 
 459   gst_value_init_and_copy (&val, append_value);
 460   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
 461 }
 462 
 463 /**
 464  * gst_value_list_prepend_value:
 465  * @value: a #GValue of type #GST_TYPE_LIST
 466  * @prepend_value: the value to prepend
 467  *
 468  * Prepends @prepend_value to the GstValueList in @value.
 469  */
 470 void
 471 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
 472 {
 473   GValue val = { 0, };
 474 
 475   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
 476   g_return_if_fail (G_IS_VALUE (prepend_value));
 477   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
 478           prepend_value));
 479 
 480   gst_value_init_and_copy (&val, prepend_value);
 481   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
 482 }
 483 
 484 /**
 485  * gst_value_list_concat:
 486  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
 487  * @value1: a #GValue
 488  * @value2: a #GValue
 489  *
 490  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
 491  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
 492  * @dest will be initialized to the type #GST_TYPE_LIST.
 493  */
 494 void
 495 gst_value_list_concat (GValue * dest, const GValue * value1,
 496     const GValue * value2)
 497 {
 498   guint i, value1_length, value2_length;
 499   GArray *array;
 500 
 501   g_return_if_fail (dest != NULL);
 502   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
 503   g_return_if_fail (G_IS_VALUE (value1));
 504   g_return_if_fail (G_IS_VALUE (value2));
 505   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
 506 
 507   value1_length =
 508       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
 509   value2_length =
 510       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
 511   g_value_init (dest, GST_TYPE_LIST);
 512   array = (GArray *) dest->data[0].v_pointer;
 513   g_array_set_size (array, value1_length + value2_length);
 514 
 515   if (GST_VALUE_HOLDS_LIST (value1)) {
 516     for (i = 0; i < value1_length; i++) {
 517       gst_value_init_and_copy (&g_array_index (array, GValue, i),
 518           VALUE_LIST_GET_VALUE (value1, i));
 519     }
 520   } else {
 521     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
 522   }
 523 
 524   if (GST_VALUE_HOLDS_LIST (value2)) {
 525     for (i = 0; i < value2_length; i++) {
 526       gst_value_init_and_copy (&g_array_index (array, GValue,
 527               i + value1_length), VALUE_LIST_GET_VALUE (value2, i));
 528     }
 529   } else {
 530     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
 531         value2);
 532   }
 533 }
 534 
 535 /* same as gst_value_list_concat() but takes ownership of GValues */
 536 static void
 537 gst_value_list_concat_and_take_values (GValue * dest, GValue * val1,
 538     GValue * val2)
 539 {
 540   guint i, val1_length, val2_length;
 541   gboolean val1_is_list;
 542   gboolean val2_is_list;
 543   GArray *array;
 544 
 545   g_assert (dest != NULL);
 546   g_assert (G_VALUE_TYPE (dest) == 0);
 547   g_assert (G_IS_VALUE (val1));
 548   g_assert (G_IS_VALUE (val2));
 549   g_assert (gst_value_list_or_array_are_compatible (val1, val2));
 550 
 551   val1_is_list = GST_VALUE_HOLDS_LIST (val1);
 552   val1_length = (val1_is_list ? VALUE_LIST_SIZE (val1) : 1);
 553 
 554   val2_is_list = GST_VALUE_HOLDS_LIST (val2);
 555   val2_length = (val2_is_list ? VALUE_LIST_SIZE (val2) : 1);
 556 
 557   g_value_init (dest, GST_TYPE_LIST);
 558   array = (GArray *) dest->data[0].v_pointer;
 559   g_array_set_size (array, val1_length + val2_length);
 560 
 561   if (val1_is_list) {
 562     for (i = 0; i < val1_length; i++) {
 563       g_array_index (array, GValue, i) = *VALUE_LIST_GET_VALUE (val1, i);
 564     }
 565     g_array_set_size (VALUE_LIST_ARRAY (val1), 0);
 566     g_value_unset (val1);
 567   } else {
 568     g_array_index (array, GValue, 0) = *val1;
 569     G_VALUE_TYPE (val1) = G_TYPE_INVALID;
 570   }
 571 
 572   if (val2_is_list) {
 573     for (i = 0; i < val2_length; i++) {
 574       const GValue *v2 = VALUE_LIST_GET_VALUE (val2, i);
 575       g_array_index (array, GValue, i + val1_length) = *v2;
 576     }
 577     g_array_set_size (VALUE_LIST_ARRAY (val2), 0);
 578     g_value_unset (val2);
 579   } else {
 580     g_array_index (array, GValue, val1_length) = *val2;
 581     G_VALUE_TYPE (val2) = G_TYPE_INVALID;
 582   }
 583 }
 584 
 585 /**
 586  * gst_value_list_merge:
 587  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
 588  * @value1: a #GValue
 589  * @value2: a #GValue
 590  *
 591  * Merges copies of @value1 and @value2.  Values that are not
 592  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
 593  *
 594  * The result will be put into @dest and will either be a list that will not
 595  * contain any duplicates, or a non-list type (if @value1 and @value2
 596  * were equal).
 597  */
 598 void
 599 gst_value_list_merge (GValue * dest, const GValue * value1,
 600     const GValue * value2)
 601 {
 602   guint i, j, k, value1_length, value2_length, skipped;
 603   const GValue *src;
 604   gboolean skip;
 605   GArray *array;
 606 
 607   g_return_if_fail (dest != NULL);
 608   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
 609   g_return_if_fail (G_IS_VALUE (value1));
 610   g_return_if_fail (G_IS_VALUE (value2));
 611   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
 612 
 613   value1_length =
 614       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
 615   value2_length =
 616       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
 617   g_value_init (dest, GST_TYPE_LIST);
 618   array = (GArray *) dest->data[0].v_pointer;
 619   g_array_set_size (array, value1_length + value2_length);
 620 
 621   if (GST_VALUE_HOLDS_LIST (value1)) {
 622     for (i = 0; i < value1_length; i++) {
 623       gst_value_init_and_copy (&g_array_index (array, GValue, i),
 624           VALUE_LIST_GET_VALUE (value1, i));
 625     }
 626   } else {
 627     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
 628   }
 629 
 630   j = value1_length;
 631   skipped = 0;
 632   if (GST_VALUE_HOLDS_LIST (value2)) {
 633     for (i = 0; i < value2_length; i++) {
 634       skip = FALSE;
 635       src = VALUE_LIST_GET_VALUE (value2, i);
 636       for (k = 0; k < value1_length; k++) {
 637         if (gst_value_compare (&g_array_index (array, GValue, k),
 638                 src) == GST_VALUE_EQUAL) {
 639           skip = TRUE;
 640           skipped++;
 641           break;
 642         }
 643       }
 644       if (!skip) {
 645         gst_value_init_and_copy (&g_array_index (array, GValue, j), src);
 646         j++;
 647       }
 648     }
 649   } else {
 650     skip = FALSE;
 651     for (k = 0; k < value1_length; k++) {
 652       if (gst_value_compare (&g_array_index (array, GValue, k),
 653               value2) == GST_VALUE_EQUAL) {
 654         skip = TRUE;
 655         skipped++;
 656         break;
 657       }
 658     }
 659     if (!skip) {
 660       gst_value_init_and_copy (&g_array_index (array, GValue, j), value2);
 661     }
 662   }
 663   if (skipped) {
 664     guint new_size = value1_length + (value2_length - skipped);
 665 
 666     if (new_size > 1) {
 667       /* shrink list */
 668       g_array_set_size (array, new_size);
 669     } else {
 670       GValue single_dest;
 671 
 672       /* size is 1, take single value in list and make it new dest */
 673       single_dest = g_array_index (array, GValue, 0);
 674 
 675       /* clean up old value allocations: must set array size to 0, because
 676        * allocated values are not inited meaning g_value_unset() will not
 677        * work on them */
 678       g_array_set_size (array, 0);
 679       g_value_unset (dest);
 680 
 681       /* the single value is our new result */
 682       *dest = single_dest;
 683     }
 684   }
 685 }
 686 
 687 /**
 688  * gst_value_list_get_size:
 689  * @value: a #GValue of type #GST_TYPE_LIST
 690  *
 691  * Gets the number of values contained in @value.
 692  *
 693  * Returns: the number of values
 694  */
 695 guint
 696 gst_value_list_get_size (const GValue * value)
 697 {
 698   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
 699 
 700   return ((GArray *) value->data[0].v_pointer)->len;
 701 }
 702 
 703 /**
 704  * gst_value_list_get_value:
 705  * @value: a #GValue of type #GST_TYPE_LIST
 706  * @index: index of value to get from the list
 707  *
 708  * Gets the value that is a member of the list contained in @value and
 709  * has the index @index.
 710  *
 711  * Returns: (transfer none): the value at the given index
 712  */
 713 const GValue *
 714 gst_value_list_get_value (const GValue * value, guint index)
 715 {
 716   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
 717   g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL);
 718 
 719   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
 720       GValue, index);
 721 }
 722 
 723 /**
 724  * gst_value_array_append_value:
 725  * @value: a #GValue of type #GST_TYPE_ARRAY
 726  * @append_value: the value to append
 727  *
 728  * Appends @append_value to the GstValueArray in @value.
 729  */
 730 void
 731 gst_value_array_append_value (GValue * value, const GValue * append_value)
 732 {
 733   GValue val = { 0, };
 734 
 735   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
 736   g_return_if_fail (G_IS_VALUE (append_value));
 737   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
 738           append_value));
 739 
 740   gst_value_init_and_copy (&val, append_value);
 741   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
 742 }
 743 
 744 static inline void
 745 _gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
 746 {
 747   g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
 748   memset (append_value, 0, sizeof (GValue));
 749 }
 750 
 751 /**
 752  * gst_value_array_append_and_take_value:
 753  * @value: a #GValue of type #GST_TYPE_ARRAY
 754  * @append_value: (transfer full): the value to append
 755  *
 756  * Appends @append_value to the GstValueArray in @value.
 757  *
 758  * Since: 1.2
 759  */
 760 void
 761 gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
 762 {
 763   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
 764   g_return_if_fail (G_IS_VALUE (append_value));
 765   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
 766           append_value));
 767 
 768   _gst_value_array_append_and_take_value (value, append_value);
 769 }
 770 
 771 #ifndef GSTREAMER_LITE
 772 /**
 773  * gst_value_array_prepend_value:
 774  * @value: a #GValue of type #GST_TYPE_ARRAY
 775  * @prepend_value: the value to prepend
 776  *
 777  * Prepends @prepend_value to the GstValueArray in @value.
 778  */
 779 void
 780 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
 781 {
 782   GValue val = { 0, };
 783 
 784   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
 785   g_return_if_fail (G_IS_VALUE (prepend_value));
 786   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
 787           prepend_value));
 788 
 789   gst_value_init_and_copy (&val, prepend_value);
 790   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
 791 }
 792 #endif // GSTREAMER_LITE
 793 
 794 /**
 795  * gst_value_array_get_size:
 796  * @value: a #GValue of type #GST_TYPE_ARRAY
 797  *
 798  * Gets the number of values contained in @value.
 799  *
 800  * Returns: the number of values
 801  */
 802 guint
 803 gst_value_array_get_size (const GValue * value)
 804 {
 805   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
 806 
 807   return ((GArray *) value->data[0].v_pointer)->len;
 808 }
 809 
 810 /**
 811  * gst_value_array_get_value:
 812  * @value: a #GValue of type #GST_TYPE_ARRAY
 813  * @index: index of value to get from the array
 814  *
 815  * Gets the value that is a member of the array contained in @value and
 816  * has the index @index.
 817  *
 818  * Returns: (transfer none): the value at the given index
 819  */
 820 const GValue *
 821 gst_value_array_get_value (const GValue * value, guint index)
 822 {
 823   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
 824   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
 825 
 826   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
 827       GValue, index);
 828 }
 829 
 830 static void
 831 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
 832 {
 833   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
 834 }
 835 
 836 static void
 837 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
 838 {
 839   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
 840 }
 841 
 842 /* Do an unordered compare of the contents of a list */
 843 static gint
 844 gst_value_compare_list (const GValue * value1, const GValue * value2)
 845 {
 846   guint i, j;
 847   GArray *array1 = value1->data[0].v_pointer;
 848   GArray *array2 = value2->data[0].v_pointer;
 849   GValue *v1;
 850   GValue *v2;
 851   gint len, to_remove;
 852   guint8 *removed;
 853   GstValueCompareFunc compare;
 854 
 855   /* get length and do initial length check. */
 856   len = array1->len;
 857   if (len != array2->len)
 858     return GST_VALUE_UNORDERED;
 859 
 860   /* place to mark removed value indices of array2 */
 861   removed = g_newa (guint8, len);
 862   memset (removed, 0, len);
 863   to_remove = len;
 864 
 865   /* loop over array1, all items should be in array2. When we find an
 866    * item in array2, remove it from array2 by marking it as removed */
 867   for (i = 0; i < len; i++) {
 868     v1 = &g_array_index (array1, GValue, i);
 869     if ((compare = gst_value_get_compare_func (v1))) {
 870       for (j = 0; j < len; j++) {
 871         /* item is removed, we can skip it */
 872         if (removed[j])
 873           continue;
 874         v2 = &g_array_index (array2, GValue, j);
 875         if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
 876           /* mark item as removed now that we found it in array2 and
 877            * decrement the number of remaining items in array2. */
 878           removed[j] = 1;
 879           to_remove--;
 880           break;
 881         }
 882       }
 883       /* item in array1 and not in array2, UNORDERED */
 884       if (j == len)
 885         return GST_VALUE_UNORDERED;
 886     } else
 887       return GST_VALUE_UNORDERED;
 888   }
 889   /* if not all items were removed, array2 contained something not in array1 */
 890   if (to_remove != 0)
 891     return GST_VALUE_UNORDERED;
 892 
 893   /* arrays are equal */
 894   return GST_VALUE_EQUAL;
 895 }
 896 
 897 /* Perform an ordered comparison of the contents of an array */
 898 static gint
 899 gst_value_compare_array (const GValue * value1, const GValue * value2)
 900 {
 901   guint i;
 902   GArray *array1 = value1->data[0].v_pointer;
 903   GArray *array2 = value2->data[0].v_pointer;
 904   guint len = array1->len;
 905   GValue *v1;
 906   GValue *v2;
 907 
 908   if (len != array2->len)
 909     return GST_VALUE_UNORDERED;
 910 
 911   for (i = 0; i < len; i++) {
 912     v1 = &g_array_index (array1, GValue, i);
 913     v2 = &g_array_index (array2, GValue, i);
 914     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
 915       return GST_VALUE_UNORDERED;
 916   }
 917 
 918   return GST_VALUE_EQUAL;
 919 }
 920 
 921 static gchar *
 922 gst_value_serialize_list (const GValue * value)
 923 {
 924   return gst_value_serialize_any_list (value, "{ ", " }");
 925 }
 926 
 927 static gboolean
 928 gst_value_deserialize_list (GValue * dest, const gchar * s)
 929 {
 930   g_warning ("gst_value_deserialize_list: unimplemented");
 931   return FALSE;
 932 }
 933 
 934 static gchar *
 935 gst_value_serialize_array (const GValue * value)
 936 {
 937   return gst_value_serialize_any_list (value, "< ", " >");
 938 }
 939 
 940 static gboolean
 941 gst_value_deserialize_array (GValue * dest, const gchar * s)
 942 {
 943   g_warning ("gst_value_deserialize_array: unimplemented");
 944   return FALSE;
 945 }
 946 
 947 /*************
 948  * int range *
 949  *
 950  * Values in the range are defined as any value greater or equal
 951  * to min*step, AND lesser or equal to max*step.
 952  * For step == 1, this falls back to the traditional range semantics.
 953  *
 954  * data[0] = (min << 32) | (max)
 955  * data[1] = step
 956  *
 957  *************/
 958 
 959 #define INT_RANGE_MIN(v) ((gint) (((v)->data[0].v_uint64) >> 32))
 960 #define INT_RANGE_MAX(v) ((gint) (((v)->data[0].v_uint64) & 0xffffffff))
 961 #define INT_RANGE_STEP(v) ((v)->data[1].v_int)
 962 
 963 static void
 964 gst_value_init_int_range (GValue * value)
 965 {
 966   G_STATIC_ASSERT (sizeof (gint) <= 2 * sizeof (guint64));
 967 
 968   value->data[0].v_uint64 = 0;
 969   value->data[1].v_int = 1;
 970 }
 971 
 972 static void
 973 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
 974 {
 975   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
 976   dest_value->data[1].v_int = src_value->data[1].v_int;
 977 }
 978 
 979 static gchar *
 980 gst_value_collect_int_range (GValue * value, guint n_collect_values,
 981     GTypeCValue * collect_values, guint collect_flags)
 982 {
 983   if (n_collect_values != 2)
 984     return g_strdup_printf ("not enough value locations for `%s' passed",
 985         G_VALUE_TYPE_NAME (value));
 986   if (collect_values[0].v_int >= collect_values[1].v_int)
 987     return g_strdup_printf ("range start is not smaller than end for `%s'",
 988         G_VALUE_TYPE_NAME (value));
 989 
 990   gst_value_set_int_range_step (value, collect_values[0].v_int,
 991       collect_values[1].v_int, 1);
 992 
 993   return NULL;
 994 }
 995 
 996 static gchar *
 997 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
 998     GTypeCValue * collect_values, guint collect_flags)
 999 {
1000   guint32 *int_range_start = collect_values[0].v_pointer;
1001   guint32 *int_range_end = collect_values[1].v_pointer;
1002 
1003   if (!int_range_start)
1004     return g_strdup_printf ("start value location for `%s' passed as NULL",
1005         G_VALUE_TYPE_NAME (value));
1006   if (!int_range_end)
1007     return g_strdup_printf ("end value location for `%s' passed as NULL",
1008         G_VALUE_TYPE_NAME (value));
1009 
1010   *int_range_start = INT_RANGE_MIN (value);
1011   *int_range_end = INT_RANGE_MAX (value);
1012 
1013   return NULL;
1014 }
1015 
1016 /**
1017  * gst_value_set_int_range_step:
1018  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1019  * @start: the start of the range
1020  * @end: the end of the range
1021  * @step: the step of the range
1022  *
1023  * Sets @value to the range specified by @start, @end and @step.
1024  */
1025 void
1026 gst_value_set_int_range_step (GValue * value, gint start, gint end, gint step)
1027 {
1028   guint64 sstart, sstop;
1029 
1030   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
1031   g_return_if_fail (start < end);
1032   g_return_if_fail (step > 0);
1033   g_return_if_fail (start % step == 0);
1034   g_return_if_fail (end % step == 0);
1035 
1036   sstart = (guint) (start / step);
1037   sstop = (guint) (end / step);
1038   value->data[0].v_uint64 = (sstart << 32) | sstop;
1039   value->data[1].v_int = step;
1040 }
1041 
1042 /**
1043  * gst_value_set_int_range:
1044  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1045  * @start: the start of the range
1046  * @end: the end of the range
1047  *
1048  * Sets @value to the range specified by @start and @end.
1049  */
1050 void
1051 gst_value_set_int_range (GValue * value, gint start, gint end)
1052 {
1053   gst_value_set_int_range_step (value, start, end, 1);
1054 }
1055 
1056 /**
1057  * gst_value_get_int_range_min:
1058  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1059  *
1060  * Gets the minimum of the range specified by @value.
1061  *
1062  * Returns: the minimum of the range
1063  */
1064 gint
1065 gst_value_get_int_range_min (const GValue * value)
1066 {
1067   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1068 
1069   return INT_RANGE_MIN (value) * INT_RANGE_STEP (value);
1070 }
1071 
1072 /**
1073  * gst_value_get_int_range_max:
1074  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1075  *
1076  * Gets the maximum of the range specified by @value.
1077  *
1078  * Returns: the maximum of the range
1079  */
1080 gint
1081 gst_value_get_int_range_max (const GValue * value)
1082 {
1083   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1084 
1085   return INT_RANGE_MAX (value) * INT_RANGE_STEP (value);
1086 }
1087 
1088 /**
1089  * gst_value_get_int_range_step:
1090  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1091  *
1092  * Gets the step of the range specified by @value.
1093  *
1094  * Returns: the step of the range
1095  */
1096 gint
1097 gst_value_get_int_range_step (const GValue * value)
1098 {
1099   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1100 
1101   return INT_RANGE_STEP (value);
1102 }
1103 
1104 static void
1105 gst_value_transform_int_range_string (const GValue * src_value,
1106     GValue * dest_value)
1107 {
1108   if (INT_RANGE_STEP (src_value) == 1)
1109   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
1110         INT_RANGE_MIN (src_value), INT_RANGE_MAX (src_value));
1111   else
1112     dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d,%d]",
1113         INT_RANGE_MIN (src_value) * INT_RANGE_STEP (src_value),
1114         INT_RANGE_MAX (src_value) * INT_RANGE_STEP (src_value),
1115         INT_RANGE_STEP (src_value));
1116 }
1117 
1118 static gint
1119 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
1120 {
1121   /* calculate the number of values in each range */
1122   gint n1 = INT_RANGE_MAX (value1) - INT_RANGE_MIN (value1) + 1;
1123   gint n2 = INT_RANGE_MAX (value2) - INT_RANGE_MIN (value2) + 1;
1124 
1125   /* they must be equal */
1126   if (n1 != n2)
1127     return GST_VALUE_UNORDERED;
1128 
1129   /* if empty, equal */
1130   if (n1 == 0)
1131     return GST_VALUE_EQUAL;
1132 
1133   /* if more than one value, then it is only equal if the step is equal
1134      and bounds lie on the same value */
1135   if (n1 > 1) {
1136     if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) &&
1137         INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2) &&
1138         INT_RANGE_MAX (value1) == INT_RANGE_MAX (value2)) {
1139       return GST_VALUE_EQUAL;
1140     }
1141   return GST_VALUE_UNORDERED;
1142   } else {
1143     /* if just one, only if the value is equal */
1144     if (INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2))
1145       return GST_VALUE_EQUAL;
1146     return GST_VALUE_UNORDERED;
1147   }
1148 }
1149 
1150 static gchar *
1151 gst_value_serialize_int_range (const GValue * value)
1152 {
1153   if (INT_RANGE_STEP (value) == 1)
1154     return g_strdup_printf ("[ %d, %d ]", INT_RANGE_MIN (value),
1155         INT_RANGE_MAX (value));
1156   else
1157     return g_strdup_printf ("[ %d, %d, %d ]",
1158         INT_RANGE_MIN (value) * INT_RANGE_STEP (value),
1159         INT_RANGE_MAX (value) * INT_RANGE_STEP (value), INT_RANGE_STEP (value));
1160 }
1161 
1162 static gboolean
1163 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
1164 {
1165   g_warning ("unimplemented");
1166   return FALSE;
1167 }
1168 
1169 /***************
1170  * int64 range *
1171  *
1172  * Values in the range are defined as any value greater or equal
1173  * to min*step, AND lesser or equal to max*step.
1174  * For step == 1, this falls back to the traditional range semantics.
1175  ***************/
1176 
1177 #define INT64_RANGE_MIN(v) (((gint64 *)((v)->data[0].v_pointer))[0])
1178 #define INT64_RANGE_MAX(v) (((gint64 *)((v)->data[0].v_pointer))[1])
1179 #define INT64_RANGE_STEP(v) (((gint64 *)((v)->data[0].v_pointer))[2])
1180 
1181 static void
1182 gst_value_init_int64_range (GValue * value)
1183 {
1184   gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64));
1185   value->data[0].v_pointer = vals;
1186   INT64_RANGE_MIN (value) = 0;
1187   INT64_RANGE_MAX (value) = 0;
1188   INT64_RANGE_STEP (value) = 1;
1189 }
1190 
1191 static void
1192 gst_value_free_int64_range (GValue * value)
1193 {
1194   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1195   g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer);
1196   value->data[0].v_pointer = NULL;
1197 }
1198 
1199 static void
1200 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value)
1201 {
1202   gint64 *vals = (gint64 *) dest_value->data[0].v_pointer;
1203   gint64 *src_vals = (gint64 *) src_value->data[0].v_pointer;
1204 
1205   if (vals == NULL) {
1206     gst_value_init_int64_range (dest_value);
1207   }
1208 
1209   if (src_vals != NULL) {
1210     INT64_RANGE_MIN (dest_value) = INT64_RANGE_MIN (src_value);
1211     INT64_RANGE_MAX (dest_value) = INT64_RANGE_MAX (src_value);
1212     INT64_RANGE_STEP (dest_value) = INT64_RANGE_STEP (src_value);
1213   }
1214 }
1215 
1216 static gchar *
1217 gst_value_collect_int64_range (GValue * value, guint n_collect_values,
1218     GTypeCValue * collect_values, guint collect_flags)
1219 {
1220   gint64 *vals = value->data[0].v_pointer;
1221 
1222   if (n_collect_values != 2)
1223     return g_strdup_printf ("not enough value locations for `%s' passed",
1224         G_VALUE_TYPE_NAME (value));
1225   if (collect_values[0].v_int64 >= collect_values[1].v_int64)
1226     return g_strdup_printf ("range start is not smaller than end for `%s'",
1227         G_VALUE_TYPE_NAME (value));
1228 
1229   if (vals == NULL) {
1230     gst_value_init_int64_range (value);
1231   }
1232 
1233   gst_value_set_int64_range_step (value, collect_values[0].v_int64,
1234       collect_values[1].v_int64, 1);
1235 
1236   return NULL;
1237 }
1238 
1239 static gchar *
1240 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values,
1241     GTypeCValue * collect_values, guint collect_flags)
1242 {
1243   guint64 *int_range_start = collect_values[0].v_pointer;
1244   guint64 *int_range_end = collect_values[1].v_pointer;
1245   guint64 *int_range_step = collect_values[2].v_pointer;
1246   gint64 *vals = (gint64 *) value->data[0].v_pointer;
1247 
1248   if (!int_range_start)
1249     return g_strdup_printf ("start value location for `%s' passed as NULL",
1250         G_VALUE_TYPE_NAME (value));
1251   if (!int_range_end)
1252     return g_strdup_printf ("end value location for `%s' passed as NULL",
1253         G_VALUE_TYPE_NAME (value));
1254   if (!int_range_step)
1255     return g_strdup_printf ("step value location for `%s' passed as NULL",
1256         G_VALUE_TYPE_NAME (value));
1257 
1258   if (G_UNLIKELY (vals == NULL)) {
1259     return g_strdup_printf ("Uninitialised `%s' passed",
1260         G_VALUE_TYPE_NAME (value));
1261   }
1262 
1263   *int_range_start = INT64_RANGE_MIN (value);
1264   *int_range_end = INT64_RANGE_MAX (value);
1265   *int_range_step = INT64_RANGE_STEP (value);
1266 
1267   return NULL;
1268 }
1269 
1270 /**
1271  * gst_value_set_int64_range_step:
1272  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1273  * @start: the start of the range
1274  * @end: the end of the range
1275  * @step: the step of the range
1276  *
1277  * Sets @value to the range specified by @start, @end and @step.
1278  */
1279 void
1280 gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end,
1281     gint64 step)
1282 {
1283   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1284   g_return_if_fail (start < end);
1285   g_return_if_fail (step > 0);
1286   g_return_if_fail (start % step == 0);
1287   g_return_if_fail (end % step == 0);
1288 
1289   INT64_RANGE_MIN (value) = start / step;
1290   INT64_RANGE_MAX (value) = end / step;
1291   INT64_RANGE_STEP (value) = step;
1292 }
1293 
1294 /**
1295  * gst_value_set_int64_range:
1296  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1297  * @start: the start of the range
1298  * @end: the end of the range
1299  *
1300  * Sets @value to the range specified by @start and @end.
1301  */
1302 void
1303 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
1304 {
1305   gst_value_set_int64_range_step (value, start, end, 1);
1306 }
1307 
1308 /**
1309  * gst_value_get_int64_range_min:
1310  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1311  *
1312  * Gets the minimum of the range specified by @value.
1313  *
1314  * Returns: the minimum of the range
1315  */
1316 gint64
1317 gst_value_get_int64_range_min (const GValue * value)
1318 {
1319   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1320 
1321   return INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value);
1322 }
1323 
1324 /**
1325  * gst_value_get_int64_range_max:
1326  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1327  *
1328  * Gets the maximum of the range specified by @value.
1329  *
1330  * Returns: the maximum of the range
1331  */
1332 gint64
1333 gst_value_get_int64_range_max (const GValue * value)
1334 {
1335   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1336 
1337   return INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value);
1338 }
1339 
1340 /**
1341  * gst_value_get_int64_range_step:
1342  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1343  *
1344  * Gets the step of the range specified by @value.
1345  *
1346  * Returns: the step of the range
1347  */
1348 gint64
1349 gst_value_get_int64_range_step (const GValue * value)
1350 {
1351   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1352 
1353   return INT64_RANGE_STEP (value);
1354 }
1355 
1356 static void
1357 gst_value_transform_int64_range_string (const GValue * src_value,
1358     GValue * dest_value)
1359 {
1360   if (INT64_RANGE_STEP (src_value) == 1)
1361   dest_value->data[0].v_pointer =
1362       g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]",
1363         INT64_RANGE_MIN (src_value), INT64_RANGE_MAX (src_value));
1364   else
1365     dest_value->data[0].v_pointer =
1366         g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT
1367         ",%" G_GINT64_FORMAT "]",
1368         INT64_RANGE_MIN (src_value) * INT64_RANGE_STEP (src_value),
1369         INT64_RANGE_MAX (src_value) * INT64_RANGE_STEP (src_value),
1370         INT64_RANGE_STEP (src_value));
1371 }
1372 
1373 static gint
1374 gst_value_compare_int64_range (const GValue * value1, const GValue * value2)
1375 {
1376   /* calculate the number of values in each range */
1377   gint64 n1 = INT64_RANGE_MAX (value1) - INT64_RANGE_MIN (value1) + 1;
1378   gint64 n2 = INT64_RANGE_MAX (value2) - INT64_RANGE_MIN (value2) + 1;
1379 
1380   /* they must be equal */
1381   if (n1 != n2)
1382     return GST_VALUE_UNORDERED;
1383 
1384   /* if empty, equal */
1385   if (n1 == 0)
1386     return GST_VALUE_EQUAL;
1387 
1388   /* if more than one value, then it is only equal if the step is equal
1389      and bounds lie on the same value */
1390   if (n1 > 1) {
1391     if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) &&
1392         INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2) &&
1393         INT64_RANGE_MAX (value1) == INT64_RANGE_MAX (value2)) {
1394       return GST_VALUE_EQUAL;
1395     }
1396   return GST_VALUE_UNORDERED;
1397   } else {
1398     /* if just one, only if the value is equal */
1399     if (INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2))
1400       return GST_VALUE_EQUAL;
1401     return GST_VALUE_UNORDERED;
1402   }
1403 }
1404 
1405 static gchar *
1406 gst_value_serialize_int64_range (const GValue * value)
1407 {
1408   if (INT64_RANGE_STEP (value) == 1)
1409   return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]",
1410         INT64_RANGE_MIN (value), INT64_RANGE_MAX (value));
1411   else
1412     return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ", %"
1413         G_GINT64_FORMAT " ]",
1414         INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value),
1415         INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value),
1416         INT64_RANGE_STEP (value));
1417 }
1418 
1419 static gboolean
1420 gst_value_deserialize_int64_range (GValue * dest, const gchar * s)
1421 {
1422   g_warning ("unimplemented");
1423   return FALSE;
1424 }
1425 
1426 /****************
1427  * double range *
1428  ****************/
1429 
1430 static void
1431 gst_value_init_double_range (GValue * value)
1432 {
1433   value->data[0].v_double = 0;
1434   value->data[1].v_double = 0;
1435 }
1436 
1437 static void
1438 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
1439 {
1440   dest_value->data[0].v_double = src_value->data[0].v_double;
1441   dest_value->data[1].v_double = src_value->data[1].v_double;
1442 }
1443 
1444 static gchar *
1445 gst_value_collect_double_range (GValue * value, guint n_collect_values,
1446     GTypeCValue * collect_values, guint collect_flags)
1447 {
1448   if (n_collect_values != 2)
1449     return g_strdup_printf ("not enough value locations for `%s' passed",
1450         G_VALUE_TYPE_NAME (value));
1451   if (collect_values[0].v_double >= collect_values[1].v_double)
1452     return g_strdup_printf ("range start is not smaller than end for `%s'",
1453         G_VALUE_TYPE_NAME (value));
1454 
1455   value->data[0].v_double = collect_values[0].v_double;
1456   value->data[1].v_double = collect_values[1].v_double;
1457 
1458   return NULL;
1459 }
1460 
1461 static gchar *
1462 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
1463     GTypeCValue * collect_values, guint collect_flags)
1464 {
1465   gdouble *double_range_start = collect_values[0].v_pointer;
1466   gdouble *double_range_end = collect_values[1].v_pointer;
1467 
1468   if (!double_range_start)
1469     return g_strdup_printf ("start value location for `%s' passed as NULL",
1470         G_VALUE_TYPE_NAME (value));
1471   if (!double_range_end)
1472     return g_strdup_printf ("end value location for `%s' passed as NULL",
1473         G_VALUE_TYPE_NAME (value));
1474 
1475   *double_range_start = value->data[0].v_double;
1476   *double_range_end = value->data[1].v_double;
1477 
1478   return NULL;
1479 }
1480 
1481 /**
1482  * gst_value_set_double_range:
1483  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1484  * @start: the start of the range
1485  * @end: the end of the range
1486  *
1487  * Sets @value to the range specified by @start and @end.
1488  */
1489 void
1490 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
1491 {
1492   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
1493   g_return_if_fail (start < end);
1494 
1495   value->data[0].v_double = start;
1496   value->data[1].v_double = end;
1497 }
1498 
1499 /**
1500  * gst_value_get_double_range_min:
1501  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1502  *
1503  * Gets the minimum of the range specified by @value.
1504  *
1505  * Returns: the minimum of the range
1506  */
1507 gdouble
1508 gst_value_get_double_range_min (const GValue * value)
1509 {
1510   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1511 
1512   return value->data[0].v_double;
1513 }
1514 
1515 /**
1516  * gst_value_get_double_range_max:
1517  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1518  *
1519  * Gets the maximum of the range specified by @value.
1520  *
1521  * Returns: the maximum of the range
1522  */
1523 gdouble
1524 gst_value_get_double_range_max (const GValue * value)
1525 {
1526   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1527 
1528   return value->data[1].v_double;
1529 }
1530 
1531 static void
1532 gst_value_transform_double_range_string (const GValue * src_value,
1533     GValue * dest_value)
1534 {
1535   gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
1536 
1537   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
1538       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
1539           src_value->data[0].v_double),
1540       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
1541           src_value->data[1].v_double));
1542 }
1543 
1544 static gint
1545 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
1546 {
1547   if (value2->data[0].v_double == value1->data[0].v_double &&
1548       value2->data[1].v_double == value1->data[1].v_double)
1549     return GST_VALUE_EQUAL;
1550   return GST_VALUE_UNORDERED;
1551 }
1552 
1553 static gchar *
1554 gst_value_serialize_double_range (const GValue * value)
1555 {
1556   gchar d1[G_ASCII_DTOSTR_BUF_SIZE];
1557   gchar d2[G_ASCII_DTOSTR_BUF_SIZE];
1558 
1559   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1560   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
1561   return g_strdup_printf ("[ %s, %s ]", d1, d2);
1562 }
1563 
1564 static gboolean
1565 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
1566 {
1567   g_warning ("unimplemented");
1568   return FALSE;
1569 }
1570 
1571 /****************
1572  * fraction range *
1573  ****************/
1574 
1575 static void
1576 gst_value_init_fraction_range (GValue * value)
1577 {
1578   GValue *vals;
1579   GType ftype;
1580 
1581   ftype = GST_TYPE_FRACTION;
1582 
1583   value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue));
1584   g_value_init (&vals[0], ftype);
1585   g_value_init (&vals[1], ftype);
1586 }
1587 
1588 static void
1589 gst_value_free_fraction_range (GValue * value)
1590 {
1591   GValue *vals = (GValue *) value->data[0].v_pointer;
1592 
1593   if (vals != NULL) {
1594     /* we know the two values contain fractions without internal allocs */
1595     /* g_value_unset (&vals[0]); */
1596     /* g_value_unset (&vals[1]); */
1597     g_slice_free1 (2 * sizeof (GValue), vals);
1598     value->data[0].v_pointer = NULL;
1599   }
1600 }
1601 
1602 static void
1603 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
1604 {
1605   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
1606   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
1607 
1608   if (vals == NULL) {
1609     gst_value_init_fraction_range (dest_value);
1610     vals = dest_value->data[0].v_pointer;
1611   }
1612   if (src_vals != NULL) {
1613     g_value_copy (&src_vals[0], &vals[0]);
1614     g_value_copy (&src_vals[1], &vals[1]);
1615   }
1616 }
1617 
1618 static gchar *
1619 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1620     GTypeCValue * collect_values, guint collect_flags)
1621 {
1622   GValue *vals = (GValue *) value->data[0].v_pointer;
1623 
1624   if (n_collect_values != 4)
1625     return g_strdup_printf ("not enough value locations for `%s' passed",
1626         G_VALUE_TYPE_NAME (value));
1627   if (collect_values[1].v_int == 0)
1628     return g_strdup_printf ("passed '0' as first denominator for `%s'",
1629         G_VALUE_TYPE_NAME (value));
1630   if (collect_values[3].v_int == 0)
1631     return g_strdup_printf ("passed '0' as second denominator for `%s'",
1632         G_VALUE_TYPE_NAME (value));
1633   if (gst_util_fraction_compare (collect_values[0].v_int,
1634           collect_values[1].v_int, collect_values[2].v_int,
1635           collect_values[3].v_int) >= 0)
1636     return g_strdup_printf ("range start is not smaller than end for `%s'",
1637         G_VALUE_TYPE_NAME (value));
1638 
1639   if (vals == NULL) {
1640     gst_value_init_fraction_range (value);
1641     vals = value->data[0].v_pointer;
1642   }
1643 
1644   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1645       collect_values[1].v_int);
1646   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1647       collect_values[3].v_int);
1648 
1649   return NULL;
1650 }
1651 
1652 static gchar *
1653 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1654     GTypeCValue * collect_values, guint collect_flags)
1655 {
1656   gint i;
1657   gint *dest_values[4];
1658   GValue *vals = (GValue *) value->data[0].v_pointer;
1659 
1660   if (G_UNLIKELY (n_collect_values != 4))
1661     return g_strdup_printf ("not enough value locations for `%s' passed",
1662         G_VALUE_TYPE_NAME (value));
1663 
1664   for (i = 0; i < 4; i++) {
1665     if (G_UNLIKELY (collect_values[i].v_pointer == NULL)) {
1666       return g_strdup_printf ("value location for `%s' passed as NULL",
1667           G_VALUE_TYPE_NAME (value));
1668     }
1669     dest_values[i] = collect_values[i].v_pointer;
1670   }
1671 
1672   if (G_UNLIKELY (vals == NULL)) {
1673     return g_strdup_printf ("Uninitialised `%s' passed",
1674         G_VALUE_TYPE_NAME (value));
1675   }
1676 
1677   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1678   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1679   dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]);
1680   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1681   return NULL;
1682 }
1683 
1684 /**
1685  * gst_value_set_fraction_range:
1686  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1687  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1688  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1689  *
1690  * Sets @value to the range specified by @start and @end.
1691  */
1692 void
1693 gst_value_set_fraction_range (GValue * value, const GValue * start,
1694     const GValue * end)
1695 {
1696   GValue *vals;
1697 
1698   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1699   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start));
1700   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end));
1701   g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int,
1702           start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0);
1703 
1704   vals = (GValue *) value->data[0].v_pointer;
1705   if (vals == NULL) {
1706     gst_value_init_fraction_range (value);
1707     vals = value->data[0].v_pointer;
1708   }
1709   g_value_copy (start, &vals[0]);
1710   g_value_copy (end, &vals[1]);
1711 }
1712 
1713 /**
1714  * gst_value_set_fraction_range_full:
1715  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1716  * @numerator_start: the numerator start of the range
1717  * @denominator_start: the denominator start of the range
1718  * @numerator_end: the numerator end of the range
1719  * @denominator_end: the denominator end of the range
1720  *
1721  * Sets @value to the range specified by @numerator_start/@denominator_start
1722  * and @numerator_end/@denominator_end.
1723  */
1724 void
1725 gst_value_set_fraction_range_full (GValue * value,
1726     gint numerator_start, gint denominator_start,
1727     gint numerator_end, gint denominator_end)
1728 {
1729   GValue start = { 0 };
1730   GValue end = { 0 };
1731 
1732   g_return_if_fail (value != NULL);
1733   g_return_if_fail (denominator_start != 0);
1734   g_return_if_fail (denominator_end != 0);
1735   g_return_if_fail (gst_util_fraction_compare (numerator_start,
1736           denominator_start, numerator_end, denominator_end) < 0);
1737 
1738   g_value_init (&start, GST_TYPE_FRACTION);
1739   g_value_init (&end, GST_TYPE_FRACTION);
1740 
1741   gst_value_set_fraction (&start, numerator_start, denominator_start);
1742   gst_value_set_fraction (&end, numerator_end, denominator_end);
1743   gst_value_set_fraction_range (value, &start, &end);
1744 
1745   /* we know the two values contain fractions without internal allocs */
1746   /* g_value_unset (&start); */
1747   /* g_value_unset (&end);   */
1748 }
1749 
1750 /* FIXME 2.0: Don't leak the internal representation of fraction
1751  * ranges but instead return the numerator and denominator
1752  * separately.
1753  * This would allow to store fraction ranges as
1754  *  data[0] = (min_n << 32) | (min_d)
1755  *  data[1] = (max_n << 32) | (max_d)
1756  * without requiring an additional allocation for each value.
1757  */
1758 
1759 /**
1760  * gst_value_get_fraction_range_min:
1761  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1762  *
1763  * Gets the minimum of the range specified by @value.
1764  *
1765  * Returns: the minimum of the range
1766  */
1767 const GValue *
1768 gst_value_get_fraction_range_min (const GValue * value)
1769 {
1770   GValue *vals;
1771 
1772   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1773 
1774   vals = (GValue *) value->data[0].v_pointer;
1775   if (vals != NULL) {
1776     return &vals[0];
1777   }
1778 
1779   return NULL;
1780 }
1781 
1782 /**
1783  * gst_value_get_fraction_range_max:
1784  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1785  *
1786  * Gets the maximum of the range specified by @value.
1787  *
1788  * Returns: the maximum of the range
1789  */
1790 const GValue *
1791 gst_value_get_fraction_range_max (const GValue * value)
1792 {
1793   GValue *vals;
1794 
1795   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1796 
1797   vals = (GValue *) value->data[0].v_pointer;
1798   if (vals != NULL) {
1799     return &vals[1];
1800   }
1801 
1802   return NULL;
1803 }
1804 
1805 static gchar *
1806 gst_value_serialize_fraction_range (const GValue * value)
1807 {
1808   GValue *vals = (GValue *) value->data[0].v_pointer;
1809   gchar *retval;
1810 
1811   if (vals == NULL) {
1812     retval = g_strdup ("[ 0/1, 0/1 ]");
1813   } else {
1814     gchar *start, *end;
1815 
1816     start = gst_value_serialize_fraction (&vals[0]);
1817     end = gst_value_serialize_fraction (&vals[1]);
1818 
1819     retval = g_strdup_printf ("[ %s, %s ]", start, end);
1820     g_free (start);
1821     g_free (end);
1822   }
1823 
1824   return retval;
1825 }
1826 
1827 static void
1828 gst_value_transform_fraction_range_string (const GValue * src_value,
1829     GValue * dest_value)
1830 {
1831   dest_value->data[0].v_pointer =
1832       gst_value_serialize_fraction_range (src_value);
1833 }
1834 
1835 static gint
1836 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
1837 {
1838   GValue *vals1, *vals2;
1839   GstValueCompareFunc compare;
1840 
1841   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
1842     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
1843 
1844   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
1845     return GST_VALUE_UNORDERED;
1846 
1847   vals1 = (GValue *) value1->data[0].v_pointer;
1848   vals2 = (GValue *) value2->data[0].v_pointer;
1849   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
1850     if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
1851         GST_VALUE_EQUAL &&
1852         gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
1853         GST_VALUE_EQUAL)
1854       return GST_VALUE_EQUAL;
1855   }
1856   return GST_VALUE_UNORDERED;
1857 }
1858 
1859 static gboolean
1860 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
1861 {
1862   g_warning ("unimplemented");
1863   return FALSE;
1864 }
1865 
1866 /***********
1867  * GstCaps *
1868  ***********/
1869 
1870 /**
1871  * gst_value_set_caps:
1872  * @value: a GValue initialized to GST_TYPE_CAPS
1873  * @caps: (transfer none): the caps to set the value to
1874  *
1875  * Sets the contents of @value to @caps. A reference to the
1876  * provided @caps will be taken by the @value.
1877  */
1878 void
1879 gst_value_set_caps (GValue * value, const GstCaps * caps)
1880 {
1881   g_return_if_fail (G_IS_VALUE (value));
1882   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
1883   g_return_if_fail (caps == NULL || GST_IS_CAPS (caps));
1884 
1885   g_value_set_boxed (value, caps);
1886 }
1887 
1888 /**
1889  * gst_value_get_caps:
1890  * @value: a GValue initialized to GST_TYPE_CAPS
1891  *
1892  * Gets the contents of @value. The reference count of the returned
1893  * #GstCaps will not be modified, therefore the caller must take one
1894  * before getting rid of the @value.
1895  *
1896  * Returns: (transfer none): the contents of @value
1897  */
1898 const GstCaps *
1899 gst_value_get_caps (const GValue * value)
1900 {
1901   g_return_val_if_fail (G_IS_VALUE (value), NULL);
1902   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
1903 
1904   return (GstCaps *) g_value_get_boxed (value);
1905 }
1906 
1907 static gint
1908 gst_value_compare_caps (const GValue * value1, const GValue * value2)
1909 {
1910   GstCaps *caps1 = GST_CAPS (gst_value_get_caps (value1));
1911   GstCaps *caps2 = GST_CAPS (gst_value_get_caps (value2));
1912 
1913   if (gst_caps_is_equal (caps1, caps2))
1914     return GST_VALUE_EQUAL;
1915   return GST_VALUE_UNORDERED;
1916 }
1917 
1918 static gchar *
1919 gst_value_serialize_caps (const GValue * value)
1920 {
1921   GstCaps *caps = g_value_get_boxed (value);
1922   return gst_string_take_and_wrap (gst_caps_to_string (caps));
1923 }
1924 
1925 static gboolean
1926 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1927 {
1928   GstCaps *caps;
1929 
1930   if (*s != '"') {
1931   caps = gst_caps_from_string (s);
1932   } else {
1933     gchar *str = gst_string_unwrap (s);
1934 
1935     if (G_UNLIKELY (!str))
1936       return FALSE;
1937 
1938     caps = gst_caps_from_string (str);
1939     g_free (str);
1940   }
1941 
1942   if (caps) {
1943     g_value_take_boxed (dest, caps);
1944     return TRUE;
1945   }
1946   return FALSE;
1947 }
1948 
1949 /**************
1950  * GstSegment *
1951  **************/
1952 
1953 static gchar *
1954 gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
1955 {
1956   GstSegment *seg = g_value_get_boxed (value);
1957   gchar *t, *res;
1958   GstStructure *s;
1959 
1960   s = gst_structure_new ("GstSegment",
1961       "flags", GST_TYPE_SEGMENT_FLAGS, seg->flags,
1962       "rate", G_TYPE_DOUBLE, seg->rate,
1963       "applied-rate", G_TYPE_DOUBLE, seg->applied_rate,
1964       "format", GST_TYPE_FORMAT, seg->format,
1965       "base", G_TYPE_UINT64, seg->base,
1966       "offset", G_TYPE_UINT64, seg->offset,
1967       "start", G_TYPE_UINT64, seg->start,
1968       "stop", G_TYPE_UINT64, seg->stop,
1969       "time", G_TYPE_UINT64, seg->time,
1970       "position", G_TYPE_UINT64, seg->position,
1971       "duration", G_TYPE_UINT64, seg->duration, NULL);
1972   t = gst_structure_to_string (s);
1973   if (escape) {
1974     res = g_strdup_printf ("\"%s\"", t);
1975     g_free (t);
1976   } else {
1977     res = t;
1978   }
1979   gst_structure_free (s);
1980 
1981   return res;
1982 }
1983 
1984 static gchar *
1985 gst_value_serialize_segment (const GValue * value)
1986 {
1987   return gst_value_serialize_segment_internal (value, TRUE);
1988 }
1989 
1990 static gboolean
1991 gst_value_deserialize_segment (GValue * dest, const gchar * s)
1992 {
1993   GstStructure *str;
1994   GstSegment seg;
1995   gboolean res;
1996 
1997   str = gst_structure_from_string (s, NULL);
1998   if (str == NULL)
1999     return FALSE;
2000 
2001   res = gst_structure_get (str,
2002       "flags", GST_TYPE_SEGMENT_FLAGS, &seg.flags,
2003       "rate", G_TYPE_DOUBLE, &seg.rate,
2004       "applied-rate", G_TYPE_DOUBLE, &seg.applied_rate,
2005       "format", GST_TYPE_FORMAT, &seg.format,
2006       "base", G_TYPE_UINT64, &seg.base,
2007       "offset", G_TYPE_UINT64, &seg.offset,
2008       "start", G_TYPE_UINT64, &seg.start,
2009       "stop", G_TYPE_UINT64, &seg.stop,
2010       "time", G_TYPE_UINT64, &seg.time,
2011       "position", G_TYPE_UINT64, &seg.position,
2012       "duration", G_TYPE_UINT64, &seg.duration, NULL);
2013   gst_structure_free (str);
2014 
2015   if (res)
2016     g_value_set_boxed (dest, &seg);
2017 
2018   return res;
2019 }
2020 
2021 /****************
2022  * GstStructure *
2023  ****************/
2024 
2025 /**
2026  * gst_value_set_structure:
2027  * @value: a GValue initialized to GST_TYPE_STRUCTURE
2028  * @structure: the structure to set the value to
2029  *
2030  * Sets the contents of @value to @structure.  The actual
2031  */
2032 void
2033 gst_value_set_structure (GValue * value, const GstStructure * structure)
2034 {
2035   g_return_if_fail (G_IS_VALUE (value));
2036   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
2037   g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
2038 
2039   g_value_set_boxed (value, structure);
2040 }
2041 
2042 /**
2043  * gst_value_get_structure:
2044  * @value: a GValue initialized to GST_TYPE_STRUCTURE
2045  *
2046  * Gets the contents of @value.
2047  *
2048  * Returns: (transfer none): the contents of @value
2049  */
2050 const GstStructure *
2051 gst_value_get_structure (const GValue * value)
2052 {
2053   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2054   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
2055 
2056   return (GstStructure *) g_value_get_boxed (value);
2057 }
2058 
2059 static gchar *
2060 gst_value_serialize_structure (const GValue * value)
2061 {
2062   GstStructure *structure = g_value_get_boxed (value);
2063 
2064   return gst_string_take_and_wrap (gst_structure_to_string (structure));
2065 }
2066 
2067 static gboolean
2068 gst_value_deserialize_structure (GValue * dest, const gchar * s)
2069 {
2070   GstStructure *structure;
2071 
2072   if (*s != '"') {
2073     structure = gst_structure_from_string (s, NULL);
2074   } else {
2075     gchar *str = gst_string_unwrap (s);
2076 
2077     if (G_UNLIKELY (!str))
2078       return FALSE;
2079 
2080     structure = gst_structure_from_string (str, NULL);
2081     g_free (str);
2082   }
2083 
2084   if (G_LIKELY (structure)) {
2085     g_value_take_boxed (dest, structure);
2086     return TRUE;
2087   }
2088   return FALSE;
2089 }
2090 
2091 /*******************
2092  * GstCapsFeatures *
2093  *******************/
2094 
2095 /**
2096  * gst_value_set_caps_features:
2097  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2098  * @features: the features to set the value to
2099  *
2100  * Sets the contents of @value to @features.
2101  */
2102 void
2103 gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
2104 {
2105   g_return_if_fail (G_IS_VALUE (value));
2106   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
2107   g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
2108 
2109   g_value_set_boxed (value, features);
2110 }
2111 
2112 /**
2113  * gst_value_get_caps_features:
2114  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2115  *
2116  * Gets the contents of @value.
2117  *
2118  * Returns: (transfer none): the contents of @value
2119  */
2120 const GstCapsFeatures *
2121 gst_value_get_caps_features (const GValue * value)
2122 {
2123   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2124   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
2125 
2126   return (GstCapsFeatures *) g_value_get_boxed (value);
2127 }
2128 
2129 static gchar *
2130 gst_value_serialize_caps_features (const GValue * value)
2131 {
2132   GstCapsFeatures *features = g_value_get_boxed (value);
2133 
2134   return gst_string_take_and_wrap (gst_caps_features_to_string (features));
2135 }
2136 
2137 static gboolean
2138 gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
2139 {
2140   GstCapsFeatures *features;
2141 
2142   if (*s != '"') {
2143     features = gst_caps_features_from_string (s);
2144   } else {
2145     gchar *str = gst_string_unwrap (s);
2146 
2147     if (G_UNLIKELY (!str))
2148       return FALSE;
2149 
2150     features = gst_caps_features_from_string (str);
2151     g_free (str);
2152   }
2153 
2154   if (G_LIKELY (features)) {
2155     g_value_take_boxed (dest, features);
2156     return TRUE;
2157   }
2158   return FALSE;
2159 }
2160 
2161 /**************
2162  * GstTagList *
2163  **************/
2164 
2165 static gboolean
2166 gst_value_deserialize_tag_list (GValue * dest, const gchar * s)
2167 {
2168   GstTagList *taglist;
2169 
2170   if (*s != '"') {
2171     taglist = gst_tag_list_new_from_string (s);
2172   } else {
2173     gchar *str = gst_string_unwrap (s);
2174 
2175     if (G_UNLIKELY (!str))
2176       return FALSE;
2177 
2178     taglist = gst_tag_list_new_from_string (str);
2179     g_free (str);
2180   }
2181 
2182   if (G_LIKELY (taglist != NULL)) {
2183     g_value_take_boxed (dest, taglist);
2184     return TRUE;
2185   }
2186   return FALSE;
2187 }
2188 
2189 static gchar *
2190 gst_value_serialize_tag_list (const GValue * value)
2191 {
2192   GstTagList *taglist = g_value_get_boxed (value);
2193 
2194   return gst_string_take_and_wrap (gst_tag_list_to_string (taglist));
2195 }
2196 
2197 
2198 /*************
2199  * GstBuffer *
2200  *************/
2201 
2202 static gint
2203 compare_buffer (GstBuffer * buf1, GstBuffer * buf2)
2204 {
2205   gsize size1, size2;
2206   GstMapInfo info1, info2;
2207   gint result, mret;
2208 
2209   if (buf1 == buf2)
2210     return GST_VALUE_EQUAL;
2211 
2212   size1 = gst_buffer_get_size (buf1);
2213   size2 = gst_buffer_get_size (buf2);
2214 
2215   if (size1 != size2)
2216     return GST_VALUE_UNORDERED;
2217 
2218   if (size1 == 0)
2219     return GST_VALUE_EQUAL;
2220 
2221   if (!gst_buffer_map (buf1, &info1, GST_MAP_READ))
2222   return GST_VALUE_UNORDERED;
2223 
2224   if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
2225     gst_buffer_unmap (buf1, &info1);
2226     return GST_VALUE_UNORDERED;
2227   }
2228 
2229   mret = memcmp (info1.data, info2.data, info1.size);
2230   if (mret == 0)
2231     result = GST_VALUE_EQUAL;
2232   else if (mret < 0)
2233     result = GST_VALUE_LESS_THAN;
2234   else
2235     result = GST_VALUE_GREATER_THAN;
2236 
2237   gst_buffer_unmap (buf1, &info1);
2238   gst_buffer_unmap (buf2, &info2);
2239 
2240   return result;
2241 }
2242 
2243 static gint
2244 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
2245 {
2246   GstBuffer *buf1 = gst_value_get_buffer (value1);
2247   GstBuffer *buf2 = gst_value_get_buffer (value2);
2248 
2249   return compare_buffer (buf1, buf2);
2250 }
2251 
2252 static gchar *
2253 gst_value_serialize_buffer (const GValue * value)
2254 {
2255   GstMapInfo info;
2256   guint8 *data;
2257   gint i;
2258   gchar *string;
2259   GstBuffer *buffer;
2260 
2261   buffer = gst_value_get_buffer (value);
2262   if (buffer == NULL)
2263     return NULL;
2264 
2265   if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
2266     return NULL;
2267 
2268   data = info.data;
2269 
2270   string = g_malloc (info.size * 2 + 1);
2271   for (i = 0; i < info.size; i++) {
2272     sprintf (string + i * 2, "%02x", data[i]);
2273   }
2274   string[info.size * 2] = 0;
2275 
2276   gst_buffer_unmap (buffer, &info);
2277 
2278   return string;
2279 }
2280 
2281 static gboolean
2282 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
2283 {
2284   GstBuffer *buffer;
2285   gint len;
2286   gchar ts[3];
2287   GstMapInfo info;
2288   guint8 *data;
2289   gint i;
2290 
2291   len = strlen (s);
2292   if (len & 1)
2293     goto wrong_length;
2294 
2295   buffer = gst_buffer_new_allocate (NULL, len / 2, NULL);
2296   if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
2297     goto map_failed;
2298   data = info.data;
2299 
2300   for (i = 0; i < len / 2; i++) {
2301     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
2302       goto wrong_char;
2303 
2304     ts[0] = s[i * 2 + 0];
2305     ts[1] = s[i * 2 + 1];
2306     ts[2] = 0;
2307 
2308     data[i] = (guint8) strtoul (ts, NULL, 16);
2309   }
2310   gst_buffer_unmap (buffer, &info);
2311 
2312   gst_value_take_buffer (dest, buffer);
2313 
2314   return TRUE;
2315 
2316   /* ERRORS */
2317 wrong_length:
2318   {
2319     return FALSE;
2320   }
2321 map_failed:
2322   {
2323     return FALSE;
2324   }
2325 wrong_char:
2326   {
2327     gst_buffer_unref (buffer);
2328     gst_buffer_unmap (buffer, &info);
2329     return FALSE;
2330   }
2331 }
2332 
2333 /*************
2334  * GstSample *
2335  *************/
2336 
2337 /* This function is mostly used for comparing image/buffer tags in taglists */
2338 static gint
2339 gst_value_compare_sample (const GValue * value1, const GValue * value2)
2340 {
2341   GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1));
2342   GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2));
2343 
2344   /* FIXME: should we take into account anything else such as caps? */
2345   return compare_buffer (buf1, buf2);
2346 }
2347 
2348 static gchar *
2349 gst_value_serialize_sample (const GValue * value)
2350 {
2351   const GstStructure *info_structure;
2352   GstSegment *segment;
2353   GstBuffer *buffer;
2354   GstCaps *caps;
2355   GstSample *sample;
2356   GValue val = { 0, };
2357   gchar *info_str, *caps_str, *tmp;
2358   gchar *buf_str, *seg_str, *s;
2359 
2360   sample = g_value_get_boxed (value);
2361 
2362   buffer = gst_sample_get_buffer (sample);
2363   if (buffer) {
2364     g_value_init (&val, GST_TYPE_BUFFER);
2365     g_value_set_boxed (&val, buffer);
2366     buf_str = gst_value_serialize_buffer (&val);
2367     g_value_unset (&val);
2368   } else {
2369     buf_str = g_strdup ("None");
2370   }
2371 
2372   caps = gst_sample_get_caps (sample);
2373   if (caps) {
2374     tmp = gst_caps_to_string (caps);
2375     caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2376     g_strdelimit (caps_str, "=", '_');
2377     g_free (tmp);
2378   } else {
2379     caps_str = g_strdup ("None");
2380   }
2381 
2382   segment = gst_sample_get_segment (sample);
2383   if (segment) {
2384     g_value_init (&val, GST_TYPE_SEGMENT);
2385     g_value_set_boxed (&val, segment);
2386     tmp = gst_value_serialize_segment_internal (&val, FALSE);
2387     seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2388     g_strdelimit (seg_str, "=", '_');
2389     g_free (tmp);
2390     g_value_unset (&val);
2391   } else {
2392     seg_str = g_strdup ("None");
2393   }
2394 
2395   info_structure = gst_sample_get_info (sample);
2396   if (info_structure) {
2397     tmp = gst_structure_to_string (info_structure);
2398     info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2399     g_strdelimit (info_str, "=", '_');
2400     g_free (tmp);
2401   } else {
2402     info_str = g_strdup ("None");
2403   }
2404 
2405   s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
2406   g_free (buf_str);
2407   g_free (caps_str);
2408   g_free (seg_str);
2409   g_free (info_str);
2410 
2411   return s;
2412 }
2413 
2414 static gboolean
2415 gst_value_deserialize_sample (GValue * dest, const gchar * s)
2416 {
2417   GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
2418   GstStructure *info;
2419   GstSample *sample;
2420   GstCaps *caps;
2421   gboolean ret = FALSE;
2422   gchar **fields;
2423   gsize outlen;
2424   gint len;
2425 
2426   GST_TRACE ("deserialize '%s'", s);
2427 
2428   fields = g_strsplit (s, ":", -1);
2429   len = g_strv_length (fields);
2430   if (len != 4)
2431     goto wrong_length;
2432 
2433   g_value_init (&bval, GST_TYPE_BUFFER);
2434   g_value_init (&sval, GST_TYPE_SEGMENT);
2435 
2436   if (!gst_value_deserialize_buffer (&bval, fields[0]))
2437     goto fail;
2438 
2439   if (strcmp (fields[1], "None") != 0) {
2440     g_strdelimit (fields[1], "_", '=');
2441     g_base64_decode_inplace (fields[1], &outlen);
2442     GST_TRACE ("caps    : %s", fields[1]);
2443     caps = gst_caps_from_string (fields[1]);
2444     if (caps == NULL)
2445       goto fail;
2446   } else {
2447     caps = NULL;
2448   }
2449 
2450   if (strcmp (fields[2], "None") != 0) {
2451     g_strdelimit (fields[2], "_", '=');
2452     g_base64_decode_inplace (fields[2], &outlen);
2453     GST_TRACE ("segment : %s", fields[2]);
2454     if (!gst_value_deserialize_segment (&sval, fields[2]))
2455       goto fail;
2456   }
2457 
2458   if (strcmp (fields[3], "None") != 0) {
2459     g_strdelimit (fields[3], "_", '=');
2460     g_base64_decode_inplace (fields[3], &outlen);
2461     GST_TRACE ("info    : %s", fields[3]);
2462     info = gst_structure_from_string (fields[3], NULL);
2463     if (info == NULL)
2464       goto fail;
2465   } else {
2466     info = NULL;
2467   }
2468 
2469   sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
2470       g_value_get_boxed (&sval), info);
2471 
2472   g_value_take_boxed (dest, sample);
2473 
2474   if (caps)
2475     gst_caps_unref (caps);
2476 
2477   ret = TRUE;
2478 
2479 fail:
2480 
2481   g_value_unset (&bval);
2482   g_value_unset (&sval);
2483 
2484 wrong_length:
2485 
2486   g_strfreev (fields);
2487 
2488   return ret;
2489 }
2490 
2491 /***********
2492  * boolean *
2493  ***********/
2494 
2495 static gint
2496 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
2497 {
2498   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
2499     return GST_VALUE_EQUAL;
2500   return GST_VALUE_UNORDERED;
2501 }
2502 
2503 static gchar *
2504 gst_value_serialize_boolean (const GValue * value)
2505 {
2506   if (value->data[0].v_int) {
2507     return g_strdup ("true");
2508   }
2509   return g_strdup ("false");
2510 }
2511 
2512 static gboolean
2513 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
2514 {
2515   gboolean ret = FALSE;
2516 
2517   if (g_ascii_strcasecmp (s, "true") == 0 ||
2518       g_ascii_strcasecmp (s, "yes") == 0 ||
2519       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
2520     g_value_set_boolean (dest, TRUE);
2521     ret = TRUE;
2522   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
2523       g_ascii_strcasecmp (s, "no") == 0 ||
2524       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
2525     g_value_set_boolean (dest, FALSE);
2526     ret = TRUE;
2527   }
2528 
2529   return ret;
2530 }
2531 
2532 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
2533 static gint                                                             \
2534 gst_value_compare_ ## _type                                             \
2535 (const GValue * value1, const GValue * value2)                          \
2536 {                                                                       \
2537   g ## _type val1 = g_value_get_ ## _type (value1);                     \
2538   g ## _type val2 = g_value_get_ ## _type (value2);                     \
2539   if (val1 > val2)                                                      \
2540     return GST_VALUE_GREATER_THAN;                                      \
2541   if (val1 < val2)                                                      \
2542     return GST_VALUE_LESS_THAN;                                         \
2543   return GST_VALUE_EQUAL;                                               \
2544 }                                                                       \
2545                                                                         \
2546 static gchar *                                                          \
2547 gst_value_serialize_ ## _type (const GValue * value)                    \
2548 {                                                                       \
2549   GValue val = { 0, };                                                  \
2550   g_value_init (&val, G_TYPE_STRING);                                   \
2551   if (!g_value_transform (value, &val))                                 \
2552     g_assert_not_reached ();                                            \
2553   /* NO_COPY_MADNESS!!! */                                              \
2554   return (char *) g_value_get_string (&val);                            \
2555 }
2556 
2557 /* deserialize the given s into to as a gint64.
2558  * check if the result is actually storeable in the given size number of
2559  * bytes.
2560  */
2561 static gboolean
2562 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
2563     gint64 min, gint64 max, gint size)
2564 {
2565   gboolean ret = FALSE;
2566   gchar *end;
2567   guint64 mask = ~0;
2568 
2569   errno = 0;
2570   *to = g_ascii_strtoull (s, &end, 0);
2571   /* a range error is a definitive no-no */
2572   if (errno == ERANGE) {
2573     return FALSE;
2574   }
2575 
2576   if (*end == 0) {
2577     ret = TRUE;
2578   } else {
2579     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
2580       *to = G_LITTLE_ENDIAN;
2581       ret = TRUE;
2582     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
2583       *to = G_BIG_ENDIAN;
2584       ret = TRUE;
2585     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
2586       *to = G_BYTE_ORDER;
2587       ret = TRUE;
2588     } else if (g_ascii_strcasecmp (s, "min") == 0) {
2589       *to = min;
2590       ret = TRUE;
2591     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2592       *to = max;
2593       ret = TRUE;
2594     }
2595   }
2596   if (ret) {
2597     /* by definition, a gint64 fits into a gint64; so ignore those */
2598     if (size != sizeof (mask)) {
2599       if (*to >= 0) {
2600         /* for positive numbers, we create a mask of 1's outside of the range
2601          * and 0's inside the range.  An and will thus keep only 1 bits
2602          * outside of the range */
2603         mask <<= (size * 8);
2604         if ((mask & *to) != 0) {
2605           ret = FALSE;
2606         }
2607       } else {
2608         /* for negative numbers, we do a 2's complement version */
2609         mask <<= ((size * 8) - 1);
2610         if ((mask & *to) != mask) {
2611           ret = FALSE;
2612         }
2613       }
2614     }
2615   }
2616   return ret;
2617 }
2618 
2619 #define CREATE_SERIALIZATION(_type,_macro)                              \
2620 CREATE_SERIALIZATION_START(_type,_macro)                                \
2621                                                                         \
2622 static gboolean                                                         \
2623 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2624 {                                                                       \
2625   gint64 x;                                                             \
2626                                                                         \
2627   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
2628       G_MAX ## _macro, sizeof (g ## _type))) {                          \
2629     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
2630     return TRUE;                                                        \
2631   } else {                                                              \
2632     return FALSE;                                                       \
2633   }                                                                     \
2634 }
2635 
2636 #define CREATE_USERIALIZATION(_type,_macro)                             \
2637 CREATE_SERIALIZATION_START(_type,_macro)                                \
2638                                                                         \
2639 static gboolean                                                         \
2640 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2641 {                                                                       \
2642   gint64 x;                                                             \
2643   gchar *end;                                                           \
2644   gboolean ret = FALSE;                                                 \
2645                                                                         \
2646   errno = 0;                                                            \
2647   x = g_ascii_strtoull (s, &end, 0);                                    \
2648   /* a range error is a definitive no-no */                             \
2649   if (errno == ERANGE) {                                                \
2650     return FALSE;                                                       \
2651   }                                                                     \
2652   /* the cast ensures the range check later on makes sense */           \
2653   x = (g ## _type) x;                                                   \
2654   if (*end == 0) {                                                      \
2655     ret = TRUE;                                                         \
2656   } else {                                                              \
2657     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
2658       x = G_LITTLE_ENDIAN;                                              \
2659       ret = TRUE;                                                       \
2660     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
2661       x = G_BIG_ENDIAN;                                                 \
2662       ret = TRUE;                                                       \
2663     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
2664       x = G_BYTE_ORDER;                                                 \
2665       ret = TRUE;                                                       \
2666     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
2667       x = 0;                                                            \
2668       ret = TRUE;                                                       \
2669     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
2670       x = G_MAX ## _macro;                                              \
2671       ret = TRUE;                                                       \
2672     }                                                                   \
2673   }                                                                     \
2674   if (ret) {                                                            \
2675     if (x > G_MAX ## _macro) {                                          \
2676       ret = FALSE;                                                      \
2677     } else {                                                            \
2678       g_value_set_ ## _type (dest, x);                                  \
2679     }                                                                   \
2680   }                                                                     \
2681   return ret;                                                           \
2682 }
2683 
2684 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
2685 G_STMT_START {                                                          \
2686   static const GstValueTable gst_value = {                              \
2687     _gtype,                                                             \
2688     gst_value_compare_ ## _type,                                        \
2689     gst_value_serialize_ ## _type,                                      \
2690     gst_value_deserialize_ ## _type,                                    \
2691   };                                                                    \
2692                                                                         \
2693   gst_value_register (&gst_value);                                      \
2694 } G_STMT_END
2695 
2696 CREATE_SERIALIZATION (int, INT);
2697 CREATE_SERIALIZATION (int64, INT64);
2698 CREATE_SERIALIZATION (long, LONG);
2699 
2700 CREATE_USERIALIZATION (uint, UINT);
2701 CREATE_USERIALIZATION (uint64, UINT64);
2702 CREATE_USERIALIZATION (ulong, ULONG);
2703 
2704 /* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */
2705 #ifndef G_MAXUCHAR
2706 #define G_MAXUCHAR 255
2707 #endif
2708 CREATE_USERIALIZATION (uchar, UCHAR);
2709 
2710 /**********
2711  * double *
2712  **********/
2713 static gint
2714 gst_value_compare_double (const GValue * value1, const GValue * value2)
2715 {
2716   if (value1->data[0].v_double > value2->data[0].v_double)
2717     return GST_VALUE_GREATER_THAN;
2718   if (value1->data[0].v_double < value2->data[0].v_double)
2719     return GST_VALUE_LESS_THAN;
2720   if (value1->data[0].v_double == value2->data[0].v_double)
2721     return GST_VALUE_EQUAL;
2722   return GST_VALUE_UNORDERED;
2723 }
2724 
2725 static gchar *
2726 gst_value_serialize_double (const GValue * value)
2727 {
2728   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2729 
2730   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
2731   return g_strdup (d);
2732 }
2733 
2734 static gboolean
2735 gst_value_deserialize_double (GValue * dest, const gchar * s)
2736 {
2737   gdouble x;
2738   gboolean ret = FALSE;
2739   gchar *end;
2740 
2741   x = g_ascii_strtod (s, &end);
2742   if (*end == 0) {
2743     ret = TRUE;
2744   } else {
2745     if (g_ascii_strcasecmp (s, "min") == 0) {
2746       x = -G_MAXDOUBLE;
2747       ret = TRUE;
2748     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2749       x = G_MAXDOUBLE;
2750       ret = TRUE;
2751     }
2752   }
2753   if (ret) {
2754     g_value_set_double (dest, x);
2755   }
2756   return ret;
2757 }
2758 
2759 /*********
2760  * float *
2761  *********/
2762 
2763 static gint
2764 gst_value_compare_float (const GValue * value1, const GValue * value2)
2765 {
2766   if (value1->data[0].v_float > value2->data[0].v_float)
2767     return GST_VALUE_GREATER_THAN;
2768   if (value1->data[0].v_float < value2->data[0].v_float)
2769     return GST_VALUE_LESS_THAN;
2770   if (value1->data[0].v_float == value2->data[0].v_float)
2771     return GST_VALUE_EQUAL;
2772   return GST_VALUE_UNORDERED;
2773 }
2774 
2775 static gchar *
2776 gst_value_serialize_float (const GValue * value)
2777 {
2778   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2779 
2780   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
2781   return g_strdup (d);
2782 }
2783 
2784 static gboolean
2785 gst_value_deserialize_float (GValue * dest, const gchar * s)
2786 {
2787   gdouble x;
2788   gboolean ret = FALSE;
2789   gchar *end;
2790 
2791   x = g_ascii_strtod (s, &end);
2792   if (*end == 0) {
2793     ret = TRUE;
2794   } else {
2795     if (g_ascii_strcasecmp (s, "min") == 0) {
2796       x = -G_MAXFLOAT;
2797       ret = TRUE;
2798     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2799       x = G_MAXFLOAT;
2800       ret = TRUE;
2801     }
2802   }
2803   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
2804     ret = FALSE;
2805   if (ret) {
2806     g_value_set_float (dest, (float) x);
2807   }
2808   return ret;
2809 }
2810 
2811 /**********
2812  * string *
2813  **********/
2814 
2815 static gint
2816 gst_value_compare_string (const GValue * value1, const GValue * value2)
2817 {
2818   if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
2819     /* if only one is NULL, no match - otherwise both NULL == EQUAL */
2820     if (value1->data[0].v_pointer != value2->data[0].v_pointer)
2821       return GST_VALUE_UNORDERED;
2822   } else {
2823     gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
2824 
2825     if (x < 0)
2826       return GST_VALUE_LESS_THAN;
2827     if (x > 0)
2828       return GST_VALUE_GREATER_THAN;
2829   }
2830 
2831   return GST_VALUE_EQUAL;
2832 }
2833 
2834 static gint
2835 gst_string_measure_wrapping (const gchar * s)
2836 {
2837   gint len;
2838   gboolean wrap = FALSE;
2839 
2840   if (G_UNLIKELY (s == NULL))
2841     return -1;
2842 
2843   /* Special case: the actual string NULL needs wrapping */
2844   if (G_UNLIKELY (strcmp (s, "NULL") == 0))
2845     return 4;
2846 
2847   len = 0;
2848   while (*s) {
2849     if (GST_ASCII_IS_STRING (*s)) {
2850       len++;
2851     } else if (*s < 0x20 || *s >= 0x7f) {
2852       wrap = TRUE;
2853       len += 4;
2854     } else {
2855       wrap = TRUE;
2856       len += 2;
2857     }
2858     s++;
2859   }
2860 
2861   /* Wrap the string if we found something that needs
2862    * wrapping, or the empty string (len == 0) */
2863   return (wrap || len == 0) ? len : -1;
2864 }
2865 
2866 static gchar *
2867 gst_string_wrap_inner (const gchar * s, gint len)
2868 {
2869   gchar *d, *e;
2870 
2871   e = d = g_malloc (len + 3);
2872 
2873   *e++ = '\"';
2874   while (*s) {
2875     if (GST_ASCII_IS_STRING (*s)) {
2876       *e++ = *s++;
2877     } else if (*s < 0x20 || *s >= 0x7f) {
2878       *e++ = '\\';
2879       *e++ = '0' + ((*(guchar *) s) >> 6);
2880       *e++ = '0' + (((*s) >> 3) & 0x7);
2881       *e++ = '0' + ((*s++) & 0x7);
2882     } else {
2883       *e++ = '\\';
2884       *e++ = *s++;
2885     }
2886   }
2887   *e++ = '\"';
2888   *e = 0;
2889 
2890   g_assert (e - d <= len + 3);
2891   return d;
2892 }
2893 
2894 /* Do string wrapping/escaping */
2895 static gchar *
2896 gst_string_wrap (const gchar * s)
2897 {
2898   gint len = gst_string_measure_wrapping (s);
2899 
2900   if (G_LIKELY (len < 0))
2901     return g_strdup (s);
2902 
2903   return gst_string_wrap_inner (s, len);
2904 }
2905 
2906 /* Same as above, but take ownership of the string */
2907 static gchar *
2908 gst_string_take_and_wrap (gchar * s)
2909 {
2910   gchar *out;
2911   gint len = gst_string_measure_wrapping (s);
2912 
2913   if (G_LIKELY (len < 0))
2914     return s;
2915 
2916   out = gst_string_wrap_inner (s, len);
2917   g_free (s);
2918 
2919   return out;
2920 }
2921 
2922 /*
2923  * This function takes a string delimited with double quotes (")
2924  * and unescapes any \xxx octal numbers.
2925  *
2926  * If sequences of \y are found where y is not in the range of
2927  * 0->3, y is copied unescaped.
2928  *
2929  * If \xyy is found where x is an octal number but y is not, an
2930  * error is encountered and %NULL is returned.
2931  *
2932  * the input string must be \0 terminated.
2933  */
2934 static gchar *
2935 gst_string_unwrap (const gchar * s)
2936 {
2937   gchar *ret;
2938   gchar *read, *write;
2939 
2940   /* NULL string returns NULL */
2941   if (s == NULL)
2942     return NULL;
2943 
2944   /* strings not starting with " are invalid */
2945   if (*s != '"')
2946     return NULL;
2947 
2948   /* make copy of original string to hold the result. This
2949    * string will always be smaller than the original */
2950   ret = g_strdup (s);
2951   read = ret;
2952   write = ret;
2953 
2954   /* need to move to the next position as we parsed the " */
2955   read++;
2956 
2957   while (*read) {
2958     if (GST_ASCII_IS_STRING (*read)) {
2959       /* normal chars are just copied */
2960       *write++ = *read++;
2961     } else if (*read == '"') {
2962       /* quote marks end of string */
2963       break;
2964     } else if (*read == '\\') {
2965       /* got an escape char, move to next position to read a tripplet
2966        * of octal numbers */
2967       read++;
2968       /* is the next char a possible first octal number? */
2969       if (*read >= '0' && *read <= '3') {
2970         /* parse other 2 numbers, if one of them is not in the range of
2971          * an octal number, we error. We also catch the case where a zero
2972          * byte is found here. */
2973         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
2974           goto beach;
2975 
2976         /* now convert the octal number to a byte again. */
2977         *write++ = ((read[0] - '0') << 6) +
2978             ((read[1] - '0') << 3) + (read[2] - '0');
2979 
2980         read += 3;
2981       } else {
2982         /* if we run into a \0 here, we definitely won't get a quote later */
2983         if (*read == 0)
2984           goto beach;
2985 
2986         /* else copy \X sequence */
2987         *write++ = *read++;
2988       }
2989     } else {
2990       /* weird character, error */
2991       goto beach;
2992     }
2993   }
2994   /* if the string is not ending in " and zero terminated, we error */
2995   if (*read != '"' || read[1] != '\0')
2996     goto beach;
2997 
2998   /* null terminate result string and return */
2999   *write = '\0';
3000   return ret;
3001 
3002 beach:
3003   g_free (ret);
3004   return NULL;
3005 }
3006 
3007 static gchar *
3008 gst_value_serialize_string (const GValue * value)
3009 {
3010   return gst_string_wrap (value->data[0].v_pointer);
3011 }
3012 
3013 static gboolean
3014 gst_value_deserialize_string (GValue * dest, const gchar * s)
3015 {
3016   if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
3017     g_value_set_string (dest, NULL);
3018     return TRUE;
3019   } else if (G_LIKELY (*s != '"')) {
3020     if (!g_utf8_validate (s, -1, NULL))
3021       return FALSE;
3022     g_value_set_string (dest, s);
3023     return TRUE;
3024   } else {
3025     gchar *str = gst_string_unwrap (s);
3026     if (G_UNLIKELY (!str))
3027       return FALSE;
3028     g_value_take_string (dest, str);
3029   }
3030 
3031   return TRUE;
3032 }
3033 
3034 /********
3035  * enum *
3036  ********/
3037 
3038 static gint
3039 gst_value_compare_enum (const GValue * value1, const GValue * value2)
3040 {
3041   GEnumValue *en1, *en2;
3042   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3043   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3044 
3045   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3046   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3047   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
3048   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
3049   g_type_class_unref (klass1);
3050   g_type_class_unref (klass2);
3051   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
3052   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
3053   if (en1->value < en2->value)
3054     return GST_VALUE_LESS_THAN;
3055   if (en1->value > en2->value)
3056     return GST_VALUE_GREATER_THAN;
3057 
3058   return GST_VALUE_EQUAL;
3059 }
3060 
3061 static gchar *
3062 gst_value_serialize_enum (const GValue * value)
3063 {
3064   GEnumValue *en;
3065   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
3066 
3067   g_return_val_if_fail (klass, NULL);
3068   en = g_enum_get_value (klass, g_value_get_enum (value));
3069   g_type_class_unref (klass);
3070 
3071   /* might be one of the custom formats registered later */
3072   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
3073     const GstFormatDefinition *format_def;
3074 
3075     format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value));
3076     g_return_val_if_fail (format_def != NULL, NULL);
3077     return g_strdup (format_def->description);
3078   }
3079 
3080   g_return_val_if_fail (en, NULL);
3081   return g_strdup (en->value_name);
3082 }
3083 
3084 static gint
3085 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
3086     const gchar * s)
3087 {
3088   const GstFormatDefinition *format_def =
3089       g_value_get_pointer (format_def_value);
3090 
3091   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
3092     return 0;
3093 
3094   return g_ascii_strcasecmp (s, format_def->description);
3095 }
3096 
3097 static gboolean
3098 gst_value_deserialize_enum (GValue * dest, const gchar * s)
3099 {
3100   GEnumValue *en;
3101   gchar *endptr = NULL;
3102   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3103 
3104   g_return_val_if_fail (klass, FALSE);
3105   if (!(en = g_enum_get_value_by_name (klass, s))) {
3106     if (!(en = g_enum_get_value_by_nick (klass, s))) {
3107       gint i = strtol (s, &endptr, 0);
3108 
3109       if (endptr && *endptr == '\0') {
3110         en = g_enum_get_value (klass, i);
3111       }
3112     }
3113   }
3114   g_type_class_unref (klass);
3115 
3116   /* might be one of the custom formats registered later */
3117   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
3118     GValue res = { 0, };
3119     const GstFormatDefinition *format_def;
3120     GstIterator *iter;
3121     gboolean found;
3122 
3123     iter = gst_format_iterate_definitions ();
3124 
3125     found = gst_iterator_find_custom (iter,
3126         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
3127 
3128     if (found) {
3129       format_def = g_value_get_pointer (&res);
3130     g_return_val_if_fail (format_def != NULL, FALSE);
3131     g_value_set_enum (dest, (gint) format_def->value);
3132       g_value_unset (&res);
3133     }
3134     gst_iterator_free (iter);
3135     return found;
3136   }
3137 
3138   /* enum name/nick not found */
3139   if (en == NULL)
3140     return FALSE;
3141 
3142   g_value_set_enum (dest, en->value);
3143   return TRUE;
3144 }
3145 
3146 /********
3147  * flags *
3148  ********/
3149 
3150 /* we just compare the value here */
3151 static gint
3152 gst_value_compare_flags (const GValue * value1, const GValue * value2)
3153 {
3154   guint fl1, fl2;
3155   GFlagsClass *klass1 =
3156       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3157   GFlagsClass *klass2 =
3158       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3159 
3160   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3161   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3162   fl1 = g_value_get_flags (value1);
3163   fl2 = g_value_get_flags (value2);
3164   g_type_class_unref (klass1);
3165   g_type_class_unref (klass2);
3166   if (fl1 < fl2)
3167     return GST_VALUE_LESS_THAN;
3168   if (fl1 > fl2)
3169     return GST_VALUE_GREATER_THAN;
3170 
3171   return GST_VALUE_EQUAL;
3172 }
3173 
3174 /* the different flags are serialized separated with a + */
3175 static gchar *
3176 gst_value_serialize_flags (const GValue * value)
3177 {
3178   guint flags;
3179   GFlagsValue *fl;
3180   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
3181   gchar *result, *tmp;
3182   gboolean first = TRUE;
3183 
3184   g_return_val_if_fail (klass, NULL);
3185 
3186   flags = g_value_get_flags (value);
3187 
3188   /* if no flags are set, try to serialize to the _NONE string */
3189   if (!flags) {
3190     fl = g_flags_get_first_value (klass, flags);
3191     if (fl)
3192     return g_strdup (fl->value_name);
3193     else
3194       return g_strdup ("0");
3195   }
3196 
3197   /* some flags are set, so serialize one by one */
3198   result = g_strdup ("");
3199   while (flags) {
3200     fl = g_flags_get_first_value (klass, flags);
3201     if (fl != NULL) {
3202       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
3203       g_free (result);
3204       result = tmp;
3205       first = FALSE;
3206 
3207       /* clear flag */
3208       flags &= ~fl->value;
3209     }
3210   }
3211   g_type_class_unref (klass);
3212 
3213   return result;
3214 }
3215 
3216 static gboolean
3217 gst_value_deserialize_flags (GValue * dest, const gchar * s)
3218 {
3219   GFlagsValue *fl;
3220   gchar *endptr = NULL;
3221   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3222   gchar **split;
3223   guint flags;
3224   gint i;
3225 
3226   g_return_val_if_fail (klass, FALSE);
3227 
3228   /* split into parts delimited with + */
3229   split = g_strsplit (s, "+", 0);
3230 
3231   flags = 0;
3232   i = 0;
3233   /* loop over each part */
3234   while (split[i]) {
3235     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
3236       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
3237         gint val = strtol (split[i], &endptr, 0);
3238 
3239         /* just or numeric value */
3240         if (endptr && *endptr == '\0') {
3241           flags |= val;
3242         }
3243       }
3244     }
3245     if (fl) {
3246       flags |= fl->value;
3247     }
3248     i++;
3249   }
3250   g_strfreev (split);
3251   g_type_class_unref (klass);
3252   g_value_set_flags (dest, flags);
3253 
3254   return TRUE;
3255 }
3256 
3257 /****************
3258  * subset *
3259  ****************/
3260 
3261 static gboolean
3262 gst_value_is_subset_int_range_int_range (const GValue * value1,
3263     const GValue * value2)
3264 {
3265   gint gcd;
3266 
3267   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
3268   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
3269 
3270   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
3271       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
3272     return FALSE;
3273   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
3274       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
3275     return FALSE;
3276 
3277   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
3278     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
3279         INT_RANGE_STEP (value1))
3280       return FALSE;
3281     return TRUE;
3282   }
3283 
3284   gcd =
3285       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
3286       INT_RANGE_STEP (value2));
3287   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
3288     return FALSE;
3289 
3290   return TRUE;
3291 }
3292 
3293 static gboolean
3294 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
3295     const GValue * value2)
3296 {
3297   gint64 gcd;
3298 
3299   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
3300   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
3301 
3302   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
3303     return FALSE;
3304   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
3305     return FALSE;
3306 
3307   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
3308     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
3309         INT64_RANGE_STEP (value1))
3310       return FALSE;
3311     return TRUE;
3312   }
3313 
3314   gcd =
3315       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
3316       INT64_RANGE_STEP (value2));
3317   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
3318     return FALSE;
3319 
3320   return TRUE;
3321 }
3322 
3323 /**
3324  * gst_value_is_subset:
3325  * @value1: a #GValue
3326  * @value2: a #GValue
3327  *
3328  * Check that @value1 is a subset of @value2.
3329  *
3330  * Return: %TRUE is @value1 is a subset of @value2
3331  */
3332 gboolean
3333 gst_value_is_subset (const GValue * value1, const GValue * value2)
3334 {
3335   /* special case for int/int64 ranges, since we cannot compute
3336      the difference for those when they have different steps,
3337      and it's actually a lot simpler to compute whether a range
3338      is a subset of another. */
3339   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
3340     return gst_value_is_subset_int_range_int_range (value1, value2);
3341   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
3342       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
3343     return gst_value_is_subset_int64_range_int64_range (value1, value2);
3344   }
3345 
3346   /*
3347    * 1 - [1,2] = empty
3348    * -> !subset
3349    *
3350    * [1,2] - 1 = 2
3351    *  -> 1 - [1,2] = empty
3352    *  -> subset
3353    *
3354    * [1,3] - [1,2] = 3
3355    * -> [1,2] - [1,3] = empty
3356    * -> subset
3357    *
3358    * {1,2} - {1,3} = 2
3359    * -> {1,3} - {1,2} = 3
3360    * -> !subset
3361    *
3362    *  First caps subtraction needs to return a non-empty set, second
3363    *  subtractions needs to give en empty set.
3364    *  Both substractions are switched below, as it's faster that way.
3365    */
3366   if (!gst_value_subtract (NULL, value1, value2)) {
3367     if (gst_value_subtract (NULL, value2, value1)) {
3368       return TRUE;
3369     }
3370   }
3371   return FALSE;
3372 }
3373 
3374 /*********
3375  * union *
3376  *********/
3377 
3378 static gboolean
3379 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
3380     const GValue * src2)
3381 {
3382   gint v = src1->data[0].v_int;
3383 
3384   /* check if it's already in the range */
3385   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
3386       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
3387       v % INT_RANGE_STEP (src2) == 0) {
3388     if (dest)
3389     gst_value_init_and_copy (dest, src2);
3390     return TRUE;
3391   }
3392 
3393   /* check if it extends the range */
3394   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
3395     if (dest) {
3396       guint64 new_min =
3397           (guint) ((INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2));
3398       guint64 new_max = (guint) (INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3399 
3400       gst_value_init_and_copy (dest, src2);
3401       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3402     }
3403     return TRUE;
3404   }
3405   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
3406     if (dest) {
3407       guint64 new_min = (guint) (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3408       guint64 new_max =
3409           (guint) ((INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2));
3410 
3411       gst_value_init_and_copy (dest, src2);
3412       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3413     }
3414     return TRUE;
3415   }
3416 
3417   return FALSE;
3418 }
3419 
3420 static gboolean
3421 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
3422     const GValue * src2)
3423 {
3424   /* We can union in several special cases:
3425      1 - one is a subset of another
3426      2 - same step and not disjoint
3427      3 - different step, at least one with one value which matches a 'next' or 'previous'
3428      - anything else ?
3429    */
3430 
3431   /* 1 - subset */
3432   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
3433     if (dest)
3434       gst_value_init_and_copy (dest, src2);
3435     return TRUE;
3436   }
3437   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
3438     if (dest)
3439       gst_value_init_and_copy (dest, src1);
3440     return TRUE;
3441   }
3442 
3443   /* 2 - same step and not disjoint */
3444   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
3445     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
3446             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
3447         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
3448             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
3449       if (dest) {
3450         gint step = INT_RANGE_STEP (src1);
3451         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
3452         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
3453     g_value_init (dest, GST_TYPE_INT_RANGE);
3454         gst_value_set_int_range_step (dest, min, max, step);
3455       }
3456     return TRUE;
3457   }
3458   }
3459 
3460   /* 3 - single value matches next or previous */
3461   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
3462     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
3463     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
3464     if (n1 == 1 || n2 == 1) {
3465       const GValue *range_value = NULL;
3466       gint scalar = 0;
3467       if (n1 == 1) {
3468         range_value = src2;
3469         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
3470       } else if (n2 == 1) {
3471         range_value = src1;
3472         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
3473       }
3474 
3475       if (scalar ==
3476           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
3477         if (dest) {
3478           guint64 new_min = (guint)
3479               ((INT_RANGE_MIN (range_value) -
3480                   1) * INT_RANGE_STEP (range_value));
3481           guint64 new_max = (guint)
3482               (INT_RANGE_MAX (range_value) * INT_RANGE_STEP (range_value));
3483 
3484           gst_value_init_and_copy (dest, range_value);
3485           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3486         }
3487         return TRUE;
3488       } else if (scalar ==
3489           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
3490         if (dest) {
3491           guint64 new_min = (guint)
3492               (INT_RANGE_MIN (range_value) * INT_RANGE_STEP (range_value));
3493           guint64 new_max = (guint)
3494               ((INT_RANGE_MAX (range_value) +
3495                   1) * INT_RANGE_STEP (range_value));
3496           gst_value_init_and_copy (dest, range_value);
3497           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3498         }
3499         return TRUE;
3500       }
3501     }
3502   }
3503 
3504   /* If we get there, we did not find a way to make a union that can be
3505      represented with our simplistic model. */
3506   return FALSE;
3507 }
3508 
3509 /****************
3510  * intersection *
3511  ****************/
3512 
3513 static gboolean
3514 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
3515     const GValue * src2)
3516 {
3517   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
3518       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
3519       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
3520     if (dest)
3521     gst_value_init_and_copy (dest, src1);
3522     return TRUE;
3523   }
3524 
3525   return FALSE;
3526 }
3527 
3528 static gboolean
3529 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
3530     const GValue * src2)
3531 {
3532   gint min;
3533   gint max;
3534   gint step;
3535 
3536   step =
3537       INT_RANGE_STEP (src1) /
3538       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
3539       INT_RANGE_STEP (src2));
3540   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
3541     return FALSE;
3542   step *= INT_RANGE_STEP (src2);
3543 
3544   min =
3545       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
3546       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3547   min = (min + step - 1) / step * step;
3548   max =
3549       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
3550       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3551   max = max / step * step;
3552 
3553   if (min < max) {
3554     if (dest) {
3555     g_value_init (dest, GST_TYPE_INT_RANGE);
3556       gst_value_set_int_range_step (dest, min, max, step);
3557     }
3558     return TRUE;
3559   }
3560   if (min == max) {
3561     if (dest) {
3562     g_value_init (dest, G_TYPE_INT);
3563     g_value_set_int (dest, min);
3564     }
3565     return TRUE;
3566   }
3567 
3568   return FALSE;
3569 }
3570 
3571 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
3572 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
3573 
3574 static gboolean
3575 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
3576     const GValue * src2)
3577 {
3578   if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
3579       INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
3580       src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
3581     if (dest)
3582     gst_value_init_and_copy (dest, src1);
3583     return TRUE;
3584   }
3585 
3586   return FALSE;
3587 }
3588 
3589 static gboolean
3590 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
3591     const GValue * src2)
3592 {
3593   gint64 min;
3594   gint64 max;
3595   gint64 step;
3596 
3597   step =
3598       INT64_RANGE_STEP (src1) /
3599       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
3600       INT64_RANGE_STEP (src2));
3601   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
3602     return FALSE;
3603   step *= INT64_RANGE_STEP (src2);
3604 
3605   min =
3606       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
3607       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
3608   min = (min + step - 1) / step * step;
3609   max =
3610       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
3611       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
3612   max = max / step * step;
3613 
3614   if (min < max) {
3615     if (dest) {
3616     g_value_init (dest, GST_TYPE_INT64_RANGE);
3617       gst_value_set_int64_range_step (dest, min, max, step);
3618     }
3619     return TRUE;
3620   }
3621   if (min == max) {
3622     if (dest) {
3623     g_value_init (dest, G_TYPE_INT64);
3624     g_value_set_int64 (dest, min);
3625     }
3626     return TRUE;
3627   }
3628 
3629   return FALSE;
3630 }
3631 
3632 static gboolean
3633 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
3634     const GValue * src2)
3635 {
3636   if (src2->data[0].v_double <= src1->data[0].v_double &&
3637       src2->data[1].v_double >= src1->data[0].v_double) {
3638     if (dest)
3639     gst_value_init_and_copy (dest, src1);
3640     return TRUE;
3641   }
3642 
3643   return FALSE;
3644 }
3645 
3646 static gboolean
3647 gst_value_intersect_double_range_double_range (GValue * dest,
3648     const GValue * src1, const GValue * src2)
3649 {
3650   gdouble min;
3651   gdouble max;
3652 
3653   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
3654   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
3655 
3656   if (min < max) {
3657     if (dest) {
3658     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
3659     gst_value_set_double_range (dest, min, max);
3660     }
3661     return TRUE;
3662   }
3663   if (min == max) {
3664     if (dest) {
3665     g_value_init (dest, G_TYPE_DOUBLE);
3666     g_value_set_int (dest, (int) min);
3667     }
3668     return TRUE;
3669   }
3670 
3671   return FALSE;
3672 }
3673 
3674 static gboolean
3675 gst_value_intersect_list (GValue * dest, const GValue * value1,
3676     const GValue * value2)
3677 {
3678   guint i, size;
3679   GValue intersection = { 0, };
3680   gboolean ret = FALSE;
3681 
3682   size = VALUE_LIST_SIZE (value1);
3683   for (i = 0; i < size; i++) {
3684     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
3685 
3686     /* quicker version when we don't need the resulting set */
3687     if (!dest) {
3688       if (gst_value_intersect (NULL, cur, value2)) {
3689         ret = TRUE;
3690         break;
3691       }
3692       continue;
3693     }
3694 
3695     if (gst_value_intersect (&intersection, cur, value2)) {
3696       /* append value */
3697       if (!ret) {
3698         gst_value_move (dest, &intersection);
3699         ret = TRUE;
3700       } else if (GST_VALUE_HOLDS_LIST (dest)) {
3701         _gst_value_list_append_and_take_value (dest, &intersection);
3702       } else {
3703         GValue temp;
3704 
3705         gst_value_move (&temp, dest);
3706         gst_value_list_merge (dest, &temp, &intersection);
3707         g_value_unset (&temp);
3708       g_value_unset (&intersection);
3709     }
3710   }
3711   }
3712 
3713   return ret;
3714 }
3715 
3716 static gboolean
3717 gst_value_intersect_array (GValue * dest, const GValue * src1,
3718     const GValue * src2)
3719 {
3720   guint size;
3721   guint n;
3722   GValue val = { 0 };
3723 
3724   /* only works on similar-sized arrays */
3725   size = gst_value_array_get_size (src1);
3726   if (size != gst_value_array_get_size (src2))
3727     return FALSE;
3728 
3729   /* quicker value when we don't need the resulting set */
3730   if (!dest) {
3731     for (n = 0; n < size; n++) {
3732       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
3733               gst_value_array_get_value (src2, n))) {
3734         return FALSE;
3735       }
3736     }
3737     return TRUE;
3738   }
3739 
3740   g_value_init (dest, GST_TYPE_ARRAY);
3741 
3742   for (n = 0; n < size; n++) {
3743     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
3744             gst_value_array_get_value (src2, n))) {
3745       g_value_unset (dest);
3746       return FALSE;
3747     }
3748     _gst_value_array_append_and_take_value (dest, &val);
3749   }
3750 
3751   return TRUE;
3752 }
3753 
3754 static gboolean
3755 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
3756     const GValue * src2)
3757 {
3758   gint res1, res2;
3759   GValue *vals;
3760   GstValueCompareFunc compare;
3761 
3762   vals = src2->data[0].v_pointer;
3763 
3764   if (vals == NULL)
3765     return FALSE;
3766 
3767   if ((compare = gst_value_get_compare_func (src1))) {
3768     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
3769     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
3770 
3771     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
3772         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
3773       if (dest)
3774       gst_value_init_and_copy (dest, src1);
3775       return TRUE;
3776     }
3777   }
3778 
3779   return FALSE;
3780 }
3781 
3782 static gboolean
3783 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
3784     const GValue * src1, const GValue * src2)
3785 {
3786   GValue *min;
3787   GValue *max;
3788   gint res;
3789   GValue *vals1, *vals2;
3790   GstValueCompareFunc compare;
3791 
3792   vals1 = src1->data[0].v_pointer;
3793   vals2 = src2->data[0].v_pointer;
3794   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
3795 
3796   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
3797     /* min = MAX (src1.start, src2.start) */
3798     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
3799     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3800     if (res == GST_VALUE_LESS_THAN)
3801       min = &vals2[0];          /* Take the max of the 2 */
3802     else
3803       min = &vals1[0];
3804 
3805     /* max = MIN (src1.end, src2.end) */
3806     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
3807     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3808     if (res == GST_VALUE_GREATER_THAN)
3809       max = &vals2[1];          /* Take the min of the 2 */
3810     else
3811       max = &vals1[1];
3812 
3813     res = gst_value_compare_with_func (min, max, compare);
3814     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3815     if (res == GST_VALUE_LESS_THAN) {
3816       if (dest) {
3817       g_value_init (dest, GST_TYPE_FRACTION_RANGE);
3818       vals1 = dest->data[0].v_pointer;
3819       g_value_copy (min, &vals1[0]);
3820       g_value_copy (max, &vals1[1]);
3821       }
3822       return TRUE;
3823     }
3824     if (res == GST_VALUE_EQUAL) {
3825       if (dest)
3826       gst_value_init_and_copy (dest, min);
3827       return TRUE;
3828     }
3829   }
3830 
3831   return FALSE;
3832 }
3833 
3834 /***************
3835  * subtraction *
3836  ***************/
3837 
3838 static gboolean
3839 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
3840     const GValue * subtrahend)
3841 {
3842   gint min = gst_value_get_int_range_min (subtrahend);
3843   gint max = gst_value_get_int_range_max (subtrahend);
3844   gint step = gst_value_get_int_range_step (subtrahend);
3845   gint val = g_value_get_int (minuend);
3846 
3847   if (step == 0)
3848     return FALSE;
3849 
3850   /* subtracting a range from an int only works if the int is not in the
3851    * range */
3852   if (val < min || val > max || val % step) {
3853     /* and the result is the int */
3854     if (dest)
3855     gst_value_init_and_copy (dest, minuend);
3856     return TRUE;
3857   }
3858   return FALSE;
3859 }
3860 
3861 /* creates a new int range based on input values.
3862  */
3863 static gboolean
3864 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
3865     gint max2, gint step)
3866 {
3867   GValue v1 = { 0, };
3868   GValue v2 = { 0, };
3869   GValue *pv1, *pv2;            /* yeah, hungarian! */
3870 
3871   g_return_val_if_fail (step > 0, FALSE);
3872   g_return_val_if_fail (min1 % step == 0, FALSE);
3873   g_return_val_if_fail (max1 % step == 0, FALSE);
3874   g_return_val_if_fail (min2 % step == 0, FALSE);
3875   g_return_val_if_fail (max2 % step == 0, FALSE);
3876 
3877   if (min1 <= max1 && min2 <= max2) {
3878     pv1 = &v1;
3879     pv2 = &v2;
3880   } else if (min1 <= max1) {
3881     pv1 = dest;
3882     pv2 = NULL;
3883   } else if (min2 <= max2) {
3884     pv1 = NULL;
3885     pv2 = dest;
3886   } else {
3887     return FALSE;
3888   }
3889 
3890   if (!dest)
3891     return TRUE;
3892 
3893   if (min1 < max1) {
3894     g_value_init (pv1, GST_TYPE_INT_RANGE);
3895     gst_value_set_int_range_step (pv1, min1, max1, step);
3896   } else if (min1 == max1) {
3897     g_value_init (pv1, G_TYPE_INT);
3898     g_value_set_int (pv1, min1);
3899   }
3900   if (min2 < max2) {
3901     g_value_init (pv2, GST_TYPE_INT_RANGE);
3902     gst_value_set_int_range_step (pv2, min2, max2, step);
3903   } else if (min2 == max2) {
3904     g_value_init (pv2, G_TYPE_INT);
3905     g_value_set_int (pv2, min2);
3906   }
3907 
3908   if (min1 <= max1 && min2 <= max2) {
3909     gst_value_list_concat_and_take_values (dest, pv1, pv2);
3910   }
3911   return TRUE;
3912 }
3913 
3914 static gboolean
3915 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
3916     const GValue * subtrahend)
3917 {
3918   gint min = gst_value_get_int_range_min (minuend);
3919   gint max = gst_value_get_int_range_max (minuend);
3920   gint step = gst_value_get_int_range_step (minuend);
3921   gint val = g_value_get_int (subtrahend);
3922 
3923   g_return_val_if_fail (min < max, FALSE);
3924 
3925   if (step == 0)
3926     return FALSE;
3927 
3928   /* value is outside of the range, return range unchanged */
3929   if (val < min || val > max || val % step) {
3930     if (dest)
3931     gst_value_init_and_copy (dest, minuend);
3932     return TRUE;
3933   } else {
3934     /* max must be MAXINT too as val <= max */
3935     if (val >= G_MAXINT - step + 1) {
3936       max -= step;
3937       val -= step;
3938     }
3939     /* min must be MININT too as val >= max */
3940     if (val <= G_MININT + step - 1) {
3941       min += step;
3942       val += step;
3943     }
3944     if (dest)
3945       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
3946   }
3947   return TRUE;
3948 }
3949 
3950 static gboolean
3951 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
3952     const GValue * subtrahend)
3953 {
3954   gint min1 = gst_value_get_int_range_min (minuend);
3955   gint max1 = gst_value_get_int_range_max (minuend);
3956   gint step1 = gst_value_get_int_range_step (minuend);
3957   gint min2 = gst_value_get_int_range_min (subtrahend);
3958   gint max2 = gst_value_get_int_range_max (subtrahend);
3959   gint step2 = gst_value_get_int_range_step (subtrahend);
3960   gint step;
3961 
3962   if (step1 != step2) {
3963     /* ENOIMPL */
3964     g_assert (FALSE);
3965     return FALSE;
3966   }
3967   step = step1;
3968 
3969   if (step == 0)
3970     return FALSE;
3971 
3972   if (max2 >= max1 && min2 <= min1) {
3973     return FALSE;
3974   } else if (max2 >= max1) {
3975     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3976         step, 0, step);
3977   } else if (min2 <= min1) {
3978     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
3979         step, 0, step);
3980   } else {
3981     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3982         MAX (max2 + step, min1), max1, step);
3983   }
3984 }
3985 
3986 static gboolean
3987 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
3988     const GValue * subtrahend)
3989 {
3990   gint64 min = gst_value_get_int64_range_min (subtrahend);
3991   gint64 max = gst_value_get_int64_range_max (subtrahend);
3992   gint64 step = gst_value_get_int64_range_step (subtrahend);
3993   gint64 val = g_value_get_int64 (minuend);
3994 
3995   if (step == 0)
3996     return FALSE;
3997   /* subtracting a range from an int64 only works if the int64 is not in the
3998    * range */
3999   if (val < min || val > max || val % step) {
4000     /* and the result is the int64 */
4001     if (dest)
4002     gst_value_init_and_copy (dest, minuend);
4003     return TRUE;
4004   }
4005   return FALSE;
4006 }
4007 
4008 /* creates a new int64 range based on input values.
4009  */
4010 static gboolean
4011 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
4012     gint64 min2, gint64 max2, gint64 step)
4013 {
4014   GValue v1 = { 0, };
4015   GValue v2 = { 0, };
4016   GValue *pv1, *pv2;            /* yeah, hungarian! */
4017 
4018   g_return_val_if_fail (step > 0, FALSE);
4019   g_return_val_if_fail (min1 % step == 0, FALSE);
4020   g_return_val_if_fail (max1 % step == 0, FALSE);
4021   g_return_val_if_fail (min2 % step == 0, FALSE);
4022   g_return_val_if_fail (max2 % step == 0, FALSE);
4023 
4024   if (min1 <= max1 && min2 <= max2) {
4025     pv1 = &v1;
4026     pv2 = &v2;
4027   } else if (min1 <= max1) {
4028     pv1 = dest;
4029     pv2 = NULL;
4030   } else if (min2 <= max2) {
4031     pv1 = NULL;
4032     pv2 = dest;
4033   } else {
4034     return FALSE;
4035   }
4036 
4037   if (!dest)
4038     return TRUE;
4039 
4040   if (min1 < max1) {
4041     g_value_init (pv1, GST_TYPE_INT64_RANGE);
4042     gst_value_set_int64_range_step (pv1, min1, max1, step);
4043   } else if (min1 == max1) {
4044     g_value_init (pv1, G_TYPE_INT64);
4045     g_value_set_int64 (pv1, min1);
4046   }
4047   if (min2 < max2) {
4048     g_value_init (pv2, GST_TYPE_INT64_RANGE);
4049     gst_value_set_int64_range_step (pv2, min2, max2, step);
4050   } else if (min2 == max2) {
4051     g_value_init (pv2, G_TYPE_INT64);
4052     g_value_set_int64 (pv2, min2);
4053   }
4054 
4055   if (min1 <= max1 && min2 <= max2) {
4056     gst_value_list_concat_and_take_values (dest, pv1, pv2);
4057   }
4058   return TRUE;
4059 }
4060 
4061 static gboolean
4062 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
4063     const GValue * subtrahend)
4064 {
4065   gint64 min = gst_value_get_int64_range_min (minuend);
4066   gint64 max = gst_value_get_int64_range_max (minuend);
4067   gint64 step = gst_value_get_int64_range_step (minuend);
4068   gint64 val = g_value_get_int64 (subtrahend);
4069 
4070   g_return_val_if_fail (min < max, FALSE);
4071 
4072   if (step == 0)
4073     return FALSE;
4074 
4075   /* value is outside of the range, return range unchanged */
4076   if (val < min || val > max || val % step) {
4077     if (dest)
4078     gst_value_init_and_copy (dest, minuend);
4079     return TRUE;
4080   } else {
4081     /* max must be MAXINT64 too as val <= max */
4082     if (val >= G_MAXINT64 - step + 1) {
4083       max -= step;
4084       val -= step;
4085     }
4086     /* min must be MININT64 too as val >= max */
4087     if (val <= G_MININT64 + step - 1) {
4088       min += step;
4089       val += step;
4090     }
4091     if (dest)
4092       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
4093           step);
4094   }
4095   return TRUE;
4096 }
4097 
4098 static gboolean
4099 gst_value_subtract_int64_range_int64_range (GValue * dest,
4100     const GValue * minuend, const GValue * subtrahend)
4101 {
4102   gint64 min1 = gst_value_get_int64_range_min (minuend);
4103   gint64 max1 = gst_value_get_int64_range_max (minuend);
4104   gint64 step1 = gst_value_get_int64_range_step (minuend);
4105   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
4106   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
4107   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
4108   gint64 step;
4109 
4110   if (step1 != step2) {
4111     /* ENOIMPL */
4112     g_assert (FALSE);
4113     return FALSE;
4114   }
4115 
4116   if (step1 == 0)
4117     return FALSE;
4118 
4119   step = step1;
4120 
4121   if (max2 >= max1 && min2 <= min1) {
4122     return FALSE;
4123   } else if (max2 >= max1) {
4124     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4125             max1), step, 0, step);
4126   } else if (min2 <= min1) {
4127     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
4128         max1, step, 0, step);
4129   } else {
4130     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4131             max1), MAX (max2 + step, min1), max1, step);
4132   }
4133 }
4134 
4135 static gboolean
4136 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
4137     const GValue * subtrahend)
4138 {
4139   gdouble min = gst_value_get_double_range_min (subtrahend);
4140   gdouble max = gst_value_get_double_range_max (subtrahend);
4141   gdouble val = g_value_get_double (minuend);
4142 
4143   if (val < min || val > max) {
4144     if (dest)
4145     gst_value_init_and_copy (dest, minuend);
4146     return TRUE;
4147   }
4148   return FALSE;
4149 }
4150 
4151 static gboolean
4152 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
4153     const GValue * subtrahend)
4154 {
4155   /* since we don't have open ranges, we cannot create a hole in
4156    * a double range. We return the original range */
4157   if (dest)
4158   gst_value_init_and_copy (dest, minuend);
4159   return TRUE;
4160 }
4161 
4162 static gboolean
4163 gst_value_subtract_double_range_double_range (GValue * dest,
4164     const GValue * minuend, const GValue * subtrahend)
4165 {
4166   /* since we don't have open ranges, we have to approximate */
4167   /* done like with ints */
4168   gdouble min1 = gst_value_get_double_range_min (minuend);
4169   gdouble max2 = gst_value_get_double_range_max (minuend);
4170   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
4171   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
4172   GValue v1 = { 0, };
4173   GValue v2 = { 0, };
4174   GValue *pv1, *pv2;            /* yeah, hungarian! */
4175 
4176   if (min1 < max1 && min2 < max2) {
4177     pv1 = &v1;
4178     pv2 = &v2;
4179   } else if (min1 < max1) {
4180     pv1 = dest;
4181     pv2 = NULL;
4182   } else if (min2 < max2) {
4183     pv1 = NULL;
4184     pv2 = dest;
4185   } else {
4186     return FALSE;
4187   }
4188 
4189   if (!dest)
4190     return TRUE;
4191 
4192   if (min1 < max1) {
4193     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
4194     gst_value_set_double_range (pv1, min1, max1);
4195   }
4196   if (min2 < max2) {
4197     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
4198     gst_value_set_double_range (pv2, min2, max2);
4199   }
4200 
4201   if (min1 < max1 && min2 < max2) {
4202     gst_value_list_concat_and_take_values (dest, pv1, pv2);
4203   }
4204   return TRUE;
4205 }
4206 
4207 static gboolean
4208 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
4209     const GValue * subtrahend)
4210 {
4211   guint i, size;
4212   GValue subtraction = { 0, };
4213   gboolean ret = FALSE;
4214 
4215   size = VALUE_LIST_SIZE (minuend);
4216   for (i = 0; i < size; i++) {
4217     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
4218 
4219     /* quicker version when we can discard the result */
4220     if (!dest) {
4221       if (gst_value_subtract (NULL, cur, subtrahend)) {
4222         ret = TRUE;
4223         break;
4224       }
4225       continue;
4226     }
4227 
4228     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
4229       if (!ret) {
4230         gst_value_move (dest, &subtraction);
4231         ret = TRUE;
4232       } else if (G_VALUE_TYPE (dest) == GST_TYPE_LIST
4233           && G_VALUE_TYPE (&subtraction) != GST_TYPE_LIST) {
4234         _gst_value_list_append_and_take_value (dest, &subtraction);
4235       } else {
4236         GValue temp;
4237 
4238         gst_value_move (&temp, dest);
4239         gst_value_list_concat_and_take_values (dest, &temp, &subtraction);
4240       }
4241     }
4242   }
4243   return ret;
4244 }
4245 
4246 static gboolean
4247 gst_value_subtract_list (GValue * dest, const GValue * minuend,
4248     const GValue * subtrahend)
4249 {
4250   guint i, size;
4251   GValue data[2] = { {0,}, {0,} };
4252   GValue *subtraction = &data[0], *result = &data[1];
4253 
4254   gst_value_init_and_copy (result, minuend);
4255   size = VALUE_LIST_SIZE (subtrahend);
4256   for (i = 0; i < size; i++) {
4257     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
4258 
4259     if (gst_value_subtract (subtraction, result, cur)) {
4260       GValue *temp = result;
4261 
4262       result = subtraction;
4263       subtraction = temp;
4264       g_value_unset (subtraction);
4265     } else {
4266       g_value_unset (result);
4267       return FALSE;
4268     }
4269   }
4270   if (dest) {
4271     gst_value_move (dest, result);
4272   } else {
4273   g_value_unset (result);
4274   }
4275   return TRUE;
4276 }
4277 
4278 static gboolean
4279 gst_value_subtract_fraction_fraction_range (GValue * dest,
4280     const GValue * minuend, const GValue * subtrahend)
4281 {
4282   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
4283   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
4284   GstValueCompareFunc compare;
4285 
4286   if ((compare = gst_value_get_compare_func (minuend))) {
4287     /* subtracting a range from an fraction only works if the fraction
4288      * is not in the range */
4289     if (gst_value_compare_with_func (minuend, min, compare) ==
4290         GST_VALUE_LESS_THAN ||
4291         gst_value_compare_with_func (minuend, max, compare) ==
4292         GST_VALUE_GREATER_THAN) {
4293       /* and the result is the value */
4294       if (dest)
4295       gst_value_init_and_copy (dest, minuend);
4296       return TRUE;
4297     }
4298   }
4299   return FALSE;
4300 }
4301 
4302 static gboolean
4303 gst_value_subtract_fraction_range_fraction (GValue * dest,
4304     const GValue * minuend, const GValue * subtrahend)
4305 {
4306   /* since we don't have open ranges, we cannot create a hole in
4307    * a range. We return the original range */
4308   if (dest)
4309   gst_value_init_and_copy (dest, minuend);
4310   return TRUE;
4311 }
4312 
4313 static gboolean
4314 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
4315     const GValue * minuend, const GValue * subtrahend)
4316 {
4317   /* since we don't have open ranges, we have to approximate */
4318   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
4319   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
4320   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
4321   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
4322   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
4323   gint cmp1, cmp2;
4324   GValue v1 = { 0, };
4325   GValue v2 = { 0, };
4326   GValue *pv1, *pv2;            /* yeah, hungarian! */
4327   GstValueCompareFunc compare;
4328 
4329   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
4330   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
4331 
4332   compare = gst_value_get_compare_func (min1);
4333   g_return_val_if_fail (compare, FALSE);
4334 
4335   cmp1 = gst_value_compare_with_func (max2, max1, compare);
4336   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4337   if (cmp1 == GST_VALUE_LESS_THAN)
4338     max1 = max2;
4339   cmp1 = gst_value_compare_with_func (min1, min2, compare);
4340   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4341   if (cmp1 == GST_VALUE_GREATER_THAN)
4342     min2 = min1;
4343 
4344   cmp1 = gst_value_compare_with_func (min1, max1, compare);
4345   cmp2 = gst_value_compare_with_func (min2, max2, compare);
4346 
4347   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4348     pv1 = &v1;
4349     pv2 = &v2;
4350   } else if (cmp1 == GST_VALUE_LESS_THAN) {
4351     pv1 = dest;
4352     pv2 = NULL;
4353   } else if (cmp2 == GST_VALUE_LESS_THAN) {
4354     pv1 = NULL;
4355     pv2 = dest;
4356   } else {
4357     return FALSE;
4358   }
4359 
4360   if (!dest)
4361     return TRUE;
4362 
4363   if (cmp1 == GST_VALUE_LESS_THAN) {
4364     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
4365     gst_value_set_fraction_range (pv1, min1, max1);
4366   }
4367   if (cmp2 == GST_VALUE_LESS_THAN) {
4368     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
4369     gst_value_set_fraction_range (pv2, min2, max2);
4370   }
4371 
4372   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4373     gst_value_list_concat_and_take_values (dest, pv1, pv2);
4374   }
4375   return TRUE;
4376 }
4377 
4378 
4379 /**************
4380  * comparison *
4381  **************/
4382 
4383 /*
4384  * gst_value_get_compare_func:
4385  * @value1: a value to get the compare function for
4386  *
4387  * Determines the compare function to be used with values of the same type as
4388  * @value1. The function can be given to gst_value_compare_with_func().
4389  *
4390  * Returns: A #GstValueCompareFunc value
4391  */
4392 static GstValueCompareFunc
4393 gst_value_get_compare_func (const GValue * value1)
4394 {
4395   GstValueTable *table, *best = NULL;
4396   guint i;
4397   GType type1;
4398 
4399   type1 = G_VALUE_TYPE (value1);
4400 
4401   /* this is a fast check */
4402   best = gst_value_hash_lookup_type (type1);
4403 
4404   /* slower checks */
4405   if (G_UNLIKELY (!best || !best->compare)) {
4406     guint len = gst_value_table->len;
4407 
4408     best = NULL;
4409     for (i = 0; i < len; i++) {
4410       table = &g_array_index (gst_value_table, GstValueTable, i);
4411       if (table->compare && g_type_is_a (type1, table->type)) {
4412         if (!best || g_type_is_a (table->type, best->type))
4413           best = table;
4414       }
4415     }
4416   }
4417   if (G_LIKELY (best))
4418     return best->compare;
4419 
4420   return NULL;
4421 }
4422 
4423 static inline gboolean
4424 gst_value_can_compare_unchecked (const GValue * value1, const GValue * value2)
4425 {
4426   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4427     return FALSE;
4428 
4429   return gst_value_get_compare_func (value1) != NULL;
4430 }
4431 
4432 /**
4433  * gst_value_can_compare:
4434  * @value1: a value to compare
4435  * @value2: another value to compare
4436  *
4437  * Determines if @value1 and @value2 can be compared.
4438  *
4439  * Returns: %TRUE if the values can be compared
4440  */
4441 gboolean
4442 gst_value_can_compare (const GValue * value1, const GValue * value2)
4443 {
4444   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4445   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4446 
4447   return gst_value_can_compare_unchecked (value1, value2);
4448 }
4449 
4450 static gboolean
4451 gst_value_list_equals_range (const GValue * list, const GValue * value)
4452 {
4453   const GValue *first;
4454   guint list_size, n;
4455 
4456   g_assert (G_IS_VALUE (list));
4457   g_assert (G_IS_VALUE (value));
4458   g_assert (GST_VALUE_HOLDS_LIST (list));
4459 
4460   /* TODO: compare against an empty list ? No type though... */
4461   list_size = VALUE_LIST_SIZE (list);
4462   if (list_size == 0)
4463     return FALSE;
4464 
4465   /* compare the basic types - they have to match */
4466   first = VALUE_LIST_GET_VALUE (list, 0);
4467 #define CHECK_TYPES(type,prefix) \
4468   (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value))
4469   if (CHECK_TYPES (INT, G)) {
4470     const gint rmin = gst_value_get_int_range_min (value);
4471     const gint rmax = gst_value_get_int_range_max (value);
4472     const gint rstep = gst_value_get_int_range_step (value);
4473     if (rstep == 0)
4474       return FALSE;
4475     /* note: this will overflow for min 0 and max INT_MAX, but this
4476        would only be equal to a list of INT_MAX elements, which seems
4477        very unlikely */
4478     if (list_size != rmax / rstep - rmin / rstep + 1)
4479       return FALSE;
4480     for (n = 0; n < list_size; ++n) {
4481       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
4482       if (v < rmin || v > rmax || v % rstep) {
4483         return FALSE;
4484       }
4485     }
4486     return TRUE;
4487   } else if (CHECK_TYPES (INT64, G)) {
4488     const gint64 rmin = gst_value_get_int64_range_min (value);
4489     const gint64 rmax = gst_value_get_int64_range_max (value);
4490     const gint64 rstep = gst_value_get_int64_range_step (value);
4491     GST_DEBUG ("List/range of int64s");
4492     if (rstep == 0)
4493       return FALSE;
4494     if (list_size != rmax / rstep - rmin / rstep + 1)
4495       return FALSE;
4496     for (n = 0; n < list_size; ++n) {
4497       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
4498       if (v < rmin || v > rmax || v % rstep)
4499         return FALSE;
4500     }
4501     return TRUE;
4502   }
4503 #undef CHECK_TYPES
4504 
4505   /* other combinations don't make sense for equality */
4506   return FALSE;
4507 }
4508 
4509 /* "Pure" variant of gst_value_compare which is guaranteed to
4510  * not have list arguments and therefore does basic comparisions
4511  */
4512 static inline gint
4513 _gst_value_compare_nolist (const GValue * value1, const GValue * value2)
4514 {
4515   GstValueCompareFunc compare;
4516 
4517   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4518     return GST_VALUE_UNORDERED;
4519 
4520   compare = gst_value_get_compare_func (value1);
4521   if (compare) {
4522     return compare (value1, value2);
4523   }
4524 
4525   g_critical ("unable to compare values of type %s\n",
4526       g_type_name (G_VALUE_TYPE (value1)));
4527   return GST_VALUE_UNORDERED;
4528 }
4529 
4530 /**
4531  * gst_value_compare:
4532  * @value1: a value to compare
4533  * @value2: another value to compare
4534  *
4535  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
4536  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
4537  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
4538  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
4539  * If the values are equal, GST_VALUE_EQUAL is returned.
4540  *
4541  * Returns: comparison result
4542  */
4543 gint
4544 gst_value_compare (const GValue * value1, const GValue * value2)
4545 {
4546   gboolean value1_is_list;
4547   gboolean value2_is_list;
4548 
4549   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
4550   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
4551 
4552   value1_is_list = G_VALUE_TYPE (value1) == GST_TYPE_LIST;
4553   value2_is_list = G_VALUE_TYPE (value2) == GST_TYPE_LIST;
4554 
4555   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
4556      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
4557   if (value1_is_list && !value2_is_list) {
4558     gint i, n, ret;
4559 
4560     if (gst_value_list_equals_range (value1, value2)) {
4561       return GST_VALUE_EQUAL;
4562     }
4563 
4564     n = gst_value_list_get_size (value1);
4565     if (n == 0)
4566     return GST_VALUE_UNORDERED;
4567 
4568     for (i = 0; i < n; i++) {
4569       const GValue *elt;
4570 
4571       elt = gst_value_list_get_value (value1, i);
4572       ret = gst_value_compare (elt, value2);
4573       if (ret != GST_VALUE_EQUAL && n == 1)
4574         return ret;
4575       else if (ret != GST_VALUE_EQUAL)
4576         return GST_VALUE_UNORDERED;
4577   }
4578 
4579     return GST_VALUE_EQUAL;
4580   } else if (value2_is_list && !value1_is_list) {
4581     gint i, n, ret;
4582 
4583     if (gst_value_list_equals_range (value2, value1)) {
4584       return GST_VALUE_EQUAL;
4585     }
4586 
4587     n = gst_value_list_get_size (value2);
4588     if (n == 0)
4589   return GST_VALUE_UNORDERED;
4590 
4591     for (i = 0; i < n; i++) {
4592       const GValue *elt;
4593 
4594       elt = gst_value_list_get_value (value2, i);
4595       ret = gst_value_compare (elt, value1);
4596       if (ret != GST_VALUE_EQUAL && n == 1)
4597         return ret;
4598       else if (ret != GST_VALUE_EQUAL)
4599         return GST_VALUE_UNORDERED;
4600     }
4601 
4602     return GST_VALUE_EQUAL;
4603   }
4604 
4605   /* And now handle the generic case */
4606   return _gst_value_compare_nolist (value1, value2);
4607 }
4608 
4609 /*
4610  * gst_value_compare_with_func:
4611  * @value1: a value to compare
4612  * @value2: another value to compare
4613  * @compare: compare function
4614  *
4615  * Compares @value1 and @value2 using the @compare function. Works like
4616  * gst_value_compare() but allows to save time determining the compare function
4617  * a multiple times.
4618  *
4619  * Returns: comparison result
4620  */
4621 static gint
4622 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
4623     GstValueCompareFunc compare)
4624 {
4625   g_assert (compare);
4626 
4627   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4628     return GST_VALUE_UNORDERED;
4629 
4630   return compare (value1, value2);
4631 }
4632 
4633 /* union */
4634 
4635 /**
4636  * gst_value_can_union:
4637  * @value1: a value to union
4638  * @value2: another value to union
4639  *
4640  * Determines if @value1 and @value2 can be non-trivially unioned.
4641  * Any two values can be trivially unioned by adding both of them
4642  * to a GstValueList.  However, certain types have the possibility
4643  * to be unioned in a simpler way.  For example, an integer range
4644  * and an integer can be unioned if the integer is a subset of the
4645  * integer range.  If there is the possibility that two values can
4646  * be unioned, this function returns %TRUE.
4647  *
4648  * Returns: %TRUE if there is a function allowing the two values to
4649  * be unioned.
4650  */
4651 gboolean
4652 gst_value_can_union (const GValue * value1, const GValue * value2)
4653 {
4654   GstValueUnionInfo *union_info;
4655   guint i, len;
4656 
4657   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4658   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4659 
4660   len = gst_value_union_funcs->len;
4661 
4662   for (i = 0; i < len; i++) {
4663     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4664     if (union_info->type1 == G_VALUE_TYPE (value1) &&
4665         union_info->type2 == G_VALUE_TYPE (value2))
4666       return TRUE;
4667     if (union_info->type1 == G_VALUE_TYPE (value2) &&
4668         union_info->type2 == G_VALUE_TYPE (value1))
4669       return TRUE;
4670   }
4671 
4672   return FALSE;
4673 }
4674 
4675 /**
4676  * gst_value_union:
4677  * @dest: (out caller-allocates): the destination value
4678  * @value1: a value to union
4679  * @value2: another value to union
4680  *
4681  * Creates a GValue corresponding to the union of @value1 and @value2.
4682  *
4683  * Returns: %TRUE if the union succeeded.
4684  */
4685 gboolean
4686 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
4687 {
4688   const GstValueUnionInfo *union_info;
4689   guint i, len;
4690   GType type1, type2;
4691 
4692   g_return_val_if_fail (dest != NULL, FALSE);
4693   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4694   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4695   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
4696       FALSE);
4697 
4698   len = gst_value_union_funcs->len;
4699   type1 = G_VALUE_TYPE (value1);
4700   type2 = G_VALUE_TYPE (value2);
4701 
4702   for (i = 0; i < len; i++) {
4703     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4704     if (union_info->type1 == type1 && union_info->type2 == type2) {
4705       return union_info->func (dest, value1, value2);
4706       }
4707     if (union_info->type1 == type2 && union_info->type2 == type1) {
4708       return union_info->func (dest, value2, value1);
4709     }
4710       }
4711 
4712   gst_value_list_concat (dest, value1, value2);
4713   return TRUE;
4714 }
4715 
4716 /* gst_value_register_union_func: (skip)
4717  * @type1: a type to union
4718  * @type2: another type to union
4719  * @func: a function that implements creating a union between the two types
4720  *
4721  * Registers a union function that can create a union between #GValue items
4722  * of the type @type1 and @type2.
4723  *
4724  * Union functions should be registered at startup before any pipelines are
4725  * started, as gst_value_register_union_func() is not thread-safe and cannot
4726  * be used at the same time as gst_value_union() or gst_value_can_union().
4727  */
4728 static void
4729 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
4730 {
4731   GstValueUnionInfo union_info;
4732 
4733   union_info.type1 = type1;
4734   union_info.type2 = type2;
4735   union_info.func = func;
4736 
4737   g_array_append_val (gst_value_union_funcs, union_info);
4738 }
4739 
4740 /* intersection */
4741 
4742 /**
4743  * gst_value_can_intersect:
4744  * @value1: a value to intersect
4745  * @value2: another value to intersect
4746  *
4747  * Determines if intersecting two values will produce a valid result.
4748  * Two values will produce a valid intersection if they have the same
4749  * type.
4750  *
4751  * Returns: %TRUE if the values can intersect
4752  */
4753 gboolean
4754 gst_value_can_intersect (const GValue * value1, const GValue * value2)
4755 {
4756   GstValueIntersectInfo *intersect_info;
4757   guint i, len;
4758   GType type1, type2;
4759 
4760   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4761   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4762 
4763   type1 = G_VALUE_TYPE (value1);
4764   type2 = G_VALUE_TYPE (value2);
4765 
4766   /* practically all GstValue types have a compare function (_can_compare=TRUE)
4767    * GstStructure and GstCaps have not, but are intersectable */
4768   if (type1 == type2)
4769     return TRUE;
4770 
4771   /* special cases */
4772   if (type1 == GST_TYPE_LIST || type2 == GST_TYPE_LIST)
4773     return TRUE;
4774 
4775   /* check registered intersect functions */
4776   len = gst_value_intersect_funcs->len;
4777   for (i = 0; i < len; i++) {
4778     intersect_info = &g_array_index (gst_value_intersect_funcs,
4779         GstValueIntersectInfo, i);
4780     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
4781         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
4782       return TRUE;
4783   }
4784 
4785   return gst_value_can_compare_unchecked (value1, value2);
4786 }
4787 
4788 /**
4789  * gst_value_intersect:
4790  * @dest: (out caller-allocates) (transfer full) (allow-none):
4791  *   a uninitialized #GValue that will hold the calculated
4792  *   intersection value. May be %NULL if the resulting set if not
4793  *   needed.
4794  * @value1: a value to intersect
4795  * @value2: another value to intersect
4796  *
4797  * Calculates the intersection of two values.  If the values have
4798  * a non-empty intersection, the value representing the intersection
4799  * is placed in @dest, unless %NULL.  If the intersection is non-empty,
4800  * @dest is not modified.
4801  *
4802  * Returns: %TRUE if the intersection is non-empty
4803  */
4804 gboolean
4805 gst_value_intersect (GValue * dest, const GValue * value1,
4806     const GValue * value2)
4807 {
4808   GstValueIntersectInfo *intersect_info;
4809   guint i, len;
4810   GType type1, type2;
4811 
4812   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4813   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4814 
4815   type1 = G_VALUE_TYPE (value1);
4816   type2 = G_VALUE_TYPE (value2);
4817 
4818   /* special cases first */
4819   if (type1 == GST_TYPE_LIST)
4820     return gst_value_intersect_list (dest, value1, value2);
4821   if (type2 == GST_TYPE_LIST)
4822     return gst_value_intersect_list (dest, value2, value1);
4823 
4824   if (_gst_value_compare_nolist (value1, value2) == GST_VALUE_EQUAL) {
4825     if (dest)
4826     gst_value_init_and_copy (dest, value1);
4827     return TRUE;
4828   }
4829 
4830   len = gst_value_intersect_funcs->len;
4831   for (i = 0; i < len; i++) {
4832     intersect_info = &g_array_index (gst_value_intersect_funcs,
4833         GstValueIntersectInfo, i);
4834     if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
4835       return intersect_info->func (dest, value1, value2);
4836     }
4837     if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
4838       return intersect_info->func (dest, value2, value1);
4839     }
4840   }
4841   return FALSE;
4842 }
4843 
4844 
4845 
4846 /* gst_value_register_intersect_func: (skip)
4847  * @type1: the first type to intersect
4848  * @type2: the second type to intersect
4849  * @func: the intersection function
4850  *
4851  * Registers a function that is called to calculate the intersection
4852  * of the values having the types @type1 and @type2.
4853  *
4854  * Intersect functions should be registered at startup before any pipelines are
4855  * started, as gst_value_register_intersect_func() is not thread-safe and
4856  * cannot be used at the same time as gst_value_intersect() or
4857  * gst_value_can_intersect().
4858  */
4859 static void
4860 gst_value_register_intersect_func (GType type1, GType type2,
4861     GstValueIntersectFunc func)
4862 {
4863   GstValueIntersectInfo intersect_info;
4864 
4865   intersect_info.type1 = type1;
4866   intersect_info.type2 = type2;
4867   intersect_info.func = func;
4868 
4869   g_array_append_val (gst_value_intersect_funcs, intersect_info);
4870 }
4871 
4872 
4873 /* subtraction */
4874 
4875 /**
4876  * gst_value_subtract:
4877  * @dest: (out caller-allocates) (allow-none): the destination value
4878  *     for the result if the subtraction is not empty. May be %NULL,
4879  *     in which case the resulting set will not be computed, which can
4880  *     give a fair speedup.
4881  * @minuend: the value to subtract from
4882  * @subtrahend: the value to subtract
4883  *
4884  * Subtracts @subtrahend from @minuend and stores the result in @dest.
4885  * Note that this means subtraction as in sets, not as in mathematics.
4886  *
4887  * Returns: %TRUE if the subtraction is not empty
4888  */
4889 gboolean
4890 gst_value_subtract (GValue * dest, const GValue * minuend,
4891     const GValue * subtrahend)
4892 {
4893   GstValueSubtractInfo *info;
4894   guint i, len;
4895   GType mtype, stype;
4896 
4897   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4898   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4899 
4900   mtype = G_VALUE_TYPE (minuend);
4901   stype = G_VALUE_TYPE (subtrahend);
4902 
4903   /* special cases first */
4904   if (mtype == GST_TYPE_LIST)
4905     return gst_value_subtract_from_list (dest, minuend, subtrahend);
4906   if (stype == GST_TYPE_LIST)
4907     return gst_value_subtract_list (dest, minuend, subtrahend);
4908 
4909   len = gst_value_subtract_funcs->len;
4910   for (i = 0; i < len; i++) {
4911     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4912     if (info->minuend == mtype && info->subtrahend == stype) {
4913       return info->func (dest, minuend, subtrahend);
4914     }
4915   }
4916 
4917   if (_gst_value_compare_nolist (minuend, subtrahend) != GST_VALUE_EQUAL) {
4918     if (dest)
4919     gst_value_init_and_copy (dest, minuend);
4920     return TRUE;
4921   }
4922 
4923   return FALSE;
4924 }
4925 
4926 #if 0
4927 gboolean
4928 gst_value_subtract (GValue * dest, const GValue * minuend,
4929     const GValue * subtrahend)
4930 {
4931   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
4932 
4933   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
4934       gst_value_serialize (subtrahend),
4935       ret ? gst_value_serialize (dest) : "---");
4936   return ret;
4937 }
4938 #endif
4939 
4940 /**
4941  * gst_value_can_subtract:
4942  * @minuend: the value to subtract from
4943  * @subtrahend: the value to subtract
4944  *
4945  * Checks if it's possible to subtract @subtrahend from @minuend.
4946  *
4947  * Returns: %TRUE if a subtraction is possible
4948  */
4949 gboolean
4950 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
4951 {
4952   GstValueSubtractInfo *info;
4953   guint i, len;
4954   GType mtype, stype;
4955 
4956   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4957   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4958 
4959   mtype = G_VALUE_TYPE (minuend);
4960   stype = G_VALUE_TYPE (subtrahend);
4961 
4962   /* special cases */
4963   if (mtype == GST_TYPE_LIST || stype == GST_TYPE_LIST)
4964     return TRUE;
4965 
4966   len = gst_value_subtract_funcs->len;
4967   for (i = 0; i < len; i++) {
4968     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4969     if (info->minuend == mtype && info->subtrahend == stype)
4970       return TRUE;
4971   }
4972 
4973   return gst_value_can_compare_unchecked (minuend, subtrahend);
4974 }
4975 
4976 /* gst_value_register_subtract_func: (skip)
4977  * @minuend_type: type of the minuend
4978  * @subtrahend_type: type of the subtrahend
4979  * @func: function to use
4980  *
4981  * Registers @func as a function capable of subtracting the values of
4982  * @subtrahend_type from values of @minuend_type.
4983  *
4984  * Subtract functions should be registered at startup before any pipelines are
4985  * started, as gst_value_register_subtract_func() is not thread-safe and
4986  * cannot be used at the same time as gst_value_subtract().
4987  */
4988 static void
4989 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
4990     GstValueSubtractFunc func)
4991 {
4992   GstValueSubtractInfo info;
4993 
4994   g_return_if_fail (!gst_type_is_fixed (minuend_type)
4995       || !gst_type_is_fixed (subtrahend_type));
4996 
4997   info.minuend = minuend_type;
4998   info.subtrahend = subtrahend_type;
4999   info.func = func;
5000 
5001   g_array_append_val (gst_value_subtract_funcs, info);
5002 }
5003 
5004 /**
5005  * gst_value_register:
5006  * @table: structure containing functions to register
5007  *
5008  * Registers functions to perform calculations on #GValue items of a given
5009  * type. Each type can only be added once.
5010  */
5011 void
5012 gst_value_register (const GstValueTable * table)
5013 {
5014   GstValueTable *found;
5015 
5016   g_return_if_fail (table != NULL);
5017 
5018   g_array_append_val (gst_value_table, *table);
5019 
5020   found = gst_value_hash_lookup_type (table->type);
5021   if (found)
5022     g_warning ("adding type %s multiple times", g_type_name (table->type));
5023 
5024   /* FIXME: we're not really doing the const justice, we assume the table is
5025    * static */
5026   gst_value_hash_add_type (table->type, table);
5027 }
5028 
5029 /**
5030  * gst_value_init_and_copy:
5031  * @dest: (out caller-allocates): the target value
5032  * @src: the source value
5033  *
5034  * Initialises the target value to be of the same type as source and then copies
5035  * the contents from source to target.
5036  */
5037 void
5038 gst_value_init_and_copy (GValue * dest, const GValue * src)
5039 {
5040   g_return_if_fail (G_IS_VALUE (src));
5041   g_return_if_fail (dest != NULL);
5042 
5043   g_value_init (dest, G_VALUE_TYPE (src));
5044   g_value_copy (src, dest);
5045 }
5046 
5047 /* move src into dest and clear src */
5048 static void
5049 gst_value_move (GValue * dest, GValue * src)
5050 {
5051   g_assert (G_IS_VALUE (src));
5052   g_assert (dest != NULL);
5053 
5054   *dest = *src;
5055   memset (src, 0, sizeof (GValue));
5056 }
5057 
5058 /**
5059  * gst_value_serialize:
5060  * @value: a #GValue to serialize
5061  *
5062  * tries to transform the given @value into a string representation that allows
5063  * getting back this string later on using gst_value_deserialize().
5064  *
5065  * Free-function: g_free
5066  *
5067  * Returns: (transfer full) (nullable): the serialization for @value
5068  * or %NULL if none exists
5069  */
5070 gchar *
5071 gst_value_serialize (const GValue * value)
5072 {
5073   guint i, len;
5074   GValue s_val = { 0 };
5075   GstValueTable *table, *best;
5076   gchar *s;
5077   GType type;
5078 
5079   g_return_val_if_fail (G_IS_VALUE (value), NULL);
5080 
5081   type = G_VALUE_TYPE (value);
5082 
5083   best = gst_value_hash_lookup_type (type);
5084 
5085   if (G_UNLIKELY (!best || !best->serialize)) {
5086     len = gst_value_table->len;
5087     best = NULL;
5088     for (i = 0; i < len; i++) {
5089       table = &g_array_index (gst_value_table, GstValueTable, i);
5090       if (table->serialize && g_type_is_a (type, table->type)) {
5091         if (!best || g_type_is_a (table->type, best->type))
5092           best = table;
5093       }
5094     }
5095   }
5096   if (G_LIKELY (best))
5097     return best->serialize (value);
5098 
5099   g_value_init (&s_val, G_TYPE_STRING);
5100   if (g_value_transform (value, &s_val)) {
5101     s = gst_string_wrap (g_value_get_string (&s_val));
5102   } else {
5103     s = NULL;
5104   }
5105   g_value_unset (&s_val);
5106 
5107   return s;
5108 }
5109 
5110 /**
5111  * gst_value_deserialize:
5112  * @dest: (out caller-allocates): #GValue to fill with contents of
5113  *     deserialization
5114  * @src: string to deserialize
5115  *
5116  * Tries to deserialize a string into the type specified by the given GValue.
5117  * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
5118  *
5119  * Returns: %TRUE on success
5120  */
5121 gboolean
5122 gst_value_deserialize (GValue * dest, const gchar * src)
5123 {
5124   GstValueTable *table, *best;
5125   guint i, len;
5126   GType type;
5127 
5128   g_return_val_if_fail (src != NULL, FALSE);
5129   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
5130 
5131   type = G_VALUE_TYPE (dest);
5132 
5133   best = gst_value_hash_lookup_type (type);
5134   if (G_UNLIKELY (!best || !best->deserialize)) {
5135     len = gst_value_table->len;
5136     best = NULL;
5137     for (i = 0; i < len; i++) {
5138       table = &g_array_index (gst_value_table, GstValueTable, i);
5139       if (table->deserialize && g_type_is_a (type, table->type)) {
5140         if (!best || g_type_is_a (table->type, best->type))
5141           best = table;
5142       }
5143     }
5144   }
5145   if (G_LIKELY (best))
5146     return best->deserialize (dest, src);
5147 
5148   return FALSE;
5149 }
5150 
5151 /**
5152  * gst_value_is_fixed:
5153  * @value: the #GValue to check
5154  *
5155  * Tests if the given GValue, if available in a GstStructure (or any other
5156  * container) contains a "fixed" (which means: one value) or an "unfixed"
5157  * (which means: multiple possible values, such as data lists or data
5158  * ranges) value.
5159  *
5160  * Returns: true if the value is "fixed".
5161  */
5162 
5163 gboolean
5164 gst_value_is_fixed (const GValue * value)
5165 {
5166   GType type;
5167 
5168   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
5169 
5170   type = G_VALUE_TYPE (value);
5171 
5172   /* the most common types are just basic plain glib types */
5173   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
5174     return TRUE;
5175   }
5176 
5177   if (type == GST_TYPE_ARRAY) {
5178     gint size, n;
5179     const GValue *kid;
5180 
5181     /* check recursively */
5182     size = gst_value_array_get_size (value);
5183     for (n = 0; n < size; n++) {
5184       kid = gst_value_array_get_value (value, n);
5185       if (!gst_value_is_fixed (kid))
5186         return FALSE;
5187     }
5188     return TRUE;
5189   }
5190   return gst_type_is_fixed (type);
5191 }
5192 
5193 /**
5194  * gst_value_fixate:
5195  * @dest: the #GValue destination
5196  * @src: the #GValue to fixate
5197  *
5198  * Fixate @src into a new value @dest.
5199  * For ranges, the first element is taken. For lists and arrays, the
5200  * first item is fixated and returned.
5201  * If @src is already fixed, this function returns %FALSE.
5202  *
5203  * Returns: %TRUE if @dest contains a fixated version of @src.
5204  */
5205 gboolean
5206 gst_value_fixate (GValue * dest, const GValue * src)
5207 {
5208   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
5209   g_return_val_if_fail (dest != NULL, FALSE);
5210 
5211   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
5212     g_value_init (dest, G_TYPE_INT);
5213     g_value_set_int (dest, gst_value_get_int_range_min (src));
5214   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
5215     g_value_init (dest, G_TYPE_DOUBLE);
5216     g_value_set_double (dest, gst_value_get_double_range_min (src));
5217   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
5218     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
5219   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
5220     GValue temp = { 0 };
5221 
5222     /* list could be empty */
5223     if (gst_value_list_get_size (src) <= 0)
5224       return FALSE;
5225 
5226     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
5227 
5228     if (!gst_value_fixate (dest, &temp)) {
5229       gst_value_move (dest, &temp);
5230     } else {
5231       g_value_unset (&temp);
5232     }
5233   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
5234     gboolean res = FALSE;
5235     guint n, len;
5236 
5237     len = gst_value_array_get_size (src);
5238     g_value_init (dest, GST_TYPE_ARRAY);
5239     for (n = 0; n < len; n++) {
5240       GValue kid = { 0 };
5241       const GValue *orig_kid = gst_value_array_get_value (src, n);
5242 
5243       if (!gst_value_fixate (&kid, orig_kid))
5244         gst_value_init_and_copy (&kid, orig_kid);
5245       else
5246         res = TRUE;
5247       _gst_value_array_append_and_take_value (dest, &kid);
5248     }
5249 
5250     if (!res)
5251       g_value_unset (dest);
5252 
5253     return res;
5254   } else {
5255     return FALSE;
5256   }
5257   return TRUE;
5258 }
5259 
5260 
5261 /************
5262  * fraction *
5263  ************/
5264 
5265 /* helper functions */
5266 static void
5267 gst_value_init_fraction (GValue * value)
5268 {
5269   value->data[0].v_int = 0;
5270   value->data[1].v_int = 1;
5271 }
5272 
5273 static void
5274 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
5275 {
5276   dest_value->data[0].v_int = src_value->data[0].v_int;
5277   dest_value->data[1].v_int = src_value->data[1].v_int;
5278 }
5279 
5280 static gchar *
5281 gst_value_collect_fraction (GValue * value, guint n_collect_values,
5282     GTypeCValue * collect_values, guint collect_flags)
5283 {
5284   if (n_collect_values != 2)
5285     return g_strdup_printf ("not enough value locations for `%s' passed",
5286         G_VALUE_TYPE_NAME (value));
5287   if (collect_values[1].v_int == 0)
5288     return g_strdup_printf ("passed '0' as denominator for `%s'",
5289         G_VALUE_TYPE_NAME (value));
5290   if (collect_values[0].v_int < -G_MAXINT)
5291     return
5292         g_strdup_printf
5293         ("passed value smaller than -G_MAXINT as numerator for `%s'",
5294         G_VALUE_TYPE_NAME (value));
5295   if (collect_values[1].v_int < -G_MAXINT)
5296     return
5297         g_strdup_printf
5298         ("passed value smaller than -G_MAXINT as denominator for `%s'",
5299         G_VALUE_TYPE_NAME (value));
5300 
5301   gst_value_set_fraction (value,
5302       collect_values[0].v_int, collect_values[1].v_int);
5303 
5304   return NULL;
5305 }
5306 
5307 static gchar *
5308 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
5309     GTypeCValue * collect_values, guint collect_flags)
5310 {
5311   gint *numerator = collect_values[0].v_pointer;
5312   gint *denominator = collect_values[1].v_pointer;
5313 
5314   if (!numerator)
5315     return g_strdup_printf ("numerator for `%s' passed as NULL",
5316         G_VALUE_TYPE_NAME (value));
5317   if (!denominator)
5318     return g_strdup_printf ("denominator for `%s' passed as NULL",
5319         G_VALUE_TYPE_NAME (value));
5320 
5321   *numerator = value->data[0].v_int;
5322   *denominator = value->data[1].v_int;
5323 
5324   return NULL;
5325 }
5326 
5327 /**
5328  * gst_value_set_fraction:
5329  * @value: a GValue initialized to #GST_TYPE_FRACTION
5330  * @numerator: the numerator of the fraction
5331  * @denominator: the denominator of the fraction
5332  *
5333  * Sets @value to the fraction specified by @numerator over @denominator.
5334  * The fraction gets reduced to the smallest numerator and denominator,
5335  * and if necessary the sign is moved to the numerator.
5336  */
5337 void
5338 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
5339 {
5340   gint gcd = 0;
5341 
5342   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
5343   g_return_if_fail (denominator != 0);
5344   g_return_if_fail (denominator >= -G_MAXINT);
5345   g_return_if_fail (numerator >= -G_MAXINT);
5346 
5347   /* normalize sign */
5348   if (denominator < 0) {
5349     numerator = -numerator;
5350     denominator = -denominator;
5351   }
5352 
5353   /* check for reduction */
5354   gcd = gst_util_greatest_common_divisor (numerator, denominator);
5355   if (gcd) {
5356     numerator /= gcd;
5357     denominator /= gcd;
5358   }
5359 
5360   g_assert (denominator > 0);
5361 
5362   value->data[0].v_int = numerator;
5363   value->data[1].v_int = denominator;
5364 }
5365 
5366 /**
5367  * gst_value_get_fraction_numerator:
5368  * @value: a GValue initialized to #GST_TYPE_FRACTION
5369  *
5370  * Gets the numerator of the fraction specified by @value.
5371  *
5372  * Returns: the numerator of the fraction.
5373  */
5374 gint
5375 gst_value_get_fraction_numerator (const GValue * value)
5376 {
5377   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
5378 
5379   return value->data[0].v_int;
5380 }
5381 
5382 /**
5383  * gst_value_get_fraction_denominator:
5384  * @value: a GValue initialized to #GST_TYPE_FRACTION
5385  *
5386  * Gets the denominator of the fraction specified by @value.
5387  *
5388  * Returns: the denominator of the fraction.
5389  */
5390 gint
5391 gst_value_get_fraction_denominator (const GValue * value)
5392 {
5393   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
5394 
5395   return value->data[1].v_int;
5396 }
5397 
5398 /**
5399  * gst_value_fraction_multiply:
5400  * @product: a GValue initialized to #GST_TYPE_FRACTION
5401  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
5402  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
5403  *
5404  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
5405  * @product to the product of the two fractions.
5406  *
5407  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
5408  */
5409 gboolean
5410 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
5411     const GValue * factor2)
5412 {
5413   gint n1, n2, d1, d2;
5414   gint res_n, res_d;
5415 
5416   g_return_val_if_fail (product != NULL, FALSE);
5417   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
5418   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
5419 
5420   n1 = factor1->data[0].v_int;
5421   n2 = factor2->data[0].v_int;
5422   d1 = factor1->data[1].v_int;
5423   d2 = factor2->data[1].v_int;
5424 
5425   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
5426     return FALSE;
5427 
5428   gst_value_set_fraction (product, res_n, res_d);
5429 
5430   return TRUE;
5431 }
5432 
5433 /**
5434  * gst_value_fraction_subtract:
5435  * @dest: a GValue initialized to #GST_TYPE_FRACTION
5436  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
5437  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
5438  *
5439  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
5440  *
5441  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
5442  */
5443 gboolean
5444 gst_value_fraction_subtract (GValue * dest,
5445     const GValue * minuend, const GValue * subtrahend)
5446 {
5447   gint n1, n2, d1, d2;
5448   gint res_n, res_d;
5449 
5450   g_return_val_if_fail (dest != NULL, FALSE);
5451   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
5452   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
5453 
5454   n1 = minuend->data[0].v_int;
5455   n2 = subtrahend->data[0].v_int;
5456   d1 = minuend->data[1].v_int;
5457   d2 = subtrahend->data[1].v_int;
5458 
5459   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
5460     return FALSE;
5461   gst_value_set_fraction (dest, res_n, res_d);
5462 
5463   return TRUE;
5464 }
5465 
5466 static gchar *
5467 gst_value_serialize_fraction (const GValue * value)
5468 {
5469   gint32 numerator = value->data[0].v_int;
5470   gint32 denominator = value->data[1].v_int;
5471   gboolean positive = TRUE;
5472 
5473   /* get the sign and make components absolute */
5474   if (numerator < 0) {
5475     numerator = -numerator;
5476     positive = !positive;
5477   }
5478   if (denominator < 0) {
5479     denominator = -denominator;
5480     positive = !positive;
5481   }
5482 
5483   return g_strdup_printf ("%s%d/%d",
5484       positive ? "" : "-", numerator, denominator);
5485 }
5486 
5487 static gboolean
5488 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
5489 {
5490   gint num, den;
5491   gint num_chars;
5492 
5493   if (G_UNLIKELY (s == NULL))
5494     return FALSE;
5495 
5496   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
5497     return FALSE;
5498 
5499   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
5500     if (s[num_chars] != 0)
5501       return FALSE;
5502     if (den == 0)
5503       return FALSE;
5504 
5505     gst_value_set_fraction (dest, num, den);
5506     return TRUE;
5507   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
5508     gst_value_set_fraction (dest, 1, G_MAXINT);
5509     return TRUE;
5510   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
5511     if (s[num_chars] != 0)
5512       return FALSE;
5513     gst_value_set_fraction (dest, num, 1);
5514     return TRUE;
5515   } else if (g_ascii_strcasecmp (s, "min") == 0) {
5516     gst_value_set_fraction (dest, -G_MAXINT, 1);
5517     return TRUE;
5518   } else if (g_ascii_strcasecmp (s, "max") == 0) {
5519     gst_value_set_fraction (dest, G_MAXINT, 1);
5520     return TRUE;
5521   }
5522 
5523   return FALSE;
5524 }
5525 
5526 static void
5527 gst_value_transform_fraction_string (const GValue * src_value,
5528     GValue * dest_value)
5529 {
5530   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
5531 }
5532 
5533 static void
5534 gst_value_transform_string_fraction (const GValue * src_value,
5535     GValue * dest_value)
5536 {
5537   if (!gst_value_deserialize_fraction (dest_value,
5538           src_value->data[0].v_pointer))
5539     /* If the deserialize fails, ensure we leave the fraction in a
5540      * valid, if incorrect, state */
5541     gst_value_set_fraction (dest_value, 0, 1);
5542 }
5543 
5544 static void
5545 gst_value_transform_double_fraction (const GValue * src_value,
5546     GValue * dest_value)
5547 {
5548   gdouble src = g_value_get_double (src_value);
5549   gint n, d;
5550 
5551   gst_util_double_to_fraction (src, &n, &d);
5552   gst_value_set_fraction (dest_value, n, d);
5553 }
5554 
5555 static void
5556 gst_value_transform_float_fraction (const GValue * src_value,
5557     GValue * dest_value)
5558 {
5559   gfloat src = g_value_get_float (src_value);
5560   gint n, d;
5561 
5562   gst_util_double_to_fraction (src, &n, &d);
5563   gst_value_set_fraction (dest_value, n, d);
5564 }
5565 
5566 static void
5567 gst_value_transform_fraction_double (const GValue * src_value,
5568     GValue * dest_value)
5569 {
5570   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
5571       ((double) src_value->data[1].v_int);
5572 }
5573 
5574 static void
5575 gst_value_transform_fraction_float (const GValue * src_value,
5576     GValue * dest_value)
5577 {
5578   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
5579       ((float) src_value->data[1].v_int);
5580 }
5581 
5582 static gint
5583 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
5584 {
5585   gint n1, n2;
5586   gint d1, d2;
5587   gint ret;
5588 
5589   n1 = value1->data[0].v_int;
5590   n2 = value2->data[0].v_int;
5591   d1 = value1->data[1].v_int;
5592   d2 = value2->data[1].v_int;
5593 
5594   /* fractions are reduced when set, so we can quickly see if they're equal */
5595   if (n1 == n2 && d1 == d2)
5596     return GST_VALUE_EQUAL;
5597 
5598   if (d1 == 0 && d2 == 0)
5599     return GST_VALUE_UNORDERED;
5600   else if (d1 == 0)
5601     return GST_VALUE_GREATER_THAN;
5602   else if (d2 == 0)
5603     return GST_VALUE_LESS_THAN;
5604 
5605   ret = gst_util_fraction_compare (n1, d1, n2, d2);
5606   if (ret == -1)
5607     return GST_VALUE_LESS_THAN;
5608   else if (ret == 1)
5609     return GST_VALUE_GREATER_THAN;
5610 
5611   /* Equality can't happen here because we check for that
5612    * first already */
5613   g_return_val_if_reached (GST_VALUE_UNORDERED);
5614 }
5615 
5616 /*********
5617  * GDate *
5618  *********/
5619 
5620 static gint
5621 gst_value_compare_date (const GValue * value1, const GValue * value2)
5622 {
5623   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
5624   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
5625   guint32 j1, j2;
5626 
5627   if (date1 == date2)
5628     return GST_VALUE_EQUAL;
5629 
5630   if ((date1 == NULL || !g_date_valid (date1))
5631       && (date2 != NULL && g_date_valid (date2))) {
5632     return GST_VALUE_LESS_THAN;
5633   }
5634 
5635   if ((date2 == NULL || !g_date_valid (date2))
5636       && (date1 != NULL && g_date_valid (date1))) {
5637     return GST_VALUE_GREATER_THAN;
5638   }
5639 
5640   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
5641       || !g_date_valid (date2)) {
5642     return GST_VALUE_UNORDERED;
5643   }
5644 
5645   j1 = g_date_get_julian (date1);
5646   j2 = g_date_get_julian (date2);
5647 
5648   if (j1 == j2)
5649     return GST_VALUE_EQUAL;
5650   else if (j1 < j2)
5651     return GST_VALUE_LESS_THAN;
5652   else
5653     return GST_VALUE_GREATER_THAN;
5654 }
5655 
5656 static gchar *
5657 gst_value_serialize_date (const GValue * val)
5658 {
5659   const GDate *date = (const GDate *) g_value_get_boxed (val);
5660 
5661   if (date == NULL || !g_date_valid (date))
5662     return g_strdup ("9999-99-99");
5663 
5664   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
5665       g_date_get_month (date), g_date_get_day (date));
5666 }
5667 
5668 static gboolean
5669 gst_value_deserialize_date (GValue * dest, const gchar * s)
5670 {
5671   guint year, month, day;
5672 
5673   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
5674     return FALSE;
5675 
5676   if (!g_date_valid_dmy (day, month, year))
5677     return FALSE;
5678 
5679   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
5680   return TRUE;
5681 }
5682 
5683 /*************
5684  * GstDateTime *
5685  *************/
5686 
5687 static gint
5688 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
5689 {
5690   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
5691   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
5692 
5693   if (date1 == date2)
5694     return GST_VALUE_EQUAL;
5695 
5696   if ((date1 == NULL) && (date2 != NULL)) {
5697     return GST_VALUE_LESS_THAN;
5698   }
5699   if ((date2 == NULL) && (date1 != NULL)) {
5700     return GST_VALUE_LESS_THAN;
5701   }
5702 
5703   /* returns GST_VALUE_* */
5704   return __gst_date_time_compare (date1, date2);
5705 }
5706 
5707 static gchar *
5708 gst_value_serialize_date_time (const GValue * val)
5709 {
5710   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
5711 
5712   if (date == NULL)
5713     return g_strdup ("null");
5714 
5715   return __gst_date_time_serialize (date, TRUE);
5716 }
5717 
5718 static gboolean
5719 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
5720 {
5721   GstDateTime *datetime;
5722 
5723   if (!s || strcmp (s, "null") == 0) {
5724     return FALSE;
5725   }
5726 
5727   datetime = gst_date_time_new_from_iso8601_string (s);
5728   if (datetime != NULL) {
5729     g_value_take_boxed (dest, datetime);
5730   return TRUE;
5731   }
5732   GST_WARNING ("Failed to deserialize date time string '%s'", s);
5733   return FALSE;
5734 }
5735 
5736 static void
5737 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
5738 {
5739   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
5740 }
5741 
5742 static void
5743 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
5744 {
5745   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
5746 }
5747 
5748 
5749 /************
5750  * bitmask *
5751  ************/
5752 
5753 /* helper functions */
5754 static void
5755 gst_value_init_bitmask (GValue * value)
5756 {
5757   value->data[0].v_uint64 = 0;
5758 }
5759 
5760 static void
5761 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
5762 {
5763   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5764 }
5765 
5766 static gchar *
5767 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
5768     GTypeCValue * collect_values, guint collect_flags)
5769 {
5770   if (n_collect_values != 1)
5771     return g_strdup_printf ("not enough value locations for `%s' passed",
5772         G_VALUE_TYPE_NAME (value));
5773 
5774   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
5775 
5776   return NULL;
5777 }
5778 
5779 static gchar *
5780 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
5781     GTypeCValue * collect_values, guint collect_flags)
5782 {
5783   guint64 *bitmask = collect_values[0].v_pointer;
5784 
5785   if (!bitmask)
5786     return g_strdup_printf ("value for `%s' passed as NULL",
5787         G_VALUE_TYPE_NAME (value));
5788 
5789   *bitmask = value->data[0].v_uint64;
5790 
5791   return NULL;
5792 }
5793 
5794 /**
5795  * gst_value_set_bitmask:
5796  * @value: a GValue initialized to #GST_TYPE_BITMASK
5797  * @bitmask: the bitmask
5798  *
5799  * Sets @value to the bitmask specified by @bitmask.
5800  */
5801 void
5802 gst_value_set_bitmask (GValue * value, guint64 bitmask)
5803 {
5804   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
5805 
5806   value->data[0].v_uint64 = bitmask;
5807 }
5808 
5809 /**
5810  * gst_value_get_bitmask:
5811  * @value: a GValue initialized to #GST_TYPE_BITMASK
5812  *
5813  * Gets the bitmask specified by @value.
5814  *
5815  * Returns: the bitmask.
5816  */
5817 guint64
5818 gst_value_get_bitmask (const GValue * value)
5819 {
5820   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
5821 
5822   return value->data[0].v_uint64;
5823 }
5824 
5825 static gchar *
5826 gst_value_serialize_bitmask (const GValue * value)
5827 {
5828   guint64 bitmask = value->data[0].v_uint64;
5829 
5830   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
5831 }
5832 
5833 static gboolean
5834 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
5835 {
5836   gchar *endptr = NULL;
5837   guint64 val;
5838 
5839   if (G_UNLIKELY (s == NULL))
5840     return FALSE;
5841 
5842   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
5843     return FALSE;
5844 
5845   val = g_ascii_strtoull (s, &endptr, 16);
5846   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
5847     return FALSE;
5848   if (val == 0 && endptr == s)
5849     return FALSE;
5850 
5851   gst_value_set_bitmask (dest, val);
5852 
5853   return TRUE;
5854 }
5855 
5856 static void
5857 gst_value_transform_bitmask_string (const GValue * src_value,
5858     GValue * dest_value)
5859 {
5860   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
5861 }
5862 
5863 static void
5864 gst_value_transform_string_bitmask (const GValue * src_value,
5865     GValue * dest_value)
5866 {
5867   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
5868     gst_value_set_bitmask (dest_value, 0);
5869 }
5870 
5871 static void
5872 gst_value_transform_uint64_bitmask (const GValue * src_value,
5873     GValue * dest_value)
5874 {
5875   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5876 }
5877 
5878 static void
5879 gst_value_transform_bitmask_uint64 (const GValue * src_value,
5880     GValue * dest_value)
5881 {
5882   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5883 }
5884 
5885 static gint
5886 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
5887 {
5888   guint64 v1, v2;
5889 
5890   v1 = value1->data[0].v_uint64;
5891   v2 = value2->data[0].v_uint64;
5892 
5893   if (v1 == v2)
5894     return GST_VALUE_EQUAL;
5895 
5896   return GST_VALUE_UNORDERED;
5897 }
5898 
5899 
5900 /***********************
5901  * GstAllocationParams *
5902  ***********************/
5903 static gint
5904 gst_value_compare_allocation_params (const GValue * value1,
5905     const GValue * value2)
5906 {
5907   GstAllocationParams *v1, *v2;
5908 
5909   v1 = value1->data[0].v_pointer;
5910   v2 = value2->data[0].v_pointer;
5911 
5912   if (v1 == NULL && v1 == v2)
5913     return GST_VALUE_EQUAL;
5914 
5915   if (v1 == NULL || v2 == NULL)
5916     return GST_VALUE_UNORDERED;
5917 
5918   if (v1->flags == v2->flags && v1->align == v2->align &&
5919       v1->prefix == v2->prefix && v1->padding == v2->padding)
5920     return GST_VALUE_EQUAL;
5921 
5922   return GST_VALUE_UNORDERED;
5923 }
5924 
5925 
5926 /************
5927  * GObject *
5928  ************/
5929 
5930 static gint
5931 gst_value_compare_object (const GValue * value1, const GValue * value2)
5932 {
5933   gpointer v1, v2;
5934 
5935   v1 = value1->data[0].v_pointer;
5936   v2 = value2->data[0].v_pointer;
5937 
5938   if (v1 == v2)
5939     return GST_VALUE_EQUAL;
5940 
5941   return GST_VALUE_UNORDERED;
5942 }
5943 
5944 static void
5945 gst_value_transform_object_string (const GValue * src_value,
5946     GValue * dest_value)
5947 {
5948   GstObject *obj;
5949   gchar *str;
5950 
5951   obj = g_value_get_object (src_value);
5952   if (obj) {
5953     str =
5954         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
5955         GST_OBJECT_NAME (obj));
5956   } else {
5957     str = g_strdup ("NULL");
5958   }
5959 
5960   dest_value->data[0].v_pointer = str;
5961 }
5962 
5963 static GTypeInfo _info = {
5964   0,
5965   NULL,
5966   NULL,
5967   NULL,
5968   NULL,
5969   NULL,
5970   0,
5971   0,
5972   NULL,
5973   NULL,
5974 };
5975 
5976 static GTypeFundamentalInfo _finfo = {
5977   0
5978 };
5979 
5980 #define FUNC_VALUE_GET_TYPE(type, name)                         \
5981 GType _gst_ ## type ## _type = 0;                               \
5982                                                                 \
5983 GType gst_ ## type ## _get_type (void)                          \
5984 {                                                               \
5985   static volatile GType gst_ ## type ## _type = 0;              \
5986                                                                 \
5987   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
5988     GType _type;                                                \
5989     _info.value_table = & _gst_ ## type ## _value_table;        \
5990     _type = g_type_register_fundamental (                       \
5991         g_type_fundamental_next (),                             \
5992         name, &_info, &_finfo, 0);                              \
5993     _gst_ ## type ## _type = _type;                              \
5994     g_once_init_leave(&gst_ ## type ## _type, _type);           \
5995   }                                                             \
5996                                                                 \
5997   return gst_ ## type ## _type;                                 \
5998 }
5999 
6000 static const GTypeValueTable _gst_int_range_value_table = {
6001   gst_value_init_int_range,
6002   NULL,
6003   gst_value_copy_int_range,
6004   NULL,
6005   (char *) "ii",
6006   gst_value_collect_int_range,
6007   (char *) "pp",
6008   gst_value_lcopy_int_range
6009 };
6010 
6011 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
6012 
6013 static const GTypeValueTable _gst_int64_range_value_table = {
6014   gst_value_init_int64_range,
6015   gst_value_free_int64_range,
6016   gst_value_copy_int64_range,
6017   NULL,
6018   (char *) "qq",
6019   gst_value_collect_int64_range,
6020   (char *) "pp",
6021   gst_value_lcopy_int64_range
6022 };
6023 
6024 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
6025 
6026 static const GTypeValueTable _gst_double_range_value_table = {
6027   gst_value_init_double_range,
6028   NULL,
6029   gst_value_copy_double_range,
6030   NULL,
6031   (char *) "dd",
6032   gst_value_collect_double_range,
6033   (char *) "pp",
6034   gst_value_lcopy_double_range
6035 };
6036 
6037 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
6038 
6039 static const GTypeValueTable _gst_fraction_range_value_table = {
6040   gst_value_init_fraction_range,
6041   gst_value_free_fraction_range,
6042   gst_value_copy_fraction_range,
6043   NULL,
6044   (char *) "iiii",
6045   gst_value_collect_fraction_range,
6046   (char *) "pppp",
6047   gst_value_lcopy_fraction_range
6048 };
6049 
6050 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
6051 
6052 static const GTypeValueTable _gst_value_list_value_table = {
6053   gst_value_init_list_or_array,
6054   gst_value_free_list_or_array,
6055   gst_value_copy_list_or_array,
6056   gst_value_list_or_array_peek_pointer,
6057   (char *) "p",
6058   gst_value_collect_list_or_array,
6059   (char *) "p",
6060   gst_value_lcopy_list_or_array
6061 };
6062 
6063 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
6064 
6065 static const GTypeValueTable _gst_value_array_value_table = {
6066   gst_value_init_list_or_array,
6067   gst_value_free_list_or_array,
6068   gst_value_copy_list_or_array,
6069   gst_value_list_or_array_peek_pointer,
6070   (char *) "p",
6071   gst_value_collect_list_or_array,
6072   (char *) "p",
6073   gst_value_lcopy_list_or_array
6074 };
6075 
6076 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
6077 
6078 static const GTypeValueTable _gst_fraction_value_table = {
6079   gst_value_init_fraction,
6080   NULL,
6081   gst_value_copy_fraction,
6082   NULL,
6083   (char *) "ii",
6084   gst_value_collect_fraction,
6085   (char *) "pp",
6086   gst_value_lcopy_fraction
6087 };
6088 
6089 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
6090 
6091 static const GTypeValueTable _gst_bitmask_value_table = {
6092   gst_value_init_bitmask,
6093   NULL,
6094   gst_value_copy_bitmask,
6095   NULL,
6096   (char *) "q",
6097   gst_value_collect_bitmask,
6098   (char *) "p",
6099   gst_value_lcopy_bitmask
6100 };
6101 
6102 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
6103 
6104 GType
6105 gst_g_thread_get_type (void)
6106 {
6107 #if GLIB_CHECK_VERSION(2,35,3)
6108   return G_TYPE_THREAD;
6109 #else
6110   static volatile gsize type_id = 0;
6111 
6112   if (g_once_init_enter (&type_id)) {
6113     GType tmp =
6114         g_boxed_type_register_static (g_intern_static_string ("GstGThread"),
6115         (GBoxedCopyFunc) g_thread_ref,
6116         (GBoxedFreeFunc) g_thread_unref);
6117     g_once_init_leave (&type_id, tmp);
6118   }
6119 
6120   return type_id;
6121 #endif
6122 }
6123 
6124 void
6125 _priv_gst_value_initialize (void)
6126 {
6127   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
6128   gst_value_hash = g_hash_table_new (NULL, NULL);
6129   gst_value_union_funcs = g_array_new (FALSE, FALSE,
6130       sizeof (GstValueUnionInfo));
6131   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
6132       sizeof (GstValueIntersectInfo));
6133   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
6134       sizeof (GstValueSubtractInfo));
6135 
6136   {
6137     static GstValueTable gst_value = {
6138       0,
6139       gst_value_compare_int_range,
6140       gst_value_serialize_int_range,
6141       gst_value_deserialize_int_range,
6142     };
6143 
6144     gst_value.type = gst_int_range_get_type ();
6145     gst_value_register (&gst_value);
6146   }
6147 
6148   {
6149     static GstValueTable gst_value = {
6150       0,
6151       gst_value_compare_int64_range,
6152       gst_value_serialize_int64_range,
6153       gst_value_deserialize_int64_range,
6154     };
6155 
6156     gst_value.type = gst_int64_range_get_type ();
6157     gst_value_register (&gst_value);
6158   }
6159 
6160   {
6161     static GstValueTable gst_value = {
6162       0,
6163       gst_value_compare_double_range,
6164       gst_value_serialize_double_range,
6165       gst_value_deserialize_double_range,
6166     };
6167 
6168     gst_value.type = gst_double_range_get_type ();
6169     gst_value_register (&gst_value);
6170   }
6171 
6172   {
6173     static GstValueTable gst_value = {
6174       0,
6175       gst_value_compare_fraction_range,
6176       gst_value_serialize_fraction_range,
6177       gst_value_deserialize_fraction_range,
6178     };
6179 
6180     gst_value.type = gst_fraction_range_get_type ();
6181     gst_value_register (&gst_value);
6182   }
6183 
6184   {
6185     static GstValueTable gst_value = {
6186       0,
6187       gst_value_compare_list,
6188       gst_value_serialize_list,
6189       gst_value_deserialize_list,
6190     };
6191 
6192     gst_value.type = gst_value_list_get_type ();
6193     gst_value_register (&gst_value);
6194   }
6195 
6196   {
6197     static GstValueTable gst_value = {
6198       0,
6199       gst_value_compare_array,
6200       gst_value_serialize_array,
6201       gst_value_deserialize_array,
6202     };
6203 
6204     gst_value.type = gst_value_array_get_type ();
6205     gst_value_register (&gst_value);
6206   }
6207 
6208   {
6209 #if 0
6210     static const GTypeValueTable value_table = {
6211       gst_value_init_buffer,
6212       NULL,
6213       gst_value_copy_buffer,
6214       NULL,
6215       "i",
6216       NULL,                     /*gst_value_collect_buffer, */
6217       "p",
6218       NULL                      /*gst_value_lcopy_buffer */
6219     };
6220 #endif
6221     static GstValueTable gst_value = {
6222       0,
6223       gst_value_compare_buffer,
6224       gst_value_serialize_buffer,
6225       gst_value_deserialize_buffer,
6226     };
6227 
6228     gst_value.type = GST_TYPE_BUFFER;
6229     gst_value_register (&gst_value);
6230   }
6231   {
6232     static GstValueTable gst_value = {
6233       0,
6234       gst_value_compare_sample,
6235       gst_value_serialize_sample,
6236       gst_value_deserialize_sample,
6237     };
6238 
6239     gst_value.type = GST_TYPE_SAMPLE;
6240     gst_value_register (&gst_value);
6241   }
6242   {
6243     static GstValueTable gst_value = {
6244       0,
6245       gst_value_compare_fraction,
6246       gst_value_serialize_fraction,
6247       gst_value_deserialize_fraction,
6248     };
6249 
6250     gst_value.type = gst_fraction_get_type ();
6251     gst_value_register (&gst_value);
6252   }
6253   {
6254     static GstValueTable gst_value = {
6255       0,
6256       gst_value_compare_caps,
6257       gst_value_serialize_caps,
6258       gst_value_deserialize_caps,
6259     };
6260 
6261     gst_value.type = GST_TYPE_CAPS;
6262     gst_value_register (&gst_value);
6263   }
6264   {
6265     static GstValueTable gst_value = {
6266       0,
6267       NULL,
6268       gst_value_serialize_segment,
6269       gst_value_deserialize_segment,
6270     };
6271 
6272     gst_value.type = GST_TYPE_SEGMENT;
6273     gst_value_register (&gst_value);
6274   }
6275   {
6276     static GstValueTable gst_value = {
6277       0,
6278       NULL,
6279       gst_value_serialize_structure,
6280       gst_value_deserialize_structure,
6281     };
6282 
6283     gst_value.type = GST_TYPE_STRUCTURE;
6284     gst_value_register (&gst_value);
6285   }
6286   {
6287     static GstValueTable gst_value = {
6288       0,
6289       NULL,
6290       gst_value_serialize_caps_features,
6291       gst_value_deserialize_caps_features,
6292     };
6293 
6294     gst_value.type = GST_TYPE_CAPS_FEATURES;
6295     gst_value_register (&gst_value);
6296   }
6297   {
6298     static GstValueTable gst_value = {
6299       0,
6300       NULL,
6301       gst_value_serialize_tag_list,
6302       gst_value_deserialize_tag_list,
6303     };
6304 
6305     gst_value.type = GST_TYPE_TAG_LIST;
6306     gst_value_register (&gst_value);
6307   }
6308   {
6309     static GstValueTable gst_value = {
6310       0,
6311       gst_value_compare_date,
6312       gst_value_serialize_date,
6313       gst_value_deserialize_date,
6314     };
6315 
6316     gst_value.type = G_TYPE_DATE;
6317     gst_value_register (&gst_value);
6318   }
6319   {
6320     static GstValueTable gst_value = {
6321       0,
6322       gst_value_compare_date_time,
6323       gst_value_serialize_date_time,
6324       gst_value_deserialize_date_time,
6325     };
6326 
6327     gst_value.type = gst_date_time_get_type ();
6328     gst_value_register (&gst_value);
6329   }
6330 
6331   {
6332     static GstValueTable gst_value = {
6333       0,
6334       gst_value_compare_bitmask,
6335       gst_value_serialize_bitmask,
6336       gst_value_deserialize_bitmask,
6337     };
6338 
6339     gst_value.type = gst_bitmask_get_type ();
6340     gst_value_register (&gst_value);
6341   }
6342 
6343   {
6344     static GstValueTable gst_value = {
6345       0,
6346       gst_value_compare_allocation_params,
6347       NULL,
6348       NULL,
6349     };
6350 
6351     gst_value.type = gst_allocation_params_get_type ();
6352     gst_value_register (&gst_value);
6353   }
6354 
6355   {
6356     static GstValueTable gst_value = {
6357       0,
6358       gst_value_compare_object,
6359       NULL,
6360       NULL,
6361     };
6362 
6363     gst_value.type = G_TYPE_OBJECT;
6364     gst_value_register (&gst_value);
6365   }
6366 
6367   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
6368   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
6369 
6370   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
6371   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
6372   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
6373 
6374   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
6375 
6376   REGISTER_SERIALIZATION (G_TYPE_INT, int);
6377 
6378   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
6379   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
6380 
6381   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
6382   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
6383   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
6384 
6385   REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar);
6386 
6387   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
6388       gst_value_transform_int_range_string);
6389   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
6390       gst_value_transform_int64_range_string);
6391   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
6392       gst_value_transform_double_range_string);
6393   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
6394       gst_value_transform_fraction_range_string);
6395   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
6396       gst_value_transform_list_string);
6397   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
6398       gst_value_transform_array_string);
6399   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
6400       gst_value_transform_fraction_string);
6401   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
6402       gst_value_transform_string_fraction);
6403   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
6404       gst_value_transform_fraction_double);
6405   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
6406       gst_value_transform_fraction_float);
6407   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
6408       gst_value_transform_double_fraction);
6409   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
6410       gst_value_transform_float_fraction);
6411   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
6412       gst_value_transform_date_string);
6413   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
6414       gst_value_transform_string_date);
6415   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
6416       gst_value_transform_object_string);
6417   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
6418       gst_value_transform_bitmask_uint64);
6419   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
6420       gst_value_transform_bitmask_string);
6421   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
6422       gst_value_transform_uint64_bitmask);
6423   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
6424       gst_value_transform_string_bitmask);
6425 
6426   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6427       gst_value_intersect_int_int_range);
6428   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6429       gst_value_intersect_int_range_int_range);
6430   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6431       gst_value_intersect_int64_int64_range);
6432   gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6433       gst_value_intersect_int64_range_int64_range);
6434   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6435       gst_value_intersect_double_double_range);
6436   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
6437       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
6438   gst_value_register_intersect_func (GST_TYPE_ARRAY,
6439       GST_TYPE_ARRAY, gst_value_intersect_array);
6440   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6441       gst_value_intersect_fraction_fraction_range);
6442   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
6443       GST_TYPE_FRACTION_RANGE,
6444       gst_value_intersect_fraction_range_fraction_range);
6445 
6446   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6447       gst_value_subtract_int_int_range);
6448   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
6449       gst_value_subtract_int_range_int);
6450   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6451       gst_value_subtract_int_range_int_range);
6452   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6453       gst_value_subtract_int64_int64_range);
6454   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
6455       gst_value_subtract_int64_range_int64);
6456   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6457       gst_value_subtract_int64_range_int64_range);
6458   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6459       gst_value_subtract_double_double_range);
6460   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
6461       gst_value_subtract_double_range_double);
6462   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
6463       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
6464   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6465       gst_value_subtract_fraction_fraction_range);
6466   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
6467       gst_value_subtract_fraction_range_fraction);
6468   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
6469       GST_TYPE_FRACTION_RANGE,
6470       gst_value_subtract_fraction_range_fraction_range);
6471 
6472   /* see bug #317246, #64994, #65041 */
6473   {
6474     volatile GType date_type = G_TYPE_DATE;
6475 
6476     g_type_name (date_type);
6477   }
6478 
6479   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6480       gst_value_union_int_int_range);
6481   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6482       gst_value_union_int_range_int_range);
6483 
6484 #if 0
6485   /* Implement these if needed */
6486   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6487       gst_value_union_fraction_fraction_range);
6488   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
6489       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
6490 #endif
6491 }