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