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