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