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