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