Test that removing probes from within the probe functions works.
[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  * SECTION:gstvalue
21  * @short_description: GValue implementations specific to GStreamer
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include <math.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "gst_private.h"
34 #include <gst/gst.h>
35 #include <gobject/gvaluecollector.h>
36
37 typedef struct _GstValueUnionInfo GstValueUnionInfo;
38 struct _GstValueUnionInfo
39 {
40   GType type1;
41   GType type2;
42   GstValueUnionFunc func;
43 };
44
45 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
46 struct _GstValueIntersectInfo
47 {
48   GType type1;
49   GType type2;
50   GstValueIntersectFunc func;
51 };
52
53 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
54 struct _GstValueSubtractInfo
55 {
56   GType minuend;
57   GType subtrahend;
58   GstValueSubtractFunc func;
59 };
60
61 GType gst_type_fourcc;
62 GType gst_type_int_range;
63 GType gst_type_double_range;
64 GType gst_type_list;
65 GType gst_type_array;
66 GType gst_type_fraction;
67
68 static GArray *gst_value_table;
69 static GArray *gst_value_union_funcs;
70 static GArray *gst_value_intersect_funcs;
71 static GArray *gst_value_subtract_funcs;
72
73 /********
74  * list *
75  ********/
76
77 /* two helper functions to serialize/stringify any type of list
78  * regular lists are done with { }, arrays with < >
79  */
80 static char *
81 gst_value_serialize_any_list (const GValue * value, const char *begin,
82     const char *end)
83 {
84   int i;
85   GArray *array = value->data[0].v_pointer;
86   GString *s;
87   GValue *v;
88   gchar *s_val;
89
90   s = g_string_new (begin);
91   for (i = 0; i < array->len; i++) {
92     v = &g_array_index (array, GValue, i);
93     s_val = gst_value_serialize (v);
94     g_string_append (s, s_val);
95     g_free (s_val);
96     if (i < array->len - 1) {
97       g_string_append (s, ", ");
98     }
99   }
100   g_string_append (s, end);
101   return g_string_free (s, FALSE);
102 }
103
104 static void
105 gst_value_transform_any_list_string (const GValue * src_value,
106     GValue * dest_value, const char *begin, const char *end)
107 {
108   GValue *list_value;
109   GArray *array;
110   GString *s;
111   int i;
112   char *list_s;
113
114   array = src_value->data[0].v_pointer;
115
116   s = g_string_new (begin);
117   for (i = 0; i < array->len; i++) {
118     list_value = &g_array_index (array, GValue, i);
119
120     if (i != 0) {
121       g_string_append (s, ", ");
122     }
123     list_s = g_strdup_value_contents (list_value);
124     g_string_append (s, list_s);
125     g_free (list_s);
126   }
127   g_string_append (s, end);
128
129   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
130 }
131
132 /*
133  * helper function to see if a type is fixed. Is used internally here and
134  * there. Do not export, since it doesn't work for types where the content
135  * decides the fixedness (e.g. GST_TYPE_ARRAY).
136  */
137
138 static gboolean
139 gst_type_is_fixed (GType type)
140 {
141   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
142       type == GST_TYPE_LIST) {
143     return FALSE;
144   }
145   if (G_TYPE_FUNDAMENTAL (type) <=
146       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
147     return TRUE;
148   }
149   if (type == GST_TYPE_BUFFER || type == GST_TYPE_FOURCC
150       || type == GST_TYPE_ARRAY || type == GST_TYPE_FRACTION) {
151     return TRUE;
152   }
153
154   return FALSE;
155 }
156
157 /* GValue functions usable for both regular lists and arrays */
158 static void
159 gst_value_init_list (GValue * value)
160 {
161   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
162 }
163
164 static GArray *
165 gst_value_list_array_copy (const GArray * src)
166 {
167   GArray *dest;
168   gint i;
169
170   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), src->len);
171   g_array_set_size (dest, src->len);
172   for (i = 0; i < src->len; i++) {
173     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
174         &g_array_index (src, GValue, i));
175   }
176
177   return dest;
178 }
179
180 static void
181 gst_value_copy_list (const GValue * src_value, GValue * dest_value)
182 {
183   dest_value->data[0].v_pointer =
184       gst_value_list_array_copy ((GArray *) src_value->data[0].v_pointer);
185 }
186
187 static void
188 gst_value_free_list (GValue * value)
189 {
190   gint i;
191   GArray *src = (GArray *) value->data[0].v_pointer;
192
193   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
194     for (i = 0; i < src->len; i++) {
195       g_value_unset (&g_array_index (src, GValue, i));
196     }
197     g_array_free (src, TRUE);
198   }
199 }
200
201 static gpointer
202 gst_value_list_peek_pointer (const GValue * value)
203 {
204   return value->data[0].v_pointer;
205 }
206
207 static gchar *
208 gst_value_collect_list (GValue * value, guint n_collect_values,
209     GTypeCValue * collect_values, guint collect_flags)
210 {
211   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
212     value->data[0].v_pointer = collect_values[0].v_pointer;
213     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
214   } else {
215     value->data[0].v_pointer =
216         gst_value_list_array_copy ((GArray *) collect_values[0].v_pointer);
217   }
218   return NULL;
219 }
220
221 static gchar *
222 gst_value_lcopy_list (const GValue * value, guint n_collect_values,
223     GTypeCValue * collect_values, guint collect_flags)
224 {
225   GArray **dest = collect_values[0].v_pointer;
226
227   if (!dest)
228     return g_strdup_printf ("value location for `%s' passed as NULL",
229         G_VALUE_TYPE_NAME (value));
230   if (!value->data[0].v_pointer)
231     return g_strdup_printf ("invalid value given for `%s'",
232         G_VALUE_TYPE_NAME (value));
233   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
234     *dest = (GArray *) value->data[0].v_pointer;
235   } else {
236     *dest = gst_value_list_array_copy ((GArray *) value->data[0].v_pointer);
237   }
238   return NULL;
239 }
240
241 /**
242  * gst_value_list_prepend_value:
243  * @value: a GstValueList to prepend a value to
244  * @prepend_value: the value to prepend
245  *
246  * Prepends @prepend_value to the GstValueList in @value.
247  *
248  */
249 void
250 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
251 {
252   GValue val = { 0, };
253
254   g_return_if_fail (GST_VALUE_HOLDS_LIST (value)
255       || GST_VALUE_HOLDS_ARRAY (value));
256
257   gst_value_init_and_copy (&val, prepend_value);
258   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
259 }
260
261 /**
262  * gst_value_list_append_value:
263  * @value: a GstValueList to append a value to
264  * @append_value: the value to append
265  *
266  * Appends @append_value to the GstValueList in @value.
267  */
268 void
269 gst_value_list_append_value (GValue * value, const GValue * append_value)
270 {
271   GValue val = { 0, };
272
273   g_return_if_fail (GST_VALUE_HOLDS_LIST (value)
274       || GST_VALUE_HOLDS_ARRAY (value));
275
276   gst_value_init_and_copy (&val, append_value);
277   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
278 }
279
280 /**
281  * gst_value_list_get_size:
282  * @value: a #GValue of type #GST_LIST_TYPE or #GST_ARRAY_TYPE
283  *
284  * Gets the number of values contained in @value.
285  *
286  * Returns: the number of values
287  */
288 guint
289 gst_value_list_get_size (const GValue * value)
290 {
291   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value)
292       || GST_VALUE_HOLDS_ARRAY (value), 0);
293
294   return ((GArray *) value->data[0].v_pointer)->len;
295 }
296
297 /**
298  * gst_value_list_get_value:
299  * @value: a #GValue of type #GST_LIST_TYPE or #GST_ARRAY_TYPE
300  * @index: index of value to get from the list
301  *
302  * Gets the value that is a member of the list contained in @value and
303  * has the index @index.
304  *
305  * Returns: the value at the given index
306  */
307 const GValue *
308 gst_value_list_get_value (const GValue * value, guint index)
309 {
310   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value)
311       || GST_VALUE_HOLDS_ARRAY (value), NULL);
312   g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
313
314   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
315       GValue, index);
316 }
317
318 /**
319  * gst_value_list_concat:
320  * @dest: an uninitialized #GValue to take the result
321  * @value1: first value to put into the union
322  * @value2: second value to put into the union
323  *
324  * Concatenates copies of value1 and value2 into a list.  The value
325  * @dest is initialized to the type GST_TYPE_LIST.
326  */
327 void
328 gst_value_list_concat (GValue * dest, const GValue * value1,
329     const GValue * value2)
330 {
331   guint i, value1_length, value2_length;
332   GArray *array;
333
334   g_return_if_fail (dest != NULL);
335   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
336   g_return_if_fail (G_IS_VALUE (value1));
337   g_return_if_fail (G_IS_VALUE (value2));
338
339   value1_length =
340       (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
341   value2_length =
342       (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
343   g_value_init (dest, GST_TYPE_LIST);
344   array = (GArray *) dest->data[0].v_pointer;
345   g_array_set_size (array, value1_length + value2_length);
346
347   if (GST_VALUE_HOLDS_LIST (value1)) {
348     for (i = 0; i < value1_length; i++) {
349       gst_value_init_and_copy (&g_array_index (array, GValue, i),
350           gst_value_list_get_value (value1, i));
351     }
352   } else {
353     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
354   }
355
356   if (GST_VALUE_HOLDS_LIST (value2)) {
357     for (i = 0; i < value2_length; i++) {
358       gst_value_init_and_copy (&g_array_index (array, GValue,
359               i + value1_length), gst_value_list_get_value (value2, i));
360     }
361   } else {
362     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
363         value2);
364   }
365 }
366
367 static void
368 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
369 {
370   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
371 }
372
373 static void
374 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
375 {
376   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
377 }
378
379 static int
380 gst_value_compare_list (const GValue * value1, const GValue * value2)
381 {
382   int i, j;
383   GArray *array1 = value1->data[0].v_pointer;
384   GArray *array2 = value2->data[0].v_pointer;
385   GValue *v1;
386   GValue *v2;
387
388   if (array1->len != array2->len)
389     return GST_VALUE_UNORDERED;
390
391   for (i = 0; i < array1->len; i++) {
392     v1 = &g_array_index (array1, GValue, i);
393     for (j = 0; j < array1->len; j++) {
394       v2 = &g_array_index (array2, GValue, j);
395       if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
396         break;
397     }
398     if (j == array1->len) {
399       return GST_VALUE_UNORDERED;
400     }
401   }
402
403   return GST_VALUE_EQUAL;
404 }
405
406 static char *
407 gst_value_serialize_list (const GValue * value)
408 {
409   return gst_value_serialize_any_list (value, "{ ", " }");
410 }
411
412 static gboolean
413 gst_value_deserialize_list (GValue * dest, const char *s)
414 {
415   g_warning ("unimplemented");
416   return FALSE;
417 }
418
419 static char *
420 gst_value_serialize_array (const GValue * value)
421 {
422   return gst_value_serialize_any_list (value, "< ", " >");
423 }
424
425 static gboolean
426 gst_value_deserialize_array (GValue * dest, const char *s)
427 {
428   g_warning ("unimplemented");
429   return FALSE;
430 }
431
432 /**********
433  * fourcc *
434  **********/
435
436 static void
437 gst_value_init_fourcc (GValue * value)
438 {
439   value->data[0].v_int = 0;
440 }
441
442 static void
443 gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value)
444 {
445   dest_value->data[0].v_int = src_value->data[0].v_int;
446 }
447
448 static gchar *
449 gst_value_collect_fourcc (GValue * value, guint n_collect_values,
450     GTypeCValue * collect_values, guint collect_flags)
451 {
452   value->data[0].v_int = collect_values[0].v_int;
453
454   return NULL;
455 }
456
457 static gchar *
458 gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values,
459     GTypeCValue * collect_values, guint collect_flags)
460 {
461   guint32 *fourcc_p = collect_values[0].v_pointer;
462
463   if (!fourcc_p)
464     return g_strdup_printf ("value location for `%s' passed as NULL",
465         G_VALUE_TYPE_NAME (value));
466
467   *fourcc_p = value->data[0].v_int;
468
469   return NULL;
470 }
471
472 /**
473  * gst_value_set_fourcc:
474  * @value: a GValue initialized to #GST_TYPE_FOURCC
475  * @fourcc: the #guint32 fourcc to set
476  *
477  * Sets @value to @fourcc.
478  */
479 void
480 gst_value_set_fourcc (GValue * value, guint32 fourcc)
481 {
482   g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
483
484   value->data[0].v_int = fourcc;
485 }
486
487 /**
488  * gst_value_get_fourcc:
489  * @value: a GValue initialized to #GST_TYPE_FOURCC
490  *
491  * Gets the #guint32 fourcc contained in @value.
492  *
493  * Returns: the #guint32 fourcc contained in @value.
494  */
495 guint32
496 gst_value_get_fourcc (const GValue * value)
497 {
498   g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
499
500   return value->data[0].v_int;
501 }
502
503 static void
504 gst_value_transform_fourcc_string (const GValue * src_value,
505     GValue * dest_value)
506 {
507   guint32 fourcc = src_value->data[0].v_int;
508
509   if (g_ascii_isprint ((fourcc >> 0) & 0xff) &&
510       g_ascii_isprint ((fourcc >> 8) & 0xff) &&
511       g_ascii_isprint ((fourcc >> 16) & 0xff) &&
512       g_ascii_isprint ((fourcc >> 24) & 0xff)) {
513     dest_value->data[0].v_pointer =
514         g_strdup_printf (GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
515   } else {
516     dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc);
517   }
518 }
519
520 static int
521 gst_value_compare_fourcc (const GValue * value1, const GValue * value2)
522 {
523   if (value2->data[0].v_int == value1->data[0].v_int)
524     return GST_VALUE_EQUAL;
525   return GST_VALUE_UNORDERED;
526 }
527
528 static char *
529 gst_value_serialize_fourcc (const GValue * value)
530 {
531   guint32 fourcc = value->data[0].v_int;
532
533   if (g_ascii_isalnum ((fourcc >> 0) & 0xff) &&
534       g_ascii_isalnum ((fourcc >> 8) & 0xff) &&
535       g_ascii_isalnum ((fourcc >> 16) & 0xff) &&
536       g_ascii_isalnum ((fourcc >> 24) & 0xff)) {
537     return g_strdup_printf (GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
538   } else {
539     return g_strdup_printf ("0x%08x", fourcc);
540   }
541 }
542
543 static gboolean
544 gst_value_deserialize_fourcc (GValue * dest, const char *s)
545 {
546   gboolean ret = FALSE;
547   guint32 fourcc = 0;
548   char *end;
549
550   if (strlen (s) == 4) {
551     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
552     ret = TRUE;
553   } else if (g_ascii_isdigit (*s)) {
554     fourcc = strtoul (s, &end, 0);
555     if (*end == 0) {
556       ret = TRUE;
557     }
558   }
559   gst_value_set_fourcc (dest, fourcc);
560
561   return ret;
562 }
563
564 /*************
565  * int range *
566  *************/
567
568 static void
569 gst_value_init_int_range (GValue * value)
570 {
571   value->data[0].v_int = 0;
572   value->data[1].v_int = 0;
573 }
574
575 static void
576 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
577 {
578   dest_value->data[0].v_int = src_value->data[0].v_int;
579   dest_value->data[1].v_int = src_value->data[1].v_int;
580 }
581
582 static gchar *
583 gst_value_collect_int_range (GValue * value, guint n_collect_values,
584     GTypeCValue * collect_values, guint collect_flags)
585 {
586   value->data[0].v_int = collect_values[0].v_int;
587   value->data[1].v_int = collect_values[1].v_int;
588
589   return NULL;
590 }
591
592 static gchar *
593 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
594     GTypeCValue * collect_values, guint collect_flags)
595 {
596   guint32 *int_range_start = collect_values[0].v_pointer;
597   guint32 *int_range_end = collect_values[1].v_pointer;
598
599   if (!int_range_start)
600     return g_strdup_printf ("start value location for `%s' passed as NULL",
601         G_VALUE_TYPE_NAME (value));
602   if (!int_range_end)
603     return g_strdup_printf ("end value location for `%s' passed as NULL",
604         G_VALUE_TYPE_NAME (value));
605
606   *int_range_start = value->data[0].v_int;
607   *int_range_end = value->data[1].v_int;
608
609   return NULL;
610 }
611
612 /**
613  * gst_value_set_int_range:
614  * @value: a GValue initialized to GST_TYPE_INT_RANGE
615  * @start: the start of the range
616  * @end: the end of the range
617  *
618  * Sets @value to the range specified by @start and @end.
619  */
620 void
621 gst_value_set_int_range (GValue * value, int start, int end)
622 {
623   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
624   g_return_if_fail (start < end);
625
626   value->data[0].v_int = start;
627   value->data[1].v_int = end;
628 }
629
630 /**
631  * gst_value_get_int_range_min:
632  * @value: a GValue initialized to GST_TYPE_INT_RANGE
633  *
634  * Gets the minimum of the range specified by @value.
635  *
636  * Returns: the minimum of the range
637  */
638 int
639 gst_value_get_int_range_min (const GValue * value)
640 {
641   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
642
643   return value->data[0].v_int;
644 }
645
646 /**
647  * gst_value_get_int_range_max:
648  * @value: a GValue initialized to GST_TYPE_INT_RANGE
649  *
650  * Gets the maximum of the range specified by @value.
651  *
652  * Returns: the maxumum of the range
653  */
654 int
655 gst_value_get_int_range_max (const GValue * value)
656 {
657   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
658
659   return value->data[1].v_int;
660 }
661
662 static void
663 gst_value_transform_int_range_string (const GValue * src_value,
664     GValue * dest_value)
665 {
666   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
667       (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
668 }
669
670 static int
671 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
672 {
673   if (value2->data[0].v_int == value1->data[0].v_int &&
674       value2->data[1].v_int == value1->data[1].v_int)
675     return GST_VALUE_EQUAL;
676   return GST_VALUE_UNORDERED;
677 }
678
679 static char *
680 gst_value_serialize_int_range (const GValue * value)
681 {
682   return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
683       value->data[1].v_int);
684 }
685
686 static gboolean
687 gst_value_deserialize_int_range (GValue * dest, const char *s)
688 {
689   g_warning ("unimplemented");
690   return FALSE;
691 }
692
693 /****************
694  * double range *
695  ****************/
696
697 static void
698 gst_value_init_double_range (GValue * value)
699 {
700   value->data[0].v_double = 0;
701   value->data[1].v_double = 0;
702 }
703
704 static void
705 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
706 {
707   dest_value->data[0].v_double = src_value->data[0].v_double;
708   dest_value->data[1].v_double = src_value->data[1].v_double;
709 }
710
711 static gchar *
712 gst_value_collect_double_range (GValue * value, guint n_collect_values,
713     GTypeCValue * collect_values, guint collect_flags)
714 {
715   value->data[0].v_double = collect_values[0].v_double;
716   value->data[1].v_double = collect_values[1].v_double;
717
718   return NULL;
719 }
720
721 static gchar *
722 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
723     GTypeCValue * collect_values, guint collect_flags)
724 {
725   gdouble *double_range_start = collect_values[0].v_pointer;
726   gdouble *double_range_end = collect_values[1].v_pointer;
727
728   if (!double_range_start)
729     return g_strdup_printf ("start value location for `%s' passed as NULL",
730         G_VALUE_TYPE_NAME (value));
731   if (!double_range_end)
732     return g_strdup_printf ("end value location for `%s' passed as NULL",
733         G_VALUE_TYPE_NAME (value));
734
735   *double_range_start = value->data[0].v_double;
736   *double_range_end = value->data[1].v_double;
737
738   return NULL;
739 }
740
741 /**
742  * gst_value_set_double_range:
743  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
744  * @start: the start of the range
745  * @end: the end of the range
746  *
747  * Sets @value to the range specified by @start and @end.
748  */
749 void
750 gst_value_set_double_range (GValue * value, double start, double end)
751 {
752   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
753
754   value->data[0].v_double = start;
755   value->data[1].v_double = end;
756 }
757
758 /**
759  * gst_value_get_double_range_min:
760  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
761  *
762  * Gets the minimum of the range specified by @value.
763  *
764  * Returns: the minumum of the range
765  */
766 double
767 gst_value_get_double_range_min (const GValue * value)
768 {
769   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
770
771   return value->data[0].v_double;
772 }
773
774 /**
775  * gst_value_get_double_range_max:
776  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
777  *
778  * Gets the maximum of the range specified by @value.
779  *
780  * Returns: the maxumum of the range
781  */
782 double
783 gst_value_get_double_range_max (const GValue * value)
784 {
785   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
786
787   return value->data[1].v_double;
788 }
789
790 static void
791 gst_value_transform_double_range_string (const GValue * src_value,
792     GValue * dest_value)
793 {
794   char s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
795
796   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
797       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
798           src_value->data[0].v_double),
799       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
800           src_value->data[1].v_double));
801 }
802
803 static int
804 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
805 {
806   if (value2->data[0].v_double == value1->data[0].v_double &&
807       value2->data[0].v_double == value1->data[0].v_double)
808     return GST_VALUE_EQUAL;
809   return GST_VALUE_UNORDERED;
810 }
811
812 static char *
813 gst_value_serialize_double_range (const GValue * value)
814 {
815   char d1[G_ASCII_DTOSTR_BUF_SIZE];
816   char d2[G_ASCII_DTOSTR_BUF_SIZE];
817
818   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
819   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
820   return g_strdup_printf ("[ %s, %s ]", d1, d2);
821 }
822
823 static gboolean
824 gst_value_deserialize_double_range (GValue * dest, const char *s)
825 {
826   g_warning ("unimplemented");
827   return FALSE;
828 }
829
830 /***********
831  * GstCaps *
832  ***********/
833
834 /**
835  * gst_value_set_caps:
836  * @value: a GValue initialized to GST_TYPE_CAPS
837  * @caps: the caps to set the value to
838  *
839  * Sets the contents of @value to coorespond to @caps.  The actual
840  * #GstCaps structure is copied before it is used.
841  */
842 void
843 gst_value_set_caps (GValue * value, const GstCaps * caps)
844 {
845   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
846
847   g_value_set_boxed (value, caps);
848 }
849
850 /**
851  * gst_value_get_caps:
852  * @value: a GValue initialized to GST_TYPE_CAPS
853  *
854  * Gets the contents of @value.
855  *
856  * Returns: the contents of @value
857  */
858 const GstCaps *
859 gst_value_get_caps (const GValue * value)
860 {
861   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
862
863   return (GstCaps *) g_value_get_boxed (value);
864 }
865
866 static char *
867 gst_value_serialize_caps (const GValue * value)
868 {
869   GstCaps *caps = g_value_get_boxed (value);
870
871   return gst_caps_to_string (caps);
872 }
873
874 static gboolean
875 gst_value_deserialize_caps (GValue * dest, const char *s)
876 {
877   GstCaps *caps;
878
879   caps = gst_caps_from_string (s);
880
881   if (caps) {
882     g_value_set_boxed (dest, caps);
883     return TRUE;
884   }
885   return FALSE;
886 }
887
888
889 /*************
890  * GstBuffer *
891  *************/
892
893 static int
894 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
895 {
896   GstBuffer *buf1 = GST_BUFFER (gst_value_get_mini_object (value1));
897   GstBuffer *buf2 = GST_BUFFER (gst_value_get_mini_object (value2));
898
899   if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2))
900     return GST_VALUE_UNORDERED;
901   if (GST_BUFFER_SIZE (buf1) == 0)
902     return GST_VALUE_EQUAL;
903   g_assert (GST_BUFFER_DATA (buf1));
904   g_assert (GST_BUFFER_DATA (buf2));
905   if (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2),
906           GST_BUFFER_SIZE (buf1)) == 0)
907     return GST_VALUE_EQUAL;
908
909   return GST_VALUE_UNORDERED;
910 }
911
912 static char *
913 gst_value_serialize_buffer (const GValue * value)
914 {
915   guint8 *data;
916   int i;
917   int size;
918   char *string;
919   GstBuffer *buffer = GST_BUFFER (gst_value_get_mini_object (value));
920
921   data = GST_BUFFER_DATA (buffer);
922   size = GST_BUFFER_SIZE (buffer);
923
924   string = g_malloc (size * 2 + 1);
925   for (i = 0; i < size; i++) {
926     sprintf (string + i * 2, "%02x", data[i]);
927   }
928   string[size * 2] = 0;
929
930   return string;
931 }
932
933 static gboolean
934 gst_value_deserialize_buffer (GValue * dest, const char *s)
935 {
936   GstBuffer *buffer;
937   gboolean ret = TRUE;
938   int len;
939   char ts[3];
940   guint8 *data;
941   int i;
942
943   len = strlen (s);
944   if (len & 1)
945     return FALSE;
946   buffer = gst_buffer_new_and_alloc (len / 2);
947   data = GST_BUFFER_DATA (buffer);
948   for (i = 0; i < len / 2; i++) {
949     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) {
950       ret = FALSE;
951       break;
952     }
953     ts[0] = s[i * 2 + 0];
954     ts[1] = s[i * 2 + 1];
955     ts[2] = 0;
956
957     data[i] = strtoul (ts, NULL, 16);
958   }
959
960   if (ret) {
961     gst_value_take_mini_object (dest, GST_MINI_OBJECT (buffer));
962     return TRUE;
963   } else {
964     gst_buffer_unref (buffer);
965     return FALSE;
966   }
967 }
968
969
970 /***********
971  * boolean *
972  ***********/
973
974 static int
975 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
976 {
977   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
978     return GST_VALUE_EQUAL;
979   return GST_VALUE_UNORDERED;
980 }
981
982 static char *
983 gst_value_serialize_boolean (const GValue * value)
984 {
985   if (value->data[0].v_int) {
986     return g_strdup ("true");
987   }
988   return g_strdup ("false");
989 }
990
991 static gboolean
992 gst_value_deserialize_boolean (GValue * dest, const char *s)
993 {
994   gboolean ret = FALSE;
995
996   if (g_ascii_strcasecmp (s, "true") == 0 ||
997       g_ascii_strcasecmp (s, "yes") == 0 ||
998       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
999     g_value_set_boolean (dest, TRUE);
1000     ret = TRUE;
1001   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
1002       g_ascii_strcasecmp (s, "no") == 0 ||
1003       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
1004     g_value_set_boolean (dest, FALSE);
1005     ret = TRUE;
1006   }
1007
1008   return ret;
1009 }
1010
1011 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
1012 static gint                                                             \
1013 gst_value_compare_ ## _type                                             \
1014 (const GValue * value1, const GValue * value2)                          \
1015 {                                                                       \
1016   g ## _type val1 = g_value_get_ ## _type (value1);                     \
1017   g ## _type val2 = g_value_get_ ## _type (value2);                     \
1018   if (val1 > val2)                                                      \
1019     return GST_VALUE_GREATER_THAN;                                      \
1020   if (val1 < val2)                                                      \
1021     return GST_VALUE_LESS_THAN;                                         \
1022   return GST_VALUE_EQUAL;                                               \
1023 }                                                                       \
1024                                                                         \
1025 static char *                                                           \
1026 gst_value_serialize_ ## _type (const GValue * value)                    \
1027 {                                                                       \
1028   GValue val = { 0, };                                                  \
1029   g_value_init (&val, G_TYPE_STRING);                                   \
1030   if (!g_value_transform (value, &val))                                 \
1031     g_assert_not_reached ();                                            \
1032   /* NO_COPY_MADNESS!!! */                                              \
1033   return (char *) g_value_get_string (&val);                            \
1034 }
1035
1036 /* deserialize the given s into to as a long long.
1037  * check if the result is actually storeable in the given size number of
1038  * bytes.
1039  */
1040 static gboolean
1041 gst_value_deserialize_int_helper (long long *to, const char *s,
1042     long long min, long long max, int size)
1043 {
1044   gboolean ret = FALSE;
1045   char *end;
1046   long long mask = -1;
1047
1048   errno = 0;
1049   *to = g_ascii_strtoull (s, &end, 0);
1050   /* a range error is a definitive no-no */
1051   if (errno == ERANGE) {
1052     return FALSE;
1053   }
1054
1055   if (*end == 0) {
1056     ret = TRUE;
1057   } else {
1058     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
1059       *to = G_LITTLE_ENDIAN;
1060       ret = TRUE;
1061     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
1062       *to = G_BIG_ENDIAN;
1063       ret = TRUE;
1064     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
1065       *to = G_BYTE_ORDER;
1066       ret = TRUE;
1067     } else if (g_ascii_strcasecmp (s, "min") == 0) {
1068       *to = min;
1069       ret = TRUE;
1070     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1071       *to = max;
1072       ret = TRUE;
1073     }
1074   }
1075   if (ret) {
1076     /* by definition, a long long fits into a long long; so ignore those */
1077     if (size != sizeof (mask)) {
1078       if (*to >= 0) {
1079         /* for positive numbers, we create a mask of 1's outside of the range
1080          * and 0's inside the range.  An and will thus keep only 1 bits
1081          * outside of the range */
1082         mask <<= (size * 8);
1083         if ((mask & *to) != 0) {
1084           ret = FALSE;
1085         }
1086       } else {
1087         /* for negative numbers, we do a 2's complement version */
1088         mask <<= ((size * 8) - 1);
1089         if ((mask & *to) != mask) {
1090           ret = FALSE;
1091         }
1092       }
1093     }
1094   }
1095   return ret;
1096 }
1097
1098 #define CREATE_SERIALIZATION(_type,_macro)                              \
1099 CREATE_SERIALIZATION_START(_type,_macro)                                \
1100                                                                         \
1101 static gboolean                                                         \
1102 gst_value_deserialize_ ## _type (GValue * dest, const char *s)          \
1103 {                                                                       \
1104   long long x;                                                          \
1105                                                                         \
1106   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
1107       G_MAX ## _macro, sizeof (g ## _type))) {                          \
1108     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
1109     return TRUE;                                                        \
1110   } else {                                                              \
1111     return FALSE;                                                       \
1112   }                                                                     \
1113 }
1114
1115 #define CREATE_USERIALIZATION(_type,_macro)                             \
1116 CREATE_SERIALIZATION_START(_type,_macro)                                \
1117                                                                         \
1118 static gboolean                                                         \
1119 gst_value_deserialize_ ## _type (GValue * dest, const char *s)          \
1120 {                                                                       \
1121   guint64 x;                                                            \
1122   char *end;                                                            \
1123   gboolean ret = FALSE;                                                 \
1124                                                                         \
1125   errno = 0;                                                            \
1126   x = g_ascii_strtoull (s, &end, 0);                                    \
1127   /* a range error is a definitive no-no */                             \
1128   if (errno == ERANGE) {                                                \
1129     return FALSE;                                                       \
1130   }                                                                     \
1131   /* the cast ensures the range check later on makes sense */           \
1132   x = (g ## _type) x;                                                   \
1133   if (*end == 0) {                                                      \
1134     ret = TRUE;                                                         \
1135   } else {                                                              \
1136     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
1137       x = G_LITTLE_ENDIAN;                                              \
1138       ret = TRUE;                                                       \
1139     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
1140       x = G_BIG_ENDIAN;                                                 \
1141       ret = TRUE;                                                       \
1142     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
1143       x = G_BYTE_ORDER;                                                 \
1144       ret = TRUE;                                                       \
1145     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
1146       x = 0;                                                            \
1147       ret = TRUE;                                                       \
1148     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
1149       x = G_MAX ## _macro;                                              \
1150       ret = TRUE;                                                       \
1151     }                                                                   \
1152   }                                                                     \
1153   if (ret) {                                                            \
1154     if (x > G_MAX ## _macro) {                                          \
1155       ret = FALSE;                                                      \
1156     } else {                                                            \
1157       g_value_set_ ## _type (dest, x);                                  \
1158     }                                                                   \
1159   }                                                                     \
1160   return ret;                                                           \
1161 }
1162
1163 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
1164 G_STMT_START {                                                          \
1165   static const GstValueTable gst_value = {                              \
1166     _gtype,                                                             \
1167     gst_value_compare_ ## _type,                                        \
1168     gst_value_serialize_ ## _type,                                      \
1169     gst_value_deserialize_ ## _type,                                    \
1170   };                                                                    \
1171                                                                         \
1172   gst_value_register (&gst_value);                                      \
1173 } G_STMT_END
1174
1175 CREATE_SERIALIZATION (int, INT)
1176     CREATE_SERIALIZATION (int64, INT64)
1177     CREATE_SERIALIZATION (long, LONG)
1178 CREATE_USERIALIZATION (uint, UINT)
1179 CREATE_USERIALIZATION (uint64, UINT64)
1180 CREATE_USERIALIZATION (ulong, ULONG)
1181
1182 /**********
1183  * double *
1184  **********/
1185      static int
1186          gst_value_compare_double (const GValue * value1, const GValue * value2)
1187 {
1188   if (value1->data[0].v_double > value2->data[0].v_double)
1189     return GST_VALUE_GREATER_THAN;
1190   if (value1->data[0].v_double < value2->data[0].v_double)
1191     return GST_VALUE_LESS_THAN;
1192   if (value1->data[0].v_double == value2->data[0].v_double)
1193     return GST_VALUE_EQUAL;
1194   return GST_VALUE_UNORDERED;
1195 }
1196
1197 static char *
1198 gst_value_serialize_double (const GValue * value)
1199 {
1200   char d[G_ASCII_DTOSTR_BUF_SIZE];
1201
1202   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1203   return g_strdup (d);
1204 }
1205
1206 static gboolean
1207 gst_value_deserialize_double (GValue * dest, const char *s)
1208 {
1209   double x;
1210   gboolean ret = FALSE;
1211   char *end;
1212
1213   x = g_ascii_strtod (s, &end);
1214   if (*end == 0) {
1215     ret = TRUE;
1216   } else {
1217     if (g_ascii_strcasecmp (s, "min") == 0) {
1218       x = -G_MAXDOUBLE;
1219       ret = TRUE;
1220     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1221       x = G_MAXDOUBLE;
1222       ret = TRUE;
1223     }
1224   }
1225   if (ret) {
1226     g_value_set_double (dest, x);
1227   }
1228   return ret;
1229 }
1230
1231 /*********
1232  * float *
1233  *********/
1234
1235 static int
1236 gst_value_compare_float (const GValue * value1, const GValue * value2)
1237 {
1238   if (value1->data[0].v_float > value2->data[0].v_float)
1239     return GST_VALUE_GREATER_THAN;
1240   if (value1->data[0].v_float < value2->data[0].v_float)
1241     return GST_VALUE_LESS_THAN;
1242   if (value1->data[0].v_float == value2->data[0].v_float)
1243     return GST_VALUE_EQUAL;
1244   return GST_VALUE_UNORDERED;
1245 }
1246
1247 static char *
1248 gst_value_serialize_float (const GValue * value)
1249 {
1250   char d[G_ASCII_DTOSTR_BUF_SIZE];
1251
1252   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
1253   return g_strdup (d);
1254 }
1255
1256 static gboolean
1257 gst_value_deserialize_float (GValue * dest, const char *s)
1258 {
1259   double x;
1260   gboolean ret = FALSE;
1261   char *end;
1262
1263   x = g_ascii_strtod (s, &end);
1264   if (*end == 0) {
1265     ret = TRUE;
1266   } else {
1267     if (g_ascii_strcasecmp (s, "min") == 0) {
1268       x = -G_MAXFLOAT;
1269       ret = TRUE;
1270     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1271       x = G_MAXFLOAT;
1272       ret = TRUE;
1273     }
1274   }
1275   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
1276     ret = FALSE;
1277   if (ret) {
1278     g_value_set_float (dest, x);
1279   }
1280   return ret;
1281 }
1282
1283 /**********
1284  * string *
1285  **********/
1286
1287 static int
1288 gst_value_compare_string (const GValue * value1, const GValue * value2)
1289 {
1290   int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
1291
1292   if (x < 0)
1293     return GST_VALUE_LESS_THAN;
1294   if (x > 0)
1295     return GST_VALUE_GREATER_THAN;
1296   return GST_VALUE_EQUAL;
1297 }
1298
1299 #define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
1300     ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
1301     ((c) == '.'))
1302
1303 static gchar *
1304 gst_string_wrap (const char *s)
1305 {
1306   const gchar *t;
1307   int len;
1308   gchar *d, *e;
1309   gboolean wrap = FALSE;
1310
1311   len = 0;
1312   t = s;
1313   if (!s)
1314     return g_strdup ("");
1315   while (*t) {
1316     if (GST_ASCII_IS_STRING (*t)) {
1317       len++;
1318     } else if (*t < 0x20 || *t >= 0x7f) {
1319       wrap = TRUE;
1320       len += 4;
1321     } else {
1322       wrap = TRUE;
1323       len += 2;
1324     }
1325     t++;
1326   }
1327
1328   if (!wrap)
1329     return g_strdup (s);
1330
1331   e = d = g_malloc (len + 3);
1332
1333   *e++ = '\"';
1334   t = s;
1335   while (*t) {
1336     if (GST_ASCII_IS_STRING (*t)) {
1337       *e++ = *t++;
1338     } else if (*t < 0x20 || *t >= 0x7f) {
1339       *e++ = '\\';
1340       *e++ = '0' + ((*(guchar *) t) >> 6);
1341       *e++ = '0' + (((*t) >> 3) & 0x7);
1342       *e++ = '0' + ((*t++) & 0x7);
1343     } else {
1344       *e++ = '\\';
1345       *e++ = *t++;
1346     }
1347   }
1348   *e++ = '\"';
1349   *e = 0;
1350
1351   return d;
1352 }
1353
1354 /* 
1355  * This function takes a string delimited with double quotes (")
1356  * and unescapes any \xxx octal numbers.
1357  *
1358  * If sequences of \y are found where y is not in the range of
1359  * 0->3, y is copied unescaped.
1360  *
1361  * If \xyy is found where x is an octal number but y is not, an
1362  * error is encountered and NULL is returned.
1363  *
1364  * the input string must be \0 terminated.
1365  */
1366 static char *
1367 gst_string_unwrap (const gchar * s)
1368 {
1369   gchar *ret;
1370   gchar *read, *write;
1371
1372   /* NULL string returns NULL */
1373   if (s == NULL)
1374     return NULL;
1375
1376   /* strings not starting with " are invalid */
1377   if (*s != '"')
1378     return NULL;
1379
1380   /* make copy of original string to hold the result. This
1381    * string will always be smaller than the original */
1382   ret = g_strdup (s);
1383   read = ret;
1384   write = ret;
1385
1386   /* need to move to the next position as we parsed the " */
1387   read++;
1388
1389   while (*read) {
1390     if (GST_ASCII_IS_STRING (*read)) {
1391       /* normal chars are just copied */
1392       *write++ = *read++;
1393     } else if (*read == '"') {
1394       /* quote marks end of string */
1395       break;
1396     } else if (*read == '\\') {
1397       /* got an escape char, move to next position to read a tripplet
1398        * of octal numbers */
1399       read++;
1400       /* is the next char a possible first octal number? */
1401       if (*read >= '0' && *read <= '3') {
1402         /* parse other 2 numbers, if one of them is not in the range of
1403          * an octal number, we error. We also catch the case where a zero
1404          * byte is found here. */
1405         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
1406           goto beach;
1407
1408         /* now convert the octal number to a byte again. */
1409         *write++ = ((read[0] - '0') << 6) +
1410             ((read[1] - '0') << 3) + (read[2] - '0');
1411
1412         read += 3;
1413       } else {
1414         /* if we run into a \0 here, we definately won't get a quote later */
1415         if (*read == 0)
1416           goto beach;
1417
1418         /* else copy \X sequence */
1419         *write++ = *read++;
1420       }
1421     } else {
1422       /* weird character, error */
1423       goto beach;
1424     }
1425   }
1426   /* if the string is not ending in " and zero terminated, we error */
1427   if (*read != '"' || read[1] != '\0')
1428     goto beach;
1429
1430   /* null terminate result string and return */
1431   *write++ = '\0';
1432   return ret;
1433
1434 beach:
1435   g_free (ret);
1436   return NULL;
1437 }
1438
1439 static char *
1440 gst_value_serialize_string (const GValue * value)
1441 {
1442   return gst_string_wrap (value->data[0].v_pointer);
1443 }
1444
1445 static gboolean
1446 gst_value_deserialize_string (GValue * dest, const char *s)
1447 {
1448   if (*s != '"') {
1449     if (!g_utf8_validate (s, -1, NULL))
1450       return FALSE;
1451     g_value_set_string (dest, s);
1452     return TRUE;
1453   } else {
1454     gchar *str = gst_string_unwrap (s);
1455
1456     if (!str)
1457       return FALSE;
1458     g_value_take_string (dest, str);
1459   }
1460
1461   return TRUE;
1462 }
1463
1464 /********
1465  * enum *
1466  ********/
1467
1468 static int
1469 gst_value_compare_enum (const GValue * value1, const GValue * value2)
1470 {
1471   GEnumValue *en1, *en2;
1472   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
1473   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
1474
1475   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
1476   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
1477   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
1478   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
1479   g_type_class_unref (klass1);
1480   g_type_class_unref (klass2);
1481   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
1482   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
1483   if (en1->value < en2->value)
1484     return GST_VALUE_LESS_THAN;
1485   if (en1->value > en2->value)
1486     return GST_VALUE_GREATER_THAN;
1487
1488   return GST_VALUE_EQUAL;
1489 }
1490
1491 static char *
1492 gst_value_serialize_enum (const GValue * value)
1493 {
1494   GEnumValue *en;
1495   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
1496
1497   g_return_val_if_fail (klass, NULL);
1498   en = g_enum_get_value (klass, g_value_get_enum (value));
1499   g_type_class_unref (klass);
1500   g_return_val_if_fail (en, NULL);
1501   return g_strdup (en->value_name);
1502 }
1503
1504 static gboolean
1505 gst_value_deserialize_enum (GValue * dest, const char *s)
1506 {
1507   GEnumValue *en;
1508   gchar *endptr = NULL;
1509   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
1510
1511   g_return_val_if_fail (klass, FALSE);
1512   if (!(en = g_enum_get_value_by_name (klass, s))) {
1513     if (!(en = g_enum_get_value_by_nick (klass, s))) {
1514       gint i = strtol (s, &endptr, 0);
1515
1516       if (endptr && *endptr == '\0') {
1517         en = g_enum_get_value (klass, i);
1518       }
1519     }
1520   }
1521   g_type_class_unref (klass);
1522   g_return_val_if_fail (en, FALSE);
1523   g_value_set_enum (dest, en->value);
1524   return TRUE;
1525 }
1526
1527 /********
1528  * flags *
1529  ********/
1530
1531 /* we just compare the value here */
1532 static int
1533 gst_value_compare_flags (const GValue * value1, const GValue * value2)
1534 {
1535   guint fl1, fl2;
1536   GFlagsClass *klass1 =
1537       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
1538   GFlagsClass *klass2 =
1539       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
1540
1541   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
1542   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
1543   fl1 = g_value_get_flags (value1);
1544   fl2 = g_value_get_flags (value2);
1545   g_type_class_unref (klass1);
1546   g_type_class_unref (klass2);
1547   if (fl1 < fl2)
1548     return GST_VALUE_LESS_THAN;
1549   if (fl1 > fl2)
1550     return GST_VALUE_GREATER_THAN;
1551
1552   return GST_VALUE_EQUAL;
1553 }
1554
1555 /* the different flags are serialized separated with a + */
1556 static char *
1557 gst_value_serialize_flags (const GValue * value)
1558 {
1559   guint flags;
1560   GFlagsValue *fl;
1561   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
1562   gchar *result, *tmp;
1563   gboolean first = TRUE;
1564
1565   g_return_val_if_fail (klass, NULL);
1566
1567   result = g_strdup ("");
1568   flags = g_value_get_flags (value);
1569   while (flags) {
1570     fl = g_flags_get_first_value (klass, flags);
1571     if (fl != NULL) {
1572       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
1573       g_free (result);
1574       result = tmp;
1575       first = FALSE;
1576     }
1577     /* clear flag */
1578     flags &= ~fl->value;
1579   }
1580   g_type_class_unref (klass);
1581
1582   return result;
1583 }
1584
1585 static gboolean
1586 gst_value_deserialize_flags (GValue * dest, const char *s)
1587 {
1588   GFlagsValue *fl;
1589   gchar *endptr = NULL;
1590   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
1591   gchar **split;
1592   guint flags;
1593   gint i;
1594
1595   g_return_val_if_fail (klass, FALSE);
1596
1597   /* split into parts delimited with + */
1598   split = g_strsplit (s, "+", 0);
1599
1600   flags = 0;
1601   i = 0;
1602   /* loop over each part */
1603   while (split[i]) {
1604     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
1605       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
1606         gint val = strtol (split[i], &endptr, 0);
1607
1608         /* just or numeric value */
1609         if (endptr && *endptr == '\0') {
1610           flags |= val;
1611         }
1612       }
1613     }
1614     if (fl) {
1615       flags |= fl->value;
1616     }
1617     i++;
1618   }
1619   g_strfreev (split);
1620   g_type_class_unref (klass);
1621   g_value_set_flags (dest, flags);
1622
1623   return TRUE;
1624 }
1625
1626 /*********
1627  * union *
1628  *********/
1629
1630 static gboolean
1631 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
1632     const GValue * src2)
1633 {
1634   if (src2->data[0].v_int <= src1->data[0].v_int &&
1635       src2->data[1].v_int >= src1->data[0].v_int) {
1636     gst_value_init_and_copy (dest, src2);
1637     return TRUE;
1638   }
1639   return FALSE;
1640 }
1641
1642 static gboolean
1643 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
1644     const GValue * src2)
1645 {
1646   int min;
1647   int max;
1648
1649   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
1650   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
1651
1652   if (min <= max) {
1653     g_value_init (dest, GST_TYPE_INT_RANGE);
1654     gst_value_set_int_range (dest,
1655         MIN (src1->data[0].v_int, src2->data[0].v_int),
1656         MAX (src1->data[1].v_int, src2->data[1].v_int));
1657     return TRUE;
1658   }
1659
1660   return FALSE;
1661 }
1662
1663 /****************
1664  * intersection *
1665  ****************/
1666
1667 static gboolean
1668 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
1669     const GValue * src2)
1670 {
1671   if (src2->data[0].v_int <= src1->data[0].v_int &&
1672       src2->data[1].v_int >= src1->data[0].v_int) {
1673     gst_value_init_and_copy (dest, src1);
1674     return TRUE;
1675   }
1676
1677   return FALSE;
1678 }
1679
1680 static gboolean
1681 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
1682     const GValue * src2)
1683 {
1684   int min;
1685   int max;
1686
1687   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
1688   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
1689
1690   if (min < max) {
1691     g_value_init (dest, GST_TYPE_INT_RANGE);
1692     gst_value_set_int_range (dest, min, max);
1693     return TRUE;
1694   }
1695   if (min == max) {
1696     g_value_init (dest, G_TYPE_INT);
1697     g_value_set_int (dest, min);
1698     return TRUE;
1699   }
1700
1701   return FALSE;
1702 }
1703
1704 static gboolean
1705 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
1706     const GValue * src2)
1707 {
1708   if (src2->data[0].v_double <= src1->data[0].v_double &&
1709       src2->data[1].v_double >= src1->data[0].v_double) {
1710     gst_value_init_and_copy (dest, src1);
1711     return TRUE;
1712   }
1713
1714   return FALSE;
1715 }
1716
1717 static gboolean
1718 gst_value_intersect_double_range_double_range (GValue * dest,
1719     const GValue * src1, const GValue * src2)
1720 {
1721   double min;
1722   double max;
1723
1724   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
1725   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
1726
1727   if (min < max) {
1728     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
1729     gst_value_set_double_range (dest, min, max);
1730     return TRUE;
1731   }
1732   if (min == max) {
1733     g_value_init (dest, G_TYPE_DOUBLE);
1734     g_value_set_int (dest, min);
1735     return TRUE;
1736   }
1737
1738   return FALSE;
1739 }
1740
1741 static gboolean
1742 gst_value_intersect_list (GValue * dest, const GValue * value1,
1743     const GValue * value2)
1744 {
1745   guint i, size;
1746   GValue intersection = { 0, };
1747   gboolean ret = FALSE;
1748
1749   size = gst_value_list_get_size (value1);
1750   for (i = 0; i < size; i++) {
1751     const GValue *cur = gst_value_list_get_value (value1, i);
1752
1753     if (gst_value_intersect (&intersection, cur, value2)) {
1754       /* append value */
1755       if (!ret) {
1756         gst_value_init_and_copy (dest, &intersection);
1757         ret = TRUE;
1758       } else if (GST_VALUE_HOLDS_LIST (dest)) {
1759         gst_value_list_append_value (dest, &intersection);
1760       } else {
1761         GValue temp = { 0, };
1762
1763         gst_value_init_and_copy (&temp, dest);
1764         g_value_unset (dest);
1765         gst_value_list_concat (dest, &temp, &intersection);
1766         g_value_unset (&temp);
1767       }
1768       g_value_unset (&intersection);
1769     }
1770   }
1771
1772   return ret;
1773 }
1774
1775 static gboolean
1776 gst_value_intersect_array (GValue * dest, const GValue * src1,
1777     const GValue * src2)
1778 {
1779   gint size, n;
1780   GValue val = { 0 };
1781
1782   /* only works on similar-sized arrays */
1783   size = gst_value_list_get_size (src1);
1784   if (size != gst_value_list_get_size (src2))
1785     return FALSE;
1786   g_value_init (dest, GST_TYPE_ARRAY);
1787
1788   for (n = 0; n < size; n++) {
1789     if (!gst_value_intersect (&val, gst_value_list_get_value (src1, n),
1790             gst_value_list_get_value (src2, n))) {
1791       g_value_unset (dest);
1792       return FALSE;
1793     }
1794     gst_value_list_append_value (dest, &val);
1795     g_value_unset (&val);
1796   }
1797
1798   return TRUE;
1799 }
1800
1801 /***************
1802  * subtraction *
1803  ***************/
1804
1805 static gboolean
1806 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
1807     const GValue * subtrahend)
1808 {
1809   int min = gst_value_get_int_range_min (subtrahend);
1810   int max = gst_value_get_int_range_max (subtrahend);
1811   int val = g_value_get_int (minuend);
1812
1813   /* subtracting a range from an int only works if the int is not in the
1814    * range */
1815   if (val < min || val > max) {
1816     /* and the result is the int */
1817     gst_value_init_and_copy (dest, minuend);
1818     return TRUE;
1819   }
1820   return FALSE;
1821 }
1822
1823 /* creates a new int range based on input values. 
1824  */
1825 static gboolean
1826 gst_value_create_new_range (GValue * dest, int min1, int max1, int min2,
1827     int max2)
1828 {
1829   GValue v1 = { 0, };
1830   GValue v2 = { 0, };
1831   GValue *pv1, *pv2;            /* yeah, hungarian! */
1832
1833   if (min1 <= max1 && min2 <= max2) {
1834     pv1 = &v1;
1835     pv2 = &v2;
1836   } else if (min1 <= max1) {
1837     pv1 = dest;
1838     pv2 = NULL;
1839   } else if (min2 <= max2) {
1840     pv1 = NULL;
1841     pv2 = dest;
1842   } else {
1843     return FALSE;
1844   }
1845
1846   if (min1 < max1) {
1847     g_value_init (pv1, GST_TYPE_INT_RANGE);
1848     gst_value_set_int_range (pv1, min1, max1);
1849   } else if (min1 == max1) {
1850     g_value_init (pv1, G_TYPE_INT);
1851     g_value_set_int (pv1, min1);
1852   }
1853   if (min2 < max2) {
1854     g_value_init (pv2, GST_TYPE_INT_RANGE);
1855     gst_value_set_int_range (pv2, min2, max2);
1856   } else if (min2 == max2) {
1857     g_value_init (pv2, G_TYPE_INT);
1858     g_value_set_int (pv2, min2);
1859   }
1860
1861   if (min1 <= max1 && min2 <= max2) {
1862     gst_value_list_concat (dest, pv1, pv2);
1863     g_value_unset (pv1);
1864     g_value_unset (pv2);
1865   }
1866   return TRUE;
1867 }
1868
1869 static gboolean
1870 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
1871     const GValue * subtrahend)
1872 {
1873   int min = gst_value_get_int_range_min (minuend);
1874   int max = gst_value_get_int_range_max (minuend);
1875   int val = g_value_get_int (subtrahend);
1876
1877   g_return_val_if_fail (min < max, FALSE);
1878
1879   /* value is outside of the range, return range unchanged */
1880   if (val < min || val > max) {
1881     gst_value_init_and_copy (dest, minuend);
1882     return TRUE;
1883   } else {
1884     /* max must be MAXINT too as val <= max */
1885     if (val == G_MAXINT) {
1886       max--;
1887       val--;
1888     }
1889     /* min must be MININT too as val >= max */
1890     if (val == G_MININT) {
1891       min++;
1892       val++;
1893     }
1894     gst_value_create_new_range (dest, min, val - 1, val + 1, max);
1895   }
1896   return TRUE;
1897 }
1898
1899 static gboolean
1900 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
1901     const GValue * subtrahend)
1902 {
1903   int min1 = gst_value_get_int_range_min (minuend);
1904   int max1 = gst_value_get_int_range_max (minuend);
1905   int min2 = gst_value_get_int_range_min (subtrahend);
1906   int max2 = gst_value_get_int_range_max (subtrahend);
1907
1908   if (max2 == G_MAXINT && min2 == G_MININT) {
1909     return FALSE;
1910   } else if (max2 == G_MAXINT) {
1911     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
1912   } else if (min2 == G_MININT) {
1913     return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
1914   } else {
1915     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
1916         MAX (max2 + 1, min1), max1);
1917   }
1918 }
1919
1920 static gboolean
1921 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
1922     const GValue * subtrahend)
1923 {
1924   double min = gst_value_get_double_range_min (subtrahend);
1925   double max = gst_value_get_double_range_max (subtrahend);
1926   double val = g_value_get_double (minuend);
1927
1928   if (val < min || val > max) {
1929     gst_value_init_and_copy (dest, minuend);
1930     return TRUE;
1931   }
1932   return FALSE;
1933 }
1934
1935 static gboolean
1936 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
1937     const GValue * subtrahend)
1938 {
1939   /* since we don't have open ranges, we cannot create a hole in
1940    * a double range. We return the original range */
1941   gst_value_init_and_copy (dest, minuend);
1942   return TRUE;
1943 }
1944
1945 static gboolean
1946 gst_value_subtract_double_range_double_range (GValue * dest,
1947     const GValue * minuend, const GValue * subtrahend)
1948 {
1949   /* since we don't have open ranges, we have to approximate */
1950   /* done like with ints */
1951   double min1 = gst_value_get_double_range_min (minuend);
1952   double max2 = gst_value_get_double_range_max (minuend);
1953   double max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
1954   double min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
1955   GValue v1 = { 0, };
1956   GValue v2 = { 0, };
1957   GValue *pv1, *pv2;            /* yeah, hungarian! */
1958
1959   if (min1 < max1 && min2 < max2) {
1960     pv1 = &v1;
1961     pv2 = &v2;
1962   } else if (min1 < max1) {
1963     pv1 = dest;
1964     pv2 = NULL;
1965   } else if (min2 < max2) {
1966     pv1 = NULL;
1967     pv2 = dest;
1968   } else {
1969     return FALSE;
1970   }
1971
1972   if (min1 < max1) {
1973     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
1974     gst_value_set_double_range (pv1, min1, max1);
1975   }
1976   if (min2 < max2) {
1977     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
1978     gst_value_set_double_range (pv2, min2, max2);
1979   }
1980
1981   if (min1 < max1 && min2 < max2) {
1982     gst_value_list_concat (dest, pv1, pv2);
1983     g_value_unset (pv1);
1984     g_value_unset (pv2);
1985   }
1986   return TRUE;
1987 }
1988
1989 static gboolean
1990 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
1991     const GValue * subtrahend)
1992 {
1993   guint i, size;
1994   GValue subtraction = { 0, };
1995   gboolean ret = FALSE;
1996
1997   size = gst_value_list_get_size (minuend);
1998   for (i = 0; i < size; i++) {
1999     const GValue *cur = gst_value_list_get_value (minuend, i);
2000
2001     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
2002       if (!ret) {
2003         gst_value_init_and_copy (dest, &subtraction);
2004         ret = TRUE;
2005       } else if (GST_VALUE_HOLDS_LIST (dest)
2006           && GST_VALUE_HOLDS_LIST (&subtraction)) {
2007         /* unroll */
2008         GValue unroll = { 0, };
2009
2010         gst_value_init_and_copy (&unroll, dest);
2011         g_value_unset (dest);
2012         gst_value_list_concat (dest, &unroll, &subtraction);
2013       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2014         gst_value_list_append_value (dest, &subtraction);
2015       } else {
2016         GValue temp = { 0, };
2017
2018         gst_value_init_and_copy (&temp, dest);
2019         g_value_unset (dest);
2020         gst_value_list_concat (dest, &temp, &subtraction);
2021         g_value_unset (&temp);
2022       }
2023       g_value_unset (&subtraction);
2024     }
2025   }
2026   return ret;
2027 }
2028
2029 static gboolean
2030 gst_value_subtract_list (GValue * dest, const GValue * minuend,
2031     const GValue * subtrahend)
2032 {
2033   guint i, size;
2034   GValue data[2] = { {0,}, {0,} };
2035   GValue *subtraction = &data[0], *result = &data[1];
2036
2037   gst_value_init_and_copy (result, minuend);
2038   size = gst_value_list_get_size (subtrahend);
2039   for (i = 0; i < size; i++) {
2040     const GValue *cur = gst_value_list_get_value (subtrahend, i);
2041
2042     if (gst_value_subtract (subtraction, result, cur)) {
2043       GValue *temp = result;
2044
2045       result = subtraction;
2046       subtraction = temp;
2047       g_value_unset (subtraction);
2048     } else {
2049       g_value_unset (result);
2050       return FALSE;
2051     }
2052   }
2053   gst_value_init_and_copy (dest, result);
2054   g_value_unset (result);
2055   return TRUE;
2056 }
2057
2058
2059 /**************
2060  * comparison *
2061  **************/
2062
2063 /**
2064  * gst_value_can_compare:
2065  * @value1: a value to compare
2066  * @value2: another value to compare
2067  *
2068  * Determines if @value1 and @value2 can be compared.
2069  *
2070  * Returns: TRUE if the values can be compared
2071  */
2072 gboolean
2073 gst_value_can_compare (const GValue * value1, const GValue * value2)
2074 {
2075   GstValueTable *table;
2076   int i;
2077
2078   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2079     return FALSE;
2080
2081   for (i = 0; i < gst_value_table->len; i++) {
2082     table = &g_array_index (gst_value_table, GstValueTable, i);
2083     if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
2084       return TRUE;
2085   }
2086
2087   return FALSE;
2088 }
2089
2090 /**
2091  * gst_value_compare:
2092  * @value1: a value to compare
2093  * @value2: another value to compare
2094  *
2095  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
2096  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
2097  * if @value1 is greater than @value2, GST_VALUE_GREATER is returned.
2098  * If @value1 is less than @value2, GST_VALUE_LESSER is returned.
2099  * If the values are equal, GST_VALUE_EQUAL is returned.
2100  *
2101  * Returns: A GstValueCompareType value
2102  */
2103 int
2104 gst_value_compare (const GValue * value1, const GValue * value2)
2105 {
2106   GstValueTable *table, *best = NULL;
2107   int i;
2108
2109   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2110     return GST_VALUE_UNORDERED;
2111
2112   for (i = 0; i < gst_value_table->len; i++) {
2113     table = &g_array_index (gst_value_table, GstValueTable, i);
2114     if (table->type == G_VALUE_TYPE (value1) && table->compare != NULL) {
2115       best = table;
2116       break;
2117     }
2118     if (g_type_is_a (G_VALUE_TYPE (value1), table->type)) {
2119       if (!best || g_type_is_a (table->type, best->type))
2120         best = table;
2121     }
2122   }
2123   if (best) {
2124     return best->compare (value1, value2);
2125   }
2126
2127   g_critical ("unable to compare values of type %s\n",
2128       g_type_name (G_VALUE_TYPE (value1)));
2129   return GST_VALUE_UNORDERED;
2130 }
2131
2132 /* union */
2133
2134 /**
2135  * gst_value_can_union:
2136  * @value1: a value to union
2137  * @value2: another value to union
2138  *
2139  * Determines if @value1 and @value2 can be non-trivially unioned.
2140  * Any two values can be trivially unioned by adding both of them
2141  * to a GstValueList.  However, certain types have the possibility
2142  * to be unioned in a simpler way.  For example, an integer range
2143  * and an integer can be unioned if the integer is a subset of the
2144  * integer range.  If there is the possibility that two values can
2145  * be unioned, this function returns TRUE.
2146  *
2147  * Returns: TRUE if there is a function allowing the two values to
2148  * be unioned.
2149  */
2150 gboolean
2151 gst_value_can_union (const GValue * value1, const GValue * value2)
2152 {
2153   GstValueUnionInfo *union_info;
2154   int i;
2155
2156   for (i = 0; i < gst_value_union_funcs->len; i++) {
2157     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2158     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2159         union_info->type2 == G_VALUE_TYPE (value2))
2160       return TRUE;
2161     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2162         union_info->type2 == G_VALUE_TYPE (value1))
2163       return TRUE;
2164   }
2165
2166   return FALSE;
2167 }
2168
2169 /**
2170  * gst_value_union:
2171  * @dest: the destination value
2172  * @value1: a value to union
2173  * @value2: another value to union
2174  *
2175  * Creates a GValue cooresponding to the union of @value1 and @value2.
2176  *
2177  * Returns: TRUE if the values could be unioned
2178  */
2179 gboolean
2180 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
2181 {
2182   GstValueUnionInfo *union_info;
2183   int i;
2184
2185   for (i = 0; i < gst_value_union_funcs->len; i++) {
2186     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2187     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2188         union_info->type2 == G_VALUE_TYPE (value2)) {
2189       if (union_info->func (dest, value1, value2)) {
2190         return TRUE;
2191       }
2192     }
2193     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2194         union_info->type2 == G_VALUE_TYPE (value1)) {
2195       if (union_info->func (dest, value2, value1)) {
2196         return TRUE;
2197       }
2198     }
2199   }
2200
2201   gst_value_list_concat (dest, value1, value2);
2202   return TRUE;
2203 }
2204
2205 /**
2206  * gst_value_register_union_func:
2207  * @type1: a type to union
2208  * @type2: another type to union
2209  * @func: a function that implments creating a union between the two types
2210  *
2211  * Registers a union function that can create a union between GValues
2212  * of the type @type1 and @type2.
2213  *
2214  */
2215 void
2216 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
2217 {
2218   GstValueUnionInfo union_info;
2219
2220   union_info.type1 = type1;
2221   union_info.type2 = type2;
2222   union_info.func = func;
2223
2224   g_array_append_val (gst_value_union_funcs, union_info);
2225 }
2226
2227 /* intersection */
2228
2229 /**
2230  * gst_value_can_intersect:
2231  * @value1: a value to intersect
2232  * @value2: another value to intersect
2233  *
2234  * Determines if intersecting two values will produce a valid result.
2235  * Two values will produce a valid intersection if they have the same
2236  * type, or if there is a method (registered by
2237  * #gst_value_register_intersection_func) to calculate the intersection.
2238  *
2239  * Returns: TRUE if the values can intersect
2240  */
2241 gboolean
2242 gst_value_can_intersect (const GValue * value1, const GValue * value2)
2243 {
2244   GstValueIntersectInfo *intersect_info;
2245   int i;
2246
2247   /* special cases */
2248   if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
2249     return TRUE;
2250
2251   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2252     intersect_info = &g_array_index (gst_value_intersect_funcs,
2253         GstValueIntersectInfo, i);
2254     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2255         intersect_info->type2 == G_VALUE_TYPE (value2))
2256       if (intersect_info->type2 == G_VALUE_TYPE (value1) &&
2257           intersect_info->type1 == G_VALUE_TYPE (value2))
2258         return TRUE;
2259   }
2260
2261   return gst_value_can_compare (value1, value2);
2262 }
2263
2264 /**
2265  * gst_value_intersect:
2266  * @dest: a uninitialized #GValue that will hold the calculated
2267  * intersection value
2268  * @value1: a value to intersect
2269  * @value2: another value to intersect
2270  *
2271  * Calculates the intersection of two values.  If the values have
2272  * a non-empty intersection, the value representing the intersection
2273  * is placed in @dest.  If the intersection is non-empty, @dest is
2274  * not modified.
2275  *
2276  * Returns: TRUE if the intersection is non-empty
2277  */
2278 gboolean
2279 gst_value_intersect (GValue * dest, const GValue * value1,
2280     const GValue * value2)
2281 {
2282   GstValueIntersectInfo *intersect_info;
2283   int i;
2284   int ret = FALSE;
2285
2286   /* special cases first */
2287   if (GST_VALUE_HOLDS_LIST (value1))
2288     return gst_value_intersect_list (dest, value1, value2);
2289   if (GST_VALUE_HOLDS_LIST (value2))
2290     return gst_value_intersect_list (dest, value2, value1);
2291
2292   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2293     intersect_info = &g_array_index (gst_value_intersect_funcs,
2294         GstValueIntersectInfo, i);
2295     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2296         intersect_info->type2 == G_VALUE_TYPE (value2)) {
2297       ret = intersect_info->func (dest, value1, value2);
2298       return ret;
2299     }
2300     if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
2301         intersect_info->type2 == G_VALUE_TYPE (value1)) {
2302       ret = intersect_info->func (dest, value2, value1);
2303       return ret;
2304     }
2305   }
2306
2307   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
2308     gst_value_init_and_copy (dest, value1);
2309     ret = TRUE;
2310   }
2311
2312   return ret;
2313 }
2314
2315 /**
2316  * gst_value_register_intersection_func:
2317  * @type1: the first type to intersect
2318  * @type2: the second type to intersect
2319  * @func: the intersection function
2320  *
2321  * Registers a function that is called to calculate the intersection
2322  * of the values having the types @type1 and @type2.
2323  */
2324 /**
2325  * GstValueIntersectFunc:
2326  * @dest: a uninitialized #GValue that will hold the calculated
2327  * intersection value
2328  * @value1: a value to intersect
2329  * @value2: another value to intersect
2330  *
2331  * Functions having this type calculate the intersection of @value1
2332  * and @value2.  If the intersection is non-empty, the result is
2333  * placed in @dest and TRUE is returned.  If the intersection is
2334  * empty, @dest is unmodified and FALSE is returned.
2335  *
2336  * Returns: TRUE if the intersection is non-empty, FALSE otherwise
2337  */
2338 void
2339 gst_value_register_intersect_func (GType type1, GType type2,
2340     GstValueIntersectFunc func)
2341 {
2342   GstValueIntersectInfo intersect_info;
2343
2344   intersect_info.type1 = type1;
2345   intersect_info.type2 = type2;
2346   intersect_info.func = func;
2347
2348   g_array_append_val (gst_value_intersect_funcs, intersect_info);
2349 }
2350
2351
2352 /* subtraction */
2353
2354 /**
2355  * gst_value_subtract:
2356  * @dest: the destination value for the result if the subtraction is not empty
2357  * @minuend: the value to subtract from
2358  * @subtrahend: the value to subtract
2359  *
2360  * Subtracts @subtrahend from @minuend and stores the result in @dest.
2361  * Note that this means subtraction as in sets, not as in mathematics.
2362  *
2363  * Returns: TRUE if the subtraction is not empty
2364  */
2365 gboolean
2366 gst_value_subtract (GValue * dest, const GValue * minuend,
2367     const GValue * subtrahend)
2368 {
2369   GstValueSubtractInfo *info;
2370   int i;
2371
2372   /* special cases first */
2373   if (GST_VALUE_HOLDS_LIST (minuend))
2374     return gst_value_subtract_from_list (dest, minuend, subtrahend);
2375   if (GST_VALUE_HOLDS_LIST (subtrahend))
2376     return gst_value_subtract_list (dest, minuend, subtrahend);
2377
2378   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2379     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2380     if (info->minuend == G_VALUE_TYPE (minuend) &&
2381         info->subtrahend == G_VALUE_TYPE (subtrahend)) {
2382       return info->func (dest, minuend, subtrahend);
2383     }
2384   }
2385
2386   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
2387     gst_value_init_and_copy (dest, minuend);
2388     return TRUE;
2389   }
2390
2391   return FALSE;
2392 }
2393
2394 #if 0
2395 gboolean
2396 gst_value_subtract (GValue * dest, const GValue * minuend,
2397     const GValue * subtrahend)
2398 {
2399   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
2400
2401   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
2402       gst_value_serialize (subtrahend),
2403       ret ? gst_value_serialize (dest) : "---");
2404   return ret;
2405 }
2406 #endif
2407
2408 /**
2409  * gst_value_can_subtract:
2410  * @minuend: the value to subtract from
2411  * @subtrahend: the value to subtract
2412  *
2413  * Checks if it's possible to subtract @subtrahend from @minuend.
2414  *
2415  * Returns: TRUE if a subtraction is possible
2416  */
2417 gboolean
2418 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
2419 {
2420   GstValueSubtractInfo *info;
2421   int i;
2422
2423   /* special cases */
2424   if (GST_VALUE_HOLDS_LIST (minuend) || GST_VALUE_HOLDS_LIST (subtrahend))
2425     return TRUE;
2426
2427   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2428     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2429     if (info->minuend == G_VALUE_TYPE (minuend) &&
2430         info->subtrahend == G_VALUE_TYPE (subtrahend))
2431       return TRUE;
2432   }
2433
2434   return gst_value_can_compare (minuend, subtrahend);
2435 }
2436
2437 /**
2438  * gst_value_register_subtract_func:
2439  * @minuend_type: type of the minuend
2440  * @subtrahend_type: type of the subtrahend
2441  * @func: function to use
2442  *
2443  * Registers @func as a function capable of subtracting the values of 
2444  * @subtrahend_type from values of @minuend_type.
2445  */
2446 void
2447 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
2448     GstValueSubtractFunc func)
2449 {
2450   GstValueSubtractInfo info;
2451
2452   /* one type must be unfixed, other subtractions can be done as comparisons */
2453   g_return_if_fail (!gst_type_is_fixed (minuend_type)
2454       || !gst_type_is_fixed (subtrahend_type));
2455
2456   info.minuend = minuend_type;
2457   info.subtrahend = subtrahend_type;
2458   info.func = func;
2459
2460   g_array_append_val (gst_value_subtract_funcs, info);
2461 }
2462
2463 /**
2464  * gst_value_register:
2465  * @table: structure containing functions to register
2466  *
2467  * Registers functions to perform calculations on #GValues of a given
2468  * type.
2469  */
2470 /**
2471  * GstValueTable:
2472  * @type: GType that the functions operate on.
2473  * @compare: A function that compares two values of this type.
2474  * @serialize: A function that transforms a value of this type to a
2475  * string.  Strings created by this function must be unique and should
2476  * be human readable.
2477  * @deserialize: A function that transforms a string to a value of
2478  * this type.  This function must transform strings created by the
2479  * serialize function back to the original value.  This function may
2480  * optionally transform other strings into values.
2481  */
2482 void
2483 gst_value_register (const GstValueTable * table)
2484 {
2485   g_array_append_val (gst_value_table, *table);
2486 }
2487
2488 /**
2489  * gst_value_init_and_copy:
2490  * @dest: the target value
2491  * @src: the source value
2492  *
2493  * Initialises the target value to be of the same type as source and then copies
2494  * the contents from source to target.
2495  */
2496 void
2497 gst_value_init_and_copy (GValue * dest, const GValue * src)
2498 {
2499   g_value_init (dest, G_VALUE_TYPE (src));
2500   g_value_copy (src, dest);
2501 }
2502
2503 /**
2504  * gst_value_serialize:
2505  * @value: a #GValue to serialize
2506  *
2507  * tries to transform the given @value into a string representation that allows
2508  * getting back this string later on using gst_value_deserialize().
2509  *
2510  * Returns: the serialization for @value or NULL if none exists
2511  */
2512 gchar *
2513 gst_value_serialize (const GValue * value)
2514 {
2515   int i;
2516   GValue s_val = { 0 };
2517   GstValueTable *table, *best = NULL;
2518   char *s;
2519
2520   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2521
2522   for (i = 0; i < gst_value_table->len; i++) {
2523     table = &g_array_index (gst_value_table, GstValueTable, i);
2524     if (table->serialize == NULL)
2525       continue;
2526     if (table->type == G_VALUE_TYPE (value)) {
2527       best = table;
2528       break;
2529     }
2530     if (g_type_is_a (G_VALUE_TYPE (value), table->type)) {
2531       if (!best || g_type_is_a (table->type, best->type))
2532         best = table;
2533     }
2534   }
2535   if (best)
2536     return best->serialize (value);
2537
2538   g_value_init (&s_val, G_TYPE_STRING);
2539   if (g_value_transform (value, &s_val)) {
2540     s = gst_string_wrap (g_value_get_string (&s_val));
2541   } else {
2542     s = NULL;
2543   }
2544   g_value_unset (&s_val);
2545
2546   return s;
2547 }
2548
2549 /**
2550  * gst_value_deserialize:
2551  * @dest: #GValue to fill with contents of deserialization
2552  * @src: string to deserialize
2553  *
2554  * Tries to deserialize a string into the type specified by the given GValue.
2555  * If the operation succeeds, TRUE is returned, FALSE otherwise.
2556  *
2557  * Returns: TRUE on success
2558  */
2559 gboolean
2560 gst_value_deserialize (GValue * dest, const gchar * src)
2561 {
2562   GstValueTable *table, *best = NULL;
2563   int i;
2564
2565   g_return_val_if_fail (src != NULL, FALSE);
2566   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
2567
2568   for (i = 0; i < gst_value_table->len; i++) {
2569     table = &g_array_index (gst_value_table, GstValueTable, i);
2570     if (table->serialize == NULL)
2571       continue;
2572
2573     if (table->type == G_VALUE_TYPE (dest)) {
2574       best = table;
2575       break;
2576     }
2577
2578     if (g_type_is_a (G_VALUE_TYPE (dest), table->type)) {
2579       if (!best || g_type_is_a (table->type, best->type))
2580         best = table;
2581     }
2582   }
2583   if (best) {
2584     return best->deserialize (dest, src);
2585   }
2586
2587   return FALSE;
2588 }
2589
2590 /**
2591  * gst_value_is_fixed:
2592  * @value: the #GValue to check
2593  *
2594  * Tests if the given GValue, if available in a GstStructure (or any other
2595  * container) contains a "fixed" (which means: one value) or an "unfixed"
2596  * (which means: multiple possible values, such as data lists or data
2597  * ranges) value.
2598  *
2599  * Returns: true if the value is "fixed".
2600  */
2601
2602 gboolean
2603 gst_value_is_fixed (const GValue * value)
2604 {
2605   GType type = G_VALUE_TYPE (value);
2606
2607   if (type == GST_TYPE_ARRAY) {
2608     gboolean fixed = TRUE;
2609     gint size, n;
2610     const GValue *kid;
2611
2612     /* check recursively */
2613     size = gst_value_list_get_size (value);
2614     for (n = 0; n < size; n++) {
2615       kid = gst_value_list_get_value (value, n);
2616       fixed &= gst_value_is_fixed (kid);
2617     }
2618
2619     return fixed;
2620   }
2621
2622   return gst_type_is_fixed (type);
2623 }
2624
2625 /************
2626  * fraction *
2627  ************/
2628
2629 /* helper functions */
2630
2631 /* Finds the greatest common divisor.
2632  * Returns 1 if none other found.
2633  * This is Euclid's algorithm. */
2634 static gint
2635 gst_greatest_common_divisor (gint a, gint b)
2636 {
2637   while (b != 0) {
2638     int temp = a;
2639
2640     a = b;
2641     b = temp % b;
2642   }
2643
2644   return ABS (a);
2645 }
2646
2647 static void
2648 gst_value_init_fraction (GValue * value)
2649 {
2650   value->data[0].v_int = 0;
2651   value->data[1].v_int = 1;
2652 }
2653
2654 static void
2655 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
2656 {
2657   dest_value->data[0].v_int = src_value->data[0].v_int;
2658   dest_value->data[1].v_int = src_value->data[1].v_int;
2659 }
2660
2661 static gchar *
2662 gst_value_collect_fraction (GValue * value, guint n_collect_values,
2663     GTypeCValue * collect_values, guint collect_flags)
2664 {
2665   value->data[0].v_int = collect_values[0].v_int;
2666   value->data[1].v_int = collect_values[1].v_int;
2667
2668   return NULL;
2669 }
2670
2671 static gchar *
2672 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
2673     GTypeCValue * collect_values, guint collect_flags)
2674 {
2675   gint *numerator = collect_values[0].v_pointer;
2676   gint *denominator = collect_values[1].v_pointer;
2677
2678   if (!numerator)
2679     return g_strdup_printf ("numerator for `%s' passed as NULL",
2680         G_VALUE_TYPE_NAME (value));
2681   if (!denominator)
2682     return g_strdup_printf ("denominator for `%s' passed as NULL",
2683         G_VALUE_TYPE_NAME (value));
2684
2685   *numerator = value->data[0].v_int;
2686   *denominator = value->data[1].v_int;
2687
2688   return NULL;
2689 }
2690
2691 /**
2692  * gst_value_set_fraction:
2693  * @value: a GValue initialized to #GST_TYPE_FRACTION
2694  * @numerator: the numerator of the fraction
2695  * @denominator: the denominator of the fraction
2696  *
2697  * Sets @value to the fraction specified by @numerator over @denominator.
2698  * The fraction gets reduced to the smallest numerator and denominator,
2699  * and if necessary the sign is moved to the numerator.
2700  */
2701 void
2702 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
2703 {
2704   gint gcd = 0;
2705
2706   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
2707   g_return_if_fail (denominator != 0);
2708   g_return_if_fail (denominator >= -G_MAXINT);
2709   g_return_if_fail (numerator >= -G_MAXINT);
2710
2711   /* normalize sign */
2712   if (denominator < 0) {
2713     numerator = -numerator;
2714     denominator = -denominator;
2715   }
2716
2717   /* check for reduction */
2718   gcd = gst_greatest_common_divisor (numerator, denominator);
2719   if (gcd) {
2720     numerator /= gcd;
2721     denominator /= gcd;
2722   }
2723   value->data[0].v_int = numerator;
2724   value->data[1].v_int = denominator;
2725 }
2726
2727 /**
2728  * gst_value_get_fraction_numerator:
2729  * @value: a GValue initialized to #GST_TYPE_FRACTION
2730  *
2731  * Gets the numerator of the fraction specified by @value.
2732  *
2733  * Returns: the numerator of the fraction.
2734  */
2735 int
2736 gst_value_get_fraction_numerator (const GValue * value)
2737 {
2738   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
2739
2740   return value->data[0].v_int;
2741 }
2742
2743 /**
2744  * gst_value_get_fraction_denominator:
2745  * @value: a GValue initialized to #GST_TYPE_FRACTION
2746  *
2747  * Gets the denominator of the fraction specified by @value.
2748  *
2749  * Returns: the denominator of the fraction.
2750  */
2751 int
2752 gst_value_get_fraction_denominator (const GValue * value)
2753 {
2754   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
2755
2756   return value->data[1].v_int;
2757 }
2758
2759 /**
2760  * gst_value_fraction_multiply:
2761  * @product: a GValue initialized to #GST_TYPE_FRACTION
2762  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
2763  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
2764  *
2765  * Multiplies the two GValues containing a GstFraction and sets @product
2766  * to the product of the two fractions.
2767  *
2768  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
2769  */
2770 gboolean
2771 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
2772     const GValue * factor2)
2773 {
2774   gint gcd, n1, n2, d1, d2;
2775
2776   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
2777   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
2778
2779   n1 = factor1->data[0].v_int;
2780   n2 = factor2->data[0].v_int;
2781   d1 = factor1->data[1].v_int;
2782   d2 = factor2->data[1].v_int;
2783
2784   gcd = gst_greatest_common_divisor (n1, d2);
2785   n1 /= gcd;
2786   d2 /= gcd;
2787   gcd = gst_greatest_common_divisor (n2, d1);
2788   n2 /= gcd;
2789   d1 /= gcd;
2790
2791   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (n2), FALSE);
2792   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
2793
2794   gst_value_set_fraction (product, n1 * n2, d1 * d2);
2795
2796   return TRUE;
2797 }
2798
2799 static char *
2800 gst_value_serialize_fraction (const GValue * value)
2801 {
2802   gint32 numerator = value->data[0].v_int;
2803   gint32 denominator = value->data[1].v_int;
2804   gboolean positive = TRUE;
2805
2806   /* get the sign and make components absolute */
2807   if (numerator < 0) {
2808     numerator = -numerator;
2809     positive = !positive;
2810   }
2811   if (denominator < 0) {
2812     denominator = -denominator;
2813     positive = !positive;
2814   }
2815
2816   return g_strdup_printf ("%s%d/%d",
2817       positive ? "" : "-", numerator, denominator);
2818 }
2819
2820 static gboolean
2821 gst_value_deserialize_fraction (GValue * dest, const char *s)
2822 {
2823   gint num, den;
2824   char *div;
2825   char *tmp;
2826
2827   div = strstr (s, "/");
2828   if (!div)
2829     return FALSE;
2830   tmp = g_strndup (s, (size_t) (div - s));
2831   num = atoi (tmp);
2832   g_free (tmp);
2833   den = atoi (div + 1);
2834
2835   gst_value_set_fraction (dest, num, den);
2836
2837   return TRUE;
2838 }
2839
2840 static void
2841 gst_value_transform_fraction_string (const GValue * src_value,
2842     GValue * dest_value)
2843 {
2844   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
2845 }
2846
2847 static void
2848 gst_value_transform_string_fraction (const GValue * src_value,
2849     GValue * dest_value)
2850 {
2851   gst_value_deserialize_fraction (dest_value, src_value->data[0].v_pointer);
2852 }
2853
2854 #define MAX_TERMS       30
2855 #define MIN_DIVISOR     1.0e-10
2856 #define MAX_ERROR       1.0e-20
2857
2858 /* use continued fractions to transform a double into a fraction,
2859  * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
2860  * This algorithm takes care of overflows.
2861  */
2862 static void
2863 gst_value_transform_double_fraction (const GValue * src_value,
2864     GValue * dest_value)
2865 {
2866   gdouble V, F;                 /* double being converted */
2867   gint N, D;                    /* will contain the result */
2868   gint A;                       /* current term in continued fraction */
2869   gint64 N1, D1;                /* numerator, denominator of last approx */
2870   gint64 N2, D2;                /* numerator, denominator of previous approx */
2871   gint i;
2872   gboolean negative = FALSE;
2873
2874   /* initialize fraction being converted */
2875   F = src_value->data[0].v_double;
2876   if (F < 0.0) {
2877     F = -F;
2878     negative = TRUE;
2879   }
2880
2881   V = F;
2882   /* initialize fractions with 1/0, 0/1 */
2883   N1 = 1;
2884   D1 = 0;
2885   N2 = 0;
2886   D2 = 1;
2887   N = 1;
2888   D = 1;
2889
2890   for (i = 0; i < MAX_TERMS; i++) {
2891     /* get next term */
2892     A = floor (F);
2893     /* get new divisor */
2894     F = F - A;
2895
2896     /* calculate new fraction in temp */
2897     N2 = N1 * A + N2;
2898     D2 = D1 * A + D2;
2899
2900     /* guard against overflow */
2901     if (N2 > G_MAXINT || D2 > G_MAXINT) {
2902       break;
2903     }
2904
2905     N = N2;
2906     D = D2;
2907
2908     /* save last two fractions */
2909     N2 = N1;
2910     D2 = D1;
2911     N1 = N;
2912     D1 = D;
2913
2914     /* quit if dividing by zero or close enough to target */
2915     if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
2916       break;
2917     }
2918
2919     /* Take reciprocal */
2920     F = 1 / F;
2921   }
2922   /* fix for overflow */
2923   if (D == 0) {
2924     N = G_MAXINT;
2925     D = 1;
2926   }
2927   /* fix for negative */
2928   if (negative)
2929     N = -N;
2930
2931   /* will also simplify */
2932   gst_value_set_fraction (dest_value, N, D);
2933 }
2934
2935 static void
2936 gst_value_transform_fraction_double (const GValue * src_value,
2937     GValue * dest_value)
2938 {
2939   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
2940       ((double) src_value->data[1].v_int);
2941 }
2942
2943 static int
2944 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
2945 {
2946   gint n1, n2;
2947   gint d1, d2;
2948
2949   gint64 new_num_1;
2950   gint64 new_num_2;
2951
2952   n1 = value1->data[0].v_int;
2953   n2 = value2->data[0].v_int;
2954   d1 = value1->data[1].v_int;
2955   d2 = value2->data[1].v_int;
2956
2957   /* fractions are reduced when set, so we can quickly see if they're equal */
2958   if (n1 == n2 && d1 == d2)
2959     return GST_VALUE_EQUAL;
2960
2961   /* extend to 64 bits */
2962   new_num_1 = ((gint64) n1) * d2;
2963   new_num_2 = ((gint64) n2) * d1;
2964   if (new_num_1 < new_num_2)
2965     return GST_VALUE_LESS_THAN;
2966   if (new_num_1 > new_num_2)
2967     return GST_VALUE_GREATER_THAN;
2968
2969   g_assert_not_reached ();
2970   return GST_VALUE_UNORDERED;
2971 }
2972
2973 void
2974 _gst_value_initialize (void)
2975 {
2976   GTypeInfo info = {
2977     0,
2978     NULL,
2979     NULL,
2980     NULL,
2981     NULL,
2982     NULL,
2983     0,
2984     0,
2985     NULL,
2986     NULL,
2987   };
2988   GTypeFundamentalInfo finfo = {
2989     0
2990   };
2991
2992   //const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
2993
2994   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
2995   gst_value_union_funcs = g_array_new (FALSE, FALSE,
2996       sizeof (GstValueUnionInfo));
2997   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
2998       sizeof (GstValueIntersectInfo));
2999   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
3000       sizeof (GstValueSubtractInfo));
3001
3002   {
3003     static const GTypeValueTable value_table = {
3004       gst_value_init_fourcc,
3005       NULL,
3006       gst_value_copy_fourcc,
3007       NULL,
3008       "i",
3009       gst_value_collect_fourcc,
3010       "p",
3011       gst_value_lcopy_fourcc
3012     };
3013     static GstValueTable gst_value = {
3014       0,
3015       gst_value_compare_fourcc,
3016       gst_value_serialize_fourcc,
3017       gst_value_deserialize_fourcc,
3018     };
3019
3020     info.value_table = &value_table;
3021     gst_type_fourcc = g_type_register_fundamental (g_type_fundamental_next (),
3022         "GstFourcc", &info, &finfo, 0);
3023     gst_value.type = gst_type_fourcc;
3024     gst_value_register (&gst_value);
3025   }
3026
3027   {
3028     static const GTypeValueTable value_table = {
3029       gst_value_init_int_range,
3030       NULL,
3031       gst_value_copy_int_range,
3032       NULL,
3033       "ii",
3034       gst_value_collect_int_range,
3035       "pp",
3036       gst_value_lcopy_int_range
3037     };
3038     static GstValueTable gst_value = {
3039       0,
3040       gst_value_compare_int_range,
3041       gst_value_serialize_int_range,
3042       gst_value_deserialize_int_range,
3043     };
3044
3045     info.value_table = &value_table;
3046     gst_type_int_range =
3047         g_type_register_fundamental (g_type_fundamental_next (), "GstIntRange",
3048         &info, &finfo, 0);
3049     gst_value.type = gst_type_int_range;
3050     gst_value_register (&gst_value);
3051   }
3052
3053   {
3054     static const GTypeValueTable value_table = {
3055       gst_value_init_double_range,
3056       NULL,
3057       gst_value_copy_double_range,
3058       NULL,
3059       "dd",
3060       gst_value_collect_double_range,
3061       "pp",
3062       gst_value_lcopy_double_range
3063     };
3064     static GstValueTable gst_value = {
3065       0,
3066       gst_value_compare_double_range,
3067       gst_value_serialize_double_range,
3068       gst_value_deserialize_double_range,
3069     };
3070
3071     info.value_table = &value_table;
3072     gst_type_double_range =
3073         g_type_register_fundamental (g_type_fundamental_next (),
3074         "GstDoubleRange", &info, &finfo, 0);
3075     gst_value.type = gst_type_double_range;
3076     gst_value_register (&gst_value);
3077   }
3078
3079   {
3080     static const GTypeValueTable value_table = {
3081       gst_value_init_list,
3082       gst_value_free_list,
3083       gst_value_copy_list,
3084       gst_value_list_peek_pointer,
3085       "p",
3086       gst_value_collect_list,
3087       "p",
3088       gst_value_lcopy_list
3089     };
3090     static GstValueTable gst_value = {
3091       0,
3092       gst_value_compare_list,
3093       gst_value_serialize_list,
3094       gst_value_deserialize_list,
3095     };
3096
3097     info.value_table = &value_table;
3098     gst_type_list = g_type_register_fundamental (g_type_fundamental_next (),
3099         "GstValueList", &info, &finfo, 0);
3100     gst_value.type = gst_type_list;
3101     gst_value_register (&gst_value);
3102   }
3103
3104   {
3105     static const GTypeValueTable value_table = {
3106       gst_value_init_list,
3107       gst_value_free_list,
3108       gst_value_copy_list,
3109       gst_value_list_peek_pointer,
3110       "p",
3111       gst_value_collect_list,
3112       "p",
3113       gst_value_lcopy_list
3114     };
3115     static GstValueTable gst_value = {
3116       0,
3117       gst_value_compare_list,
3118       gst_value_serialize_array,
3119       gst_value_deserialize_array,
3120     };
3121
3122     info.value_table = &value_table;
3123     gst_type_array =
3124         g_type_register_fundamental (g_type_fundamental_next (),
3125         "GstValueArray", &info, &finfo, 0);
3126     gst_value.type = gst_type_array;
3127     gst_value_register (&gst_value);
3128   }
3129
3130   {
3131 #if 0
3132     static const GTypeValueTable value_table = {
3133       gst_value_init_buffer,
3134       NULL,
3135       gst_value_copy_buffer,
3136       NULL,
3137       "i",
3138       NULL,                     /*gst_value_collect_buffer, */
3139       "p",
3140       NULL                      /*gst_value_lcopy_buffer */
3141     };
3142 #endif
3143     static GstValueTable gst_value = {
3144       0,
3145       gst_value_compare_buffer,
3146       gst_value_serialize_buffer,
3147       gst_value_deserialize_buffer,
3148     };
3149
3150     gst_value.type = GST_TYPE_BUFFER;
3151     gst_value_register (&gst_value);
3152   }
3153   {
3154     static const GTypeValueTable value_table = {
3155       gst_value_init_fraction,
3156       NULL,
3157       gst_value_copy_fraction,
3158       NULL,
3159       "ii",
3160       gst_value_collect_fraction,
3161       "pp",
3162       gst_value_lcopy_fraction
3163     };
3164     static GstValueTable gst_value = {
3165       0,
3166       gst_value_compare_fraction,
3167       gst_value_serialize_fraction,
3168       gst_value_deserialize_fraction,
3169     };
3170
3171     info.value_table = &value_table;
3172     gst_type_fraction =
3173         g_type_register_fundamental (g_type_fundamental_next (), "GstFraction",
3174         &info, &finfo, 0);
3175     gst_value.type = gst_type_fraction;
3176     gst_value_register (&gst_value);
3177   }
3178   {
3179     static GstValueTable gst_value = {
3180       0,
3181       NULL,
3182       gst_value_serialize_caps,
3183       gst_value_deserialize_caps,
3184     };
3185
3186     gst_value.type = GST_TYPE_CAPS;
3187     gst_value_register (&gst_value);
3188   }
3189
3190
3191   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
3192   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
3193
3194   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
3195   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
3196   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
3197
3198   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
3199
3200   REGISTER_SERIALIZATION (G_TYPE_INT, int);
3201
3202   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
3203   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
3204
3205   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
3206   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
3207   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
3208
3209   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
3210       gst_value_transform_fourcc_string);
3211   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
3212       gst_value_transform_int_range_string);
3213   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
3214       gst_value_transform_double_range_string);
3215   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
3216       gst_value_transform_list_string);
3217   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
3218       gst_value_transform_array_string);
3219   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
3220       gst_value_transform_fraction_string);
3221   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
3222       gst_value_transform_string_fraction);
3223   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
3224       gst_value_transform_fraction_double);
3225   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
3226       gst_value_transform_double_fraction);
3227
3228   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3229       gst_value_intersect_int_int_range);
3230   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3231       gst_value_intersect_int_range_int_range);
3232   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
3233       gst_value_intersect_double_double_range);
3234   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
3235       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
3236   gst_value_register_intersect_func (GST_TYPE_ARRAY,
3237       GST_TYPE_ARRAY, gst_value_intersect_array);
3238
3239   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3240       gst_value_subtract_int_int_range);
3241   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
3242       gst_value_subtract_int_range_int);
3243   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3244       gst_value_subtract_int_range_int_range);
3245   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
3246       gst_value_subtract_double_double_range);
3247   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
3248       gst_value_subtract_double_range_double);
3249   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
3250       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
3251
3252   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3253       gst_value_union_int_int_range);
3254   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3255       gst_value_union_int_range_int_range);
3256 }