source: trunk/third/gstreamer/gst/gstvalue.c @ 21448

Revision 21448, 77.4 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21447, which included commits to RCS files with non-trunk default branches.
Line 
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#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23#include <math.h>
24#include <stdlib.h>
25#include <string.h>
26#include <ctype.h>
27
28#include "gst_private.h"
29#include <gst/gst.h>
30#include <gobject/gvaluecollector.h>
31
32typedef struct _GstValueUnionInfo GstValueUnionInfo;
33struct _GstValueUnionInfo
34{
35  GType type1;
36  GType type2;
37  GstValueUnionFunc func;
38};
39
40typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
41struct _GstValueIntersectInfo
42{
43  GType type1;
44  GType type2;
45  GstValueIntersectFunc func;
46};
47
48typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
49struct _GstValueSubtractInfo
50{
51  GType minuend;
52  GType subtrahend;
53  GstValueSubtractFunc func;
54};
55
56GType gst_type_fourcc;
57GType gst_type_int_range;
58GType gst_type_double_range;
59GType gst_type_list;
60GType gst_type_fixed_list;
61GType gst_type_fraction;
62
63static GArray *gst_value_table;
64static GArray *gst_value_union_funcs;
65static GArray *gst_value_intersect_funcs;
66static GArray *gst_value_subtract_funcs;
67
68/********
69 * list *
70 ********/
71
72/* two helper functions to serialize/stringify any type of list
73 * regular lists are done with { }, fixed lists with < >
74 */
75static char *
76gst_value_serialize_any_list (const GValue * value, const char *begin,
77    const char *end)
78{
79  int i;
80  GArray *array = value->data[0].v_pointer;
81  GString *s;
82  GValue *v;
83  gchar *s_val;
84
85  s = g_string_new (begin);
86  for (i = 0; i < array->len; i++) {
87    v = &g_array_index (array, GValue, i);
88    s_val = gst_value_serialize (v);
89    g_string_append (s, s_val);
90    g_free (s_val);
91    if (i < array->len - 1) {
92      g_string_append (s, ", ");
93    }
94  }
95  g_string_append (s, end);
96  return g_string_free (s, FALSE);
97}
98
99static void
100gst_value_transform_any_list_string (const GValue * src_value,
101    GValue * dest_value, const char *begin, const char *end)
102{
103  GValue *list_value;
104  GArray *array;
105  GString *s;
106  int i;
107  char *list_s;
108
109  array = src_value->data[0].v_pointer;
110
111  s = g_string_new (begin);
112  for (i = 0; i < array->len; i++) {
113    list_value = &g_array_index (array, GValue, i);
114
115    if (i != 0) {
116      g_string_append (s, ", ");
117    }
118    list_s = g_strdup_value_contents (list_value);
119    g_string_append (s, list_s);
120    g_free (list_s);
121  }
122  g_string_append (s, end);
123
124  dest_value->data[0].v_pointer = g_string_free (s, FALSE);
125}
126
127/* GValue functions usable for both regular lists and fixed lists */
128static void
129gst_value_init_list (GValue * value)
130{
131  value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
132}
133
134static GArray *
135gst_value_list_array_copy (const GArray * src)
136{
137  GArray *dest;
138  gint i;
139
140  dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), src->len);
141  g_array_set_size (dest, src->len);
142  for (i = 0; i < src->len; i++) {
143    gst_value_init_and_copy (&g_array_index (dest, GValue, i),
144        &g_array_index (src, GValue, i));
145  }
146
147  return dest;
148}
149
150static void
151gst_value_copy_list (const GValue * src_value, GValue * dest_value)
152{
153  dest_value->data[0].v_pointer =
154      gst_value_list_array_copy ((GArray *) src_value->data[0].v_pointer);
155}
156
157static void
158gst_value_free_list (GValue * value)
159{
160  gint i;
161  GArray *src = (GArray *) value->data[0].v_pointer;
162
163  if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
164    for (i = 0; i < src->len; i++) {
165      g_value_unset (&g_array_index (src, GValue, i));
166    }
167    g_array_free (src, TRUE);
168  }
169}
170
171static gpointer
172gst_value_list_peek_pointer (const GValue * value)
173{
174  return value->data[0].v_pointer;
175}
176
177static gchar *
178gst_value_collect_list (GValue * value, guint n_collect_values,
179    GTypeCValue * collect_values, guint collect_flags)
180{
181  if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
182    value->data[0].v_pointer = collect_values[0].v_pointer;
183    value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
184  } else {
185    value->data[0].v_pointer =
186        gst_value_list_array_copy ((GArray *) collect_values[0].v_pointer);
187  }
188  return NULL;
189}
190
191static gchar *
192gst_value_lcopy_list (const GValue * value, guint n_collect_values,
193    GTypeCValue * collect_values, guint collect_flags)
194{
195  GArray **dest = collect_values[0].v_pointer;
196
197  if (!dest)
198    return g_strdup_printf ("value location for `%s' passed as NULL",
199        G_VALUE_TYPE_NAME (value));
200  if (!value->data[0].v_pointer)
201    return g_strdup_printf ("invalid value given for `%s'",
202        G_VALUE_TYPE_NAME (value));
203  if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
204    *dest = (GArray *) value->data[0].v_pointer;
205  } else {
206    *dest = gst_value_list_array_copy ((GArray *) value->data[0].v_pointer);
207  }
208  return NULL;
209}
210
211/**
212 * gst_value_list_prepend_value:
213 * @value: a GstValueList to prepend a value to
214 * @prepend_value: the value to prepend
215 *
216 * Prepends @prepend_value to the GstValueList in @value.
217 *
218 */
219void
220gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
221{
222  GValue val = { 0, };
223
224  g_return_if_fail (GST_VALUE_HOLDS_LIST (value)
225      || GST_VALUE_HOLDS_FIXED_LIST (value));
226
227  gst_value_init_and_copy (&val, prepend_value);
228  g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
229}
230
231/**
232 * gst_value_list_append_value:
233 * @value: a GstValueList to append a value to
234 * @append_value: the value to append
235 *
236 * Appends @append_value to the GstValueList in @value.
237 */
238void
239gst_value_list_append_value (GValue * value, const GValue * append_value)
240{
241  GValue val = { 0, };
242
243  g_return_if_fail (GST_VALUE_HOLDS_LIST (value)
244      || GST_VALUE_HOLDS_FIXED_LIST (value));
245
246  gst_value_init_and_copy (&val, append_value);
247  g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
248}
249
250/**
251 * gst_value_list_get_size:
252 * @value: a GstValueList
253 *
254 * Gets the number of values contained in @value.
255 *
256 * Returns: the number of values
257 */
258guint
259gst_value_list_get_size (const GValue * value)
260{
261  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value)
262      || GST_VALUE_HOLDS_FIXED_LIST (value), 0);
263
264  return ((GArray *) value->data[0].v_pointer)->len;
265}
266
267/**
268 * gst_value_list_get_value:
269 * @value: a GstValueList
270 * @index: index of value to get from the list
271 *
272 * Gets the value that is a member of the list contained in @value and
273 * has the index @index.
274 *
275 * Returns: the value at the given index
276 */
277const GValue *
278gst_value_list_get_value (const GValue * value, guint index)
279{
280  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value)
281      || GST_VALUE_HOLDS_FIXED_LIST (value), NULL);
282  g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
283
284  return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
285      GValue, index);
286}
287
288/**
289 * gst_value_list_concat:
290 * @dest: an uninitialized #GValue to take the result
291 * @value1: first value to put into the union
292 * @value2: second value to put into the union
293 *
294 * Concatenates copies of value1 and value2 into a list.  The value
295 * @dest is initialized to the type GST_TYPE_LIST.
296 */
297void
298gst_value_list_concat (GValue * dest, const GValue * value1,
299    const GValue * value2)
300{
301  guint i, value1_length, value2_length;
302  GArray *array;
303
304  g_return_if_fail (dest != NULL);
305  g_return_if_fail (G_VALUE_TYPE (dest) == 0);
306  g_return_if_fail (G_IS_VALUE (value1));
307  g_return_if_fail (G_IS_VALUE (value2));
308
309  value1_length =
310      (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
311  value2_length =
312      (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
313  g_value_init (dest, GST_TYPE_LIST);
314  array = (GArray *) dest->data[0].v_pointer;
315  g_array_set_size (array, value1_length + value2_length);
316
317  if (GST_VALUE_HOLDS_LIST (value1)) {
318    for (i = 0; i < value1_length; i++) {
319      gst_value_init_and_copy (&g_array_index (array, GValue, i),
320          gst_value_list_get_value (value1, i));
321    }
322  } else {
323    gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
324  }
325
326  if (GST_VALUE_HOLDS_LIST (value2)) {
327    for (i = 0; i < value2_length; i++) {
328      gst_value_init_and_copy (&g_array_index (array, GValue,
329              i + value1_length), gst_value_list_get_value (value2, i));
330    }
331  } else {
332    gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
333        value2);
334  }
335}
336
337static void
338gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
339{
340  gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
341}
342
343static void
344gst_value_transform_fixed_list_string (const GValue * src_value,
345    GValue * dest_value)
346{
347  gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
348}
349
350static int
351gst_value_compare_list (const GValue * value1, const GValue * value2)
352{
353  int i, j;
354  GArray *array1 = value1->data[0].v_pointer;
355  GArray *array2 = value2->data[0].v_pointer;
356  GValue *v1;
357  GValue *v2;
358
359  if (array1->len != array2->len)
360    return GST_VALUE_UNORDERED;
361
362  for (i = 0; i < array1->len; i++) {
363    v1 = &g_array_index (array1, GValue, i);
364    for (j = 0; j < array1->len; j++) {
365      v2 = &g_array_index (array2, GValue, j);
366      if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
367        break;
368    }
369    if (j == array1->len) {
370      return GST_VALUE_UNORDERED;
371    }
372  }
373
374  return GST_VALUE_EQUAL;
375}
376
377static char *
378gst_value_serialize_list (const GValue * value)
379{
380  return gst_value_serialize_any_list (value, "{ ", " }");
381}
382
383static gboolean
384gst_value_deserialize_list (GValue * dest, const char *s)
385{
386  g_warning ("unimplemented");
387  return FALSE;
388}
389
390static char *
391gst_value_serialize_fixed_list (const GValue * value)
392{
393  return gst_value_serialize_any_list (value, "< ", " >");
394}
395
396static gboolean
397gst_value_deserialize_fixed_list (GValue * dest, const char *s)
398{
399  g_warning ("unimplemented");
400  return FALSE;
401}
402
403/**********
404 * fourcc *
405 **********/
406
407static void
408gst_value_init_fourcc (GValue * value)
409{
410  value->data[0].v_int = 0;
411}
412
413static void
414gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value)
415{
416  dest_value->data[0].v_int = src_value->data[0].v_int;
417}
418
419static gchar *
420gst_value_collect_fourcc (GValue * value, guint n_collect_values,
421    GTypeCValue * collect_values, guint collect_flags)
422{
423  value->data[0].v_int = collect_values[0].v_int;
424
425  return NULL;
426}
427
428static gchar *
429gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values,
430    GTypeCValue * collect_values, guint collect_flags)
431{
432  guint32 *fourcc_p = collect_values[0].v_pointer;
433
434  if (!fourcc_p)
435    return g_strdup_printf ("value location for `%s' passed as NULL",
436        G_VALUE_TYPE_NAME (value));
437
438  *fourcc_p = value->data[0].v_int;
439
440  return NULL;
441}
442
443/**
444 * gst_value_set_fourcc:
445 * @value: a GValue initialized to GST_TYPE_FOURCC
446 * @fourcc: the fourcc to set
447 *
448 * Sets @value to @fourcc.
449 */
450void
451gst_value_set_fourcc (GValue * value, guint32 fourcc)
452{
453  g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
454
455  value->data[0].v_int = fourcc;
456}
457
458/**
459 * gst_value_get_fourcc:
460 * @value: a GValue initialized to GST_TYPE_FOURCC
461 *
462 * Gets the fourcc contained in @value.
463 *
464 * Returns: the fourcc contained in @value.
465 */
466guint32
467gst_value_get_fourcc (const GValue * value)
468{
469  g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
470
471  return value->data[0].v_int;
472}
473
474static void
475gst_value_transform_fourcc_string (const GValue * src_value,
476    GValue * dest_value)
477{
478  guint32 fourcc = src_value->data[0].v_int;
479
480  if (g_ascii_isprint ((fourcc >> 0) & 0xff) &&
481      g_ascii_isprint ((fourcc >> 8) & 0xff) &&
482      g_ascii_isprint ((fourcc >> 16) & 0xff) &&
483      g_ascii_isprint ((fourcc >> 24) & 0xff)) {
484    dest_value->data[0].v_pointer =
485        g_strdup_printf (GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
486  } else {
487    dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc);
488  }
489}
490
491static int
492gst_value_compare_fourcc (const GValue * value1, const GValue * value2)
493{
494  if (value2->data[0].v_int == value1->data[0].v_int)
495    return GST_VALUE_EQUAL;
496  return GST_VALUE_UNORDERED;
497}
498
499static char *
500gst_value_serialize_fourcc (const GValue * value)
501{
502  guint32 fourcc = value->data[0].v_int;
503
504  if (g_ascii_isalnum ((fourcc >> 0) & 0xff) &&
505      g_ascii_isalnum ((fourcc >> 8) & 0xff) &&
506      g_ascii_isalnum ((fourcc >> 16) & 0xff) &&
507      g_ascii_isalnum ((fourcc >> 24) & 0xff)) {
508    return g_strdup_printf (GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
509  } else {
510    return g_strdup_printf ("0x%08x", fourcc);
511  }
512}
513
514static gboolean
515gst_value_deserialize_fourcc (GValue * dest, const char *s)
516{
517  gboolean ret = FALSE;
518  guint32 fourcc = 0;
519  char *end;
520
521  if (strlen (s) == 4) {
522    fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
523    ret = TRUE;
524  } else if (g_ascii_isdigit (*s)) {
525    fourcc = strtoul (s, &end, 0);
526    if (*end == 0) {
527      ret = TRUE;
528    }
529  }
530  gst_value_set_fourcc (dest, fourcc);
531
532  return ret;
533}
534
535/*************
536 * int range *
537 *************/
538
539static void
540gst_value_init_int_range (GValue * value)
541{
542  value->data[0].v_int = 0;
543  value->data[1].v_int = 0;
544}
545
546static void
547gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
548{
549  dest_value->data[0].v_int = src_value->data[0].v_int;
550  dest_value->data[1].v_int = src_value->data[1].v_int;
551}
552
553static gchar *
554gst_value_collect_int_range (GValue * value, guint n_collect_values,
555    GTypeCValue * collect_values, guint collect_flags)
556{
557  /* FIXME */
558  value->data[0].v_int = collect_values[0].v_int;
559  value->data[1].v_int = collect_values[1].v_int;
560
561  return NULL;
562}
563
564static gchar *
565gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
566    GTypeCValue * collect_values, guint collect_flags)
567{
568  guint32 *int_range_start = collect_values[0].v_pointer;
569  guint32 *int_range_end = collect_values[1].v_pointer;
570
571  if (!int_range_start)
572    return g_strdup_printf ("start value location for `%s' passed as NULL",
573        G_VALUE_TYPE_NAME (value));
574  if (!int_range_end)
575    return g_strdup_printf ("end value location for `%s' passed as NULL",
576        G_VALUE_TYPE_NAME (value));
577
578  *int_range_start = value->data[0].v_int;
579  *int_range_end = value->data[1].v_int;
580
581  return NULL;
582}
583
584/**
585 * gst_value_set_int_range:
586 * @value: a GValue initialized to GST_TYPE_INT_RANGE
587 * @start: the start of the range
588 * @end: the end of the range
589 *
590 * Sets @value to the range specified by @start and @end.
591 */
592void
593gst_value_set_int_range (GValue * value, int start, int end)
594{
595  g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
596  g_return_if_fail (start < end);
597
598  value->data[0].v_int = start;
599  value->data[1].v_int = end;
600}
601
602/**
603 * gst_value_get_int_range_min:
604 * @value: a GValue initialized to GST_TYPE_INT_RANGE
605 *
606 * Gets the minimum of the range specified by @value.
607 *
608 * Returns: the minimum of the range
609 */
610int
611gst_value_get_int_range_min (const GValue * value)
612{
613  g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
614
615  return value->data[0].v_int;
616}
617
618/**
619 * gst_value_get_int_range_max:
620 * @value: a GValue initialized to GST_TYPE_INT_RANGE
621 *
622 * Gets the maximum of the range specified by @value.
623 *
624 * Returns: the maxumum of the range
625 */
626int
627gst_value_get_int_range_max (const GValue * value)
628{
629  g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
630
631  return value->data[1].v_int;
632}
633
634static void
635gst_value_transform_int_range_string (const GValue * src_value,
636    GValue * dest_value)
637{
638  dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
639      (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
640}
641
642static int
643gst_value_compare_int_range (const GValue * value1, const GValue * value2)
644{
645  if (value2->data[0].v_int == value1->data[0].v_int &&
646      value2->data[1].v_int == value1->data[1].v_int)
647    return GST_VALUE_EQUAL;
648  return GST_VALUE_UNORDERED;
649}
650
651static char *
652gst_value_serialize_int_range (const GValue * value)
653{
654  return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
655      value->data[1].v_int);
656}
657
658static gboolean
659gst_value_deserialize_int_range (GValue * dest, const char *s)
660{
661  g_warning ("unimplemented");
662  return FALSE;
663}
664
665/****************
666 * double range *
667 ****************/
668
669static void
670gst_value_init_double_range (GValue * value)
671{
672  value->data[0].v_double = 0;
673  value->data[1].v_double = 0;
674}
675
676static void
677gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
678{
679  dest_value->data[0].v_double = src_value->data[0].v_double;
680  dest_value->data[1].v_double = src_value->data[1].v_double;
681}
682
683static gchar *
684gst_value_collect_double_range (GValue * value, guint n_collect_values,
685    GTypeCValue * collect_values, guint collect_flags)
686{
687  value->data[0].v_double = collect_values[0].v_double;
688  value->data[1].v_double = collect_values[1].v_double;
689
690  return NULL;
691}
692
693static gchar *
694gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
695    GTypeCValue * collect_values, guint collect_flags)
696{
697  gdouble *double_range_start = collect_values[0].v_pointer;
698  gdouble *double_range_end = collect_values[1].v_pointer;
699
700  if (!double_range_start)
701    return g_strdup_printf ("start value location for `%s' passed as NULL",
702        G_VALUE_TYPE_NAME (value));
703  if (!double_range_end)
704    return g_strdup_printf ("end value location for `%s' passed as NULL",
705        G_VALUE_TYPE_NAME (value));
706
707  *double_range_start = value->data[0].v_double;
708  *double_range_end = value->data[1].v_double;
709
710  return NULL;
711}
712
713/**
714 * gst_value_set_double_range:
715 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
716 * @start: the start of the range
717 * @end: the end of the range
718 *
719 * Sets @value to the range specified by @start and @end.
720 */
721void
722gst_value_set_double_range (GValue * value, double start, double end)
723{
724  g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
725
726  value->data[0].v_double = start;
727  value->data[1].v_double = end;
728}
729
730/**
731 * gst_value_get_double_range_min:
732 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
733 *
734 * Gets the minimum of the range specified by @value.
735 *
736 * Returns: the minumum of the range
737 */
738double
739gst_value_get_double_range_min (const GValue * value)
740{
741  g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
742
743  return value->data[0].v_double;
744}
745
746/**
747 * gst_value_get_double_range_max:
748 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
749 *
750 * Gets the maximum of the range specified by @value.
751 *
752 * Returns: the maxumum of the range
753 */
754double
755gst_value_get_double_range_max (const GValue * value)
756{
757  g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
758
759  return value->data[1].v_double;
760}
761
762static void
763gst_value_transform_double_range_string (const GValue * src_value,
764    GValue * dest_value)
765{
766  char s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
767
768  dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
769      g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
770          src_value->data[0].v_double),
771      g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
772          src_value->data[1].v_double));
773}
774
775static int
776gst_value_compare_double_range (const GValue * value1, const GValue * value2)
777{
778  if (value2->data[0].v_double == value1->data[0].v_double &&
779      value2->data[0].v_double == value1->data[0].v_double)
780    return GST_VALUE_EQUAL;
781  return GST_VALUE_UNORDERED;
782}
783
784static char *
785gst_value_serialize_double_range (const GValue * value)
786{
787  char d1[G_ASCII_DTOSTR_BUF_SIZE];
788  char d2[G_ASCII_DTOSTR_BUF_SIZE];
789
790  g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
791  g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
792  return g_strdup_printf ("[ %s, %s ]", d1, d2);
793}
794
795static gboolean
796gst_value_deserialize_double_range (GValue * dest, const char *s)
797{
798  g_warning ("unimplemented");
799  return FALSE;
800}
801
802/***********
803 * GstCaps *
804 ***********/
805
806/**
807 * gst_value_set_caps:
808 * @value: a GValue initialized to GST_TYPE_CAPS
809 * @caps: the caps to set the value to
810 *
811 * Sets the contents of @value to coorespond to @caps.  The actual
812 * #GstCaps structure is copied before it is used.
813 */
814void
815gst_value_set_caps (GValue * value, const GstCaps * caps)
816{
817  g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
818
819  g_value_set_boxed (value, caps);
820}
821
822/**
823 * gst_value_get_caps:
824 * @value: a GValue initialized to GST_TYPE_CAPS
825 *
826 * Gets the contents of @value.
827 *
828 * Returns: the contents of @value
829 */
830const GstCaps *
831gst_value_get_caps (const GValue * value)
832{
833  g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
834
835  return (GstCaps *) g_value_get_boxed (value);
836}
837
838/*************
839 * GstBuffer *
840 *************/
841
842static int
843gst_value_compare_buffer (const GValue * value1, const GValue * value2)
844{
845  GstBuffer *buf1 = g_value_get_boxed (value1);
846  GstBuffer *buf2 = g_value_get_boxed (value2);
847
848  if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2))
849    return GST_VALUE_UNORDERED;
850  if (GST_BUFFER_SIZE (buf1) == 0)
851    return GST_VALUE_EQUAL;
852  g_assert (GST_BUFFER_DATA (buf1));
853  g_assert (GST_BUFFER_DATA (buf2));
854  if (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2),
855          GST_BUFFER_SIZE (buf1)) == 0)
856    return GST_VALUE_EQUAL;
857
858  return GST_VALUE_UNORDERED;
859}
860
861static char *
862gst_value_serialize_buffer (const GValue * value)
863{
864  guint8 *data;
865  int i;
866  int size;
867  char *string;
868  GstBuffer *buffer = g_value_get_boxed (value);
869
870  data = GST_BUFFER_DATA (buffer);
871  size = GST_BUFFER_SIZE (buffer);
872
873  string = g_malloc (size * 2 + 1);
874  for (i = 0; i < size; i++) {
875    sprintf (string + i * 2, "%02x", data[i]);
876  }
877  string[size * 2] = 0;
878
879  return string;
880}
881
882static gboolean
883gst_value_deserialize_buffer (GValue * dest, const char *s)
884{
885  GstBuffer *buffer;
886  gboolean ret = TRUE;
887  int len;
888  char ts[3];
889  guint8 *data;
890  int i;
891
892  len = strlen (s);
893  if (len & 1)
894    return FALSE;
895  buffer = gst_buffer_new_and_alloc (len / 2);
896  data = GST_BUFFER_DATA (buffer);
897  for (i = 0; i < len / 2; i++) {
898    if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) {
899      ret = FALSE;
900      break;
901    }
902    ts[0] = s[i * 2 + 0];
903    ts[1] = s[i * 2 + 1];
904    ts[2] = 0;
905
906    data[i] = strtoul (ts, NULL, 16);
907  }
908
909  if (ret) {
910    g_value_set_boxed (dest, buffer);
911    return TRUE;
912  } else {
913    gst_buffer_unref (buffer);
914    return FALSE;
915  }
916}
917
918
919/***********
920 * boolean *
921 ***********/
922
923static int
924gst_value_compare_boolean (const GValue * value1, const GValue * value2)
925{
926  if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
927    return GST_VALUE_EQUAL;
928  return GST_VALUE_UNORDERED;
929}
930
931static char *
932gst_value_serialize_boolean (const GValue * value)
933{
934  if (value->data[0].v_int) {
935    return g_strdup ("true");
936  }
937  return g_strdup ("false");
938}
939
940static gboolean
941gst_value_deserialize_boolean (GValue * dest, const char *s)
942{
943  gboolean ret = FALSE;
944
945  if (g_ascii_strcasecmp (s, "true") == 0 ||
946      g_ascii_strcasecmp (s, "yes") == 0 ||
947      g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
948    g_value_set_boolean (dest, TRUE);
949    ret = TRUE;
950  } else if (g_ascii_strcasecmp (s, "false") == 0 ||
951      g_ascii_strcasecmp (s, "no") == 0 ||
952      g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
953    g_value_set_boolean (dest, FALSE);
954    ret = TRUE;
955  }
956
957  return ret;
958}
959
960/*******
961 * int *
962 *******/
963
964static int
965gst_strtoll (const char *s, char **end, int base)
966{
967  long long i;
968
969  if (s[0] == '-') {
970    i = -(long long) g_ascii_strtoull (s + 1, end, base);
971  } else {
972    i = g_ascii_strtoull (s, end, base);
973  }
974
975  return i;
976}
977
978#define CREATE_SERIALIZATION_START(_type,_macro) \
979static gint \
980gst_value_compare_ ## _type (const GValue * value1, const GValue * value2) \
981{ \
982  g ## _type val1 = g_value_get_ ## _type (value1); \
983  g ## _type val2 = g_value_get_ ## _type (value2); \
984  if (val1 > val2) \
985    return GST_VALUE_GREATER_THAN; \
986  if (val1 < val2) \
987    return GST_VALUE_LESS_THAN; \
988  return GST_VALUE_EQUAL; \
989} \
990\
991static char * \
992gst_value_serialize_ ## _type (const GValue * value) \
993{ \
994  GValue val = { 0, }; \
995  g_value_init (&val, G_TYPE_STRING); \
996  if (!g_value_transform (value, &val)) \
997    g_assert_not_reached (); \
998  /* NO_COPY_MADNESS!!! */ \
999  return (char *) g_value_get_string (&val); \
1000}
1001
1002static gboolean
1003gst_value_deserialize_int_helper (long long *to, const char *s, long long min,
1004    long long max)
1005{
1006  gboolean ret = FALSE;
1007  char *end;
1008
1009  *to = gst_strtoll (s, &end, 0);
1010  if (*end == 0) {
1011    ret = TRUE;
1012  } else {
1013    if (g_ascii_strcasecmp (s, "little_endian") == 0) {
1014      *to = G_LITTLE_ENDIAN;
1015      ret = TRUE;
1016    } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
1017      *to = G_BIG_ENDIAN;
1018      ret = TRUE;
1019    } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
1020      *to = G_BYTE_ORDER;
1021      ret = TRUE;
1022    } else if (g_ascii_strcasecmp (s, "min") == 0) {
1023      *to = min;
1024      ret = TRUE;
1025    } else if (g_ascii_strcasecmp (s, "max") == 0) {
1026      *to = max;
1027      ret = TRUE;
1028    }
1029  }
1030  if (ret) {
1031    if (*to < min || *to > max) {
1032      ret = FALSE;
1033    }
1034  }
1035  return ret;
1036}
1037
1038#define CREATE_SERIALIZATION(_type,_macro) \
1039CREATE_SERIALIZATION_START(_type,_macro) \
1040\
1041static gboolean \
1042gst_value_deserialize_ ## _type (GValue * dest, const char *s) \
1043{ \
1044  long long x; \
1045\
1046  if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro, G_MAX ## _macro)) { \
1047    g_value_set_ ## _type (dest, x); \
1048    return TRUE; \
1049  } else { \
1050    return FALSE; \
1051  } \
1052}
1053
1054#define CREATE_USERIALIZATION(_type,_macro) \
1055CREATE_SERIALIZATION_START(_type,_macro) \
1056\
1057static gboolean \
1058gst_value_deserialize_ ## _type (GValue * dest, const char *s) \
1059{ \
1060  unsigned long long x; \
1061  char *end; \
1062  gboolean ret = FALSE; \
1063\
1064  x = g_ascii_strtoull (s, &end, 0); \
1065  if (*end == 0) { \
1066    ret = TRUE; \
1067  } else { \
1068    if (g_ascii_strcasecmp (s, "little_endian") == 0) { \
1069      x = G_LITTLE_ENDIAN; \
1070      ret = TRUE; \
1071    } else if (g_ascii_strcasecmp (s, "big_endian") == 0) { \
1072      x = G_BIG_ENDIAN; \
1073      ret = TRUE; \
1074    } else if (g_ascii_strcasecmp (s, "byte_order") == 0) { \
1075      x = G_BYTE_ORDER; \
1076      ret = TRUE; \
1077    } else if (g_ascii_strcasecmp (s, "min") == 0) { \
1078      x = 0; \
1079      ret = TRUE; \
1080    } else if (g_ascii_strcasecmp (s, "max") == 0) { \
1081      x = G_MAX ## _macro; \
1082      ret = TRUE; \
1083    } \
1084  } \
1085  if (ret) { \
1086    if (x > G_MAX ## _macro) {\
1087      ret = FALSE; \
1088    } else { \
1089      g_value_set_ ## _type (dest, x); \
1090    } \
1091  } \
1092  return ret; \
1093}
1094
1095#define REGISTER_SERIALIZATION(_gtype, _type) G_STMT_START{ \
1096  static const GstValueTable gst_value = { \
1097    _gtype, \
1098    gst_value_compare_ ## _type, \
1099    gst_value_serialize_ ## _type, \
1100    gst_value_deserialize_ ## _type, \
1101  }; \
1102\
1103  gst_value_register (&gst_value); \
1104} G_STMT_END
1105
1106CREATE_SERIALIZATION (int, INT)
1107    CREATE_SERIALIZATION (int64, INT64)
1108    CREATE_SERIALIZATION (long, LONG)
1109CREATE_USERIALIZATION (uint, UINT)
1110CREATE_USERIALIZATION (uint64, UINT64)
1111CREATE_USERIALIZATION (ulong, ULONG)
1112
1113/**********
1114 * double *
1115 **********/
1116     static int
1117         gst_value_compare_double (const GValue * value1, const GValue * value2)
1118{
1119  if (value1->data[0].v_double > value2->data[0].v_double)
1120    return GST_VALUE_GREATER_THAN;
1121  if (value1->data[0].v_double < value2->data[0].v_double)
1122    return GST_VALUE_LESS_THAN;
1123  if (value1->data[0].v_double == value2->data[0].v_double)
1124    return GST_VALUE_EQUAL;
1125  return GST_VALUE_UNORDERED;
1126}
1127
1128static char *
1129gst_value_serialize_double (const GValue * value)
1130{
1131  char d[G_ASCII_DTOSTR_BUF_SIZE];
1132
1133  g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1134  return g_strdup (d);
1135}
1136
1137static gboolean
1138gst_value_deserialize_double (GValue * dest, const char *s)
1139{
1140  double x;
1141  gboolean ret = FALSE;
1142  char *end;
1143
1144  x = g_ascii_strtod (s, &end);
1145  if (*end == 0) {
1146    ret = TRUE;
1147  } else {
1148    if (g_ascii_strcasecmp (s, "min") == 0) {
1149      x = -G_MAXDOUBLE;
1150      ret = TRUE;
1151    } else if (g_ascii_strcasecmp (s, "max") == 0) {
1152      x = G_MAXDOUBLE;
1153      ret = TRUE;
1154    }
1155  }
1156  if (ret) {
1157    g_value_set_double (dest, x);
1158  }
1159  return ret;
1160}
1161
1162/*********
1163 * float *
1164 *********/
1165
1166static int
1167gst_value_compare_float (const GValue * value1, const GValue * value2)
1168{
1169  if (value1->data[0].v_float > value2->data[0].v_float)
1170    return GST_VALUE_GREATER_THAN;
1171  if (value1->data[0].v_float < value2->data[0].v_float)
1172    return GST_VALUE_LESS_THAN;
1173  if (value1->data[0].v_float == value2->data[0].v_float)
1174    return GST_VALUE_EQUAL;
1175  return GST_VALUE_UNORDERED;
1176}
1177
1178static char *
1179gst_value_serialize_float (const GValue * value)
1180{
1181  char d[G_ASCII_DTOSTR_BUF_SIZE];
1182
1183  g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
1184  return g_strdup (d);
1185}
1186
1187static gboolean
1188gst_value_deserialize_float (GValue * dest, const char *s)
1189{
1190  double x;
1191  gboolean ret = FALSE;
1192  char *end;
1193
1194  x = g_ascii_strtod (s, &end);
1195  if (*end == 0) {
1196    ret = TRUE;
1197  } else {
1198    if (g_ascii_strcasecmp (s, "min") == 0) {
1199      x = -G_MAXFLOAT;
1200      ret = TRUE;
1201    } else if (g_ascii_strcasecmp (s, "max") == 0) {
1202      x = G_MAXFLOAT;
1203      ret = TRUE;
1204    }
1205  }
1206  if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
1207    ret = FALSE;
1208  if (ret) {
1209    g_value_set_float (dest, x);
1210  }
1211  return ret;
1212}
1213
1214/**********
1215 * string *
1216 **********/
1217
1218static int
1219gst_value_compare_string (const GValue * value1, const GValue * value2)
1220{
1221  int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
1222
1223  if (x < 0)
1224    return GST_VALUE_LESS_THAN;
1225  if (x > 0)
1226    return GST_VALUE_GREATER_THAN;
1227  return GST_VALUE_EQUAL;
1228}
1229
1230#define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
1231    ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
1232    ((c) == '.'))
1233
1234static gchar *
1235gst_string_wrap (const char *s)
1236{
1237  const gchar *t;
1238  int len;
1239  gchar *d, *e;
1240  gboolean wrap = FALSE;
1241
1242  len = 0;
1243  t = s;
1244  if (!s)
1245    return g_strdup ("");
1246  while (*t) {
1247    if (GST_ASCII_IS_STRING (*t)) {
1248      len++;
1249    } else if (*t < 0x20 || *t >= 0x7f) {
1250      wrap = TRUE;
1251      len += 4;
1252    } else {
1253      wrap = TRUE;
1254      len += 2;
1255    }
1256    t++;
1257  }
1258
1259  if (!wrap)
1260    return g_strdup (s);
1261
1262  e = d = g_malloc (len + 3);
1263
1264  *e++ = '\"';
1265  t = s;
1266  while (*t) {
1267    if (GST_ASCII_IS_STRING (*t)) {
1268      *e++ = *t++;
1269    } else if (*t < 0x20 || *t >= 0x7f) {
1270      *e++ = '\\';
1271      *e++ = '0' + ((*(guchar *) t) >> 6);
1272      *e++ = '0' + (((*t) >> 3) & 0x7);
1273      *e++ = '0' + ((*t++) & 0x7);
1274    } else {
1275      *e++ = '\\';
1276      *e++ = *t++;
1277    }
1278  }
1279  *e++ = '\"';
1280  *e = 0;
1281
1282  return d;
1283}
1284
1285static char *
1286gst_string_unwrap (const gchar * s)
1287{
1288  /* FIXME: do better memory management? */
1289  gchar *ret = g_strdup (s);
1290  gchar *read = ret, *write = ret;
1291
1292  if (*read++ != '"') {
1293    g_free (ret);
1294    return NULL;
1295  }
1296  while (*read) {
1297    if (GST_ASCII_IS_STRING (*read)) {
1298      *write++ = *read++;
1299    } else if (*read == '"') {
1300      break;
1301    } else if (*read == '\\') {
1302      read++;
1303      if (*read >= '0' && *read <= '7') {
1304        if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7') {
1305          g_free (ret);
1306          return NULL;
1307        }
1308        *write++ = ((read[0] - '0') << 6) +
1309            ((read[1] - '0') << 3) + (read[2] - '0');
1310        read += 3;
1311      } else {
1312        *write++ = *read++;
1313      }
1314    } else {
1315      g_free (ret);
1316      return NULL;
1317    }
1318  }
1319  if (*read != '"' || read[1] != '\0') {
1320    g_free (ret);
1321    return NULL;
1322  }
1323  *write++ = '\0';
1324  return ret;
1325}
1326
1327static char *
1328gst_value_serialize_string (const GValue * value)
1329{
1330  return gst_string_wrap (value->data[0].v_pointer);
1331}
1332
1333static gboolean
1334gst_value_deserialize_string (GValue * dest, const char *s)
1335{
1336  if (*s != '"') {
1337    if (!g_utf8_validate (s, -1, NULL))
1338      return FALSE;
1339    g_value_set_string (dest, s);
1340    return TRUE;
1341  } else {
1342    gchar *str = gst_string_unwrap (s);
1343
1344    if (!str)
1345      return FALSE;
1346    g_value_set_string_take_ownership (dest, str);
1347  }
1348
1349  return TRUE;
1350}
1351
1352/********
1353 * enum *
1354 ********/
1355
1356static int
1357gst_value_compare_enum (const GValue * value1, const GValue * value2)
1358{
1359  GEnumValue *en1, *en2;
1360  GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
1361  GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
1362
1363  g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
1364  g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
1365  en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
1366  en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
1367  g_type_class_unref (klass1);
1368  g_type_class_unref (klass2);
1369  g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
1370  g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
1371  if (en1->value < en2->value)
1372    return GST_VALUE_LESS_THAN;
1373  if (en1->value > en2->value)
1374    return GST_VALUE_GREATER_THAN;
1375
1376  return GST_VALUE_EQUAL;
1377}
1378
1379static char *
1380gst_value_serialize_enum (const GValue * value)
1381{
1382  GEnumValue *en;
1383  GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
1384
1385  g_return_val_if_fail (klass, NULL);
1386  en = g_enum_get_value (klass, g_value_get_enum (value));
1387  g_type_class_unref (klass);
1388  g_return_val_if_fail (en, NULL);
1389  return g_strdup (en->value_name);
1390}
1391
1392static gboolean
1393gst_value_deserialize_enum (GValue * dest, const char *s)
1394{
1395  GEnumValue *en;
1396  gchar *endptr = NULL;
1397  GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
1398
1399  g_return_val_if_fail (klass, FALSE);
1400  if (!(en = g_enum_get_value_by_name (klass, s))) {
1401    if (!(en = g_enum_get_value_by_nick (klass, s))) {
1402      gint i = strtol (s, &endptr, 0);
1403
1404      if (endptr && *endptr == '\0') {
1405        en = g_enum_get_value (klass, i);
1406      }
1407    }
1408  }
1409  g_type_class_unref (klass);
1410  g_return_val_if_fail (en, FALSE);
1411  g_value_set_enum (dest, en->value);
1412  return TRUE;
1413}
1414
1415/*********
1416 * union *
1417 *********/
1418
1419static gboolean
1420gst_value_union_int_int_range (GValue * dest, const GValue * src1,
1421    const GValue * src2)
1422{
1423  g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_INT, FALSE);
1424  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
1425
1426  if (src2->data[0].v_int <= src1->data[0].v_int &&
1427      src2->data[1].v_int >= src1->data[0].v_int) {
1428    gst_value_init_and_copy (dest, src2);
1429    return TRUE;
1430  }
1431
1432  return FALSE;
1433}
1434
1435static gboolean
1436gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
1437    const GValue * src2)
1438{
1439  int min;
1440  int max;
1441
1442  g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_INT_RANGE, FALSE);
1443  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
1444
1445  min = MAX (src1->data[0].v_int, src2->data[0].v_int);
1446  max = MIN (src1->data[1].v_int, src2->data[1].v_int);
1447
1448  if (min <= max) {
1449    g_value_init (dest, GST_TYPE_INT_RANGE);
1450    gst_value_set_int_range (dest,
1451        MIN (src1->data[0].v_int, src2->data[0].v_int),
1452        MAX (src1->data[1].v_int, src2->data[1].v_int));
1453    return TRUE;
1454  }
1455
1456  return FALSE;
1457}
1458
1459/****************
1460 * intersection *
1461 ****************/
1462
1463static gboolean
1464gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
1465    const GValue * src2)
1466{
1467  g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_INT, FALSE);
1468  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
1469
1470  if (src2->data[0].v_int <= src1->data[0].v_int &&
1471      src2->data[1].v_int >= src1->data[0].v_int) {
1472    gst_value_init_and_copy (dest, src1);
1473    return TRUE;
1474  }
1475
1476  return FALSE;
1477}
1478
1479static gboolean
1480gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
1481    const GValue * src2)
1482{
1483  int min;
1484  int max;
1485
1486  g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_INT_RANGE, FALSE);
1487  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
1488
1489  min = MAX (src1->data[0].v_int, src2->data[0].v_int);
1490  max = MIN (src1->data[1].v_int, src2->data[1].v_int);
1491
1492  if (min < max) {
1493    g_value_init (dest, GST_TYPE_INT_RANGE);
1494    gst_value_set_int_range (dest, min, max);
1495    return TRUE;
1496  }
1497  if (min == max) {
1498    g_value_init (dest, G_TYPE_INT);
1499    g_value_set_int (dest, min);
1500    return TRUE;
1501  }
1502
1503  return FALSE;
1504}
1505
1506static gboolean
1507gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
1508    const GValue * src2)
1509{
1510  g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_DOUBLE, FALSE);
1511  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
1512
1513  if (src2->data[0].v_double <= src1->data[0].v_double &&
1514      src2->data[1].v_double >= src1->data[0].v_double) {
1515    gst_value_init_and_copy (dest, src1);
1516    return TRUE;
1517  }
1518
1519  return FALSE;
1520}
1521
1522static gboolean
1523gst_value_intersect_double_range_double_range (GValue * dest,
1524    const GValue * src1, const GValue * src2)
1525{
1526  double min;
1527  double max;
1528
1529  g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_DOUBLE_RANGE, FALSE);
1530  g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
1531
1532  min = MAX (src1->data[0].v_double, src2->data[0].v_double);
1533  max = MIN (src1->data[1].v_double, src2->data[1].v_double);
1534
1535  if (min < max) {
1536    g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
1537    gst_value_set_double_range (dest, min, max);
1538    return TRUE;
1539  }
1540  if (min == max) {
1541    g_value_init (dest, G_TYPE_DOUBLE);
1542    g_value_set_int (dest, min);
1543    return TRUE;
1544  }
1545
1546  return FALSE;
1547}
1548
1549static gboolean
1550gst_value_intersect_list (GValue * dest, const GValue * value1,
1551    const GValue * value2)
1552{
1553  guint i, size;
1554  GValue intersection = { 0, };
1555  gboolean ret = FALSE;
1556
1557  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value1), FALSE);
1558
1559  size = gst_value_list_get_size (value1);
1560  for (i = 0; i < size; i++) {
1561    const GValue *cur = gst_value_list_get_value (value1, i);
1562
1563    if (gst_value_intersect (&intersection, cur, value2)) {
1564      /* append value */
1565      if (!ret) {
1566        gst_value_init_and_copy (dest, &intersection);
1567        ret = TRUE;
1568      } else if (GST_VALUE_HOLDS_LIST (dest)) {
1569        gst_value_list_append_value (dest, &intersection);
1570      } else {
1571        GValue temp = { 0, };
1572
1573        gst_value_init_and_copy (&temp, dest);
1574        g_value_unset (dest);
1575        gst_value_list_concat (dest, &temp, &intersection);
1576      }
1577      g_value_unset (&intersection);
1578    }
1579  }
1580
1581  return ret;
1582}
1583
1584static gboolean
1585gst_value_intersect_fixed_list (GValue * dest, const GValue * src1,
1586    const GValue * src2)
1587{
1588  gint size, n;
1589  GValue val = { 0 };
1590
1591  /* only works on similar-sized arrays */
1592  size = gst_value_list_get_size (src1);
1593  if (size != gst_value_list_get_size (src2))
1594    return FALSE;
1595  g_value_init (dest, GST_TYPE_FIXED_LIST);
1596
1597  for (n = 0; n < size; n++) {
1598    if (!gst_value_intersect (&val, gst_value_list_get_value (src1, n),
1599            gst_value_list_get_value (src2, n))) {
1600      g_value_unset (dest);
1601      return FALSE;
1602    }
1603    gst_value_list_append_value (dest, &val);
1604    g_value_unset (&val);
1605  }
1606
1607  return TRUE;
1608}
1609
1610/***************
1611 * subtraction *
1612 ***************/
1613
1614static gboolean
1615gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
1616    const GValue * subtrahend)
1617{
1618  int min = gst_value_get_int_range_min (subtrahend);
1619  int max = gst_value_get_int_range_max (subtrahend);
1620  int val = g_value_get_int (minuend);
1621
1622  if (val < min || val > max) {
1623    gst_value_init_and_copy (dest, minuend);
1624    return TRUE;
1625  }
1626  return FALSE;
1627}
1628
1629static gboolean
1630gst_value_create_new_range (GValue * dest, int min1, int max1, int min2,
1631    int max2)
1632{
1633  GValue v1 = { 0, };
1634  GValue v2 = { 0, };
1635  GValue *pv1, *pv2;            /* yeah, hungarian! */
1636
1637  if (min1 <= max1 && min2 <= max2) {
1638    pv1 = &v1;
1639    pv2 = &v2;
1640  } else if (min1 <= max1) {
1641    pv1 = dest;
1642    pv2 = NULL;
1643  } else if (min2 <= max2) {
1644    pv1 = NULL;
1645    pv2 = dest;
1646  } else {
1647    return FALSE;
1648  }
1649
1650  if (min1 < max1) {
1651    g_value_init (pv1, GST_TYPE_INT_RANGE);
1652    gst_value_set_int_range (pv1, min1, max1);
1653  } else if (min1 == max1) {
1654    g_value_init (pv1, G_TYPE_INT);
1655    g_value_set_int (pv1, min1);
1656  }
1657  if (min2 < max2) {
1658    g_value_init (pv2, GST_TYPE_INT_RANGE);
1659    gst_value_set_int_range (pv2, min2, max2);
1660  } else if (min2 == max2) {
1661    g_value_init (pv2, G_TYPE_INT);
1662    g_value_set_int (pv2, min2);
1663  }
1664
1665  if (min1 <= max1 && min2 <= max2) {
1666    gst_value_list_concat (dest, pv1, pv2);
1667    g_value_unset (pv1);
1668    g_value_unset (pv2);
1669  }
1670  return TRUE;
1671}
1672
1673static gboolean
1674gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
1675    const GValue * subtrahend)
1676{
1677  int min = gst_value_get_int_range_min (minuend);
1678  int max = gst_value_get_int_range_max (minuend);
1679  int val = g_value_get_int (subtrahend);
1680
1681  g_return_val_if_fail (min < max, FALSE);
1682
1683  if (val < min || val > max) {
1684    gst_value_init_and_copy (dest, minuend);
1685    return TRUE;
1686  } else {
1687    if (val == G_MAXINT) {
1688      max--;
1689      val--;
1690    }
1691    if (val == G_MININT) {
1692      min++;
1693      val++;
1694    }
1695    gst_value_create_new_range (dest, min, val - 1, val + 1, max);
1696  }
1697  return TRUE;
1698}
1699
1700static gboolean
1701gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
1702    const GValue * subtrahend)
1703{
1704  int min1 = gst_value_get_int_range_min (minuend);
1705  int max1 = gst_value_get_int_range_max (minuend);
1706  int min2 = gst_value_get_int_range_min (subtrahend);
1707  int max2 = gst_value_get_int_range_max (subtrahend);
1708
1709  if (max2 == G_MAXINT && min2 == G_MININT) {
1710    return FALSE;
1711  } else if (max2 == G_MAXINT) {
1712    return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
1713  } else if (min2 == G_MININT) {
1714    return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
1715  } else {
1716    return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
1717        MAX (max2 + 1, min1), max1);
1718  }
1719}
1720
1721static gboolean
1722gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
1723    const GValue * subtrahend)
1724{
1725  double min = gst_value_get_double_range_min (subtrahend);
1726  double max = gst_value_get_double_range_max (subtrahend);
1727  double val = g_value_get_double (minuend);
1728
1729  if (val < min || val > max) {
1730    gst_value_init_and_copy (dest, minuend);
1731    return TRUE;
1732  }
1733  return FALSE;
1734}
1735
1736static gboolean
1737gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
1738    const GValue * subtrahend)
1739{
1740  /* FIXME! */
1741  gst_value_init_and_copy (dest, minuend);
1742  return TRUE;
1743}
1744
1745static gboolean
1746gst_value_subtract_double_range_double_range (GValue * dest,
1747    const GValue * minuend, const GValue * subtrahend)
1748{
1749  /* FIXME! */
1750  /* done like with ints */
1751  double min1 = gst_value_get_double_range_min (minuend);
1752  double max2 = gst_value_get_double_range_max (minuend);
1753  double max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
1754  double min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
1755  GValue v1 = { 0, };
1756  GValue v2 = { 0, };
1757  GValue *pv1, *pv2;            /* yeah, hungarian! */
1758
1759  if (min1 < max1 && min2 < max2) {
1760    pv1 = &v1;
1761    pv2 = &v2;
1762  } else if (min1 < max1) {
1763    pv1 = dest;
1764    pv2 = NULL;
1765  } else if (min2 < max2) {
1766    pv1 = NULL;
1767    pv2 = dest;
1768  } else {
1769    return FALSE;
1770  }
1771
1772  if (min1 < max1) {
1773    g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
1774    gst_value_set_double_range (pv1, min1, max1);
1775  }
1776  if (min2 < max2) {
1777    g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
1778    gst_value_set_double_range (pv2, min2, max2);
1779  }
1780
1781  if (min1 < max1 && min2 < max2) {
1782    gst_value_list_concat (dest, pv1, pv2);
1783    g_value_unset (pv1);
1784    g_value_unset (pv2);
1785  }
1786  return TRUE;
1787}
1788
1789static gboolean
1790gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
1791    const GValue * subtrahend)
1792{
1793  guint i, size;
1794  GValue subtraction = { 0, };
1795  gboolean ret = FALSE;
1796
1797  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (minuend), FALSE);
1798
1799  size = gst_value_list_get_size (minuend);
1800  for (i = 0; i < size; i++) {
1801    const GValue *cur = gst_value_list_get_value (minuend, i);
1802
1803    if (gst_value_subtract (&subtraction, cur, subtrahend)) {
1804      if (!ret) {
1805        gst_value_init_and_copy (dest, &subtraction);
1806        ret = TRUE;
1807      } else if (GST_VALUE_HOLDS_LIST (dest)
1808          && GST_VALUE_HOLDS_LIST (&subtraction)) {
1809        /* unroll */
1810        GValue unroll = { 0, };
1811
1812        gst_value_init_and_copy (&unroll, dest);
1813        g_value_unset (dest);
1814        gst_value_list_concat (dest, &unroll, &subtraction);
1815      } else if (GST_VALUE_HOLDS_LIST (dest)) {
1816        gst_value_list_append_value (dest, &subtraction);
1817      } else {
1818        GValue temp = { 0, };
1819
1820        gst_value_init_and_copy (&temp, dest);
1821        g_value_unset (dest);
1822        gst_value_list_concat (dest, &temp, &subtraction);
1823        g_value_unset (&temp);
1824      }
1825      g_value_unset (&subtraction);
1826    }
1827  }
1828  return ret;
1829}
1830
1831static gboolean
1832gst_value_subtract_list (GValue * dest, const GValue * minuend,
1833    const GValue * subtrahend)
1834{
1835  guint i, size;
1836  GValue data[2] = { {0,}, {0,} };
1837  GValue *subtraction = &data[0], *result = &data[1];
1838
1839  g_return_val_if_fail (GST_VALUE_HOLDS_LIST (subtrahend), FALSE);
1840
1841  gst_value_init_and_copy (result, minuend);
1842  size = gst_value_list_get_size (subtrahend);
1843  for (i = 0; i < size; i++) {
1844    const GValue *cur = gst_value_list_get_value (subtrahend, i);
1845
1846    if (gst_value_subtract (subtraction, result, cur)) {
1847      GValue *temp = result;
1848
1849      result = subtraction;
1850      subtraction = temp;
1851      g_value_unset (subtraction);
1852    } else {
1853      g_value_unset (result);
1854      return FALSE;
1855    }
1856  }
1857  gst_value_init_and_copy (dest, result);
1858  g_value_unset (result);
1859  return TRUE;
1860}
1861
1862
1863/**************
1864 * comparison *
1865 **************/
1866
1867/**
1868 * gst_value_can_compare:
1869 * @value1: a value to compare
1870 * @value2: another value to compare
1871 *
1872 * Determines if @value1 and @value2 can be compared.
1873 *
1874 * Returns: TRUE if the values can be compared
1875 */
1876gboolean
1877gst_value_can_compare (const GValue * value1, const GValue * value2)
1878{
1879  GstValueTable *table;
1880  int i;
1881
1882  if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
1883    return FALSE;
1884  for (i = 0; i < gst_value_table->len; i++) {
1885    table = &g_array_index (gst_value_table, GstValueTable, i);
1886    if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
1887      return TRUE;
1888  }
1889
1890  return FALSE;
1891}
1892
1893/**
1894 * gst_value_compare:
1895 * @value1: a value to compare
1896 * @value2: another value to compare
1897 *
1898 * Compares @value1 and @value2.  If @value1 and @value2 cannot be
1899 * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
1900 * if @value1 is greater than @value2, GST_VALUE_GREATER is returned.
1901 * If @value1 is less than @value2, GST_VALUE_LESSER is returned.
1902 * If the values are equal, GST_VALUE_EQUAL is returned.
1903 *
1904 * Returns: A GstValueCompareType value
1905 */
1906int
1907gst_value_compare (const GValue * value1, const GValue * value2)
1908{
1909  GstValueTable *table, *best = NULL;
1910  int i;
1911
1912  if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
1913    return GST_VALUE_UNORDERED;
1914
1915  for (i = 0; i < gst_value_table->len; i++) {
1916    table = &g_array_index (gst_value_table, GstValueTable, i);
1917    if (table->type == G_VALUE_TYPE (value1) && table->compare != NULL) {
1918      best = table;
1919      break;
1920    }
1921    if (g_type_is_a (G_VALUE_TYPE (value1), table->type)) {
1922      if (!best || g_type_is_a (table->type, best->type))
1923        best = table;
1924    }
1925  }
1926  if (best) {
1927    return best->compare (value1, value2);
1928  }
1929
1930  g_critical ("unable to compare values of type %s\n",
1931      g_type_name (G_VALUE_TYPE (value1)));
1932  return GST_VALUE_UNORDERED;
1933}
1934
1935/* union */
1936
1937/**
1938 * gst_value_can_union:
1939 * @value1: a value to union
1940 * @value2: another value to union
1941 *
1942 * Determines if @value1 and @value2 can be non-trivially unioned.
1943 * Any two values can be trivially unioned by adding both of them
1944 * to a GstValueList.  However, certain types have the possibility
1945 * to be unioned in a simpler way.  For example, an integer range
1946 * and an integer can be unioned if the integer is a subset of the
1947 * integer range.  If there is the possibility that two values can
1948 * be unioned, this function returns TRUE.
1949 *
1950 * Returns: TRUE if there is a function allowing the two values to
1951 * be unioned.
1952 */
1953gboolean
1954gst_value_can_union (const GValue * value1, const GValue * value2)
1955{
1956  GstValueUnionInfo *union_info;
1957  int i;
1958
1959  for (i = 0; i < gst_value_union_funcs->len; i++) {
1960    union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
1961    if (union_info->type1 == G_VALUE_TYPE (value1) &&
1962        union_info->type2 == G_VALUE_TYPE (value2))
1963      return TRUE;
1964    if (union_info->type1 == G_VALUE_TYPE (value2) &&
1965        union_info->type2 == G_VALUE_TYPE (value1))
1966      return TRUE;
1967  }
1968
1969  return FALSE;
1970}
1971
1972/**
1973 * gst_value_union:
1974 * @dest: the destination value
1975 * @value1: a value to union
1976 * @value2: another value to union
1977 *
1978 * Creates a GValue cooresponding to the union of @value1 and @value2.
1979 *
1980 * Returns: TRUE if the values could be unioned
1981 */
1982gboolean
1983gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
1984{
1985  GstValueUnionInfo *union_info;
1986  int i;
1987
1988  for (i = 0; i < gst_value_union_funcs->len; i++) {
1989    union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
1990    if (union_info->type1 == G_VALUE_TYPE (value1) &&
1991        union_info->type2 == G_VALUE_TYPE (value2)) {
1992      if (union_info->func (dest, value1, value2)) {
1993        return TRUE;
1994      }
1995    }
1996    if (union_info->type1 == G_VALUE_TYPE (value2) &&
1997        union_info->type2 == G_VALUE_TYPE (value1)) {
1998      if (union_info->func (dest, value2, value1)) {
1999        return TRUE;
2000      }
2001    }
2002  }
2003
2004  gst_value_list_concat (dest, value1, value2);
2005  return TRUE;
2006}
2007
2008/**
2009 * gst_value_register_union_func:
2010 * @type1: a type to union
2011 * @type2: another type to union
2012 * @func: a function that implments creating a union between the two types
2013 *
2014 * Registers a union function that can create a union between GValues
2015 * of the type @type1 and @type2.
2016 *
2017 */
2018void
2019gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
2020{
2021  GstValueUnionInfo union_info;
2022
2023  union_info.type1 = type1;
2024  union_info.type2 = type2;
2025  union_info.func = func;
2026
2027  g_array_append_val (gst_value_union_funcs, union_info);
2028}
2029
2030/* intersection */
2031
2032/**
2033 * gst_value_can_intersect:
2034 * @value1: a value to intersect
2035 * @value2: another value to intersect
2036 *
2037 * Determines if intersecting two values will produce a valid result.
2038 * Two values will produce a valid intersection if they have the same
2039 * type, or if there is a method (registered by
2040 * #gst_value_register_intersection_func) to calculate the intersection.
2041 *
2042 * Returns: TRUE if the values can intersect
2043 */
2044gboolean
2045gst_value_can_intersect (const GValue * value1, const GValue * value2)
2046{
2047  GstValueIntersectInfo *intersect_info;
2048  int i;
2049
2050  /* special cases */
2051  if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
2052    return TRUE;
2053
2054  for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2055    intersect_info = &g_array_index (gst_value_intersect_funcs,
2056        GstValueIntersectInfo, i);
2057    if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2058        intersect_info->type2 == G_VALUE_TYPE (value2))
2059      if (intersect_info->type2 == G_VALUE_TYPE (value1) &&
2060          intersect_info->type1 == G_VALUE_TYPE (value2))
2061        return TRUE;
2062  }
2063
2064  return gst_value_can_compare (value1, value2);
2065}
2066
2067/**
2068 * gst_value_intersect:
2069 * @dest: a uninitialized #GValue that will hold the calculated
2070 * intersection value
2071 * @value1: a value to intersect
2072 * @value2: another value to intersect
2073 *
2074 * Calculates the intersection of two values.  If the values have
2075 * a non-empty intersection, the value representing the intersection
2076 * is placed in @dest.  If the intersection is non-empty, @dest is
2077 * not modified.
2078 *
2079 * Returns: TRUE if the intersection is non-empty
2080 */
2081gboolean
2082gst_value_intersect (GValue * dest, const GValue * value1,
2083    const GValue * value2)
2084{
2085  GstValueIntersectInfo *intersect_info;
2086  int i;
2087  int ret = FALSE;
2088
2089  /* special cases first */
2090  if (GST_VALUE_HOLDS_LIST (value1))
2091    return gst_value_intersect_list (dest, value1, value2);
2092  if (GST_VALUE_HOLDS_LIST (value2))
2093    return gst_value_intersect_list (dest, value2, value1);
2094
2095  for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2096    intersect_info = &g_array_index (gst_value_intersect_funcs,
2097        GstValueIntersectInfo, i);
2098    if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2099        intersect_info->type2 == G_VALUE_TYPE (value2)) {
2100      ret = intersect_info->func (dest, value1, value2);
2101      return ret;
2102    }
2103    if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
2104        intersect_info->type2 == G_VALUE_TYPE (value1)) {
2105      ret = intersect_info->func (dest, value2, value1);
2106      return ret;
2107    }
2108  }
2109
2110  if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
2111    gst_value_init_and_copy (dest, value1);
2112    ret = TRUE;
2113  }
2114
2115  return ret;
2116}
2117
2118/**
2119 * gst_value_register_intersection_func:
2120 * @type1: the first type to intersect
2121 * @type2: the second type to intersect
2122 * @func: the intersection function
2123 *
2124 * Registers a function that is called to calculate the intersection
2125 * of the values having the types @type1 and @type2.
2126 */
2127/**
2128 * GstValueIntersectFunc:
2129 * @dest: a uninitialized #GValue that will hold the calculated
2130 * intersection value
2131 * @value1: a value to intersect
2132 * @value2: another value to intersect
2133 *
2134 * Functions having this type calculate the intersection of @value1
2135 * and @value2.  If the intersection is non-empty, the result is
2136 * placed in @dest and TRUE is returned.  If the intersection is
2137 * empty, @dest is unmodified and FALSE is returned.
2138 *
2139 * Returns: TRUE if the intersection is non-empty, FALSE otherwise
2140 */
2141void
2142gst_value_register_intersect_func (GType type1, GType type2,
2143    GstValueIntersectFunc func)
2144{
2145  GstValueIntersectInfo intersect_info;
2146
2147  intersect_info.type1 = type1;
2148  intersect_info.type2 = type2;
2149  intersect_info.func = func;
2150
2151  g_array_append_val (gst_value_intersect_funcs, intersect_info);
2152}
2153
2154
2155/* subtraction */
2156
2157/**
2158 * gst_value_subtract:
2159 * @dest: the destination value for the result if the subtraction is not empty
2160 * @minuend: the value to subtract from
2161 * @subtrahend: the value to subtract
2162 *
2163 * Subtracts @subtrahend from @minuend and stores the result in @dest.
2164 * Note that this means subtraction as in sets, not as in mathematics.
2165 *
2166 * Returns: TRUE if the subtraction is not empty
2167 */
2168gboolean
2169gst_value_subtract (GValue * dest, const GValue * minuend,
2170    const GValue * subtrahend)
2171{
2172  GstValueSubtractInfo *info;
2173  int i;
2174
2175  /* special cases first */
2176  if (GST_VALUE_HOLDS_LIST (minuend))
2177    return gst_value_subtract_from_list (dest, minuend, subtrahend);
2178  if (GST_VALUE_HOLDS_LIST (subtrahend))
2179    return gst_value_subtract_list (dest, minuend, subtrahend);
2180
2181  for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2182    info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2183    if (info->minuend == G_VALUE_TYPE (minuend) &&
2184        info->subtrahend == G_VALUE_TYPE (subtrahend)) {
2185      return info->func (dest, minuend, subtrahend);
2186    }
2187  }
2188
2189  if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
2190    gst_value_init_and_copy (dest, minuend);
2191    return TRUE;
2192  }
2193
2194  return FALSE;
2195}
2196
2197#if 0
2198gboolean
2199gst_value_subtract (GValue * dest, const GValue * minuend,
2200    const GValue * subtrahend)
2201{
2202  gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
2203
2204  g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
2205      gst_value_serialize (subtrahend),
2206      ret ? gst_value_serialize (dest) : "---");
2207  return ret;
2208}
2209#endif
2210
2211/**
2212 * gst_value_can_subtract:
2213 * @minuend: the value to subtract from
2214 * @subtrahend: the value to subtract
2215 *
2216 * Checks if it's possible to subtract @subtrahend from @minuend.
2217 *
2218 * Returns: TRUE if a subtraction is possible
2219 */
2220gboolean
2221gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
2222{
2223  GstValueSubtractInfo *info;
2224  int i;
2225
2226  /* special cases */
2227  if (GST_VALUE_HOLDS_LIST (minuend) || GST_VALUE_HOLDS_LIST (subtrahend))
2228    return TRUE;
2229
2230  for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2231    info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2232    if (info->minuend == G_VALUE_TYPE (minuend) &&
2233        info->subtrahend == G_VALUE_TYPE (subtrahend))
2234      return TRUE;
2235  }
2236
2237  return gst_value_can_compare (minuend, subtrahend);
2238}
2239
2240/**
2241 * gst_value_register_subtract_func:
2242 * @minuend_type: type of the minuend
2243 * @subtrahend_type: type of the subtrahend
2244 * @func: function to use
2245 *
2246 * Registers @func as a function capable of subtracting the values of
2247 * @subtrahend_type from values of @minuend_type.
2248 */
2249void
2250gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
2251    GstValueSubtractFunc func)
2252{
2253  GstValueSubtractInfo info;
2254
2255  /* one type must be unfixed, other subtractions can be done as comparisons */
2256  g_return_if_fail (!gst_type_is_fixed (minuend_type)
2257      || !gst_type_is_fixed (subtrahend_type));
2258
2259  info.minuend = minuend_type;
2260  info.subtrahend = subtrahend_type;
2261  info.func = func;
2262
2263  g_array_append_val (gst_value_subtract_funcs, info);
2264}
2265
2266/**
2267 * gst_value_register:
2268 * @table: structure containing functions to register
2269 *
2270 * Registers functions to perform calculations on #GValues of a given
2271 * type.
2272 */
2273/**
2274 * GstValueTable:
2275 * @type: GType that the functions operate on.
2276 * @compare: A function that compares two values of this type.
2277 * @serialize: A function that transforms a value of this type to a
2278 * string.  Strings created by this function must be unique and should
2279 * be human readable.
2280 * @deserialize: A function that transforms a string to a value of
2281 * this type.  This function must transform strings created by the
2282 * serialize function back to the original value.  This function may
2283 * optionally transform other strings into values.
2284 */
2285void
2286gst_value_register (const GstValueTable * table)
2287{
2288  g_array_append_val (gst_value_table, *table);
2289}
2290
2291/**
2292 * gst_value_init_and_copy:
2293 * @dest: the target value
2294 * @src: the source value
2295 *
2296 * Initialises the target value to be of the same type as source and then copies
2297 * the contents from source to target.
2298 */
2299void
2300gst_value_init_and_copy (GValue * dest, const GValue * src)
2301{
2302  g_value_init (dest, G_VALUE_TYPE (src));
2303  g_value_copy (src, dest);
2304}
2305
2306/**
2307 * gst_value_serialize:
2308 * @value: a #GValue to serialize
2309 *
2310 * tries to transform the given @value into a string representation that allows
2311 * getting back this string later on using gst_value_deserialize().
2312 *
2313 * Returns: the serialization for @value or NULL if none exists
2314 */
2315gchar *
2316gst_value_serialize (const GValue * value)
2317{
2318  int i;
2319  GValue s_val = { 0 };
2320  GstValueTable *table, *best = NULL;
2321  char *s;
2322
2323  g_return_val_if_fail (G_IS_VALUE (value), NULL);
2324
2325  for (i = 0; i < gst_value_table->len; i++) {
2326    table = &g_array_index (gst_value_table, GstValueTable, i);
2327    if (table->serialize == NULL)
2328      continue;
2329    if (table->type == G_VALUE_TYPE (value)) {
2330      best = table;
2331      break;
2332    }
2333    if (g_type_is_a (G_VALUE_TYPE (value), table->type)) {
2334      if (!best || g_type_is_a (table->type, best->type))
2335        best = table;
2336    }
2337  }
2338  if (best)
2339    return best->serialize (value);
2340
2341  g_value_init (&s_val, G_TYPE_STRING);
2342  if (g_value_transform (value, &s_val)) {
2343    s = gst_string_wrap (g_value_get_string (&s_val));
2344  } else {
2345    s = NULL;
2346  }
2347  g_value_unset (&s_val);
2348
2349  return s;
2350}
2351
2352/**
2353 * gst_value_deserialize:
2354 * @dest: #GValue to fill with contents of deserialization
2355 * @src: string to deserialize
2356 *
2357 * Tries to deserialize a string into the type specified by the given GValue.
2358 * If the operation succeeds, TRUE is returned, FALSE otherwise.
2359 *
2360 * Returns: TRUE on success
2361 */
2362gboolean
2363gst_value_deserialize (GValue * dest, const gchar * src)
2364{
2365  GstValueTable *table, *best = NULL;
2366  int i;
2367
2368  g_return_val_if_fail (src != NULL, FALSE);
2369  g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
2370
2371  for (i = 0; i < gst_value_table->len; i++) {
2372    table = &g_array_index (gst_value_table, GstValueTable, i);
2373    if (table->serialize == NULL)
2374      continue;
2375    if (table->type == G_VALUE_TYPE (dest)) {
2376      best = table;
2377      break;
2378    }
2379    if (g_type_is_a (G_VALUE_TYPE (dest), table->type)) {
2380      if (!best || g_type_is_a (table->type, best->type))
2381        best = table;
2382    }
2383  }
2384  if (best)
2385    return best->deserialize (dest, src);
2386
2387  return FALSE;
2388}
2389
2390/**
2391 * gst_type_is_fixed:
2392 * @type: the #GType to check
2393 *
2394 * Tests if the given GType, if available in a GstStructure (or any other
2395 * container) will contain a "fixed" (which means: one possible value) or
2396 * an "unfixed" (which means: multiple possible values, such as data lists
2397 * or data ranges) value.
2398 *
2399 * Returns: true if the type is "fixed".
2400 */
2401gboolean
2402gst_type_is_fixed (GType type)
2403{
2404  if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
2405      type == GST_TYPE_LIST) {
2406    return FALSE;
2407  }
2408  if (G_TYPE_FUNDAMENTAL (type) <=
2409      G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
2410    return TRUE;
2411  }
2412  if (type == GST_TYPE_BUFFER || type == GST_TYPE_FOURCC
2413      || type == GST_TYPE_FIXED_LIST || type == GST_TYPE_FRACTION) {
2414    return TRUE;
2415  }
2416
2417  return FALSE;
2418}
2419
2420/**
2421 * gst_value_is_fixed:
2422 * @value: the #GValue to check
2423 *
2424 * Tests if the given GValue, if available in a GstStructure (or any other
2425 * container) contains a "fixed" (which means: one value) or an "unfixed"
2426 * (which means: multiple possible values, such as data lists or data
2427 * ranges) value.
2428 *
2429 * Returns: true if the value is "fixed".
2430 */
2431
2432gboolean
2433gst_value_is_fixed (const GValue * value)
2434{
2435  GType type = G_VALUE_TYPE (value);
2436
2437  if (type == GST_TYPE_FIXED_LIST) {
2438    gboolean fixed = TRUE;
2439    gint size, n;
2440    const GValue *kid;
2441
2442    /* check recursively */
2443    size = gst_value_list_get_size (value);
2444    for (n = 0; n < size; n++) {
2445      kid = gst_value_list_get_value (value, n);
2446      fixed &= gst_value_is_fixed (kid);
2447    }
2448
2449    return fixed;
2450  }
2451
2452  return gst_type_is_fixed (type);
2453}
2454
2455/************
2456 * fraction *
2457 ************/
2458
2459/* helper functions */
2460
2461/* Finds the greatest common divisor.
2462 * Returns 1 if none other found.
2463 * This is Euclid's algorithm. */
2464static gint
2465gst_greatest_common_divisor (gint a, gint b)
2466{
2467  while (b != 0) {
2468    int temp = a;
2469
2470    a = b;
2471    b = temp % b;
2472  }
2473
2474  return ABS (a);
2475}
2476
2477static void
2478gst_value_init_fraction (GValue * value)
2479{
2480  value->data[0].v_int = 0;
2481  value->data[1].v_int = 1;
2482}
2483
2484static void
2485gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
2486{
2487  dest_value->data[0].v_int = src_value->data[0].v_int;
2488  dest_value->data[1].v_int = src_value->data[1].v_int;
2489}
2490
2491static gchar *
2492gst_value_collect_fraction (GValue * value, guint n_collect_values,
2493    GTypeCValue * collect_values, guint collect_flags)
2494{
2495  value->data[0].v_int = collect_values[0].v_int;
2496  value->data[1].v_int = collect_values[1].v_int;
2497
2498  return NULL;
2499}
2500
2501static gchar *
2502gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
2503    GTypeCValue * collect_values, guint collect_flags)
2504{
2505  gint *numerator = collect_values[0].v_pointer;
2506  gint *denominator = collect_values[1].v_pointer;
2507
2508  if (!numerator)
2509    return g_strdup_printf ("numerator for `%s' passed as NULL",
2510        G_VALUE_TYPE_NAME (value));
2511  if (!denominator)
2512    return g_strdup_printf ("denominator for `%s' passed as NULL",
2513        G_VALUE_TYPE_NAME (value));
2514
2515  *numerator = value->data[0].v_int;
2516  *denominator = value->data[1].v_int;
2517
2518  return NULL;
2519}
2520
2521/**
2522 * gst_value_set_fraction:
2523 * @value: a GValue initialized to GST_TYPE_FRACTION
2524 * @numerator: the numerator of the fraction
2525 * @denominator: the denominator of the fraction
2526 *
2527 * Sets @value to the fraction specified by @numerator over @denominator.
2528 * The fraction gets reduced to the smallest numerator and denominator,
2529 * and if necessary the sign is moved to the numerator.
2530 */
2531void
2532gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
2533{
2534  gint gcd = 0;
2535
2536  g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
2537  g_return_if_fail (denominator != 0);
2538  g_return_if_fail (denominator >= -G_MAXINT);
2539  g_return_if_fail (numerator >= -G_MAXINT);
2540
2541  /* normalize sign */
2542  if (denominator < 0) {
2543    numerator = -numerator;
2544    denominator = -denominator;
2545  }
2546
2547  /* check for reduction */
2548  gcd = gst_greatest_common_divisor (numerator, denominator);
2549  if (gcd) {
2550    numerator /= gcd;
2551    denominator /= gcd;
2552  }
2553  value->data[0].v_int = numerator;
2554  value->data[1].v_int = denominator;
2555}
2556
2557/**
2558 * gst_value_get_fraction_numerator:
2559 * @value: a GValue initialized to GST_TYPE_FRACTION
2560 *
2561 * Gets the numerator of the fraction specified by @value.
2562 *
2563 * Returns: the numerator of the fraction.
2564 */
2565int
2566gst_value_get_fraction_numerator (const GValue * value)
2567{
2568  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
2569
2570  return value->data[0].v_int;
2571}
2572
2573/**
2574 * gst_value_get_fraction_denominator:
2575 * @value: a GValue initialized to GST_TYPE_FRACTION
2576 *
2577 * Gets the denominator of the fraction specified by @value.
2578 *
2579 * Returns: the denominator of the fraction.
2580 */
2581int
2582gst_value_get_fraction_denominator (const GValue * value)
2583{
2584  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
2585
2586  return value->data[1].v_int;
2587}
2588
2589/**
2590 * gst_value_fraction_multiply:
2591 * @product: a GValue initialized to GST_TYPE_FRACTION
2592 * @factor1: a GValue initialized to GST_TYPE_FRACTION
2593 * @factor2: a GValue initialized to GST_TYPE_FRACTION
2594 *
2595 * Multiplies the two GValues containing a GstFraction and sets @product
2596 * to the product of the two fractions.
2597 *
2598 * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
2599 */
2600gboolean
2601gst_value_fraction_multiply (GValue * product, const GValue * factor1,
2602    const GValue * factor2)
2603{
2604  gint gcd, n1, n2, d1, d2;
2605
2606  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
2607  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
2608
2609  n1 = factor1->data[0].v_int;
2610  n2 = factor2->data[0].v_int;
2611  d1 = factor1->data[1].v_int;
2612  d2 = factor2->data[1].v_int;
2613
2614  gcd = gst_greatest_common_divisor (n1, d2);
2615  n1 /= gcd;
2616  d2 /= gcd;
2617  gcd = gst_greatest_common_divisor (n2, d1);
2618  n2 /= gcd;
2619  d1 /= gcd;
2620
2621  g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (n2), FALSE);
2622  g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
2623
2624  gst_value_set_fraction (product, n1 * n2, d1 * d2);
2625
2626  return TRUE;
2627}
2628
2629static char *
2630gst_value_serialize_fraction (const GValue * value)
2631{
2632  gint32 numerator = value->data[0].v_int;
2633  gint32 denominator = value->data[1].v_int;
2634  gboolean positive = TRUE;
2635
2636  /* get the sign and make components absolute */
2637  if (numerator < 0) {
2638    numerator = -numerator;
2639    positive = !positive;
2640  }
2641  if (denominator < 0) {
2642    denominator = -denominator;
2643    positive = !positive;
2644  }
2645
2646  return g_strdup_printf ("%s%d/%d",
2647      positive ? "" : "-", numerator, denominator);
2648}
2649
2650static gboolean
2651gst_value_deserialize_fraction (GValue * dest, const char *s)
2652{
2653  gint num, den;
2654  char *div;
2655  char *tmp;
2656
2657  div = strstr (s, "/");
2658  if (!div)
2659    return FALSE;
2660  tmp = g_strndup (s, (size_t) (div - s));
2661  num = atoi (tmp);
2662  g_free (tmp);
2663  den = atoi (div + 1);
2664
2665  gst_value_set_fraction (dest, num, den);
2666
2667  return TRUE;
2668}
2669
2670static void
2671gst_value_transform_fraction_string (const GValue * src_value,
2672    GValue * dest_value)
2673{
2674  dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
2675}
2676
2677static void
2678gst_value_transform_string_fraction (const GValue * src_value,
2679    GValue * dest_value)
2680{
2681  gst_value_deserialize_fraction (dest_value, src_value->data[0].v_pointer);
2682}
2683
2684#define MAX_TERMS       30
2685#define MIN_DIVISOR     1.0e-10
2686#define MAX_ERROR       1.0e-20
2687
2688/* use continued fractions to transform a double into a fraction,
2689 * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
2690 * This algorithm takes care of overflows.
2691 */
2692static void
2693gst_value_transform_double_fraction (const GValue * src_value,
2694    GValue * dest_value)
2695{
2696  gdouble V, F;                 /* double being converted */
2697  gint N, D;                    /* will contain the result */
2698  gint A;                       /* current term in continued fraction */
2699  gint64 N1, D1;                /* numerator, denominator of last approx */
2700  gint64 N2, D2;                /* numerator, denominator of previous approx */
2701  gint i;
2702  gboolean negative = FALSE;
2703
2704  /* initialize fraction being converted */
2705  F = src_value->data[0].v_double;
2706  if (F < 0.0) {
2707    F = -F;
2708    negative = TRUE;
2709  }
2710
2711  V = F;
2712  /* initialize fractions with 1/0, 0/1 */
2713  N1 = 1;
2714  D1 = 0;
2715  N2 = 0;
2716  D2 = 1;
2717  N = 1;
2718  D = 1;
2719
2720  for (i = 0; i < MAX_TERMS; i++) {
2721    /* get next term */
2722    A = floor (F);
2723    /* get new divisor */
2724    F = F - A;
2725
2726    /* calculate new fraction in temp */
2727    N2 = N1 * A + N2;
2728    D2 = D1 * A + D2;
2729
2730    /* guard against overflow */
2731    if (N2 > G_MAXINT || D2 > G_MAXINT) {
2732      break;
2733    }
2734
2735    N = N2;
2736    D = D2;
2737
2738    /* save last two fractions */
2739    N2 = N1;
2740    D2 = D1;
2741    N1 = N;
2742    D1 = D;
2743
2744    /* quit if dividing by zero or close enough to target */
2745    if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
2746      break;
2747    }
2748
2749    /* Take reciprocal */
2750    F = 1 / F;
2751  }
2752  /* fix for overflow */
2753  if (D == 0) {
2754    N = G_MAXINT;
2755    D = 1;
2756  }
2757  /* fix for negative */
2758  if (negative)
2759    N = -N;
2760
2761  /* will also simplify */
2762  gst_value_set_fraction (dest_value, N, D);
2763}
2764
2765static void
2766gst_value_transform_fraction_double (const GValue * src_value,
2767    GValue * dest_value)
2768{
2769  dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
2770      ((double) src_value->data[1].v_int);
2771}
2772
2773static int
2774gst_value_compare_fraction (const GValue * value1, const GValue * value2)
2775{
2776  /* FIXME: maybe we should make this more mathematically correct instead
2777   * of approximating with gdoubles */
2778
2779  gint n1, n2;
2780  gint d1, d2;
2781
2782  gdouble new_num_1;
2783  gdouble new_num_2;
2784
2785  n1 = value1->data[0].v_int;
2786  n2 = value2->data[0].v_int;
2787  d1 = value1->data[1].v_int;
2788  d2 = value2->data[1].v_int;
2789
2790  /* fractions are reduced when set, so we can quickly see if they're equal */
2791  if (n1 == n2 && d1 == d2)
2792    return GST_VALUE_EQUAL;
2793
2794  new_num_1 = n1 * d2;
2795  new_num_2 = n2 * d1;
2796  if (new_num_1 < new_num_2)
2797    return GST_VALUE_LESS_THAN;
2798  if (new_num_1 > new_num_2)
2799    return GST_VALUE_GREATER_THAN;
2800  g_assert_not_reached ();
2801  return GST_VALUE_UNORDERED;
2802}
2803
2804void
2805_gst_value_initialize (void)
2806{
2807  GTypeInfo info = {
2808    0,
2809    NULL,
2810    NULL,
2811    NULL,
2812    NULL,
2813    NULL,
2814    0,
2815    0,
2816    NULL,
2817    NULL,
2818  };
2819  GTypeFundamentalInfo finfo = {
2820    0
2821  };
2822
2823  //const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
2824
2825  gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
2826  gst_value_union_funcs = g_array_new (FALSE, FALSE,
2827      sizeof (GstValueUnionInfo));
2828  gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
2829      sizeof (GstValueIntersectInfo));
2830  gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
2831      sizeof (GstValueSubtractInfo));
2832
2833  {
2834    static const GTypeValueTable value_table = {
2835      gst_value_init_fourcc,
2836      NULL,
2837      gst_value_copy_fourcc,
2838      NULL,
2839      "i",
2840      gst_value_collect_fourcc,
2841      "p",
2842      gst_value_lcopy_fourcc
2843    };
2844    static GstValueTable gst_value = {
2845      0,
2846      gst_value_compare_fourcc,
2847      gst_value_serialize_fourcc,
2848      gst_value_deserialize_fourcc,
2849    };
2850
2851    info.value_table = &value_table;
2852    gst_type_fourcc = g_type_register_fundamental (g_type_fundamental_next (),
2853        "GstFourcc", &info, &finfo, 0);
2854    gst_value.type = gst_type_fourcc;
2855    gst_value_register (&gst_value);
2856  }
2857
2858  {
2859    static const GTypeValueTable value_table = {
2860      gst_value_init_int_range,
2861      NULL,
2862      gst_value_copy_int_range,
2863      NULL,
2864      "ii",
2865      gst_value_collect_int_range,
2866      "pp",
2867      gst_value_lcopy_int_range
2868    };
2869    static GstValueTable gst_value = {
2870      0,
2871      gst_value_compare_int_range,
2872      gst_value_serialize_int_range,
2873      gst_value_deserialize_int_range,
2874    };
2875
2876    info.value_table = &value_table;
2877    gst_type_int_range =
2878        g_type_register_fundamental (g_type_fundamental_next (), "GstIntRange",
2879        &info, &finfo, 0);
2880    gst_value.type = gst_type_int_range;
2881    gst_value_register (&gst_value);
2882  }
2883
2884  {
2885    static const GTypeValueTable value_table = {
2886      gst_value_init_double_range,
2887      NULL,
2888      gst_value_copy_double_range,
2889      NULL,
2890      "dd",
2891      gst_value_collect_double_range,
2892      "pp",
2893      gst_value_lcopy_double_range
2894    };
2895    static GstValueTable gst_value = {
2896      0,
2897      gst_value_compare_double_range,
2898      gst_value_serialize_double_range,
2899      gst_value_deserialize_double_range,
2900    };
2901
2902    info.value_table = &value_table;
2903    gst_type_double_range =
2904        g_type_register_fundamental (g_type_fundamental_next (),
2905        "GstDoubleRange", &info, &finfo, 0);
2906    gst_value.type = gst_type_double_range;
2907    gst_value_register (&gst_value);
2908  }
2909
2910  {
2911    static const GTypeValueTable value_table = {
2912      gst_value_init_list,
2913      gst_value_free_list,
2914      gst_value_copy_list,
2915      gst_value_list_peek_pointer,
2916      "p",
2917      gst_value_collect_list,
2918      "p",
2919      gst_value_lcopy_list
2920    };
2921    static GstValueTable gst_value = {
2922      0,
2923      gst_value_compare_list,
2924      gst_value_serialize_list,
2925      gst_value_deserialize_list,
2926    };
2927
2928    info.value_table = &value_table;
2929    gst_type_list = g_type_register_fundamental (g_type_fundamental_next (),
2930        "GstValueList", &info, &finfo, 0);
2931    gst_value.type = gst_type_list;
2932    gst_value_register (&gst_value);
2933  }
2934
2935  {
2936    static const GTypeValueTable value_table = {
2937      gst_value_init_list,
2938      gst_value_free_list,
2939      gst_value_copy_list,
2940      gst_value_list_peek_pointer,
2941      "p",
2942      gst_value_collect_list,
2943      "p",
2944      gst_value_lcopy_list
2945    };
2946    static GstValueTable gst_value = {
2947      0,
2948      gst_value_compare_list,
2949      gst_value_serialize_fixed_list,
2950      gst_value_deserialize_fixed_list,
2951    };
2952
2953    info.value_table = &value_table;
2954    gst_type_fixed_list =
2955        g_type_register_fundamental (g_type_fundamental_next (),
2956        "GstValueFixedList", &info, &finfo, 0);
2957    gst_value.type = gst_type_fixed_list;
2958    gst_value_register (&gst_value);
2959  }
2960
2961  {
2962#if 0
2963    static const GTypeValueTable value_table = {
2964      gst_value_init_buffer,
2965      NULL,
2966      gst_value_copy_buffer,
2967      NULL,
2968      "i",
2969      NULL,                     /*gst_value_collect_buffer, */
2970      "p",
2971      NULL                      /*gst_value_lcopy_buffer */
2972    };
2973#endif
2974    static GstValueTable gst_value = {
2975      0,
2976      gst_value_compare_buffer,
2977      gst_value_serialize_buffer,
2978      gst_value_deserialize_buffer,
2979    };
2980
2981#if 0
2982    info.value_table = &value_table;
2983    gst_type_fourcc =
2984        g_type_register_static (G_TYPE_BOXED, "GstFourcc", &info, 0);
2985#endif
2986    gst_value.type = GST_TYPE_BUFFER;
2987    gst_value_register (&gst_value);
2988  }
2989  {
2990    static const GTypeValueTable value_table = {
2991      gst_value_init_fraction,
2992      NULL,
2993      gst_value_copy_fraction,
2994      NULL,
2995      "ii",
2996      gst_value_collect_fraction,
2997      "pp",
2998      gst_value_lcopy_fraction
2999    };
3000    static GstValueTable gst_value = {
3001      0,
3002      gst_value_compare_fraction,
3003      gst_value_serialize_fraction,
3004      gst_value_deserialize_fraction,
3005    };
3006
3007    info.value_table = &value_table;
3008    gst_type_fraction =
3009        g_type_register_fundamental (g_type_fundamental_next (), "GstFraction",
3010        &info, &finfo, 0);
3011    gst_value.type = gst_type_fraction;
3012    gst_value_register (&gst_value);
3013  }
3014
3015
3016  REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
3017  REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
3018
3019  REGISTER_SERIALIZATION (G_TYPE_STRING, string);
3020  REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
3021  REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
3022
3023  REGISTER_SERIALIZATION (G_TYPE_INT, int);
3024
3025  REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
3026  REGISTER_SERIALIZATION (G_TYPE_LONG, long);
3027
3028  REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
3029  REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
3030  REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
3031
3032  g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
3033      gst_value_transform_fourcc_string);
3034  g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
3035      gst_value_transform_int_range_string);
3036  g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
3037      gst_value_transform_double_range_string);
3038  g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
3039      gst_value_transform_list_string);
3040  g_value_register_transform_func (GST_TYPE_FIXED_LIST, G_TYPE_STRING,
3041      gst_value_transform_fixed_list_string);
3042  g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
3043      gst_value_transform_fraction_string);
3044  g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
3045      gst_value_transform_string_fraction);
3046  g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
3047      gst_value_transform_fraction_double);
3048  g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
3049      gst_value_transform_double_fraction);
3050
3051  gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3052      gst_value_intersect_int_int_range);
3053  gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3054      gst_value_intersect_int_range_int_range);
3055  gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
3056      gst_value_intersect_double_double_range);
3057  gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
3058      GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
3059  gst_value_register_intersect_func (GST_TYPE_FIXED_LIST,
3060      GST_TYPE_FIXED_LIST, gst_value_intersect_fixed_list);
3061
3062  gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3063      gst_value_subtract_int_int_range);
3064  gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
3065      gst_value_subtract_int_range_int);
3066  gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3067      gst_value_subtract_int_range_int_range);
3068  gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
3069      gst_value_subtract_double_double_range);
3070  gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
3071      gst_value_subtract_double_range_double);
3072  gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
3073      GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
3074
3075  gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3076      gst_value_union_int_int_range);
3077  gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3078      gst_value_union_int_range_int_range);
3079}
Note: See TracBrowser for help on using the repository browser.