gstvalue: Fix comparision of double range
[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 maximum 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 maximum 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 maximum 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[1].v_double == value1->data[1].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   return gst_string_take_and_wrap (gst_caps_to_string (caps));
1891 }
1892
1893 static gboolean
1894 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1895 {
1896   GstCaps *caps;
1897
1898   if (*s != '"') {
1899     caps = gst_caps_from_string (s);
1900   } else {
1901     gchar *str = gst_string_unwrap (s);
1902
1903     if (G_UNLIKELY (!str))
1904       return FALSE;
1905
1906     caps = gst_caps_from_string (str);
1907     g_free (str);
1908   }
1909
1910   if (caps) {
1911     g_value_take_boxed (dest, caps);
1912     return TRUE;
1913   }
1914   return FALSE;
1915 }
1916
1917 /**************
1918  * GstSegment *
1919  **************/
1920
1921 static gchar *
1922 gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
1923 {
1924   GstSegment *seg = g_value_get_boxed (value);
1925   gchar *t, *res;
1926   GstStructure *s;
1927
1928   s = gst_structure_new ("GstSegment",
1929       "flags", GST_TYPE_SEGMENT_FLAGS, seg->flags,
1930       "rate", G_TYPE_DOUBLE, seg->rate,
1931       "applied-rate", G_TYPE_DOUBLE, seg->applied_rate,
1932       "format", GST_TYPE_FORMAT, seg->format,
1933       "base", G_TYPE_UINT64, seg->base,
1934       "offset", G_TYPE_UINT64, seg->offset,
1935       "start", G_TYPE_UINT64, seg->start,
1936       "stop", G_TYPE_UINT64, seg->stop,
1937       "time", G_TYPE_UINT64, seg->time,
1938       "position", G_TYPE_UINT64, seg->position,
1939       "duration", G_TYPE_UINT64, seg->duration, NULL);
1940   t = gst_structure_to_string (s);
1941   if (escape) {
1942     res = g_strdup_printf ("\"%s\"", t);
1943     g_free (t);
1944   } else {
1945     res = t;
1946   }
1947   gst_structure_free (s);
1948
1949   return res;
1950 }
1951
1952 static gchar *
1953 gst_value_serialize_segment (const GValue * value)
1954 {
1955   return gst_value_serialize_segment_internal (value, TRUE);
1956 }
1957
1958 static gboolean
1959 gst_value_deserialize_segment (GValue * dest, const gchar * s)
1960 {
1961   GstStructure *str;
1962   GstSegment seg;
1963   gboolean res;
1964
1965   str = gst_structure_from_string (s, NULL);
1966   if (str == NULL)
1967     return FALSE;
1968
1969   res = gst_structure_get (str,
1970       "flags", GST_TYPE_SEGMENT_FLAGS, &seg.flags,
1971       "rate", G_TYPE_DOUBLE, &seg.rate,
1972       "applied-rate", G_TYPE_DOUBLE, &seg.applied_rate,
1973       "format", GST_TYPE_FORMAT, &seg.format,
1974       "base", G_TYPE_UINT64, &seg.base,
1975       "offset", G_TYPE_UINT64, &seg.offset,
1976       "start", G_TYPE_UINT64, &seg.start,
1977       "stop", G_TYPE_UINT64, &seg.stop,
1978       "time", G_TYPE_UINT64, &seg.time,
1979       "position", G_TYPE_UINT64, &seg.position,
1980       "duration", G_TYPE_UINT64, &seg.duration, NULL);
1981   gst_structure_free (str);
1982
1983   if (res)
1984     g_value_set_boxed (dest, &seg);
1985
1986   return res;
1987 }
1988
1989 /****************
1990  * GstStructure *
1991  ****************/
1992
1993 /**
1994  * gst_value_set_structure:
1995  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1996  * @structure: the structure to set the value to
1997  *
1998  * Sets the contents of @value to @structure.  The actual
1999  */
2000 void
2001 gst_value_set_structure (GValue * value, const GstStructure * structure)
2002 {
2003   g_return_if_fail (G_IS_VALUE (value));
2004   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
2005   g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
2006
2007   g_value_set_boxed (value, structure);
2008 }
2009
2010 /**
2011  * gst_value_get_structure:
2012  * @value: a GValue initialized to GST_TYPE_STRUCTURE
2013  *
2014  * Gets the contents of @value.
2015  *
2016  * Returns: (transfer none): the contents of @value
2017  */
2018 const GstStructure *
2019 gst_value_get_structure (const GValue * value)
2020 {
2021   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2022   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
2023
2024   return (GstStructure *) g_value_get_boxed (value);
2025 }
2026
2027 static gchar *
2028 gst_value_serialize_structure (const GValue * value)
2029 {
2030   GstStructure *structure = g_value_get_boxed (value);
2031
2032   return gst_string_take_and_wrap (gst_structure_to_string (structure));
2033 }
2034
2035 static gboolean
2036 gst_value_deserialize_structure (GValue * dest, const gchar * s)
2037 {
2038   GstStructure *structure;
2039
2040   if (*s != '"') {
2041     structure = gst_structure_from_string (s, NULL);
2042   } else {
2043     gchar *str = gst_string_unwrap (s);
2044
2045     if (G_UNLIKELY (!str))
2046       return FALSE;
2047
2048     structure = gst_structure_from_string (str, NULL);
2049     g_free (str);
2050   }
2051
2052   if (G_LIKELY (structure)) {
2053     g_value_take_boxed (dest, structure);
2054     return TRUE;
2055   }
2056   return FALSE;
2057 }
2058
2059 /*******************
2060  * GstCapsFeatures *
2061  *******************/
2062
2063 /**
2064  * gst_value_set_caps_features:
2065  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2066  * @features: the features to set the value to
2067  *
2068  * Sets the contents of @value to @features.
2069  */
2070 void
2071 gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
2072 {
2073   g_return_if_fail (G_IS_VALUE (value));
2074   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
2075   g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
2076
2077   g_value_set_boxed (value, features);
2078 }
2079
2080 /**
2081  * gst_value_get_caps_features:
2082  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2083  *
2084  * Gets the contents of @value.
2085  *
2086  * Returns: (transfer none): the contents of @value
2087  */
2088 const GstCapsFeatures *
2089 gst_value_get_caps_features (const GValue * value)
2090 {
2091   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2092   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
2093
2094   return (GstCapsFeatures *) g_value_get_boxed (value);
2095 }
2096
2097 static gchar *
2098 gst_value_serialize_caps_features (const GValue * value)
2099 {
2100   GstCapsFeatures *features = g_value_get_boxed (value);
2101
2102   return gst_string_take_and_wrap (gst_caps_features_to_string (features));
2103 }
2104
2105 static gboolean
2106 gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
2107 {
2108   GstCapsFeatures *features;
2109
2110   if (*s != '"') {
2111     features = gst_caps_features_from_string (s);
2112   } else {
2113     gchar *str = gst_string_unwrap (s);
2114
2115     if (G_UNLIKELY (!str))
2116       return FALSE;
2117
2118     features = gst_caps_features_from_string (str);
2119     g_free (str);
2120   }
2121
2122   if (G_LIKELY (features)) {
2123     g_value_take_boxed (dest, features);
2124     return TRUE;
2125   }
2126   return FALSE;
2127 }
2128
2129 /**************
2130  * GstTagList *
2131  **************/
2132
2133 static gboolean
2134 gst_value_deserialize_tag_list (GValue * dest, const gchar * s)
2135 {
2136   GstTagList *taglist;
2137
2138   if (*s != '"') {
2139     taglist = gst_tag_list_new_from_string (s);
2140   } else {
2141     gchar *str = gst_string_unwrap (s);
2142
2143     if (G_UNLIKELY (!str))
2144       return FALSE;
2145
2146     taglist = gst_tag_list_new_from_string (str);
2147     g_free (str);
2148   }
2149
2150   if (G_LIKELY (taglist != NULL)) {
2151     g_value_take_boxed (dest, taglist);
2152     return TRUE;
2153   }
2154   return FALSE;
2155 }
2156
2157 static gchar *
2158 gst_value_serialize_tag_list (const GValue * value)
2159 {
2160   GstTagList *taglist = g_value_get_boxed (value);
2161
2162   return gst_string_take_and_wrap (gst_tag_list_to_string (taglist));
2163 }
2164
2165
2166 /*************
2167  * GstBuffer *
2168  *************/
2169
2170 static gint
2171 compare_buffer (GstBuffer * buf1, GstBuffer * buf2)
2172 {
2173   gsize size1, size2;
2174   GstMapInfo info1, info2;
2175   gint result, mret;
2176
2177   if (buf1 == buf2)
2178     return GST_VALUE_EQUAL;
2179
2180   size1 = gst_buffer_get_size (buf1);
2181   size2 = gst_buffer_get_size (buf2);
2182
2183   if (size1 != size2)
2184     return GST_VALUE_UNORDERED;
2185
2186   if (size1 == 0)
2187     return GST_VALUE_EQUAL;
2188
2189   if (!gst_buffer_map (buf1, &info1, GST_MAP_READ))
2190     return GST_VALUE_UNORDERED;
2191
2192   if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
2193     gst_buffer_unmap (buf1, &info1);
2194     return GST_VALUE_UNORDERED;
2195   }
2196
2197   mret = memcmp (info1.data, info2.data, info1.size);
2198   if (mret == 0)
2199     result = GST_VALUE_EQUAL;
2200   else if (mret < 0)
2201     result = GST_VALUE_LESS_THAN;
2202   else
2203     result = GST_VALUE_GREATER_THAN;
2204
2205   gst_buffer_unmap (buf1, &info1);
2206   gst_buffer_unmap (buf2, &info2);
2207
2208   return result;
2209 }
2210
2211 static gint
2212 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
2213 {
2214   GstBuffer *buf1 = gst_value_get_buffer (value1);
2215   GstBuffer *buf2 = gst_value_get_buffer (value2);
2216
2217   return compare_buffer (buf1, buf2);
2218 }
2219
2220 static gchar *
2221 gst_value_serialize_buffer (const GValue * value)
2222 {
2223   GstMapInfo info;
2224   guint8 *data;
2225   gint i;
2226   gchar *string;
2227   GstBuffer *buffer;
2228
2229   buffer = gst_value_get_buffer (value);
2230   if (buffer == NULL)
2231     return NULL;
2232
2233   if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
2234     return NULL;
2235
2236   data = info.data;
2237
2238   string = g_malloc (info.size * 2 + 1);
2239   for (i = 0; i < info.size; i++) {
2240     sprintf (string + i * 2, "%02x", data[i]);
2241   }
2242   string[info.size * 2] = 0;
2243
2244   gst_buffer_unmap (buffer, &info);
2245
2246   return string;
2247 }
2248
2249 static gboolean
2250 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
2251 {
2252   GstBuffer *buffer;
2253   gint len;
2254   gchar ts[3];
2255   GstMapInfo info;
2256   guint8 *data;
2257   gint i;
2258
2259   len = strlen (s);
2260   if (len & 1)
2261     goto wrong_length;
2262
2263   buffer = gst_buffer_new_allocate (NULL, len / 2, NULL);
2264   if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
2265     goto map_failed;
2266   data = info.data;
2267
2268   for (i = 0; i < len / 2; i++) {
2269     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
2270       goto wrong_char;
2271
2272     ts[0] = s[i * 2 + 0];
2273     ts[1] = s[i * 2 + 1];
2274     ts[2] = 0;
2275
2276     data[i] = (guint8) strtoul (ts, NULL, 16);
2277   }
2278   gst_buffer_unmap (buffer, &info);
2279
2280   gst_value_take_buffer (dest, buffer);
2281
2282   return TRUE;
2283
2284   /* ERRORS */
2285 wrong_length:
2286   {
2287     return FALSE;
2288   }
2289 map_failed:
2290   {
2291     return FALSE;
2292   }
2293 wrong_char:
2294   {
2295     gst_buffer_unref (buffer);
2296     gst_buffer_unmap (buffer, &info);
2297     return FALSE;
2298   }
2299 }
2300
2301 /*************
2302  * GstSample *
2303  *************/
2304
2305 /* This function is mostly used for comparing image/buffer tags in taglists */
2306 static gint
2307 gst_value_compare_sample (const GValue * value1, const GValue * value2)
2308 {
2309   GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1));
2310   GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2));
2311
2312   /* FIXME: should we take into account anything else such as caps? */
2313   return compare_buffer (buf1, buf2);
2314 }
2315
2316 static gchar *
2317 gst_value_serialize_sample (const GValue * value)
2318 {
2319   const GstStructure *info_structure;
2320   GstSegment *segment;
2321   GstBuffer *buffer;
2322   GstCaps *caps;
2323   GstSample *sample;
2324   GValue val = { 0, };
2325   gchar *info_str, *caps_str, *tmp;
2326   gchar *buf_str, *seg_str, *s;
2327
2328   sample = g_value_get_boxed (value);
2329
2330   buffer = gst_sample_get_buffer (sample);
2331   if (buffer) {
2332     g_value_init (&val, GST_TYPE_BUFFER);
2333     g_value_set_boxed (&val, buffer);
2334     buf_str = gst_value_serialize_buffer (&val);
2335     g_value_unset (&val);
2336   } else {
2337     buf_str = g_strdup ("None");
2338   }
2339
2340   caps = gst_sample_get_caps (sample);
2341   if (caps) {
2342     tmp = gst_caps_to_string (caps);
2343     caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2344     g_strdelimit (caps_str, "=", '_');
2345     g_free (tmp);
2346   } else {
2347     caps_str = g_strdup ("None");
2348   }
2349
2350   segment = gst_sample_get_segment (sample);
2351   if (segment) {
2352     g_value_init (&val, GST_TYPE_SEGMENT);
2353     g_value_set_boxed (&val, segment);
2354     tmp = gst_value_serialize_segment_internal (&val, FALSE);
2355     seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2356     g_strdelimit (seg_str, "=", '_');
2357     g_free (tmp);
2358     g_value_unset (&val);
2359   } else {
2360     seg_str = g_strdup ("None");
2361   }
2362
2363   info_structure = gst_sample_get_info (sample);
2364   if (info_structure) {
2365     tmp = gst_structure_to_string (info_structure);
2366     info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2367     g_strdelimit (info_str, "=", '_');
2368     g_free (tmp);
2369   } else {
2370     info_str = g_strdup ("None");
2371   }
2372
2373   s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
2374   g_free (buf_str);
2375   g_free (caps_str);
2376   g_free (seg_str);
2377   g_free (info_str);
2378
2379   return s;
2380 }
2381
2382 static gboolean
2383 gst_value_deserialize_sample (GValue * dest, const gchar * s)
2384 {
2385   GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
2386   GstStructure *info;
2387   GstSample *sample;
2388   GstCaps *caps;
2389   gboolean ret = FALSE;
2390   gchar **fields;
2391   gsize outlen;
2392   gint len;
2393
2394   GST_TRACE ("deserialize '%s'", s);
2395
2396   fields = g_strsplit (s, ":", -1);
2397   len = g_strv_length (fields);
2398   if (len != 4)
2399     goto wrong_length;
2400
2401   g_value_init (&bval, GST_TYPE_BUFFER);
2402   g_value_init (&sval, GST_TYPE_SEGMENT);
2403
2404   if (!gst_value_deserialize_buffer (&bval, fields[0]))
2405     goto fail;
2406
2407   if (strcmp (fields[1], "None") != 0) {
2408     g_strdelimit (fields[1], "_", '=');
2409     g_base64_decode_inplace (fields[1], &outlen);
2410     GST_TRACE ("caps    : %s", fields[1]);
2411     caps = gst_caps_from_string (fields[1]);
2412     if (caps == NULL)
2413       goto fail;
2414   } else {
2415     caps = NULL;
2416   }
2417
2418   if (strcmp (fields[2], "None") != 0) {
2419     g_strdelimit (fields[2], "_", '=');
2420     g_base64_decode_inplace (fields[2], &outlen);
2421     GST_TRACE ("segment : %s", fields[2]);
2422     if (!gst_value_deserialize_segment (&sval, fields[2]))
2423       goto fail;
2424   }
2425
2426   if (strcmp (fields[3], "None") != 0) {
2427     g_strdelimit (fields[3], "_", '=');
2428     g_base64_decode_inplace (fields[3], &outlen);
2429     GST_TRACE ("info    : %s", fields[3]);
2430     info = gst_structure_from_string (fields[3], NULL);
2431     if (info == NULL)
2432       goto fail;
2433   } else {
2434     info = NULL;
2435   }
2436
2437   sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
2438       g_value_get_boxed (&sval), info);
2439
2440   g_value_take_boxed (dest, sample);
2441
2442   if (caps)
2443     gst_caps_unref (caps);
2444
2445   ret = TRUE;
2446
2447 fail:
2448
2449   g_value_unset (&bval);
2450   g_value_unset (&sval);
2451
2452 wrong_length:
2453
2454   g_strfreev (fields);
2455
2456   return ret;
2457 }
2458
2459 /***********
2460  * boolean *
2461  ***********/
2462
2463 static gint
2464 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
2465 {
2466   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
2467     return GST_VALUE_EQUAL;
2468   return GST_VALUE_UNORDERED;
2469 }
2470
2471 static gchar *
2472 gst_value_serialize_boolean (const GValue * value)
2473 {
2474   if (value->data[0].v_int) {
2475     return g_strdup ("true");
2476   }
2477   return g_strdup ("false");
2478 }
2479
2480 static gboolean
2481 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
2482 {
2483   gboolean ret = FALSE;
2484
2485   if (g_ascii_strcasecmp (s, "true") == 0 ||
2486       g_ascii_strcasecmp (s, "yes") == 0 ||
2487       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
2488     g_value_set_boolean (dest, TRUE);
2489     ret = TRUE;
2490   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
2491       g_ascii_strcasecmp (s, "no") == 0 ||
2492       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
2493     g_value_set_boolean (dest, FALSE);
2494     ret = TRUE;
2495   }
2496
2497   return ret;
2498 }
2499
2500 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
2501 static gint                                                             \
2502 gst_value_compare_ ## _type                                             \
2503 (const GValue * value1, const GValue * value2)                          \
2504 {                                                                       \
2505   g ## _type val1 = g_value_get_ ## _type (value1);                     \
2506   g ## _type val2 = g_value_get_ ## _type (value2);                     \
2507   if (val1 > val2)                                                      \
2508     return GST_VALUE_GREATER_THAN;                                      \
2509   if (val1 < val2)                                                      \
2510     return GST_VALUE_LESS_THAN;                                         \
2511   return GST_VALUE_EQUAL;                                               \
2512 }                                                                       \
2513                                                                         \
2514 static gchar *                                                          \
2515 gst_value_serialize_ ## _type (const GValue * value)                    \
2516 {                                                                       \
2517   GValue val = { 0, };                                                  \
2518   g_value_init (&val, G_TYPE_STRING);                                   \
2519   if (!g_value_transform (value, &val))                                 \
2520     g_assert_not_reached ();                                            \
2521   /* NO_COPY_MADNESS!!! */                                              \
2522   return (char *) g_value_get_string (&val);                            \
2523 }
2524
2525 /* deserialize the given s into to as a gint64.
2526  * check if the result is actually storeable in the given size number of
2527  * bytes.
2528  */
2529 static gboolean
2530 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
2531     gint64 min, gint64 max, gint size)
2532 {
2533   gboolean ret = FALSE;
2534   gchar *end;
2535   gint64 mask = -1;
2536
2537   errno = 0;
2538   *to = g_ascii_strtoull (s, &end, 0);
2539   /* a range error is a definitive no-no */
2540   if (errno == ERANGE) {
2541     return FALSE;
2542   }
2543
2544   if (*end == 0) {
2545     ret = TRUE;
2546   } else {
2547     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
2548       *to = G_LITTLE_ENDIAN;
2549       ret = TRUE;
2550     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
2551       *to = G_BIG_ENDIAN;
2552       ret = TRUE;
2553     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
2554       *to = G_BYTE_ORDER;
2555       ret = TRUE;
2556     } else if (g_ascii_strcasecmp (s, "min") == 0) {
2557       *to = min;
2558       ret = TRUE;
2559     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2560       *to = max;
2561       ret = TRUE;
2562     }
2563   }
2564   if (ret) {
2565     /* by definition, a gint64 fits into a gint64; so ignore those */
2566     if (size != sizeof (mask)) {
2567       if (*to >= 0) {
2568         /* for positive numbers, we create a mask of 1's outside of the range
2569          * and 0's inside the range.  An and will thus keep only 1 bits
2570          * outside of the range */
2571         mask <<= (size * 8);
2572         if ((mask & *to) != 0) {
2573           ret = FALSE;
2574         }
2575       } else {
2576         /* for negative numbers, we do a 2's complement version */
2577         mask <<= ((size * 8) - 1);
2578         if ((mask & *to) != mask) {
2579           ret = FALSE;
2580         }
2581       }
2582     }
2583   }
2584   return ret;
2585 }
2586
2587 #define CREATE_SERIALIZATION(_type,_macro)                              \
2588 CREATE_SERIALIZATION_START(_type,_macro)                                \
2589                                                                         \
2590 static gboolean                                                         \
2591 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2592 {                                                                       \
2593   gint64 x;                                                             \
2594                                                                         \
2595   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
2596       G_MAX ## _macro, sizeof (g ## _type))) {                          \
2597     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
2598     return TRUE;                                                        \
2599   } else {                                                              \
2600     return FALSE;                                                       \
2601   }                                                                     \
2602 }
2603
2604 #define CREATE_USERIALIZATION(_type,_macro)                             \
2605 CREATE_SERIALIZATION_START(_type,_macro)                                \
2606                                                                         \
2607 static gboolean                                                         \
2608 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2609 {                                                                       \
2610   gint64 x;                                                             \
2611   gchar *end;                                                           \
2612   gboolean ret = FALSE;                                                 \
2613                                                                         \
2614   errno = 0;                                                            \
2615   x = g_ascii_strtoull (s, &end, 0);                                    \
2616   /* a range error is a definitive no-no */                             \
2617   if (errno == ERANGE) {                                                \
2618     return FALSE;                                                       \
2619   }                                                                     \
2620   /* the cast ensures the range check later on makes sense */           \
2621   x = (g ## _type) x;                                                   \
2622   if (*end == 0) {                                                      \
2623     ret = TRUE;                                                         \
2624   } else {                                                              \
2625     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
2626       x = G_LITTLE_ENDIAN;                                              \
2627       ret = TRUE;                                                       \
2628     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
2629       x = G_BIG_ENDIAN;                                                 \
2630       ret = TRUE;                                                       \
2631     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
2632       x = G_BYTE_ORDER;                                                 \
2633       ret = TRUE;                                                       \
2634     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
2635       x = 0;                                                            \
2636       ret = TRUE;                                                       \
2637     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
2638       x = G_MAX ## _macro;                                              \
2639       ret = TRUE;                                                       \
2640     }                                                                   \
2641   }                                                                     \
2642   if (ret) {                                                            \
2643     if (x > G_MAX ## _macro) {                                          \
2644       ret = FALSE;                                                      \
2645     } else {                                                            \
2646       g_value_set_ ## _type (dest, x);                                  \
2647     }                                                                   \
2648   }                                                                     \
2649   return ret;                                                           \
2650 }
2651
2652 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
2653 G_STMT_START {                                                          \
2654   static const GstValueTable gst_value = {                              \
2655     _gtype,                                                             \
2656     gst_value_compare_ ## _type,                                        \
2657     gst_value_serialize_ ## _type,                                      \
2658     gst_value_deserialize_ ## _type,                                    \
2659   };                                                                    \
2660                                                                         \
2661   gst_value_register (&gst_value);                                      \
2662 } G_STMT_END
2663
2664 CREATE_SERIALIZATION (int, INT);
2665 CREATE_SERIALIZATION (int64, INT64);
2666 CREATE_SERIALIZATION (long, LONG);
2667
2668 CREATE_USERIALIZATION (uint, UINT);
2669 CREATE_USERIALIZATION (uint64, UINT64);
2670 CREATE_USERIALIZATION (ulong, ULONG);
2671
2672 /* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */
2673 #ifndef G_MAXUCHAR
2674 #define G_MAXUCHAR 255
2675 #endif
2676 CREATE_USERIALIZATION (uchar, UCHAR);
2677
2678 /**********
2679  * double *
2680  **********/
2681 static gint
2682 gst_value_compare_double (const GValue * value1, const GValue * value2)
2683 {
2684   if (value1->data[0].v_double > value2->data[0].v_double)
2685     return GST_VALUE_GREATER_THAN;
2686   if (value1->data[0].v_double < value2->data[0].v_double)
2687     return GST_VALUE_LESS_THAN;
2688   if (value1->data[0].v_double == value2->data[0].v_double)
2689     return GST_VALUE_EQUAL;
2690   return GST_VALUE_UNORDERED;
2691 }
2692
2693 static gchar *
2694 gst_value_serialize_double (const GValue * value)
2695 {
2696   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2697
2698   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
2699   return g_strdup (d);
2700 }
2701
2702 static gboolean
2703 gst_value_deserialize_double (GValue * dest, const gchar * s)
2704 {
2705   gdouble x;
2706   gboolean ret = FALSE;
2707   gchar *end;
2708
2709   x = g_ascii_strtod (s, &end);
2710   if (*end == 0) {
2711     ret = TRUE;
2712   } else {
2713     if (g_ascii_strcasecmp (s, "min") == 0) {
2714       x = -G_MAXDOUBLE;
2715       ret = TRUE;
2716     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2717       x = G_MAXDOUBLE;
2718       ret = TRUE;
2719     }
2720   }
2721   if (ret) {
2722     g_value_set_double (dest, x);
2723   }
2724   return ret;
2725 }
2726
2727 /*********
2728  * float *
2729  *********/
2730
2731 static gint
2732 gst_value_compare_float (const GValue * value1, const GValue * value2)
2733 {
2734   if (value1->data[0].v_float > value2->data[0].v_float)
2735     return GST_VALUE_GREATER_THAN;
2736   if (value1->data[0].v_float < value2->data[0].v_float)
2737     return GST_VALUE_LESS_THAN;
2738   if (value1->data[0].v_float == value2->data[0].v_float)
2739     return GST_VALUE_EQUAL;
2740   return GST_VALUE_UNORDERED;
2741 }
2742
2743 static gchar *
2744 gst_value_serialize_float (const GValue * value)
2745 {
2746   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2747
2748   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
2749   return g_strdup (d);
2750 }
2751
2752 static gboolean
2753 gst_value_deserialize_float (GValue * dest, const gchar * s)
2754 {
2755   gdouble x;
2756   gboolean ret = FALSE;
2757   gchar *end;
2758
2759   x = g_ascii_strtod (s, &end);
2760   if (*end == 0) {
2761     ret = TRUE;
2762   } else {
2763     if (g_ascii_strcasecmp (s, "min") == 0) {
2764       x = -G_MAXFLOAT;
2765       ret = TRUE;
2766     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2767       x = G_MAXFLOAT;
2768       ret = TRUE;
2769     }
2770   }
2771   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
2772     ret = FALSE;
2773   if (ret) {
2774     g_value_set_float (dest, (float) x);
2775   }
2776   return ret;
2777 }
2778
2779 /**********
2780  * string *
2781  **********/
2782
2783 static gint
2784 gst_value_compare_string (const GValue * value1, const GValue * value2)
2785 {
2786   if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
2787     /* if only one is NULL, no match - otherwise both NULL == EQUAL */
2788     if (value1->data[0].v_pointer != value2->data[0].v_pointer)
2789       return GST_VALUE_UNORDERED;
2790   } else {
2791     gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
2792
2793     if (x < 0)
2794       return GST_VALUE_LESS_THAN;
2795     if (x > 0)
2796       return GST_VALUE_GREATER_THAN;
2797   }
2798
2799   return GST_VALUE_EQUAL;
2800 }
2801
2802 static gint
2803 gst_string_measure_wrapping (const gchar * s)
2804 {
2805   gint len;
2806   gboolean wrap = FALSE;
2807
2808   if (G_UNLIKELY (s == NULL))
2809     return -1;
2810
2811   /* Special case: the actual string NULL needs wrapping */
2812   if (G_UNLIKELY (strcmp (s, "NULL") == 0))
2813     return 4;
2814
2815   len = 0;
2816   while (*s) {
2817     if (GST_ASCII_IS_STRING (*s)) {
2818       len++;
2819     } else if (*s < 0x20 || *s >= 0x7f) {
2820       wrap = TRUE;
2821       len += 4;
2822     } else {
2823       wrap = TRUE;
2824       len += 2;
2825     }
2826     s++;
2827   }
2828
2829   /* Wrap the string if we found something that needs
2830    * wrapping, or the empty string (len == 0) */
2831   return (wrap || len == 0) ? len : -1;
2832 }
2833
2834 static gchar *
2835 gst_string_wrap_inner (const gchar * s, gint len)
2836 {
2837   gchar *d, *e;
2838
2839   e = d = g_malloc (len + 3);
2840
2841   *e++ = '\"';
2842   while (*s) {
2843     if (GST_ASCII_IS_STRING (*s)) {
2844       *e++ = *s++;
2845     } else if (*s < 0x20 || *s >= 0x7f) {
2846       *e++ = '\\';
2847       *e++ = '0' + ((*(guchar *) s) >> 6);
2848       *e++ = '0' + (((*s) >> 3) & 0x7);
2849       *e++ = '0' + ((*s++) & 0x7);
2850     } else {
2851       *e++ = '\\';
2852       *e++ = *s++;
2853     }
2854   }
2855   *e++ = '\"';
2856   *e = 0;
2857
2858   g_assert (e - d <= len + 3);
2859   return d;
2860 }
2861
2862 /* Do string wrapping/escaping */
2863 static gchar *
2864 gst_string_wrap (const gchar * s)
2865 {
2866   gint len = gst_string_measure_wrapping (s);
2867
2868   if (G_LIKELY (len < 0))
2869     return g_strdup (s);
2870
2871   return gst_string_wrap_inner (s, len);
2872 }
2873
2874 /* Same as above, but take ownership of the string */
2875 static gchar *
2876 gst_string_take_and_wrap (gchar * s)
2877 {
2878   gchar *out;
2879   gint len = gst_string_measure_wrapping (s);
2880
2881   if (G_LIKELY (len < 0))
2882     return s;
2883
2884   out = gst_string_wrap_inner (s, len);
2885   g_free (s);
2886
2887   return out;
2888 }
2889
2890 /*
2891  * This function takes a string delimited with double quotes (")
2892  * and unescapes any \xxx octal numbers.
2893  *
2894  * If sequences of \y are found where y is not in the range of
2895  * 0->3, y is copied unescaped.
2896  *
2897  * If \xyy is found where x is an octal number but y is not, an
2898  * error is encountered and NULL is returned.
2899  *
2900  * the input string must be \0 terminated.
2901  */
2902 static gchar *
2903 gst_string_unwrap (const gchar * s)
2904 {
2905   gchar *ret;
2906   gchar *read, *write;
2907
2908   /* NULL string returns NULL */
2909   if (s == NULL)
2910     return NULL;
2911
2912   /* strings not starting with " are invalid */
2913   if (*s != '"')
2914     return NULL;
2915
2916   /* make copy of original string to hold the result. This
2917    * string will always be smaller than the original */
2918   ret = g_strdup (s);
2919   read = ret;
2920   write = ret;
2921
2922   /* need to move to the next position as we parsed the " */
2923   read++;
2924
2925   while (*read) {
2926     if (GST_ASCII_IS_STRING (*read)) {
2927       /* normal chars are just copied */
2928       *write++ = *read++;
2929     } else if (*read == '"') {
2930       /* quote marks end of string */
2931       break;
2932     } else if (*read == '\\') {
2933       /* got an escape char, move to next position to read a tripplet
2934        * of octal numbers */
2935       read++;
2936       /* is the next char a possible first octal number? */
2937       if (*read >= '0' && *read <= '3') {
2938         /* parse other 2 numbers, if one of them is not in the range of
2939          * an octal number, we error. We also catch the case where a zero
2940          * byte is found here. */
2941         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
2942           goto beach;
2943
2944         /* now convert the octal number to a byte again. */
2945         *write++ = ((read[0] - '0') << 6) +
2946             ((read[1] - '0') << 3) + (read[2] - '0');
2947
2948         read += 3;
2949       } else {
2950         /* if we run into a \0 here, we definitely won't get a quote later */
2951         if (*read == 0)
2952           goto beach;
2953
2954         /* else copy \X sequence */
2955         *write++ = *read++;
2956       }
2957     } else {
2958       /* weird character, error */
2959       goto beach;
2960     }
2961   }
2962   /* if the string is not ending in " and zero terminated, we error */
2963   if (*read != '"' || read[1] != '\0')
2964     goto beach;
2965
2966   /* null terminate result string and return */
2967   *write = '\0';
2968   return ret;
2969
2970 beach:
2971   g_free (ret);
2972   return NULL;
2973 }
2974
2975 static gchar *
2976 gst_value_serialize_string (const GValue * value)
2977 {
2978   return gst_string_wrap (value->data[0].v_pointer);
2979 }
2980
2981 static gboolean
2982 gst_value_deserialize_string (GValue * dest, const gchar * s)
2983 {
2984   if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
2985     g_value_set_string (dest, NULL);
2986     return TRUE;
2987   } else if (G_LIKELY (*s != '"')) {
2988     if (!g_utf8_validate (s, -1, NULL))
2989       return FALSE;
2990     g_value_set_string (dest, s);
2991     return TRUE;
2992   } else {
2993     gchar *str = gst_string_unwrap (s);
2994     if (G_UNLIKELY (!str))
2995       return FALSE;
2996     g_value_take_string (dest, str);
2997   }
2998
2999   return TRUE;
3000 }
3001
3002 /********
3003  * enum *
3004  ********/
3005
3006 static gint
3007 gst_value_compare_enum (const GValue * value1, const GValue * value2)
3008 {
3009   GEnumValue *en1, *en2;
3010   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3011   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3012
3013   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3014   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3015   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
3016   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
3017   g_type_class_unref (klass1);
3018   g_type_class_unref (klass2);
3019   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
3020   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
3021   if (en1->value < en2->value)
3022     return GST_VALUE_LESS_THAN;
3023   if (en1->value > en2->value)
3024     return GST_VALUE_GREATER_THAN;
3025
3026   return GST_VALUE_EQUAL;
3027 }
3028
3029 static gchar *
3030 gst_value_serialize_enum (const GValue * value)
3031 {
3032   GEnumValue *en;
3033   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
3034
3035   g_return_val_if_fail (klass, NULL);
3036   en = g_enum_get_value (klass, g_value_get_enum (value));
3037   g_type_class_unref (klass);
3038
3039   /* might be one of the custom formats registered later */
3040   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
3041     const GstFormatDefinition *format_def;
3042
3043     format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value));
3044     g_return_val_if_fail (format_def != NULL, NULL);
3045     return g_strdup (format_def->description);
3046   }
3047
3048   g_return_val_if_fail (en, NULL);
3049   return g_strdup (en->value_name);
3050 }
3051
3052 static gint
3053 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
3054     const gchar * s)
3055 {
3056   const GstFormatDefinition *format_def =
3057       g_value_get_pointer (format_def_value);
3058
3059   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
3060     return 0;
3061
3062   return g_ascii_strcasecmp (s, format_def->description);
3063 }
3064
3065 static gboolean
3066 gst_value_deserialize_enum (GValue * dest, const gchar * s)
3067 {
3068   GEnumValue *en;
3069   gchar *endptr = NULL;
3070   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3071
3072   g_return_val_if_fail (klass, FALSE);
3073   if (!(en = g_enum_get_value_by_name (klass, s))) {
3074     if (!(en = g_enum_get_value_by_nick (klass, s))) {
3075       gint i = strtol (s, &endptr, 0);
3076
3077       if (endptr && *endptr == '\0') {
3078         en = g_enum_get_value (klass, i);
3079       }
3080     }
3081   }
3082   g_type_class_unref (klass);
3083
3084   /* might be one of the custom formats registered later */
3085   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
3086     GValue res = { 0, };
3087     const GstFormatDefinition *format_def;
3088     GstIterator *iter;
3089     gboolean found;
3090
3091     iter = gst_format_iterate_definitions ();
3092
3093     found = gst_iterator_find_custom (iter,
3094         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
3095
3096     if (found) {
3097       format_def = g_value_get_pointer (&res);
3098       g_return_val_if_fail (format_def != NULL, FALSE);
3099       g_value_set_enum (dest, (gint) format_def->value);
3100       g_value_unset (&res);
3101     }
3102     gst_iterator_free (iter);
3103     return found;
3104   }
3105
3106   /* enum name/nick not found */
3107   if (en == NULL)
3108     return FALSE;
3109
3110   g_value_set_enum (dest, en->value);
3111   return TRUE;
3112 }
3113
3114 /********
3115  * flags *
3116  ********/
3117
3118 /* we just compare the value here */
3119 static gint
3120 gst_value_compare_flags (const GValue * value1, const GValue * value2)
3121 {
3122   guint fl1, fl2;
3123   GFlagsClass *klass1 =
3124       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3125   GFlagsClass *klass2 =
3126       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3127
3128   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3129   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3130   fl1 = g_value_get_flags (value1);
3131   fl2 = g_value_get_flags (value2);
3132   g_type_class_unref (klass1);
3133   g_type_class_unref (klass2);
3134   if (fl1 < fl2)
3135     return GST_VALUE_LESS_THAN;
3136   if (fl1 > fl2)
3137     return GST_VALUE_GREATER_THAN;
3138
3139   return GST_VALUE_EQUAL;
3140 }
3141
3142 /* the different flags are serialized separated with a + */
3143 static gchar *
3144 gst_value_serialize_flags (const GValue * value)
3145 {
3146   guint flags;
3147   GFlagsValue *fl;
3148   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
3149   gchar *result, *tmp;
3150   gboolean first = TRUE;
3151
3152   g_return_val_if_fail (klass, NULL);
3153
3154   flags = g_value_get_flags (value);
3155
3156   /* if no flags are set, try to serialize to the _NONE string */
3157   if (!flags) {
3158     fl = g_flags_get_first_value (klass, flags);
3159     if (fl)
3160       return g_strdup (fl->value_name);
3161     else
3162       return g_strdup ("0");
3163   }
3164
3165   /* some flags are set, so serialize one by one */
3166   result = g_strdup ("");
3167   while (flags) {
3168     fl = g_flags_get_first_value (klass, flags);
3169     if (fl != NULL) {
3170       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
3171       g_free (result);
3172       result = tmp;
3173       first = FALSE;
3174
3175       /* clear flag */
3176       flags &= ~fl->value;
3177     }
3178   }
3179   g_type_class_unref (klass);
3180
3181   return result;
3182 }
3183
3184 static gboolean
3185 gst_value_deserialize_flags (GValue * dest, const gchar * s)
3186 {
3187   GFlagsValue *fl;
3188   gchar *endptr = NULL;
3189   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3190   gchar **split;
3191   guint flags;
3192   gint i;
3193
3194   g_return_val_if_fail (klass, FALSE);
3195
3196   /* split into parts delimited with + */
3197   split = g_strsplit (s, "+", 0);
3198
3199   flags = 0;
3200   i = 0;
3201   /* loop over each part */
3202   while (split[i]) {
3203     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
3204       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
3205         gint val = strtol (split[i], &endptr, 0);
3206
3207         /* just or numeric value */
3208         if (endptr && *endptr == '\0') {
3209           flags |= val;
3210         }
3211       }
3212     }
3213     if (fl) {
3214       flags |= fl->value;
3215     }
3216     i++;
3217   }
3218   g_strfreev (split);
3219   g_type_class_unref (klass);
3220   g_value_set_flags (dest, flags);
3221
3222   return TRUE;
3223 }
3224
3225 /****************
3226  * subset *
3227  ****************/
3228
3229 static gboolean
3230 gst_value_is_subset_int_range_int_range (const GValue * value1,
3231     const GValue * value2)
3232 {
3233   gint gcd;
3234
3235   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
3236   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
3237
3238   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
3239       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
3240     return FALSE;
3241   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
3242       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
3243     return FALSE;
3244
3245   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
3246     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
3247         INT_RANGE_STEP (value1))
3248       return FALSE;
3249     return TRUE;
3250   }
3251
3252   gcd =
3253       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
3254       INT_RANGE_STEP (value2));
3255   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
3256     return FALSE;
3257
3258   return TRUE;
3259 }
3260
3261 static gboolean
3262 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
3263     const GValue * value2)
3264 {
3265   gint64 gcd;
3266
3267   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
3268   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
3269
3270   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
3271     return FALSE;
3272   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
3273     return FALSE;
3274
3275   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
3276     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
3277         INT64_RANGE_STEP (value1))
3278       return FALSE;
3279     return TRUE;
3280   }
3281
3282   gcd =
3283       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
3284       INT64_RANGE_STEP (value2));
3285   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
3286     return FALSE;
3287
3288   return TRUE;
3289 }
3290
3291 /**
3292  * gst_value_is_subset:
3293  * @value1: a #GValue
3294  * @value2: a #GValue
3295  *
3296  * Check that @value1 is a subset of @value2.
3297  *
3298  * Return: %TRUE is @value1 is a subset of @value2
3299  */
3300 gboolean
3301 gst_value_is_subset (const GValue * value1, const GValue * value2)
3302 {
3303   /* special case for int/int64 ranges, since we cannot compute
3304      the difference for those when they have different steps,
3305      and it's actually a lot simpler to compute whether a range
3306      is a subset of another. */
3307   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
3308     return gst_value_is_subset_int_range_int_range (value1, value2);
3309   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
3310       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
3311     return gst_value_is_subset_int64_range_int64_range (value1, value2);
3312   }
3313
3314   /*
3315    * 1 - [1,2] = empty
3316    * -> !subset
3317    *
3318    * [1,2] - 1 = 2
3319    *  -> 1 - [1,2] = empty
3320    *  -> subset
3321    *
3322    * [1,3] - [1,2] = 3
3323    * -> [1,2] - [1,3] = empty
3324    * -> subset
3325    *
3326    * {1,2} - {1,3} = 2
3327    * -> {1,3} - {1,2} = 3
3328    * -> !subset
3329    *
3330    *  First caps subtraction needs to return a non-empty set, second
3331    *  subtractions needs to give en empty set.
3332    *  Both substractions are switched below, as it's faster that way.
3333    */
3334   if (!gst_value_subtract (NULL, value1, value2)) {
3335     if (gst_value_subtract (NULL, value2, value1)) {
3336       return TRUE;
3337     }
3338   }
3339   return FALSE;
3340 }
3341
3342 /*********
3343  * union *
3344  *********/
3345
3346 static gboolean
3347 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
3348     const GValue * src2)
3349 {
3350   gint v = src1->data[0].v_int;
3351
3352   /* check if it's already in the range */
3353   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
3354       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
3355       v % INT_RANGE_STEP (src2) == 0) {
3356     if (dest)
3357       gst_value_init_and_copy (dest, src2);
3358     return TRUE;
3359   }
3360
3361   /* check if it extends the range */
3362   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
3363     if (dest) {
3364       gst_value_init_and_copy (dest, src2);
3365       --INT_RANGE_MIN (src2);
3366     }
3367     return TRUE;
3368   }
3369   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
3370     if (dest) {
3371       gst_value_init_and_copy (dest, src2);
3372       ++INT_RANGE_MAX (src2);
3373     }
3374     return TRUE;
3375   }
3376
3377   return FALSE;
3378 }
3379
3380 static gboolean
3381 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
3382     const GValue * src2)
3383 {
3384   /* We can union in several special cases:
3385      1 - one is a subset of another
3386      2 - same step and not disjoint
3387      3 - different step, at least one with one value which matches a 'next' or 'previous'
3388      - anything else ?
3389    */
3390
3391   /* 1 - subset */
3392   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
3393     if (dest)
3394       gst_value_init_and_copy (dest, src2);
3395     return TRUE;
3396   }
3397   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
3398     if (dest)
3399       gst_value_init_and_copy (dest, src1);
3400     return TRUE;
3401   }
3402
3403   /* 2 - same step and not disjoint */
3404   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
3405     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
3406             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
3407         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
3408             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
3409       if (dest) {
3410         gint step = INT_RANGE_STEP (src1);
3411         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
3412         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
3413         g_value_init (dest, GST_TYPE_INT_RANGE);
3414         gst_value_set_int_range_step (dest, min, max, step);
3415       }
3416       return TRUE;
3417     }
3418   }
3419
3420   /* 3 - single value matches next or previous */
3421   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
3422     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
3423     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
3424     if (n1 == 1 || n2 == 1) {
3425       const GValue *range_value = NULL;
3426       gint scalar = 0;
3427       if (n1 == 1) {
3428         range_value = src2;
3429         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
3430       } else if (n2 == 1) {
3431         range_value = src1;
3432         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
3433       }
3434
3435       if (scalar ==
3436           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
3437         if (dest) {
3438           gst_value_init_and_copy (dest, range_value);
3439           --INT_RANGE_MIN (range_value);
3440         }
3441         return TRUE;
3442       } else if (scalar ==
3443           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
3444         if (dest) {
3445           gst_value_init_and_copy (dest, range_value);
3446           ++INT_RANGE_MIN (range_value);
3447         }
3448         return TRUE;
3449       }
3450     }
3451   }
3452
3453   /* If we get there, we did not find a way to make a union that can be
3454      represented with our simplistic model. */
3455   return FALSE;
3456 }
3457
3458 /****************
3459  * intersection *
3460  ****************/
3461
3462 static gboolean
3463 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
3464     const GValue * src2)
3465 {
3466   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
3467       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
3468       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
3469     if (dest)
3470       gst_value_init_and_copy (dest, src1);
3471     return TRUE;
3472   }
3473
3474   return FALSE;
3475 }
3476
3477 static gboolean
3478 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
3479     const GValue * src2)
3480 {
3481   gint min;
3482   gint max;
3483   gint step;
3484
3485   step =
3486       INT_RANGE_STEP (src1) /
3487       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
3488       INT_RANGE_STEP (src2));
3489   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
3490     return FALSE;
3491   step *= INT_RANGE_STEP (src2);
3492
3493   min =
3494       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
3495       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3496   min = (min + step - 1) / step * step;
3497   max =
3498       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
3499       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3500   max = max / step * step;
3501
3502   if (min < max) {
3503     if (dest) {
3504       g_value_init (dest, GST_TYPE_INT_RANGE);
3505       gst_value_set_int_range_step (dest, min, max, step);
3506     }
3507     return TRUE;
3508   }
3509   if (min == max) {
3510     if (dest) {
3511       g_value_init (dest, G_TYPE_INT);
3512       g_value_set_int (dest, min);
3513     }
3514     return TRUE;
3515   }
3516
3517   return FALSE;
3518 }
3519
3520 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
3521 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
3522
3523 static gboolean
3524 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
3525     const GValue * src2)
3526 {
3527   if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
3528       INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
3529       src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
3530     if (dest)
3531       gst_value_init_and_copy (dest, src1);
3532     return TRUE;
3533   }
3534
3535   return FALSE;
3536 }
3537
3538 static gboolean
3539 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
3540     const GValue * src2)
3541 {
3542   gint64 min;
3543   gint64 max;
3544   gint64 step;
3545
3546   step =
3547       INT64_RANGE_STEP (src1) /
3548       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
3549       INT64_RANGE_STEP (src2));
3550   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
3551     return FALSE;
3552   step *= INT64_RANGE_STEP (src2);
3553
3554   min =
3555       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
3556       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
3557   min = (min + step - 1) / step * step;
3558   max =
3559       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
3560       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
3561   max = max / step * step;
3562
3563   if (min < max) {
3564     if (dest) {
3565       g_value_init (dest, GST_TYPE_INT64_RANGE);
3566       gst_value_set_int64_range_step (dest, min, max, step);
3567     }
3568     return TRUE;
3569   }
3570   if (min == max) {
3571     if (dest) {
3572       g_value_init (dest, G_TYPE_INT64);
3573       g_value_set_int64 (dest, min);
3574     }
3575     return TRUE;
3576   }
3577
3578   return FALSE;
3579 }
3580
3581 static gboolean
3582 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
3583     const GValue * src2)
3584 {
3585   if (src2->data[0].v_double <= src1->data[0].v_double &&
3586       src2->data[1].v_double >= src1->data[0].v_double) {
3587     if (dest)
3588       gst_value_init_and_copy (dest, src1);
3589     return TRUE;
3590   }
3591
3592   return FALSE;
3593 }
3594
3595 static gboolean
3596 gst_value_intersect_double_range_double_range (GValue * dest,
3597     const GValue * src1, const GValue * src2)
3598 {
3599   gdouble min;
3600   gdouble max;
3601
3602   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
3603   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
3604
3605   if (min < max) {
3606     if (dest) {
3607       g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
3608       gst_value_set_double_range (dest, min, max);
3609     }
3610     return TRUE;
3611   }
3612   if (min == max) {
3613     if (dest) {
3614       g_value_init (dest, G_TYPE_DOUBLE);
3615       g_value_set_int (dest, (int) min);
3616     }
3617     return TRUE;
3618   }
3619
3620   return FALSE;
3621 }
3622
3623 static gboolean
3624 gst_value_intersect_list (GValue * dest, const GValue * value1,
3625     const GValue * value2)
3626 {
3627   guint i, size;
3628   GValue intersection = { 0, };
3629   gboolean ret = FALSE;
3630
3631   size = VALUE_LIST_SIZE (value1);
3632   for (i = 0; i < size; i++) {
3633     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
3634
3635     /* quicker version when we don't need the resulting set */
3636     if (!dest) {
3637       if (gst_value_intersect (NULL, cur, value2)) {
3638         ret = TRUE;
3639         break;
3640       }
3641       continue;
3642     }
3643
3644     if (gst_value_intersect (&intersection, cur, value2)) {
3645       /* append value */
3646       if (!ret) {
3647         gst_value_move (dest, &intersection);
3648         ret = TRUE;
3649       } else if (GST_VALUE_HOLDS_LIST (dest)) {
3650         _gst_value_list_append_and_take_value (dest, &intersection);
3651       } else {
3652         GValue temp;
3653
3654         gst_value_move (&temp, dest);
3655         gst_value_list_merge (dest, &temp, &intersection);
3656         g_value_unset (&temp);
3657         g_value_unset (&intersection);
3658       }
3659     }
3660   }
3661
3662   return ret;
3663 }
3664
3665 static gboolean
3666 gst_value_intersect_array (GValue * dest, const GValue * src1,
3667     const GValue * src2)
3668 {
3669   guint size;
3670   guint n;
3671   GValue val = { 0 };
3672
3673   /* only works on similar-sized arrays */
3674   size = gst_value_array_get_size (src1);
3675   if (size != gst_value_array_get_size (src2))
3676     return FALSE;
3677
3678   /* quicker value when we don't need the resulting set */
3679   if (!dest) {
3680     for (n = 0; n < size; n++) {
3681       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
3682               gst_value_array_get_value (src2, n))) {
3683         return FALSE;
3684       }
3685     }
3686     return TRUE;
3687   }
3688
3689   g_value_init (dest, GST_TYPE_ARRAY);
3690
3691   for (n = 0; n < size; n++) {
3692     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
3693             gst_value_array_get_value (src2, n))) {
3694       g_value_unset (dest);
3695       return FALSE;
3696     }
3697     _gst_value_array_append_and_take_value (dest, &val);
3698   }
3699
3700   return TRUE;
3701 }
3702
3703 static gboolean
3704 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
3705     const GValue * src2)
3706 {
3707   gint res1, res2;
3708   GValue *vals;
3709   GstValueCompareFunc compare;
3710
3711   vals = src2->data[0].v_pointer;
3712
3713   if (vals == NULL)
3714     return FALSE;
3715
3716   if ((compare = gst_value_get_compare_func (src1))) {
3717     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
3718     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
3719
3720     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
3721         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
3722       if (dest)
3723         gst_value_init_and_copy (dest, src1);
3724       return TRUE;
3725     }
3726   }
3727
3728   return FALSE;
3729 }
3730
3731 static gboolean
3732 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
3733     const GValue * src1, const GValue * src2)
3734 {
3735   GValue *min;
3736   GValue *max;
3737   gint res;
3738   GValue *vals1, *vals2;
3739   GstValueCompareFunc compare;
3740
3741   vals1 = src1->data[0].v_pointer;
3742   vals2 = src2->data[0].v_pointer;
3743   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
3744
3745   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
3746     /* min = MAX (src1.start, src2.start) */
3747     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
3748     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3749     if (res == GST_VALUE_LESS_THAN)
3750       min = &vals2[0];          /* Take the max of the 2 */
3751     else
3752       min = &vals1[0];
3753
3754     /* max = MIN (src1.end, src2.end) */
3755     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
3756     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3757     if (res == GST_VALUE_GREATER_THAN)
3758       max = &vals2[1];          /* Take the min of the 2 */
3759     else
3760       max = &vals1[1];
3761
3762     res = gst_value_compare_with_func (min, max, compare);
3763     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3764     if (res == GST_VALUE_LESS_THAN) {
3765       if (dest) {
3766         g_value_init (dest, GST_TYPE_FRACTION_RANGE);
3767         vals1 = dest->data[0].v_pointer;
3768         g_value_copy (min, &vals1[0]);
3769         g_value_copy (max, &vals1[1]);
3770       }
3771       return TRUE;
3772     }
3773     if (res == GST_VALUE_EQUAL) {
3774       if (dest)
3775         gst_value_init_and_copy (dest, min);
3776       return TRUE;
3777     }
3778   }
3779
3780   return FALSE;
3781 }
3782
3783 /***************
3784  * subtraction *
3785  ***************/
3786
3787 static gboolean
3788 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
3789     const GValue * subtrahend)
3790 {
3791   gint min = gst_value_get_int_range_min (subtrahend);
3792   gint max = gst_value_get_int_range_max (subtrahend);
3793   gint step = gst_value_get_int_range_step (subtrahend);
3794   gint val = g_value_get_int (minuend);
3795
3796   /* subtracting a range from an int only works if the int is not in the
3797    * range */
3798   if (val < min || val > max || val % step) {
3799     /* and the result is the int */
3800     if (dest)
3801       gst_value_init_and_copy (dest, minuend);
3802     return TRUE;
3803   }
3804   return FALSE;
3805 }
3806
3807 /* creates a new int range based on input values.
3808  */
3809 static gboolean
3810 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
3811     gint max2, gint step)
3812 {
3813   GValue v1 = { 0, };
3814   GValue v2 = { 0, };
3815   GValue *pv1, *pv2;            /* yeah, hungarian! */
3816
3817   g_return_val_if_fail (step > 0, FALSE);
3818   g_return_val_if_fail (min1 % step == 0, FALSE);
3819   g_return_val_if_fail (max1 % step == 0, FALSE);
3820   g_return_val_if_fail (min2 % step == 0, FALSE);
3821   g_return_val_if_fail (max2 % step == 0, FALSE);
3822
3823   if (min1 <= max1 && min2 <= max2) {
3824     pv1 = &v1;
3825     pv2 = &v2;
3826   } else if (min1 <= max1) {
3827     pv1 = dest;
3828     pv2 = NULL;
3829   } else if (min2 <= max2) {
3830     pv1 = NULL;
3831     pv2 = dest;
3832   } else {
3833     return FALSE;
3834   }
3835
3836   if (!dest)
3837     return TRUE;
3838
3839   if (min1 < max1) {
3840     g_value_init (pv1, GST_TYPE_INT_RANGE);
3841     gst_value_set_int_range_step (pv1, min1, max1, step);
3842   } else if (min1 == max1) {
3843     g_value_init (pv1, G_TYPE_INT);
3844     g_value_set_int (pv1, min1);
3845   }
3846   if (min2 < max2) {
3847     g_value_init (pv2, GST_TYPE_INT_RANGE);
3848     gst_value_set_int_range_step (pv2, min2, max2, step);
3849   } else if (min2 == max2) {
3850     g_value_init (pv2, G_TYPE_INT);
3851     g_value_set_int (pv2, min2);
3852   }
3853
3854   if (min1 <= max1 && min2 <= max2) {
3855     gst_value_list_concat (dest, pv1, pv2);
3856     g_value_unset (pv1);
3857     g_value_unset (pv2);
3858   }
3859   return TRUE;
3860 }
3861
3862 static gboolean
3863 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
3864     const GValue * subtrahend)
3865 {
3866   gint min = gst_value_get_int_range_min (minuend);
3867   gint max = gst_value_get_int_range_max (minuend);
3868   gint step = gst_value_get_int_range_step (minuend);
3869   gint val = g_value_get_int (subtrahend);
3870
3871   g_return_val_if_fail (min < max, FALSE);
3872
3873   /* value is outside of the range, return range unchanged */
3874   if (val < min || val > max || val % step) {
3875     if (dest)
3876       gst_value_init_and_copy (dest, minuend);
3877     return TRUE;
3878   } else {
3879     /* max must be MAXINT too as val <= max */
3880     if (val >= G_MAXINT - step + 1) {
3881       max -= step;
3882       val -= step;
3883     }
3884     /* min must be MININT too as val >= max */
3885     if (val <= G_MININT + step - 1) {
3886       min += step;
3887       val += step;
3888     }
3889     if (dest)
3890       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
3891   }
3892   return TRUE;
3893 }
3894
3895 static gboolean
3896 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
3897     const GValue * subtrahend)
3898 {
3899   gint min1 = gst_value_get_int_range_min (minuend);
3900   gint max1 = gst_value_get_int_range_max (minuend);
3901   gint step1 = gst_value_get_int_range_step (minuend);
3902   gint min2 = gst_value_get_int_range_min (subtrahend);
3903   gint max2 = gst_value_get_int_range_max (subtrahend);
3904   gint step2 = gst_value_get_int_range_step (subtrahend);
3905   gint step;
3906
3907   if (step1 != step2) {
3908     /* ENOIMPL */
3909     g_assert (FALSE);
3910     return FALSE;
3911   }
3912   step = step1;
3913
3914   if (max2 >= max1 && min2 <= min1) {
3915     return FALSE;
3916   } else if (max2 >= max1) {
3917     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3918         step, 0, step);
3919   } else if (min2 <= min1) {
3920     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
3921         step, 0, step);
3922   } else {
3923     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3924         MAX (max2 + step, min1), max1, step);
3925   }
3926 }
3927
3928 static gboolean
3929 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
3930     const GValue * subtrahend)
3931 {
3932   gint64 min = gst_value_get_int64_range_min (subtrahend);
3933   gint64 max = gst_value_get_int64_range_max (subtrahend);
3934   gint64 step = gst_value_get_int64_range_step (subtrahend);
3935   gint64 val = g_value_get_int64 (minuend);
3936
3937   /* subtracting a range from an int64 only works if the int64 is not in the
3938    * range */
3939   if (val < min || val > max || val % step) {
3940     /* and the result is the int64 */
3941     if (dest)
3942       gst_value_init_and_copy (dest, minuend);
3943     return TRUE;
3944   }
3945   return FALSE;
3946 }
3947
3948 /* creates a new int64 range based on input values.
3949  */
3950 static gboolean
3951 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
3952     gint64 min2, gint64 max2, gint64 step)
3953 {
3954   GValue v1 = { 0, };
3955   GValue v2 = { 0, };
3956   GValue *pv1, *pv2;            /* yeah, hungarian! */
3957
3958   g_return_val_if_fail (step > 0, FALSE);
3959   g_return_val_if_fail (min1 % step == 0, FALSE);
3960   g_return_val_if_fail (max1 % step == 0, FALSE);
3961   g_return_val_if_fail (min2 % step == 0, FALSE);
3962   g_return_val_if_fail (max2 % step == 0, FALSE);
3963
3964   if (min1 <= max1 && min2 <= max2) {
3965     pv1 = &v1;
3966     pv2 = &v2;
3967   } else if (min1 <= max1) {
3968     pv1 = dest;
3969     pv2 = NULL;
3970   } else if (min2 <= max2) {
3971     pv1 = NULL;
3972     pv2 = dest;
3973   } else {
3974     return FALSE;
3975   }
3976
3977   if (!dest)
3978     return TRUE;
3979
3980   if (min1 < max1) {
3981     g_value_init (pv1, GST_TYPE_INT64_RANGE);
3982     gst_value_set_int64_range_step (pv1, min1, max1, step);
3983   } else if (min1 == max1) {
3984     g_value_init (pv1, G_TYPE_INT64);
3985     g_value_set_int64 (pv1, min1);
3986   }
3987   if (min2 < max2) {
3988     g_value_init (pv2, GST_TYPE_INT64_RANGE);
3989     gst_value_set_int64_range_step (pv2, min2, max2, step);
3990   } else if (min2 == max2) {
3991     g_value_init (pv2, G_TYPE_INT64);
3992     g_value_set_int64 (pv2, min2);
3993   }
3994
3995   if (min1 <= max1 && min2 <= max2) {
3996     gst_value_list_concat (dest, pv1, pv2);
3997     g_value_unset (pv1);
3998     g_value_unset (pv2);
3999   }
4000   return TRUE;
4001 }
4002
4003 static gboolean
4004 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
4005     const GValue * subtrahend)
4006 {
4007   gint64 min = gst_value_get_int64_range_min (minuend);
4008   gint64 max = gst_value_get_int64_range_max (minuend);
4009   gint64 step = gst_value_get_int64_range_step (minuend);
4010   gint64 val = g_value_get_int64 (subtrahend);
4011
4012   g_return_val_if_fail (min < max, FALSE);
4013
4014   /* value is outside of the range, return range unchanged */
4015   if (val < min || val > max || val % step) {
4016     if (dest)
4017       gst_value_init_and_copy (dest, minuend);
4018     return TRUE;
4019   } else {
4020     /* max must be MAXINT64 too as val <= max */
4021     if (val >= G_MAXINT64 - step + 1) {
4022       max -= step;
4023       val -= step;
4024     }
4025     /* min must be MININT64 too as val >= max */
4026     if (val <= G_MININT64 + step - 1) {
4027       min += step;
4028       val += step;
4029     }
4030     if (dest)
4031       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
4032           step);
4033   }
4034   return TRUE;
4035 }
4036
4037 static gboolean
4038 gst_value_subtract_int64_range_int64_range (GValue * dest,
4039     const GValue * minuend, const GValue * subtrahend)
4040 {
4041   gint64 min1 = gst_value_get_int64_range_min (minuend);
4042   gint64 max1 = gst_value_get_int64_range_max (minuend);
4043   gint64 step1 = gst_value_get_int64_range_step (minuend);
4044   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
4045   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
4046   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
4047   gint64 step;
4048
4049   if (step1 != step2) {
4050     /* ENOIMPL */
4051     g_assert (FALSE);
4052     return FALSE;
4053   }
4054   step = step1;
4055
4056   if (max2 >= max1 && min2 <= min1) {
4057     return FALSE;
4058   } else if (max2 >= max1) {
4059     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4060             max1), step, 0, step);
4061   } else if (min2 <= min1) {
4062     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
4063         max1, step, 0, step);
4064   } else {
4065     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4066             max1), MAX (max2 + step, min1), max1, step);
4067   }
4068 }
4069
4070 static gboolean
4071 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
4072     const GValue * subtrahend)
4073 {
4074   gdouble min = gst_value_get_double_range_min (subtrahend);
4075   gdouble max = gst_value_get_double_range_max (subtrahend);
4076   gdouble val = g_value_get_double (minuend);
4077
4078   if (val < min || val > max) {
4079     if (dest)
4080       gst_value_init_and_copy (dest, minuend);
4081     return TRUE;
4082   }
4083   return FALSE;
4084 }
4085
4086 static gboolean
4087 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
4088     const GValue * subtrahend)
4089 {
4090   /* since we don't have open ranges, we cannot create a hole in
4091    * a double range. We return the original range */
4092   if (dest)
4093     gst_value_init_and_copy (dest, minuend);
4094   return TRUE;
4095 }
4096
4097 static gboolean
4098 gst_value_subtract_double_range_double_range (GValue * dest,
4099     const GValue * minuend, const GValue * subtrahend)
4100 {
4101   /* since we don't have open ranges, we have to approximate */
4102   /* done like with ints */
4103   gdouble min1 = gst_value_get_double_range_min (minuend);
4104   gdouble max2 = gst_value_get_double_range_max (minuend);
4105   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
4106   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
4107   GValue v1 = { 0, };
4108   GValue v2 = { 0, };
4109   GValue *pv1, *pv2;            /* yeah, hungarian! */
4110
4111   if (min1 < max1 && min2 < max2) {
4112     pv1 = &v1;
4113     pv2 = &v2;
4114   } else if (min1 < max1) {
4115     pv1 = dest;
4116     pv2 = NULL;
4117   } else if (min2 < max2) {
4118     pv1 = NULL;
4119     pv2 = dest;
4120   } else {
4121     return FALSE;
4122   }
4123
4124   if (!dest)
4125     return TRUE;
4126
4127   if (min1 < max1) {
4128     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
4129     gst_value_set_double_range (pv1, min1, max1);
4130   }
4131   if (min2 < max2) {
4132     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
4133     gst_value_set_double_range (pv2, min2, max2);
4134   }
4135
4136   if (min1 < max1 && min2 < max2) {
4137     gst_value_list_concat (dest, pv1, pv2);
4138     g_value_unset (pv1);
4139     g_value_unset (pv2);
4140   }
4141   return TRUE;
4142 }
4143
4144 static gboolean
4145 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
4146     const GValue * subtrahend)
4147 {
4148   guint i, size;
4149   GValue subtraction = { 0, };
4150   gboolean ret = FALSE;
4151   GType ltype;
4152
4153   ltype = gst_value_list_get_type ();
4154
4155   size = VALUE_LIST_SIZE (minuend);
4156   for (i = 0; i < size; i++) {
4157     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
4158
4159     /* quicker version when we can discard the result */
4160     if (!dest) {
4161       if (gst_value_subtract (NULL, cur, subtrahend)) {
4162         ret = TRUE;
4163         break;
4164       }
4165       continue;
4166     }
4167
4168     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
4169       if (!ret) {
4170         gst_value_move (dest, &subtraction);
4171         ret = TRUE;
4172       } else if (G_VALUE_HOLDS (dest, ltype)
4173           && !G_VALUE_HOLDS (&subtraction, ltype)) {
4174         _gst_value_list_append_and_take_value (dest, &subtraction);
4175       } else {
4176         GValue temp;
4177
4178         gst_value_move (&temp, dest);
4179         gst_value_list_concat (dest, &temp, &subtraction);
4180         g_value_unset (&temp);
4181         g_value_unset (&subtraction);
4182       }
4183     }
4184   }
4185   return ret;
4186 }
4187
4188 static gboolean
4189 gst_value_subtract_list (GValue * dest, const GValue * minuend,
4190     const GValue * subtrahend)
4191 {
4192   guint i, size;
4193   GValue data[2] = { {0,}, {0,} };
4194   GValue *subtraction = &data[0], *result = &data[1];
4195
4196   gst_value_init_and_copy (result, minuend);
4197   size = VALUE_LIST_SIZE (subtrahend);
4198   for (i = 0; i < size; i++) {
4199     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
4200
4201     if (gst_value_subtract (subtraction, result, cur)) {
4202       GValue *temp = result;
4203
4204       result = subtraction;
4205       subtraction = temp;
4206       g_value_unset (subtraction);
4207     } else {
4208       g_value_unset (result);
4209       return FALSE;
4210     }
4211   }
4212   if (dest) {
4213     gst_value_move (dest, result);
4214   } else {
4215     g_value_unset (result);
4216   }
4217   return TRUE;
4218 }
4219
4220 static gboolean
4221 gst_value_subtract_fraction_fraction_range (GValue * dest,
4222     const GValue * minuend, const GValue * subtrahend)
4223 {
4224   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
4225   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
4226   GstValueCompareFunc compare;
4227
4228   if ((compare = gst_value_get_compare_func (minuend))) {
4229     /* subtracting a range from an fraction only works if the fraction
4230      * is not in the range */
4231     if (gst_value_compare_with_func (minuend, min, compare) ==
4232         GST_VALUE_LESS_THAN ||
4233         gst_value_compare_with_func (minuend, max, compare) ==
4234         GST_VALUE_GREATER_THAN) {
4235       /* and the result is the value */
4236       if (dest)
4237         gst_value_init_and_copy (dest, minuend);
4238       return TRUE;
4239     }
4240   }
4241   return FALSE;
4242 }
4243
4244 static gboolean
4245 gst_value_subtract_fraction_range_fraction (GValue * dest,
4246     const GValue * minuend, const GValue * subtrahend)
4247 {
4248   /* since we don't have open ranges, we cannot create a hole in
4249    * a range. We return the original range */
4250   if (dest)
4251     gst_value_init_and_copy (dest, minuend);
4252   return TRUE;
4253 }
4254
4255 static gboolean
4256 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
4257     const GValue * minuend, const GValue * subtrahend)
4258 {
4259   /* since we don't have open ranges, we have to approximate */
4260   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
4261   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
4262   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
4263   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
4264   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
4265   gint cmp1, cmp2;
4266   GValue v1 = { 0, };
4267   GValue v2 = { 0, };
4268   GValue *pv1, *pv2;            /* yeah, hungarian! */
4269   GstValueCompareFunc compare;
4270
4271   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
4272   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
4273
4274   compare = gst_value_get_compare_func (min1);
4275   g_return_val_if_fail (compare, FALSE);
4276
4277   cmp1 = gst_value_compare_with_func (max2, max1, compare);
4278   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4279   if (cmp1 == GST_VALUE_LESS_THAN)
4280     max1 = max2;
4281   cmp1 = gst_value_compare_with_func (min1, min2, compare);
4282   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4283   if (cmp1 == GST_VALUE_GREATER_THAN)
4284     min2 = min1;
4285
4286   cmp1 = gst_value_compare_with_func (min1, max1, compare);
4287   cmp2 = gst_value_compare_with_func (min2, max2, compare);
4288
4289   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4290     pv1 = &v1;
4291     pv2 = &v2;
4292   } else if (cmp1 == GST_VALUE_LESS_THAN) {
4293     pv1 = dest;
4294     pv2 = NULL;
4295   } else if (cmp2 == GST_VALUE_LESS_THAN) {
4296     pv1 = NULL;
4297     pv2 = dest;
4298   } else {
4299     return FALSE;
4300   }
4301
4302   if (!dest)
4303     return TRUE;
4304
4305   if (cmp1 == GST_VALUE_LESS_THAN) {
4306     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
4307     gst_value_set_fraction_range (pv1, min1, max1);
4308   }
4309   if (cmp2 == GST_VALUE_LESS_THAN) {
4310     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
4311     gst_value_set_fraction_range (pv2, min2, max2);
4312   }
4313
4314   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4315     gst_value_list_concat (dest, pv1, pv2);
4316     g_value_unset (pv1);
4317     g_value_unset (pv2);
4318   }
4319   return TRUE;
4320 }
4321
4322
4323 /**************
4324  * comparison *
4325  **************/
4326
4327 /*
4328  * gst_value_get_compare_func:
4329  * @value1: a value to get the compare function for
4330  *
4331  * Determines the compare function to be used with values of the same type as
4332  * @value1. The function can be given to gst_value_compare_with_func().
4333  *
4334  * Returns: A #GstValueCompareFunc value
4335  */
4336 static GstValueCompareFunc
4337 gst_value_get_compare_func (const GValue * value1)
4338 {
4339   GstValueTable *table, *best = NULL;
4340   guint i;
4341   GType type1;
4342
4343   type1 = G_VALUE_TYPE (value1);
4344
4345   /* this is a fast check */
4346   best = gst_value_hash_lookup_type (type1);
4347
4348   /* slower checks */
4349   if (G_UNLIKELY (!best || !best->compare)) {
4350     guint len = gst_value_table->len;
4351
4352     best = NULL;
4353     for (i = 0; i < len; i++) {
4354       table = &g_array_index (gst_value_table, GstValueTable, i);
4355       if (table->compare && g_type_is_a (type1, table->type)) {
4356         if (!best || g_type_is_a (table->type, best->type))
4357           best = table;
4358       }
4359     }
4360   }
4361   if (G_LIKELY (best))
4362     return best->compare;
4363
4364   return NULL;
4365 }
4366
4367 /**
4368  * gst_value_can_compare:
4369  * @value1: a value to compare
4370  * @value2: another value to compare
4371  *
4372  * Determines if @value1 and @value2 can be compared.
4373  *
4374  * Returns: TRUE if the values can be compared
4375  */
4376 gboolean
4377 gst_value_can_compare (const GValue * value1, const GValue * value2)
4378 {
4379   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4380   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4381
4382   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4383     return FALSE;
4384
4385   return gst_value_get_compare_func (value1) != NULL;
4386 }
4387
4388 static gboolean
4389 gst_value_list_equals_range (const GValue * list, const GValue * value)
4390 {
4391   const GValue *first;
4392   guint list_size, n;
4393
4394   g_return_val_if_fail (G_IS_VALUE (list), FALSE);
4395   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
4396   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (list), FALSE);
4397
4398   /* TODO: compare against an empty list ? No type though... */
4399   list_size = VALUE_LIST_SIZE (list);
4400   if (list_size == 0)
4401     return FALSE;
4402
4403   /* compare the basic types - they have to match */
4404   first = VALUE_LIST_GET_VALUE (list, 0);
4405 #define CHECK_TYPES(type,prefix) \
4406   (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value))
4407   if (CHECK_TYPES (INT, G)) {
4408     const gint rmin = gst_value_get_int_range_min (value);
4409     const gint rmax = gst_value_get_int_range_max (value);
4410     const gint rstep = gst_value_get_int_range_step (value);
4411     /* note: this will overflow for min 0 and max INT_MAX, but this
4412        would only be equal to a list of INT_MAX elements, which seems
4413        very unlikely */
4414     if (list_size != rmax / rstep - rmin / rstep + 1)
4415       return FALSE;
4416     for (n = 0; n < list_size; ++n) {
4417       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
4418       if (v < rmin || v > rmax || v % rstep) {
4419         return FALSE;
4420       }
4421     }
4422     return TRUE;
4423   } else if (CHECK_TYPES (INT64, G)) {
4424     const gint64 rmin = gst_value_get_int64_range_min (value);
4425     const gint64 rmax = gst_value_get_int64_range_max (value);
4426     const gint64 rstep = gst_value_get_int64_range_step (value);
4427     GST_DEBUG ("List/range of int64s");
4428     if (list_size != rmax / rstep - rmin / rstep + 1)
4429       return FALSE;
4430     for (n = 0; n < list_size; ++n) {
4431       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
4432       if (v < rmin || v > rmax || v % rstep)
4433         return FALSE;
4434     }
4435     return TRUE;
4436   }
4437 #undef CHECK_TYPES
4438
4439   /* other combinations don't make sense for equality */
4440   return FALSE;
4441 }
4442
4443 /**
4444  * gst_value_compare:
4445  * @value1: a value to compare
4446  * @value2: another value to compare
4447  *
4448  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
4449  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
4450  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
4451  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
4452  * If the values are equal, GST_VALUE_EQUAL is returned.
4453  *
4454  * Returns: comparison result
4455  */
4456 gint
4457 gst_value_compare (const GValue * value1, const GValue * value2)
4458 {
4459   GstValueCompareFunc compare;
4460   GType ltype;
4461
4462   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
4463   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
4464
4465   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
4466      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
4467   ltype = gst_value_list_get_type ();
4468   if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype)) {
4469     gint i, n, ret;
4470
4471     if (gst_value_list_equals_range (value1, value2)) {
4472       return GST_VALUE_EQUAL;
4473     }
4474
4475     n = gst_value_list_get_size (value1);
4476     if (n == 0)
4477       return GST_VALUE_UNORDERED;
4478
4479     for (i = 0; i < n; i++) {
4480       const GValue *elt;
4481
4482       elt = gst_value_list_get_value (value1, i);
4483       ret = gst_value_compare (elt, value2);
4484       if (ret != GST_VALUE_EQUAL && n == 1)
4485         return ret;
4486       else if (ret != GST_VALUE_EQUAL)
4487         return GST_VALUE_UNORDERED;
4488     }
4489
4490     return GST_VALUE_EQUAL;
4491   } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype)) {
4492     gint i, n, ret;
4493
4494     if (gst_value_list_equals_range (value2, value1)) {
4495       return GST_VALUE_EQUAL;
4496     }
4497
4498     n = gst_value_list_get_size (value2);
4499     if (n == 0)
4500       return GST_VALUE_UNORDERED;
4501
4502     for (i = 0; i < n; i++) {
4503       const GValue *elt;
4504
4505       elt = gst_value_list_get_value (value2, i);
4506       ret = gst_value_compare (elt, value1);
4507       if (ret != GST_VALUE_EQUAL && n == 1)
4508         return ret;
4509       else if (ret != GST_VALUE_EQUAL)
4510         return GST_VALUE_UNORDERED;
4511     }
4512
4513     return GST_VALUE_EQUAL;
4514   }
4515
4516   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4517     return GST_VALUE_UNORDERED;
4518
4519   compare = gst_value_get_compare_func (value1);
4520   if (compare) {
4521     return compare (value1, value2);
4522   }
4523
4524   g_critical ("unable to compare values of type %s\n",
4525       g_type_name (G_VALUE_TYPE (value1)));
4526   return GST_VALUE_UNORDERED;
4527 }
4528
4529 /*
4530  * gst_value_compare_with_func:
4531  * @value1: a value to compare
4532  * @value2: another value to compare
4533  * @compare: compare function
4534  *
4535  * Compares @value1 and @value2 using the @compare function. Works like
4536  * gst_value_compare() but allows to save time determining the compare function
4537  * a multiple times. 
4538  *
4539  * Returns: comparison result
4540  */
4541 static gint
4542 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
4543     GstValueCompareFunc compare)
4544 {
4545   g_assert (compare);
4546
4547   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4548     return GST_VALUE_UNORDERED;
4549
4550   return compare (value1, value2);
4551 }
4552
4553 /* union */
4554
4555 /**
4556  * gst_value_can_union:
4557  * @value1: a value to union
4558  * @value2: another value to union
4559  *
4560  * Determines if @value1 and @value2 can be non-trivially unioned.
4561  * Any two values can be trivially unioned by adding both of them
4562  * to a GstValueList.  However, certain types have the possibility
4563  * to be unioned in a simpler way.  For example, an integer range
4564  * and an integer can be unioned if the integer is a subset of the
4565  * integer range.  If there is the possibility that two values can
4566  * be unioned, this function returns TRUE.
4567  *
4568  * Returns: TRUE if there is a function allowing the two values to
4569  * be unioned.
4570  */
4571 gboolean
4572 gst_value_can_union (const GValue * value1, const GValue * value2)
4573 {
4574   GstValueUnionInfo *union_info;
4575   guint i, len;
4576
4577   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4578   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4579
4580   len = gst_value_union_funcs->len;
4581
4582   for (i = 0; i < len; i++) {
4583     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4584     if (union_info->type1 == G_VALUE_TYPE (value1) &&
4585         union_info->type2 == G_VALUE_TYPE (value2))
4586       return TRUE;
4587     if (union_info->type1 == G_VALUE_TYPE (value2) &&
4588         union_info->type2 == G_VALUE_TYPE (value1))
4589       return TRUE;
4590   }
4591
4592   return FALSE;
4593 }
4594
4595 /**
4596  * gst_value_union:
4597  * @dest: (out caller-allocates): the destination value
4598  * @value1: a value to union
4599  * @value2: another value to union
4600  *
4601  * Creates a GValue corresponding to the union of @value1 and @value2.
4602  *
4603  * Returns: TRUE if the union succeeded.
4604  */
4605 gboolean
4606 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
4607 {
4608   const GstValueUnionInfo *union_info;
4609   guint i, len;
4610   GType type1, type2;
4611
4612   g_return_val_if_fail (dest != NULL, FALSE);
4613   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4614   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4615   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
4616       FALSE);
4617
4618   len = gst_value_union_funcs->len;
4619   type1 = G_VALUE_TYPE (value1);
4620   type2 = G_VALUE_TYPE (value2);
4621
4622   for (i = 0; i < len; i++) {
4623     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4624     if (union_info->type1 == type1 && union_info->type2 == type2) {
4625       return union_info->func (dest, value1, value2);
4626     }
4627     if (union_info->type1 == type2 && union_info->type2 == type1) {
4628       return union_info->func (dest, value2, value1);
4629     }
4630   }
4631
4632   gst_value_list_concat (dest, value1, value2);
4633   return TRUE;
4634 }
4635
4636 /* gst_value_register_union_func: (skip)
4637  * @type1: a type to union
4638  * @type2: another type to union
4639  * @func: a function that implements creating a union between the two types
4640  *
4641  * Registers a union function that can create a union between #GValue items
4642  * of the type @type1 and @type2.
4643  *
4644  * Union functions should be registered at startup before any pipelines are
4645  * started, as gst_value_register_union_func() is not thread-safe and cannot
4646  * be used at the same time as gst_value_union() or gst_value_can_union().
4647  */
4648 static void
4649 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
4650 {
4651   GstValueUnionInfo union_info;
4652
4653   union_info.type1 = type1;
4654   union_info.type2 = type2;
4655   union_info.func = func;
4656
4657   g_array_append_val (gst_value_union_funcs, union_info);
4658 }
4659
4660 /* intersection */
4661
4662 /**
4663  * gst_value_can_intersect:
4664  * @value1: a value to intersect
4665  * @value2: another value to intersect
4666  *
4667  * Determines if intersecting two values will produce a valid result.
4668  * Two values will produce a valid intersection if they have the same
4669  * type.
4670  *
4671  * Returns: TRUE if the values can intersect
4672  */
4673 gboolean
4674 gst_value_can_intersect (const GValue * value1, const GValue * value2)
4675 {
4676   GstValueIntersectInfo *intersect_info;
4677   guint i, len;
4678   GType ltype, type1, type2;
4679
4680   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4681   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4682
4683   ltype = gst_value_list_get_type ();
4684
4685   /* special cases */
4686   if (G_VALUE_HOLDS (value1, ltype) || G_VALUE_HOLDS (value2, ltype))
4687     return TRUE;
4688
4689   type1 = G_VALUE_TYPE (value1);
4690   type2 = G_VALUE_TYPE (value2);
4691
4692   /* practically all GstValue types have a compare function (_can_compare=TRUE)
4693    * GstStructure and GstCaps have npot, but are intersectable */
4694   if (type1 == type2)
4695     return TRUE;
4696
4697   /* check registered intersect functions */
4698   len = gst_value_intersect_funcs->len;
4699   for (i = 0; i < len; i++) {
4700     intersect_info = &g_array_index (gst_value_intersect_funcs,
4701         GstValueIntersectInfo, i);
4702     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
4703         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
4704       return TRUE;
4705   }
4706
4707   return gst_value_can_compare (value1, value2);
4708 }
4709
4710 /**
4711  * gst_value_intersect:
4712  * @dest: (out caller-allocates) (transfer full): a uninitialized #GValue that will hold the calculated
4713  * intersection value. May be NULL if the resulting set if not needed.
4714  * @value1: a value to intersect
4715  * @value2: another value to intersect
4716  *
4717  * Calculates the intersection of two values.  If the values have
4718  * a non-empty intersection, the value representing the intersection
4719  * is placed in @dest, unless NULL.  If the intersection is non-empty,
4720  * @dest is not modified.
4721  *
4722  * Returns: TRUE if the intersection is non-empty
4723  */
4724 gboolean
4725 gst_value_intersect (GValue * dest, const GValue * value1,
4726     const GValue * value2)
4727 {
4728   GstValueIntersectInfo *intersect_info;
4729   guint i, len;
4730   GType ltype, type1, type2;
4731
4732   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4733   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4734
4735   ltype = gst_value_list_get_type ();
4736
4737   /* special cases first */
4738   if (G_VALUE_HOLDS (value1, ltype))
4739     return gst_value_intersect_list (dest, value1, value2);
4740   if (G_VALUE_HOLDS (value2, ltype))
4741     return gst_value_intersect_list (dest, value2, value1);
4742
4743   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
4744     if (dest)
4745       gst_value_init_and_copy (dest, value1);
4746     return TRUE;
4747   }
4748
4749   type1 = G_VALUE_TYPE (value1);
4750   type2 = G_VALUE_TYPE (value2);
4751
4752   len = gst_value_intersect_funcs->len;
4753   for (i = 0; i < len; i++) {
4754     intersect_info = &g_array_index (gst_value_intersect_funcs,
4755         GstValueIntersectInfo, i);
4756     if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
4757       return intersect_info->func (dest, value1, value2);
4758     }
4759     if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
4760       return intersect_info->func (dest, value2, value1);
4761     }
4762   }
4763   return FALSE;
4764 }
4765
4766
4767
4768 /* gst_value_register_intersect_func: (skip)
4769  * @type1: the first type to intersect
4770  * @type2: the second type to intersect
4771  * @func: the intersection function
4772  *
4773  * Registers a function that is called to calculate the intersection
4774  * of the values having the types @type1 and @type2.
4775  *
4776  * Intersect functions should be registered at startup before any pipelines are
4777  * started, as gst_value_register_intersect_func() is not thread-safe and
4778  * cannot be used at the same time as gst_value_intersect() or
4779  * gst_value_can_intersect().
4780  */
4781 static void
4782 gst_value_register_intersect_func (GType type1, GType type2,
4783     GstValueIntersectFunc func)
4784 {
4785   GstValueIntersectInfo intersect_info;
4786
4787   intersect_info.type1 = type1;
4788   intersect_info.type2 = type2;
4789   intersect_info.func = func;
4790
4791   g_array_append_val (gst_value_intersect_funcs, intersect_info);
4792 }
4793
4794
4795 /* subtraction */
4796
4797 /**
4798  * gst_value_subtract:
4799  * @dest: (out caller-allocates): the destination value for the result if the
4800  *     subtraction is not empty. May be NULL, in which case the resulting set
4801  *     will not be computed, which can give a fair speedup.
4802  * @minuend: the value to subtract from
4803  * @subtrahend: the value to subtract
4804  *
4805  * Subtracts @subtrahend from @minuend and stores the result in @dest.
4806  * Note that this means subtraction as in sets, not as in mathematics.
4807  *
4808  * Returns: %TRUE if the subtraction is not empty
4809  */
4810 gboolean
4811 gst_value_subtract (GValue * dest, const GValue * minuend,
4812     const GValue * subtrahend)
4813 {
4814   GstValueSubtractInfo *info;
4815   guint i, len;
4816   GType ltype, mtype, stype;
4817
4818   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4819   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4820
4821   ltype = gst_value_list_get_type ();
4822
4823   /* special cases first */
4824   if (G_VALUE_HOLDS (minuend, ltype))
4825     return gst_value_subtract_from_list (dest, minuend, subtrahend);
4826   if (G_VALUE_HOLDS (subtrahend, ltype))
4827     return gst_value_subtract_list (dest, minuend, subtrahend);
4828
4829   mtype = G_VALUE_TYPE (minuend);
4830   stype = G_VALUE_TYPE (subtrahend);
4831
4832   len = gst_value_subtract_funcs->len;
4833   for (i = 0; i < len; i++) {
4834     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4835     if (info->minuend == mtype && info->subtrahend == stype) {
4836       return info->func (dest, minuend, subtrahend);
4837     }
4838   }
4839
4840   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
4841     if (dest)
4842       gst_value_init_and_copy (dest, minuend);
4843     return TRUE;
4844   }
4845
4846   return FALSE;
4847 }
4848
4849 #if 0
4850 gboolean
4851 gst_value_subtract (GValue * dest, const GValue * minuend,
4852     const GValue * subtrahend)
4853 {
4854   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
4855
4856   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
4857       gst_value_serialize (subtrahend),
4858       ret ? gst_value_serialize (dest) : "---");
4859   return ret;
4860 }
4861 #endif
4862
4863 /**
4864  * gst_value_can_subtract:
4865  * @minuend: the value to subtract from
4866  * @subtrahend: the value to subtract
4867  *
4868  * Checks if it's possible to subtract @subtrahend from @minuend.
4869  *
4870  * Returns: TRUE if a subtraction is possible
4871  */
4872 gboolean
4873 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
4874 {
4875   GstValueSubtractInfo *info;
4876   guint i, len;
4877   GType ltype, mtype, stype;
4878
4879   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4880   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4881
4882   ltype = gst_value_list_get_type ();
4883
4884   /* special cases */
4885   if (G_VALUE_HOLDS (minuend, ltype) || G_VALUE_HOLDS (subtrahend, ltype))
4886     return TRUE;
4887
4888   mtype = G_VALUE_TYPE (minuend);
4889   stype = G_VALUE_TYPE (subtrahend);
4890
4891   len = gst_value_subtract_funcs->len;
4892   for (i = 0; i < len; i++) {
4893     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4894     if (info->minuend == mtype && info->subtrahend == stype)
4895       return TRUE;
4896   }
4897
4898   return gst_value_can_compare (minuend, subtrahend);
4899 }
4900
4901 /* gst_value_register_subtract_func: (skip)
4902  * @minuend_type: type of the minuend
4903  * @subtrahend_type: type of the subtrahend
4904  * @func: function to use
4905  *
4906  * Registers @func as a function capable of subtracting the values of
4907  * @subtrahend_type from values of @minuend_type.
4908  *
4909  * Subtract functions should be registered at startup before any pipelines are
4910  * started, as gst_value_register_subtract_func() is not thread-safe and
4911  * cannot be used at the same time as gst_value_subtract().
4912  */
4913 static void
4914 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
4915     GstValueSubtractFunc func)
4916 {
4917   GstValueSubtractInfo info;
4918
4919   g_return_if_fail (!gst_type_is_fixed (minuend_type)
4920       || !gst_type_is_fixed (subtrahend_type));
4921
4922   info.minuend = minuend_type;
4923   info.subtrahend = subtrahend_type;
4924   info.func = func;
4925
4926   g_array_append_val (gst_value_subtract_funcs, info);
4927 }
4928
4929 /**
4930  * gst_value_register:
4931  * @table: structure containing functions to register
4932  *
4933  * Registers functions to perform calculations on #GValue items of a given
4934  * type. Each type can only be added once.
4935  */
4936 void
4937 gst_value_register (const GstValueTable * table)
4938 {
4939   GstValueTable *found;
4940
4941   g_return_if_fail (table != NULL);
4942
4943   g_array_append_val (gst_value_table, *table);
4944
4945   found = gst_value_hash_lookup_type (table->type);
4946   if (found)
4947     g_warning ("adding type %s multiple times", g_type_name (table->type));
4948
4949   /* FIXME: we're not really doing the const justice, we assume the table is
4950    * static */
4951   gst_value_hash_add_type (table->type, table);
4952 }
4953
4954 /**
4955  * gst_value_init_and_copy:
4956  * @dest: (out caller-allocates): the target value
4957  * @src: the source value
4958  *
4959  * Initialises the target value to be of the same type as source and then copies
4960  * the contents from source to target.
4961  */
4962 void
4963 gst_value_init_and_copy (GValue * dest, const GValue * src)
4964 {
4965   g_return_if_fail (G_IS_VALUE (src));
4966   g_return_if_fail (dest != NULL);
4967
4968   g_value_init (dest, G_VALUE_TYPE (src));
4969   g_value_copy (src, dest);
4970 }
4971
4972 /* move src into dest and clear src */
4973 static void
4974 gst_value_move (GValue * dest, GValue * src)
4975 {
4976   g_assert (G_IS_VALUE (src));
4977   g_assert (dest != NULL);
4978
4979   *dest = *src;
4980   memset (src, 0, sizeof (GValue));
4981 }
4982
4983 /**
4984  * gst_value_serialize:
4985  * @value: a #GValue to serialize
4986  *
4987  * tries to transform the given @value into a string representation that allows
4988  * getting back this string later on using gst_value_deserialize().
4989  *
4990  * Free-function: g_free
4991  *
4992  * Returns: (transfer full): the serialization for @value or NULL if none exists
4993  */
4994 gchar *
4995 gst_value_serialize (const GValue * value)
4996 {
4997   guint i, len;
4998   GValue s_val = { 0 };
4999   GstValueTable *table, *best;
5000   gchar *s;
5001   GType type;
5002
5003   g_return_val_if_fail (G_IS_VALUE (value), NULL);
5004
5005   type = G_VALUE_TYPE (value);
5006
5007   best = gst_value_hash_lookup_type (type);
5008
5009   if (G_UNLIKELY (!best || !best->serialize)) {
5010     len = gst_value_table->len;
5011     best = NULL;
5012     for (i = 0; i < len; i++) {
5013       table = &g_array_index (gst_value_table, GstValueTable, i);
5014       if (table->serialize && g_type_is_a (type, table->type)) {
5015         if (!best || g_type_is_a (table->type, best->type))
5016           best = table;
5017       }
5018     }
5019   }
5020   if (G_LIKELY (best))
5021     return best->serialize (value);
5022
5023   g_value_init (&s_val, G_TYPE_STRING);
5024   if (g_value_transform (value, &s_val)) {
5025     s = gst_string_wrap (g_value_get_string (&s_val));
5026   } else {
5027     s = NULL;
5028   }
5029   g_value_unset (&s_val);
5030
5031   return s;
5032 }
5033
5034 /**
5035  * gst_value_deserialize:
5036  * @dest: (out caller-allocates): #GValue to fill with contents of
5037  *     deserialization
5038  * @src: string to deserialize
5039  *
5040  * Tries to deserialize a string into the type specified by the given GValue.
5041  * If the operation succeeds, TRUE is returned, FALSE otherwise.
5042  *
5043  * Returns: TRUE on success
5044  */
5045 gboolean
5046 gst_value_deserialize (GValue * dest, const gchar * src)
5047 {
5048   GstValueTable *table, *best;
5049   guint i, len;
5050   GType type;
5051
5052   g_return_val_if_fail (src != NULL, FALSE);
5053   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
5054
5055   type = G_VALUE_TYPE (dest);
5056
5057   best = gst_value_hash_lookup_type (type);
5058   if (G_UNLIKELY (!best || !best->deserialize)) {
5059     len = gst_value_table->len;
5060     best = NULL;
5061     for (i = 0; i < len; i++) {
5062       table = &g_array_index (gst_value_table, GstValueTable, i);
5063       if (table->deserialize && g_type_is_a (type, table->type)) {
5064         if (!best || g_type_is_a (table->type, best->type))
5065           best = table;
5066       }
5067     }
5068   }
5069   if (G_LIKELY (best))
5070     return best->deserialize (dest, src);
5071
5072   return FALSE;
5073 }
5074
5075 /**
5076  * gst_value_is_fixed:
5077  * @value: the #GValue to check
5078  *
5079  * Tests if the given GValue, if available in a GstStructure (or any other
5080  * container) contains a "fixed" (which means: one value) or an "unfixed"
5081  * (which means: multiple possible values, such as data lists or data
5082  * ranges) value.
5083  *
5084  * Returns: true if the value is "fixed".
5085  */
5086
5087 gboolean
5088 gst_value_is_fixed (const GValue * value)
5089 {
5090   GType type;
5091
5092   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
5093
5094   type = G_VALUE_TYPE (value);
5095
5096   /* the most common types are just basic plain glib types */
5097   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
5098     return TRUE;
5099   }
5100
5101   if (type == GST_TYPE_ARRAY) {
5102     gint size, n;
5103     const GValue *kid;
5104
5105     /* check recursively */
5106     size = gst_value_array_get_size (value);
5107     for (n = 0; n < size; n++) {
5108       kid = gst_value_array_get_value (value, n);
5109       if (!gst_value_is_fixed (kid))
5110         return FALSE;
5111     }
5112     return TRUE;
5113   }
5114   return gst_type_is_fixed (type);
5115 }
5116
5117 /**
5118  * gst_value_fixate:
5119  * @dest: the #GValue destination
5120  * @src: the #GValue to fixate
5121  *
5122  * Fixate @src into a new value @dest.
5123  * For ranges, the first element is taken. For lists and arrays, the
5124  * first item is fixated and returned.
5125  * If @src is already fixed, this function returns FALSE.
5126  *
5127  * Returns: true if @dest contains a fixated version of @src.
5128  */
5129 gboolean
5130 gst_value_fixate (GValue * dest, const GValue * src)
5131 {
5132   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
5133   g_return_val_if_fail (dest != NULL, FALSE);
5134
5135   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
5136     g_value_init (dest, G_TYPE_INT);
5137     g_value_set_int (dest, gst_value_get_int_range_min (src));
5138   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
5139     g_value_init (dest, G_TYPE_DOUBLE);
5140     g_value_set_double (dest, gst_value_get_double_range_min (src));
5141   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
5142     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
5143   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
5144     GValue temp = { 0 };
5145
5146     /* list could be empty */
5147     if (gst_value_list_get_size (src) <= 0)
5148       return FALSE;
5149
5150     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
5151
5152     if (!gst_value_fixate (dest, &temp)) {
5153       gst_value_move (dest, &temp);
5154     } else {
5155       g_value_unset (&temp);
5156     }
5157   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
5158     gboolean res = FALSE;
5159     guint n, len;
5160
5161     len = gst_value_array_get_size (src);
5162     g_value_init (dest, GST_TYPE_ARRAY);
5163     for (n = 0; n < len; n++) {
5164       GValue kid = { 0 };
5165       const GValue *orig_kid = gst_value_array_get_value (src, n);
5166
5167       if (!gst_value_fixate (&kid, orig_kid))
5168         gst_value_init_and_copy (&kid, orig_kid);
5169       else
5170         res = TRUE;
5171       _gst_value_array_append_and_take_value (dest, &kid);
5172     }
5173
5174     if (!res)
5175       g_value_unset (dest);
5176
5177     return res;
5178   } else {
5179     return FALSE;
5180   }
5181   return TRUE;
5182 }
5183
5184
5185 /************
5186  * fraction *
5187  ************/
5188
5189 /* helper functions */
5190 static void
5191 gst_value_init_fraction (GValue * value)
5192 {
5193   value->data[0].v_int = 0;
5194   value->data[1].v_int = 1;
5195 }
5196
5197 static void
5198 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
5199 {
5200   dest_value->data[0].v_int = src_value->data[0].v_int;
5201   dest_value->data[1].v_int = src_value->data[1].v_int;
5202 }
5203
5204 static gchar *
5205 gst_value_collect_fraction (GValue * value, guint n_collect_values,
5206     GTypeCValue * collect_values, guint collect_flags)
5207 {
5208   if (n_collect_values != 2)
5209     return g_strdup_printf ("not enough value locations for `%s' passed",
5210         G_VALUE_TYPE_NAME (value));
5211   if (collect_values[1].v_int == 0)
5212     return g_strdup_printf ("passed '0' as denominator for `%s'",
5213         G_VALUE_TYPE_NAME (value));
5214   if (collect_values[0].v_int < -G_MAXINT)
5215     return
5216         g_strdup_printf
5217         ("passed value smaller than -G_MAXINT as numerator for `%s'",
5218         G_VALUE_TYPE_NAME (value));
5219   if (collect_values[1].v_int < -G_MAXINT)
5220     return
5221         g_strdup_printf
5222         ("passed value smaller than -G_MAXINT as denominator for `%s'",
5223         G_VALUE_TYPE_NAME (value));
5224
5225   gst_value_set_fraction (value,
5226       collect_values[0].v_int, collect_values[1].v_int);
5227
5228   return NULL;
5229 }
5230
5231 static gchar *
5232 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
5233     GTypeCValue * collect_values, guint collect_flags)
5234 {
5235   gint *numerator = collect_values[0].v_pointer;
5236   gint *denominator = collect_values[1].v_pointer;
5237
5238   if (!numerator)
5239     return g_strdup_printf ("numerator for `%s' passed as NULL",
5240         G_VALUE_TYPE_NAME (value));
5241   if (!denominator)
5242     return g_strdup_printf ("denominator for `%s' passed as NULL",
5243         G_VALUE_TYPE_NAME (value));
5244
5245   *numerator = value->data[0].v_int;
5246   *denominator = value->data[1].v_int;
5247
5248   return NULL;
5249 }
5250
5251 /**
5252  * gst_value_set_fraction:
5253  * @value: a GValue initialized to #GST_TYPE_FRACTION
5254  * @numerator: the numerator of the fraction
5255  * @denominator: the denominator of the fraction
5256  *
5257  * Sets @value to the fraction specified by @numerator over @denominator.
5258  * The fraction gets reduced to the smallest numerator and denominator,
5259  * and if necessary the sign is moved to the numerator.
5260  */
5261 void
5262 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
5263 {
5264   gint gcd = 0;
5265
5266   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
5267   g_return_if_fail (denominator != 0);
5268   g_return_if_fail (denominator >= -G_MAXINT);
5269   g_return_if_fail (numerator >= -G_MAXINT);
5270
5271   /* normalize sign */
5272   if (denominator < 0) {
5273     numerator = -numerator;
5274     denominator = -denominator;
5275   }
5276
5277   /* check for reduction */
5278   gcd = gst_util_greatest_common_divisor (numerator, denominator);
5279   if (gcd) {
5280     numerator /= gcd;
5281     denominator /= gcd;
5282   }
5283
5284   g_assert (denominator > 0);
5285
5286   value->data[0].v_int = numerator;
5287   value->data[1].v_int = denominator;
5288 }
5289
5290 /**
5291  * gst_value_get_fraction_numerator:
5292  * @value: a GValue initialized to #GST_TYPE_FRACTION
5293  *
5294  * Gets the numerator of the fraction specified by @value.
5295  *
5296  * Returns: the numerator of the fraction.
5297  */
5298 gint
5299 gst_value_get_fraction_numerator (const GValue * value)
5300 {
5301   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
5302
5303   return value->data[0].v_int;
5304 }
5305
5306 /**
5307  * gst_value_get_fraction_denominator:
5308  * @value: a GValue initialized to #GST_TYPE_FRACTION
5309  *
5310  * Gets the denominator of the fraction specified by @value.
5311  *
5312  * Returns: the denominator of the fraction.
5313  */
5314 gint
5315 gst_value_get_fraction_denominator (const GValue * value)
5316 {
5317   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
5318
5319   return value->data[1].v_int;
5320 }
5321
5322 /**
5323  * gst_value_fraction_multiply:
5324  * @product: a GValue initialized to #GST_TYPE_FRACTION
5325  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
5326  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
5327  *
5328  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
5329  * @product to the product of the two fractions.
5330  *
5331  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
5332  */
5333 gboolean
5334 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
5335     const GValue * factor2)
5336 {
5337   gint n1, n2, d1, d2;
5338   gint res_n, res_d;
5339
5340   g_return_val_if_fail (product != NULL, FALSE);
5341   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
5342   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
5343
5344   n1 = factor1->data[0].v_int;
5345   n2 = factor2->data[0].v_int;
5346   d1 = factor1->data[1].v_int;
5347   d2 = factor2->data[1].v_int;
5348
5349   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
5350     return FALSE;
5351
5352   gst_value_set_fraction (product, res_n, res_d);
5353
5354   return TRUE;
5355 }
5356
5357 /**
5358  * gst_value_fraction_subtract:
5359  * @dest: a GValue initialized to #GST_TYPE_FRACTION
5360  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
5361  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
5362  *
5363  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
5364  *
5365  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
5366  */
5367 gboolean
5368 gst_value_fraction_subtract (GValue * dest,
5369     const GValue * minuend, const GValue * subtrahend)
5370 {
5371   gint n1, n2, d1, d2;
5372   gint res_n, res_d;
5373
5374   g_return_val_if_fail (dest != NULL, FALSE);
5375   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
5376   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
5377
5378   n1 = minuend->data[0].v_int;
5379   n2 = subtrahend->data[0].v_int;
5380   d1 = minuend->data[1].v_int;
5381   d2 = subtrahend->data[1].v_int;
5382
5383   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
5384     return FALSE;
5385   gst_value_set_fraction (dest, res_n, res_d);
5386
5387   return TRUE;
5388 }
5389
5390 static gchar *
5391 gst_value_serialize_fraction (const GValue * value)
5392 {
5393   gint32 numerator = value->data[0].v_int;
5394   gint32 denominator = value->data[1].v_int;
5395   gboolean positive = TRUE;
5396
5397   /* get the sign and make components absolute */
5398   if (numerator < 0) {
5399     numerator = -numerator;
5400     positive = !positive;
5401   }
5402   if (denominator < 0) {
5403     denominator = -denominator;
5404     positive = !positive;
5405   }
5406
5407   return g_strdup_printf ("%s%d/%d",
5408       positive ? "" : "-", numerator, denominator);
5409 }
5410
5411 static gboolean
5412 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
5413 {
5414   gint num, den;
5415   gint num_chars;
5416
5417   if (G_UNLIKELY (s == NULL))
5418     return FALSE;
5419
5420   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
5421     return FALSE;
5422
5423   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
5424     if (s[num_chars] != 0)
5425       return FALSE;
5426     if (den == 0)
5427       return FALSE;
5428
5429     gst_value_set_fraction (dest, num, den);
5430     return TRUE;
5431   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
5432     gst_value_set_fraction (dest, 1, G_MAXINT);
5433     return TRUE;
5434   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
5435     if (s[num_chars] != 0)
5436       return FALSE;
5437     gst_value_set_fraction (dest, num, 1);
5438     return TRUE;
5439   } else if (g_ascii_strcasecmp (s, "min") == 0) {
5440     gst_value_set_fraction (dest, -G_MAXINT, 1);
5441     return TRUE;
5442   } else if (g_ascii_strcasecmp (s, "max") == 0) {
5443     gst_value_set_fraction (dest, G_MAXINT, 1);
5444     return TRUE;
5445   }
5446
5447   return FALSE;
5448 }
5449
5450 static void
5451 gst_value_transform_fraction_string (const GValue * src_value,
5452     GValue * dest_value)
5453 {
5454   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
5455 }
5456
5457 static void
5458 gst_value_transform_string_fraction (const GValue * src_value,
5459     GValue * dest_value)
5460 {
5461   if (!gst_value_deserialize_fraction (dest_value,
5462           src_value->data[0].v_pointer))
5463     /* If the deserialize fails, ensure we leave the fraction in a
5464      * valid, if incorrect, state */
5465     gst_value_set_fraction (dest_value, 0, 1);
5466 }
5467
5468 static void
5469 gst_value_transform_double_fraction (const GValue * src_value,
5470     GValue * dest_value)
5471 {
5472   gdouble src = g_value_get_double (src_value);
5473   gint n, d;
5474
5475   gst_util_double_to_fraction (src, &n, &d);
5476   gst_value_set_fraction (dest_value, n, d);
5477 }
5478
5479 static void
5480 gst_value_transform_float_fraction (const GValue * src_value,
5481     GValue * dest_value)
5482 {
5483   gfloat src = g_value_get_float (src_value);
5484   gint n, d;
5485
5486   gst_util_double_to_fraction (src, &n, &d);
5487   gst_value_set_fraction (dest_value, n, d);
5488 }
5489
5490 static void
5491 gst_value_transform_fraction_double (const GValue * src_value,
5492     GValue * dest_value)
5493 {
5494   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
5495       ((double) src_value->data[1].v_int);
5496 }
5497
5498 static void
5499 gst_value_transform_fraction_float (const GValue * src_value,
5500     GValue * dest_value)
5501 {
5502   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
5503       ((float) src_value->data[1].v_int);
5504 }
5505
5506 static gint
5507 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
5508 {
5509   gint n1, n2;
5510   gint d1, d2;
5511   gint ret;
5512
5513   n1 = value1->data[0].v_int;
5514   n2 = value2->data[0].v_int;
5515   d1 = value1->data[1].v_int;
5516   d2 = value2->data[1].v_int;
5517
5518   /* fractions are reduced when set, so we can quickly see if they're equal */
5519   if (n1 == n2 && d1 == d2)
5520     return GST_VALUE_EQUAL;
5521
5522   if (d1 == 0 && d2 == 0)
5523     return GST_VALUE_UNORDERED;
5524   else if (d1 == 0)
5525     return GST_VALUE_GREATER_THAN;
5526   else if (d2 == 0)
5527     return GST_VALUE_LESS_THAN;
5528
5529   ret = gst_util_fraction_compare (n1, d1, n2, d2);
5530   if (ret == -1)
5531     return GST_VALUE_LESS_THAN;
5532   else if (ret == 1)
5533     return GST_VALUE_GREATER_THAN;
5534
5535   /* Equality can't happen here because we check for that
5536    * first already */
5537   g_return_val_if_reached (GST_VALUE_UNORDERED);
5538 }
5539
5540 /*********
5541  * GDate *
5542  *********/
5543
5544 static gint
5545 gst_value_compare_date (const GValue * value1, const GValue * value2)
5546 {
5547   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
5548   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
5549   guint32 j1, j2;
5550
5551   if (date1 == date2)
5552     return GST_VALUE_EQUAL;
5553
5554   if ((date1 == NULL || !g_date_valid (date1))
5555       && (date2 != NULL && g_date_valid (date2))) {
5556     return GST_VALUE_LESS_THAN;
5557   }
5558
5559   if ((date2 == NULL || !g_date_valid (date2))
5560       && (date1 != NULL && g_date_valid (date1))) {
5561     return GST_VALUE_GREATER_THAN;
5562   }
5563
5564   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
5565       || !g_date_valid (date2)) {
5566     return GST_VALUE_UNORDERED;
5567   }
5568
5569   j1 = g_date_get_julian (date1);
5570   j2 = g_date_get_julian (date2);
5571
5572   if (j1 == j2)
5573     return GST_VALUE_EQUAL;
5574   else if (j1 < j2)
5575     return GST_VALUE_LESS_THAN;
5576   else
5577     return GST_VALUE_GREATER_THAN;
5578 }
5579
5580 static gchar *
5581 gst_value_serialize_date (const GValue * val)
5582 {
5583   const GDate *date = (const GDate *) g_value_get_boxed (val);
5584
5585   if (date == NULL || !g_date_valid (date))
5586     return g_strdup ("9999-99-99");
5587
5588   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
5589       g_date_get_month (date), g_date_get_day (date));
5590 }
5591
5592 static gboolean
5593 gst_value_deserialize_date (GValue * dest, const gchar * s)
5594 {
5595   guint year, month, day;
5596
5597   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
5598     return FALSE;
5599
5600   if (!g_date_valid_dmy (day, month, year))
5601     return FALSE;
5602
5603   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
5604   return TRUE;
5605 }
5606
5607 /*************
5608  * GstDateTime *
5609  *************/
5610
5611 static gint
5612 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
5613 {
5614   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
5615   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
5616
5617   if (date1 == date2)
5618     return GST_VALUE_EQUAL;
5619
5620   if ((date1 == NULL) && (date2 != NULL)) {
5621     return GST_VALUE_LESS_THAN;
5622   }
5623   if ((date2 == NULL) && (date1 != NULL)) {
5624     return GST_VALUE_LESS_THAN;
5625   }
5626
5627   /* returns GST_VALUE_* */
5628   return __gst_date_time_compare (date1, date2);
5629 }
5630
5631 static gchar *
5632 gst_value_serialize_date_time (const GValue * val)
5633 {
5634   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
5635
5636   if (date == NULL)
5637     return g_strdup ("null");
5638
5639   return __gst_date_time_serialize (date, TRUE);
5640 }
5641
5642 static gboolean
5643 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
5644 {
5645   GstDateTime *datetime;
5646
5647   if (!s || strcmp (s, "null") == 0) {
5648     return FALSE;
5649   }
5650
5651   datetime = gst_date_time_new_from_iso8601_string (s);
5652   if (datetime != NULL) {
5653     g_value_take_boxed (dest, datetime);
5654     return TRUE;
5655   }
5656   GST_WARNING ("Failed to deserialize date time string '%s'", s);
5657   return FALSE;
5658 }
5659
5660 static void
5661 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
5662 {
5663   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
5664 }
5665
5666 static void
5667 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
5668 {
5669   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
5670 }
5671
5672
5673 /************
5674  * bitmask *
5675  ************/
5676
5677 /* helper functions */
5678 static void
5679 gst_value_init_bitmask (GValue * value)
5680 {
5681   value->data[0].v_uint64 = 0;
5682 }
5683
5684 static void
5685 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
5686 {
5687   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5688 }
5689
5690 static gchar *
5691 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
5692     GTypeCValue * collect_values, guint collect_flags)
5693 {
5694   if (n_collect_values != 1)
5695     return g_strdup_printf ("not enough value locations for `%s' passed",
5696         G_VALUE_TYPE_NAME (value));
5697
5698   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
5699
5700   return NULL;
5701 }
5702
5703 static gchar *
5704 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
5705     GTypeCValue * collect_values, guint collect_flags)
5706 {
5707   guint64 *bitmask = collect_values[0].v_pointer;
5708
5709   if (!bitmask)
5710     return g_strdup_printf ("value for `%s' passed as NULL",
5711         G_VALUE_TYPE_NAME (value));
5712
5713   *bitmask = value->data[0].v_uint64;
5714
5715   return NULL;
5716 }
5717
5718 /**
5719  * gst_value_set_bitmask:
5720  * @value: a GValue initialized to #GST_TYPE_BITMASK
5721  * @bitmask: the bitmask
5722  *
5723  * Sets @value to the bitmask specified by @bitmask.
5724  */
5725 void
5726 gst_value_set_bitmask (GValue * value, guint64 bitmask)
5727 {
5728   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
5729
5730   value->data[0].v_uint64 = bitmask;
5731 }
5732
5733 /**
5734  * gst_value_get_bitmask:
5735  * @value: a GValue initialized to #GST_TYPE_BITMASK
5736  *
5737  * Gets the bitmask specified by @value.
5738  *
5739  * Returns: the bitmask.
5740  */
5741 guint64
5742 gst_value_get_bitmask (const GValue * value)
5743 {
5744   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
5745
5746   return value->data[0].v_uint64;
5747 }
5748
5749 static gchar *
5750 gst_value_serialize_bitmask (const GValue * value)
5751 {
5752   guint64 bitmask = value->data[0].v_uint64;
5753
5754   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
5755 }
5756
5757 static gboolean
5758 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
5759 {
5760   gchar *endptr = NULL;
5761   guint64 val;
5762
5763   if (G_UNLIKELY (s == NULL))
5764     return FALSE;
5765
5766   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
5767     return FALSE;
5768
5769   val = g_ascii_strtoull (s, &endptr, 16);
5770   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
5771     return FALSE;
5772   if (val == 0 && endptr == s)
5773     return FALSE;
5774
5775   gst_value_set_bitmask (dest, val);
5776
5777   return TRUE;
5778 }
5779
5780 static void
5781 gst_value_transform_bitmask_string (const GValue * src_value,
5782     GValue * dest_value)
5783 {
5784   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
5785 }
5786
5787 static void
5788 gst_value_transform_string_bitmask (const GValue * src_value,
5789     GValue * dest_value)
5790 {
5791   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
5792     gst_value_set_bitmask (dest_value, 0);
5793 }
5794
5795 static void
5796 gst_value_transform_uint64_bitmask (const GValue * src_value,
5797     GValue * dest_value)
5798 {
5799   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5800 }
5801
5802 static void
5803 gst_value_transform_bitmask_uint64 (const GValue * src_value,
5804     GValue * dest_value)
5805 {
5806   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5807 }
5808
5809 static gint
5810 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
5811 {
5812   guint64 v1, v2;
5813
5814   v1 = value1->data[0].v_uint64;
5815   v2 = value2->data[0].v_uint64;
5816
5817   if (v1 == v2)
5818     return GST_VALUE_EQUAL;
5819
5820   return GST_VALUE_UNORDERED;
5821 }
5822
5823 static void
5824 gst_value_transform_object_string (const GValue * src_value,
5825     GValue * dest_value)
5826 {
5827   GstObject *obj;
5828   gchar *str;
5829
5830   obj = g_value_get_object (src_value);
5831   if (obj) {
5832     str =
5833         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
5834         GST_OBJECT_NAME (obj));
5835   } else {
5836     str = g_strdup ("NULL");
5837   }
5838
5839   dest_value->data[0].v_pointer = str;
5840 }
5841
5842 static GTypeInfo _info = {
5843   0,
5844   NULL,
5845   NULL,
5846   NULL,
5847   NULL,
5848   NULL,
5849   0,
5850   0,
5851   NULL,
5852   NULL,
5853 };
5854
5855 static GTypeFundamentalInfo _finfo = {
5856   0
5857 };
5858
5859 #define FUNC_VALUE_GET_TYPE(type, name)                         \
5860 GType gst_ ## type ## _get_type (void)                          \
5861 {                                                               \
5862   static volatile GType gst_ ## type ## _type = 0;                       \
5863                                                                 \
5864   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
5865     GType _type;                                        \
5866     _info.value_table = & _gst_ ## type ## _value_table;        \
5867     _type = g_type_register_fundamental (       \
5868         g_type_fundamental_next (),                             \
5869         name, &_info, &_finfo, 0);                              \
5870     g_once_init_leave(&gst_ ## type ## _type, _type);   \
5871   }                                                             \
5872                                                                 \
5873   return gst_ ## type ## _type;                                 \
5874 }
5875
5876 static const GTypeValueTable _gst_int_range_value_table = {
5877   gst_value_init_int_range,
5878   gst_value_free_int_range,
5879   gst_value_copy_int_range,
5880   NULL,
5881   (char *) "ii",
5882   gst_value_collect_int_range,
5883   (char *) "pp",
5884   gst_value_lcopy_int_range
5885 };
5886
5887 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
5888
5889 static const GTypeValueTable _gst_int64_range_value_table = {
5890   gst_value_init_int64_range,
5891   gst_value_free_int64_range,
5892   gst_value_copy_int64_range,
5893   NULL,
5894   (char *) "qq",
5895   gst_value_collect_int64_range,
5896   (char *) "pp",
5897   gst_value_lcopy_int64_range
5898 };
5899
5900 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
5901
5902 static const GTypeValueTable _gst_double_range_value_table = {
5903   gst_value_init_double_range,
5904   NULL,
5905   gst_value_copy_double_range,
5906   NULL,
5907   (char *) "dd",
5908   gst_value_collect_double_range,
5909   (char *) "pp",
5910   gst_value_lcopy_double_range
5911 };
5912
5913 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
5914
5915 static const GTypeValueTable _gst_fraction_range_value_table = {
5916   gst_value_init_fraction_range,
5917   gst_value_free_fraction_range,
5918   gst_value_copy_fraction_range,
5919   NULL,
5920   (char *) "iiii",
5921   gst_value_collect_fraction_range,
5922   (char *) "pppp",
5923   gst_value_lcopy_fraction_range
5924 };
5925
5926 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
5927
5928 static const GTypeValueTable _gst_value_list_value_table = {
5929   gst_value_init_list_or_array,
5930   gst_value_free_list_or_array,
5931   gst_value_copy_list_or_array,
5932   gst_value_list_or_array_peek_pointer,
5933   (char *) "p",
5934   gst_value_collect_list_or_array,
5935   (char *) "p",
5936   gst_value_lcopy_list_or_array
5937 };
5938
5939 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
5940
5941 static const GTypeValueTable _gst_value_array_value_table = {
5942   gst_value_init_list_or_array,
5943   gst_value_free_list_or_array,
5944   gst_value_copy_list_or_array,
5945   gst_value_list_or_array_peek_pointer,
5946   (char *) "p",
5947   gst_value_collect_list_or_array,
5948   (char *) "p",
5949   gst_value_lcopy_list_or_array
5950 };
5951
5952 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
5953
5954 static const GTypeValueTable _gst_fraction_value_table = {
5955   gst_value_init_fraction,
5956   NULL,
5957   gst_value_copy_fraction,
5958   NULL,
5959   (char *) "ii",
5960   gst_value_collect_fraction,
5961   (char *) "pp",
5962   gst_value_lcopy_fraction
5963 };
5964
5965 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
5966
5967 G_DEFINE_BOXED_TYPE (GstDateTime, gst_date_time,
5968     (GBoxedCopyFunc) gst_date_time_ref, (GBoxedFreeFunc) gst_date_time_unref);
5969
5970 static const GTypeValueTable _gst_bitmask_value_table = {
5971   gst_value_init_bitmask,
5972   NULL,
5973   gst_value_copy_bitmask,
5974   NULL,
5975   (char *) "q",
5976   gst_value_collect_bitmask,
5977   (char *) "p",
5978   gst_value_lcopy_bitmask
5979 };
5980
5981 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
5982
5983 GType
5984 gst_g_thread_get_type (void)
5985 {
5986 #if GLIB_CHECK_VERSION(2,35,3)
5987   return G_TYPE_THREAD;
5988 #else
5989   static volatile gsize type_id = 0;
5990
5991   if (g_once_init_enter (&type_id)) {
5992     GType tmp =
5993         g_boxed_type_register_static (g_intern_static_string ("GstGThread"),
5994         (GBoxedCopyFunc) g_thread_ref,
5995         (GBoxedFreeFunc) g_thread_unref);
5996     g_once_init_leave (&type_id, tmp);
5997   }
5998
5999   return type_id;
6000 #endif
6001 }
6002
6003 void
6004 _priv_gst_value_initialize (void)
6005 {
6006   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
6007   gst_value_hash = g_hash_table_new (NULL, NULL);
6008   gst_value_union_funcs = g_array_new (FALSE, FALSE,
6009       sizeof (GstValueUnionInfo));
6010   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
6011       sizeof (GstValueIntersectInfo));
6012   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
6013       sizeof (GstValueSubtractInfo));
6014
6015   {
6016     static GstValueTable gst_value = {
6017       0,
6018       gst_value_compare_int_range,
6019       gst_value_serialize_int_range,
6020       gst_value_deserialize_int_range,
6021     };
6022
6023     gst_value.type = gst_int_range_get_type ();
6024     gst_value_register (&gst_value);
6025   }
6026
6027   {
6028     static GstValueTable gst_value = {
6029       0,
6030       gst_value_compare_int64_range,
6031       gst_value_serialize_int64_range,
6032       gst_value_deserialize_int64_range,
6033     };
6034
6035     gst_value.type = gst_int64_range_get_type ();
6036     gst_value_register (&gst_value);
6037   }
6038
6039   {
6040     static GstValueTable gst_value = {
6041       0,
6042       gst_value_compare_double_range,
6043       gst_value_serialize_double_range,
6044       gst_value_deserialize_double_range,
6045     };
6046
6047     gst_value.type = gst_double_range_get_type ();
6048     gst_value_register (&gst_value);
6049   }
6050
6051   {
6052     static GstValueTable gst_value = {
6053       0,
6054       gst_value_compare_fraction_range,
6055       gst_value_serialize_fraction_range,
6056       gst_value_deserialize_fraction_range,
6057     };
6058
6059     gst_value.type = gst_fraction_range_get_type ();
6060     gst_value_register (&gst_value);
6061   }
6062
6063   {
6064     static GstValueTable gst_value = {
6065       0,
6066       gst_value_compare_list,
6067       gst_value_serialize_list,
6068       gst_value_deserialize_list,
6069     };
6070
6071     gst_value.type = gst_value_list_get_type ();
6072     gst_value_register (&gst_value);
6073   }
6074
6075   {
6076     static GstValueTable gst_value = {
6077       0,
6078       gst_value_compare_array,
6079       gst_value_serialize_array,
6080       gst_value_deserialize_array,
6081     };
6082
6083     gst_value.type = gst_value_array_get_type ();
6084     gst_value_register (&gst_value);
6085   }
6086
6087   {
6088 #if 0
6089     static const GTypeValueTable value_table = {
6090       gst_value_init_buffer,
6091       NULL,
6092       gst_value_copy_buffer,
6093       NULL,
6094       "i",
6095       NULL,                     /*gst_value_collect_buffer, */
6096       "p",
6097       NULL                      /*gst_value_lcopy_buffer */
6098     };
6099 #endif
6100     static GstValueTable gst_value = {
6101       0,
6102       gst_value_compare_buffer,
6103       gst_value_serialize_buffer,
6104       gst_value_deserialize_buffer,
6105     };
6106
6107     gst_value.type = GST_TYPE_BUFFER;
6108     gst_value_register (&gst_value);
6109   }
6110   {
6111     static GstValueTable gst_value = {
6112       0,
6113       gst_value_compare_sample,
6114       gst_value_serialize_sample,
6115       gst_value_deserialize_sample,
6116     };
6117
6118     gst_value.type = GST_TYPE_SAMPLE;
6119     gst_value_register (&gst_value);
6120   }
6121   {
6122     static GstValueTable gst_value = {
6123       0,
6124       gst_value_compare_fraction,
6125       gst_value_serialize_fraction,
6126       gst_value_deserialize_fraction,
6127     };
6128
6129     gst_value.type = gst_fraction_get_type ();
6130     gst_value_register (&gst_value);
6131   }
6132   {
6133     static GstValueTable gst_value = {
6134       0,
6135       gst_value_compare_caps,
6136       gst_value_serialize_caps,
6137       gst_value_deserialize_caps,
6138     };
6139
6140     gst_value.type = GST_TYPE_CAPS;
6141     gst_value_register (&gst_value);
6142   }
6143   {
6144     static GstValueTable gst_value = {
6145       0,
6146       NULL,
6147       gst_value_serialize_segment,
6148       gst_value_deserialize_segment,
6149     };
6150
6151     gst_value.type = GST_TYPE_SEGMENT;
6152     gst_value_register (&gst_value);
6153   }
6154   {
6155     static GstValueTable gst_value = {
6156       0,
6157       NULL,
6158       gst_value_serialize_structure,
6159       gst_value_deserialize_structure,
6160     };
6161
6162     gst_value.type = GST_TYPE_STRUCTURE;
6163     gst_value_register (&gst_value);
6164   }
6165   {
6166     static GstValueTable gst_value = {
6167       0,
6168       NULL,
6169       gst_value_serialize_caps_features,
6170       gst_value_deserialize_caps_features,
6171     };
6172
6173     gst_value.type = GST_TYPE_CAPS_FEATURES;
6174     gst_value_register (&gst_value);
6175   }
6176   {
6177     static GstValueTable gst_value = {
6178       0,
6179       NULL,
6180       gst_value_serialize_tag_list,
6181       gst_value_deserialize_tag_list,
6182     };
6183
6184     gst_value.type = GST_TYPE_TAG_LIST;
6185     gst_value_register (&gst_value);
6186   }
6187   {
6188     static GstValueTable gst_value = {
6189       0,
6190       gst_value_compare_date,
6191       gst_value_serialize_date,
6192       gst_value_deserialize_date,
6193     };
6194
6195     gst_value.type = G_TYPE_DATE;
6196     gst_value_register (&gst_value);
6197   }
6198   {
6199     static GstValueTable gst_value = {
6200       0,
6201       gst_value_compare_date_time,
6202       gst_value_serialize_date_time,
6203       gst_value_deserialize_date_time,
6204     };
6205
6206     gst_value.type = gst_date_time_get_type ();
6207     gst_value_register (&gst_value);
6208   }
6209
6210   {
6211     static GstValueTable gst_value = {
6212       0,
6213       gst_value_compare_bitmask,
6214       gst_value_serialize_bitmask,
6215       gst_value_deserialize_bitmask,
6216     };
6217
6218     gst_value.type = gst_bitmask_get_type ();
6219     gst_value_register (&gst_value);
6220   }
6221
6222   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
6223   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
6224
6225   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
6226   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
6227   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
6228
6229   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
6230
6231   REGISTER_SERIALIZATION (G_TYPE_INT, int);
6232
6233   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
6234   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
6235
6236   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
6237   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
6238   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
6239
6240   REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar);
6241
6242   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
6243       gst_value_transform_int_range_string);
6244   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
6245       gst_value_transform_int64_range_string);
6246   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
6247       gst_value_transform_double_range_string);
6248   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
6249       gst_value_transform_fraction_range_string);
6250   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
6251       gst_value_transform_list_string);
6252   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
6253       gst_value_transform_array_string);
6254   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
6255       gst_value_transform_fraction_string);
6256   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
6257       gst_value_transform_string_fraction);
6258   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
6259       gst_value_transform_fraction_double);
6260   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
6261       gst_value_transform_fraction_float);
6262   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
6263       gst_value_transform_double_fraction);
6264   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
6265       gst_value_transform_float_fraction);
6266   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
6267       gst_value_transform_date_string);
6268   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
6269       gst_value_transform_string_date);
6270   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
6271       gst_value_transform_object_string);
6272   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
6273       gst_value_transform_bitmask_uint64);
6274   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
6275       gst_value_transform_bitmask_string);
6276   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
6277       gst_value_transform_uint64_bitmask);
6278   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
6279       gst_value_transform_string_bitmask);
6280
6281   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6282       gst_value_intersect_int_int_range);
6283   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6284       gst_value_intersect_int_range_int_range);
6285   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6286       gst_value_intersect_int64_int64_range);
6287   gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6288       gst_value_intersect_int64_range_int64_range);
6289   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6290       gst_value_intersect_double_double_range);
6291   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
6292       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
6293   gst_value_register_intersect_func (GST_TYPE_ARRAY,
6294       GST_TYPE_ARRAY, gst_value_intersect_array);
6295   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6296       gst_value_intersect_fraction_fraction_range);
6297   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
6298       GST_TYPE_FRACTION_RANGE,
6299       gst_value_intersect_fraction_range_fraction_range);
6300
6301   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6302       gst_value_subtract_int_int_range);
6303   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
6304       gst_value_subtract_int_range_int);
6305   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6306       gst_value_subtract_int_range_int_range);
6307   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6308       gst_value_subtract_int64_int64_range);
6309   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
6310       gst_value_subtract_int64_range_int64);
6311   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6312       gst_value_subtract_int64_range_int64_range);
6313   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6314       gst_value_subtract_double_double_range);
6315   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
6316       gst_value_subtract_double_range_double);
6317   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
6318       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
6319   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6320       gst_value_subtract_fraction_fraction_range);
6321   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
6322       gst_value_subtract_fraction_range_fraction);
6323   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
6324       GST_TYPE_FRACTION_RANGE,
6325       gst_value_subtract_fraction_range_fraction_range);
6326
6327   /* see bug #317246, #64994, #65041 */
6328   {
6329     volatile GType date_type = G_TYPE_DATE;
6330
6331     g_type_name (date_type);
6332   }
6333
6334   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6335       gst_value_union_int_int_range);
6336   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6337       gst_value_union_int_range_int_range);
6338
6339 #if 0
6340   /* Implement these if needed */
6341   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6342       gst_value_union_fraction_fraction_range);
6343   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
6344       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
6345 #endif
6346 }