value: Fix copy&paste mistakes in the bitmask function docs
[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     if (found) {
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     }
3093     gst_iterator_free (iter);
3094     return found;
3095   }
3096
3097   /* enum name/nick not found */
3098   if (en == NULL)
3099     return FALSE;
3100
3101   g_value_set_enum (dest, en->value);
3102   return TRUE;
3103 }
3104
3105 /********
3106  * flags *
3107  ********/
3108
3109 /* we just compare the value here */
3110 static gint
3111 gst_value_compare_flags (const GValue * value1, const GValue * value2)
3112 {
3113   guint fl1, fl2;
3114   GFlagsClass *klass1 =
3115       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3116   GFlagsClass *klass2 =
3117       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3118
3119   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3120   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3121   fl1 = g_value_get_flags (value1);
3122   fl2 = g_value_get_flags (value2);
3123   g_type_class_unref (klass1);
3124   g_type_class_unref (klass2);
3125   if (fl1 < fl2)
3126     return GST_VALUE_LESS_THAN;
3127   if (fl1 > fl2)
3128     return GST_VALUE_GREATER_THAN;
3129
3130   return GST_VALUE_EQUAL;
3131 }
3132
3133 /* the different flags are serialized separated with a + */
3134 static gchar *
3135 gst_value_serialize_flags (const GValue * value)
3136 {
3137   guint flags;
3138   GFlagsValue *fl;
3139   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
3140   gchar *result, *tmp;
3141   gboolean first = TRUE;
3142
3143   g_return_val_if_fail (klass, NULL);
3144
3145   flags = g_value_get_flags (value);
3146
3147   /* if no flags are set, try to serialize to the _NONE string */
3148   if (!flags) {
3149     fl = g_flags_get_first_value (klass, flags);
3150     if (fl)
3151       return g_strdup (fl->value_name);
3152     else
3153       return g_strdup ("0");
3154   }
3155
3156   /* some flags are set, so serialize one by one */
3157   result = g_strdup ("");
3158   while (flags) {
3159     fl = g_flags_get_first_value (klass, flags);
3160     if (fl != NULL) {
3161       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
3162       g_free (result);
3163       result = tmp;
3164       first = FALSE;
3165
3166       /* clear flag */
3167       flags &= ~fl->value;
3168     }
3169   }
3170   g_type_class_unref (klass);
3171
3172   return result;
3173 }
3174
3175 static gboolean
3176 gst_value_deserialize_flags (GValue * dest, const gchar * s)
3177 {
3178   GFlagsValue *fl;
3179   gchar *endptr = NULL;
3180   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3181   gchar **split;
3182   guint flags;
3183   gint i;
3184
3185   g_return_val_if_fail (klass, FALSE);
3186
3187   /* split into parts delimited with + */
3188   split = g_strsplit (s, "+", 0);
3189
3190   flags = 0;
3191   i = 0;
3192   /* loop over each part */
3193   while (split[i]) {
3194     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
3195       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
3196         gint val = strtol (split[i], &endptr, 0);
3197
3198         /* just or numeric value */
3199         if (endptr && *endptr == '\0') {
3200           flags |= val;
3201         }
3202       }
3203     }
3204     if (fl) {
3205       flags |= fl->value;
3206     }
3207     i++;
3208   }
3209   g_strfreev (split);
3210   g_type_class_unref (klass);
3211   g_value_set_flags (dest, flags);
3212
3213   return TRUE;
3214 }
3215
3216 /****************
3217  * subset *
3218  ****************/
3219
3220 static gboolean
3221 gst_value_is_subset_int_range_int_range (const GValue * value1,
3222     const GValue * value2)
3223 {
3224   gint gcd;
3225
3226   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
3227   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
3228
3229   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
3230       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
3231     return FALSE;
3232   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
3233       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
3234     return FALSE;
3235
3236   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
3237     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
3238         INT_RANGE_STEP (value1))
3239       return FALSE;
3240     return TRUE;
3241   }
3242
3243   gcd =
3244       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
3245       INT_RANGE_STEP (value2));
3246   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
3247     return FALSE;
3248
3249   return TRUE;
3250 }
3251
3252 static gboolean
3253 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
3254     const GValue * value2)
3255 {
3256   gint64 gcd;
3257
3258   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
3259   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
3260
3261   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
3262     return FALSE;
3263   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
3264     return FALSE;
3265
3266   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
3267     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
3268         INT64_RANGE_STEP (value1))
3269       return FALSE;
3270     return TRUE;
3271   }
3272
3273   gcd =
3274       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
3275       INT64_RANGE_STEP (value2));
3276   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
3277     return FALSE;
3278
3279   return TRUE;
3280 }
3281
3282 /**
3283  * gst_value_is_subset:
3284  * @value1: a #GValue
3285  * @value2: a #GValue
3286  *
3287  * Check that @value1 is a subset of @value2.
3288  *
3289  * Return: %TRUE is @value1 is a subset of @value2
3290  */
3291 gboolean
3292 gst_value_is_subset (const GValue * value1, const GValue * value2)
3293 {
3294   /* special case for int/int64 ranges, since we cannot compute
3295      the difference for those when they have different steps,
3296      and it's actually a lot simpler to compute whether a range
3297      is a subset of another. */
3298   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
3299     return gst_value_is_subset_int_range_int_range (value1, value2);
3300   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
3301       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
3302     return gst_value_is_subset_int64_range_int64_range (value1, value2);
3303   }
3304
3305   /*
3306    * 1 - [1,2] = empty
3307    * -> !subset
3308    *
3309    * [1,2] - 1 = 2
3310    *  -> 1 - [1,2] = empty
3311    *  -> subset
3312    *
3313    * [1,3] - [1,2] = 3
3314    * -> [1,2] - [1,3] = empty
3315    * -> subset
3316    *
3317    * {1,2} - {1,3} = 2
3318    * -> {1,3} - {1,2} = 3
3319    * -> !subset
3320    *
3321    *  First caps subtraction needs to return a non-empty set, second
3322    *  subtractions needs to give en empty set.
3323    *  Both substractions are switched below, as it's faster that way.
3324    */
3325   if (!gst_value_subtract (NULL, value1, value2)) {
3326     if (gst_value_subtract (NULL, value2, value1)) {
3327       return TRUE;
3328     }
3329   }
3330   return FALSE;
3331 }
3332
3333 /*********
3334  * union *
3335  *********/
3336
3337 static gboolean
3338 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
3339     const GValue * src2)
3340 {
3341   gint v = src1->data[0].v_int;
3342
3343   /* check if it's already in the range */
3344   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
3345       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
3346       v % INT_RANGE_STEP (src2) == 0) {
3347     if (dest)
3348       gst_value_init_and_copy (dest, src2);
3349     return TRUE;
3350   }
3351
3352   /* check if it extends the range */
3353   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
3354     if (dest) {
3355       gst_value_init_and_copy (dest, src2);
3356       --INT_RANGE_MIN (src2);
3357     }
3358     return TRUE;
3359   }
3360   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
3361     if (dest) {
3362       gst_value_init_and_copy (dest, src2);
3363       ++INT_RANGE_MAX (src2);
3364     }
3365     return TRUE;
3366   }
3367
3368   return FALSE;
3369 }
3370
3371 static gboolean
3372 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
3373     const GValue * src2)
3374 {
3375   /* We can union in several special cases:
3376      1 - one is a subset of another
3377      2 - same step and not disjoint
3378      3 - different step, at least one with one value which matches a 'next' or 'previous'
3379      - anything else ?
3380    */
3381
3382   /* 1 - subset */
3383   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
3384     if (dest)
3385       gst_value_init_and_copy (dest, src2);
3386     return TRUE;
3387   }
3388   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
3389     if (dest)
3390       gst_value_init_and_copy (dest, src1);
3391     return TRUE;
3392   }
3393
3394   /* 2 - same step and not disjoint */
3395   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
3396     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
3397             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
3398         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
3399             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
3400       if (dest) {
3401         gint step = INT_RANGE_STEP (src1);
3402         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
3403         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
3404         g_value_init (dest, GST_TYPE_INT_RANGE);
3405         gst_value_set_int_range_step (dest, min, max, step);
3406       }
3407       return TRUE;
3408     }
3409   }
3410
3411   /* 3 - single value matches next or previous */
3412   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
3413     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
3414     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
3415     if (n1 == 1 || n2 == 1) {
3416       const GValue *range_value = NULL;
3417       gint scalar = 0;
3418       if (n1 == 1) {
3419         range_value = src2;
3420         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
3421       } else if (n2 == 1) {
3422         range_value = src1;
3423         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
3424       }
3425
3426       if (scalar ==
3427           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
3428         if (dest) {
3429           gst_value_init_and_copy (dest, range_value);
3430           --INT_RANGE_MIN (range_value);
3431         }
3432         return TRUE;
3433       } else if (scalar ==
3434           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
3435         if (dest) {
3436           gst_value_init_and_copy (dest, range_value);
3437           ++INT_RANGE_MIN (range_value);
3438         }
3439         return TRUE;
3440       }
3441     }
3442   }
3443
3444   /* If we get there, we did not find a way to make a union that can be
3445      represented with our simplistic model. */
3446   return FALSE;
3447 }
3448
3449 /****************
3450  * intersection *
3451  ****************/
3452
3453 static gboolean
3454 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
3455     const GValue * src2)
3456 {
3457   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
3458       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
3459       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
3460     if (dest)
3461       gst_value_init_and_copy (dest, src1);
3462     return TRUE;
3463   }
3464
3465   return FALSE;
3466 }
3467
3468 static gboolean
3469 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
3470     const GValue * src2)
3471 {
3472   gint min;
3473   gint max;
3474   gint step;
3475
3476   step =
3477       INT_RANGE_STEP (src1) /
3478       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
3479       INT_RANGE_STEP (src2));
3480   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
3481     return FALSE;
3482   step *= INT_RANGE_STEP (src2);
3483
3484   min =
3485       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
3486       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3487   min = (min + step - 1) / step * step;
3488   max =
3489       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
3490       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3491   max = max / step * step;
3492
3493   if (min < max) {
3494     if (dest) {
3495       g_value_init (dest, GST_TYPE_INT_RANGE);
3496       gst_value_set_int_range_step (dest, min, max, step);
3497     }
3498     return TRUE;
3499   }
3500   if (min == max) {
3501     if (dest) {
3502       g_value_init (dest, G_TYPE_INT);
3503       g_value_set_int (dest, min);
3504     }
3505     return TRUE;
3506   }
3507
3508   return FALSE;
3509 }
3510
3511 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
3512 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
3513
3514 static gboolean
3515 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
3516     const GValue * src2)
3517 {
3518   if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
3519       INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
3520       src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
3521     if (dest)
3522       gst_value_init_and_copy (dest, src1);
3523     return TRUE;
3524   }
3525
3526   return FALSE;
3527 }
3528
3529 static gboolean
3530 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
3531     const GValue * src2)
3532 {
3533   gint64 min;
3534   gint64 max;
3535   gint64 step;
3536
3537   step =
3538       INT64_RANGE_STEP (src1) /
3539       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
3540       INT64_RANGE_STEP (src2));
3541   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
3542     return FALSE;
3543   step *= INT64_RANGE_STEP (src2);
3544
3545   min =
3546       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
3547       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
3548   min = (min + step - 1) / step * step;
3549   max =
3550       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
3551       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
3552   max = max / step * step;
3553
3554   if (min < max) {
3555     if (dest) {
3556       g_value_init (dest, GST_TYPE_INT64_RANGE);
3557       gst_value_set_int64_range_step (dest, min, max, step);
3558     }
3559     return TRUE;
3560   }
3561   if (min == max) {
3562     if (dest) {
3563       g_value_init (dest, G_TYPE_INT64);
3564       g_value_set_int64 (dest, min);
3565     }
3566     return TRUE;
3567   }
3568
3569   return FALSE;
3570 }
3571
3572 static gboolean
3573 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
3574     const GValue * src2)
3575 {
3576   if (src2->data[0].v_double <= src1->data[0].v_double &&
3577       src2->data[1].v_double >= src1->data[0].v_double) {
3578     if (dest)
3579       gst_value_init_and_copy (dest, src1);
3580     return TRUE;
3581   }
3582
3583   return FALSE;
3584 }
3585
3586 static gboolean
3587 gst_value_intersect_double_range_double_range (GValue * dest,
3588     const GValue * src1, const GValue * src2)
3589 {
3590   gdouble min;
3591   gdouble max;
3592
3593   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
3594   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
3595
3596   if (min < max) {
3597     if (dest) {
3598       g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
3599       gst_value_set_double_range (dest, min, max);
3600     }
3601     return TRUE;
3602   }
3603   if (min == max) {
3604     if (dest) {
3605       g_value_init (dest, G_TYPE_DOUBLE);
3606       g_value_set_int (dest, (int) min);
3607     }
3608     return TRUE;
3609   }
3610
3611   return FALSE;
3612 }
3613
3614 static gboolean
3615 gst_value_intersect_list (GValue * dest, const GValue * value1,
3616     const GValue * value2)
3617 {
3618   guint i, size;
3619   GValue intersection = { 0, };
3620   gboolean ret = FALSE;
3621
3622   size = VALUE_LIST_SIZE (value1);
3623   for (i = 0; i < size; i++) {
3624     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
3625
3626     /* quicker version when we don't need the resulting set */
3627     if (!dest) {
3628       if (gst_value_intersect (NULL, cur, value2)) {
3629         ret = TRUE;
3630         break;
3631       }
3632       continue;
3633     }
3634
3635     if (gst_value_intersect (&intersection, cur, value2)) {
3636       /* append value */
3637       if (!ret) {
3638         gst_value_move (dest, &intersection);
3639         ret = TRUE;
3640       } else if (GST_VALUE_HOLDS_LIST (dest)) {
3641         _gst_value_list_append_and_take_value (dest, &intersection);
3642       } else {
3643         GValue temp;
3644
3645         gst_value_move (&temp, dest);
3646         gst_value_list_merge (dest, &temp, &intersection);
3647         g_value_unset (&temp);
3648         g_value_unset (&intersection);
3649       }
3650     }
3651   }
3652
3653   return ret;
3654 }
3655
3656 static gboolean
3657 gst_value_intersect_array (GValue * dest, const GValue * src1,
3658     const GValue * src2)
3659 {
3660   guint size;
3661   guint n;
3662   GValue val = { 0 };
3663
3664   /* only works on similar-sized arrays */
3665   size = gst_value_array_get_size (src1);
3666   if (size != gst_value_array_get_size (src2))
3667     return FALSE;
3668
3669   /* quicker value when we don't need the resulting set */
3670   if (!dest) {
3671     for (n = 0; n < size; n++) {
3672       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
3673               gst_value_array_get_value (src2, n))) {
3674         return FALSE;
3675       }
3676     }
3677     return TRUE;
3678   }
3679
3680   g_value_init (dest, GST_TYPE_ARRAY);
3681
3682   for (n = 0; n < size; n++) {
3683     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
3684             gst_value_array_get_value (src2, n))) {
3685       g_value_unset (dest);
3686       return FALSE;
3687     }
3688     _gst_value_array_append_and_take_value (dest, &val);
3689   }
3690
3691   return TRUE;
3692 }
3693
3694 static gboolean
3695 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
3696     const GValue * src2)
3697 {
3698   gint res1, res2;
3699   GValue *vals;
3700   GstValueCompareFunc compare;
3701
3702   vals = src2->data[0].v_pointer;
3703
3704   if (vals == NULL)
3705     return FALSE;
3706
3707   if ((compare = gst_value_get_compare_func (src1))) {
3708     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
3709     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
3710
3711     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
3712         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
3713       if (dest)
3714         gst_value_init_and_copy (dest, src1);
3715       return TRUE;
3716     }
3717   }
3718
3719   return FALSE;
3720 }
3721
3722 static gboolean
3723 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
3724     const GValue * src1, const GValue * src2)
3725 {
3726   GValue *min;
3727   GValue *max;
3728   gint res;
3729   GValue *vals1, *vals2;
3730   GstValueCompareFunc compare;
3731
3732   vals1 = src1->data[0].v_pointer;
3733   vals2 = src2->data[0].v_pointer;
3734   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
3735
3736   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
3737     /* min = MAX (src1.start, src2.start) */
3738     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
3739     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3740     if (res == GST_VALUE_LESS_THAN)
3741       min = &vals2[0];          /* Take the max of the 2 */
3742     else
3743       min = &vals1[0];
3744
3745     /* max = MIN (src1.end, src2.end) */
3746     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
3747     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3748     if (res == GST_VALUE_GREATER_THAN)
3749       max = &vals2[1];          /* Take the min of the 2 */
3750     else
3751       max = &vals1[1];
3752
3753     res = gst_value_compare_with_func (min, max, compare);
3754     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3755     if (res == GST_VALUE_LESS_THAN) {
3756       if (dest) {
3757         g_value_init (dest, GST_TYPE_FRACTION_RANGE);
3758         vals1 = dest->data[0].v_pointer;
3759         g_value_copy (min, &vals1[0]);
3760         g_value_copy (max, &vals1[1]);
3761       }
3762       return TRUE;
3763     }
3764     if (res == GST_VALUE_EQUAL) {
3765       if (dest)
3766         gst_value_init_and_copy (dest, min);
3767       return TRUE;
3768     }
3769   }
3770
3771   return FALSE;
3772 }
3773
3774 /***************
3775  * subtraction *
3776  ***************/
3777
3778 static gboolean
3779 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
3780     const GValue * subtrahend)
3781 {
3782   gint min = gst_value_get_int_range_min (subtrahend);
3783   gint max = gst_value_get_int_range_max (subtrahend);
3784   gint step = gst_value_get_int_range_step (subtrahend);
3785   gint val = g_value_get_int (minuend);
3786
3787   /* subtracting a range from an int only works if the int is not in the
3788    * range */
3789   if (val < min || val > max || val % step) {
3790     /* and the result is the int */
3791     if (dest)
3792       gst_value_init_and_copy (dest, minuend);
3793     return TRUE;
3794   }
3795   return FALSE;
3796 }
3797
3798 /* creates a new int range based on input values.
3799  */
3800 static gboolean
3801 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
3802     gint max2, gint step)
3803 {
3804   GValue v1 = { 0, };
3805   GValue v2 = { 0, };
3806   GValue *pv1, *pv2;            /* yeah, hungarian! */
3807
3808   g_return_val_if_fail (step > 0, FALSE);
3809   g_return_val_if_fail (min1 % step == 0, FALSE);
3810   g_return_val_if_fail (max1 % step == 0, FALSE);
3811   g_return_val_if_fail (min2 % step == 0, FALSE);
3812   g_return_val_if_fail (max2 % step == 0, FALSE);
3813
3814   if (min1 <= max1 && min2 <= max2) {
3815     pv1 = &v1;
3816     pv2 = &v2;
3817   } else if (min1 <= max1) {
3818     pv1 = dest;
3819     pv2 = NULL;
3820   } else if (min2 <= max2) {
3821     pv1 = NULL;
3822     pv2 = dest;
3823   } else {
3824     return FALSE;
3825   }
3826
3827   if (!dest)
3828     return TRUE;
3829
3830   if (min1 < max1) {
3831     g_value_init (pv1, GST_TYPE_INT_RANGE);
3832     gst_value_set_int_range_step (pv1, min1, max1, step);
3833   } else if (min1 == max1) {
3834     g_value_init (pv1, G_TYPE_INT);
3835     g_value_set_int (pv1, min1);
3836   }
3837   if (min2 < max2) {
3838     g_value_init (pv2, GST_TYPE_INT_RANGE);
3839     gst_value_set_int_range_step (pv2, min2, max2, step);
3840   } else if (min2 == max2) {
3841     g_value_init (pv2, G_TYPE_INT);
3842     g_value_set_int (pv2, min2);
3843   }
3844
3845   if (min1 <= max1 && min2 <= max2) {
3846     gst_value_list_concat (dest, pv1, pv2);
3847     g_value_unset (pv1);
3848     g_value_unset (pv2);
3849   }
3850   return TRUE;
3851 }
3852
3853 static gboolean
3854 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
3855     const GValue * subtrahend)
3856 {
3857   gint min = gst_value_get_int_range_min (minuend);
3858   gint max = gst_value_get_int_range_max (minuend);
3859   gint step = gst_value_get_int_range_step (minuend);
3860   gint val = g_value_get_int (subtrahend);
3861
3862   g_return_val_if_fail (min < max, FALSE);
3863
3864   /* value is outside of the range, return range unchanged */
3865   if (val < min || val > max || val % step) {
3866     if (dest)
3867       gst_value_init_and_copy (dest, minuend);
3868     return TRUE;
3869   } else {
3870     /* max must be MAXINT too as val <= max */
3871     if (val >= G_MAXINT - step + 1) {
3872       max -= step;
3873       val -= step;
3874     }
3875     /* min must be MININT too as val >= max */
3876     if (val <= G_MININT + step - 1) {
3877       min += step;
3878       val += step;
3879     }
3880     if (dest)
3881       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
3882   }
3883   return TRUE;
3884 }
3885
3886 static gboolean
3887 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
3888     const GValue * subtrahend)
3889 {
3890   gint min1 = gst_value_get_int_range_min (minuend);
3891   gint max1 = gst_value_get_int_range_max (minuend);
3892   gint step1 = gst_value_get_int_range_step (minuend);
3893   gint min2 = gst_value_get_int_range_min (subtrahend);
3894   gint max2 = gst_value_get_int_range_max (subtrahend);
3895   gint step2 = gst_value_get_int_range_step (subtrahend);
3896   gint step;
3897
3898   if (step1 != step2) {
3899     /* ENOIMPL */
3900     g_assert (FALSE);
3901     return FALSE;
3902   }
3903   step = step1;
3904
3905   if (max2 >= max1 && min2 <= min1) {
3906     return FALSE;
3907   } else if (max2 >= max1) {
3908     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3909         step, 0, step);
3910   } else if (min2 <= min1) {
3911     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
3912         step, 0, step);
3913   } else {
3914     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3915         MAX (max2 + step, min1), max1, step);
3916   }
3917 }
3918
3919 static gboolean
3920 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
3921     const GValue * subtrahend)
3922 {
3923   gint64 min = gst_value_get_int64_range_min (subtrahend);
3924   gint64 max = gst_value_get_int64_range_max (subtrahend);
3925   gint64 step = gst_value_get_int64_range_step (subtrahend);
3926   gint64 val = g_value_get_int64 (minuend);
3927
3928   /* subtracting a range from an int64 only works if the int64 is not in the
3929    * range */
3930   if (val < min || val > max || val % step) {
3931     /* and the result is the int64 */
3932     if (dest)
3933       gst_value_init_and_copy (dest, minuend);
3934     return TRUE;
3935   }
3936   return FALSE;
3937 }
3938
3939 /* creates a new int64 range based on input values.
3940  */
3941 static gboolean
3942 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
3943     gint64 min2, gint64 max2, gint64 step)
3944 {
3945   GValue v1 = { 0, };
3946   GValue v2 = { 0, };
3947   GValue *pv1, *pv2;            /* yeah, hungarian! */
3948
3949   g_return_val_if_fail (step > 0, FALSE);
3950   g_return_val_if_fail (min1 % step == 0, FALSE);
3951   g_return_val_if_fail (max1 % step == 0, FALSE);
3952   g_return_val_if_fail (min2 % step == 0, FALSE);
3953   g_return_val_if_fail (max2 % step == 0, FALSE);
3954
3955   if (min1 <= max1 && min2 <= max2) {
3956     pv1 = &v1;
3957     pv2 = &v2;
3958   } else if (min1 <= max1) {
3959     pv1 = dest;
3960     pv2 = NULL;
3961   } else if (min2 <= max2) {
3962     pv1 = NULL;
3963     pv2 = dest;
3964   } else {
3965     return FALSE;
3966   }
3967
3968   if (!dest)
3969     return TRUE;
3970
3971   if (min1 < max1) {
3972     g_value_init (pv1, GST_TYPE_INT64_RANGE);
3973     gst_value_set_int64_range_step (pv1, min1, max1, step);
3974   } else if (min1 == max1) {
3975     g_value_init (pv1, G_TYPE_INT64);
3976     g_value_set_int64 (pv1, min1);
3977   }
3978   if (min2 < max2) {
3979     g_value_init (pv2, GST_TYPE_INT64_RANGE);
3980     gst_value_set_int64_range_step (pv2, min2, max2, step);
3981   } else if (min2 == max2) {
3982     g_value_init (pv2, G_TYPE_INT64);
3983     g_value_set_int64 (pv2, min2);
3984   }
3985
3986   if (min1 <= max1 && min2 <= max2) {
3987     gst_value_list_concat (dest, pv1, pv2);
3988     g_value_unset (pv1);
3989     g_value_unset (pv2);
3990   }
3991   return TRUE;
3992 }
3993
3994 static gboolean
3995 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
3996     const GValue * subtrahend)
3997 {
3998   gint64 min = gst_value_get_int64_range_min (minuend);
3999   gint64 max = gst_value_get_int64_range_max (minuend);
4000   gint64 step = gst_value_get_int64_range_step (minuend);
4001   gint64 val = g_value_get_int64 (subtrahend);
4002
4003   g_return_val_if_fail (min < max, FALSE);
4004
4005   /* value is outside of the range, return range unchanged */
4006   if (val < min || val > max || val % step) {
4007     if (dest)
4008       gst_value_init_and_copy (dest, minuend);
4009     return TRUE;
4010   } else {
4011     /* max must be MAXINT64 too as val <= max */
4012     if (val >= G_MAXINT64 - step + 1) {
4013       max -= step;
4014       val -= step;
4015     }
4016     /* min must be MININT64 too as val >= max */
4017     if (val <= G_MININT64 + step - 1) {
4018       min += step;
4019       val += step;
4020     }
4021     if (dest)
4022       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
4023           step);
4024   }
4025   return TRUE;
4026 }
4027
4028 static gboolean
4029 gst_value_subtract_int64_range_int64_range (GValue * dest,
4030     const GValue * minuend, const GValue * subtrahend)
4031 {
4032   gint64 min1 = gst_value_get_int64_range_min (minuend);
4033   gint64 max1 = gst_value_get_int64_range_max (minuend);
4034   gint64 step1 = gst_value_get_int64_range_step (minuend);
4035   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
4036   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
4037   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
4038   gint64 step;
4039
4040   if (step1 != step2) {
4041     /* ENOIMPL */
4042     g_assert (FALSE);
4043     return FALSE;
4044   }
4045   step = step1;
4046
4047   if (max2 >= max1 && min2 <= min1) {
4048     return FALSE;
4049   } else if (max2 >= max1) {
4050     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4051             max1), step, 0, step);
4052   } else if (min2 <= min1) {
4053     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
4054         max1, step, 0, step);
4055   } else {
4056     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4057             max1), MAX (max2 + step, min1), max1, step);
4058   }
4059 }
4060
4061 static gboolean
4062 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
4063     const GValue * subtrahend)
4064 {
4065   gdouble min = gst_value_get_double_range_min (subtrahend);
4066   gdouble max = gst_value_get_double_range_max (subtrahend);
4067   gdouble val = g_value_get_double (minuend);
4068
4069   if (val < min || val > max) {
4070     if (dest)
4071       gst_value_init_and_copy (dest, minuend);
4072     return TRUE;
4073   }
4074   return FALSE;
4075 }
4076
4077 static gboolean
4078 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
4079     const GValue * subtrahend)
4080 {
4081   /* since we don't have open ranges, we cannot create a hole in
4082    * a double range. We return the original range */
4083   if (dest)
4084     gst_value_init_and_copy (dest, minuend);
4085   return TRUE;
4086 }
4087
4088 static gboolean
4089 gst_value_subtract_double_range_double_range (GValue * dest,
4090     const GValue * minuend, const GValue * subtrahend)
4091 {
4092   /* since we don't have open ranges, we have to approximate */
4093   /* done like with ints */
4094   gdouble min1 = gst_value_get_double_range_min (minuend);
4095   gdouble max2 = gst_value_get_double_range_max (minuend);
4096   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
4097   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
4098   GValue v1 = { 0, };
4099   GValue v2 = { 0, };
4100   GValue *pv1, *pv2;            /* yeah, hungarian! */
4101
4102   if (min1 < max1 && min2 < max2) {
4103     pv1 = &v1;
4104     pv2 = &v2;
4105   } else if (min1 < max1) {
4106     pv1 = dest;
4107     pv2 = NULL;
4108   } else if (min2 < max2) {
4109     pv1 = NULL;
4110     pv2 = dest;
4111   } else {
4112     return FALSE;
4113   }
4114
4115   if (!dest)
4116     return TRUE;
4117
4118   if (min1 < max1) {
4119     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
4120     gst_value_set_double_range (pv1, min1, max1);
4121   }
4122   if (min2 < max2) {
4123     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
4124     gst_value_set_double_range (pv2, min2, max2);
4125   }
4126
4127   if (min1 < max1 && min2 < max2) {
4128     gst_value_list_concat (dest, pv1, pv2);
4129     g_value_unset (pv1);
4130     g_value_unset (pv2);
4131   }
4132   return TRUE;
4133 }
4134
4135 static gboolean
4136 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
4137     const GValue * subtrahend)
4138 {
4139   guint i, size;
4140   GValue subtraction = { 0, };
4141   gboolean ret = FALSE;
4142   GType ltype;
4143
4144   ltype = gst_value_list_get_type ();
4145
4146   size = VALUE_LIST_SIZE (minuend);
4147   for (i = 0; i < size; i++) {
4148     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
4149
4150     /* quicker version when we can discard the result */
4151     if (!dest) {
4152       if (gst_value_subtract (NULL, cur, subtrahend)) {
4153         ret = TRUE;
4154         break;
4155       }
4156       continue;
4157     }
4158
4159     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
4160       if (!ret) {
4161         gst_value_move (dest, &subtraction);
4162         ret = TRUE;
4163       } else if (G_VALUE_HOLDS (dest, ltype)
4164           && !G_VALUE_HOLDS (&subtraction, ltype)) {
4165         _gst_value_list_append_and_take_value (dest, &subtraction);
4166       } else {
4167         GValue temp;
4168
4169         gst_value_move (&temp, dest);
4170         gst_value_list_concat (dest, &temp, &subtraction);
4171         g_value_unset (&temp);
4172         g_value_unset (&subtraction);
4173       }
4174     }
4175   }
4176   return ret;
4177 }
4178
4179 static gboolean
4180 gst_value_subtract_list (GValue * dest, const GValue * minuend,
4181     const GValue * subtrahend)
4182 {
4183   guint i, size;
4184   GValue data[2] = { {0,}, {0,} };
4185   GValue *subtraction = &data[0], *result = &data[1];
4186
4187   gst_value_init_and_copy (result, minuend);
4188   size = VALUE_LIST_SIZE (subtrahend);
4189   for (i = 0; i < size; i++) {
4190     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
4191
4192     if (gst_value_subtract (subtraction, result, cur)) {
4193       GValue *temp = result;
4194
4195       result = subtraction;
4196       subtraction = temp;
4197       g_value_unset (subtraction);
4198     } else {
4199       g_value_unset (result);
4200       return FALSE;
4201     }
4202   }
4203   if (dest) {
4204     gst_value_move (dest, result);
4205   } else {
4206     g_value_unset (result);
4207   }
4208   return TRUE;
4209 }
4210
4211 static gboolean
4212 gst_value_subtract_fraction_fraction_range (GValue * dest,
4213     const GValue * minuend, const GValue * subtrahend)
4214 {
4215   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
4216   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
4217   GstValueCompareFunc compare;
4218
4219   if ((compare = gst_value_get_compare_func (minuend))) {
4220     /* subtracting a range from an fraction only works if the fraction
4221      * is not in the range */
4222     if (gst_value_compare_with_func (minuend, min, compare) ==
4223         GST_VALUE_LESS_THAN ||
4224         gst_value_compare_with_func (minuend, max, compare) ==
4225         GST_VALUE_GREATER_THAN) {
4226       /* and the result is the value */
4227       if (dest)
4228         gst_value_init_and_copy (dest, minuend);
4229       return TRUE;
4230     }
4231   }
4232   return FALSE;
4233 }
4234
4235 static gboolean
4236 gst_value_subtract_fraction_range_fraction (GValue * dest,
4237     const GValue * minuend, const GValue * subtrahend)
4238 {
4239   /* since we don't have open ranges, we cannot create a hole in
4240    * a range. We return the original range */
4241   if (dest)
4242     gst_value_init_and_copy (dest, minuend);
4243   return TRUE;
4244 }
4245
4246 static gboolean
4247 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
4248     const GValue * minuend, const GValue * subtrahend)
4249 {
4250   /* since we don't have open ranges, we have to approximate */
4251   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
4252   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
4253   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
4254   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
4255   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
4256   gint cmp1, cmp2;
4257   GValue v1 = { 0, };
4258   GValue v2 = { 0, };
4259   GValue *pv1, *pv2;            /* yeah, hungarian! */
4260   GstValueCompareFunc compare;
4261
4262   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
4263   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
4264
4265   compare = gst_value_get_compare_func (min1);
4266   g_return_val_if_fail (compare, FALSE);
4267
4268   cmp1 = gst_value_compare_with_func (max2, max1, compare);
4269   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4270   if (cmp1 == GST_VALUE_LESS_THAN)
4271     max1 = max2;
4272   cmp1 = gst_value_compare_with_func (min1, min2, compare);
4273   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4274   if (cmp1 == GST_VALUE_GREATER_THAN)
4275     min2 = min1;
4276
4277   cmp1 = gst_value_compare_with_func (min1, max1, compare);
4278   cmp2 = gst_value_compare_with_func (min2, max2, compare);
4279
4280   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4281     pv1 = &v1;
4282     pv2 = &v2;
4283   } else if (cmp1 == GST_VALUE_LESS_THAN) {
4284     pv1 = dest;
4285     pv2 = NULL;
4286   } else if (cmp2 == GST_VALUE_LESS_THAN) {
4287     pv1 = NULL;
4288     pv2 = dest;
4289   } else {
4290     return FALSE;
4291   }
4292
4293   if (!dest)
4294     return TRUE;
4295
4296   if (cmp1 == GST_VALUE_LESS_THAN) {
4297     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
4298     gst_value_set_fraction_range (pv1, min1, max1);
4299   }
4300   if (cmp2 == GST_VALUE_LESS_THAN) {
4301     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
4302     gst_value_set_fraction_range (pv2, min2, max2);
4303   }
4304
4305   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4306     gst_value_list_concat (dest, pv1, pv2);
4307     g_value_unset (pv1);
4308     g_value_unset (pv2);
4309   }
4310   return TRUE;
4311 }
4312
4313
4314 /**************
4315  * comparison *
4316  **************/
4317
4318 /*
4319  * gst_value_get_compare_func:
4320  * @value1: a value to get the compare function for
4321  *
4322  * Determines the compare function to be used with values of the same type as
4323  * @value1. The function can be given to gst_value_compare_with_func().
4324  *
4325  * Returns: A #GstValueCompareFunc value
4326  */
4327 static GstValueCompareFunc
4328 gst_value_get_compare_func (const GValue * value1)
4329 {
4330   GstValueTable *table, *best = NULL;
4331   guint i;
4332   GType type1;
4333
4334   type1 = G_VALUE_TYPE (value1);
4335
4336   /* this is a fast check */
4337   best = gst_value_hash_lookup_type (type1);
4338
4339   /* slower checks */
4340   if (G_UNLIKELY (!best || !best->compare)) {
4341     guint len = gst_value_table->len;
4342
4343     best = NULL;
4344     for (i = 0; i < len; i++) {
4345       table = &g_array_index (gst_value_table, GstValueTable, i);
4346       if (table->compare && g_type_is_a (type1, table->type)) {
4347         if (!best || g_type_is_a (table->type, best->type))
4348           best = table;
4349       }
4350     }
4351   }
4352   if (G_LIKELY (best))
4353     return best->compare;
4354
4355   return NULL;
4356 }
4357
4358 /**
4359  * gst_value_can_compare:
4360  * @value1: a value to compare
4361  * @value2: another value to compare
4362  *
4363  * Determines if @value1 and @value2 can be compared.
4364  *
4365  * Returns: TRUE if the values can be compared
4366  */
4367 gboolean
4368 gst_value_can_compare (const GValue * value1, const GValue * value2)
4369 {
4370   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4371   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4372
4373   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4374     return FALSE;
4375
4376   return gst_value_get_compare_func (value1) != NULL;
4377 }
4378
4379 static gboolean
4380 gst_value_list_equals_range (const GValue * list, const GValue * value)
4381 {
4382   const GValue *first;
4383   guint list_size, n;
4384
4385   g_return_val_if_fail (G_IS_VALUE (list), FALSE);
4386   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
4387   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (list), FALSE);
4388
4389   /* TODO: compare against an empty list ? No type though... */
4390   list_size = VALUE_LIST_SIZE (list);
4391   if (list_size == 0)
4392     return FALSE;
4393
4394   /* compare the basic types - they have to match */
4395   first = VALUE_LIST_GET_VALUE (list, 0);
4396 #define CHECK_TYPES(type,prefix) \
4397   (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value))
4398   if (CHECK_TYPES (INT, G)) {
4399     const gint rmin = gst_value_get_int_range_min (value);
4400     const gint rmax = gst_value_get_int_range_max (value);
4401     const gint rstep = gst_value_get_int_range_step (value);
4402     /* note: this will overflow for min 0 and max INT_MAX, but this
4403        would only be equal to a list of INT_MAX elements, which seems
4404        very unlikely */
4405     if (list_size != rmax / rstep - rmin / rstep + 1)
4406       return FALSE;
4407     for (n = 0; n < list_size; ++n) {
4408       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
4409       if (v < rmin || v > rmax || v % rstep) {
4410         return FALSE;
4411       }
4412     }
4413     return TRUE;
4414   } else if (CHECK_TYPES (INT64, G)) {
4415     const gint64 rmin = gst_value_get_int64_range_min (value);
4416     const gint64 rmax = gst_value_get_int64_range_max (value);
4417     const gint64 rstep = gst_value_get_int64_range_step (value);
4418     GST_DEBUG ("List/range of int64s");
4419     if (list_size != rmax / rstep - rmin / rstep + 1)
4420       return FALSE;
4421     for (n = 0; n < list_size; ++n) {
4422       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
4423       if (v < rmin || v > rmax || v % rstep)
4424         return FALSE;
4425     }
4426     return TRUE;
4427   }
4428 #undef CHECK_TYPES
4429
4430   /* other combinations don't make sense for equality */
4431   return FALSE;
4432 }
4433
4434 /**
4435  * gst_value_compare:
4436  * @value1: a value to compare
4437  * @value2: another value to compare
4438  *
4439  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
4440  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
4441  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
4442  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
4443  * If the values are equal, GST_VALUE_EQUAL is returned.
4444  *
4445  * Returns: comparison result
4446  */
4447 gint
4448 gst_value_compare (const GValue * value1, const GValue * value2)
4449 {
4450   GstValueCompareFunc compare;
4451   GType ltype;
4452
4453   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
4454   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
4455
4456   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
4457      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
4458   ltype = gst_value_list_get_type ();
4459   if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype)) {
4460
4461     if (gst_value_list_equals_range (value1, value2)) {
4462       return GST_VALUE_EQUAL;
4463     } else if (gst_value_list_get_size (value1) == 1) {
4464       const GValue *elt;
4465
4466       elt = gst_value_list_get_value (value1, 0);
4467       return gst_value_compare (elt, value2);
4468     }
4469   } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype)) {
4470     if (gst_value_list_equals_range (value2, value1)) {
4471       return GST_VALUE_EQUAL;
4472     } else if (gst_value_list_get_size (value2) == 1) {
4473       const GValue *elt;
4474
4475       elt = gst_value_list_get_value (value2, 0);
4476       return gst_value_compare (elt, value1);
4477     }
4478   }
4479
4480   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4481     return GST_VALUE_UNORDERED;
4482
4483   compare = gst_value_get_compare_func (value1);
4484   if (compare) {
4485     return compare (value1, value2);
4486   }
4487
4488   g_critical ("unable to compare values of type %s\n",
4489       g_type_name (G_VALUE_TYPE (value1)));
4490   return GST_VALUE_UNORDERED;
4491 }
4492
4493 /*
4494  * gst_value_compare_with_func:
4495  * @value1: a value to compare
4496  * @value2: another value to compare
4497  * @compare: compare function
4498  *
4499  * Compares @value1 and @value2 using the @compare function. Works like
4500  * gst_value_compare() but allows to save time determining the compare function
4501  * a multiple times. 
4502  *
4503  * Returns: comparison result
4504  */
4505 static gint
4506 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
4507     GstValueCompareFunc compare)
4508 {
4509   g_assert (compare);
4510
4511   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4512     return GST_VALUE_UNORDERED;
4513
4514   return compare (value1, value2);
4515 }
4516
4517 /* union */
4518
4519 /**
4520  * gst_value_can_union:
4521  * @value1: a value to union
4522  * @value2: another value to union
4523  *
4524  * Determines if @value1 and @value2 can be non-trivially unioned.
4525  * Any two values can be trivially unioned by adding both of them
4526  * to a GstValueList.  However, certain types have the possibility
4527  * to be unioned in a simpler way.  For example, an integer range
4528  * and an integer can be unioned if the integer is a subset of the
4529  * integer range.  If there is the possibility that two values can
4530  * be unioned, this function returns TRUE.
4531  *
4532  * Returns: TRUE if there is a function allowing the two values to
4533  * be unioned.
4534  */
4535 gboolean
4536 gst_value_can_union (const GValue * value1, const GValue * value2)
4537 {
4538   GstValueUnionInfo *union_info;
4539   guint i, len;
4540
4541   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4542   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4543
4544   len = gst_value_union_funcs->len;
4545
4546   for (i = 0; i < len; i++) {
4547     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4548     if (union_info->type1 == G_VALUE_TYPE (value1) &&
4549         union_info->type2 == G_VALUE_TYPE (value2))
4550       return TRUE;
4551     if (union_info->type1 == G_VALUE_TYPE (value2) &&
4552         union_info->type2 == G_VALUE_TYPE (value1))
4553       return TRUE;
4554   }
4555
4556   return FALSE;
4557 }
4558
4559 /**
4560  * gst_value_union:
4561  * @dest: (out caller-allocates): the destination value
4562  * @value1: a value to union
4563  * @value2: another value to union
4564  *
4565  * Creates a GValue corresponding to the union of @value1 and @value2.
4566  *
4567  * Returns: TRUE if the union suceeded.
4568  */
4569 gboolean
4570 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
4571 {
4572   const GstValueUnionInfo *union_info;
4573   guint i, len;
4574   GType type1, type2;
4575
4576   g_return_val_if_fail (dest != NULL, FALSE);
4577   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4578   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4579   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
4580       FALSE);
4581
4582   len = gst_value_union_funcs->len;
4583   type1 = G_VALUE_TYPE (value1);
4584   type2 = G_VALUE_TYPE (value2);
4585
4586   for (i = 0; i < len; i++) {
4587     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4588     if (union_info->type1 == type1 && union_info->type2 == type2) {
4589       return union_info->func (dest, value1, value2);
4590     }
4591     if (union_info->type1 == type2 && union_info->type2 == type1) {
4592       return union_info->func (dest, value2, value1);
4593     }
4594   }
4595
4596   gst_value_list_concat (dest, value1, value2);
4597   return TRUE;
4598 }
4599
4600 /* gst_value_register_union_func: (skip)
4601  * @type1: a type to union
4602  * @type2: another type to union
4603  * @func: a function that implements creating a union between the two types
4604  *
4605  * Registers a union function that can create a union between #GValue items
4606  * of the type @type1 and @type2.
4607  *
4608  * Union functions should be registered at startup before any pipelines are
4609  * started, as gst_value_register_union_func() is not thread-safe and cannot
4610  * be used at the same time as gst_value_union() or gst_value_can_union().
4611  */
4612 static void
4613 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
4614 {
4615   GstValueUnionInfo union_info;
4616
4617   union_info.type1 = type1;
4618   union_info.type2 = type2;
4619   union_info.func = func;
4620
4621   g_array_append_val (gst_value_union_funcs, union_info);
4622 }
4623
4624 /* intersection */
4625
4626 /**
4627  * gst_value_can_intersect:
4628  * @value1: a value to intersect
4629  * @value2: another value to intersect
4630  *
4631  * Determines if intersecting two values will produce a valid result.
4632  * Two values will produce a valid intersection if they have the same
4633  * type, or if there is a method (registered by
4634  * gst_value_register_intersect_func()) to calculate the intersection.
4635  *
4636  * Returns: TRUE if the values can intersect
4637  */
4638 gboolean
4639 gst_value_can_intersect (const GValue * value1, const GValue * value2)
4640 {
4641   GstValueIntersectInfo *intersect_info;
4642   guint i, len;
4643   GType ltype, type1, type2;
4644
4645   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4646   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4647
4648   ltype = gst_value_list_get_type ();
4649
4650   /* special cases */
4651   if (G_VALUE_HOLDS (value1, ltype) || G_VALUE_HOLDS (value2, ltype))
4652     return TRUE;
4653
4654   type1 = G_VALUE_TYPE (value1);
4655   type2 = G_VALUE_TYPE (value2);
4656
4657   /* practically all GstValue types have a compare function (_can_compare=TRUE)
4658    * GstStructure and GstCaps have npot, but are intersectable */
4659   if (type1 == type2)
4660     return TRUE;
4661
4662   /* check registered intersect functions */
4663   len = gst_value_intersect_funcs->len;
4664   for (i = 0; i < len; i++) {
4665     intersect_info = &g_array_index (gst_value_intersect_funcs,
4666         GstValueIntersectInfo, i);
4667     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
4668         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
4669       return TRUE;
4670   }
4671
4672   return gst_value_can_compare (value1, value2);
4673 }
4674
4675 /**
4676  * gst_value_intersect:
4677  * @dest: (out caller-allocates) (transfer full): a uninitialized #GValue that will hold the calculated
4678  * intersection value. May be NULL if the resulting set if not needed.
4679  * @value1: a value to intersect
4680  * @value2: another value to intersect
4681  *
4682  * Calculates the intersection of two values.  If the values have
4683  * a non-empty intersection, the value representing the intersection
4684  * is placed in @dest, unless NULL.  If the intersection is non-empty,
4685  * @dest is not modified.
4686  *
4687  * Returns: TRUE if the intersection is non-empty
4688  */
4689 gboolean
4690 gst_value_intersect (GValue * dest, const GValue * value1,
4691     const GValue * value2)
4692 {
4693   GstValueIntersectInfo *intersect_info;
4694   guint i, len;
4695   GType ltype, type1, type2;
4696
4697   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4698   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4699
4700   ltype = gst_value_list_get_type ();
4701
4702   /* special cases first */
4703   if (G_VALUE_HOLDS (value1, ltype))
4704     return gst_value_intersect_list (dest, value1, value2);
4705   if (G_VALUE_HOLDS (value2, ltype))
4706     return gst_value_intersect_list (dest, value2, value1);
4707
4708   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
4709     if (dest)
4710       gst_value_init_and_copy (dest, value1);
4711     return TRUE;
4712   }
4713
4714   type1 = G_VALUE_TYPE (value1);
4715   type2 = G_VALUE_TYPE (value2);
4716
4717   len = gst_value_intersect_funcs->len;
4718   for (i = 0; i < len; i++) {
4719     intersect_info = &g_array_index (gst_value_intersect_funcs,
4720         GstValueIntersectInfo, i);
4721     if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
4722       return intersect_info->func (dest, value1, value2);
4723     }
4724     if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
4725       return intersect_info->func (dest, value2, value1);
4726     }
4727   }
4728   return FALSE;
4729 }
4730
4731
4732
4733 /* gst_value_register_intersect_func: (skip)
4734  * @type1: the first type to intersect
4735  * @type2: the second type to intersect
4736  * @func: the intersection function
4737  *
4738  * Registers a function that is called to calculate the intersection
4739  * of the values having the types @type1 and @type2.
4740  *
4741  * Intersect functions should be registered at startup before any pipelines are
4742  * started, as gst_value_register_intersect_func() is not thread-safe and
4743  * cannot be used at the same time as gst_value_intersect() or
4744  * gst_value_can_intersect().
4745  */
4746 static void
4747 gst_value_register_intersect_func (GType type1, GType type2,
4748     GstValueIntersectFunc func)
4749 {
4750   GstValueIntersectInfo intersect_info;
4751
4752   intersect_info.type1 = type1;
4753   intersect_info.type2 = type2;
4754   intersect_info.func = func;
4755
4756   g_array_append_val (gst_value_intersect_funcs, intersect_info);
4757 }
4758
4759
4760 /* subtraction */
4761
4762 /**
4763  * gst_value_subtract:
4764  * @dest: (out caller-allocates): the destination value for the result if the
4765  *     subtraction is not empty. May be NULL, in which case the resulting set
4766  *     will not be computed, which can give a fair speedup.
4767  * @minuend: the value to subtract from
4768  * @subtrahend: the value to subtract
4769  *
4770  * Subtracts @subtrahend from @minuend and stores the result in @dest.
4771  * Note that this means subtraction as in sets, not as in mathematics.
4772  *
4773  * Returns: %TRUE if the subtraction is not empty
4774  */
4775 gboolean
4776 gst_value_subtract (GValue * dest, const GValue * minuend,
4777     const GValue * subtrahend)
4778 {
4779   GstValueSubtractInfo *info;
4780   guint i, len;
4781   GType ltype, mtype, stype;
4782
4783   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4784   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4785
4786   ltype = gst_value_list_get_type ();
4787
4788   /* special cases first */
4789   if (G_VALUE_HOLDS (minuend, ltype))
4790     return gst_value_subtract_from_list (dest, minuend, subtrahend);
4791   if (G_VALUE_HOLDS (subtrahend, ltype))
4792     return gst_value_subtract_list (dest, minuend, subtrahend);
4793
4794   mtype = G_VALUE_TYPE (minuend);
4795   stype = G_VALUE_TYPE (subtrahend);
4796
4797   len = gst_value_subtract_funcs->len;
4798   for (i = 0; i < len; i++) {
4799     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4800     if (info->minuend == mtype && info->subtrahend == stype) {
4801       return info->func (dest, minuend, subtrahend);
4802     }
4803   }
4804
4805   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
4806     if (dest)
4807       gst_value_init_and_copy (dest, minuend);
4808     return TRUE;
4809   }
4810
4811   return FALSE;
4812 }
4813
4814 #if 0
4815 gboolean
4816 gst_value_subtract (GValue * dest, const GValue * minuend,
4817     const GValue * subtrahend)
4818 {
4819   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
4820
4821   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
4822       gst_value_serialize (subtrahend),
4823       ret ? gst_value_serialize (dest) : "---");
4824   return ret;
4825 }
4826 #endif
4827
4828 /**
4829  * gst_value_can_subtract:
4830  * @minuend: the value to subtract from
4831  * @subtrahend: the value to subtract
4832  *
4833  * Checks if it's possible to subtract @subtrahend from @minuend.
4834  *
4835  * Returns: TRUE if a subtraction is possible
4836  */
4837 gboolean
4838 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
4839 {
4840   GstValueSubtractInfo *info;
4841   guint i, len;
4842   GType ltype, mtype, stype;
4843
4844   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4845   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4846
4847   ltype = gst_value_list_get_type ();
4848
4849   /* special cases */
4850   if (G_VALUE_HOLDS (minuend, ltype) || G_VALUE_HOLDS (subtrahend, ltype))
4851     return TRUE;
4852
4853   mtype = G_VALUE_TYPE (minuend);
4854   stype = G_VALUE_TYPE (subtrahend);
4855
4856   len = gst_value_subtract_funcs->len;
4857   for (i = 0; i < len; i++) {
4858     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4859     if (info->minuend == mtype && info->subtrahend == stype)
4860       return TRUE;
4861   }
4862
4863   return gst_value_can_compare (minuend, subtrahend);
4864 }
4865
4866 /* gst_value_register_subtract_func: (skip)
4867  * @minuend_type: type of the minuend
4868  * @subtrahend_type: type of the subtrahend
4869  * @func: function to use
4870  *
4871  * Registers @func as a function capable of subtracting the values of
4872  * @subtrahend_type from values of @minuend_type.
4873  *
4874  * Subtract functions should be registered at startup before any pipelines are
4875  * started, as gst_value_register_subtract_func() is not thread-safe and
4876  * cannot be used at the same time as gst_value_subtract().
4877  */
4878 static void
4879 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
4880     GstValueSubtractFunc func)
4881 {
4882   GstValueSubtractInfo info;
4883
4884   g_return_if_fail (!gst_type_is_fixed (minuend_type)
4885       || !gst_type_is_fixed (subtrahend_type));
4886
4887   info.minuend = minuend_type;
4888   info.subtrahend = subtrahend_type;
4889   info.func = func;
4890
4891   g_array_append_val (gst_value_subtract_funcs, info);
4892 }
4893
4894 /**
4895  * gst_value_register:
4896  * @table: structure containing functions to register
4897  *
4898  * Registers functions to perform calculations on #GValue items of a given
4899  * type. Each type can only be added once.
4900  */
4901 void
4902 gst_value_register (const GstValueTable * table)
4903 {
4904   GstValueTable *found;
4905
4906   g_return_if_fail (table != NULL);
4907
4908   g_array_append_val (gst_value_table, *table);
4909
4910   found = gst_value_hash_lookup_type (table->type);
4911   if (found)
4912     g_warning ("adding type %s multiple times", g_type_name (table->type));
4913
4914   /* FIXME: we're not really doing the const justice, we assume the table is
4915    * static */
4916   gst_value_hash_add_type (table->type, table);
4917 }
4918
4919 /**
4920  * gst_value_init_and_copy:
4921  * @dest: (out caller-allocates): the target value
4922  * @src: the source value
4923  *
4924  * Initialises the target value to be of the same type as source and then copies
4925  * the contents from source to target.
4926  */
4927 void
4928 gst_value_init_and_copy (GValue * dest, const GValue * src)
4929 {
4930   g_return_if_fail (G_IS_VALUE (src));
4931   g_return_if_fail (dest != NULL);
4932
4933   g_value_init (dest, G_VALUE_TYPE (src));
4934   g_value_copy (src, dest);
4935 }
4936
4937 /* move src into dest and clear src */
4938 static void
4939 gst_value_move (GValue * dest, GValue * src)
4940 {
4941   g_assert (G_IS_VALUE (src));
4942   g_assert (dest != NULL);
4943
4944   *dest = *src;
4945   memset (src, 0, sizeof (GValue));
4946 }
4947
4948 /**
4949  * gst_value_serialize:
4950  * @value: a #GValue to serialize
4951  *
4952  * tries to transform the given @value into a string representation that allows
4953  * getting back this string later on using gst_value_deserialize().
4954  *
4955  * Free-function: g_free
4956  *
4957  * Returns: (transfer full): the serialization for @value or NULL if none exists
4958  */
4959 gchar *
4960 gst_value_serialize (const GValue * value)
4961 {
4962   guint i, len;
4963   GValue s_val = { 0 };
4964   GstValueTable *table, *best;
4965   gchar *s;
4966   GType type;
4967
4968   g_return_val_if_fail (G_IS_VALUE (value), NULL);
4969
4970   type = G_VALUE_TYPE (value);
4971
4972   best = gst_value_hash_lookup_type (type);
4973
4974   if (G_UNLIKELY (!best || !best->serialize)) {
4975     len = gst_value_table->len;
4976     best = NULL;
4977     for (i = 0; i < len; i++) {
4978       table = &g_array_index (gst_value_table, GstValueTable, i);
4979       if (table->serialize && g_type_is_a (type, table->type)) {
4980         if (!best || g_type_is_a (table->type, best->type))
4981           best = table;
4982       }
4983     }
4984   }
4985   if (G_LIKELY (best))
4986     return best->serialize (value);
4987
4988   g_value_init (&s_val, G_TYPE_STRING);
4989   if (g_value_transform (value, &s_val)) {
4990     s = gst_string_wrap (g_value_get_string (&s_val));
4991   } else {
4992     s = NULL;
4993   }
4994   g_value_unset (&s_val);
4995
4996   return s;
4997 }
4998
4999 /**
5000  * gst_value_deserialize:
5001  * @dest: (out caller-allocates): #GValue to fill with contents of
5002  *     deserialization
5003  * @src: string to deserialize
5004  *
5005  * Tries to deserialize a string into the type specified by the given GValue.
5006  * If the operation succeeds, TRUE is returned, FALSE otherwise.
5007  *
5008  * Returns: TRUE on success
5009  */
5010 gboolean
5011 gst_value_deserialize (GValue * dest, const gchar * src)
5012 {
5013   GstValueTable *table, *best;
5014   guint i, len;
5015   GType type;
5016
5017   g_return_val_if_fail (src != NULL, FALSE);
5018   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
5019
5020   type = G_VALUE_TYPE (dest);
5021
5022   best = gst_value_hash_lookup_type (type);
5023   if (G_UNLIKELY (!best || !best->deserialize)) {
5024     len = gst_value_table->len;
5025     best = NULL;
5026     for (i = 0; i < len; i++) {
5027       table = &g_array_index (gst_value_table, GstValueTable, i);
5028       if (table->deserialize && g_type_is_a (type, table->type)) {
5029         if (!best || g_type_is_a (table->type, best->type))
5030           best = table;
5031       }
5032     }
5033   }
5034   if (G_LIKELY (best))
5035     return best->deserialize (dest, src);
5036
5037   return FALSE;
5038 }
5039
5040 /**
5041  * gst_value_is_fixed:
5042  * @value: the #GValue to check
5043  *
5044  * Tests if the given GValue, if available in a GstStructure (or any other
5045  * container) contains a "fixed" (which means: one value) or an "unfixed"
5046  * (which means: multiple possible values, such as data lists or data
5047  * ranges) value.
5048  *
5049  * Returns: true if the value is "fixed".
5050  */
5051
5052 gboolean
5053 gst_value_is_fixed (const GValue * value)
5054 {
5055   GType type;
5056
5057   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
5058
5059   type = G_VALUE_TYPE (value);
5060
5061   /* the most common types are just basic plain glib types */
5062   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
5063     return TRUE;
5064   }
5065
5066   if (type == GST_TYPE_ARRAY) {
5067     gint size, n;
5068     const GValue *kid;
5069
5070     /* check recursively */
5071     size = gst_value_array_get_size (value);
5072     for (n = 0; n < size; n++) {
5073       kid = gst_value_array_get_value (value, n);
5074       if (!gst_value_is_fixed (kid))
5075         return FALSE;
5076     }
5077     return TRUE;
5078   }
5079   return gst_type_is_fixed (type);
5080 }
5081
5082 /**
5083  * gst_value_fixate:
5084  * @dest: the #GValue destination
5085  * @src: the #GValue to fixate
5086  *
5087  * Fixate @src into a new value @dest.
5088  * For ranges, the first element is taken. For lists and arrays, the
5089  * first item is fixated and returned.
5090  * If @src is already fixed, this function returns FALSE.
5091  *
5092  * Returns: true if @dest contains a fixated version of @src.
5093  */
5094 gboolean
5095 gst_value_fixate (GValue * dest, const GValue * src)
5096 {
5097   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
5098   g_return_val_if_fail (dest != NULL, FALSE);
5099
5100   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
5101     g_value_init (dest, G_TYPE_INT);
5102     g_value_set_int (dest, gst_value_get_int_range_min (src));
5103   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
5104     g_value_init (dest, G_TYPE_DOUBLE);
5105     g_value_set_double (dest, gst_value_get_double_range_min (src));
5106   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
5107     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
5108   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
5109     GValue temp = { 0 };
5110
5111     /* list could be empty */
5112     if (gst_value_list_get_size (src) <= 0)
5113       return FALSE;
5114
5115     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
5116
5117     if (!gst_value_fixate (dest, &temp)) {
5118       gst_value_move (dest, &temp);
5119     } else {
5120       g_value_unset (&temp);
5121     }
5122   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
5123     gboolean res = FALSE;
5124     guint n, len;
5125
5126     len = gst_value_array_get_size (src);
5127     g_value_init (dest, GST_TYPE_ARRAY);
5128     for (n = 0; n < len; n++) {
5129       GValue kid = { 0 };
5130       const GValue *orig_kid = gst_value_array_get_value (src, n);
5131
5132       if (!gst_value_fixate (&kid, orig_kid))
5133         gst_value_init_and_copy (&kid, orig_kid);
5134       else
5135         res = TRUE;
5136       _gst_value_array_append_and_take_value (dest, &kid);
5137     }
5138
5139     if (!res)
5140       g_value_unset (dest);
5141
5142     return res;
5143   } else {
5144     return FALSE;
5145   }
5146   return TRUE;
5147 }
5148
5149
5150 /************
5151  * fraction *
5152  ************/
5153
5154 /* helper functions */
5155 static void
5156 gst_value_init_fraction (GValue * value)
5157 {
5158   value->data[0].v_int = 0;
5159   value->data[1].v_int = 1;
5160 }
5161
5162 static void
5163 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
5164 {
5165   dest_value->data[0].v_int = src_value->data[0].v_int;
5166   dest_value->data[1].v_int = src_value->data[1].v_int;
5167 }
5168
5169 static gchar *
5170 gst_value_collect_fraction (GValue * value, guint n_collect_values,
5171     GTypeCValue * collect_values, guint collect_flags)
5172 {
5173   if (n_collect_values != 2)
5174     return g_strdup_printf ("not enough value locations for `%s' passed",
5175         G_VALUE_TYPE_NAME (value));
5176   if (collect_values[1].v_int == 0)
5177     return g_strdup_printf ("passed '0' as denominator for `%s'",
5178         G_VALUE_TYPE_NAME (value));
5179   if (collect_values[0].v_int < -G_MAXINT)
5180     return
5181         g_strdup_printf
5182         ("passed value smaller than -G_MAXINT as numerator for `%s'",
5183         G_VALUE_TYPE_NAME (value));
5184   if (collect_values[1].v_int < -G_MAXINT)
5185     return
5186         g_strdup_printf
5187         ("passed value smaller than -G_MAXINT as denominator for `%s'",
5188         G_VALUE_TYPE_NAME (value));
5189
5190   gst_value_set_fraction (value,
5191       collect_values[0].v_int, collect_values[1].v_int);
5192
5193   return NULL;
5194 }
5195
5196 static gchar *
5197 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
5198     GTypeCValue * collect_values, guint collect_flags)
5199 {
5200   gint *numerator = collect_values[0].v_pointer;
5201   gint *denominator = collect_values[1].v_pointer;
5202
5203   if (!numerator)
5204     return g_strdup_printf ("numerator for `%s' passed as NULL",
5205         G_VALUE_TYPE_NAME (value));
5206   if (!denominator)
5207     return g_strdup_printf ("denominator for `%s' passed as NULL",
5208         G_VALUE_TYPE_NAME (value));
5209
5210   *numerator = value->data[0].v_int;
5211   *denominator = value->data[1].v_int;
5212
5213   return NULL;
5214 }
5215
5216 /**
5217  * gst_value_set_fraction:
5218  * @value: a GValue initialized to #GST_TYPE_FRACTION
5219  * @numerator: the numerator of the fraction
5220  * @denominator: the denominator of the fraction
5221  *
5222  * Sets @value to the fraction specified by @numerator over @denominator.
5223  * The fraction gets reduced to the smallest numerator and denominator,
5224  * and if necessary the sign is moved to the numerator.
5225  */
5226 void
5227 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
5228 {
5229   gint gcd = 0;
5230
5231   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
5232   g_return_if_fail (denominator != 0);
5233   g_return_if_fail (denominator >= -G_MAXINT);
5234   g_return_if_fail (numerator >= -G_MAXINT);
5235
5236   /* normalize sign */
5237   if (denominator < 0) {
5238     numerator = -numerator;
5239     denominator = -denominator;
5240   }
5241
5242   /* check for reduction */
5243   gcd = gst_util_greatest_common_divisor (numerator, denominator);
5244   if (gcd) {
5245     numerator /= gcd;
5246     denominator /= gcd;
5247   }
5248
5249   g_assert (denominator > 0);
5250
5251   value->data[0].v_int = numerator;
5252   value->data[1].v_int = denominator;
5253 }
5254
5255 /**
5256  * gst_value_get_fraction_numerator:
5257  * @value: a GValue initialized to #GST_TYPE_FRACTION
5258  *
5259  * Gets the numerator of the fraction specified by @value.
5260  *
5261  * Returns: the numerator of the fraction.
5262  */
5263 gint
5264 gst_value_get_fraction_numerator (const GValue * value)
5265 {
5266   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
5267
5268   return value->data[0].v_int;
5269 }
5270
5271 /**
5272  * gst_value_get_fraction_denominator:
5273  * @value: a GValue initialized to #GST_TYPE_FRACTION
5274  *
5275  * Gets the denominator of the fraction specified by @value.
5276  *
5277  * Returns: the denominator of the fraction.
5278  */
5279 gint
5280 gst_value_get_fraction_denominator (const GValue * value)
5281 {
5282   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
5283
5284   return value->data[1].v_int;
5285 }
5286
5287 /**
5288  * gst_value_fraction_multiply:
5289  * @product: a GValue initialized to #GST_TYPE_FRACTION
5290  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
5291  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
5292  *
5293  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
5294  * @product to the product of the two fractions.
5295  *
5296  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
5297  */
5298 gboolean
5299 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
5300     const GValue * factor2)
5301 {
5302   gint n1, n2, d1, d2;
5303   gint res_n, res_d;
5304
5305   g_return_val_if_fail (product != NULL, FALSE);
5306   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
5307   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
5308
5309   n1 = factor1->data[0].v_int;
5310   n2 = factor2->data[0].v_int;
5311   d1 = factor1->data[1].v_int;
5312   d2 = factor2->data[1].v_int;
5313
5314   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
5315     return FALSE;
5316
5317   gst_value_set_fraction (product, res_n, res_d);
5318
5319   return TRUE;
5320 }
5321
5322 /**
5323  * gst_value_fraction_subtract:
5324  * @dest: a GValue initialized to #GST_TYPE_FRACTION
5325  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
5326  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
5327  *
5328  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
5329  *
5330  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
5331  */
5332 gboolean
5333 gst_value_fraction_subtract (GValue * dest,
5334     const GValue * minuend, const GValue * subtrahend)
5335 {
5336   gint n1, n2, d1, d2;
5337   gint res_n, res_d;
5338
5339   g_return_val_if_fail (dest != NULL, FALSE);
5340   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
5341   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
5342
5343   n1 = minuend->data[0].v_int;
5344   n2 = subtrahend->data[0].v_int;
5345   d1 = minuend->data[1].v_int;
5346   d2 = subtrahend->data[1].v_int;
5347
5348   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
5349     return FALSE;
5350   gst_value_set_fraction (dest, res_n, res_d);
5351
5352   return TRUE;
5353 }
5354
5355 static gchar *
5356 gst_value_serialize_fraction (const GValue * value)
5357 {
5358   gint32 numerator = value->data[0].v_int;
5359   gint32 denominator = value->data[1].v_int;
5360   gboolean positive = TRUE;
5361
5362   /* get the sign and make components absolute */
5363   if (numerator < 0) {
5364     numerator = -numerator;
5365     positive = !positive;
5366   }
5367   if (denominator < 0) {
5368     denominator = -denominator;
5369     positive = !positive;
5370   }
5371
5372   return g_strdup_printf ("%s%d/%d",
5373       positive ? "" : "-", numerator, denominator);
5374 }
5375
5376 static gboolean
5377 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
5378 {
5379   gint num, den;
5380   gint num_chars;
5381
5382   if (G_UNLIKELY (s == NULL))
5383     return FALSE;
5384
5385   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
5386     return FALSE;
5387
5388   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
5389     if (s[num_chars] != 0)
5390       return FALSE;
5391     if (den == 0)
5392       return FALSE;
5393
5394     gst_value_set_fraction (dest, num, den);
5395     return TRUE;
5396   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
5397     gst_value_set_fraction (dest, 1, G_MAXINT);
5398     return TRUE;
5399   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
5400     if (s[num_chars] != 0)
5401       return FALSE;
5402     gst_value_set_fraction (dest, num, 1);
5403     return TRUE;
5404   } else if (g_ascii_strcasecmp (s, "min") == 0) {
5405     gst_value_set_fraction (dest, -G_MAXINT, 1);
5406     return TRUE;
5407   } else if (g_ascii_strcasecmp (s, "max") == 0) {
5408     gst_value_set_fraction (dest, G_MAXINT, 1);
5409     return TRUE;
5410   }
5411
5412   return FALSE;
5413 }
5414
5415 static void
5416 gst_value_transform_fraction_string (const GValue * src_value,
5417     GValue * dest_value)
5418 {
5419   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
5420 }
5421
5422 static void
5423 gst_value_transform_string_fraction (const GValue * src_value,
5424     GValue * dest_value)
5425 {
5426   if (!gst_value_deserialize_fraction (dest_value,
5427           src_value->data[0].v_pointer))
5428     /* If the deserialize fails, ensure we leave the fraction in a
5429      * valid, if incorrect, state */
5430     gst_value_set_fraction (dest_value, 0, 1);
5431 }
5432
5433 static void
5434 gst_value_transform_double_fraction (const GValue * src_value,
5435     GValue * dest_value)
5436 {
5437   gdouble src = g_value_get_double (src_value);
5438   gint n, d;
5439
5440   gst_util_double_to_fraction (src, &n, &d);
5441   gst_value_set_fraction (dest_value, n, d);
5442 }
5443
5444 static void
5445 gst_value_transform_float_fraction (const GValue * src_value,
5446     GValue * dest_value)
5447 {
5448   gfloat src = g_value_get_float (src_value);
5449   gint n, d;
5450
5451   gst_util_double_to_fraction (src, &n, &d);
5452   gst_value_set_fraction (dest_value, n, d);
5453 }
5454
5455 static void
5456 gst_value_transform_fraction_double (const GValue * src_value,
5457     GValue * dest_value)
5458 {
5459   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
5460       ((double) src_value->data[1].v_int);
5461 }
5462
5463 static void
5464 gst_value_transform_fraction_float (const GValue * src_value,
5465     GValue * dest_value)
5466 {
5467   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
5468       ((float) src_value->data[1].v_int);
5469 }
5470
5471 static gint
5472 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
5473 {
5474   gint n1, n2;
5475   gint d1, d2;
5476   gint ret;
5477
5478   n1 = value1->data[0].v_int;
5479   n2 = value2->data[0].v_int;
5480   d1 = value1->data[1].v_int;
5481   d2 = value2->data[1].v_int;
5482
5483   /* fractions are reduced when set, so we can quickly see if they're equal */
5484   if (n1 == n2 && d1 == d2)
5485     return GST_VALUE_EQUAL;
5486
5487   if (d1 == 0 && d2 == 0)
5488     return GST_VALUE_UNORDERED;
5489   else if (d1 == 0)
5490     return GST_VALUE_GREATER_THAN;
5491   else if (d2 == 0)
5492     return GST_VALUE_LESS_THAN;
5493
5494   ret = gst_util_fraction_compare (n1, d1, n2, d2);
5495   if (ret == -1)
5496     return GST_VALUE_LESS_THAN;
5497   else if (ret == 1)
5498     return GST_VALUE_GREATER_THAN;
5499
5500   /* Equality can't happen here because we check for that
5501    * first already */
5502   g_return_val_if_reached (GST_VALUE_UNORDERED);
5503 }
5504
5505 /*********
5506  * GDate *
5507  *********/
5508
5509 static gint
5510 gst_value_compare_date (const GValue * value1, const GValue * value2)
5511 {
5512   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
5513   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
5514   guint32 j1, j2;
5515
5516   if (date1 == date2)
5517     return GST_VALUE_EQUAL;
5518
5519   if ((date1 == NULL || !g_date_valid (date1))
5520       && (date2 != NULL && g_date_valid (date2))) {
5521     return GST_VALUE_LESS_THAN;
5522   }
5523
5524   if ((date2 == NULL || !g_date_valid (date2))
5525       && (date1 != NULL && g_date_valid (date1))) {
5526     return GST_VALUE_GREATER_THAN;
5527   }
5528
5529   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
5530       || !g_date_valid (date2)) {
5531     return GST_VALUE_UNORDERED;
5532   }
5533
5534   j1 = g_date_get_julian (date1);
5535   j2 = g_date_get_julian (date2);
5536
5537   if (j1 == j2)
5538     return GST_VALUE_EQUAL;
5539   else if (j1 < j2)
5540     return GST_VALUE_LESS_THAN;
5541   else
5542     return GST_VALUE_GREATER_THAN;
5543 }
5544
5545 static gchar *
5546 gst_value_serialize_date (const GValue * val)
5547 {
5548   const GDate *date = (const GDate *) g_value_get_boxed (val);
5549
5550   if (date == NULL || !g_date_valid (date))
5551     return g_strdup ("9999-99-99");
5552
5553   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
5554       g_date_get_month (date), g_date_get_day (date));
5555 }
5556
5557 static gboolean
5558 gst_value_deserialize_date (GValue * dest, const gchar * s)
5559 {
5560   guint year, month, day;
5561
5562   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
5563     return FALSE;
5564
5565   if (!g_date_valid_dmy (day, month, year))
5566     return FALSE;
5567
5568   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
5569   return TRUE;
5570 }
5571
5572 /*************
5573  * GstDateTime *
5574  *************/
5575
5576 static gint
5577 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
5578 {
5579   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
5580   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
5581
5582   if (date1 == date2)
5583     return GST_VALUE_EQUAL;
5584
5585   if ((date1 == NULL) && (date2 != NULL)) {
5586     return GST_VALUE_LESS_THAN;
5587   }
5588   if ((date2 == NULL) && (date1 != NULL)) {
5589     return GST_VALUE_LESS_THAN;
5590   }
5591
5592   /* returns GST_VALUE_* */
5593   return __gst_date_time_compare (date1, date2);
5594 }
5595
5596 static gchar *
5597 gst_value_serialize_date_time (const GValue * val)
5598 {
5599   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
5600
5601   if (date == NULL)
5602     return g_strdup ("null");
5603
5604   return __gst_date_time_serialize (date, TRUE);
5605 }
5606
5607 static gboolean
5608 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
5609 {
5610   GstDateTime *datetime;
5611
5612   if (!s || strcmp (s, "null") == 0) {
5613     return FALSE;
5614   }
5615
5616   datetime = gst_date_time_new_from_iso8601_string (s);
5617   if (datetime != NULL) {
5618     g_value_take_boxed (dest, datetime);
5619     return TRUE;
5620   }
5621   GST_WARNING ("Failed to deserialize date time string '%s'", s);
5622   return FALSE;
5623 }
5624
5625 static void
5626 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
5627 {
5628   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
5629 }
5630
5631 static void
5632 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
5633 {
5634   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
5635 }
5636
5637
5638 /************
5639  * bitmask *
5640  ************/
5641
5642 /* helper functions */
5643 static void
5644 gst_value_init_bitmask (GValue * value)
5645 {
5646   value->data[0].v_uint64 = 0;
5647 }
5648
5649 static void
5650 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
5651 {
5652   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5653 }
5654
5655 static gchar *
5656 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
5657     GTypeCValue * collect_values, guint collect_flags)
5658 {
5659   if (n_collect_values != 1)
5660     return g_strdup_printf ("not enough value locations for `%s' passed",
5661         G_VALUE_TYPE_NAME (value));
5662
5663   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
5664
5665   return NULL;
5666 }
5667
5668 static gchar *
5669 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
5670     GTypeCValue * collect_values, guint collect_flags)
5671 {
5672   guint64 *bitmask = collect_values[0].v_pointer;
5673
5674   if (!bitmask)
5675     return g_strdup_printf ("value for `%s' passed as NULL",
5676         G_VALUE_TYPE_NAME (value));
5677
5678   *bitmask = value->data[0].v_uint64;
5679
5680   return NULL;
5681 }
5682
5683 /**
5684  * gst_value_set_bitmask:
5685  * @value: a GValue initialized to #GST_TYPE_BITMASK
5686  * @bitmask: the bitmask
5687  *
5688  * Sets @value to the bitmask specified by @bitmask.
5689  */
5690 void
5691 gst_value_set_bitmask (GValue * value, guint64 bitmask)
5692 {
5693   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
5694
5695   value->data[0].v_uint64 = bitmask;
5696 }
5697
5698 /**
5699  * gst_value_get_bitmask:
5700  * @value: a GValue initialized to #GST_TYPE_BITMASK
5701  *
5702  * Gets the bitmask specified by @value.
5703  *
5704  * Returns: the bitmask.
5705  */
5706 guint64
5707 gst_value_get_bitmask (const GValue * value)
5708 {
5709   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
5710
5711   return value->data[0].v_uint64;
5712 }
5713
5714 static gchar *
5715 gst_value_serialize_bitmask (const GValue * value)
5716 {
5717   guint64 bitmask = value->data[0].v_uint64;
5718
5719   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
5720 }
5721
5722 static gboolean
5723 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
5724 {
5725   gchar *endptr = NULL;
5726   guint64 val;
5727
5728   if (G_UNLIKELY (s == NULL))
5729     return FALSE;
5730
5731   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
5732     return FALSE;
5733
5734   val = g_ascii_strtoull (s, &endptr, 16);
5735   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
5736     return FALSE;
5737   if (val == 0 && endptr == s)
5738     return FALSE;
5739
5740   gst_value_set_bitmask (dest, val);
5741
5742   return TRUE;
5743 }
5744
5745 static void
5746 gst_value_transform_bitmask_string (const GValue * src_value,
5747     GValue * dest_value)
5748 {
5749   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
5750 }
5751
5752 static void
5753 gst_value_transform_string_bitmask (const GValue * src_value,
5754     GValue * dest_value)
5755 {
5756   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
5757     gst_value_set_bitmask (dest_value, 0);
5758 }
5759
5760 static void
5761 gst_value_transform_uint64_bitmask (const GValue * src_value,
5762     GValue * dest_value)
5763 {
5764   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5765 }
5766
5767 static void
5768 gst_value_transform_bitmask_uint64 (const GValue * src_value,
5769     GValue * dest_value)
5770 {
5771   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5772 }
5773
5774 static gint
5775 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
5776 {
5777   guint64 v1, v2;
5778
5779   v1 = value1->data[0].v_uint64;
5780   v2 = value2->data[0].v_uint64;
5781
5782   if (v1 == v2)
5783     return GST_VALUE_EQUAL;
5784
5785   return GST_VALUE_UNORDERED;
5786 }
5787
5788 static void
5789 gst_value_transform_object_string (const GValue * src_value,
5790     GValue * dest_value)
5791 {
5792   GstObject *obj;
5793   gchar *str;
5794
5795   obj = g_value_get_object (src_value);
5796   if (obj) {
5797     str =
5798         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
5799         GST_OBJECT_NAME (obj));
5800   } else {
5801     str = g_strdup ("NULL");
5802   }
5803
5804   dest_value->data[0].v_pointer = str;
5805 }
5806
5807 static GTypeInfo _info = {
5808   0,
5809   NULL,
5810   NULL,
5811   NULL,
5812   NULL,
5813   NULL,
5814   0,
5815   0,
5816   NULL,
5817   NULL,
5818 };
5819
5820 static GTypeFundamentalInfo _finfo = {
5821   0
5822 };
5823
5824 #define FUNC_VALUE_GET_TYPE(type, name)                         \
5825 GType gst_ ## type ## _get_type (void)                          \
5826 {                                                               \
5827   static volatile GType gst_ ## type ## _type = 0;                       \
5828                                                                 \
5829   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
5830     GType _type;                                        \
5831     _info.value_table = & _gst_ ## type ## _value_table;        \
5832     _type = g_type_register_fundamental (       \
5833         g_type_fundamental_next (),                             \
5834         name, &_info, &_finfo, 0);                              \
5835     g_once_init_leave(&gst_ ## type ## _type, _type);   \
5836   }                                                             \
5837                                                                 \
5838   return gst_ ## type ## _type;                                 \
5839 }
5840
5841 static const GTypeValueTable _gst_int_range_value_table = {
5842   gst_value_init_int_range,
5843   gst_value_free_int_range,
5844   gst_value_copy_int_range,
5845   NULL,
5846   (char *) "ii",
5847   gst_value_collect_int_range,
5848   (char *) "pp",
5849   gst_value_lcopy_int_range
5850 };
5851
5852 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
5853
5854 static const GTypeValueTable _gst_int64_range_value_table = {
5855   gst_value_init_int64_range,
5856   gst_value_free_int64_range,
5857   gst_value_copy_int64_range,
5858   NULL,
5859   (char *) "qq",
5860   gst_value_collect_int64_range,
5861   (char *) "pp",
5862   gst_value_lcopy_int64_range
5863 };
5864
5865 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
5866
5867 static const GTypeValueTable _gst_double_range_value_table = {
5868   gst_value_init_double_range,
5869   NULL,
5870   gst_value_copy_double_range,
5871   NULL,
5872   (char *) "dd",
5873   gst_value_collect_double_range,
5874   (char *) "pp",
5875   gst_value_lcopy_double_range
5876 };
5877
5878 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
5879
5880 static const GTypeValueTable _gst_fraction_range_value_table = {
5881   gst_value_init_fraction_range,
5882   gst_value_free_fraction_range,
5883   gst_value_copy_fraction_range,
5884   NULL,
5885   (char *) "iiii",
5886   gst_value_collect_fraction_range,
5887   (char *) "pppp",
5888   gst_value_lcopy_fraction_range
5889 };
5890
5891 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
5892
5893 static const GTypeValueTable _gst_value_list_value_table = {
5894   gst_value_init_list_or_array,
5895   gst_value_free_list_or_array,
5896   gst_value_copy_list_or_array,
5897   gst_value_list_or_array_peek_pointer,
5898   (char *) "p",
5899   gst_value_collect_list_or_array,
5900   (char *) "p",
5901   gst_value_lcopy_list_or_array
5902 };
5903
5904 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
5905
5906 static const GTypeValueTable _gst_value_array_value_table = {
5907   gst_value_init_list_or_array,
5908   gst_value_free_list_or_array,
5909   gst_value_copy_list_or_array,
5910   gst_value_list_or_array_peek_pointer,
5911   (char *) "p",
5912   gst_value_collect_list_or_array,
5913   (char *) "p",
5914   gst_value_lcopy_list_or_array
5915 };
5916
5917 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
5918
5919 static const GTypeValueTable _gst_fraction_value_table = {
5920   gst_value_init_fraction,
5921   NULL,
5922   gst_value_copy_fraction,
5923   NULL,
5924   (char *) "ii",
5925   gst_value_collect_fraction,
5926   (char *) "pp",
5927   gst_value_lcopy_fraction
5928 };
5929
5930 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
5931
5932 G_DEFINE_BOXED_TYPE (GstDateTime, gst_date_time,
5933     (GBoxedCopyFunc) gst_date_time_ref, (GBoxedFreeFunc) gst_date_time_unref);
5934
5935 static const GTypeValueTable _gst_bitmask_value_table = {
5936   gst_value_init_bitmask,
5937   NULL,
5938   gst_value_copy_bitmask,
5939   NULL,
5940   (char *) "q",
5941   gst_value_collect_bitmask,
5942   (char *) "p",
5943   gst_value_lcopy_bitmask
5944 };
5945
5946 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
5947
5948 GType
5949 gst_g_thread_get_type (void)
5950 {
5951 #if GLIB_CHECK_VERSION(2,35,3)
5952   return G_TYPE_THREAD;
5953 #else
5954   static volatile gsize type_id = 0;
5955
5956   if (g_once_init_enter (&type_id)) {
5957     GType tmp =
5958         g_boxed_type_register_static (g_intern_static_string ("GstGThread"),
5959         (GBoxedCopyFunc) g_thread_ref,
5960         (GBoxedFreeFunc) g_thread_unref);
5961     g_once_init_leave (&type_id, tmp);
5962   }
5963
5964   return type_id;
5965 #endif
5966 }
5967
5968 void
5969 _priv_gst_value_initialize (void)
5970 {
5971   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
5972   gst_value_hash = g_hash_table_new (NULL, NULL);
5973   gst_value_union_funcs = g_array_new (FALSE, FALSE,
5974       sizeof (GstValueUnionInfo));
5975   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
5976       sizeof (GstValueIntersectInfo));
5977   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
5978       sizeof (GstValueSubtractInfo));
5979
5980   {
5981     static GstValueTable gst_value = {
5982       0,
5983       gst_value_compare_int_range,
5984       gst_value_serialize_int_range,
5985       gst_value_deserialize_int_range,
5986     };
5987
5988     gst_value.type = gst_int_range_get_type ();
5989     gst_value_register (&gst_value);
5990   }
5991
5992   {
5993     static GstValueTable gst_value = {
5994       0,
5995       gst_value_compare_int64_range,
5996       gst_value_serialize_int64_range,
5997       gst_value_deserialize_int64_range,
5998     };
5999
6000     gst_value.type = gst_int64_range_get_type ();
6001     gst_value_register (&gst_value);
6002   }
6003
6004   {
6005     static GstValueTable gst_value = {
6006       0,
6007       gst_value_compare_double_range,
6008       gst_value_serialize_double_range,
6009       gst_value_deserialize_double_range,
6010     };
6011
6012     gst_value.type = gst_double_range_get_type ();
6013     gst_value_register (&gst_value);
6014   }
6015
6016   {
6017     static GstValueTable gst_value = {
6018       0,
6019       gst_value_compare_fraction_range,
6020       gst_value_serialize_fraction_range,
6021       gst_value_deserialize_fraction_range,
6022     };
6023
6024     gst_value.type = gst_fraction_range_get_type ();
6025     gst_value_register (&gst_value);
6026   }
6027
6028   {
6029     static GstValueTable gst_value = {
6030       0,
6031       gst_value_compare_list,
6032       gst_value_serialize_list,
6033       gst_value_deserialize_list,
6034     };
6035
6036     gst_value.type = gst_value_list_get_type ();
6037     gst_value_register (&gst_value);
6038   }
6039
6040   {
6041     static GstValueTable gst_value = {
6042       0,
6043       gst_value_compare_array,
6044       gst_value_serialize_array,
6045       gst_value_deserialize_array,
6046     };
6047
6048     gst_value.type = gst_value_array_get_type ();
6049     gst_value_register (&gst_value);
6050   }
6051
6052   {
6053 #if 0
6054     static const GTypeValueTable value_table = {
6055       gst_value_init_buffer,
6056       NULL,
6057       gst_value_copy_buffer,
6058       NULL,
6059       "i",
6060       NULL,                     /*gst_value_collect_buffer, */
6061       "p",
6062       NULL                      /*gst_value_lcopy_buffer */
6063     };
6064 #endif
6065     static GstValueTable gst_value = {
6066       0,
6067       gst_value_compare_buffer,
6068       gst_value_serialize_buffer,
6069       gst_value_deserialize_buffer,
6070     };
6071
6072     gst_value.type = GST_TYPE_BUFFER;
6073     gst_value_register (&gst_value);
6074   }
6075   {
6076     static GstValueTable gst_value = {
6077       0,
6078       gst_value_compare_sample,
6079       gst_value_serialize_sample,
6080       gst_value_deserialize_sample,
6081     };
6082
6083     gst_value.type = GST_TYPE_SAMPLE;
6084     gst_value_register (&gst_value);
6085   }
6086   {
6087     static GstValueTable gst_value = {
6088       0,
6089       gst_value_compare_fraction,
6090       gst_value_serialize_fraction,
6091       gst_value_deserialize_fraction,
6092     };
6093
6094     gst_value.type = gst_fraction_get_type ();
6095     gst_value_register (&gst_value);
6096   }
6097   {
6098     static GstValueTable gst_value = {
6099       0,
6100       gst_value_compare_caps,
6101       gst_value_serialize_caps,
6102       gst_value_deserialize_caps,
6103     };
6104
6105     gst_value.type = GST_TYPE_CAPS;
6106     gst_value_register (&gst_value);
6107   }
6108   {
6109     static GstValueTable gst_value = {
6110       0,
6111       NULL,
6112       gst_value_serialize_segment,
6113       gst_value_deserialize_segment,
6114     };
6115
6116     gst_value.type = GST_TYPE_SEGMENT;
6117     gst_value_register (&gst_value);
6118   }
6119   {
6120     static GstValueTable gst_value = {
6121       0,
6122       NULL,
6123       gst_value_serialize_structure,
6124       gst_value_deserialize_structure,
6125     };
6126
6127     gst_value.type = GST_TYPE_STRUCTURE;
6128     gst_value_register (&gst_value);
6129   }
6130   {
6131     static GstValueTable gst_value = {
6132       0,
6133       NULL,
6134       gst_value_serialize_caps_features,
6135       gst_value_deserialize_caps_features,
6136     };
6137
6138     gst_value.type = GST_TYPE_CAPS_FEATURES;
6139     gst_value_register (&gst_value);
6140   }
6141   {
6142     static GstValueTable gst_value = {
6143       0,
6144       NULL,
6145       gst_value_serialize_tag_list,
6146       gst_value_deserialize_tag_list,
6147     };
6148
6149     gst_value.type = GST_TYPE_TAG_LIST;
6150     gst_value_register (&gst_value);
6151   }
6152   {
6153     static GstValueTable gst_value = {
6154       0,
6155       gst_value_compare_date,
6156       gst_value_serialize_date,
6157       gst_value_deserialize_date,
6158     };
6159
6160     gst_value.type = G_TYPE_DATE;
6161     gst_value_register (&gst_value);
6162   }
6163   {
6164     static GstValueTable gst_value = {
6165       0,
6166       gst_value_compare_date_time,
6167       gst_value_serialize_date_time,
6168       gst_value_deserialize_date_time,
6169     };
6170
6171     gst_value.type = gst_date_time_get_type ();
6172     gst_value_register (&gst_value);
6173   }
6174
6175   {
6176     static GstValueTable gst_value = {
6177       0,
6178       gst_value_compare_bitmask,
6179       gst_value_serialize_bitmask,
6180       gst_value_deserialize_bitmask,
6181     };
6182
6183     gst_value.type = gst_bitmask_get_type ();
6184     gst_value_register (&gst_value);
6185   }
6186
6187   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
6188   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
6189
6190   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
6191   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
6192   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
6193
6194   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
6195
6196   REGISTER_SERIALIZATION (G_TYPE_INT, int);
6197
6198   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
6199   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
6200
6201   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
6202   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
6203   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
6204
6205   REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar);
6206
6207   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
6208       gst_value_transform_int_range_string);
6209   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
6210       gst_value_transform_int64_range_string);
6211   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
6212       gst_value_transform_double_range_string);
6213   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
6214       gst_value_transform_fraction_range_string);
6215   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
6216       gst_value_transform_list_string);
6217   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
6218       gst_value_transform_array_string);
6219   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
6220       gst_value_transform_fraction_string);
6221   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
6222       gst_value_transform_string_fraction);
6223   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
6224       gst_value_transform_fraction_double);
6225   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
6226       gst_value_transform_fraction_float);
6227   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
6228       gst_value_transform_double_fraction);
6229   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
6230       gst_value_transform_float_fraction);
6231   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
6232       gst_value_transform_date_string);
6233   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
6234       gst_value_transform_string_date);
6235   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
6236       gst_value_transform_object_string);
6237   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
6238       gst_value_transform_bitmask_uint64);
6239   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
6240       gst_value_transform_bitmask_string);
6241   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
6242       gst_value_transform_uint64_bitmask);
6243   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
6244       gst_value_transform_string_bitmask);
6245
6246   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6247       gst_value_intersect_int_int_range);
6248   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6249       gst_value_intersect_int_range_int_range);
6250   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6251       gst_value_intersect_int64_int64_range);
6252   gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6253       gst_value_intersect_int64_range_int64_range);
6254   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6255       gst_value_intersect_double_double_range);
6256   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
6257       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
6258   gst_value_register_intersect_func (GST_TYPE_ARRAY,
6259       GST_TYPE_ARRAY, gst_value_intersect_array);
6260   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6261       gst_value_intersect_fraction_fraction_range);
6262   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
6263       GST_TYPE_FRACTION_RANGE,
6264       gst_value_intersect_fraction_range_fraction_range);
6265
6266   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6267       gst_value_subtract_int_int_range);
6268   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
6269       gst_value_subtract_int_range_int);
6270   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6271       gst_value_subtract_int_range_int_range);
6272   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6273       gst_value_subtract_int64_int64_range);
6274   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
6275       gst_value_subtract_int64_range_int64);
6276   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6277       gst_value_subtract_int64_range_int64_range);
6278   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6279       gst_value_subtract_double_double_range);
6280   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
6281       gst_value_subtract_double_range_double);
6282   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
6283       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
6284   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6285       gst_value_subtract_fraction_fraction_range);
6286   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
6287       gst_value_subtract_fraction_range_fraction);
6288   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
6289       GST_TYPE_FRACTION_RANGE,
6290       gst_value_subtract_fraction_range_fraction_range);
6291
6292   /* see bug #317246, #64994, #65041 */
6293   {
6294     volatile GType date_type = G_TYPE_DATE;
6295
6296     g_type_name (date_type);
6297   }
6298
6299   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6300       gst_value_union_int_int_range);
6301   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6302       gst_value_union_int_range_int_range);
6303
6304 #if 0
6305   /* Implement these if needed */
6306   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6307       gst_value_union_fraction_fraction_range);
6308   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
6309       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
6310 #endif
6311 }