gst/gstvalue.c: Fix typos.
[platform/upstream/gstreamer.git] / gst / gstvalue.c
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, 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 GstValue (or GValue) from multiple
28  * threads may lead to undefined behaviour. 
29  *
30  * Last reviewed on 2008-03-11 (0.10.18)
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 #include <math.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40
41 #include "gst_private.h"
42 #include "glib-compat-private.h"
43 #include <gst/gst.h>
44 #include <gobject/gvaluecollector.h>
45
46 typedef struct _GstValueUnionInfo GstValueUnionInfo;
47 struct _GstValueUnionInfo
48 {
49   GType type1;
50   GType type2;
51   GstValueUnionFunc func;
52 };
53
54 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
55 struct _GstValueIntersectInfo
56 {
57   GType type1;
58   GType type2;
59   GstValueIntersectFunc func;
60 };
61
62 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
63 struct _GstValueSubtractInfo
64 {
65   GType minuend;
66   GType subtrahend;
67   GstValueSubtractFunc func;
68 };
69
70 static GArray *gst_value_table;
71 static GArray *gst_value_union_funcs;
72 static GArray *gst_value_intersect_funcs;
73 static GArray *gst_value_subtract_funcs;
74
75 /* Forward declarations */
76 static gint gst_greatest_common_divisor (gint a, gint b);
77 static gchar *gst_value_serialize_fraction (const GValue * value);
78
79 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
80 static gint gst_value_compare_with_func (const GValue * value1,
81     const GValue * value2, GstValueCompareFunc compare);
82
83 /********
84  * list *
85  ********/
86
87 /* two helper functions to serialize/stringify any type of list
88  * regular lists are done with { }, arrays with < >
89  */
90 static gchar *
91 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
92     const gchar * end)
93 {
94   guint i;
95   GArray *array = value->data[0].v_pointer;
96   GString *s;
97   GValue *v;
98   gchar *s_val;
99
100   /* estimate minimum string length to minimise re-allocs in GString */
101   s = g_string_sized_new (2 + (6 * array->len) + 2);
102   g_string_append (s, begin);
103   for (i = 0; i < array->len; i++) {
104     v = &g_array_index (array, GValue, i);
105     s_val = gst_value_serialize (v);
106     g_string_append (s, s_val);
107     g_free (s_val);
108     if (i < array->len - 1) {
109       g_string_append_len (s, ", ", 2);
110     }
111   }
112   g_string_append (s, end);
113   return g_string_free (s, FALSE);
114 }
115
116 static void
117 gst_value_transform_any_list_string (const GValue * src_value,
118     GValue * dest_value, const gchar * begin, const gchar * end)
119 {
120   GValue *list_value;
121   GArray *array;
122   GString *s;
123   guint i;
124   gchar *list_s;
125
126   array = src_value->data[0].v_pointer;
127
128   /* estimate minimum string length to minimise re-allocs in GString */
129   s = g_string_sized_new (2 + (10 * array->len) + 2);
130   g_string_append (s, begin);
131   for (i = 0; i < array->len; i++) {
132     list_value = &g_array_index (array, GValue, i);
133
134     if (i != 0) {
135       g_string_append_len (s, ", ", 2);
136     }
137     list_s = g_strdup_value_contents (list_value);
138     g_string_append (s, list_s);
139     g_free (list_s);
140   }
141   g_string_append (s, end);
142
143   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
144 }
145
146 /*
147  * helper function to see if a type is fixed. Is used internally here and
148  * there. Do not export, since it doesn't work for types where the content
149  * decides the fixedness (e.g. GST_TYPE_ARRAY).
150  */
151
152 static gboolean
153 gst_type_is_fixed (GType type)
154 {
155   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
156       type == GST_TYPE_LIST) {
157     return FALSE;
158   }
159   if (G_TYPE_FUNDAMENTAL (type) <=
160       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
161     return TRUE;
162   }
163   if (type == GST_TYPE_BUFFER || type == GST_TYPE_FOURCC
164       || type == GST_TYPE_ARRAY || type == GST_TYPE_FRACTION) {
165     return TRUE;
166   }
167
168   return FALSE;
169 }
170
171 /* GValue functions usable for both regular lists and arrays */
172 static void
173 gst_value_init_list_or_array (GValue * value)
174 {
175   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
176 }
177
178 static GArray *
179 copy_garray_of_gstvalue (const GArray * src)
180 {
181   GArray *dest;
182   guint i;
183
184   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), src->len);
185   g_array_set_size (dest, src->len);
186   for (i = 0; i < src->len; i++) {
187     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
188         &g_array_index (src, GValue, i));
189   }
190
191   return dest;
192 }
193
194 static void
195 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
196 {
197   dest_value->data[0].v_pointer =
198       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
199 }
200
201 static void
202 gst_value_free_list_or_array (GValue * value)
203 {
204   guint i;
205   GArray *src = (GArray *) value->data[0].v_pointer;
206
207   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
208     for (i = 0; i < src->len; i++) {
209       g_value_unset (&g_array_index (src, GValue, i));
210     }
211     g_array_free (src, TRUE);
212   }
213 }
214
215 static gpointer
216 gst_value_list_or_array_peek_pointer (const GValue * value)
217 {
218   return value->data[0].v_pointer;
219 }
220
221 static gchar *
222 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
223     GTypeCValue * collect_values, guint collect_flags)
224 {
225   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
226     value->data[0].v_pointer = collect_values[0].v_pointer;
227     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
228   } else {
229     value->data[0].v_pointer =
230         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
231   }
232   return NULL;
233 }
234
235 static gchar *
236 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
237     GTypeCValue * collect_values, guint collect_flags)
238 {
239   GArray **dest = collect_values[0].v_pointer;
240
241   if (!dest)
242     return g_strdup_printf ("value location for `%s' passed as NULL",
243         G_VALUE_TYPE_NAME (value));
244   if (!value->data[0].v_pointer)
245     return g_strdup_printf ("invalid value given for `%s'",
246         G_VALUE_TYPE_NAME (value));
247   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
248     *dest = (GArray *) value->data[0].v_pointer;
249   } else {
250     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
251   }
252   return NULL;
253 }
254
255 /**
256  * gst_value_list_append_value:
257  * @value: a #GValue of type #GST_TYPE_LIST
258  * @append_value: the value to append
259  *
260  * Appends @append_value to the GstValueList in @value.
261  */
262 void
263 gst_value_list_append_value (GValue * value, const GValue * append_value)
264 {
265   GValue val = { 0, };
266
267   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
268
269   gst_value_init_and_copy (&val, append_value);
270   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
271 }
272
273 /**
274  * gst_value_list_prepend_value:
275  * @value: a #GValue of type #GST_TYPE_LIST
276  * @prepend_value: the value to prepend
277  *
278  * Prepends @prepend_value to the GstValueList in @value.
279  */
280 void
281 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
282 {
283   GValue val = { 0, };
284
285   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
286
287   gst_value_init_and_copy (&val, prepend_value);
288   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
289 }
290
291 /**
292  * gst_value_list_concat:
293  * @dest: an uninitialized #GValue to take the result
294  * @value1: a #GValue
295  * @value2: a #GValue
296  *
297  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
298  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
299  * @dest will be initialized to the type #GST_TYPE_LIST.
300  */
301 void
302 gst_value_list_concat (GValue * dest, const GValue * value1,
303     const GValue * value2)
304 {
305   guint i, value1_length, value2_length;
306   GArray *array;
307
308   g_return_if_fail (dest != NULL);
309   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
310   g_return_if_fail (G_IS_VALUE (value1));
311   g_return_if_fail (G_IS_VALUE (value2));
312
313   value1_length =
314       (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
315   value2_length =
316       (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
317   g_value_init (dest, GST_TYPE_LIST);
318   array = (GArray *) dest->data[0].v_pointer;
319   g_array_set_size (array, value1_length + value2_length);
320
321   if (GST_VALUE_HOLDS_LIST (value1)) {
322     for (i = 0; i < value1_length; i++) {
323       gst_value_init_and_copy (&g_array_index (array, GValue, i),
324           gst_value_list_get_value (value1, i));
325     }
326   } else {
327     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
328   }
329
330   if (GST_VALUE_HOLDS_LIST (value2)) {
331     for (i = 0; i < value2_length; i++) {
332       gst_value_init_and_copy (&g_array_index (array, GValue,
333               i + value1_length), gst_value_list_get_value (value2, i));
334     }
335   } else {
336     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
337         value2);
338   }
339 }
340
341 /**
342  * gst_value_list_get_size:
343  * @value: a #GValue of type #GST_TYPE_LIST
344  *
345  * Gets the number of values contained in @value.
346  *
347  * Returns: the number of values
348  */
349 guint
350 gst_value_list_get_size (const GValue * value)
351 {
352   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
353
354   return ((GArray *) value->data[0].v_pointer)->len;
355 }
356
357 /**
358  * gst_value_list_get_value:
359  * @value: a #GValue of type #GST_TYPE_LIST
360  * @index: index of value to get from the list
361  *
362  * Gets the value that is a member of the list contained in @value and
363  * has the index @index.
364  *
365  * Returns: the value at the given index
366  */
367 const GValue *
368 gst_value_list_get_value (const GValue * value, guint index)
369 {
370   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
371   g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
372
373   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
374       GValue, index);
375 }
376
377 /**
378  * gst_value_array_append_value:
379  * @value: a #GValue of type #GST_TYPE_ARRAY
380  * @append_value: the value to append
381  *
382  * Appends @append_value to the GstValueArray in @value.
383  */
384 void
385 gst_value_array_append_value (GValue * value, const GValue * append_value)
386 {
387   GValue val = { 0, };
388
389   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
390
391   gst_value_init_and_copy (&val, append_value);
392   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
393 }
394
395 /**
396  * gst_value_array_prepend_value:
397  * @value: a #GValue of type #GST_TYPE_ARRAY
398  * @prepend_value: the value to prepend
399  *
400  * Prepends @prepend_value to the GstValueArray in @value.
401  */
402 void
403 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
404 {
405   GValue val = { 0, };
406
407   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
408
409   gst_value_init_and_copy (&val, prepend_value);
410   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
411 }
412
413 /**
414  * gst_value_array_get_size:
415  * @value: a #GValue of type #GST_TYPE_ARRAY
416  *
417  * Gets the number of values contained in @value.
418  *
419  * Returns: the number of values
420  */
421 guint
422 gst_value_array_get_size (const GValue * value)
423 {
424   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
425
426   return ((GArray *) value->data[0].v_pointer)->len;
427 }
428
429 /**
430  * gst_value_array_get_value:
431  * @value: a #GValue of type #GST_TYPE_ARRAY
432  * @index: index of value to get from the array
433  *
434  * Gets the value that is a member of the array contained in @value and
435  * has the index @index.
436  *
437  * Returns: the value at the given index
438  */
439 const GValue *
440 gst_value_array_get_value (const GValue * value, guint index)
441 {
442   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
443   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
444
445   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
446       GValue, index);
447 }
448
449 static void
450 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
451 {
452   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
453 }
454
455 static void
456 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
457 {
458   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
459 }
460
461 /* Do an unordered compare of the contents of a list */
462 static int
463 gst_value_compare_list (const GValue * value1, const GValue * value2)
464 {
465   guint i, j;
466   GArray *array1 = value1->data[0].v_pointer;
467   GArray *array2 = value2->data[0].v_pointer;
468   GValue *v1;
469   GValue *v2;
470   gint len, to_remove;
471   guint8 *removed;
472   GstValueCompareFunc compare;
473
474   /* get length and do initial length check. */
475   len = array1->len;
476   if (len != array2->len)
477     return GST_VALUE_UNORDERED;
478
479   /* place to mark removed value indices of array2 */
480   removed = g_newa (guint8, len);
481   memset (removed, 0, len);
482   to_remove = len;
483
484   /* loop over array1, all items should be in array2. When we find an
485    * item in array2, remove it from array2 by marking it as removed */
486   for (i = 0; i < len; i++) {
487     v1 = &g_array_index (array1, GValue, i);
488     if ((compare = gst_value_get_compare_func (v1))) {
489       for (j = 0; j < len; j++) {
490         /* item is removed, we can skip it */
491         if (removed[j])
492           continue;
493         v2 = &g_array_index (array2, GValue, j);
494         if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
495           /* mark item as removed now that we found it in array2 and 
496            * decrement the number of remaining items in array2. */
497           removed[j] = 1;
498           to_remove--;
499           break;
500         }
501       }
502       /* item in array1 and not in array2, UNORDERED */
503       if (j == len)
504         return GST_VALUE_UNORDERED;
505     } else
506       return GST_VALUE_UNORDERED;
507   }
508   /* if not all items were removed, array2 contained something not in array1 */
509   if (to_remove != 0)
510     return GST_VALUE_UNORDERED;
511
512   /* arrays are equal */
513   return GST_VALUE_EQUAL;
514 }
515
516 /* Perform an ordered comparison of the contents of an array */
517 static int
518 gst_value_compare_array (const GValue * value1, const GValue * value2)
519 {
520   guint i;
521   GArray *array1 = value1->data[0].v_pointer;
522   GArray *array2 = value2->data[0].v_pointer;
523   GValue *v1;
524   GValue *v2;
525
526   if (array1->len != array2->len)
527     return GST_VALUE_UNORDERED;
528
529   for (i = 0; i < array1->len; i++) {
530     v1 = &g_array_index (array1, GValue, i);
531     v2 = &g_array_index (array2, GValue, i);
532     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
533       return GST_VALUE_UNORDERED;
534   }
535
536   return GST_VALUE_EQUAL;
537 }
538
539 static gchar *
540 gst_value_serialize_list (const GValue * value)
541 {
542   return gst_value_serialize_any_list (value, "{ ", " }");
543 }
544
545 static gboolean
546 gst_value_deserialize_list (GValue * dest, const gchar * s)
547 {
548   g_warning ("gst_value_deserialize_list: unimplemented");
549   return FALSE;
550 }
551
552 static gchar *
553 gst_value_serialize_array (const GValue * value)
554 {
555   return gst_value_serialize_any_list (value, "< ", " >");
556 }
557
558 static gboolean
559 gst_value_deserialize_array (GValue * dest, const gchar * s)
560 {
561   g_warning ("gst_value_deserialize_array: unimplemented");
562   return FALSE;
563 }
564
565 /**********
566  * fourcc *
567  **********/
568
569 static void
570 gst_value_init_fourcc (GValue * value)
571 {
572   value->data[0].v_int = 0;
573 }
574
575 static void
576 gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value)
577 {
578   dest_value->data[0].v_int = src_value->data[0].v_int;
579 }
580
581 static gchar *
582 gst_value_collect_fourcc (GValue * value, guint n_collect_values,
583     GTypeCValue * collect_values, guint collect_flags)
584 {
585   value->data[0].v_int = collect_values[0].v_int;
586
587   return NULL;
588 }
589
590 static gchar *
591 gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values,
592     GTypeCValue * collect_values, guint collect_flags)
593 {
594   guint32 *fourcc_p = collect_values[0].v_pointer;
595
596   if (!fourcc_p)
597     return g_strdup_printf ("value location for `%s' passed as NULL",
598         G_VALUE_TYPE_NAME (value));
599
600   *fourcc_p = value->data[0].v_int;
601
602   return NULL;
603 }
604
605 /**
606  * gst_value_set_fourcc:
607  * @value: a GValue initialized to #GST_TYPE_FOURCC
608  * @fourcc: the #guint32 fourcc to set
609  *
610  * Sets @value to @fourcc.
611  */
612 void
613 gst_value_set_fourcc (GValue * value, guint32 fourcc)
614 {
615   g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
616
617   value->data[0].v_int = fourcc;
618 }
619
620 /**
621  * gst_value_get_fourcc:
622  * @value: a GValue initialized to #GST_TYPE_FOURCC
623  *
624  * Gets the #guint32 fourcc contained in @value.
625  *
626  * Returns: the #guint32 fourcc contained in @value.
627  */
628 guint32
629 gst_value_get_fourcc (const GValue * value)
630 {
631   g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
632
633   return value->data[0].v_int;
634 }
635
636 static void
637 gst_value_transform_fourcc_string (const GValue * src_value,
638     GValue * dest_value)
639 {
640   guint32 fourcc = src_value->data[0].v_int;
641
642   if (g_ascii_isprint ((fourcc >> 0) & 0xff) &&
643       g_ascii_isprint ((fourcc >> 8) & 0xff) &&
644       g_ascii_isprint ((fourcc >> 16) & 0xff) &&
645       g_ascii_isprint ((fourcc >> 24) & 0xff)) {
646     dest_value->data[0].v_pointer =
647         g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
648   } else {
649     dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc);
650   }
651 }
652
653 static gint
654 gst_value_compare_fourcc (const GValue * value1, const GValue * value2)
655 {
656   if (value2->data[0].v_int == value1->data[0].v_int)
657     return GST_VALUE_EQUAL;
658   return GST_VALUE_UNORDERED;
659 }
660
661 static gchar *
662 gst_value_serialize_fourcc (const GValue * value)
663 {
664   guint32 fourcc = value->data[0].v_int;
665
666   if (g_ascii_isalnum ((fourcc >> 0) & 0xff) &&
667       g_ascii_isalnum ((fourcc >> 8) & 0xff) &&
668       g_ascii_isalnum ((fourcc >> 16) & 0xff) &&
669       g_ascii_isalnum ((fourcc >> 24) & 0xff)) {
670     return g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
671   } else {
672     return g_strdup_printf ("0x%08x", fourcc);
673   }
674 }
675
676 static gboolean
677 gst_value_deserialize_fourcc (GValue * dest, const char *s)
678 {
679   gboolean ret = FALSE;
680   guint32 fourcc = 0;
681   char *end;
682
683   if (strlen (s) == 4) {
684     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
685     ret = TRUE;
686   } else if (g_ascii_isdigit (*s)) {
687     fourcc = strtoul (s, &end, 0);
688     if (*end == 0) {
689       ret = TRUE;
690     }
691   }
692   gst_value_set_fourcc (dest, fourcc);
693
694   return ret;
695 }
696
697 /*************
698  * int range *
699  *************/
700
701 static void
702 gst_value_init_int_range (GValue * value)
703 {
704   value->data[0].v_int = 0;
705   value->data[1].v_int = 0;
706 }
707
708 static void
709 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
710 {
711   dest_value->data[0].v_int = src_value->data[0].v_int;
712   dest_value->data[1].v_int = src_value->data[1].v_int;
713 }
714
715 static gchar *
716 gst_value_collect_int_range (GValue * value, guint n_collect_values,
717     GTypeCValue * collect_values, guint collect_flags)
718 {
719   value->data[0].v_int = collect_values[0].v_int;
720   value->data[1].v_int = collect_values[1].v_int;
721
722   return NULL;
723 }
724
725 static gchar *
726 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
727     GTypeCValue * collect_values, guint collect_flags)
728 {
729   guint32 *int_range_start = collect_values[0].v_pointer;
730   guint32 *int_range_end = collect_values[1].v_pointer;
731
732   if (!int_range_start)
733     return g_strdup_printf ("start value location for `%s' passed as NULL",
734         G_VALUE_TYPE_NAME (value));
735   if (!int_range_end)
736     return g_strdup_printf ("end value location for `%s' passed as NULL",
737         G_VALUE_TYPE_NAME (value));
738
739   *int_range_start = value->data[0].v_int;
740   *int_range_end = value->data[1].v_int;
741
742   return NULL;
743 }
744
745 /**
746  * gst_value_set_int_range:
747  * @value: a GValue initialized to GST_TYPE_INT_RANGE
748  * @start: the start of the range
749  * @end: the end of the range
750  *
751  * Sets @value to the range specified by @start and @end.
752  */
753 void
754 gst_value_set_int_range (GValue * value, gint start, gint end)
755 {
756   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
757   g_return_if_fail (start < end);
758
759   value->data[0].v_int = start;
760   value->data[1].v_int = end;
761 }
762
763 /**
764  * gst_value_get_int_range_min:
765  * @value: a GValue initialized to GST_TYPE_INT_RANGE
766  *
767  * Gets the minimum of the range specified by @value.
768  *
769  * Returns: the minimum of the range
770  */
771 gint
772 gst_value_get_int_range_min (const GValue * value)
773 {
774   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
775
776   return value->data[0].v_int;
777 }
778
779 /**
780  * gst_value_get_int_range_max:
781  * @value: a GValue initialized to GST_TYPE_INT_RANGE
782  *
783  * Gets the maximum of the range specified by @value.
784  *
785  * Returns: the maxumum of the range
786  */
787 gint
788 gst_value_get_int_range_max (const GValue * value)
789 {
790   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
791
792   return value->data[1].v_int;
793 }
794
795 static void
796 gst_value_transform_int_range_string (const GValue * src_value,
797     GValue * dest_value)
798 {
799   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
800       (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
801 }
802
803 static gint
804 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
805 {
806   if (value2->data[0].v_int == value1->data[0].v_int &&
807       value2->data[1].v_int == value1->data[1].v_int)
808     return GST_VALUE_EQUAL;
809   return GST_VALUE_UNORDERED;
810 }
811
812 static gchar *
813 gst_value_serialize_int_range (const GValue * value)
814 {
815   return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
816       value->data[1].v_int);
817 }
818
819 static gboolean
820 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
821 {
822   g_warning ("unimplemented");
823   return FALSE;
824 }
825
826 /****************
827  * double range *
828  ****************/
829
830 static void
831 gst_value_init_double_range (GValue * value)
832 {
833   value->data[0].v_double = 0;
834   value->data[1].v_double = 0;
835 }
836
837 static void
838 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
839 {
840   dest_value->data[0].v_double = src_value->data[0].v_double;
841   dest_value->data[1].v_double = src_value->data[1].v_double;
842 }
843
844 static gchar *
845 gst_value_collect_double_range (GValue * value, guint n_collect_values,
846     GTypeCValue * collect_values, guint collect_flags)
847 {
848   value->data[0].v_double = collect_values[0].v_double;
849   value->data[1].v_double = collect_values[1].v_double;
850
851   return NULL;
852 }
853
854 static gchar *
855 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
856     GTypeCValue * collect_values, guint collect_flags)
857 {
858   gdouble *double_range_start = collect_values[0].v_pointer;
859   gdouble *double_range_end = collect_values[1].v_pointer;
860
861   if (!double_range_start)
862     return g_strdup_printf ("start value location for `%s' passed as NULL",
863         G_VALUE_TYPE_NAME (value));
864   if (!double_range_end)
865     return g_strdup_printf ("end value location for `%s' passed as NULL",
866         G_VALUE_TYPE_NAME (value));
867
868   *double_range_start = value->data[0].v_double;
869   *double_range_end = value->data[1].v_double;
870
871   return NULL;
872 }
873
874 /**
875  * gst_value_set_double_range:
876  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
877  * @start: the start of the range
878  * @end: the end of the range
879  *
880  * Sets @value to the range specified by @start and @end.
881  */
882 void
883 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
884 {
885   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
886
887   value->data[0].v_double = start;
888   value->data[1].v_double = end;
889 }
890
891 /**
892  * gst_value_get_double_range_min:
893  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
894  *
895  * Gets the minimum of the range specified by @value.
896  *
897  * Returns: the minimum of the range
898  */
899 gdouble
900 gst_value_get_double_range_min (const GValue * value)
901 {
902   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
903
904   return value->data[0].v_double;
905 }
906
907 /**
908  * gst_value_get_double_range_max:
909  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
910  *
911  * Gets the maximum of the range specified by @value.
912  *
913  * Returns: the maxumum of the range
914  */
915 gdouble
916 gst_value_get_double_range_max (const GValue * value)
917 {
918   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
919
920   return value->data[1].v_double;
921 }
922
923 static void
924 gst_value_transform_double_range_string (const GValue * src_value,
925     GValue * dest_value)
926 {
927   char s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
928
929   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
930       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
931           src_value->data[0].v_double),
932       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
933           src_value->data[1].v_double));
934 }
935
936 static gint
937 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
938 {
939   if (value2->data[0].v_double == value1->data[0].v_double &&
940       value2->data[0].v_double == value1->data[0].v_double)
941     return GST_VALUE_EQUAL;
942   return GST_VALUE_UNORDERED;
943 }
944
945 static gchar *
946 gst_value_serialize_double_range (const GValue * value)
947 {
948   char d1[G_ASCII_DTOSTR_BUF_SIZE];
949   char d2[G_ASCII_DTOSTR_BUF_SIZE];
950
951   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
952   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
953   return g_strdup_printf ("[ %s, %s ]", d1, d2);
954 }
955
956 static gboolean
957 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
958 {
959   g_warning ("unimplemented");
960   return FALSE;
961 }
962
963 /****************
964  * fraction range *
965  ****************/
966
967 static void
968 gst_value_init_fraction_range (GValue * value)
969 {
970   GValue *vals;
971
972   value->data[0].v_pointer = vals = g_new0 (GValue, 2);
973   g_value_init (&vals[0], GST_TYPE_FRACTION);
974   g_value_init (&vals[1], GST_TYPE_FRACTION);
975 }
976
977 static void
978 gst_value_free_fraction_range (GValue * value)
979 {
980   GValue *vals = (GValue *) value->data[0].v_pointer;
981
982   if (vals != NULL) {
983     g_value_unset (&vals[0]);
984     g_value_unset (&vals[1]);
985     g_free (vals);
986     value->data[0].v_pointer = NULL;
987   }
988 }
989
990 static void
991 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
992 {
993   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
994   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
995
996   if (vals == NULL) {
997     dest_value->data[0].v_pointer = vals = g_new0 (GValue, 2);
998     g_return_if_fail (vals != NULL);
999     g_value_init (&vals[0], GST_TYPE_FRACTION);
1000     g_value_init (&vals[1], GST_TYPE_FRACTION);
1001   }
1002
1003   if (src_vals != NULL) {
1004     g_value_copy (&src_vals[0], &vals[0]);
1005     g_value_copy (&src_vals[1], &vals[1]);
1006   }
1007 }
1008
1009 static gchar *
1010 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1011     GTypeCValue * collect_values, guint collect_flags)
1012 {
1013   GValue *vals = (GValue *) value->data[0].v_pointer;
1014
1015   if (n_collect_values != 4)
1016     return g_strdup_printf ("not enough value locations for `%s' passed",
1017         G_VALUE_TYPE_NAME (value));
1018   if (vals == NULL) {
1019     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
1020     if (vals == NULL)
1021       return g_strdup_printf ("Could not initialise`%s' during collect",
1022           G_VALUE_TYPE_NAME (value));
1023     g_value_init (&vals[0], GST_TYPE_FRACTION);
1024     g_value_init (&vals[1], GST_TYPE_FRACTION);
1025   }
1026
1027   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1028       collect_values[1].v_int);
1029   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1030       collect_values[3].v_int);
1031
1032   return NULL;
1033 }
1034
1035 static gchar *
1036 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1037     GTypeCValue * collect_values, guint collect_flags)
1038 {
1039   int i;
1040   int *dest_values[4];
1041   GValue *vals = (GValue *) value->data[0].v_pointer;
1042
1043   if (n_collect_values != 4)
1044     return g_strdup_printf ("not enough value locations for `%s' passed",
1045         G_VALUE_TYPE_NAME (value));
1046
1047   for (i = 0; i < 4; i++) {
1048     if (collect_values[i].v_pointer == NULL) {
1049       return g_strdup_printf ("value location for `%s' passed as NULL",
1050           G_VALUE_TYPE_NAME (value));
1051     }
1052     dest_values[i] = collect_values[i].v_pointer;
1053   }
1054
1055   if (vals == NULL) {
1056     return g_strdup_printf ("Uninitialised `%s' passed",
1057         G_VALUE_TYPE_NAME (value));
1058   }
1059
1060   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1061   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1062   dest_values[2][0] = gst_value_get_fraction_denominator (&vals[1]);
1063   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1064   return NULL;
1065 }
1066
1067 /**
1068  * gst_value_set_fraction_range:
1069  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1070  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1071  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1072  *
1073  * Sets @value to the range specified by @start and @end.
1074  */
1075 void
1076 gst_value_set_fraction_range (GValue * value, const GValue * start,
1077     const GValue * end)
1078 {
1079   GValue *vals;
1080
1081   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1082
1083   vals = (GValue *) value->data[0].v_pointer;
1084   if (vals == NULL) {
1085     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
1086     g_value_init (&vals[0], GST_TYPE_FRACTION);
1087     g_value_init (&vals[1], GST_TYPE_FRACTION);
1088   }
1089
1090   g_value_copy (start, &vals[0]);
1091   g_value_copy (end, &vals[1]);
1092 }
1093
1094 /**
1095  * gst_value_set_fraction_range_full:
1096  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1097  * @numerator_start: the numerator start of the range
1098  * @denominator_start: the denominator start of the range
1099  * @numerator_end: the numerator end of the range
1100  * @denominator_end: the denominator end of the range
1101  *
1102  * Sets @value to the range specified by @numerator_start/@denominator_start
1103  * and @numerator_end/@denominator_end.
1104  */
1105 void
1106 gst_value_set_fraction_range_full (GValue * value,
1107     gint numerator_start, gint denominator_start,
1108     gint numerator_end, gint denominator_end)
1109 {
1110   GValue start = { 0 };
1111   GValue end = { 0 };
1112
1113   g_value_init (&start, GST_TYPE_FRACTION);
1114   g_value_init (&end, GST_TYPE_FRACTION);
1115
1116   gst_value_set_fraction (&start, numerator_start, denominator_start);
1117   gst_value_set_fraction (&end, numerator_end, denominator_end);
1118   gst_value_set_fraction_range (value, &start, &end);
1119
1120   g_value_unset (&start);
1121   g_value_unset (&end);
1122 }
1123
1124 /**
1125  * gst_value_get_fraction_range_min:
1126  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1127  *
1128  * Gets the minimum of the range specified by @value.
1129  *
1130  * Returns: the minimum of the range
1131  */
1132 const GValue *
1133 gst_value_get_fraction_range_min (const GValue * value)
1134 {
1135   GValue *vals;
1136
1137   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
1138
1139   vals = (GValue *) value->data[0].v_pointer;
1140   if (vals != NULL) {
1141     return &vals[0];
1142   }
1143
1144   return NULL;
1145 }
1146
1147 /**
1148  * gst_value_get_fraction_range_max:
1149  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1150  *
1151  * Gets the maximum of the range specified by @value.
1152  *
1153  * Returns: the maximum of the range
1154  */
1155 const GValue *
1156 gst_value_get_fraction_range_max (const GValue * value)
1157 {
1158   GValue *vals;
1159
1160   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
1161
1162   vals = (GValue *) value->data[0].v_pointer;
1163   if (vals != NULL) {
1164     return &vals[1];
1165   }
1166
1167   return NULL;
1168 }
1169
1170 static char *
1171 gst_value_serialize_fraction_range (const GValue * value)
1172 {
1173   GValue *vals = (GValue *) value->data[0].v_pointer;
1174   gchar *retval;
1175
1176   if (vals == NULL) {
1177     retval = g_strdup ("[ 0/1, 0/1 ]");
1178   } else {
1179     gchar *start, *end;
1180
1181     start = gst_value_serialize_fraction (&vals[0]);
1182     end = gst_value_serialize_fraction (&vals[1]);
1183
1184     retval = g_strdup_printf ("[ %s, %s ]", start, end);
1185     g_free (start);
1186     g_free (end);
1187   }
1188
1189   return retval;
1190 }
1191
1192 static void
1193 gst_value_transform_fraction_range_string (const GValue * src_value,
1194     GValue * dest_value)
1195 {
1196   dest_value->data[0].v_pointer =
1197       gst_value_serialize_fraction_range (src_value);
1198 }
1199
1200 static gint
1201 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
1202 {
1203   GValue *vals1, *vals2;
1204   GstValueCompareFunc compare;
1205
1206   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
1207     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
1208
1209   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
1210     return GST_VALUE_UNORDERED;
1211
1212   vals1 = (GValue *) value1->data[0].v_pointer;
1213   vals2 = (GValue *) value2->data[0].v_pointer;
1214   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
1215     if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
1216         GST_VALUE_EQUAL &&
1217         gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
1218         GST_VALUE_EQUAL)
1219       return GST_VALUE_EQUAL;
1220   }
1221   return GST_VALUE_UNORDERED;
1222 }
1223
1224 static gboolean
1225 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
1226 {
1227   g_warning ("unimplemented");
1228   return FALSE;
1229 }
1230
1231 /***********
1232  * GstCaps *
1233  ***********/
1234
1235 /**
1236  * gst_value_set_caps:
1237  * @value: a GValue initialized to GST_TYPE_CAPS
1238  * @caps: the caps to set the value to
1239  *
1240  * Sets the contents of @value to @caps.  The actual
1241  * #GstCaps structure is copied before it is used.
1242  */
1243 void
1244 gst_value_set_caps (GValue * value, const GstCaps * caps)
1245 {
1246   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
1247
1248   g_value_set_boxed (value, caps);
1249 }
1250
1251 /**
1252  * gst_value_get_caps:
1253  * @value: a GValue initialized to GST_TYPE_CAPS
1254  *
1255  * Gets the contents of @value.
1256  *
1257  * Returns: the contents of @value
1258  */
1259 const GstCaps *
1260 gst_value_get_caps (const GValue * value)
1261 {
1262   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
1263
1264   return (GstCaps *) g_value_get_boxed (value);
1265 }
1266
1267 static char *
1268 gst_value_serialize_caps (const GValue * value)
1269 {
1270   GstCaps *caps = g_value_get_boxed (value);
1271
1272   return gst_caps_to_string (caps);
1273 }
1274
1275 static gboolean
1276 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1277 {
1278   GstCaps *caps;
1279
1280   caps = gst_caps_from_string (s);
1281
1282   if (caps) {
1283     g_value_take_boxed (dest, caps);
1284     return TRUE;
1285   }
1286   return FALSE;
1287 }
1288
1289 /****************
1290  * GstStructure *
1291  ****************/
1292
1293 /**
1294  * gst_value_set_structure:
1295  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1296  * @structure: the structure to set the value to
1297  *
1298  * Sets the contents of @value to @structure.  The actual
1299  *
1300  * Since: 0.10.15
1301  */
1302 void
1303 gst_value_set_structure (GValue * value, const GstStructure * structure)
1304 {
1305   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
1306
1307   g_value_set_boxed (value, structure);
1308 }
1309
1310 /**
1311  * gst_value_get_structure:
1312  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1313  *
1314  * Gets the contents of @value.
1315  *
1316  * Returns: the contents of @value
1317  *
1318  * Since: 0.10.15
1319  */
1320 const GstStructure *
1321 gst_value_get_structure (const GValue * value)
1322 {
1323   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
1324
1325   return (GstStructure *) g_value_get_boxed (value);
1326 }
1327
1328 static char *
1329 gst_value_serialize_structure (const GValue * value)
1330 {
1331   GstStructure *structure = g_value_get_boxed (value);
1332
1333   return gst_structure_to_string (structure);
1334 }
1335
1336 static gboolean
1337 gst_value_deserialize_structure (GValue * dest, const gchar * s)
1338 {
1339   GstStructure *structure;
1340
1341   structure = gst_structure_from_string (s, NULL);
1342
1343   if (structure) {
1344     g_value_set_boxed (dest, structure);
1345     return TRUE;
1346   }
1347   return FALSE;
1348 }
1349
1350 /*************
1351  * GstBuffer *
1352  *************/
1353
1354 static int
1355 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
1356 {
1357   GstBuffer *buf1 = GST_BUFFER (gst_value_get_mini_object (value1));
1358   GstBuffer *buf2 = GST_BUFFER (gst_value_get_mini_object (value2));
1359
1360   if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2))
1361     return GST_VALUE_UNORDERED;
1362   if (GST_BUFFER_SIZE (buf1) == 0)
1363     return GST_VALUE_EQUAL;
1364   g_assert (GST_BUFFER_DATA (buf1));
1365   g_assert (GST_BUFFER_DATA (buf2));
1366   if (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2),
1367           GST_BUFFER_SIZE (buf1)) == 0)
1368     return GST_VALUE_EQUAL;
1369
1370   return GST_VALUE_UNORDERED;
1371 }
1372
1373 static char *
1374 gst_value_serialize_buffer (const GValue * value)
1375 {
1376   guint8 *data;
1377   int i;
1378   int size;
1379   char *string;
1380   GstBuffer *buffer;
1381
1382   buffer = gst_value_get_buffer (value);
1383   if (buffer == NULL)
1384     return NULL;
1385
1386   data = GST_BUFFER_DATA (buffer);
1387   size = GST_BUFFER_SIZE (buffer);
1388
1389   string = g_malloc (size * 2 + 1);
1390   for (i = 0; i < size; i++) {
1391     sprintf (string + i * 2, "%02x", data[i]);
1392   }
1393   string[size * 2] = 0;
1394
1395   return string;
1396 }
1397
1398 static gboolean
1399 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
1400 {
1401   GstBuffer *buffer;
1402   int len;
1403   char ts[3];
1404   guint8 *data;
1405   int i;
1406
1407   len = strlen (s);
1408   if (len & 1)
1409     goto wrong_length;
1410
1411   buffer = gst_buffer_new_and_alloc (len / 2);
1412   data = GST_BUFFER_DATA (buffer);
1413   for (i = 0; i < len / 2; i++) {
1414     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
1415       goto wrong_char;
1416
1417     ts[0] = s[i * 2 + 0];
1418     ts[1] = s[i * 2 + 1];
1419     ts[2] = 0;
1420
1421     data[i] = (guint8) strtoul (ts, NULL, 16);
1422   }
1423
1424   gst_value_take_buffer (dest, buffer);
1425
1426   return TRUE;
1427
1428   /* ERRORS */
1429 wrong_length:
1430   {
1431     return FALSE;
1432   }
1433 wrong_char:
1434   {
1435     gst_buffer_unref (buffer);
1436     return FALSE;
1437   }
1438 }
1439
1440
1441 /***********
1442  * boolean *
1443  ***********/
1444
1445 static int
1446 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
1447 {
1448   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
1449     return GST_VALUE_EQUAL;
1450   return GST_VALUE_UNORDERED;
1451 }
1452
1453 static char *
1454 gst_value_serialize_boolean (const GValue * value)
1455 {
1456   if (value->data[0].v_int) {
1457     return g_strdup ("true");
1458   }
1459   return g_strdup ("false");
1460 }
1461
1462 static gboolean
1463 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
1464 {
1465   gboolean ret = FALSE;
1466
1467   if (g_ascii_strcasecmp (s, "true") == 0 ||
1468       g_ascii_strcasecmp (s, "yes") == 0 ||
1469       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
1470     g_value_set_boolean (dest, TRUE);
1471     ret = TRUE;
1472   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
1473       g_ascii_strcasecmp (s, "no") == 0 ||
1474       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
1475     g_value_set_boolean (dest, FALSE);
1476     ret = TRUE;
1477   }
1478
1479   return ret;
1480 }
1481
1482 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
1483 static gint                                                             \
1484 gst_value_compare_ ## _type                                             \
1485 (const GValue * value1, const GValue * value2)                          \
1486 {                                                                       \
1487   g ## _type val1 = g_value_get_ ## _type (value1);                     \
1488   g ## _type val2 = g_value_get_ ## _type (value2);                     \
1489   if (val1 > val2)                                                      \
1490     return GST_VALUE_GREATER_THAN;                                      \
1491   if (val1 < val2)                                                      \
1492     return GST_VALUE_LESS_THAN;                                         \
1493   return GST_VALUE_EQUAL;                                               \
1494 }                                                                       \
1495                                                                         \
1496 static char *                                                           \
1497 gst_value_serialize_ ## _type (const GValue * value)                    \
1498 {                                                                       \
1499   GValue val = { 0, };                                                  \
1500   g_value_init (&val, G_TYPE_STRING);                                   \
1501   if (!g_value_transform (value, &val))                                 \
1502     g_assert_not_reached ();                                            \
1503   /* NO_COPY_MADNESS!!! */                                              \
1504   return (char *) g_value_get_string (&val);                            \
1505 }
1506
1507 /* deserialize the given s into to as a gint64.
1508  * check if the result is actually storeable in the given size number of
1509  * bytes.
1510  */
1511 static gboolean
1512 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
1513     gint64 min, gint64 max, gint size)
1514 {
1515   gboolean ret = FALSE;
1516   char *end;
1517   gint64 mask = -1;
1518
1519   errno = 0;
1520   *to = g_ascii_strtoull (s, &end, 0);
1521   /* a range error is a definitive no-no */
1522   if (errno == ERANGE) {
1523     return FALSE;
1524   }
1525
1526   if (*end == 0) {
1527     ret = TRUE;
1528   } else {
1529     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
1530       *to = G_LITTLE_ENDIAN;
1531       ret = TRUE;
1532     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
1533       *to = G_BIG_ENDIAN;
1534       ret = TRUE;
1535     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
1536       *to = G_BYTE_ORDER;
1537       ret = TRUE;
1538     } else if (g_ascii_strcasecmp (s, "min") == 0) {
1539       *to = min;
1540       ret = TRUE;
1541     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1542       *to = max;
1543       ret = TRUE;
1544     }
1545   }
1546   if (ret) {
1547     /* by definition, a gint64 fits into a gint64; so ignore those */
1548     if (size != sizeof (mask)) {
1549       if (*to >= 0) {
1550         /* for positive numbers, we create a mask of 1's outside of the range
1551          * and 0's inside the range.  An and will thus keep only 1 bits
1552          * outside of the range */
1553         mask <<= (size * 8);
1554         if ((mask & *to) != 0) {
1555           ret = FALSE;
1556         }
1557       } else {
1558         /* for negative numbers, we do a 2's complement version */
1559         mask <<= ((size * 8) - 1);
1560         if ((mask & *to) != mask) {
1561           ret = FALSE;
1562         }
1563       }
1564     }
1565   }
1566   return ret;
1567 }
1568
1569 #define CREATE_SERIALIZATION(_type,_macro)                              \
1570 CREATE_SERIALIZATION_START(_type,_macro)                                \
1571                                                                         \
1572 static gboolean                                                         \
1573 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1574 {                                                                       \
1575   gint64 x;                                                             \
1576                                                                         \
1577   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
1578       G_MAX ## _macro, sizeof (g ## _type))) {                          \
1579     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
1580     return TRUE;                                                        \
1581   } else {                                                              \
1582     return FALSE;                                                       \
1583   }                                                                     \
1584 }
1585
1586 #define CREATE_USERIALIZATION(_type,_macro)                             \
1587 CREATE_SERIALIZATION_START(_type,_macro)                                \
1588                                                                         \
1589 static gboolean                                                         \
1590 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1591 {                                                                       \
1592   gint64 x;                                                             \
1593   char *end;                                                            \
1594   gboolean ret = FALSE;                                                 \
1595                                                                         \
1596   errno = 0;                                                            \
1597   x = g_ascii_strtoull (s, &end, 0);                                    \
1598   /* a range error is a definitive no-no */                             \
1599   if (errno == ERANGE) {                                                \
1600     return FALSE;                                                       \
1601   }                                                                     \
1602   /* the cast ensures the range check later on makes sense */           \
1603   x = (g ## _type) x;                                                   \
1604   if (*end == 0) {                                                      \
1605     ret = TRUE;                                                         \
1606   } else {                                                              \
1607     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
1608       x = G_LITTLE_ENDIAN;                                              \
1609       ret = TRUE;                                                       \
1610     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
1611       x = G_BIG_ENDIAN;                                                 \
1612       ret = TRUE;                                                       \
1613     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
1614       x = G_BYTE_ORDER;                                                 \
1615       ret = TRUE;                                                       \
1616     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
1617       x = 0;                                                            \
1618       ret = TRUE;                                                       \
1619     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
1620       x = G_MAX ## _macro;                                              \
1621       ret = TRUE;                                                       \
1622     }                                                                   \
1623   }                                                                     \
1624   if (ret) {                                                            \
1625     if (x > G_MAX ## _macro) {                                          \
1626       ret = FALSE;                                                      \
1627     } else {                                                            \
1628       g_value_set_ ## _type (dest, x);                                  \
1629     }                                                                   \
1630   }                                                                     \
1631   return ret;                                                           \
1632 }
1633
1634 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
1635 G_STMT_START {                                                          \
1636   static const GstValueTable gst_value = {                              \
1637     _gtype,                                                             \
1638     gst_value_compare_ ## _type,                                        \
1639     gst_value_serialize_ ## _type,                                      \
1640     gst_value_deserialize_ ## _type,                                    \
1641   };                                                                    \
1642                                                                         \
1643   gst_value_register (&gst_value);                                      \
1644 } G_STMT_END
1645
1646 CREATE_SERIALIZATION (int, INT);
1647 CREATE_SERIALIZATION (int64, INT64);
1648 CREATE_SERIALIZATION (long, LONG);
1649
1650 CREATE_USERIALIZATION (uint, UINT);
1651 CREATE_USERIALIZATION (uint64, UINT64);
1652 CREATE_USERIALIZATION (ulong, ULONG);
1653
1654 /**********
1655  * double *
1656  **********/
1657 static int
1658 gst_value_compare_double (const GValue * value1, const GValue * value2)
1659 {
1660   if (value1->data[0].v_double > value2->data[0].v_double)
1661     return GST_VALUE_GREATER_THAN;
1662   if (value1->data[0].v_double < value2->data[0].v_double)
1663     return GST_VALUE_LESS_THAN;
1664   if (value1->data[0].v_double == value2->data[0].v_double)
1665     return GST_VALUE_EQUAL;
1666   return GST_VALUE_UNORDERED;
1667 }
1668
1669 static char *
1670 gst_value_serialize_double (const GValue * value)
1671 {
1672   char d[G_ASCII_DTOSTR_BUF_SIZE];
1673
1674   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1675   return g_strdup (d);
1676 }
1677
1678 static gboolean
1679 gst_value_deserialize_double (GValue * dest, const gchar * s)
1680 {
1681   double x;
1682   gboolean ret = FALSE;
1683   char *end;
1684
1685   x = g_ascii_strtod (s, &end);
1686   if (*end == 0) {
1687     ret = TRUE;
1688   } else {
1689     if (g_ascii_strcasecmp (s, "min") == 0) {
1690       x = -G_MAXDOUBLE;
1691       ret = TRUE;
1692     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1693       x = G_MAXDOUBLE;
1694       ret = TRUE;
1695     }
1696   }
1697   if (ret) {
1698     g_value_set_double (dest, x);
1699   }
1700   return ret;
1701 }
1702
1703 /*********
1704  * float *
1705  *********/
1706
1707 static gint
1708 gst_value_compare_float (const GValue * value1, const GValue * value2)
1709 {
1710   if (value1->data[0].v_float > value2->data[0].v_float)
1711     return GST_VALUE_GREATER_THAN;
1712   if (value1->data[0].v_float < value2->data[0].v_float)
1713     return GST_VALUE_LESS_THAN;
1714   if (value1->data[0].v_float == value2->data[0].v_float)
1715     return GST_VALUE_EQUAL;
1716   return GST_VALUE_UNORDERED;
1717 }
1718
1719 static gchar *
1720 gst_value_serialize_float (const GValue * value)
1721 {
1722   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
1723
1724   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
1725   return g_strdup (d);
1726 }
1727
1728 static gboolean
1729 gst_value_deserialize_float (GValue * dest, const gchar * s)
1730 {
1731   double x;
1732   gboolean ret = FALSE;
1733   char *end;
1734
1735   x = g_ascii_strtod (s, &end);
1736   if (*end == 0) {
1737     ret = TRUE;
1738   } else {
1739     if (g_ascii_strcasecmp (s, "min") == 0) {
1740       x = -G_MAXFLOAT;
1741       ret = TRUE;
1742     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1743       x = G_MAXFLOAT;
1744       ret = TRUE;
1745     }
1746   }
1747   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
1748     ret = FALSE;
1749   if (ret) {
1750     g_value_set_float (dest, (float) x);
1751   }
1752   return ret;
1753 }
1754
1755 /**********
1756  * string *
1757  **********/
1758
1759 static gint
1760 gst_value_compare_string (const GValue * value1, const GValue * value2)
1761 {
1762   int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
1763
1764   if (x < 0)
1765     return GST_VALUE_LESS_THAN;
1766   if (x > 0)
1767     return GST_VALUE_GREATER_THAN;
1768   return GST_VALUE_EQUAL;
1769 }
1770
1771 /* keep in sync with gststructure.c */
1772 #define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
1773     ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
1774     ((c) == '.'))
1775
1776 static gchar *
1777 gst_string_wrap (const gchar * s)
1778 {
1779   const gchar *t;
1780   int len;
1781   gchar *d, *e;
1782   gboolean wrap = FALSE;
1783
1784   len = 0;
1785   t = s;
1786   if (!s)
1787     return NULL;
1788   while (*t) {
1789     if (GST_ASCII_IS_STRING (*t)) {
1790       len++;
1791     } else if (*t < 0x20 || *t >= 0x7f) {
1792       wrap = TRUE;
1793       len += 4;
1794     } else {
1795       wrap = TRUE;
1796       len += 2;
1797     }
1798     t++;
1799   }
1800
1801   if (!wrap)
1802     return g_strdup (s);
1803
1804   e = d = g_malloc (len + 3);
1805
1806   *e++ = '\"';
1807   t = s;
1808   while (*t) {
1809     if (GST_ASCII_IS_STRING (*t)) {
1810       *e++ = *t++;
1811     } else if (*t < 0x20 || *t >= 0x7f) {
1812       *e++ = '\\';
1813       *e++ = '0' + ((*(guchar *) t) >> 6);
1814       *e++ = '0' + (((*t) >> 3) & 0x7);
1815       *e++ = '0' + ((*t++) & 0x7);
1816     } else {
1817       *e++ = '\\';
1818       *e++ = *t++;
1819     }
1820   }
1821   *e++ = '\"';
1822   *e = 0;
1823
1824   return d;
1825 }
1826
1827 /*
1828  * This function takes a string delimited with double quotes (")
1829  * and unescapes any \xxx octal numbers.
1830  *
1831  * If sequences of \y are found where y is not in the range of
1832  * 0->3, y is copied unescaped.
1833  *
1834  * If \xyy is found where x is an octal number but y is not, an
1835  * error is encountered and NULL is returned.
1836  *
1837  * the input string must be \0 terminated.
1838  */
1839 static gchar *
1840 gst_string_unwrap (const gchar * s)
1841 {
1842   gchar *ret;
1843   gchar *read, *write;
1844
1845   /* NULL string returns NULL */
1846   if (s == NULL)
1847     return NULL;
1848
1849   /* strings not starting with " are invalid */
1850   if (*s != '"')
1851     return NULL;
1852
1853   /* make copy of original string to hold the result. This
1854    * string will always be smaller than the original */
1855   ret = g_strdup (s);
1856   read = ret;
1857   write = ret;
1858
1859   /* need to move to the next position as we parsed the " */
1860   read++;
1861
1862   while (*read) {
1863     if (GST_ASCII_IS_STRING (*read)) {
1864       /* normal chars are just copied */
1865       *write++ = *read++;
1866     } else if (*read == '"') {
1867       /* quote marks end of string */
1868       break;
1869     } else if (*read == '\\') {
1870       /* got an escape char, move to next position to read a tripplet
1871        * of octal numbers */
1872       read++;
1873       /* is the next char a possible first octal number? */
1874       if (*read >= '0' && *read <= '3') {
1875         /* parse other 2 numbers, if one of them is not in the range of
1876          * an octal number, we error. We also catch the case where a zero
1877          * byte is found here. */
1878         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
1879           goto beach;
1880
1881         /* now convert the octal number to a byte again. */
1882         *write++ = ((read[0] - '0') << 6) +
1883             ((read[1] - '0') << 3) + (read[2] - '0');
1884
1885         read += 3;
1886       } else {
1887         /* if we run into a \0 here, we definately won't get a quote later */
1888         if (*read == 0)
1889           goto beach;
1890
1891         /* else copy \X sequence */
1892         *write++ = *read++;
1893       }
1894     } else {
1895       /* weird character, error */
1896       goto beach;
1897     }
1898   }
1899   /* if the string is not ending in " and zero terminated, we error */
1900   if (*read != '"' || read[1] != '\0')
1901     goto beach;
1902
1903   /* null terminate result string and return */
1904   *write++ = '\0';
1905   return ret;
1906
1907 beach:
1908   g_free (ret);
1909   return NULL;
1910 }
1911
1912 static gchar *
1913 gst_value_serialize_string (const GValue * value)
1914 {
1915   return gst_string_wrap (value->data[0].v_pointer);
1916 }
1917
1918 static gboolean
1919 gst_value_deserialize_string (GValue * dest, const gchar * s)
1920 {
1921   if (*s != '"') {
1922     if (!g_utf8_validate (s, -1, NULL))
1923       return FALSE;
1924     g_value_set_string (dest, s);
1925     return TRUE;
1926   } else {
1927     gchar *str = gst_string_unwrap (s);
1928
1929     if (!str)
1930       return FALSE;
1931     g_value_take_string (dest, str);
1932   }
1933
1934   return TRUE;
1935 }
1936
1937 /********
1938  * enum *
1939  ********/
1940
1941 static gint
1942 gst_value_compare_enum (const GValue * value1, const GValue * value2)
1943 {
1944   GEnumValue *en1, *en2;
1945   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
1946   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
1947
1948   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
1949   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
1950   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
1951   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
1952   g_type_class_unref (klass1);
1953   g_type_class_unref (klass2);
1954   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
1955   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
1956   if (en1->value < en2->value)
1957     return GST_VALUE_LESS_THAN;
1958   if (en1->value > en2->value)
1959     return GST_VALUE_GREATER_THAN;
1960
1961   return GST_VALUE_EQUAL;
1962 }
1963
1964 static gchar *
1965 gst_value_serialize_enum (const GValue * value)
1966 {
1967   GEnumValue *en;
1968   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
1969
1970   g_return_val_if_fail (klass, NULL);
1971   en = g_enum_get_value (klass, g_value_get_enum (value));
1972   g_type_class_unref (klass);
1973
1974   /* might be one of the custom formats registered later */
1975   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
1976     const GstFormatDefinition *format_def;
1977
1978     format_def = gst_format_get_details (g_value_get_enum (value));
1979     g_return_val_if_fail (format_def != NULL, NULL);
1980     return g_strdup (format_def->description);
1981   }
1982
1983   g_return_val_if_fail (en, NULL);
1984   return g_strdup (en->value_name);
1985 }
1986
1987 static gint
1988 gst_value_deserialize_enum_iter_cmp (const GstFormatDefinition * format_def,
1989     const gchar * s)
1990 {
1991   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
1992     return 0;
1993
1994   return g_ascii_strcasecmp (s, format_def->description);
1995 }
1996
1997 static gboolean
1998 gst_value_deserialize_enum (GValue * dest, const gchar * s)
1999 {
2000   GEnumValue *en;
2001   gchar *endptr = NULL;
2002   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
2003
2004   g_return_val_if_fail (klass, FALSE);
2005   if (!(en = g_enum_get_value_by_name (klass, s))) {
2006     if (!(en = g_enum_get_value_by_nick (klass, s))) {
2007       gint i = strtol (s, &endptr, 0);
2008
2009       if (endptr && *endptr == '\0') {
2010         en = g_enum_get_value (klass, i);
2011       }
2012     }
2013   }
2014   g_type_class_unref (klass);
2015
2016   /* might be one of the custom formats registered later */
2017   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
2018     const GstFormatDefinition *format_def;
2019     GstIterator *iter;
2020
2021     iter = gst_format_iterate_definitions ();
2022
2023     format_def = gst_iterator_find_custom (iter,
2024         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, (gpointer) s);
2025
2026     g_return_val_if_fail (format_def != NULL, FALSE);
2027     g_value_set_enum (dest, (gint) format_def->value);
2028     gst_iterator_free (iter);
2029     return TRUE;
2030   }
2031
2032   g_return_val_if_fail (en, FALSE);
2033   g_value_set_enum (dest, en->value);
2034   return TRUE;
2035 }
2036
2037 /********
2038  * flags *
2039  ********/
2040
2041 /* we just compare the value here */
2042 static gint
2043 gst_value_compare_flags (const GValue * value1, const GValue * value2)
2044 {
2045   guint fl1, fl2;
2046   GFlagsClass *klass1 =
2047       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
2048   GFlagsClass *klass2 =
2049       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
2050
2051   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
2052   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
2053   fl1 = g_value_get_flags (value1);
2054   fl2 = g_value_get_flags (value2);
2055   g_type_class_unref (klass1);
2056   g_type_class_unref (klass2);
2057   if (fl1 < fl2)
2058     return GST_VALUE_LESS_THAN;
2059   if (fl1 > fl2)
2060     return GST_VALUE_GREATER_THAN;
2061
2062   return GST_VALUE_EQUAL;
2063 }
2064
2065 /* the different flags are serialized separated with a + */
2066 static gchar *
2067 gst_value_serialize_flags (const GValue * value)
2068 {
2069   guint flags;
2070   GFlagsValue *fl;
2071   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
2072   gchar *result, *tmp;
2073   gboolean first = TRUE;
2074
2075   g_return_val_if_fail (klass, NULL);
2076
2077   flags = g_value_get_flags (value);
2078
2079   /* if no flags are set, try to serialize to the _NONE string */
2080   if (!flags) {
2081     fl = g_flags_get_first_value (klass, flags);
2082     return g_strdup (fl->value_name);
2083   }
2084
2085   /* some flags are set, so serialize one by one */
2086   result = g_strdup ("");
2087   while (flags) {
2088     fl = g_flags_get_first_value (klass, flags);
2089     if (fl != NULL) {
2090       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
2091       g_free (result);
2092       result = tmp;
2093       first = FALSE;
2094
2095       /* clear flag */
2096       flags &= ~fl->value;
2097     }
2098   }
2099   g_type_class_unref (klass);
2100
2101   return result;
2102 }
2103
2104 static gboolean
2105 gst_value_deserialize_flags (GValue * dest, const gchar * s)
2106 {
2107   GFlagsValue *fl;
2108   gchar *endptr = NULL;
2109   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
2110   gchar **split;
2111   guint flags;
2112   gint i;
2113
2114   g_return_val_if_fail (klass, FALSE);
2115
2116   /* split into parts delimited with + */
2117   split = g_strsplit (s, "+", 0);
2118
2119   flags = 0;
2120   i = 0;
2121   /* loop over each part */
2122   while (split[i]) {
2123     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
2124       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
2125         gint val = strtol (split[i], &endptr, 0);
2126
2127         /* just or numeric value */
2128         if (endptr && *endptr == '\0') {
2129           flags |= val;
2130         }
2131       }
2132     }
2133     if (fl) {
2134       flags |= fl->value;
2135     }
2136     i++;
2137   }
2138   g_strfreev (split);
2139   g_type_class_unref (klass);
2140   g_value_set_flags (dest, flags);
2141
2142   return TRUE;
2143 }
2144
2145 /*********
2146  * union *
2147  *********/
2148
2149 static gboolean
2150 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
2151     const GValue * src2)
2152 {
2153   if (src2->data[0].v_int <= src1->data[0].v_int &&
2154       src2->data[1].v_int >= src1->data[0].v_int) {
2155     gst_value_init_and_copy (dest, src2);
2156     return TRUE;
2157   }
2158   return FALSE;
2159 }
2160
2161 static gboolean
2162 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
2163     const GValue * src2)
2164 {
2165   gint min;
2166   gint max;
2167
2168   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2169   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2170
2171   if (min <= max) {
2172     g_value_init (dest, GST_TYPE_INT_RANGE);
2173     gst_value_set_int_range (dest,
2174         MIN (src1->data[0].v_int, src2->data[0].v_int),
2175         MAX (src1->data[1].v_int, src2->data[1].v_int));
2176     return TRUE;
2177   }
2178
2179   return FALSE;
2180 }
2181
2182 /****************
2183  * intersection *
2184  ****************/
2185
2186 static gboolean
2187 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
2188     const GValue * src2)
2189 {
2190   if (src2->data[0].v_int <= src1->data[0].v_int &&
2191       src2->data[1].v_int >= src1->data[0].v_int) {
2192     gst_value_init_and_copy (dest, src1);
2193     return TRUE;
2194   }
2195
2196   return FALSE;
2197 }
2198
2199 static gboolean
2200 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
2201     const GValue * src2)
2202 {
2203   gint min;
2204   gint max;
2205
2206   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2207   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2208
2209   if (min < max) {
2210     g_value_init (dest, GST_TYPE_INT_RANGE);
2211     gst_value_set_int_range (dest, min, max);
2212     return TRUE;
2213   }
2214   if (min == max) {
2215     g_value_init (dest, G_TYPE_INT);
2216     g_value_set_int (dest, min);
2217     return TRUE;
2218   }
2219
2220   return FALSE;
2221 }
2222
2223 static gboolean
2224 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
2225     const GValue * src2)
2226 {
2227   if (src2->data[0].v_double <= src1->data[0].v_double &&
2228       src2->data[1].v_double >= src1->data[0].v_double) {
2229     gst_value_init_and_copy (dest, src1);
2230     return TRUE;
2231   }
2232
2233   return FALSE;
2234 }
2235
2236 static gboolean
2237 gst_value_intersect_double_range_double_range (GValue * dest,
2238     const GValue * src1, const GValue * src2)
2239 {
2240   gdouble min;
2241   gdouble max;
2242
2243   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
2244   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
2245
2246   if (min < max) {
2247     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
2248     gst_value_set_double_range (dest, min, max);
2249     return TRUE;
2250   }
2251   if (min == max) {
2252     g_value_init (dest, G_TYPE_DOUBLE);
2253     g_value_set_int (dest, (int) min);
2254     return TRUE;
2255   }
2256
2257   return FALSE;
2258 }
2259
2260 static gboolean
2261 gst_value_intersect_list (GValue * dest, const GValue * value1,
2262     const GValue * value2)
2263 {
2264   guint i, size;
2265   GValue intersection = { 0, };
2266   gboolean ret = FALSE;
2267
2268   size = gst_value_list_get_size (value1);
2269   for (i = 0; i < size; i++) {
2270     const GValue *cur = gst_value_list_get_value (value1, i);
2271
2272     if (gst_value_intersect (&intersection, cur, value2)) {
2273       /* append value */
2274       if (!ret) {
2275         gst_value_init_and_copy (dest, &intersection);
2276         ret = TRUE;
2277       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2278         gst_value_list_append_value (dest, &intersection);
2279       } else {
2280         GValue temp = { 0, };
2281
2282         gst_value_init_and_copy (&temp, dest);
2283         g_value_unset (dest);
2284         gst_value_list_concat (dest, &temp, &intersection);
2285         g_value_unset (&temp);
2286       }
2287       g_value_unset (&intersection);
2288     }
2289   }
2290
2291   return ret;
2292 }
2293
2294 static gboolean
2295 gst_value_intersect_array (GValue * dest, const GValue * src1,
2296     const GValue * src2)
2297 {
2298   guint size;
2299   guint n;
2300   GValue val = { 0 };
2301
2302   /* only works on similar-sized arrays */
2303   size = gst_value_array_get_size (src1);
2304   if (size != gst_value_array_get_size (src2))
2305     return FALSE;
2306   g_value_init (dest, GST_TYPE_ARRAY);
2307
2308   for (n = 0; n < size; n++) {
2309     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
2310             gst_value_array_get_value (src2, n))) {
2311       g_value_unset (dest);
2312       return FALSE;
2313     }
2314     gst_value_array_append_value (dest, &val);
2315     g_value_unset (&val);
2316   }
2317
2318   return TRUE;
2319 }
2320
2321 static gboolean
2322 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
2323     const GValue * src2)
2324 {
2325   int res1, res2;
2326   GValue *vals;
2327   GstValueCompareFunc compare;
2328
2329   vals = src2->data[0].v_pointer;
2330
2331   if (vals == NULL)
2332     return FALSE;
2333
2334   if ((compare = gst_value_get_compare_func (src1))) {
2335     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
2336     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
2337
2338     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
2339         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
2340       gst_value_init_and_copy (dest, src1);
2341       return TRUE;
2342     }
2343   }
2344
2345   return FALSE;
2346 }
2347
2348 static gboolean
2349     gst_value_intersect_fraction_range_fraction_range
2350     (GValue * dest, const GValue * src1, const GValue * src2)
2351 {
2352   GValue *min;
2353   GValue *max;
2354   int res;
2355   GValue *vals1, *vals2;
2356   GstValueCompareFunc compare;
2357
2358   vals1 = src1->data[0].v_pointer;
2359   vals2 = src2->data[0].v_pointer;
2360   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
2361
2362   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
2363     /* min = MAX (src1.start, src2.start) */
2364     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
2365     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2366     if (res == GST_VALUE_LESS_THAN)
2367       min = &vals2[0];          /* Take the max of the 2 */
2368     else
2369       min = &vals1[0];
2370
2371     /* max = MIN (src1.end, src2.end) */
2372     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
2373     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2374     if (res == GST_VALUE_GREATER_THAN)
2375       max = &vals2[1];          /* Take the min of the 2 */
2376     else
2377       max = &vals1[1];
2378
2379     res = gst_value_compare_with_func (min, max, compare);
2380     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2381     if (res == GST_VALUE_LESS_THAN) {
2382       g_value_init (dest, GST_TYPE_FRACTION_RANGE);
2383       vals1 = dest->data[0].v_pointer;
2384       g_value_copy (min, &vals1[0]);
2385       g_value_copy (max, &vals1[1]);
2386       return TRUE;
2387     }
2388     if (res == GST_VALUE_EQUAL) {
2389       gst_value_init_and_copy (dest, min);
2390       return TRUE;
2391     }
2392   }
2393
2394   return FALSE;
2395 }
2396
2397 /***************
2398  * subtraction *
2399  ***************/
2400
2401 static gboolean
2402 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
2403     const GValue * subtrahend)
2404 {
2405   int min = gst_value_get_int_range_min (subtrahend);
2406   int max = gst_value_get_int_range_max (subtrahend);
2407   int val = g_value_get_int (minuend);
2408
2409   /* subtracting a range from an int only works if the int is not in the
2410    * range */
2411   if (val < min || val > max) {
2412     /* and the result is the int */
2413     gst_value_init_and_copy (dest, minuend);
2414     return TRUE;
2415   }
2416   return FALSE;
2417 }
2418
2419 /* creates a new int range based on input values.
2420  */
2421 static gboolean
2422 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
2423     gint max2)
2424 {
2425   GValue v1 = { 0, };
2426   GValue v2 = { 0, };
2427   GValue *pv1, *pv2;            /* yeah, hungarian! */
2428
2429   if (min1 <= max1 && min2 <= max2) {
2430     pv1 = &v1;
2431     pv2 = &v2;
2432   } else if (min1 <= max1) {
2433     pv1 = dest;
2434     pv2 = NULL;
2435   } else if (min2 <= max2) {
2436     pv1 = NULL;
2437     pv2 = dest;
2438   } else {
2439     return FALSE;
2440   }
2441
2442   if (min1 < max1) {
2443     g_value_init (pv1, GST_TYPE_INT_RANGE);
2444     gst_value_set_int_range (pv1, min1, max1);
2445   } else if (min1 == max1) {
2446     g_value_init (pv1, G_TYPE_INT);
2447     g_value_set_int (pv1, min1);
2448   }
2449   if (min2 < max2) {
2450     g_value_init (pv2, GST_TYPE_INT_RANGE);
2451     gst_value_set_int_range (pv2, min2, max2);
2452   } else if (min2 == max2) {
2453     g_value_init (pv2, G_TYPE_INT);
2454     g_value_set_int (pv2, min2);
2455   }
2456
2457   if (min1 <= max1 && min2 <= max2) {
2458     gst_value_list_concat (dest, pv1, pv2);
2459     g_value_unset (pv1);
2460     g_value_unset (pv2);
2461   }
2462   return TRUE;
2463 }
2464
2465 static gboolean
2466 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
2467     const GValue * subtrahend)
2468 {
2469   gint min = gst_value_get_int_range_min (minuend);
2470   gint max = gst_value_get_int_range_max (minuend);
2471   gint val = g_value_get_int (subtrahend);
2472
2473   g_return_val_if_fail (min < max, FALSE);
2474
2475   /* value is outside of the range, return range unchanged */
2476   if (val < min || val > max) {
2477     gst_value_init_and_copy (dest, minuend);
2478     return TRUE;
2479   } else {
2480     /* max must be MAXINT too as val <= max */
2481     if (val == G_MAXINT) {
2482       max--;
2483       val--;
2484     }
2485     /* min must be MININT too as val >= max */
2486     if (val == G_MININT) {
2487       min++;
2488       val++;
2489     }
2490     gst_value_create_new_range (dest, min, val - 1, val + 1, max);
2491   }
2492   return TRUE;
2493 }
2494
2495 static gboolean
2496 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
2497     const GValue * subtrahend)
2498 {
2499   gint min1 = gst_value_get_int_range_min (minuend);
2500   gint max1 = gst_value_get_int_range_max (minuend);
2501   gint min2 = gst_value_get_int_range_min (subtrahend);
2502   gint max2 = gst_value_get_int_range_max (subtrahend);
2503
2504   if (max2 == G_MAXINT && min2 == G_MININT) {
2505     return FALSE;
2506   } else if (max2 == G_MAXINT) {
2507     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
2508   } else if (min2 == G_MININT) {
2509     return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
2510   } else {
2511     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
2512         MAX (max2 + 1, min1), max1);
2513   }
2514 }
2515
2516 static gboolean
2517 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
2518     const GValue * subtrahend)
2519 {
2520   gdouble min = gst_value_get_double_range_min (subtrahend);
2521   gdouble max = gst_value_get_double_range_max (subtrahend);
2522   gdouble val = g_value_get_double (minuend);
2523
2524   if (val < min || val > max) {
2525     gst_value_init_and_copy (dest, minuend);
2526     return TRUE;
2527   }
2528   return FALSE;
2529 }
2530
2531 static gboolean
2532 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
2533     const GValue * subtrahend)
2534 {
2535   /* since we don't have open ranges, we cannot create a hole in
2536    * a double range. We return the original range */
2537   gst_value_init_and_copy (dest, minuend);
2538   return TRUE;
2539 }
2540
2541 static gboolean
2542 gst_value_subtract_double_range_double_range (GValue * dest,
2543     const GValue * minuend, const GValue * subtrahend)
2544 {
2545   /* since we don't have open ranges, we have to approximate */
2546   /* done like with ints */
2547   gdouble min1 = gst_value_get_double_range_min (minuend);
2548   gdouble max2 = gst_value_get_double_range_max (minuend);
2549   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
2550   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
2551   GValue v1 = { 0, };
2552   GValue v2 = { 0, };
2553   GValue *pv1, *pv2;            /* yeah, hungarian! */
2554
2555   if (min1 < max1 && min2 < max2) {
2556     pv1 = &v1;
2557     pv2 = &v2;
2558   } else if (min1 < max1) {
2559     pv1 = dest;
2560     pv2 = NULL;
2561   } else if (min2 < max2) {
2562     pv1 = NULL;
2563     pv2 = dest;
2564   } else {
2565     return FALSE;
2566   }
2567
2568   if (min1 < max1) {
2569     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
2570     gst_value_set_double_range (pv1, min1, max1);
2571   }
2572   if (min2 < max2) {
2573     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
2574     gst_value_set_double_range (pv2, min2, max2);
2575   }
2576
2577   if (min1 < max1 && min2 < max2) {
2578     gst_value_list_concat (dest, pv1, pv2);
2579     g_value_unset (pv1);
2580     g_value_unset (pv2);
2581   }
2582   return TRUE;
2583 }
2584
2585 static gboolean
2586 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
2587     const GValue * subtrahend)
2588 {
2589   guint i, size;
2590   GValue subtraction = { 0, };
2591   gboolean ret = FALSE;
2592
2593   size = gst_value_list_get_size (minuend);
2594   for (i = 0; i < size; i++) {
2595     const GValue *cur = gst_value_list_get_value (minuend, i);
2596
2597     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
2598       if (!ret) {
2599         gst_value_init_and_copy (dest, &subtraction);
2600         ret = TRUE;
2601       } else if (GST_VALUE_HOLDS_LIST (dest)
2602           && GST_VALUE_HOLDS_LIST (&subtraction)) {
2603         /* unroll */
2604         GValue unroll = { 0, };
2605
2606         gst_value_init_and_copy (&unroll, dest);
2607         g_value_unset (dest);
2608         gst_value_list_concat (dest, &unroll, &subtraction);
2609       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2610         gst_value_list_append_value (dest, &subtraction);
2611       } else {
2612         GValue temp = { 0, };
2613
2614         gst_value_init_and_copy (&temp, dest);
2615         g_value_unset (dest);
2616         gst_value_list_concat (dest, &temp, &subtraction);
2617         g_value_unset (&temp);
2618       }
2619       g_value_unset (&subtraction);
2620     }
2621   }
2622   return ret;
2623 }
2624
2625 static gboolean
2626 gst_value_subtract_list (GValue * dest, const GValue * minuend,
2627     const GValue * subtrahend)
2628 {
2629   guint i, size;
2630   GValue data[2] = { {0,}, {0,} };
2631   GValue *subtraction = &data[0], *result = &data[1];
2632
2633   gst_value_init_and_copy (result, minuend);
2634   size = gst_value_list_get_size (subtrahend);
2635   for (i = 0; i < size; i++) {
2636     const GValue *cur = gst_value_list_get_value (subtrahend, i);
2637
2638     if (gst_value_subtract (subtraction, result, cur)) {
2639       GValue *temp = result;
2640
2641       result = subtraction;
2642       subtraction = temp;
2643       g_value_unset (subtraction);
2644     } else {
2645       g_value_unset (result);
2646       return FALSE;
2647     }
2648   }
2649   gst_value_init_and_copy (dest, result);
2650   g_value_unset (result);
2651   return TRUE;
2652 }
2653
2654 static gboolean
2655 gst_value_subtract_fraction_fraction_range (GValue * dest,
2656     const GValue * minuend, const GValue * subtrahend)
2657 {
2658   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
2659   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
2660   GstValueCompareFunc compare;
2661
2662   if ((compare = gst_value_get_compare_func (minuend))) {
2663     /* subtracting a range from an fraction only works if the fraction
2664      * is not in the range */
2665     if (gst_value_compare_with_func (minuend, min, compare) ==
2666         GST_VALUE_LESS_THAN ||
2667         gst_value_compare_with_func (minuend, max, compare) ==
2668         GST_VALUE_GREATER_THAN) {
2669       /* and the result is the value */
2670       gst_value_init_and_copy (dest, minuend);
2671       return TRUE;
2672     }
2673   }
2674   return FALSE;
2675 }
2676
2677 static gboolean
2678 gst_value_subtract_fraction_range_fraction (GValue * dest,
2679     const GValue * minuend, const GValue * subtrahend)
2680 {
2681   /* since we don't have open ranges, we cannot create a hole in
2682    * a range. We return the original range */
2683   gst_value_init_and_copy (dest, minuend);
2684   return TRUE;
2685 }
2686
2687 static gboolean
2688 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
2689     const GValue * minuend, const GValue * subtrahend)
2690 {
2691   /* since we don't have open ranges, we have to approximate */
2692   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
2693   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
2694   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
2695   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
2696   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
2697   int cmp1, cmp2;
2698   GValue v1 = { 0, };
2699   GValue v2 = { 0, };
2700   GValue *pv1, *pv2;            /* yeah, hungarian! */
2701   GstValueCompareFunc compare;
2702
2703   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
2704   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
2705
2706   compare = gst_value_get_compare_func (min1);
2707   g_return_val_if_fail (compare, FALSE);
2708
2709   cmp1 = gst_value_compare_with_func (max2, max1, compare);
2710   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2711   if (cmp1 == GST_VALUE_LESS_THAN)
2712     max1 = max2;
2713   cmp1 = gst_value_compare_with_func (min1, min2, compare);
2714   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2715   if (cmp1 == GST_VALUE_GREATER_THAN)
2716     min2 = min1;
2717
2718   cmp1 = gst_value_compare_with_func (min1, max1, compare);
2719   cmp2 = gst_value_compare_with_func (min2, max2, compare);
2720
2721   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2722     pv1 = &v1;
2723     pv2 = &v2;
2724   } else if (cmp1 == GST_VALUE_LESS_THAN) {
2725     pv1 = dest;
2726     pv2 = NULL;
2727   } else if (cmp2 == GST_VALUE_LESS_THAN) {
2728     pv1 = NULL;
2729     pv2 = dest;
2730   } else {
2731     return FALSE;
2732   }
2733
2734   if (cmp1 == GST_VALUE_LESS_THAN) {
2735     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
2736     gst_value_set_fraction_range (pv1, min1, max1);
2737   }
2738   if (cmp2 == GST_VALUE_LESS_THAN) {
2739     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
2740     gst_value_set_fraction_range (pv2, min2, max2);
2741   }
2742
2743   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2744     gst_value_list_concat (dest, pv1, pv2);
2745     g_value_unset (pv1);
2746     g_value_unset (pv2);
2747   }
2748   return TRUE;
2749 }
2750
2751
2752 /**************
2753  * comparison *
2754  **************/
2755
2756 /**
2757  * gst_value_can_compare:
2758  * @value1: a value to compare
2759  * @value2: another value to compare
2760  *
2761  * Determines if @value1 and @value2 can be compared.
2762  *
2763  * Returns: TRUE if the values can be compared
2764  */
2765 gboolean
2766 gst_value_can_compare (const GValue * value1, const GValue * value2)
2767 {
2768   GstValueTable *table;
2769   guint i;
2770
2771   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2772     return FALSE;
2773
2774   for (i = 0; i < gst_value_table->len; i++) {
2775     table = &g_array_index (gst_value_table, GstValueTable, i);
2776     if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
2777       return TRUE;
2778   }
2779
2780   return FALSE;
2781 }
2782
2783 /*
2784  * gst_value_get_compare_func:
2785  * @value1: a value to get the compare function for
2786  *
2787  * Determines the compare function to be used with values of the same type as
2788  * @value1. The function can be given to gst_value_compare_with_func().
2789  *
2790  * Returns: A #GstValueCompareFunc value
2791  */
2792 static GstValueCompareFunc
2793 gst_value_get_compare_func (const GValue * value1)
2794 {
2795   GstValueTable *table, *best = NULL;
2796   guint i;
2797
2798   for (i = 0; i < gst_value_table->len; i++) {
2799     table = &g_array_index (gst_value_table, GstValueTable, i);
2800     if (table->type == G_VALUE_TYPE (value1) && table->compare != NULL) {
2801       best = table;
2802       break;
2803     }
2804     if (g_type_is_a (G_VALUE_TYPE (value1), table->type)) {
2805       if (!best || g_type_is_a (table->type, best->type))
2806         best = table;
2807     }
2808   }
2809   if (best) {
2810     return best->compare;
2811   }
2812   return NULL;
2813 }
2814
2815 /**
2816  * gst_value_compare:
2817  * @value1: a value to compare
2818  * @value2: another value to compare
2819  *
2820  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
2821  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
2822  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
2823  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
2824  * If the values are equal, GST_VALUE_EQUAL is returned.
2825  *
2826  * Returns: A #GstValueCompareType value
2827  */
2828 gint
2829 gst_value_compare (const GValue * value1, const GValue * value2)
2830 {
2831   GstValueCompareFunc compare;
2832
2833   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2834     return GST_VALUE_UNORDERED;
2835
2836   compare = gst_value_get_compare_func (value1);
2837   if (compare) {
2838     return compare (value1, value2);
2839   }
2840
2841   g_critical ("unable to compare values of type %s\n",
2842       g_type_name (G_VALUE_TYPE (value1)));
2843   return GST_VALUE_UNORDERED;
2844 }
2845
2846 /*
2847  * gst_value_compare_with_func:
2848  * @value1: a value to compare
2849  * @value2: another value to compare
2850  * @compare: compare function
2851  *
2852  * Compares @value1 and @value2 using the @compare function. Works like
2853  * gst_value_compare() but allows to save time determining the compare function
2854  * a multiple times. 
2855  *
2856  * Returns: A #GstValueCompareType value
2857  */
2858 static gint
2859 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
2860     GstValueCompareFunc compare)
2861 {
2862   g_assert (compare);
2863
2864   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2865     return GST_VALUE_UNORDERED;
2866
2867   return compare (value1, value2);
2868 }
2869
2870 /* union */
2871
2872 /**
2873  * gst_value_can_union:
2874  * @value1: a value to union
2875  * @value2: another value to union
2876  *
2877  * Determines if @value1 and @value2 can be non-trivially unioned.
2878  * Any two values can be trivially unioned by adding both of them
2879  * to a GstValueList.  However, certain types have the possibility
2880  * to be unioned in a simpler way.  For example, an integer range
2881  * and an integer can be unioned if the integer is a subset of the
2882  * integer range.  If there is the possibility that two values can
2883  * be unioned, this function returns TRUE.
2884  *
2885  * Returns: TRUE if there is a function allowing the two values to
2886  * be unioned.
2887  */
2888 gboolean
2889 gst_value_can_union (const GValue * value1, const GValue * value2)
2890 {
2891   GstValueUnionInfo *union_info;
2892   guint i;
2893
2894   for (i = 0; i < gst_value_union_funcs->len; i++) {
2895     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2896     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2897         union_info->type2 == G_VALUE_TYPE (value2))
2898       return TRUE;
2899     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2900         union_info->type2 == G_VALUE_TYPE (value1))
2901       return TRUE;
2902   }
2903
2904   return FALSE;
2905 }
2906
2907 /**
2908  * gst_value_union:
2909  * @dest: the destination value
2910  * @value1: a value to union
2911  * @value2: another value to union
2912  *
2913  * Creates a GValue cooresponding to the union of @value1 and @value2.
2914  *
2915  * Returns: always returns %TRUE
2916  */
2917 /* FIXME: change return type to 'void'? */
2918 gboolean
2919 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
2920 {
2921   GstValueUnionInfo *union_info;
2922   guint i;
2923
2924   for (i = 0; i < gst_value_union_funcs->len; i++) {
2925     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2926     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2927         union_info->type2 == G_VALUE_TYPE (value2)) {
2928       if (union_info->func (dest, value1, value2)) {
2929         return TRUE;
2930       }
2931     }
2932     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2933         union_info->type2 == G_VALUE_TYPE (value1)) {
2934       if (union_info->func (dest, value2, value1)) {
2935         return TRUE;
2936       }
2937     }
2938   }
2939
2940   gst_value_list_concat (dest, value1, value2);
2941   return TRUE;
2942 }
2943
2944 /**
2945  * gst_value_register_union_func:
2946  * @type1: a type to union
2947  * @type2: another type to union
2948  * @func: a function that implments creating a union between the two types
2949  *
2950  * Registers a union function that can create a union between GValues
2951  * of the type @type1 and @type2.
2952  *
2953  * Union functions should be registered at startup before any pipelines are
2954  * started, as gst_value_register_union_func() is not thread-safe and cannot
2955  * be used at the same time as gst_value_union() or gst_value_can_union().
2956  */
2957 void
2958 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
2959 {
2960   GstValueUnionInfo union_info;
2961
2962   union_info.type1 = type1;
2963   union_info.type2 = type2;
2964   union_info.func = func;
2965
2966   g_array_append_val (gst_value_union_funcs, union_info);
2967 }
2968
2969 /* intersection */
2970
2971 /**
2972  * gst_value_can_intersect:
2973  * @value1: a value to intersect
2974  * @value2: another value to intersect
2975  *
2976  * Determines if intersecting two values will produce a valid result.
2977  * Two values will produce a valid intersection if they have the same
2978  * type, or if there is a method (registered by
2979  * gst_value_register_intersection_func()) to calculate the intersection.
2980  *
2981  * Returns: TRUE if the values can intersect
2982  */
2983 gboolean
2984 gst_value_can_intersect (const GValue * value1, const GValue * value2)
2985 {
2986   GstValueIntersectInfo *intersect_info;
2987   guint i;
2988
2989   /* special cases */
2990   if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
2991     return TRUE;
2992
2993   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2994     intersect_info = &g_array_index (gst_value_intersect_funcs,
2995         GstValueIntersectInfo, i);
2996     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2997         intersect_info->type2 == G_VALUE_TYPE (value2))
2998       if (intersect_info->type2 == G_VALUE_TYPE (value1) &&
2999           intersect_info->type1 == G_VALUE_TYPE (value2))
3000         return TRUE;
3001   }
3002
3003   return gst_value_can_compare (value1, value2);
3004 }
3005
3006 /**
3007  * gst_value_intersect:
3008  * @dest: a uninitialized #GValue that will hold the calculated
3009  * intersection value
3010  * @value1: a value to intersect
3011  * @value2: another value to intersect
3012  *
3013  * Calculates the intersection of two values.  If the values have
3014  * a non-empty intersection, the value representing the intersection
3015  * is placed in @dest.  If the intersection is non-empty, @dest is
3016  * not modified.
3017  *
3018  * Returns: TRUE if the intersection is non-empty
3019  */
3020 gboolean
3021 gst_value_intersect (GValue * dest, const GValue * value1,
3022     const GValue * value2)
3023 {
3024   GstValueIntersectInfo *intersect_info;
3025   guint i;
3026   gboolean ret = FALSE;
3027
3028   /* special cases first */
3029   if (GST_VALUE_HOLDS_LIST (value1))
3030     return gst_value_intersect_list (dest, value1, value2);
3031   if (GST_VALUE_HOLDS_LIST (value2))
3032     return gst_value_intersect_list (dest, value2, value1);
3033
3034   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
3035     intersect_info = &g_array_index (gst_value_intersect_funcs,
3036         GstValueIntersectInfo, i);
3037     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
3038         intersect_info->type2 == G_VALUE_TYPE (value2)) {
3039       ret = intersect_info->func (dest, value1, value2);
3040       return ret;
3041     }
3042     if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
3043         intersect_info->type2 == G_VALUE_TYPE (value1)) {
3044       ret = intersect_info->func (dest, value2, value1);
3045       return ret;
3046     }
3047   }
3048
3049   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
3050     gst_value_init_and_copy (dest, value1);
3051     ret = TRUE;
3052   }
3053
3054   return ret;
3055 }
3056
3057 /**
3058  * gst_value_register_intersect_func:
3059  * @type1: the first type to intersect
3060  * @type2: the second type to intersect
3061  * @func: the intersection function
3062  *
3063  * Registers a function that is called to calculate the intersection
3064  * of the values having the types @type1 and @type2.
3065  *
3066  * Intersect functions should be registered at startup before any pipelines are
3067  * started, as gst_value_register_intersect_func() is not thread-safe and
3068  * cannot be used at the same time as gst_value_intersect() or
3069  * gst_value_can_intersect().
3070  */
3071 void
3072 gst_value_register_intersect_func (GType type1, GType type2,
3073     GstValueIntersectFunc func)
3074 {
3075   GstValueIntersectInfo intersect_info;
3076
3077   intersect_info.type1 = type1;
3078   intersect_info.type2 = type2;
3079   intersect_info.func = func;
3080
3081   g_array_append_val (gst_value_intersect_funcs, intersect_info);
3082 }
3083
3084
3085 /* subtraction */
3086
3087 /**
3088  * gst_value_subtract:
3089  * @dest: the destination value for the result if the subtraction is not empty
3090  * @minuend: the value to subtract from
3091  * @subtrahend: the value to subtract
3092  *
3093  * Subtracts @subtrahend from @minuend and stores the result in @dest.
3094  * Note that this means subtraction as in sets, not as in mathematics.
3095  *
3096  * Returns: %TRUE if the subtraction is not empty
3097  */
3098 gboolean
3099 gst_value_subtract (GValue * dest, const GValue * minuend,
3100     const GValue * subtrahend)
3101 {
3102   GstValueSubtractInfo *info;
3103   guint i;
3104
3105   /* special cases first */
3106   if (GST_VALUE_HOLDS_LIST (minuend))
3107     return gst_value_subtract_from_list (dest, minuend, subtrahend);
3108   if (GST_VALUE_HOLDS_LIST (subtrahend))
3109     return gst_value_subtract_list (dest, minuend, subtrahend);
3110
3111   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
3112     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
3113     if (info->minuend == G_VALUE_TYPE (minuend) &&
3114         info->subtrahend == G_VALUE_TYPE (subtrahend)) {
3115       return info->func (dest, minuend, subtrahend);
3116     }
3117   }
3118
3119   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
3120     gst_value_init_and_copy (dest, minuend);
3121     return TRUE;
3122   }
3123
3124   return FALSE;
3125 }
3126
3127 #if 0
3128 gboolean
3129 gst_value_subtract (GValue * dest, const GValue * minuend,
3130     const GValue * subtrahend)
3131 {
3132   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
3133
3134   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
3135       gst_value_serialize (subtrahend),
3136       ret ? gst_value_serialize (dest) : "---");
3137   return ret;
3138 }
3139 #endif
3140
3141 /**
3142  * gst_value_can_subtract:
3143  * @minuend: the value to subtract from
3144  * @subtrahend: the value to subtract
3145  *
3146  * Checks if it's possible to subtract @subtrahend from @minuend.
3147  *
3148  * Returns: TRUE if a subtraction is possible
3149  */
3150 gboolean
3151 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
3152 {
3153   GstValueSubtractInfo *info;
3154   guint i;
3155
3156   /* special cases */
3157   if (GST_VALUE_HOLDS_LIST (minuend) || GST_VALUE_HOLDS_LIST (subtrahend))
3158     return TRUE;
3159
3160   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
3161     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
3162     if (info->minuend == G_VALUE_TYPE (minuend) &&
3163         info->subtrahend == G_VALUE_TYPE (subtrahend))
3164       return TRUE;
3165   }
3166
3167   return gst_value_can_compare (minuend, subtrahend);
3168 }
3169
3170 /**
3171  * gst_value_register_subtract_func:
3172  * @minuend_type: type of the minuend
3173  * @subtrahend_type: type of the subtrahend
3174  * @func: function to use
3175  *
3176  * Registers @func as a function capable of subtracting the values of
3177  * @subtrahend_type from values of @minuend_type.
3178  *
3179  * Subtract functions should be registered at startup before any pipelines are
3180  * started, as gst_value_register_subtract_func() is not thread-safe and
3181  * cannot be used at the same time as gst_value_subtract().
3182  */
3183 void
3184 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
3185     GstValueSubtractFunc func)
3186 {
3187   GstValueSubtractInfo info;
3188
3189   /* one type must be unfixed, other subtractions can be done as comparisons */
3190   g_return_if_fail (!gst_type_is_fixed (minuend_type)
3191       || !gst_type_is_fixed (subtrahend_type));
3192
3193   info.minuend = minuend_type;
3194   info.subtrahend = subtrahend_type;
3195   info.func = func;
3196
3197   g_array_append_val (gst_value_subtract_funcs, info);
3198 }
3199
3200 /**
3201  * gst_value_register:
3202  * @table: structure containing functions to register
3203  *
3204  * Registers functions to perform calculations on #GValues of a given
3205  * type.
3206  */
3207 void
3208 gst_value_register (const GstValueTable * table)
3209 {
3210   g_array_append_val (gst_value_table, *table);
3211 }
3212
3213 /**
3214  * gst_value_init_and_copy:
3215  * @dest: the target value
3216  * @src: the source value
3217  *
3218  * Initialises the target value to be of the same type as source and then copies
3219  * the contents from source to target.
3220  */
3221 void
3222 gst_value_init_and_copy (GValue * dest, const GValue * src)
3223 {
3224   g_value_init (dest, G_VALUE_TYPE (src));
3225   g_value_copy (src, dest);
3226 }
3227
3228 /**
3229  * gst_value_serialize:
3230  * @value: a #GValue to serialize
3231  *
3232  * tries to transform the given @value into a string representation that allows
3233  * getting back this string later on using gst_value_deserialize().
3234  *
3235  * Returns: the serialization for @value or NULL if none exists
3236  */
3237 gchar *
3238 gst_value_serialize (const GValue * value)
3239 {
3240   guint i;
3241   GValue s_val = { 0 };
3242   GstValueTable *table, *best = NULL;
3243   char *s;
3244
3245   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3246
3247   for (i = 0; i < gst_value_table->len; i++) {
3248     table = &g_array_index (gst_value_table, GstValueTable, i);
3249     if (table->serialize == NULL)
3250       continue;
3251     if (table->type == G_VALUE_TYPE (value)) {
3252       best = table;
3253       break;
3254     }
3255     if (g_type_is_a (G_VALUE_TYPE (value), table->type)) {
3256       if (!best || g_type_is_a (table->type, best->type))
3257         best = table;
3258     }
3259   }
3260   if (best)
3261     return best->serialize (value);
3262
3263   g_value_init (&s_val, G_TYPE_STRING);
3264   if (g_value_transform (value, &s_val)) {
3265     s = gst_string_wrap (g_value_get_string (&s_val));
3266   } else {
3267     s = NULL;
3268   }
3269   g_value_unset (&s_val);
3270
3271   return s;
3272 }
3273
3274 /**
3275  * gst_value_deserialize:
3276  * @dest: #GValue to fill with contents of deserialization
3277  * @src: string to deserialize
3278  *
3279  * Tries to deserialize a string into the type specified by the given GValue.
3280  * If the operation succeeds, TRUE is returned, FALSE otherwise.
3281  *
3282  * Returns: TRUE on success
3283  */
3284 gboolean
3285 gst_value_deserialize (GValue * dest, const gchar * src)
3286 {
3287   GstValueTable *table, *best = NULL;
3288   guint i;
3289
3290   g_return_val_if_fail (src != NULL, FALSE);
3291   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
3292
3293   for (i = 0; i < gst_value_table->len; i++) {
3294     table = &g_array_index (gst_value_table, GstValueTable, i);
3295     if (table->serialize == NULL)
3296       continue;
3297
3298     if (table->type == G_VALUE_TYPE (dest)) {
3299       best = table;
3300       break;
3301     }
3302
3303     if (g_type_is_a (G_VALUE_TYPE (dest), table->type)) {
3304       if (!best || g_type_is_a (table->type, best->type))
3305         best = table;
3306     }
3307   }
3308   if (best) {
3309     return best->deserialize (dest, src);
3310   }
3311
3312   return FALSE;
3313 }
3314
3315 /**
3316  * gst_value_is_fixed:
3317  * @value: the #GValue to check
3318  *
3319  * Tests if the given GValue, if available in a GstStructure (or any other
3320  * container) contains a "fixed" (which means: one value) or an "unfixed"
3321  * (which means: multiple possible values, such as data lists or data
3322  * ranges) value.
3323  *
3324  * Returns: true if the value is "fixed".
3325  */
3326
3327 gboolean
3328 gst_value_is_fixed (const GValue * value)
3329 {
3330   GType type = G_VALUE_TYPE (value);
3331
3332   if (type == GST_TYPE_ARRAY) {
3333     gint size, n;
3334     const GValue *kid;
3335
3336     /* check recursively */
3337     size = gst_value_array_get_size (value);
3338     for (n = 0; n < size; n++) {
3339       kid = gst_value_array_get_value (value, n);
3340       if (!gst_value_is_fixed (kid))
3341         return FALSE;
3342     }
3343     return TRUE;
3344   }
3345
3346   return gst_type_is_fixed (type);
3347 }
3348
3349 /************
3350  * fraction *
3351  ************/
3352
3353 /* helper functions */
3354
3355 /* Finds the greatest common divisor.
3356  * Returns 1 if none other found.
3357  * This is Euclid's algorithm. */
3358 static gint
3359 gst_greatest_common_divisor (gint a, gint b)
3360 {
3361   while (b != 0) {
3362     int temp = a;
3363
3364     a = b;
3365     b = temp % b;
3366   }
3367
3368   return ABS (a);
3369 }
3370
3371 static void
3372 gst_value_init_fraction (GValue * value)
3373 {
3374   value->data[0].v_int = 0;
3375   value->data[1].v_int = 1;
3376 }
3377
3378 static void
3379 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
3380 {
3381   dest_value->data[0].v_int = src_value->data[0].v_int;
3382   dest_value->data[1].v_int = src_value->data[1].v_int;
3383 }
3384
3385 static gchar *
3386 gst_value_collect_fraction (GValue * value, guint n_collect_values,
3387     GTypeCValue * collect_values, guint collect_flags)
3388 {
3389   gst_value_set_fraction (value,
3390       collect_values[0].v_int, collect_values[1].v_int);
3391
3392   return NULL;
3393 }
3394
3395 static gchar *
3396 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
3397     GTypeCValue * collect_values, guint collect_flags)
3398 {
3399   gint *numerator = collect_values[0].v_pointer;
3400   gint *denominator = collect_values[1].v_pointer;
3401
3402   if (!numerator)
3403     return g_strdup_printf ("numerator for `%s' passed as NULL",
3404         G_VALUE_TYPE_NAME (value));
3405   if (!denominator)
3406     return g_strdup_printf ("denominator for `%s' passed as NULL",
3407         G_VALUE_TYPE_NAME (value));
3408
3409   *numerator = value->data[0].v_int;
3410   *denominator = value->data[1].v_int;
3411
3412   return NULL;
3413 }
3414
3415 /**
3416  * gst_value_set_fraction:
3417  * @value: a GValue initialized to #GST_TYPE_FRACTION
3418  * @numerator: the numerator of the fraction
3419  * @denominator: the denominator of the fraction
3420  *
3421  * Sets @value to the fraction specified by @numerator over @denominator.
3422  * The fraction gets reduced to the smallest numerator and denominator,
3423  * and if necessary the sign is moved to the numerator.
3424  */
3425 void
3426 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
3427 {
3428   gint gcd = 0;
3429
3430   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
3431   g_return_if_fail (denominator != 0);
3432   g_return_if_fail (denominator >= -G_MAXINT);
3433   g_return_if_fail (numerator >= -G_MAXINT);
3434
3435   /* normalize sign */
3436   if (denominator < 0) {
3437     numerator = -numerator;
3438     denominator = -denominator;
3439   }
3440
3441   /* check for reduction */
3442   gcd = gst_greatest_common_divisor (numerator, denominator);
3443   if (gcd) {
3444     numerator /= gcd;
3445     denominator /= gcd;
3446   }
3447
3448   g_assert (denominator > 0);
3449
3450   value->data[0].v_int = numerator;
3451   value->data[1].v_int = denominator;
3452 }
3453
3454 /**
3455  * gst_value_get_fraction_numerator:
3456  * @value: a GValue initialized to #GST_TYPE_FRACTION
3457  *
3458  * Gets the numerator of the fraction specified by @value.
3459  *
3460  * Returns: the numerator of the fraction.
3461  */
3462 gint
3463 gst_value_get_fraction_numerator (const GValue * value)
3464 {
3465   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
3466
3467   return value->data[0].v_int;
3468 }
3469
3470 /**
3471  * gst_value_get_fraction_denominator:
3472  * @value: a GValue initialized to #GST_TYPE_FRACTION
3473  *
3474  * Gets the denominator of the fraction specified by @value.
3475  *
3476  * Returns: the denominator of the fraction.
3477  */
3478 gint
3479 gst_value_get_fraction_denominator (const GValue * value)
3480 {
3481   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
3482
3483   return value->data[1].v_int;
3484 }
3485
3486 /**
3487  * gst_value_fraction_multiply:
3488  * @product: a GValue initialized to #GST_TYPE_FRACTION
3489  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
3490  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
3491  *
3492  * Multiplies the two GValues containing a GstFraction and sets @product
3493  * to the product of the two fractions.
3494  *
3495  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3496  */
3497 gboolean
3498 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
3499     const GValue * factor2)
3500 {
3501   gint gcd, n1, n2, d1, d2;
3502
3503   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
3504   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
3505
3506   n1 = factor1->data[0].v_int;
3507   n2 = factor2->data[0].v_int;
3508   d1 = factor1->data[1].v_int;
3509   d2 = factor2->data[1].v_int;
3510
3511   gcd = gst_greatest_common_divisor (n1, d2);
3512   n1 /= gcd;
3513   d2 /= gcd;
3514   gcd = gst_greatest_common_divisor (n2, d1);
3515   n2 /= gcd;
3516   d1 /= gcd;
3517
3518   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (n2), FALSE);
3519   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3520
3521   gst_value_set_fraction (product, n1 * n2, d1 * d2);
3522
3523   return TRUE;
3524 }
3525
3526 /**
3527  * gst_value_fraction_subtract:
3528  * @dest: a GValue initialized to #GST_TYPE_FRACTION
3529  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
3530  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
3531  *
3532  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
3533  *
3534  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3535  */
3536 gboolean
3537 gst_value_fraction_subtract (GValue * dest,
3538     const GValue * minuend, const GValue * subtrahend)
3539 {
3540   gint n1, n2, d1, d2;
3541
3542   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
3543   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
3544
3545   n1 = minuend->data[0].v_int;
3546   n2 = subtrahend->data[0].v_int;
3547   d1 = minuend->data[1].v_int;
3548   d2 = subtrahend->data[1].v_int;
3549
3550   if (n1 == 0) {
3551     gst_value_set_fraction (dest, -n2, d2);
3552     return TRUE;
3553   }
3554   if (n2 == 0) {
3555     gst_value_set_fraction (dest, n1, d1);
3556     return TRUE;
3557   }
3558
3559   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (d2), FALSE);
3560   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (n2), FALSE);
3561   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3562
3563   gst_value_set_fraction (dest, (n1 * d2) - (n2 * d1), d1 * d2);
3564
3565   return TRUE;
3566 }
3567
3568 static gchar *
3569 gst_value_serialize_fraction (const GValue * value)
3570 {
3571   gint32 numerator = value->data[0].v_int;
3572   gint32 denominator = value->data[1].v_int;
3573   gboolean positive = TRUE;
3574
3575   /* get the sign and make components absolute */
3576   if (numerator < 0) {
3577     numerator = -numerator;
3578     positive = !positive;
3579   }
3580   if (denominator < 0) {
3581     denominator = -denominator;
3582     positive = !positive;
3583   }
3584
3585   return g_strdup_printf ("%s%d/%d",
3586       positive ? "" : "-", numerator, denominator);
3587 }
3588
3589 static gboolean
3590 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
3591 {
3592   gint num, den;
3593
3594   if (G_UNLIKELY (s == NULL))
3595     return FALSE;
3596
3597   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
3598     return FALSE;
3599
3600   if (sscanf (s, "%d/%d", &num, &den) == 2) {
3601     gst_value_set_fraction (dest, num, den);
3602     return TRUE;
3603   }
3604   if (sscanf (s, "%d", &num) == 1) {
3605     gst_value_set_fraction (dest, num, 1);
3606     return TRUE;
3607   }
3608   if (g_ascii_strcasecmp (s, "min") == 0) {
3609     gst_value_set_fraction (dest, -G_MAXINT, 1);
3610     return TRUE;
3611   } else if (g_ascii_strcasecmp (s, "max") == 0) {
3612     gst_value_set_fraction (dest, G_MAXINT, 1);
3613     return TRUE;
3614   }
3615
3616   return FALSE;
3617 }
3618
3619 static void
3620 gst_value_transform_fraction_string (const GValue * src_value,
3621     GValue * dest_value)
3622 {
3623   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
3624 }
3625
3626 static void
3627 gst_value_transform_string_fraction (const GValue * src_value,
3628     GValue * dest_value)
3629 {
3630   if (!gst_value_deserialize_fraction (dest_value,
3631           src_value->data[0].v_pointer))
3632     /* If the deserialize fails, ensure we leave the fraction in a
3633      * valid, if incorrect, state */
3634     gst_value_set_fraction (dest_value, 0, 1);
3635 }
3636
3637 #define MAX_TERMS       30
3638 #define MIN_DIVISOR     1.0e-10
3639 #define MAX_ERROR       1.0e-20
3640
3641 /* use continued fractions to transform a double into a fraction,
3642  * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
3643  * This algorithm takes care of overflows.
3644  */
3645 static void
3646 gst_value_transform_double_fraction (const GValue * src_value,
3647     GValue * dest_value)
3648 {
3649   gdouble V, F;                 /* double being converted */
3650   gint N, D;                    /* will contain the result */
3651   gint A;                       /* current term in continued fraction */
3652   gint64 N1, D1;                /* numerator, denominator of last approx */
3653   gint64 N2, D2;                /* numerator, denominator of previous approx */
3654   gint i;
3655   gboolean negative = FALSE;
3656
3657   /* initialize fraction being converted */
3658   F = src_value->data[0].v_double;
3659   if (F < 0.0) {
3660     F = -F;
3661     negative = TRUE;
3662   }
3663
3664   V = F;
3665   /* initialize fractions with 1/0, 0/1 */
3666   N1 = 1;
3667   D1 = 0;
3668   N2 = 0;
3669   D2 = 1;
3670   N = 1;
3671   D = 1;
3672
3673   for (i = 0; i < MAX_TERMS; i++) {
3674     /* get next term */
3675     A = (gint) F;               /* no floor() needed, F is always >= 0 */
3676     /* get new divisor */
3677     F = F - A;
3678
3679     /* calculate new fraction in temp */
3680     N2 = N1 * A + N2;
3681     D2 = D1 * A + D2;
3682
3683     /* guard against overflow */
3684     if (N2 > G_MAXINT || D2 > G_MAXINT) {
3685       break;
3686     }
3687
3688     N = N2;
3689     D = D2;
3690
3691     /* save last two fractions */
3692     N2 = N1;
3693     D2 = D1;
3694     N1 = N;
3695     D1 = D;
3696
3697     /* quit if dividing by zero or close enough to target */
3698     if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
3699       break;
3700     }
3701
3702     /* Take reciprocal */
3703     F = 1 / F;
3704   }
3705   /* fix for overflow */
3706   if (D == 0) {
3707     N = G_MAXINT;
3708     D = 1;
3709   }
3710   /* fix for negative */
3711   if (negative)
3712     N = -N;
3713
3714   /* will also simplify */
3715   gst_value_set_fraction (dest_value, N, D);
3716 }
3717
3718 static void
3719 gst_value_transform_fraction_double (const GValue * src_value,
3720     GValue * dest_value)
3721 {
3722   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
3723       ((double) src_value->data[1].v_int);
3724 }
3725
3726 static gint
3727 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
3728 {
3729   gint n1, n2;
3730   gint d1, d2;
3731
3732   gint64 new_num_1;
3733   gint64 new_num_2;
3734
3735   n1 = value1->data[0].v_int;
3736   n2 = value2->data[0].v_int;
3737   d1 = value1->data[1].v_int;
3738   d2 = value2->data[1].v_int;
3739
3740   /* fractions are reduced when set, so we can quickly see if they're equal */
3741   if (n1 == n2 && d1 == d2)
3742     return GST_VALUE_EQUAL;
3743
3744   /* extend to 64 bits */
3745   new_num_1 = ((gint64) n1) * d2;
3746   new_num_2 = ((gint64) n2) * d1;
3747   if (new_num_1 < new_num_2)
3748     return GST_VALUE_LESS_THAN;
3749   if (new_num_1 > new_num_2)
3750     return GST_VALUE_GREATER_THAN;
3751
3752   /* new_num_1 == new_num_2 implies that both denominators must have 
3753    * been 0, beause otherwise simplification would have caught the
3754    * equivalence */
3755   return GST_VALUE_UNORDERED;
3756 }
3757
3758 /*********
3759  * GDate *
3760  *********/
3761
3762 /**
3763  * gst_value_set_date:
3764  * @value: a GValue initialized to GST_TYPE_DATE
3765  * @date: the date to set the value to
3766  *
3767  * Sets the contents of @value to coorespond to @date.  The actual
3768  * #GDate structure is copied before it is used.
3769  */
3770 void
3771 gst_value_set_date (GValue * value, const GDate * date)
3772 {
3773   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE);
3774   g_return_if_fail (g_date_valid (date));
3775
3776   g_value_set_boxed (value, date);
3777 }
3778
3779 /**
3780  * gst_value_get_date:
3781  * @value: a GValue initialized to GST_TYPE_DATE
3782  *
3783  * Gets the contents of @value.
3784  *
3785  * Returns: the contents of @value
3786  */
3787 const GDate *
3788 gst_value_get_date (const GValue * value)
3789 {
3790   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL);
3791
3792   return (const GDate *) g_value_get_boxed (value);
3793 }
3794
3795 static gpointer
3796 gst_date_copy (gpointer boxed)
3797 {
3798   const GDate *date = (const GDate *) boxed;
3799
3800   if (!g_date_valid (date)) {
3801     GST_WARNING ("invalid GDate");
3802     return NULL;
3803   }
3804
3805   return g_date_new_julian (g_date_get_julian (date));
3806 }
3807
3808 static gint
3809 gst_value_compare_date (const GValue * value1, const GValue * value2)
3810 {
3811   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
3812   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
3813   guint32 j1, j2;
3814
3815   if (date1 == date2)
3816     return GST_VALUE_EQUAL;
3817
3818   if ((date1 == NULL || !g_date_valid (date1))
3819       && (date2 != NULL && g_date_valid (date2))) {
3820     return GST_VALUE_LESS_THAN;
3821   }
3822
3823   if ((date2 == NULL || !g_date_valid (date2))
3824       && (date1 != NULL && g_date_valid (date1))) {
3825     return GST_VALUE_GREATER_THAN;
3826   }
3827
3828   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
3829       || !g_date_valid (date2)) {
3830     return GST_VALUE_UNORDERED;
3831   }
3832
3833   j1 = g_date_get_julian (date1);
3834   j2 = g_date_get_julian (date2);
3835
3836   if (j1 == j2)
3837     return GST_VALUE_EQUAL;
3838   else if (j1 < j2)
3839     return GST_VALUE_LESS_THAN;
3840   else
3841     return GST_VALUE_GREATER_THAN;
3842 }
3843
3844 static gchar *
3845 gst_value_serialize_date (const GValue * val)
3846 {
3847   const GDate *date = (const GDate *) g_value_get_boxed (val);
3848
3849   if (date == NULL || !g_date_valid (date))
3850     return g_strdup ("9999-99-99");
3851
3852   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
3853       g_date_get_month (date), g_date_get_day (date));
3854 }
3855
3856 static gboolean
3857 gst_value_deserialize_date (GValue * dest, const char *s)
3858 {
3859   guint year, month, day;
3860
3861   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
3862     return FALSE;
3863
3864   if (!g_date_valid_dmy (day, month, year))
3865     return FALSE;
3866
3867   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
3868   return TRUE;
3869 }
3870
3871 static void
3872 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
3873 {
3874   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
3875 }
3876
3877 static void
3878 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
3879 {
3880   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
3881 }
3882
3883 static void
3884 gst_value_transform_object_string (const GValue * src_value,
3885     GValue * dest_value)
3886 {
3887   GstObject *obj;
3888   gchar *str;
3889
3890   obj = g_value_get_object (src_value);
3891   if (obj) {
3892     str =
3893         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
3894         GST_OBJECT_NAME (obj));
3895   } else {
3896     str = g_strdup ("NULL");
3897   }
3898
3899   dest_value->data[0].v_pointer = str;
3900 }
3901
3902 static GTypeInfo _info = {
3903   0,
3904   NULL,
3905   NULL,
3906   NULL,
3907   NULL,
3908   NULL,
3909   0,
3910   0,
3911   NULL,
3912   NULL,
3913 };
3914
3915 static GTypeFundamentalInfo _finfo = {
3916   0
3917 };
3918
3919 #define FUNC_VALUE_GET_TYPE(type, name)                         \
3920 GType gst_ ## type ## _get_type (void)                          \
3921 {                                                               \
3922   static GType gst_ ## type ## _type = 0;                       \
3923                                                                 \
3924   if (G_UNLIKELY (gst_ ## type ## _type == 0)) {                \
3925     _info.value_table = & _gst_ ## type ## _value_table;        \
3926     gst_ ## type ## _type = g_type_register_fundamental (       \
3927         g_type_fundamental_next (),                             \
3928         name, &_info, &_finfo, 0);                              \
3929   }                                                             \
3930                                                                 \
3931   return gst_ ## type ## _type;                                 \
3932 }
3933
3934 static const GTypeValueTable _gst_fourcc_value_table = {
3935   gst_value_init_fourcc,
3936   NULL,
3937   gst_value_copy_fourcc,
3938   NULL,
3939   "i",
3940   gst_value_collect_fourcc,
3941   "p",
3942   gst_value_lcopy_fourcc
3943 };
3944
3945 FUNC_VALUE_GET_TYPE (fourcc, "GstFourcc");
3946
3947 static const GTypeValueTable _gst_int_range_value_table = {
3948   gst_value_init_int_range,
3949   NULL,
3950   gst_value_copy_int_range,
3951   NULL,
3952   "ii",
3953   gst_value_collect_int_range,
3954   "pp",
3955   gst_value_lcopy_int_range
3956 };
3957
3958 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
3959
3960 static const GTypeValueTable _gst_double_range_value_table = {
3961   gst_value_init_double_range,
3962   NULL,
3963   gst_value_copy_double_range,
3964   NULL,
3965   "dd",
3966   gst_value_collect_double_range,
3967   "pp",
3968   gst_value_lcopy_double_range
3969 };
3970
3971 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
3972
3973 static const GTypeValueTable _gst_fraction_range_value_table = {
3974   gst_value_init_fraction_range,
3975   gst_value_free_fraction_range,
3976   gst_value_copy_fraction_range,
3977   NULL,
3978   "iiii",
3979   gst_value_collect_fraction_range,
3980   "pppp",
3981   gst_value_lcopy_fraction_range
3982 };
3983
3984 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
3985
3986 static const GTypeValueTable _gst_value_list_value_table = {
3987   gst_value_init_list_or_array,
3988   gst_value_free_list_or_array,
3989   gst_value_copy_list_or_array,
3990   gst_value_list_or_array_peek_pointer,
3991   "p",
3992   gst_value_collect_list_or_array,
3993   "p",
3994   gst_value_lcopy_list_or_array
3995 };
3996
3997 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
3998
3999 static const GTypeValueTable _gst_value_array_value_table = {
4000   gst_value_init_list_or_array,
4001   gst_value_free_list_or_array,
4002   gst_value_copy_list_or_array,
4003   gst_value_list_or_array_peek_pointer,
4004   "p",
4005   gst_value_collect_list_or_array,
4006   "p",
4007   gst_value_lcopy_list_or_array
4008 };
4009
4010 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
4011
4012 static const GTypeValueTable _gst_fraction_value_table = {
4013   gst_value_init_fraction,
4014   NULL,
4015   gst_value_copy_fraction,
4016   NULL,
4017   "ii",
4018   gst_value_collect_fraction,
4019   "pp",
4020   gst_value_lcopy_fraction
4021 };
4022
4023 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
4024
4025
4026 GType
4027 gst_date_get_type (void)
4028 {
4029   static GType gst_date_type = 0;
4030
4031   if (G_UNLIKELY (gst_date_type == 0)) {
4032     /* FIXME 0.11: we require GLib 2.8 already
4033      * Not using G_TYPE_DATE here on purpose, even if we could
4034      * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the
4035      * serialised strings to have different type strings depending
4036      * on what version is used, so FIXME when we require GLib-2.8 */
4037     gst_date_type = g_boxed_type_register_static ("GstDate",
4038         (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free);
4039   }
4040
4041   return gst_date_type;
4042 }
4043
4044 void
4045 _gst_value_initialize (void)
4046 {
4047   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
4048   gst_value_union_funcs = g_array_new (FALSE, FALSE,
4049       sizeof (GstValueUnionInfo));
4050   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
4051       sizeof (GstValueIntersectInfo));
4052   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
4053       sizeof (GstValueSubtractInfo));
4054
4055   {
4056     static GstValueTable gst_value = {
4057       0,
4058       gst_value_compare_fourcc,
4059       gst_value_serialize_fourcc,
4060       gst_value_deserialize_fourcc,
4061     };
4062
4063     gst_value.type = gst_fourcc_get_type ();
4064     gst_value_register (&gst_value);
4065   }
4066
4067   {
4068     static GstValueTable gst_value = {
4069       0,
4070       gst_value_compare_int_range,
4071       gst_value_serialize_int_range,
4072       gst_value_deserialize_int_range,
4073     };
4074
4075     gst_value.type = gst_int_range_get_type ();
4076     gst_value_register (&gst_value);
4077   }
4078
4079   {
4080     static GstValueTable gst_value = {
4081       0,
4082       gst_value_compare_double_range,
4083       gst_value_serialize_double_range,
4084       gst_value_deserialize_double_range,
4085     };
4086
4087     gst_value.type = gst_double_range_get_type ();
4088     gst_value_register (&gst_value);
4089   }
4090
4091   {
4092     static GstValueTable gst_value = {
4093       0,
4094       gst_value_compare_fraction_range,
4095       gst_value_serialize_fraction_range,
4096       gst_value_deserialize_fraction_range,
4097     };
4098
4099     gst_value.type = gst_fraction_range_get_type ();
4100     gst_value_register (&gst_value);
4101   }
4102
4103   {
4104     static GstValueTable gst_value = {
4105       0,
4106       gst_value_compare_list,
4107       gst_value_serialize_list,
4108       gst_value_deserialize_list,
4109     };
4110
4111     gst_value.type = gst_value_list_get_type ();
4112     gst_value_register (&gst_value);
4113   }
4114
4115   {
4116     static GstValueTable gst_value = {
4117       0,
4118       gst_value_compare_array,
4119       gst_value_serialize_array,
4120       gst_value_deserialize_array,
4121     };
4122
4123     gst_value.type = gst_value_array_get_type ();;
4124     gst_value_register (&gst_value);
4125   }
4126
4127   {
4128 #if 0
4129     static const GTypeValueTable value_table = {
4130       gst_value_init_buffer,
4131       NULL,
4132       gst_value_copy_buffer,
4133       NULL,
4134       "i",
4135       NULL,                     /*gst_value_collect_buffer, */
4136       "p",
4137       NULL                      /*gst_value_lcopy_buffer */
4138     };
4139 #endif
4140     static GstValueTable gst_value = {
4141       0,
4142       gst_value_compare_buffer,
4143       gst_value_serialize_buffer,
4144       gst_value_deserialize_buffer,
4145     };
4146
4147     gst_value.type = GST_TYPE_BUFFER;
4148     gst_value_register (&gst_value);
4149   }
4150   {
4151     static GstValueTable gst_value = {
4152       0,
4153       gst_value_compare_fraction,
4154       gst_value_serialize_fraction,
4155       gst_value_deserialize_fraction,
4156     };
4157
4158     gst_value.type = gst_fraction_get_type ();
4159     gst_value_register (&gst_value);
4160   }
4161   {
4162     static GstValueTable gst_value = {
4163       0,
4164       NULL,
4165       gst_value_serialize_caps,
4166       gst_value_deserialize_caps,
4167     };
4168
4169     gst_value.type = GST_TYPE_CAPS;
4170     gst_value_register (&gst_value);
4171   }
4172   {
4173     static GstValueTable gst_value = {
4174       0,
4175       NULL,
4176       gst_value_serialize_structure,
4177       gst_value_deserialize_structure,
4178     };
4179
4180     gst_value.type = GST_TYPE_STRUCTURE;
4181     gst_value_register (&gst_value);
4182   }
4183   {
4184     static GstValueTable gst_value = {
4185       0,
4186       gst_value_compare_date,
4187       gst_value_serialize_date,
4188       gst_value_deserialize_date,
4189     };
4190
4191     gst_value.type = gst_date_get_type ();
4192     gst_value_register (&gst_value);
4193   }
4194
4195   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
4196   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
4197
4198   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
4199   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
4200   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
4201
4202   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
4203
4204   REGISTER_SERIALIZATION (G_TYPE_INT, int);
4205
4206   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
4207   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
4208
4209   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
4210   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
4211   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
4212
4213   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
4214       gst_value_transform_fourcc_string);
4215   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
4216       gst_value_transform_int_range_string);
4217   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
4218       gst_value_transform_double_range_string);
4219   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
4220       gst_value_transform_fraction_range_string);
4221   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
4222       gst_value_transform_list_string);
4223   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
4224       gst_value_transform_array_string);
4225   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
4226       gst_value_transform_fraction_string);
4227   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
4228       gst_value_transform_string_fraction);
4229   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
4230       gst_value_transform_fraction_double);
4231   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
4232       gst_value_transform_double_fraction);
4233   g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING,
4234       gst_value_transform_date_string);
4235   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE,
4236       gst_value_transform_string_date);
4237   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
4238       gst_value_transform_object_string);
4239
4240   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4241       gst_value_intersect_int_int_range);
4242   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4243       gst_value_intersect_int_range_int_range);
4244   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
4245       gst_value_intersect_double_double_range);
4246   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
4247       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
4248   gst_value_register_intersect_func (GST_TYPE_ARRAY,
4249       GST_TYPE_ARRAY, gst_value_intersect_array);
4250   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4251       gst_value_intersect_fraction_fraction_range);
4252   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
4253       GST_TYPE_FRACTION_RANGE,
4254       gst_value_intersect_fraction_range_fraction_range);
4255
4256   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4257       gst_value_subtract_int_int_range);
4258   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
4259       gst_value_subtract_int_range_int);
4260   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4261       gst_value_subtract_int_range_int_range);
4262   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
4263       gst_value_subtract_double_double_range);
4264   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
4265       gst_value_subtract_double_range_double);
4266   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
4267       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
4268
4269   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4270       gst_value_subtract_fraction_fraction_range);
4271   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
4272       gst_value_subtract_fraction_range_fraction);
4273   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
4274       GST_TYPE_FRACTION_RANGE,
4275       gst_value_subtract_fraction_range_fraction_range);
4276
4277   /* see bug #317246, #64994, #65041 */
4278   {
4279     volatile GType date_type = G_TYPE_DATE;
4280
4281     g_type_name (date_type);
4282   }
4283
4284   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4285       gst_value_union_int_int_range);
4286   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4287       gst_value_union_int_range_int_range);
4288
4289 #if 0
4290   /* Implement these if needed */
4291   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4292       gst_value_union_fraction_fraction_range);
4293   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
4294       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
4295 #endif
4296 }