gstreamer_core/gst/gstvalue.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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 and GParamSpec implementations specific
       
    23  * to GStreamer
       
    24  *
       
    25  * GValue and GParamSpec implementations specific to GStreamer.
       
    26  *
       
    27  * Note that operations on the same GstValue (or GValue) from multiple
       
    28  * threads may lead to undefined behaviour. 
       
    29  *
       
    30  * Last reviewed on 2006-03-07 (0.10.4)
       
    31  */
       
    32 
       
    33 #ifdef HAVE_CONFIG_H
       
    34 #include "config.h"
       
    35 #endif
       
    36 #include <math.h>
       
    37 #include <stdlib.h>
       
    38 #include <string.h>
       
    39 #include <ctype.h>
       
    40 
       
    41 #include "gst_private.h"
       
    42 #include "glib-compat-private.h"
       
    43 #include <gst/gst.h>
       
    44 #include <gobject/gvaluecollector.h>
       
    45 
       
    46 #ifdef __SYMBIAN32__
       
    47 #include <glib_global.h>
       
    48 #endif
       
    49 
       
    50 typedef struct _GstValueUnionInfo GstValueUnionInfo;
       
    51 struct _GstValueUnionInfo
       
    52 {
       
    53   GType type1;
       
    54   GType type2;
       
    55   GstValueUnionFunc func;
       
    56 };
       
    57 
       
    58 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
       
    59 struct _GstValueIntersectInfo
       
    60 {
       
    61   GType type1;
       
    62   GType type2;
       
    63   GstValueIntersectFunc func;
       
    64 };
       
    65 
       
    66 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
       
    67 struct _GstValueSubtractInfo
       
    68 {
       
    69   GType minuend;
       
    70   GType subtrahend;
       
    71   GstValueSubtractFunc func;
       
    72 };
       
    73 
       
    74 static GArray *gst_value_table;
       
    75 static GArray *gst_value_union_funcs;
       
    76 static GArray *gst_value_intersect_funcs;
       
    77 static GArray *gst_value_subtract_funcs;
       
    78 
       
    79 /* Forward declarations */
       
    80 static gint gst_greatest_common_divisor (gint a, gint b);
       
    81 static gchar *gst_value_serialize_fraction (const GValue * value);
       
    82 
       
    83 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
       
    84 static gint gst_value_compare_with_func (const GValue * value1,
       
    85     const GValue * value2, GstValueCompareFunc compare);
       
    86 
       
    87 /********
       
    88  * list *
       
    89  ********/
       
    90 
       
    91 /* two helper functions to serialize/stringify any type of list
       
    92  * regular lists are done with { }, arrays with < >
       
    93  */
       
    94 static gchar *
       
    95 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
       
    96     const gchar * end)
       
    97 {
       
    98   guint i;
       
    99   GArray *array = value->data[0].v_pointer;
       
   100   GString *s;
       
   101   GValue *v;
       
   102   gchar *s_val;
       
   103 
       
   104   /* estimate minimum string length to minimise re-allocs in GString */
       
   105   s = g_string_sized_new (2 + (6 * array->len) + 2);
       
   106   g_string_append (s, begin);
       
   107   for (i = 0; i < array->len; i++) {
       
   108     v = &g_array_index (array, GValue, i);
       
   109     s_val = gst_value_serialize (v);
       
   110     g_string_append (s, s_val);
       
   111     g_free (s_val);
       
   112     if (i < array->len - 1) {
       
   113       g_string_append_len (s, ", ", 2);
       
   114     }
       
   115   }
       
   116   g_string_append (s, end);
       
   117   return g_string_free (s, FALSE);
       
   118 }
       
   119 
       
   120 static void
       
   121 gst_value_transform_any_list_string (const GValue * src_value,
       
   122     GValue * dest_value, const gchar * begin, const gchar * end)
       
   123 {
       
   124   GValue *list_value;
       
   125   GArray *array;
       
   126   GString *s;
       
   127   guint i;
       
   128   gchar *list_s;
       
   129 
       
   130   array = src_value->data[0].v_pointer;
       
   131 
       
   132   /* estimate minimum string length to minimise re-allocs in GString */
       
   133   s = g_string_sized_new (2 + (10 * array->len) + 2);
       
   134   g_string_append (s, begin);
       
   135   for (i = 0; i < array->len; i++) {
       
   136     list_value = &g_array_index (array, GValue, i);
       
   137 
       
   138     if (i != 0) {
       
   139       g_string_append_len (s, ", ", 2);
       
   140     }
       
   141     list_s = g_strdup_value_contents (list_value);
       
   142     g_string_append (s, list_s);
       
   143     g_free (list_s);
       
   144   }
       
   145   g_string_append (s, end);
       
   146 
       
   147   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
       
   148 }
       
   149 
       
   150 /*
       
   151  * helper function to see if a type is fixed. Is used internally here and
       
   152  * there. Do not export, since it doesn't work for types where the content
       
   153  * decides the fixedness (e.g. GST_TYPE_ARRAY).
       
   154  */
       
   155 
       
   156 static gboolean
       
   157 gst_type_is_fixed (GType type)
       
   158 {
       
   159   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
       
   160       type == GST_TYPE_LIST) {
       
   161     return FALSE;
       
   162   }
       
   163   if (G_TYPE_FUNDAMENTAL (type) <=
       
   164       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
       
   165     return TRUE;
       
   166   }
       
   167   if (type == GST_TYPE_BUFFER || type == GST_TYPE_FOURCC
       
   168       || type == GST_TYPE_ARRAY || type == GST_TYPE_FRACTION) {
       
   169     return TRUE;
       
   170   }
       
   171 
       
   172   return FALSE;
       
   173 }
       
   174 
       
   175 /* GValue functions usable for both regular lists and arrays */
       
   176 static void
       
   177 gst_value_init_list_or_array (GValue * value)
       
   178 {
       
   179   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
       
   180 }
       
   181 
       
   182 static GArray *
       
   183 copy_garray_of_gstvalue (const GArray * src)
       
   184 {
       
   185   GArray *dest;
       
   186   guint i;
       
   187 
       
   188   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), src->len);
       
   189   g_array_set_size (dest, src->len);
       
   190   for (i = 0; i < src->len; i++) {
       
   191     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
       
   192         &g_array_index (src, GValue, i));
       
   193   }
       
   194 
       
   195   return dest;
       
   196 }
       
   197 
       
   198 static void
       
   199 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
       
   200 {
       
   201   dest_value->data[0].v_pointer =
       
   202       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
       
   203 }
       
   204 
       
   205 static void
       
   206 gst_value_free_list_or_array (GValue * value)
       
   207 {
       
   208   guint i;
       
   209   GArray *src = (GArray *) value->data[0].v_pointer;
       
   210 
       
   211   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
       
   212     for (i = 0; i < src->len; i++) {
       
   213       g_value_unset (&g_array_index (src, GValue, i));
       
   214     }
       
   215     g_array_free (src, TRUE);
       
   216   }
       
   217 }
       
   218 
       
   219 static gpointer
       
   220 gst_value_list_or_array_peek_pointer (const GValue * value)
       
   221 {
       
   222   return value->data[0].v_pointer;
       
   223 }
       
   224 
       
   225 static gchar *
       
   226 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
       
   227     GTypeCValue * collect_values, guint collect_flags)
       
   228 {
       
   229   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
       
   230     value->data[0].v_pointer = collect_values[0].v_pointer;
       
   231     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
       
   232   } else {
       
   233     value->data[0].v_pointer =
       
   234         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
       
   235   }
       
   236   return NULL;
       
   237 }
       
   238 
       
   239 static gchar *
       
   240 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
       
   241     GTypeCValue * collect_values, guint collect_flags)
       
   242 {
       
   243   GArray **dest = collect_values[0].v_pointer;
       
   244 
       
   245   if (!dest)
       
   246     return g_strdup_printf ("value location for `%s' passed as NULL",
       
   247         G_VALUE_TYPE_NAME (value));
       
   248   if (!value->data[0].v_pointer)
       
   249     return g_strdup_printf ("invalid value given for `%s'",
       
   250         G_VALUE_TYPE_NAME (value));
       
   251   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
       
   252     *dest = (GArray *) value->data[0].v_pointer;
       
   253   } else {
       
   254     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
       
   255   }
       
   256   return NULL;
       
   257 }
       
   258 
       
   259 /**
       
   260  * gst_value_list_append_value:
       
   261  * @value: a #GValue of type #GST_TYPE_LIST
       
   262  * @append_value: the value to append
       
   263  *
       
   264  * Appends @append_value to the GstValueList in @value.
       
   265  */
       
   266 #ifdef __SYMBIAN32__
       
   267 EXPORT_C
       
   268 #endif
       
   269 
       
   270 void
       
   271 gst_value_list_append_value (GValue * value, const GValue * append_value)
       
   272 {
       
   273   GValue val = { 0, };
       
   274 
       
   275   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
       
   276 
       
   277   gst_value_init_and_copy (&val, append_value);
       
   278   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
       
   279 }
       
   280 
       
   281 /**
       
   282  * gst_value_list_prepend_value:
       
   283  * @value: a #GValue of type #GST_TYPE_LIST
       
   284  * @prepend_value: the value to prepend
       
   285  *
       
   286  * Prepends @prepend_value to the GstValueList in @value.
       
   287  */
       
   288 #ifdef __SYMBIAN32__
       
   289 EXPORT_C
       
   290 #endif
       
   291 
       
   292 void
       
   293 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
       
   294 {
       
   295   GValue val = { 0, };
       
   296 
       
   297   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
       
   298 
       
   299   gst_value_init_and_copy (&val, prepend_value);
       
   300   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
       
   301 }
       
   302 
       
   303 /**
       
   304  * gst_value_list_concat:
       
   305  * @dest: an uninitialized #GValue to take the result
       
   306  * @value1: a #GValue
       
   307  * @value2: a #GValue
       
   308  *
       
   309  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
       
   310  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
       
   311  * @dest will be initialized to the type #GST_TYPE_LIST.
       
   312  */
       
   313 #ifdef __SYMBIAN32__
       
   314 EXPORT_C
       
   315 #endif
       
   316 
       
   317 void
       
   318 gst_value_list_concat (GValue * dest, const GValue * value1,
       
   319     const GValue * value2)
       
   320 {
       
   321   guint i, value1_length, value2_length;
       
   322   GArray *array;
       
   323 
       
   324   g_return_if_fail (dest != NULL);
       
   325   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
       
   326   g_return_if_fail (G_IS_VALUE (value1));
       
   327   g_return_if_fail (G_IS_VALUE (value2));
       
   328 
       
   329   value1_length =
       
   330       (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
       
   331   value2_length =
       
   332       (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
       
   333   g_value_init (dest, GST_TYPE_LIST);
       
   334   array = (GArray *) dest->data[0].v_pointer;
       
   335   g_array_set_size (array, value1_length + value2_length);
       
   336 
       
   337   if (GST_VALUE_HOLDS_LIST (value1)) {
       
   338     for (i = 0; i < value1_length; i++) {
       
   339       gst_value_init_and_copy (&g_array_index (array, GValue, i),
       
   340           gst_value_list_get_value (value1, i));
       
   341     }
       
   342   } else {
       
   343     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
       
   344   }
       
   345 
       
   346   if (GST_VALUE_HOLDS_LIST (value2)) {
       
   347     for (i = 0; i < value2_length; i++) {
       
   348       gst_value_init_and_copy (&g_array_index (array, GValue,
       
   349               i + value1_length), gst_value_list_get_value (value2, i));
       
   350     }
       
   351   } else {
       
   352     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
       
   353         value2);
       
   354   }
       
   355 }
       
   356 
       
   357 /**
       
   358  * gst_value_list_get_size:
       
   359  * @value: a #GValue of type #GST_TYPE_LIST
       
   360  *
       
   361  * Gets the number of values contained in @value.
       
   362  *
       
   363  * Returns: the number of values
       
   364  */
       
   365 #ifdef __SYMBIAN32__
       
   366 EXPORT_C
       
   367 #endif
       
   368 
       
   369 guint
       
   370 gst_value_list_get_size (const GValue * value)
       
   371 {
       
   372   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
       
   373 
       
   374   return ((GArray *) value->data[0].v_pointer)->len;
       
   375 }
       
   376 
       
   377 /**
       
   378  * gst_value_list_get_value:
       
   379  * @value: a #GValue of type #GST_TYPE_LIST
       
   380  * @index: index of value to get from the list
       
   381  *
       
   382  * Gets the value that is a member of the list contained in @value and
       
   383  * has the index @index.
       
   384  *
       
   385  * Returns: the value at the given index
       
   386  */
       
   387 #ifdef __SYMBIAN32__
       
   388 EXPORT_C
       
   389 #endif
       
   390 
       
   391 const GValue *
       
   392 gst_value_list_get_value (const GValue * value, guint index)
       
   393 {
       
   394   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
       
   395   g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
       
   396 
       
   397   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
       
   398       GValue, index);
       
   399 }
       
   400 
       
   401 /**
       
   402  * gst_value_array_append_value:
       
   403  * @value: a #GValue of type #GST_TYPE_ARRAY
       
   404  * @append_value: the value to append
       
   405  *
       
   406  * Appends @append_value to the GstValueArray in @value.
       
   407  */
       
   408 #ifdef __SYMBIAN32__
       
   409 EXPORT_C
       
   410 #endif
       
   411 
       
   412 void
       
   413 gst_value_array_append_value (GValue * value, const GValue * append_value)
       
   414 {
       
   415   GValue val = { 0, };
       
   416 
       
   417   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
       
   418 
       
   419   gst_value_init_and_copy (&val, append_value);
       
   420   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
       
   421 }
       
   422 
       
   423 /**
       
   424  * gst_value_array_prepend_value:
       
   425  * @value: a #GValue of type #GST_TYPE_ARRAY
       
   426  * @prepend_value: the value to prepend
       
   427  *
       
   428  * Prepends @prepend_value to the GstValueArray in @value.
       
   429  */
       
   430 #ifdef __SYMBIAN32__
       
   431 EXPORT_C
       
   432 #endif
       
   433 
       
   434 void
       
   435 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
       
   436 {
       
   437   GValue val = { 0, };
       
   438 
       
   439   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
       
   440 
       
   441   gst_value_init_and_copy (&val, prepend_value);
       
   442   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
       
   443 }
       
   444 
       
   445 /**
       
   446  * gst_value_array_get_size:
       
   447  * @value: a #GValue of type #GST_TYPE_ARRAY
       
   448  *
       
   449  * Gets the number of values contained in @value.
       
   450  *
       
   451  * Returns: the number of values
       
   452  */
       
   453 #ifdef __SYMBIAN32__
       
   454 EXPORT_C
       
   455 #endif
       
   456 
       
   457 guint
       
   458 gst_value_array_get_size (const GValue * value)
       
   459 {
       
   460   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
       
   461 
       
   462   return ((GArray *) value->data[0].v_pointer)->len;
       
   463 }
       
   464 
       
   465 /**
       
   466  * gst_value_array_get_value:
       
   467  * @value: a #GValue of type #GST_TYPE_ARRAY
       
   468  * @index: index of value to get from the array
       
   469  *
       
   470  * Gets the value that is a member of the array contained in @value and
       
   471  * has the index @index.
       
   472  *
       
   473  * Returns: the value at the given index
       
   474  */
       
   475 #ifdef __SYMBIAN32__
       
   476 EXPORT_C
       
   477 #endif
       
   478 
       
   479 const GValue *
       
   480 gst_value_array_get_value (const GValue * value, guint index)
       
   481 {
       
   482   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
       
   483   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
       
   484 
       
   485   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
       
   486       GValue, index);
       
   487 }
       
   488 
       
   489 static void
       
   490 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
       
   491 {
       
   492   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
       
   493 }
       
   494 
       
   495 static void
       
   496 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
       
   497 {
       
   498   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
       
   499 }
       
   500 
       
   501 /* Do an unordered compare of the contents of a list */
       
   502 static int
       
   503 gst_value_compare_list (const GValue * value1, const GValue * value2)
       
   504 {
       
   505   guint i, j;
       
   506   GArray *array1 = value1->data[0].v_pointer;
       
   507   GArray *array2 = value2->data[0].v_pointer;
       
   508   GValue *v1;
       
   509   GValue *v2;
       
   510   gint len, to_remove;
       
   511   guint8 *removed;
       
   512   GstValueCompareFunc compare;
       
   513 
       
   514   /* get length and do initial length check. */
       
   515   len = array1->len;
       
   516   if (len != array2->len)
       
   517     return GST_VALUE_UNORDERED;
       
   518 
       
   519   /* place to mark removed value indices of array2 */
       
   520   removed = g_newa (guint8, len);
       
   521   memset (removed, 0, len);
       
   522   to_remove = len;
       
   523 
       
   524   /* loop over array1, all items should be in array2. When we find an
       
   525    * item in array2, remove it from array2 by marking it as removed */
       
   526   for (i = 0; i < len; i++) {
       
   527     v1 = &g_array_index (array1, GValue, i);
       
   528     if ((compare = gst_value_get_compare_func (v1))) {
       
   529       for (j = 0; j < len; j++) {
       
   530         /* item is removed, we can skip it */
       
   531         if (removed[j])
       
   532           continue;
       
   533         v2 = &g_array_index (array2, GValue, j);
       
   534         if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
       
   535           /* mark item as removed now that we found it in array2 and 
       
   536            * decrement the number of remaining items in array2. */
       
   537           removed[j] = 1;
       
   538           to_remove--;
       
   539           break;
       
   540         }
       
   541       }
       
   542       /* item in array1 and not in array2, UNORDERED */
       
   543       if (j == len)
       
   544         return GST_VALUE_UNORDERED;
       
   545     } else
       
   546       return GST_VALUE_UNORDERED;
       
   547   }
       
   548   /* if not all items were removed, array2 contained something not in array1 */
       
   549   if (to_remove != 0)
       
   550     return GST_VALUE_UNORDERED;
       
   551 
       
   552   /* arrays are equal */
       
   553   return GST_VALUE_EQUAL;
       
   554 }
       
   555 
       
   556 /* Perform an ordered comparison of the contents of an array */
       
   557 static int
       
   558 gst_value_compare_array (const GValue * value1, const GValue * value2)
       
   559 {
       
   560   guint i;
       
   561   GArray *array1 = value1->data[0].v_pointer;
       
   562   GArray *array2 = value2->data[0].v_pointer;
       
   563   GValue *v1;
       
   564   GValue *v2;
       
   565 
       
   566   if (array1->len != array2->len)
       
   567     return GST_VALUE_UNORDERED;
       
   568 
       
   569   for (i = 0; i < array1->len; i++) {
       
   570     v1 = &g_array_index (array1, GValue, i);
       
   571     v2 = &g_array_index (array2, GValue, i);
       
   572     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
       
   573       return GST_VALUE_UNORDERED;
       
   574   }
       
   575 
       
   576   return GST_VALUE_EQUAL;
       
   577 }
       
   578 
       
   579 static gchar *
       
   580 gst_value_serialize_list (const GValue * value)
       
   581 {
       
   582   return gst_value_serialize_any_list (value, "{ ", " }");
       
   583 }
       
   584 
       
   585 static gboolean
       
   586 gst_value_deserialize_list (GValue * dest, const gchar * s)
       
   587 {
       
   588   g_warning ("gst_value_deserialize_list: unimplemented");
       
   589   return FALSE;
       
   590 }
       
   591 
       
   592 static gchar *
       
   593 gst_value_serialize_array (const GValue * value)
       
   594 {
       
   595   return gst_value_serialize_any_list (value, "< ", " >");
       
   596 }
       
   597 
       
   598 static gboolean
       
   599 gst_value_deserialize_array (GValue * dest, const gchar * s)
       
   600 {
       
   601   g_warning ("gst_value_deserialize_array: unimplemented");
       
   602   return FALSE;
       
   603 }
       
   604 
       
   605 /**********
       
   606  * fourcc *
       
   607  **********/
       
   608 
       
   609 static void
       
   610 gst_value_init_fourcc (GValue * value)
       
   611 {
       
   612   value->data[0].v_int = 0;
       
   613 }
       
   614 
       
   615 static void
       
   616 gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value)
       
   617 {
       
   618   dest_value->data[0].v_int = src_value->data[0].v_int;
       
   619 }
       
   620 
       
   621 static gchar *
       
   622 gst_value_collect_fourcc (GValue * value, guint n_collect_values,
       
   623     GTypeCValue * collect_values, guint collect_flags)
       
   624 {
       
   625   value->data[0].v_int = collect_values[0].v_int;
       
   626 
       
   627   return NULL;
       
   628 }
       
   629 
       
   630 static gchar *
       
   631 gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values,
       
   632     GTypeCValue * collect_values, guint collect_flags)
       
   633 {
       
   634   guint32 *fourcc_p = collect_values[0].v_pointer;
       
   635 
       
   636   if (!fourcc_p)
       
   637     return g_strdup_printf ("value location for `%s' passed as NULL",
       
   638         G_VALUE_TYPE_NAME (value));
       
   639 
       
   640   *fourcc_p = value->data[0].v_int;
       
   641 
       
   642   return NULL;
       
   643 }
       
   644 
       
   645 /**
       
   646  * gst_value_set_fourcc:
       
   647  * @value: a GValue initialized to #GST_TYPE_FOURCC
       
   648  * @fourcc: the #guint32 fourcc to set
       
   649  *
       
   650  * Sets @value to @fourcc.
       
   651  */
       
   652 #ifdef __SYMBIAN32__
       
   653 EXPORT_C
       
   654 #endif
       
   655 
       
   656 void
       
   657 gst_value_set_fourcc (GValue * value, guint32 fourcc)
       
   658 {
       
   659   g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
       
   660 
       
   661   value->data[0].v_int = fourcc;
       
   662 }
       
   663 
       
   664 /**
       
   665  * gst_value_get_fourcc:
       
   666  * @value: a GValue initialized to #GST_TYPE_FOURCC
       
   667  *
       
   668  * Gets the #guint32 fourcc contained in @value.
       
   669  *
       
   670  * Returns: the #guint32 fourcc contained in @value.
       
   671  */
       
   672 #ifdef __SYMBIAN32__
       
   673 EXPORT_C
       
   674 #endif
       
   675 
       
   676 guint32
       
   677 gst_value_get_fourcc (const GValue * value)
       
   678 {
       
   679   g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
       
   680 
       
   681   return value->data[0].v_int;
       
   682 }
       
   683 
       
   684 static void
       
   685 gst_value_transform_fourcc_string (const GValue * src_value,
       
   686     GValue * dest_value)
       
   687 {
       
   688   guint32 fourcc = src_value->data[0].v_int;
       
   689 
       
   690   if (g_ascii_isprint ((fourcc >> 0) & 0xff) &&
       
   691       g_ascii_isprint ((fourcc >> 8) & 0xff) &&
       
   692       g_ascii_isprint ((fourcc >> 16) & 0xff) &&
       
   693       g_ascii_isprint ((fourcc >> 24) & 0xff)) {
       
   694     dest_value->data[0].v_pointer =
       
   695         g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
       
   696   } else {
       
   697     dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc);
       
   698   }
       
   699 }
       
   700 
       
   701 static gint
       
   702 gst_value_compare_fourcc (const GValue * value1, const GValue * value2)
       
   703 {
       
   704   if (value2->data[0].v_int == value1->data[0].v_int)
       
   705     return GST_VALUE_EQUAL;
       
   706   return GST_VALUE_UNORDERED;
       
   707 }
       
   708 
       
   709 static gchar *
       
   710 gst_value_serialize_fourcc (const GValue * value)
       
   711 {
       
   712   guint32 fourcc = value->data[0].v_int;
       
   713 
       
   714   if (g_ascii_isalnum ((fourcc >> 0) & 0xff) &&
       
   715       g_ascii_isalnum ((fourcc >> 8) & 0xff) &&
       
   716       g_ascii_isalnum ((fourcc >> 16) & 0xff) &&
       
   717       g_ascii_isalnum ((fourcc >> 24) & 0xff)) {
       
   718     return g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
       
   719   } else {
       
   720     return g_strdup_printf ("0x%08x", fourcc);
       
   721   }
       
   722 }
       
   723 
       
   724 static gboolean
       
   725 gst_value_deserialize_fourcc (GValue * dest, const char *s)
       
   726 {
       
   727   gboolean ret = FALSE;
       
   728   guint32 fourcc = 0;
       
   729   char *end;
       
   730 
       
   731   if (strlen (s) == 4) {
       
   732     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
       
   733     ret = TRUE;
       
   734   } else if (g_ascii_isdigit (*s)) {
       
   735     fourcc = strtoul (s, &end, 0);
       
   736     if (*end == 0) {
       
   737       ret = TRUE;
       
   738     }
       
   739   }
       
   740   gst_value_set_fourcc (dest, fourcc);
       
   741 
       
   742   return ret;
       
   743 }
       
   744 
       
   745 /*************
       
   746  * int range *
       
   747  *************/
       
   748 
       
   749 static void
       
   750 gst_value_init_int_range (GValue * value)
       
   751 {
       
   752   value->data[0].v_int = 0;
       
   753   value->data[1].v_int = 0;
       
   754 }
       
   755 
       
   756 static void
       
   757 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
       
   758 {
       
   759   dest_value->data[0].v_int = src_value->data[0].v_int;
       
   760   dest_value->data[1].v_int = src_value->data[1].v_int;
       
   761 }
       
   762 
       
   763 static gchar *
       
   764 gst_value_collect_int_range (GValue * value, guint n_collect_values,
       
   765     GTypeCValue * collect_values, guint collect_flags)
       
   766 {
       
   767   value->data[0].v_int = collect_values[0].v_int;
       
   768   value->data[1].v_int = collect_values[1].v_int;
       
   769 
       
   770   return NULL;
       
   771 }
       
   772 
       
   773 static gchar *
       
   774 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
       
   775     GTypeCValue * collect_values, guint collect_flags)
       
   776 {
       
   777   guint32 *int_range_start = collect_values[0].v_pointer;
       
   778   guint32 *int_range_end = collect_values[1].v_pointer;
       
   779 
       
   780   if (!int_range_start)
       
   781     return g_strdup_printf ("start value location for `%s' passed as NULL",
       
   782         G_VALUE_TYPE_NAME (value));
       
   783   if (!int_range_end)
       
   784     return g_strdup_printf ("end value location for `%s' passed as NULL",
       
   785         G_VALUE_TYPE_NAME (value));
       
   786 
       
   787   *int_range_start = value->data[0].v_int;
       
   788   *int_range_end = value->data[1].v_int;
       
   789 
       
   790   return NULL;
       
   791 }
       
   792 
       
   793 /**
       
   794  * gst_value_set_int_range:
       
   795  * @value: a GValue initialized to GST_TYPE_INT_RANGE
       
   796  * @start: the start of the range
       
   797  * @end: the end of the range
       
   798  *
       
   799  * Sets @value to the range specified by @start and @end.
       
   800  */
       
   801 #ifdef __SYMBIAN32__
       
   802 EXPORT_C
       
   803 #endif
       
   804 
       
   805 void
       
   806 gst_value_set_int_range (GValue * value, gint start, gint end)
       
   807 {
       
   808   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
       
   809   g_return_if_fail (start < end);
       
   810 
       
   811   value->data[0].v_int = start;
       
   812   value->data[1].v_int = end;
       
   813 }
       
   814 
       
   815 /**
       
   816  * gst_value_get_int_range_min:
       
   817  * @value: a GValue initialized to GST_TYPE_INT_RANGE
       
   818  *
       
   819  * Gets the minimum of the range specified by @value.
       
   820  *
       
   821  * Returns: the minimum of the range
       
   822  */
       
   823 #ifdef __SYMBIAN32__
       
   824 EXPORT_C
       
   825 #endif
       
   826 
       
   827 gint
       
   828 gst_value_get_int_range_min (const GValue * value)
       
   829 {
       
   830   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
       
   831 
       
   832   return value->data[0].v_int;
       
   833 }
       
   834 
       
   835 /**
       
   836  * gst_value_get_int_range_max:
       
   837  * @value: a GValue initialized to GST_TYPE_INT_RANGE
       
   838  *
       
   839  * Gets the maximum of the range specified by @value.
       
   840  *
       
   841  * Returns: the maxumum of the range
       
   842  */
       
   843 #ifdef __SYMBIAN32__
       
   844 EXPORT_C
       
   845 #endif
       
   846 
       
   847 gint
       
   848 gst_value_get_int_range_max (const GValue * value)
       
   849 {
       
   850   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
       
   851 
       
   852   return value->data[1].v_int;
       
   853 }
       
   854 
       
   855 static void
       
   856 gst_value_transform_int_range_string (const GValue * src_value,
       
   857     GValue * dest_value)
       
   858 {
       
   859   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
       
   860       (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
       
   861 }
       
   862 
       
   863 static gint
       
   864 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
       
   865 {
       
   866   if (value2->data[0].v_int == value1->data[0].v_int &&
       
   867       value2->data[1].v_int == value1->data[1].v_int)
       
   868     return GST_VALUE_EQUAL;
       
   869   return GST_VALUE_UNORDERED;
       
   870 }
       
   871 
       
   872 static gchar *
       
   873 gst_value_serialize_int_range (const GValue * value)
       
   874 {
       
   875   return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
       
   876       value->data[1].v_int);
       
   877 }
       
   878 
       
   879 static gboolean
       
   880 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
       
   881 {
       
   882   g_warning ("unimplemented");
       
   883   return FALSE;
       
   884 }
       
   885 
       
   886 /****************
       
   887  * double range *
       
   888  ****************/
       
   889 
       
   890 static void
       
   891 gst_value_init_double_range (GValue * value)
       
   892 {
       
   893   value->data[0].v_double = 0;
       
   894   value->data[1].v_double = 0;
       
   895 }
       
   896 
       
   897 static void
       
   898 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
       
   899 {
       
   900   dest_value->data[0].v_double = src_value->data[0].v_double;
       
   901   dest_value->data[1].v_double = src_value->data[1].v_double;
       
   902 }
       
   903 
       
   904 static gchar *
       
   905 gst_value_collect_double_range (GValue * value, guint n_collect_values,
       
   906     GTypeCValue * collect_values, guint collect_flags)
       
   907 {
       
   908   value->data[0].v_double = collect_values[0].v_double;
       
   909   value->data[1].v_double = collect_values[1].v_double;
       
   910 
       
   911   return NULL;
       
   912 }
       
   913 
       
   914 static gchar *
       
   915 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
       
   916     GTypeCValue * collect_values, guint collect_flags)
       
   917 {
       
   918   gdouble *double_range_start = collect_values[0].v_pointer;
       
   919   gdouble *double_range_end = collect_values[1].v_pointer;
       
   920 
       
   921   if (!double_range_start)
       
   922     return g_strdup_printf ("start value location for `%s' passed as NULL",
       
   923         G_VALUE_TYPE_NAME (value));
       
   924   if (!double_range_end)
       
   925     return g_strdup_printf ("end value location for `%s' passed as NULL",
       
   926         G_VALUE_TYPE_NAME (value));
       
   927 
       
   928   *double_range_start = value->data[0].v_double;
       
   929   *double_range_end = value->data[1].v_double;
       
   930 
       
   931   return NULL;
       
   932 }
       
   933 
       
   934 /**
       
   935  * gst_value_set_double_range:
       
   936  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
       
   937  * @start: the start of the range
       
   938  * @end: the end of the range
       
   939  *
       
   940  * Sets @value to the range specified by @start and @end.
       
   941  */
       
   942 #ifdef __SYMBIAN32__
       
   943 EXPORT_C
       
   944 #endif
       
   945 
       
   946 void
       
   947 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
       
   948 {
       
   949   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
       
   950 
       
   951   value->data[0].v_double = start;
       
   952   value->data[1].v_double = end;
       
   953 }
       
   954 
       
   955 /**
       
   956  * gst_value_get_double_range_min:
       
   957  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
       
   958  *
       
   959  * Gets the minimum of the range specified by @value.
       
   960  *
       
   961  * Returns: the minumum of the range
       
   962  */
       
   963 #ifdef __SYMBIAN32__
       
   964 EXPORT_C
       
   965 #endif
       
   966 
       
   967 gdouble
       
   968 gst_value_get_double_range_min (const GValue * value)
       
   969 {
       
   970   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
       
   971 
       
   972   return value->data[0].v_double;
       
   973 }
       
   974 
       
   975 /**
       
   976  * gst_value_get_double_range_max:
       
   977  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
       
   978  *
       
   979  * Gets the maximum of the range specified by @value.
       
   980  *
       
   981  * Returns: the maxumum of the range
       
   982  */
       
   983 #ifdef __SYMBIAN32__
       
   984 EXPORT_C
       
   985 #endif
       
   986 
       
   987 gdouble
       
   988 gst_value_get_double_range_max (const GValue * value)
       
   989 {
       
   990   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
       
   991 
       
   992   return value->data[1].v_double;
       
   993 }
       
   994 
       
   995 static void
       
   996 gst_value_transform_double_range_string (const GValue * src_value,
       
   997     GValue * dest_value)
       
   998 {
       
   999   char s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
       
  1000 
       
  1001   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
       
  1002       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
       
  1003           src_value->data[0].v_double),
       
  1004       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
       
  1005           src_value->data[1].v_double));
       
  1006 }
       
  1007 
       
  1008 static gint
       
  1009 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
       
  1010 {
       
  1011   if (value2->data[0].v_double == value1->data[0].v_double &&
       
  1012       value2->data[0].v_double == value1->data[0].v_double)
       
  1013     return GST_VALUE_EQUAL;
       
  1014   return GST_VALUE_UNORDERED;
       
  1015 }
       
  1016 
       
  1017 static gchar *
       
  1018 gst_value_serialize_double_range (const GValue * value)
       
  1019 {
       
  1020   char d1[G_ASCII_DTOSTR_BUF_SIZE];
       
  1021   char d2[G_ASCII_DTOSTR_BUF_SIZE];
       
  1022 
       
  1023   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
       
  1024   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
       
  1025   return g_strdup_printf ("[ %s, %s ]", d1, d2);
       
  1026 }
       
  1027 
       
  1028 static gboolean
       
  1029 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
       
  1030 {
       
  1031   g_warning ("unimplemented");
       
  1032   return FALSE;
       
  1033 }
       
  1034 
       
  1035 /****************
       
  1036  * fraction range *
       
  1037  ****************/
       
  1038 
       
  1039 static void
       
  1040 gst_value_init_fraction_range (GValue * value)
       
  1041 {
       
  1042   GValue *vals;
       
  1043 
       
  1044   value->data[0].v_pointer = vals = g_new0 (GValue, 2);
       
  1045   g_value_init (&vals[0], GST_TYPE_FRACTION);
       
  1046   g_value_init (&vals[1], GST_TYPE_FRACTION);
       
  1047 }
       
  1048 
       
  1049 static void
       
  1050 gst_value_free_fraction_range (GValue * value)
       
  1051 {
       
  1052   GValue *vals = (GValue *) value->data[0].v_pointer;
       
  1053 
       
  1054   if (vals != NULL) {
       
  1055     g_value_unset (&vals[0]);
       
  1056     g_value_unset (&vals[1]);
       
  1057     g_free (vals);
       
  1058     value->data[0].v_pointer = NULL;
       
  1059   }
       
  1060 }
       
  1061 
       
  1062 static void
       
  1063 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
       
  1064 {
       
  1065   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
       
  1066   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
       
  1067 
       
  1068   if (vals == NULL) {
       
  1069     dest_value->data[0].v_pointer = vals = g_new0 (GValue, 2);
       
  1070     g_return_if_fail (vals != NULL);
       
  1071     g_value_init (&vals[0], GST_TYPE_FRACTION);
       
  1072     g_value_init (&vals[1], GST_TYPE_FRACTION);
       
  1073   }
       
  1074 
       
  1075   if (src_vals != NULL) {
       
  1076     g_value_copy (&src_vals[0], &vals[0]);
       
  1077     g_value_copy (&src_vals[1], &vals[1]);
       
  1078   }
       
  1079 }
       
  1080 
       
  1081 static gchar *
       
  1082 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
       
  1083     GTypeCValue * collect_values, guint collect_flags)
       
  1084 {
       
  1085   GValue *vals = (GValue *) value->data[0].v_pointer;
       
  1086 
       
  1087   if (n_collect_values != 4)
       
  1088     return g_strdup_printf ("not enough value locations for `%s' passed",
       
  1089         G_VALUE_TYPE_NAME (value));
       
  1090   if (vals == NULL) {
       
  1091     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
       
  1092     if (vals == NULL)
       
  1093       return g_strdup_printf ("Could not initialise`%s' during collect",
       
  1094           G_VALUE_TYPE_NAME (value));
       
  1095     g_value_init (&vals[0], GST_TYPE_FRACTION);
       
  1096     g_value_init (&vals[1], GST_TYPE_FRACTION);
       
  1097   }
       
  1098 
       
  1099   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
       
  1100       collect_values[1].v_int);
       
  1101   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
       
  1102       collect_values[3].v_int);
       
  1103 
       
  1104   return NULL;
       
  1105 }
       
  1106 
       
  1107 static gchar *
       
  1108 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
       
  1109     GTypeCValue * collect_values, guint collect_flags)
       
  1110 {
       
  1111   int i;
       
  1112   int *dest_values[4];
       
  1113   GValue *vals = (GValue *) value->data[0].v_pointer;
       
  1114 
       
  1115   if (n_collect_values != 4)
       
  1116     return g_strdup_printf ("not enough value locations for `%s' passed",
       
  1117         G_VALUE_TYPE_NAME (value));
       
  1118 
       
  1119   for (i = 0; i < 4; i++) {
       
  1120     if (collect_values[i].v_pointer == NULL) {
       
  1121       return g_strdup_printf ("value location for `%s' passed as NULL",
       
  1122           G_VALUE_TYPE_NAME (value));
       
  1123     }
       
  1124     dest_values[i] = collect_values[i].v_pointer;
       
  1125   }
       
  1126 
       
  1127   if (vals == NULL) {
       
  1128     return g_strdup_printf ("Uninitialised `%s' passed",
       
  1129         G_VALUE_TYPE_NAME (value));
       
  1130   }
       
  1131 
       
  1132   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
       
  1133   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
       
  1134   dest_values[2][0] = gst_value_get_fraction_denominator (&vals[1]);
       
  1135   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
       
  1136   return NULL;
       
  1137 }
       
  1138 
       
  1139 /**
       
  1140  * gst_value_set_fraction_range:
       
  1141  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
       
  1142  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
       
  1143  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
       
  1144  *
       
  1145  * Sets @value to the range specified by @start and @end.
       
  1146  */
       
  1147 #ifdef __SYMBIAN32__
       
  1148 EXPORT_C
       
  1149 #endif
       
  1150 
       
  1151 void
       
  1152 gst_value_set_fraction_range (GValue * value, const GValue * start,
       
  1153     const GValue * end)
       
  1154 {
       
  1155   GValue *vals;
       
  1156 
       
  1157   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
       
  1158 
       
  1159   vals = (GValue *) value->data[0].v_pointer;
       
  1160   if (vals == NULL) {
       
  1161     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
       
  1162     g_value_init (&vals[0], GST_TYPE_FRACTION);
       
  1163     g_value_init (&vals[1], GST_TYPE_FRACTION);
       
  1164   }
       
  1165 
       
  1166   g_value_copy (start, &vals[0]);
       
  1167   g_value_copy (end, &vals[1]);
       
  1168 }
       
  1169 
       
  1170 /**
       
  1171  * gst_value_set_fraction_range_full:
       
  1172  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
       
  1173  * @numerator_start: the numerator start of the range
       
  1174  * @denominator_start: the denominator start of the range
       
  1175  * @numerator_end: the numerator end of the range
       
  1176  * @denominator_end: the denominator end of the range
       
  1177  *
       
  1178  * Sets @value to the range specified by @numerator_start/@denominator_start
       
  1179  * and @numerator_end/@denominator_end.
       
  1180  */
       
  1181 #ifdef __SYMBIAN32__
       
  1182 EXPORT_C
       
  1183 #endif
       
  1184 
       
  1185 void
       
  1186 gst_value_set_fraction_range_full (GValue * value,
       
  1187     gint numerator_start, gint denominator_start,
       
  1188     gint numerator_end, gint denominator_end)
       
  1189 {
       
  1190   GValue start = { 0 };
       
  1191   GValue end = { 0 };
       
  1192 
       
  1193   g_value_init (&start, GST_TYPE_FRACTION);
       
  1194   g_value_init (&end, GST_TYPE_FRACTION);
       
  1195 
       
  1196   gst_value_set_fraction (&start, numerator_start, denominator_start);
       
  1197   gst_value_set_fraction (&end, numerator_end, denominator_end);
       
  1198   gst_value_set_fraction_range (value, &start, &end);
       
  1199 
       
  1200   g_value_unset (&start);
       
  1201   g_value_unset (&end);
       
  1202 }
       
  1203 
       
  1204 /**
       
  1205  * gst_value_get_fraction_range_min:
       
  1206  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
       
  1207  *
       
  1208  * Gets the minimum of the range specified by @value.
       
  1209  *
       
  1210  * Returns: the minumum of the range
       
  1211  */
       
  1212 #ifdef __SYMBIAN32__
       
  1213 EXPORT_C
       
  1214 #endif
       
  1215 
       
  1216 const GValue *
       
  1217 gst_value_get_fraction_range_min (const GValue * value)
       
  1218 {
       
  1219   GValue *vals;
       
  1220 
       
  1221   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
       
  1222 
       
  1223   vals = (GValue *) value->data[0].v_pointer;
       
  1224   if (vals != NULL) {
       
  1225     return &vals[0];
       
  1226   }
       
  1227 
       
  1228   return NULL;
       
  1229 }
       
  1230 
       
  1231 /**
       
  1232  * gst_value_get_fraction_range_max:
       
  1233  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
       
  1234  *
       
  1235  * Gets the maximum of the range specified by @value.
       
  1236  *
       
  1237  * Returns: the maximum of the range
       
  1238  */
       
  1239 #ifdef __SYMBIAN32__
       
  1240 EXPORT_C
       
  1241 #endif
       
  1242 
       
  1243 const GValue *
       
  1244 gst_value_get_fraction_range_max (const GValue * value)
       
  1245 {
       
  1246   GValue *vals;
       
  1247 
       
  1248   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
       
  1249 
       
  1250   vals = (GValue *) value->data[0].v_pointer;
       
  1251   if (vals != NULL) {
       
  1252     return &vals[1];
       
  1253   }
       
  1254 
       
  1255   return NULL;
       
  1256 }
       
  1257 
       
  1258 static char *
       
  1259 gst_value_serialize_fraction_range (const GValue * value)
       
  1260 {
       
  1261   GValue *vals = (GValue *) value->data[0].v_pointer;
       
  1262   gchar *retval;
       
  1263 
       
  1264   if (vals == NULL) {
       
  1265     retval = g_strdup ("[ 0/1, 0/1 ]");
       
  1266   } else {
       
  1267     gchar *start, *end;
       
  1268 
       
  1269     start = gst_value_serialize_fraction (&vals[0]);
       
  1270     end = gst_value_serialize_fraction (&vals[1]);
       
  1271 
       
  1272     retval = g_strdup_printf ("[ %s, %s ]", start, end);
       
  1273     g_free (start);
       
  1274     g_free (end);
       
  1275   }
       
  1276 
       
  1277   return retval;
       
  1278 }
       
  1279 
       
  1280 static void
       
  1281 gst_value_transform_fraction_range_string (const GValue * src_value,
       
  1282     GValue * dest_value)
       
  1283 {
       
  1284   dest_value->data[0].v_pointer =
       
  1285       gst_value_serialize_fraction_range (src_value);
       
  1286 }
       
  1287 
       
  1288 static gint
       
  1289 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
       
  1290 {
       
  1291   GValue *vals1, *vals2;
       
  1292   GstValueCompareFunc compare;
       
  1293 
       
  1294   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
       
  1295     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
       
  1296 
       
  1297   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
       
  1298     return GST_VALUE_UNORDERED;
       
  1299 
       
  1300   vals1 = (GValue *) value1->data[0].v_pointer;
       
  1301   vals2 = (GValue *) value2->data[0].v_pointer;
       
  1302   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
       
  1303     if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
       
  1304         GST_VALUE_EQUAL &&
       
  1305         gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
       
  1306         GST_VALUE_EQUAL)
       
  1307       return GST_VALUE_EQUAL;
       
  1308   }
       
  1309   return GST_VALUE_UNORDERED;
       
  1310 }
       
  1311 
       
  1312 static gboolean
       
  1313 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
       
  1314 {
       
  1315   g_warning ("unimplemented");
       
  1316   return FALSE;
       
  1317 }
       
  1318 
       
  1319 /***********
       
  1320  * GstCaps *
       
  1321  ***********/
       
  1322 
       
  1323 /**
       
  1324  * gst_value_set_caps:
       
  1325  * @value: a GValue initialized to GST_TYPE_CAPS
       
  1326  * @caps: the caps to set the value to
       
  1327  *
       
  1328  * Sets the contents of @value to @caps.  The actual
       
  1329  * #GstCaps structure is copied before it is used.
       
  1330  */
       
  1331 #ifdef __SYMBIAN32__
       
  1332 EXPORT_C
       
  1333 #endif
       
  1334 
       
  1335 void
       
  1336 gst_value_set_caps (GValue * value, const GstCaps * caps)
       
  1337 {
       
  1338   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
       
  1339 
       
  1340   g_value_set_boxed (value, caps);
       
  1341 }
       
  1342 
       
  1343 /**
       
  1344  * gst_value_get_caps:
       
  1345  * @value: a GValue initialized to GST_TYPE_CAPS
       
  1346  *
       
  1347  * Gets the contents of @value.
       
  1348  *
       
  1349  * Returns: the contents of @value
       
  1350  */
       
  1351 #ifdef __SYMBIAN32__
       
  1352 EXPORT_C
       
  1353 #endif
       
  1354 
       
  1355 const GstCaps *
       
  1356 gst_value_get_caps (const GValue * value)
       
  1357 {
       
  1358   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
       
  1359 
       
  1360   return (GstCaps *) g_value_get_boxed (value);
       
  1361 }
       
  1362 
       
  1363 static char *
       
  1364 gst_value_serialize_caps (const GValue * value)
       
  1365 {
       
  1366   GstCaps *caps = g_value_get_boxed (value);
       
  1367 
       
  1368   return gst_caps_to_string (caps);
       
  1369 }
       
  1370 
       
  1371 static gboolean
       
  1372 gst_value_deserialize_caps (GValue * dest, const gchar * s)
       
  1373 {
       
  1374   GstCaps *caps;
       
  1375 
       
  1376   caps = gst_caps_from_string (s);
       
  1377 
       
  1378   if (caps) {
       
  1379     g_value_set_boxed (dest, caps);
       
  1380     return TRUE;
       
  1381   }
       
  1382   return FALSE;
       
  1383 }
       
  1384 
       
  1385 /****************
       
  1386  * GstStructure *
       
  1387  ****************/
       
  1388 
       
  1389 /**
       
  1390  * gst_value_set_structure:
       
  1391  * @value: a GValue initialized to GST_TYPE_STRUCTURE
       
  1392  * @structure: the structure to set the value to
       
  1393  *
       
  1394  * Sets the contents of @value to @structure.  The actual
       
  1395  *
       
  1396  * Since: 0.10.15
       
  1397  */
       
  1398 #ifdef __SYMBIAN32__
       
  1399 EXPORT_C
       
  1400 #endif
       
  1401 
       
  1402 void
       
  1403 gst_value_set_structure (GValue * value, const GstStructure * structure)
       
  1404 {
       
  1405   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
       
  1406 
       
  1407   g_value_set_boxed (value, structure);
       
  1408 }
       
  1409 
       
  1410 /**
       
  1411  * gst_value_get_structure:
       
  1412  * @value: a GValue initialized to GST_TYPE_STRUCTURE
       
  1413  *
       
  1414  * Gets the contents of @value.
       
  1415  *
       
  1416  * Returns: the contents of @value
       
  1417  *
       
  1418  * Since: 0.10.15
       
  1419  */
       
  1420 #ifdef __SYMBIAN32__
       
  1421 EXPORT_C
       
  1422 #endif
       
  1423 
       
  1424 const GstStructure *
       
  1425 gst_value_get_structure (const GValue * value)
       
  1426 {
       
  1427   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
       
  1428 
       
  1429   return (GstStructure *) g_value_get_boxed (value);
       
  1430 }
       
  1431 
       
  1432 static char *
       
  1433 gst_value_serialize_structure (const GValue * value)
       
  1434 {
       
  1435   GstStructure *structure = g_value_get_boxed (value);
       
  1436 
       
  1437   return gst_structure_to_string (structure);
       
  1438 }
       
  1439 
       
  1440 static gboolean
       
  1441 gst_value_deserialize_structure (GValue * dest, const gchar * s)
       
  1442 {
       
  1443   GstStructure *structure;
       
  1444 
       
  1445   structure = gst_structure_from_string (s, NULL);
       
  1446 
       
  1447   if (structure) {
       
  1448     g_value_set_boxed (dest, structure);
       
  1449     return TRUE;
       
  1450   }
       
  1451   return FALSE;
       
  1452 }
       
  1453 
       
  1454 /*************
       
  1455  * GstBuffer *
       
  1456  *************/
       
  1457 
       
  1458 static int
       
  1459 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
       
  1460 {
       
  1461   GstBuffer *buf1 = GST_BUFFER (gst_value_get_mini_object (value1));
       
  1462   GstBuffer *buf2 = GST_BUFFER (gst_value_get_mini_object (value2));
       
  1463 
       
  1464   if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2))
       
  1465     return GST_VALUE_UNORDERED;
       
  1466   if (GST_BUFFER_SIZE (buf1) == 0)
       
  1467     return GST_VALUE_EQUAL;
       
  1468   g_assert (GST_BUFFER_DATA (buf1));
       
  1469   g_assert (GST_BUFFER_DATA (buf2));
       
  1470   if (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2),
       
  1471           GST_BUFFER_SIZE (buf1)) == 0)
       
  1472     return GST_VALUE_EQUAL;
       
  1473 
       
  1474   return GST_VALUE_UNORDERED;
       
  1475 }
       
  1476 
       
  1477 static char *
       
  1478 gst_value_serialize_buffer (const GValue * value)
       
  1479 {
       
  1480   guint8 *data;
       
  1481   int i;
       
  1482   int size;
       
  1483   char *string;
       
  1484   GstBuffer *buffer;
       
  1485 
       
  1486   buffer = gst_value_get_buffer (value);
       
  1487   if (buffer == NULL)
       
  1488     return NULL;
       
  1489 
       
  1490   data = GST_BUFFER_DATA (buffer);
       
  1491   size = GST_BUFFER_SIZE (buffer);
       
  1492 
       
  1493   string = g_malloc (size * 2 + 1);
       
  1494   for (i = 0; i < size; i++) {
       
  1495     sprintf (string + i * 2, "%02x", data[i]);
       
  1496   }
       
  1497   string[size * 2] = 0;
       
  1498 
       
  1499   return string;
       
  1500 }
       
  1501 
       
  1502 static gboolean
       
  1503 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
       
  1504 {
       
  1505   GstBuffer *buffer;
       
  1506   int len;
       
  1507   char ts[3];
       
  1508   guint8 *data;
       
  1509   int i;
       
  1510 
       
  1511   len = strlen (s);
       
  1512   if (len & 1)
       
  1513     goto wrong_length;
       
  1514 
       
  1515   buffer = gst_buffer_new_and_alloc (len / 2);
       
  1516   data = GST_BUFFER_DATA (buffer);
       
  1517   for (i = 0; i < len / 2; i++) {
       
  1518     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
       
  1519       goto wrong_char;
       
  1520 
       
  1521     ts[0] = s[i * 2 + 0];
       
  1522     ts[1] = s[i * 2 + 1];
       
  1523     ts[2] = 0;
       
  1524 
       
  1525     data[i] = (guint8) strtoul (ts, NULL, 16);
       
  1526   }
       
  1527 
       
  1528   gst_value_take_buffer (dest, buffer);
       
  1529 
       
  1530   return TRUE;
       
  1531 
       
  1532   /* ERRORS */
       
  1533 wrong_length:
       
  1534   {
       
  1535     return FALSE;
       
  1536   }
       
  1537 wrong_char:
       
  1538   {
       
  1539     gst_buffer_unref (buffer);
       
  1540     return FALSE;
       
  1541   }
       
  1542 }
       
  1543 
       
  1544 
       
  1545 /***********
       
  1546  * boolean *
       
  1547  ***********/
       
  1548 
       
  1549 static int
       
  1550 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
       
  1551 {
       
  1552   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
       
  1553     return GST_VALUE_EQUAL;
       
  1554   return GST_VALUE_UNORDERED;
       
  1555 }
       
  1556 
       
  1557 static char *
       
  1558 gst_value_serialize_boolean (const GValue * value)
       
  1559 {
       
  1560   if (value->data[0].v_int) {
       
  1561     return g_strdup ("true");
       
  1562   }
       
  1563   return g_strdup ("false");
       
  1564 }
       
  1565 
       
  1566 static gboolean
       
  1567 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
       
  1568 {
       
  1569   gboolean ret = FALSE;
       
  1570 
       
  1571   if (g_ascii_strcasecmp (s, "true") == 0 ||
       
  1572       g_ascii_strcasecmp (s, "yes") == 0 ||
       
  1573       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
       
  1574     g_value_set_boolean (dest, TRUE);
       
  1575     ret = TRUE;
       
  1576   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
       
  1577       g_ascii_strcasecmp (s, "no") == 0 ||
       
  1578       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
       
  1579     g_value_set_boolean (dest, FALSE);
       
  1580     ret = TRUE;
       
  1581   }
       
  1582 
       
  1583   return ret;
       
  1584 }
       
  1585 
       
  1586 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
       
  1587 static gint                                                             \
       
  1588 gst_value_compare_ ## _type                                             \
       
  1589 (const GValue * value1, const GValue * value2)                          \
       
  1590 {                                                                       \
       
  1591   g ## _type val1 = g_value_get_ ## _type (value1);                     \
       
  1592   g ## _type val2 = g_value_get_ ## _type (value2);                     \
       
  1593   if (val1 > val2)                                                      \
       
  1594     return GST_VALUE_GREATER_THAN;                                      \
       
  1595   if (val1 < val2)                                                      \
       
  1596     return GST_VALUE_LESS_THAN;                                         \
       
  1597   return GST_VALUE_EQUAL;                                               \
       
  1598 }                                                                       \
       
  1599                                                                         \
       
  1600 static char *                                                           \
       
  1601 gst_value_serialize_ ## _type (const GValue * value)                    \
       
  1602 {                                                                       \
       
  1603   GValue val = { 0, };                                                  \
       
  1604   g_value_init (&val, G_TYPE_STRING);                                   \
       
  1605   if (!g_value_transform (value, &val))                                 \
       
  1606     g_assert_not_reached ();                                            \
       
  1607   /* NO_COPY_MADNESS!!! */                                              \
       
  1608   return (char *) g_value_get_string (&val);                            \
       
  1609 }
       
  1610 
       
  1611 /* deserialize the given s into to as a gint64.
       
  1612  * check if the result is actually storeable in the given size number of
       
  1613  * bytes.
       
  1614  */
       
  1615 static gboolean
       
  1616 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
       
  1617     gint64 min, gint64 max, gint size)
       
  1618 {
       
  1619   gboolean ret = FALSE;
       
  1620   char *end;
       
  1621   gint64 mask = -1;
       
  1622 
       
  1623   errno = 0;
       
  1624   *to = g_ascii_strtoull (s, &end, 0);
       
  1625   /* a range error is a definitive no-no */
       
  1626   if (errno == ERANGE) {
       
  1627     return FALSE;
       
  1628   }
       
  1629 
       
  1630   if (*end == 0) {
       
  1631     ret = TRUE;
       
  1632   } else {
       
  1633     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
       
  1634       *to = G_LITTLE_ENDIAN;
       
  1635       ret = TRUE;
       
  1636     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
       
  1637       *to = G_BIG_ENDIAN;
       
  1638       ret = TRUE;
       
  1639     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
       
  1640       *to = G_BYTE_ORDER;
       
  1641       ret = TRUE;
       
  1642     } else if (g_ascii_strcasecmp (s, "min") == 0) {
       
  1643       *to = min;
       
  1644       ret = TRUE;
       
  1645     } else if (g_ascii_strcasecmp (s, "max") == 0) {
       
  1646       *to = max;
       
  1647       ret = TRUE;
       
  1648     }
       
  1649   }
       
  1650   if (ret) {
       
  1651     /* by definition, a gint64 fits into a gint64; so ignore those */
       
  1652     if (size != sizeof (mask)) {
       
  1653       if (*to >= 0) {
       
  1654         /* for positive numbers, we create a mask of 1's outside of the range
       
  1655          * and 0's inside the range.  An and will thus keep only 1 bits
       
  1656          * outside of the range */
       
  1657         mask <<= (size * 8);
       
  1658         if ((mask & *to) != 0) {
       
  1659           ret = FALSE;
       
  1660         }
       
  1661       } else {
       
  1662         /* for negative numbers, we do a 2's complement version */
       
  1663         mask <<= ((size * 8) - 1);
       
  1664         if ((mask & *to) != mask) {
       
  1665           ret = FALSE;
       
  1666         }
       
  1667       }
       
  1668     }
       
  1669   }
       
  1670   return ret;
       
  1671 }
       
  1672 
       
  1673 #define CREATE_SERIALIZATION(_type,_macro)                              \
       
  1674 CREATE_SERIALIZATION_START(_type,_macro)                                \
       
  1675                                                                         \
       
  1676 static gboolean                                                         \
       
  1677 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
       
  1678 {                                                                       \
       
  1679   gint64 x;                                                             \
       
  1680                                                                         \
       
  1681   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
       
  1682       G_MAX ## _macro, sizeof (g ## _type))) {                          \
       
  1683     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
       
  1684     return TRUE;                                                        \
       
  1685   } else {                                                              \
       
  1686     return FALSE;                                                       \
       
  1687   }                                                                     \
       
  1688 }
       
  1689 
       
  1690 #define CREATE_USERIALIZATION(_type,_macro)                             \
       
  1691 CREATE_SERIALIZATION_START(_type,_macro)                                \
       
  1692                                                                         \
       
  1693 static gboolean                                                         \
       
  1694 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
       
  1695 {                                                                       \
       
  1696   gint64 x;                                                             \
       
  1697   char *end;                                                            \
       
  1698   gboolean ret = FALSE;                                                 \
       
  1699                                                                         \
       
  1700   errno = 0;                                                            \
       
  1701   x = g_ascii_strtoull (s, &end, 0);                                    \
       
  1702   /* a range error is a definitive no-no */                             \
       
  1703   if (errno == ERANGE) {                                                \
       
  1704     return FALSE;                                                       \
       
  1705   }                                                                     \
       
  1706   /* the cast ensures the range check later on makes sense */           \
       
  1707   x = (g ## _type) x;                                                   \
       
  1708   if (*end == 0) {                                                      \
       
  1709     ret = TRUE;                                                         \
       
  1710   } else {                                                              \
       
  1711     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
       
  1712       x = G_LITTLE_ENDIAN;                                              \
       
  1713       ret = TRUE;                                                       \
       
  1714     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
       
  1715       x = G_BIG_ENDIAN;                                                 \
       
  1716       ret = TRUE;                                                       \
       
  1717     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
       
  1718       x = G_BYTE_ORDER;                                                 \
       
  1719       ret = TRUE;                                                       \
       
  1720     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
       
  1721       x = 0;                                                            \
       
  1722       ret = TRUE;                                                       \
       
  1723     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
       
  1724       x = G_MAX ## _macro;                                              \
       
  1725       ret = TRUE;                                                       \
       
  1726     }                                                                   \
       
  1727   }                                                                     \
       
  1728   if (ret) {                                                            \
       
  1729     if (x > G_MAX ## _macro) {                                          \
       
  1730       ret = FALSE;                                                      \
       
  1731     } else {                                                            \
       
  1732       g_value_set_ ## _type (dest, x);                                  \
       
  1733     }                                                                   \
       
  1734   }                                                                     \
       
  1735   return ret;                                                           \
       
  1736 }
       
  1737 
       
  1738 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
       
  1739 G_STMT_START {                                                          \
       
  1740   static const GstValueTable gst_value = {                              \
       
  1741     _gtype,                                                             \
       
  1742     gst_value_compare_ ## _type,                                        \
       
  1743     gst_value_serialize_ ## _type,                                      \
       
  1744     gst_value_deserialize_ ## _type,                                    \
       
  1745   };                                                                    \
       
  1746                                                                         \
       
  1747   gst_value_register (&gst_value);                                      \
       
  1748 } G_STMT_END
       
  1749 
       
  1750 CREATE_SERIALIZATION (int, INT);
       
  1751 CREATE_SERIALIZATION (int64, INT64);
       
  1752 CREATE_SERIALIZATION (long, LONG);
       
  1753 
       
  1754 CREATE_USERIALIZATION (uint, UINT);
       
  1755 CREATE_USERIALIZATION (uint64, UINT64);
       
  1756 CREATE_USERIALIZATION (ulong, ULONG);
       
  1757 
       
  1758 /**********
       
  1759  * double *
       
  1760  **********/
       
  1761 static int
       
  1762 gst_value_compare_double (const GValue * value1, const GValue * value2)
       
  1763 {
       
  1764   if (value1->data[0].v_double > value2->data[0].v_double)
       
  1765     return GST_VALUE_GREATER_THAN;
       
  1766   if (value1->data[0].v_double < value2->data[0].v_double)
       
  1767     return GST_VALUE_LESS_THAN;
       
  1768   if (value1->data[0].v_double == value2->data[0].v_double)
       
  1769     return GST_VALUE_EQUAL;
       
  1770   return GST_VALUE_UNORDERED;
       
  1771 }
       
  1772 
       
  1773 static char *
       
  1774 gst_value_serialize_double (const GValue * value)
       
  1775 {
       
  1776   char d[G_ASCII_DTOSTR_BUF_SIZE];
       
  1777 
       
  1778   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
       
  1779   return g_strdup (d);
       
  1780 }
       
  1781 
       
  1782 static gboolean
       
  1783 gst_value_deserialize_double (GValue * dest, const gchar * s)
       
  1784 {
       
  1785   double x;
       
  1786   gboolean ret = FALSE;
       
  1787   char *end;
       
  1788 
       
  1789   x = g_ascii_strtod (s, &end);
       
  1790   if (*end == 0) {
       
  1791     ret = TRUE;
       
  1792   } else {
       
  1793     if (g_ascii_strcasecmp (s, "min") == 0) {
       
  1794       x = -G_MAXDOUBLE;
       
  1795       ret = TRUE;
       
  1796     } else if (g_ascii_strcasecmp (s, "max") == 0) {
       
  1797       x = G_MAXDOUBLE;
       
  1798       ret = TRUE;
       
  1799     }
       
  1800   }
       
  1801   if (ret) {
       
  1802     g_value_set_double (dest, x);
       
  1803   }
       
  1804   return ret;
       
  1805 }
       
  1806 
       
  1807 /*********
       
  1808  * float *
       
  1809  *********/
       
  1810 
       
  1811 static gint
       
  1812 gst_value_compare_float (const GValue * value1, const GValue * value2)
       
  1813 {
       
  1814   if (value1->data[0].v_float > value2->data[0].v_float)
       
  1815     return GST_VALUE_GREATER_THAN;
       
  1816   if (value1->data[0].v_float < value2->data[0].v_float)
       
  1817     return GST_VALUE_LESS_THAN;
       
  1818   if (value1->data[0].v_float == value2->data[0].v_float)
       
  1819     return GST_VALUE_EQUAL;
       
  1820   return GST_VALUE_UNORDERED;
       
  1821 }
       
  1822 
       
  1823 static gchar *
       
  1824 gst_value_serialize_float (const GValue * value)
       
  1825 {
       
  1826   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
       
  1827 
       
  1828   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
       
  1829   return g_strdup (d);
       
  1830 }
       
  1831 
       
  1832 static gboolean
       
  1833 gst_value_deserialize_float (GValue * dest, const gchar * s)
       
  1834 {
       
  1835   double x;
       
  1836   gboolean ret = FALSE;
       
  1837   char *end;
       
  1838 
       
  1839   x = g_ascii_strtod (s, &end);
       
  1840   if (*end == 0) {
       
  1841     ret = TRUE;
       
  1842   } else {
       
  1843     if (g_ascii_strcasecmp (s, "min") == 0) {
       
  1844       x = -G_MAXFLOAT;
       
  1845       ret = TRUE;
       
  1846     } else if (g_ascii_strcasecmp (s, "max") == 0) {
       
  1847       x = G_MAXFLOAT;
       
  1848       ret = TRUE;
       
  1849     }
       
  1850   }
       
  1851   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
       
  1852     ret = FALSE;
       
  1853   if (ret) {
       
  1854     g_value_set_float (dest, (float) x);
       
  1855   }
       
  1856   return ret;
       
  1857 }
       
  1858 
       
  1859 /**********
       
  1860  * string *
       
  1861  **********/
       
  1862 
       
  1863 static gint
       
  1864 gst_value_compare_string (const GValue * value1, const GValue * value2)
       
  1865 {
       
  1866   int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
       
  1867 
       
  1868   if (x < 0)
       
  1869     return GST_VALUE_LESS_THAN;
       
  1870   if (x > 0)
       
  1871     return GST_VALUE_GREATER_THAN;
       
  1872   return GST_VALUE_EQUAL;
       
  1873 }
       
  1874 
       
  1875 /* keep in sync with gststructure.c */
       
  1876 #define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
       
  1877     ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
       
  1878     ((c) == '.'))
       
  1879 
       
  1880 static gchar *
       
  1881 gst_string_wrap (const gchar * s)
       
  1882 {
       
  1883   const gchar *t;
       
  1884   int len;
       
  1885   gchar *d, *e;
       
  1886   gboolean wrap = FALSE;
       
  1887 
       
  1888   len = 0;
       
  1889   t = s;
       
  1890   if (!s)
       
  1891     return NULL;
       
  1892   while (*t) {
       
  1893     if (GST_ASCII_IS_STRING (*t)) {
       
  1894       len++;
       
  1895     } else if (*t < 0x20 || *t >= 0x7f) {
       
  1896       wrap = TRUE;
       
  1897       len += 4;
       
  1898     } else {
       
  1899       wrap = TRUE;
       
  1900       len += 2;
       
  1901     }
       
  1902     t++;
       
  1903   }
       
  1904 
       
  1905   if (!wrap)
       
  1906     return g_strdup (s);
       
  1907 
       
  1908   e = d = g_malloc (len + 3);
       
  1909 
       
  1910   *e++ = '\"';
       
  1911   t = s;
       
  1912   while (*t) {
       
  1913     if (GST_ASCII_IS_STRING (*t)) {
       
  1914       *e++ = *t++;
       
  1915     } else if (*t < 0x20 || *t >= 0x7f) {
       
  1916       *e++ = '\\';
       
  1917       *e++ = '0' + ((*(guchar *) t) >> 6);
       
  1918       *e++ = '0' + (((*t) >> 3) & 0x7);
       
  1919       *e++ = '0' + ((*t++) & 0x7);
       
  1920     } else {
       
  1921       *e++ = '\\';
       
  1922       *e++ = *t++;
       
  1923     }
       
  1924   }
       
  1925   *e++ = '\"';
       
  1926   *e = 0;
       
  1927 
       
  1928   return d;
       
  1929 }
       
  1930 
       
  1931 /*
       
  1932  * This function takes a string delimited with double quotes (")
       
  1933  * and unescapes any \xxx octal numbers.
       
  1934  *
       
  1935  * If sequences of \y are found where y is not in the range of
       
  1936  * 0->3, y is copied unescaped.
       
  1937  *
       
  1938  * If \xyy is found where x is an octal number but y is not, an
       
  1939  * error is encountered and NULL is returned.
       
  1940  *
       
  1941  * the input string must be \0 terminated.
       
  1942  */
       
  1943 static gchar *
       
  1944 gst_string_unwrap (const gchar * s)
       
  1945 {
       
  1946   gchar *ret;
       
  1947   gchar *read, *write;
       
  1948 
       
  1949   /* NULL string returns NULL */
       
  1950   if (s == NULL)
       
  1951     return NULL;
       
  1952 
       
  1953   /* strings not starting with " are invalid */
       
  1954   if (*s != '"')
       
  1955     return NULL;
       
  1956 
       
  1957   /* make copy of original string to hold the result. This
       
  1958    * string will always be smaller than the original */
       
  1959   ret = g_strdup (s);
       
  1960   read = ret;
       
  1961   write = ret;
       
  1962 
       
  1963   /* need to move to the next position as we parsed the " */
       
  1964   read++;
       
  1965 
       
  1966   while (*read) {
       
  1967     if (GST_ASCII_IS_STRING (*read)) {
       
  1968       /* normal chars are just copied */
       
  1969       *write++ = *read++;
       
  1970     } else if (*read == '"') {
       
  1971       /* quote marks end of string */
       
  1972       break;
       
  1973     } else if (*read == '\\') {
       
  1974       /* got an escape char, move to next position to read a tripplet
       
  1975        * of octal numbers */
       
  1976       read++;
       
  1977       /* is the next char a possible first octal number? */
       
  1978       if (*read >= '0' && *read <= '3') {
       
  1979         /* parse other 2 numbers, if one of them is not in the range of
       
  1980          * an octal number, we error. We also catch the case where a zero
       
  1981          * byte is found here. */
       
  1982         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
       
  1983           goto beach;
       
  1984 
       
  1985         /* now convert the octal number to a byte again. */
       
  1986         *write++ = ((read[0] - '0') << 6) +
       
  1987             ((read[1] - '0') << 3) + (read[2] - '0');
       
  1988 
       
  1989         read += 3;
       
  1990       } else {
       
  1991         /* if we run into a \0 here, we definately won't get a quote later */
       
  1992         if (*read == 0)
       
  1993           goto beach;
       
  1994 
       
  1995         /* else copy \X sequence */
       
  1996         *write++ = *read++;
       
  1997       }
       
  1998     } else {
       
  1999       /* weird character, error */
       
  2000       goto beach;
       
  2001     }
       
  2002   }
       
  2003   /* if the string is not ending in " and zero terminated, we error */
       
  2004   if (*read != '"' || read[1] != '\0')
       
  2005     goto beach;
       
  2006 
       
  2007   /* null terminate result string and return */
       
  2008   *write++ = '\0';
       
  2009   return ret;
       
  2010 
       
  2011 beach:
       
  2012   g_free (ret);
       
  2013   return NULL;
       
  2014 }
       
  2015 
       
  2016 static gchar *
       
  2017 gst_value_serialize_string (const GValue * value)
       
  2018 {
       
  2019   return gst_string_wrap (value->data[0].v_pointer);
       
  2020 }
       
  2021 
       
  2022 static gboolean
       
  2023 gst_value_deserialize_string (GValue * dest, const gchar * s)
       
  2024 {
       
  2025   if (*s != '"') {
       
  2026     if (!g_utf8_validate (s, -1, NULL))
       
  2027       return FALSE;
       
  2028     g_value_set_string (dest, s);
       
  2029     return TRUE;
       
  2030   } else {
       
  2031     gchar *str = gst_string_unwrap (s);
       
  2032 
       
  2033     if (!str)
       
  2034       return FALSE;
       
  2035     g_value_take_string (dest, str);
       
  2036   }
       
  2037 
       
  2038   return TRUE;
       
  2039 }
       
  2040 
       
  2041 /********
       
  2042  * enum *
       
  2043  ********/
       
  2044 
       
  2045 static gint
       
  2046 gst_value_compare_enum (const GValue * value1, const GValue * value2)
       
  2047 {
       
  2048   GEnumValue *en1, *en2;
       
  2049   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
       
  2050   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
       
  2051 
       
  2052   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
       
  2053   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
       
  2054   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
       
  2055   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
       
  2056   g_type_class_unref (klass1);
       
  2057   g_type_class_unref (klass2);
       
  2058   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
       
  2059   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
       
  2060   if (en1->value < en2->value)
       
  2061     return GST_VALUE_LESS_THAN;
       
  2062   if (en1->value > en2->value)
       
  2063     return GST_VALUE_GREATER_THAN;
       
  2064 
       
  2065   return GST_VALUE_EQUAL;
       
  2066 }
       
  2067 
       
  2068 static gchar *
       
  2069 gst_value_serialize_enum (const GValue * value)
       
  2070 {
       
  2071   GEnumValue *en;
       
  2072   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
       
  2073 
       
  2074   g_return_val_if_fail (klass, NULL);
       
  2075   en = g_enum_get_value (klass, g_value_get_enum (value));
       
  2076   g_type_class_unref (klass);
       
  2077 
       
  2078   /* might be one of the custom formats registered later */
       
  2079   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
       
  2080     const GstFormatDefinition *format_def;
       
  2081 
       
  2082     format_def = gst_format_get_details (g_value_get_enum (value));
       
  2083     g_return_val_if_fail (format_def != NULL, NULL);
       
  2084     return g_strdup (format_def->description);
       
  2085   }
       
  2086 
       
  2087   g_return_val_if_fail (en, NULL);
       
  2088   return g_strdup (en->value_name);
       
  2089 }
       
  2090 
       
  2091 static gint
       
  2092 gst_value_deserialize_enum_iter_cmp (const GstFormatDefinition * format_def,
       
  2093     const gchar * s)
       
  2094 {
       
  2095   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
       
  2096     return 0;
       
  2097 
       
  2098   return g_ascii_strcasecmp (s, format_def->description);
       
  2099 }
       
  2100 
       
  2101 static gboolean
       
  2102 gst_value_deserialize_enum (GValue * dest, const gchar * s)
       
  2103 {
       
  2104   GEnumValue *en;
       
  2105   gchar *endptr = NULL;
       
  2106   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
       
  2107 
       
  2108   g_return_val_if_fail (klass, FALSE);
       
  2109   if (!(en = g_enum_get_value_by_name (klass, s))) {
       
  2110     if (!(en = g_enum_get_value_by_nick (klass, s))) {
       
  2111       gint i = strtol (s, &endptr, 0);
       
  2112 
       
  2113       if (endptr && *endptr == '\0') {
       
  2114         en = g_enum_get_value (klass, i);
       
  2115       }
       
  2116     }
       
  2117   }
       
  2118   g_type_class_unref (klass);
       
  2119 
       
  2120   /* might be one of the custom formats registered later */
       
  2121   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
       
  2122     const GstFormatDefinition *format_def;
       
  2123     GstIterator *iter;
       
  2124 
       
  2125     iter = gst_format_iterate_definitions ();
       
  2126 
       
  2127     format_def = gst_iterator_find_custom (iter,
       
  2128         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, (gpointer) s);
       
  2129 
       
  2130     g_return_val_if_fail (format_def != NULL, FALSE);
       
  2131     g_value_set_enum (dest, (gint) format_def->value);
       
  2132     gst_iterator_free (iter);
       
  2133     return TRUE;
       
  2134   }
       
  2135 
       
  2136   g_return_val_if_fail (en, FALSE);
       
  2137   g_value_set_enum (dest, en->value);
       
  2138   return TRUE;
       
  2139 }
       
  2140 
       
  2141 /********
       
  2142  * flags *
       
  2143  ********/
       
  2144 
       
  2145 /* we just compare the value here */
       
  2146 static gint
       
  2147 gst_value_compare_flags (const GValue * value1, const GValue * value2)
       
  2148 {
       
  2149   guint fl1, fl2;
       
  2150   GFlagsClass *klass1 =
       
  2151       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
       
  2152   GFlagsClass *klass2 =
       
  2153       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
       
  2154 
       
  2155   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
       
  2156   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
       
  2157   fl1 = g_value_get_flags (value1);
       
  2158   fl2 = g_value_get_flags (value2);
       
  2159   g_type_class_unref (klass1);
       
  2160   g_type_class_unref (klass2);
       
  2161   if (fl1 < fl2)
       
  2162     return GST_VALUE_LESS_THAN;
       
  2163   if (fl1 > fl2)
       
  2164     return GST_VALUE_GREATER_THAN;
       
  2165 
       
  2166   return GST_VALUE_EQUAL;
       
  2167 }
       
  2168 
       
  2169 /* the different flags are serialized separated with a + */
       
  2170 static gchar *
       
  2171 gst_value_serialize_flags (const GValue * value)
       
  2172 {
       
  2173   guint flags;
       
  2174   GFlagsValue *fl;
       
  2175   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
       
  2176   gchar *result, *tmp;
       
  2177   gboolean first = TRUE;
       
  2178 
       
  2179   g_return_val_if_fail (klass, NULL);
       
  2180 
       
  2181   flags = g_value_get_flags (value);
       
  2182 
       
  2183   /* if no flags are set, try to serialize to the _NONE string */
       
  2184   if (!flags) {
       
  2185     fl = g_flags_get_first_value (klass, flags);
       
  2186     return g_strdup (fl->value_name);
       
  2187   }
       
  2188 
       
  2189   /* some flags are set, so serialize one by one */
       
  2190   result = g_strdup ("");
       
  2191   while (flags) {
       
  2192     fl = g_flags_get_first_value (klass, flags);
       
  2193     if (fl != NULL) {
       
  2194       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
       
  2195       g_free (result);
       
  2196       result = tmp;
       
  2197       first = FALSE;
       
  2198 
       
  2199       /* clear flag */
       
  2200       flags &= ~fl->value;
       
  2201     }
       
  2202   }
       
  2203   g_type_class_unref (klass);
       
  2204 
       
  2205   return result;
       
  2206 }
       
  2207 
       
  2208 static gboolean
       
  2209 gst_value_deserialize_flags (GValue * dest, const gchar * s)
       
  2210 {
       
  2211   GFlagsValue *fl;
       
  2212   gchar *endptr = NULL;
       
  2213   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
       
  2214   gchar **split;
       
  2215   guint flags;
       
  2216   gint i;
       
  2217 
       
  2218   g_return_val_if_fail (klass, FALSE);
       
  2219 
       
  2220   /* split into parts delimited with + */
       
  2221   split = g_strsplit (s, "+", 0);
       
  2222 
       
  2223   flags = 0;
       
  2224   i = 0;
       
  2225   /* loop over each part */
       
  2226   while (split[i]) {
       
  2227     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
       
  2228       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
       
  2229         gint val = strtol (split[i], &endptr, 0);
       
  2230 
       
  2231         /* just or numeric value */
       
  2232         if (endptr && *endptr == '\0') {
       
  2233           flags |= val;
       
  2234         }
       
  2235       }
       
  2236     }
       
  2237     if (fl) {
       
  2238       flags |= fl->value;
       
  2239     }
       
  2240     i++;
       
  2241   }
       
  2242   g_strfreev (split);
       
  2243   g_type_class_unref (klass);
       
  2244   g_value_set_flags (dest, flags);
       
  2245 
       
  2246   return TRUE;
       
  2247 }
       
  2248 
       
  2249 /*********
       
  2250  * union *
       
  2251  *********/
       
  2252 
       
  2253 static gboolean
       
  2254 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
       
  2255     const GValue * src2)
       
  2256 {
       
  2257   if (src2->data[0].v_int <= src1->data[0].v_int &&
       
  2258       src2->data[1].v_int >= src1->data[0].v_int) {
       
  2259     gst_value_init_and_copy (dest, src2);
       
  2260     return TRUE;
       
  2261   }
       
  2262   return FALSE;
       
  2263 }
       
  2264 
       
  2265 static gboolean
       
  2266 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
       
  2267     const GValue * src2)
       
  2268 {
       
  2269   gint min;
       
  2270   gint max;
       
  2271 
       
  2272   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
       
  2273   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
       
  2274 
       
  2275   if (min <= max) {
       
  2276     g_value_init (dest, GST_TYPE_INT_RANGE);
       
  2277     gst_value_set_int_range (dest,
       
  2278         MIN (src1->data[0].v_int, src2->data[0].v_int),
       
  2279         MAX (src1->data[1].v_int, src2->data[1].v_int));
       
  2280     return TRUE;
       
  2281   }
       
  2282 
       
  2283   return FALSE;
       
  2284 }
       
  2285 
       
  2286 /****************
       
  2287  * intersection *
       
  2288  ****************/
       
  2289 
       
  2290 static gboolean
       
  2291 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
       
  2292     const GValue * src2)
       
  2293 {
       
  2294   if (src2->data[0].v_int <= src1->data[0].v_int &&
       
  2295       src2->data[1].v_int >= src1->data[0].v_int) {
       
  2296     gst_value_init_and_copy (dest, src1);
       
  2297     return TRUE;
       
  2298   }
       
  2299 
       
  2300   return FALSE;
       
  2301 }
       
  2302 
       
  2303 static gboolean
       
  2304 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
       
  2305     const GValue * src2)
       
  2306 {
       
  2307   gint min;
       
  2308   gint max;
       
  2309 
       
  2310   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
       
  2311   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
       
  2312 
       
  2313   if (min < max) {
       
  2314     g_value_init (dest, GST_TYPE_INT_RANGE);
       
  2315     gst_value_set_int_range (dest, min, max);
       
  2316     return TRUE;
       
  2317   }
       
  2318   if (min == max) {
       
  2319     g_value_init (dest, G_TYPE_INT);
       
  2320     g_value_set_int (dest, min);
       
  2321     return TRUE;
       
  2322   }
       
  2323 
       
  2324   return FALSE;
       
  2325 }
       
  2326 
       
  2327 static gboolean
       
  2328 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
       
  2329     const GValue * src2)
       
  2330 {
       
  2331   if (src2->data[0].v_double <= src1->data[0].v_double &&
       
  2332       src2->data[1].v_double >= src1->data[0].v_double) {
       
  2333     gst_value_init_and_copy (dest, src1);
       
  2334     return TRUE;
       
  2335   }
       
  2336 
       
  2337   return FALSE;
       
  2338 }
       
  2339 
       
  2340 static gboolean
       
  2341 gst_value_intersect_double_range_double_range (GValue * dest,
       
  2342     const GValue * src1, const GValue * src2)
       
  2343 {
       
  2344   gdouble min;
       
  2345   gdouble max;
       
  2346 
       
  2347   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
       
  2348   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
       
  2349 
       
  2350   if (min < max) {
       
  2351     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
       
  2352     gst_value_set_double_range (dest, min, max);
       
  2353     return TRUE;
       
  2354   }
       
  2355   if (min == max) {
       
  2356     g_value_init (dest, G_TYPE_DOUBLE);
       
  2357     g_value_set_int (dest, (int) min);
       
  2358     return TRUE;
       
  2359   }
       
  2360 
       
  2361   return FALSE;
       
  2362 }
       
  2363 
       
  2364 static gboolean
       
  2365 gst_value_intersect_list (GValue * dest, const GValue * value1,
       
  2366     const GValue * value2)
       
  2367 {
       
  2368   guint i, size;
       
  2369   GValue intersection = { 0, };
       
  2370   gboolean ret = FALSE;
       
  2371 
       
  2372   size = gst_value_list_get_size (value1);
       
  2373   for (i = 0; i < size; i++) {
       
  2374     const GValue *cur = gst_value_list_get_value (value1, i);
       
  2375 
       
  2376     if (gst_value_intersect (&intersection, cur, value2)) {
       
  2377       /* append value */
       
  2378       if (!ret) {
       
  2379         gst_value_init_and_copy (dest, &intersection);
       
  2380         ret = TRUE;
       
  2381       } else if (GST_VALUE_HOLDS_LIST (dest)) {
       
  2382         gst_value_list_append_value (dest, &intersection);
       
  2383       } else {
       
  2384         GValue temp = { 0, };
       
  2385 
       
  2386         gst_value_init_and_copy (&temp, dest);
       
  2387         g_value_unset (dest);
       
  2388         gst_value_list_concat (dest, &temp, &intersection);
       
  2389         g_value_unset (&temp);
       
  2390       }
       
  2391       g_value_unset (&intersection);
       
  2392     }
       
  2393   }
       
  2394 
       
  2395   return ret;
       
  2396 }
       
  2397 
       
  2398 static gboolean
       
  2399 gst_value_intersect_array (GValue * dest, const GValue * src1,
       
  2400     const GValue * src2)
       
  2401 {
       
  2402   guint size;
       
  2403   guint n;
       
  2404   GValue val = { 0 };
       
  2405 
       
  2406   /* only works on similar-sized arrays */
       
  2407   size = gst_value_array_get_size (src1);
       
  2408   if (size != gst_value_array_get_size (src2))
       
  2409     return FALSE;
       
  2410   g_value_init (dest, GST_TYPE_ARRAY);
       
  2411 
       
  2412   for (n = 0; n < size; n++) {
       
  2413     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
       
  2414             gst_value_array_get_value (src2, n))) {
       
  2415       g_value_unset (dest);
       
  2416       return FALSE;
       
  2417     }
       
  2418     gst_value_array_append_value (dest, &val);
       
  2419     g_value_unset (&val);
       
  2420   }
       
  2421 
       
  2422   return TRUE;
       
  2423 }
       
  2424 
       
  2425 static gboolean
       
  2426 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
       
  2427     const GValue * src2)
       
  2428 {
       
  2429   int res1, res2;
       
  2430   GValue *vals;
       
  2431   GstValueCompareFunc compare;
       
  2432 
       
  2433   vals = src2->data[0].v_pointer;
       
  2434 
       
  2435   if (vals == NULL)
       
  2436     return FALSE;
       
  2437 
       
  2438   if ((compare = gst_value_get_compare_func (src1))) {
       
  2439     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
       
  2440     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
       
  2441 
       
  2442     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
       
  2443         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
       
  2444       gst_value_init_and_copy (dest, src1);
       
  2445       return TRUE;
       
  2446     }
       
  2447   }
       
  2448 
       
  2449   return FALSE;
       
  2450 }
       
  2451 
       
  2452 static gboolean
       
  2453     gst_value_intersect_fraction_range_fraction_range
       
  2454     (GValue * dest, const GValue * src1, const GValue * src2)
       
  2455 {
       
  2456   GValue *min;
       
  2457   GValue *max;
       
  2458   int res;
       
  2459   GValue *vals1, *vals2;
       
  2460   GstValueCompareFunc compare;
       
  2461 
       
  2462   vals1 = src1->data[0].v_pointer;
       
  2463   vals2 = src2->data[0].v_pointer;
       
  2464   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
       
  2465 
       
  2466   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
       
  2467     /* min = MAX (src1.start, src2.start) */
       
  2468     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
       
  2469     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
       
  2470     if (res == GST_VALUE_LESS_THAN)
       
  2471       min = &vals2[0];          /* Take the max of the 2 */
       
  2472     else
       
  2473       min = &vals1[0];
       
  2474 
       
  2475     /* max = MIN (src1.end, src2.end) */
       
  2476     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
       
  2477     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
       
  2478     if (res == GST_VALUE_GREATER_THAN)
       
  2479       max = &vals2[1];          /* Take the min of the 2 */
       
  2480     else
       
  2481       max = &vals1[1];
       
  2482 
       
  2483     res = gst_value_compare_with_func (min, max, compare);
       
  2484     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
       
  2485     if (res == GST_VALUE_LESS_THAN) {
       
  2486       g_value_init (dest, GST_TYPE_FRACTION_RANGE);
       
  2487       vals1 = dest->data[0].v_pointer;
       
  2488       g_value_copy (min, &vals1[0]);
       
  2489       g_value_copy (max, &vals1[1]);
       
  2490       return TRUE;
       
  2491     }
       
  2492     if (res == GST_VALUE_EQUAL) {
       
  2493       gst_value_init_and_copy (dest, min);
       
  2494       return TRUE;
       
  2495     }
       
  2496   }
       
  2497 
       
  2498   return FALSE;
       
  2499 }
       
  2500 
       
  2501 /***************
       
  2502  * subtraction *
       
  2503  ***************/
       
  2504 
       
  2505 static gboolean
       
  2506 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
       
  2507     const GValue * subtrahend)
       
  2508 {
       
  2509   int min = gst_value_get_int_range_min (subtrahend);
       
  2510   int max = gst_value_get_int_range_max (subtrahend);
       
  2511   int val = g_value_get_int (minuend);
       
  2512 
       
  2513   /* subtracting a range from an int only works if the int is not in the
       
  2514    * range */
       
  2515   if (val < min || val > max) {
       
  2516     /* and the result is the int */
       
  2517     gst_value_init_and_copy (dest, minuend);
       
  2518     return TRUE;
       
  2519   }
       
  2520   return FALSE;
       
  2521 }
       
  2522 
       
  2523 /* creates a new int range based on input values.
       
  2524  */
       
  2525 static gboolean
       
  2526 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
       
  2527     gint max2)
       
  2528 {
       
  2529   GValue v1 = { 0, };
       
  2530   GValue v2 = { 0, };
       
  2531   GValue *pv1, *pv2;            /* yeah, hungarian! */
       
  2532 
       
  2533   if (min1 <= max1 && min2 <= max2) {
       
  2534     pv1 = &v1;
       
  2535     pv2 = &v2;
       
  2536   } else if (min1 <= max1) {
       
  2537     pv1 = dest;
       
  2538     pv2 = NULL;
       
  2539   } else if (min2 <= max2) {
       
  2540     pv1 = NULL;
       
  2541     pv2 = dest;
       
  2542   } else {
       
  2543     return FALSE;
       
  2544   }
       
  2545 
       
  2546   if (min1 < max1) {
       
  2547     g_value_init (pv1, GST_TYPE_INT_RANGE);
       
  2548     gst_value_set_int_range (pv1, min1, max1);
       
  2549   } else if (min1 == max1) {
       
  2550     g_value_init (pv1, G_TYPE_INT);
       
  2551     g_value_set_int (pv1, min1);
       
  2552   }
       
  2553   if (min2 < max2) {
       
  2554     g_value_init (pv2, GST_TYPE_INT_RANGE);
       
  2555     gst_value_set_int_range (pv2, min2, max2);
       
  2556   } else if (min2 == max2) {
       
  2557     g_value_init (pv2, G_TYPE_INT);
       
  2558     g_value_set_int (pv2, min2);
       
  2559   }
       
  2560 
       
  2561   if (min1 <= max1 && min2 <= max2) {
       
  2562     gst_value_list_concat (dest, pv1, pv2);
       
  2563     g_value_unset (pv1);
       
  2564     g_value_unset (pv2);
       
  2565   }
       
  2566   return TRUE;
       
  2567 }
       
  2568 
       
  2569 static gboolean
       
  2570 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
       
  2571     const GValue * subtrahend)
       
  2572 {
       
  2573   gint min = gst_value_get_int_range_min (minuend);
       
  2574   gint max = gst_value_get_int_range_max (minuend);
       
  2575   gint val = g_value_get_int (subtrahend);
       
  2576 
       
  2577   g_return_val_if_fail (min < max, FALSE);
       
  2578 
       
  2579   /* value is outside of the range, return range unchanged */
       
  2580   if (val < min || val > max) {
       
  2581     gst_value_init_and_copy (dest, minuend);
       
  2582     return TRUE;
       
  2583   } else {
       
  2584     /* max must be MAXINT too as val <= max */
       
  2585     if (val == G_MAXINT) {
       
  2586       max--;
       
  2587       val--;
       
  2588     }
       
  2589     /* min must be MININT too as val >= max */
       
  2590     if (val == G_MININT) {
       
  2591       min++;
       
  2592       val++;
       
  2593     }
       
  2594     gst_value_create_new_range (dest, min, val - 1, val + 1, max);
       
  2595   }
       
  2596   return TRUE;
       
  2597 }
       
  2598 
       
  2599 static gboolean
       
  2600 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
       
  2601     const GValue * subtrahend)
       
  2602 {
       
  2603   gint min1 = gst_value_get_int_range_min (minuend);
       
  2604   gint max1 = gst_value_get_int_range_max (minuend);
       
  2605   gint min2 = gst_value_get_int_range_min (subtrahend);
       
  2606   gint max2 = gst_value_get_int_range_max (subtrahend);
       
  2607 
       
  2608   if (max2 == G_MAXINT && min2 == G_MININT) {
       
  2609     return FALSE;
       
  2610   } else if (max2 == G_MAXINT) {
       
  2611     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
       
  2612   } else if (min2 == G_MININT) {
       
  2613     return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
       
  2614   } else {
       
  2615     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
       
  2616         MAX (max2 + 1, min1), max1);
       
  2617   }
       
  2618 }
       
  2619 
       
  2620 static gboolean
       
  2621 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
       
  2622     const GValue * subtrahend)
       
  2623 {
       
  2624   gdouble min = gst_value_get_double_range_min (subtrahend);
       
  2625   gdouble max = gst_value_get_double_range_max (subtrahend);
       
  2626   gdouble val = g_value_get_double (minuend);
       
  2627 
       
  2628   if (val < min || val > max) {
       
  2629     gst_value_init_and_copy (dest, minuend);
       
  2630     return TRUE;
       
  2631   }
       
  2632   return FALSE;
       
  2633 }
       
  2634 
       
  2635 static gboolean
       
  2636 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
       
  2637     const GValue * subtrahend)
       
  2638 {
       
  2639   /* since we don't have open ranges, we cannot create a hole in
       
  2640    * a double range. We return the original range */
       
  2641   gst_value_init_and_copy (dest, minuend);
       
  2642   return TRUE;
       
  2643 }
       
  2644 
       
  2645 static gboolean
       
  2646 gst_value_subtract_double_range_double_range (GValue * dest,
       
  2647     const GValue * minuend, const GValue * subtrahend)
       
  2648 {
       
  2649   /* since we don't have open ranges, we have to approximate */
       
  2650   /* done like with ints */
       
  2651   gdouble min1 = gst_value_get_double_range_min (minuend);
       
  2652   gdouble max2 = gst_value_get_double_range_max (minuend);
       
  2653   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
       
  2654   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
       
  2655   GValue v1 = { 0, };
       
  2656   GValue v2 = { 0, };
       
  2657   GValue *pv1, *pv2;            /* yeah, hungarian! */
       
  2658 
       
  2659   if (min1 < max1 && min2 < max2) {
       
  2660     pv1 = &v1;
       
  2661     pv2 = &v2;
       
  2662   } else if (min1 < max1) {
       
  2663     pv1 = dest;
       
  2664     pv2 = NULL;
       
  2665   } else if (min2 < max2) {
       
  2666     pv1 = NULL;
       
  2667     pv2 = dest;
       
  2668   } else {
       
  2669     return FALSE;
       
  2670   }
       
  2671 
       
  2672   if (min1 < max1) {
       
  2673     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
       
  2674     gst_value_set_double_range (pv1, min1, max1);
       
  2675   }
       
  2676   if (min2 < max2) {
       
  2677     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
       
  2678     gst_value_set_double_range (pv2, min2, max2);
       
  2679   }
       
  2680 
       
  2681   if (min1 < max1 && min2 < max2) {
       
  2682     gst_value_list_concat (dest, pv1, pv2);
       
  2683     g_value_unset (pv1);
       
  2684     g_value_unset (pv2);
       
  2685   }
       
  2686   return TRUE;
       
  2687 }
       
  2688 
       
  2689 static gboolean
       
  2690 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
       
  2691     const GValue * subtrahend)
       
  2692 {
       
  2693   guint i, size;
       
  2694   GValue subtraction = { 0, };
       
  2695   gboolean ret = FALSE;
       
  2696 
       
  2697   size = gst_value_list_get_size (minuend);
       
  2698   for (i = 0; i < size; i++) {
       
  2699     const GValue *cur = gst_value_list_get_value (minuend, i);
       
  2700 
       
  2701     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
       
  2702       if (!ret) {
       
  2703         gst_value_init_and_copy (dest, &subtraction);
       
  2704         ret = TRUE;
       
  2705       } else if (GST_VALUE_HOLDS_LIST (dest)
       
  2706           && GST_VALUE_HOLDS_LIST (&subtraction)) {
       
  2707         /* unroll */
       
  2708         GValue unroll = { 0, };
       
  2709 
       
  2710         gst_value_init_and_copy (&unroll, dest);
       
  2711         g_value_unset (dest);
       
  2712         gst_value_list_concat (dest, &unroll, &subtraction);
       
  2713       } else if (GST_VALUE_HOLDS_LIST (dest)) {
       
  2714         gst_value_list_append_value (dest, &subtraction);
       
  2715       } else {
       
  2716         GValue temp = { 0, };
       
  2717 
       
  2718         gst_value_init_and_copy (&temp, dest);
       
  2719         g_value_unset (dest);
       
  2720         gst_value_list_concat (dest, &temp, &subtraction);
       
  2721         g_value_unset (&temp);
       
  2722       }
       
  2723       g_value_unset (&subtraction);
       
  2724     }
       
  2725   }
       
  2726   return ret;
       
  2727 }
       
  2728 
       
  2729 static gboolean
       
  2730 gst_value_subtract_list (GValue * dest, const GValue * minuend,
       
  2731     const GValue * subtrahend)
       
  2732 {
       
  2733   guint i, size;
       
  2734   GValue data[2] = { {0,}, {0,} };
       
  2735   GValue *subtraction = &data[0], *result = &data[1];
       
  2736 
       
  2737   gst_value_init_and_copy (result, minuend);
       
  2738   size = gst_value_list_get_size (subtrahend);
       
  2739   for (i = 0; i < size; i++) {
       
  2740     const GValue *cur = gst_value_list_get_value (subtrahend, i);
       
  2741 
       
  2742     if (gst_value_subtract (subtraction, result, cur)) {
       
  2743       GValue *temp = result;
       
  2744 
       
  2745       result = subtraction;
       
  2746       subtraction = temp;
       
  2747       g_value_unset (subtraction);
       
  2748     } else {
       
  2749       g_value_unset (result);
       
  2750       return FALSE;
       
  2751     }
       
  2752   }
       
  2753   gst_value_init_and_copy (dest, result);
       
  2754   g_value_unset (result);
       
  2755   return TRUE;
       
  2756 }
       
  2757 
       
  2758 static gboolean
       
  2759 gst_value_subtract_fraction_fraction_range (GValue * dest,
       
  2760     const GValue * minuend, const GValue * subtrahend)
       
  2761 {
       
  2762   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
       
  2763   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
       
  2764   GstValueCompareFunc compare;
       
  2765 
       
  2766   if ((compare = gst_value_get_compare_func (minuend))) {
       
  2767     /* subtracting a range from an fraction only works if the fraction
       
  2768      * is not in the range */
       
  2769     if (gst_value_compare_with_func (minuend, min, compare) ==
       
  2770         GST_VALUE_LESS_THAN ||
       
  2771         gst_value_compare_with_func (minuend, max, compare) ==
       
  2772         GST_VALUE_GREATER_THAN) {
       
  2773       /* and the result is the value */
       
  2774       gst_value_init_and_copy (dest, minuend);
       
  2775       return TRUE;
       
  2776     }
       
  2777   }
       
  2778   return FALSE;
       
  2779 }
       
  2780 
       
  2781 static gboolean
       
  2782 gst_value_subtract_fraction_range_fraction (GValue * dest,
       
  2783     const GValue * minuend, const GValue * subtrahend)
       
  2784 {
       
  2785   /* since we don't have open ranges, we cannot create a hole in
       
  2786    * a range. We return the original range */
       
  2787   gst_value_init_and_copy (dest, minuend);
       
  2788   return TRUE;
       
  2789 }
       
  2790 
       
  2791 static gboolean
       
  2792 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
       
  2793     const GValue * minuend, const GValue * subtrahend)
       
  2794 {
       
  2795   /* since we don't have open ranges, we have to approximate */
       
  2796   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
       
  2797   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
       
  2798   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
       
  2799   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
       
  2800   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
       
  2801   int cmp1, cmp2;
       
  2802   GValue v1 = { 0, };
       
  2803   GValue v2 = { 0, };
       
  2804   GValue *pv1, *pv2;            /* yeah, hungarian! */
       
  2805   GstValueCompareFunc compare;
       
  2806 
       
  2807   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
       
  2808   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
       
  2809 
       
  2810   compare = gst_value_get_compare_func (min1);
       
  2811   g_return_val_if_fail (compare, FALSE);
       
  2812 
       
  2813   cmp1 = gst_value_compare_with_func (max2, max1, compare);
       
  2814   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
       
  2815   if (cmp1 == GST_VALUE_LESS_THAN)
       
  2816     max1 = max2;
       
  2817   cmp1 = gst_value_compare_with_func (min1, min2, compare);
       
  2818   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
       
  2819   if (cmp1 == GST_VALUE_GREATER_THAN)
       
  2820     min2 = min1;
       
  2821 
       
  2822   cmp1 = gst_value_compare_with_func (min1, max1, compare);
       
  2823   cmp2 = gst_value_compare_with_func (min2, max2, compare);
       
  2824 
       
  2825   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
       
  2826     pv1 = &v1;
       
  2827     pv2 = &v2;
       
  2828   } else if (cmp1 == GST_VALUE_LESS_THAN) {
       
  2829     pv1 = dest;
       
  2830     pv2 = NULL;
       
  2831   } else if (cmp2 == GST_VALUE_LESS_THAN) {
       
  2832     pv1 = NULL;
       
  2833     pv2 = dest;
       
  2834   } else {
       
  2835     return FALSE;
       
  2836   }
       
  2837 
       
  2838   if (cmp1 == GST_VALUE_LESS_THAN) {
       
  2839     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
       
  2840     gst_value_set_fraction_range (pv1, min1, max1);
       
  2841   }
       
  2842   if (cmp2 == GST_VALUE_LESS_THAN) {
       
  2843     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
       
  2844     gst_value_set_fraction_range (pv2, min2, max2);
       
  2845   }
       
  2846 
       
  2847   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
       
  2848     gst_value_list_concat (dest, pv1, pv2);
       
  2849     g_value_unset (pv1);
       
  2850     g_value_unset (pv2);
       
  2851   }
       
  2852   return TRUE;
       
  2853 }
       
  2854 
       
  2855 
       
  2856 /**************
       
  2857  * comparison *
       
  2858  **************/
       
  2859 
       
  2860 /**
       
  2861  * gst_value_can_compare:
       
  2862  * @value1: a value to compare
       
  2863  * @value2: another value to compare
       
  2864  *
       
  2865  * Determines if @value1 and @value2 can be compared.
       
  2866  *
       
  2867  * Returns: TRUE if the values can be compared
       
  2868  */
       
  2869 #ifdef __SYMBIAN32__
       
  2870 EXPORT_C
       
  2871 #endif
       
  2872 
       
  2873 gboolean
       
  2874 gst_value_can_compare (const GValue * value1, const GValue * value2)
       
  2875 {
       
  2876   GstValueTable *table;
       
  2877   guint i;
       
  2878 
       
  2879   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
       
  2880     return FALSE;
       
  2881 
       
  2882   for (i = 0; i < gst_value_table->len; i++) {
       
  2883     table = &g_array_index (gst_value_table, GstValueTable, i);
       
  2884     if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
       
  2885       return TRUE;
       
  2886   }
       
  2887 
       
  2888   return FALSE;
       
  2889 }
       
  2890 
       
  2891 /*
       
  2892  * gst_value_get_compare_func:
       
  2893  * @value1: a value to get the compare function for
       
  2894  *
       
  2895  * Determines the compare function to be used with values of the same type as
       
  2896  * @value1. The function can be given to gst_value_compare_with_func().
       
  2897  *
       
  2898  * Returns: A #GstValueCompareFunc value
       
  2899  */
       
  2900 static GstValueCompareFunc
       
  2901 gst_value_get_compare_func (const GValue * value1)
       
  2902 {
       
  2903   GstValueTable *table, *best = NULL;
       
  2904   guint i;
       
  2905 
       
  2906   for (i = 0; i < gst_value_table->len; i++) {
       
  2907     table = &g_array_index (gst_value_table, GstValueTable, i);
       
  2908     if (table->type == G_VALUE_TYPE (value1) && table->compare != NULL) {
       
  2909       best = table;
       
  2910       break;
       
  2911     }
       
  2912     if (g_type_is_a (G_VALUE_TYPE (value1), table->type)) {
       
  2913       if (!best || g_type_is_a (table->type, best->type))
       
  2914         best = table;
       
  2915     }
       
  2916   }
       
  2917   if (best) {
       
  2918     return best->compare;
       
  2919   }
       
  2920   return NULL;
       
  2921 }
       
  2922 
       
  2923 /**
       
  2924  * gst_value_compare:
       
  2925  * @value1: a value to compare
       
  2926  * @value2: another value to compare
       
  2927  *
       
  2928  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
       
  2929  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
       
  2930  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
       
  2931  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
       
  2932  * If the values are equal, GST_VALUE_EQUAL is returned.
       
  2933  *
       
  2934  * Returns: A #GstValueCompareType value
       
  2935  */
       
  2936 #ifdef __SYMBIAN32__
       
  2937 EXPORT_C
       
  2938 #endif 
       
  2939 gint
       
  2940 gst_value_compare (const GValue * value1, const GValue * value2)
       
  2941 {
       
  2942   GstValueCompareFunc compare;
       
  2943 
       
  2944   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
       
  2945     return GST_VALUE_UNORDERED;
       
  2946 
       
  2947   compare = gst_value_get_compare_func (value1);
       
  2948   if (compare) {
       
  2949     return compare (value1, value2);
       
  2950   }
       
  2951 
       
  2952   g_critical ("unable to compare values of type %s\n",
       
  2953       g_type_name (G_VALUE_TYPE (value1)));
       
  2954   return GST_VALUE_UNORDERED;
       
  2955 }
       
  2956 
       
  2957 /*
       
  2958  * gst_value_compare_with_func:
       
  2959  * @value1: a value to compare
       
  2960  * @value2: another value to compare
       
  2961  * @compare: compare function
       
  2962  *
       
  2963  * Compares @value1 and @value2 using the @compare function. Works like
       
  2964  * gst_value_compare() but allows to save time determining the compare function
       
  2965  * a multiple times. 
       
  2966  *
       
  2967  * Returns: A #GstValueCompareType value
       
  2968  */
       
  2969 static gint
       
  2970 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
       
  2971     GstValueCompareFunc compare)
       
  2972 {
       
  2973   g_assert (compare);
       
  2974 
       
  2975   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
       
  2976     return GST_VALUE_UNORDERED;
       
  2977 
       
  2978   return compare (value1, value2);
       
  2979 }
       
  2980 
       
  2981 /* union */
       
  2982 
       
  2983 /**
       
  2984  * gst_value_can_union:
       
  2985  * @value1: a value to union
       
  2986  * @value2: another value to union
       
  2987  *
       
  2988  * Determines if @value1 and @value2 can be non-trivially unioned.
       
  2989  * Any two values can be trivially unioned by adding both of them
       
  2990  * to a GstValueList.  However, certain types have the possibility
       
  2991  * to be unioned in a simpler way.  For example, an integer range
       
  2992  * and an integer can be unioned if the integer is a subset of the
       
  2993  * integer range.  If there is the possibility that two values can
       
  2994  * be unioned, this function returns TRUE.
       
  2995  *
       
  2996  * Returns: TRUE if there is a function allowing the two values to
       
  2997  * be unioned.
       
  2998  */
       
  2999 #ifdef __SYMBIAN32__
       
  3000 EXPORT_C
       
  3001 #endif
       
  3002 
       
  3003 gboolean
       
  3004 gst_value_can_union (const GValue * value1, const GValue * value2)
       
  3005 {
       
  3006   GstValueUnionInfo *union_info;
       
  3007   guint i;
       
  3008 
       
  3009   for (i = 0; i < gst_value_union_funcs->len; i++) {
       
  3010     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
       
  3011     if (union_info->type1 == G_VALUE_TYPE (value1) &&
       
  3012         union_info->type2 == G_VALUE_TYPE (value2))
       
  3013       return TRUE;
       
  3014     if (union_info->type1 == G_VALUE_TYPE (value2) &&
       
  3015         union_info->type2 == G_VALUE_TYPE (value1))
       
  3016       return TRUE;
       
  3017   }
       
  3018 
       
  3019   return FALSE;
       
  3020 }
       
  3021 
       
  3022 /**
       
  3023  * gst_value_union:
       
  3024  * @dest: the destination value
       
  3025  * @value1: a value to union
       
  3026  * @value2: another value to union
       
  3027  *
       
  3028  * Creates a GValue cooresponding to the union of @value1 and @value2.
       
  3029  *
       
  3030  * Returns: always returns %TRUE
       
  3031  */
       
  3032 /* FIXME: change return type to 'void'? */
       
  3033 #ifdef __SYMBIAN32__
       
  3034 EXPORT_C
       
  3035 #endif
       
  3036 
       
  3037 gboolean
       
  3038 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
       
  3039 {
       
  3040   GstValueUnionInfo *union_info;
       
  3041   guint i;
       
  3042 
       
  3043   for (i = 0; i < gst_value_union_funcs->len; i++) {
       
  3044     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
       
  3045     if (union_info->type1 == G_VALUE_TYPE (value1) &&
       
  3046         union_info->type2 == G_VALUE_TYPE (value2)) {
       
  3047       if (union_info->func (dest, value1, value2)) {
       
  3048         return TRUE;
       
  3049       }
       
  3050     }
       
  3051     if (union_info->type1 == G_VALUE_TYPE (value2) &&
       
  3052         union_info->type2 == G_VALUE_TYPE (value1)) {
       
  3053       if (union_info->func (dest, value2, value1)) {
       
  3054         return TRUE;
       
  3055       }
       
  3056     }
       
  3057   }
       
  3058 
       
  3059   gst_value_list_concat (dest, value1, value2);
       
  3060   return TRUE;
       
  3061 }
       
  3062 
       
  3063 /**
       
  3064  * gst_value_register_union_func:
       
  3065  * @type1: a type to union
       
  3066  * @type2: another type to union
       
  3067  * @func: a function that implments creating a union between the two types
       
  3068  *
       
  3069  * Registers a union function that can create a union between GValues
       
  3070  * of the type @type1 and @type2.
       
  3071  *
       
  3072  * Union functions should be registered at startup before any pipelines are
       
  3073  * started, as gst_value_register_union_func() is not thread-safe and cannot
       
  3074  * be used at the same time as gst_value_union() or gst_value_can_union().
       
  3075  */
       
  3076 #ifdef __SYMBIAN32__
       
  3077 EXPORT_C
       
  3078 #endif
       
  3079 
       
  3080 void
       
  3081 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
       
  3082 {
       
  3083   GstValueUnionInfo union_info;
       
  3084 
       
  3085   union_info.type1 = type1;
       
  3086   union_info.type2 = type2;
       
  3087   union_info.func = func;
       
  3088 
       
  3089   g_array_append_val (gst_value_union_funcs, union_info);
       
  3090 }
       
  3091 
       
  3092 /* intersection */
       
  3093 
       
  3094 /**
       
  3095  * gst_value_can_intersect:
       
  3096  * @value1: a value to intersect
       
  3097  * @value2: another value to intersect
       
  3098  *
       
  3099  * Determines if intersecting two values will produce a valid result.
       
  3100  * Two values will produce a valid intersection if they have the same
       
  3101  * type, or if there is a method (registered by
       
  3102  * gst_value_register_intersection_func()) to calculate the intersection.
       
  3103  *
       
  3104  * Returns: TRUE if the values can intersect
       
  3105  */
       
  3106 #ifdef __SYMBIAN32__
       
  3107 EXPORT_C
       
  3108 #endif
       
  3109 
       
  3110 gboolean
       
  3111 gst_value_can_intersect (const GValue * value1, const GValue * value2)
       
  3112 {
       
  3113   GstValueIntersectInfo *intersect_info;
       
  3114   guint i;
       
  3115 
       
  3116   /* special cases */
       
  3117   if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
       
  3118     return TRUE;
       
  3119 
       
  3120   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
       
  3121     intersect_info = &g_array_index (gst_value_intersect_funcs,
       
  3122         GstValueIntersectInfo, i);
       
  3123     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
       
  3124         intersect_info->type2 == G_VALUE_TYPE (value2))
       
  3125       if (intersect_info->type2 == G_VALUE_TYPE (value1) &&
       
  3126           intersect_info->type1 == G_VALUE_TYPE (value2))
       
  3127         return TRUE;
       
  3128   }
       
  3129 
       
  3130   return gst_value_can_compare (value1, value2);
       
  3131 }
       
  3132 
       
  3133 /**
       
  3134  * gst_value_intersect:
       
  3135  * @dest: a uninitialized #GValue that will hold the calculated
       
  3136  * intersection value
       
  3137  * @value1: a value to intersect
       
  3138  * @value2: another value to intersect
       
  3139  *
       
  3140  * Calculates the intersection of two values.  If the values have
       
  3141  * a non-empty intersection, the value representing the intersection
       
  3142  * is placed in @dest.  If the intersection is non-empty, @dest is
       
  3143  * not modified.
       
  3144  *
       
  3145  * Returns: TRUE if the intersection is non-empty
       
  3146  */
       
  3147 #ifdef __SYMBIAN32__
       
  3148 EXPORT_C
       
  3149 #endif
       
  3150 
       
  3151 gboolean
       
  3152 gst_value_intersect (GValue * dest, const GValue * value1,
       
  3153     const GValue * value2)
       
  3154 {
       
  3155   GstValueIntersectInfo *intersect_info;
       
  3156   guint i;
       
  3157   gboolean ret = FALSE;
       
  3158 
       
  3159   /* special cases first */
       
  3160   if (GST_VALUE_HOLDS_LIST (value1))
       
  3161     return gst_value_intersect_list (dest, value1, value2);
       
  3162   if (GST_VALUE_HOLDS_LIST (value2))
       
  3163     return gst_value_intersect_list (dest, value2, value1);
       
  3164 
       
  3165   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
       
  3166     intersect_info = &g_array_index (gst_value_intersect_funcs,
       
  3167         GstValueIntersectInfo, i);
       
  3168     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
       
  3169         intersect_info->type2 == G_VALUE_TYPE (value2)) {
       
  3170       ret = intersect_info->func (dest, value1, value2);
       
  3171       return ret;
       
  3172     }
       
  3173     if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
       
  3174         intersect_info->type2 == G_VALUE_TYPE (value1)) {
       
  3175       ret = intersect_info->func (dest, value2, value1);
       
  3176       return ret;
       
  3177     }
       
  3178   }
       
  3179 
       
  3180   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
       
  3181     gst_value_init_and_copy (dest, value1);
       
  3182     ret = TRUE;
       
  3183   }
       
  3184 
       
  3185   return ret;
       
  3186 }
       
  3187 
       
  3188 /**
       
  3189  * gst_value_register_intersect_func:
       
  3190  * @type1: the first type to intersect
       
  3191  * @type2: the second type to intersect
       
  3192  * @func: the intersection function
       
  3193  *
       
  3194  * Registers a function that is called to calculate the intersection
       
  3195  * of the values having the types @type1 and @type2.
       
  3196  *
       
  3197  * Intersect functions should be registered at startup before any pipelines are
       
  3198  * started, as gst_value_register_intersect_func() is not thread-safe and
       
  3199  * cannot be used at the same time as gst_value_intersect() or
       
  3200  * gst_value_can_intersect().
       
  3201  */
       
  3202 #ifdef __SYMBIAN32__
       
  3203 EXPORT_C
       
  3204 #endif
       
  3205 
       
  3206 void
       
  3207 gst_value_register_intersect_func (GType type1, GType type2,
       
  3208     GstValueIntersectFunc func)
       
  3209 {
       
  3210   GstValueIntersectInfo intersect_info;
       
  3211 
       
  3212   intersect_info.type1 = type1;
       
  3213   intersect_info.type2 = type2;
       
  3214   intersect_info.func = func;
       
  3215 
       
  3216   g_array_append_val (gst_value_intersect_funcs, intersect_info);
       
  3217 }
       
  3218 
       
  3219 
       
  3220 /* subtraction */
       
  3221 
       
  3222 /**
       
  3223  * gst_value_subtract:
       
  3224  * @dest: the destination value for the result if the subtraction is not empty
       
  3225  * @minuend: the value to subtract from
       
  3226  * @subtrahend: the value to subtract
       
  3227  *
       
  3228  * Subtracts @subtrahend from @minuend and stores the result in @dest.
       
  3229  * Note that this means subtraction as in sets, not as in mathematics.
       
  3230  *
       
  3231  * Returns: %TRUE if the subtraction is not empty
       
  3232  */
       
  3233 #ifdef __SYMBIAN32__
       
  3234 EXPORT_C
       
  3235 #endif
       
  3236 
       
  3237 gboolean
       
  3238 gst_value_subtract (GValue * dest, const GValue * minuend,
       
  3239     const GValue * subtrahend)
       
  3240 {
       
  3241   GstValueSubtractInfo *info;
       
  3242   guint i;
       
  3243 
       
  3244   /* special cases first */
       
  3245   if (GST_VALUE_HOLDS_LIST (minuend))
       
  3246     return gst_value_subtract_from_list (dest, minuend, subtrahend);
       
  3247   if (GST_VALUE_HOLDS_LIST (subtrahend))
       
  3248     return gst_value_subtract_list (dest, minuend, subtrahend);
       
  3249 
       
  3250   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
       
  3251     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
       
  3252     if (info->minuend == G_VALUE_TYPE (minuend) &&
       
  3253         info->subtrahend == G_VALUE_TYPE (subtrahend)) {
       
  3254       return info->func (dest, minuend, subtrahend);
       
  3255     }
       
  3256   }
       
  3257 
       
  3258   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
       
  3259     gst_value_init_and_copy (dest, minuend);
       
  3260     return TRUE;
       
  3261   }
       
  3262 
       
  3263   return FALSE;
       
  3264 }
       
  3265 
       
  3266 #if 0
       
  3267 gboolean
       
  3268 gst_value_subtract (GValue * dest, const GValue * minuend,
       
  3269     const GValue * subtrahend)
       
  3270 {
       
  3271   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
       
  3272 
       
  3273   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
       
  3274       gst_value_serialize (subtrahend),
       
  3275       ret ? gst_value_serialize (dest) : "---");
       
  3276   return ret;
       
  3277 }
       
  3278 #endif
       
  3279 
       
  3280 /**
       
  3281  * gst_value_can_subtract:
       
  3282  * @minuend: the value to subtract from
       
  3283  * @subtrahend: the value to subtract
       
  3284  *
       
  3285  * Checks if it's possible to subtract @subtrahend from @minuend.
       
  3286  *
       
  3287  * Returns: TRUE if a subtraction is possible
       
  3288  */
       
  3289 #ifdef __SYMBIAN32__
       
  3290 EXPORT_C
       
  3291 #endif
       
  3292 
       
  3293 gboolean
       
  3294 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
       
  3295 {
       
  3296   GstValueSubtractInfo *info;
       
  3297   guint i;
       
  3298 
       
  3299   /* special cases */
       
  3300   if (GST_VALUE_HOLDS_LIST (minuend) || GST_VALUE_HOLDS_LIST (subtrahend))
       
  3301     return TRUE;
       
  3302 
       
  3303   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
       
  3304     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
       
  3305     if (info->minuend == G_VALUE_TYPE (minuend) &&
       
  3306         info->subtrahend == G_VALUE_TYPE (subtrahend))
       
  3307       return TRUE;
       
  3308   }
       
  3309 
       
  3310   return gst_value_can_compare (minuend, subtrahend);
       
  3311 }
       
  3312 
       
  3313 /**
       
  3314  * gst_value_register_subtract_func:
       
  3315  * @minuend_type: type of the minuend
       
  3316  * @subtrahend_type: type of the subtrahend
       
  3317  * @func: function to use
       
  3318  *
       
  3319  * Registers @func as a function capable of subtracting the values of
       
  3320  * @subtrahend_type from values of @minuend_type.
       
  3321  *
       
  3322  * Subtract functions should be registered at startup before any pipelines are
       
  3323  * started, as gst_value_register_subtract_func() is not thread-safe and
       
  3324  * cannot be used at the same time as gst_value_subtract().
       
  3325  */
       
  3326 #ifdef __SYMBIAN32__
       
  3327 EXPORT_C
       
  3328 #endif
       
  3329 
       
  3330 void
       
  3331 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
       
  3332     GstValueSubtractFunc func)
       
  3333 {
       
  3334   GstValueSubtractInfo info;
       
  3335 
       
  3336   /* one type must be unfixed, other subtractions can be done as comparisons */
       
  3337   g_return_if_fail (!gst_type_is_fixed (minuend_type)
       
  3338       || !gst_type_is_fixed (subtrahend_type));
       
  3339 
       
  3340   info.minuend = minuend_type;
       
  3341   info.subtrahend = subtrahend_type;
       
  3342   info.func = func;
       
  3343 
       
  3344   g_array_append_val (gst_value_subtract_funcs, info);
       
  3345 }
       
  3346 
       
  3347 /**
       
  3348  * gst_value_register:
       
  3349  * @table: structure containing functions to register
       
  3350  *
       
  3351  * Registers functions to perform calculations on #GValues of a given
       
  3352  * type.
       
  3353  */
       
  3354 #ifdef __SYMBIAN32__
       
  3355 EXPORT_C
       
  3356 #endif
       
  3357 
       
  3358 void
       
  3359 gst_value_register (const GstValueTable * table)
       
  3360 {
       
  3361   g_array_append_val (gst_value_table, *table);
       
  3362 }
       
  3363 
       
  3364 /**
       
  3365  * gst_value_init_and_copy:
       
  3366  * @dest: the target value
       
  3367  * @src: the source value
       
  3368  *
       
  3369  * Initialises the target value to be of the same type as source and then copies
       
  3370  * the contents from source to target.
       
  3371  */
       
  3372 #ifdef __SYMBIAN32__
       
  3373 EXPORT_C
       
  3374 #endif
       
  3375 
       
  3376 void
       
  3377 gst_value_init_and_copy (GValue * dest, const GValue * src)
       
  3378 {
       
  3379   g_value_init (dest, G_VALUE_TYPE (src));
       
  3380   g_value_copy (src, dest);
       
  3381 }
       
  3382 
       
  3383 /**
       
  3384  * gst_value_serialize:
       
  3385  * @value: a #GValue to serialize
       
  3386  *
       
  3387  * tries to transform the given @value into a string representation that allows
       
  3388  * getting back this string later on using gst_value_deserialize().
       
  3389  *
       
  3390  * Returns: the serialization for @value or NULL if none exists
       
  3391  */
       
  3392 #ifdef __SYMBIAN32__
       
  3393 EXPORT_C
       
  3394 #endif
       
  3395 
       
  3396 gchar *
       
  3397 gst_value_serialize (const GValue * value)
       
  3398 {
       
  3399   guint i;
       
  3400   GValue s_val = { 0 };
       
  3401   GstValueTable *table, *best = NULL;
       
  3402   char *s;
       
  3403 
       
  3404   g_return_val_if_fail (G_IS_VALUE (value), NULL);
       
  3405 
       
  3406   for (i = 0; i < gst_value_table->len; i++) {
       
  3407     table = &g_array_index (gst_value_table, GstValueTable, i);
       
  3408     if (table->serialize == NULL)
       
  3409       continue;
       
  3410     if (table->type == G_VALUE_TYPE (value)) {
       
  3411       best = table;
       
  3412       break;
       
  3413     }
       
  3414     if (g_type_is_a (G_VALUE_TYPE (value), table->type)) {
       
  3415       if (!best || g_type_is_a (table->type, best->type))
       
  3416         best = table;
       
  3417     }
       
  3418   }
       
  3419   if (best)
       
  3420     return best->serialize (value);
       
  3421 
       
  3422   g_value_init (&s_val, G_TYPE_STRING);
       
  3423   if (g_value_transform (value, &s_val)) {
       
  3424     s = gst_string_wrap (g_value_get_string (&s_val));
       
  3425   } else {
       
  3426     s = NULL;
       
  3427   }
       
  3428   g_value_unset (&s_val);
       
  3429 
       
  3430   return s;
       
  3431 }
       
  3432 
       
  3433 /**
       
  3434  * gst_value_deserialize:
       
  3435  * @dest: #GValue to fill with contents of deserialization
       
  3436  * @src: string to deserialize
       
  3437  *
       
  3438  * Tries to deserialize a string into the type specified by the given GValue.
       
  3439  * If the operation succeeds, TRUE is returned, FALSE otherwise.
       
  3440  *
       
  3441  * Returns: TRUE on success
       
  3442  */
       
  3443 #ifdef __SYMBIAN32__
       
  3444 EXPORT_C
       
  3445 #endif
       
  3446 
       
  3447 gboolean
       
  3448 gst_value_deserialize (GValue * dest, const gchar * src)
       
  3449 {
       
  3450   GstValueTable *table, *best = NULL;
       
  3451   guint i;
       
  3452 
       
  3453   g_return_val_if_fail (src != NULL, FALSE);
       
  3454   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
       
  3455 
       
  3456   for (i = 0; i < gst_value_table->len; i++) {
       
  3457     table = &g_array_index (gst_value_table, GstValueTable, i);
       
  3458     if (table->serialize == NULL)
       
  3459       continue;
       
  3460 
       
  3461     if (table->type == G_VALUE_TYPE (dest)) {
       
  3462       best = table;
       
  3463       break;
       
  3464     }
       
  3465 
       
  3466     if (g_type_is_a (G_VALUE_TYPE (dest), table->type)) {
       
  3467       if (!best || g_type_is_a (table->type, best->type))
       
  3468         best = table;
       
  3469     }
       
  3470   }
       
  3471   if (best) {
       
  3472     return best->deserialize (dest, src);
       
  3473   }
       
  3474 
       
  3475   return FALSE;
       
  3476 }
       
  3477 
       
  3478 /**
       
  3479  * gst_value_is_fixed:
       
  3480  * @value: the #GValue to check
       
  3481  *
       
  3482  * Tests if the given GValue, if available in a GstStructure (or any other
       
  3483  * container) contains a "fixed" (which means: one value) or an "unfixed"
       
  3484  * (which means: multiple possible values, such as data lists or data
       
  3485  * ranges) value.
       
  3486  *
       
  3487  * Returns: true if the value is "fixed".
       
  3488  */
       
  3489 #ifdef __SYMBIAN32__
       
  3490 EXPORT_C
       
  3491 #endif
       
  3492 
       
  3493 
       
  3494 gboolean
       
  3495 gst_value_is_fixed (const GValue * value)
       
  3496 {
       
  3497   GType type = G_VALUE_TYPE (value);
       
  3498 
       
  3499   if (type == GST_TYPE_ARRAY) {
       
  3500     gint size, n;
       
  3501     const GValue *kid;
       
  3502 
       
  3503     /* check recursively */
       
  3504     size = gst_value_array_get_size (value);
       
  3505     for (n = 0; n < size; n++) {
       
  3506       kid = gst_value_array_get_value (value, n);
       
  3507       if (!gst_value_is_fixed (kid))
       
  3508         return FALSE;
       
  3509     }
       
  3510     return TRUE;
       
  3511   }
       
  3512 
       
  3513   return gst_type_is_fixed (type);
       
  3514 }
       
  3515 
       
  3516 /************
       
  3517  * fraction *
       
  3518  ************/
       
  3519 
       
  3520 /* helper functions */
       
  3521 
       
  3522 /* Finds the greatest common divisor.
       
  3523  * Returns 1 if none other found.
       
  3524  * This is Euclid's algorithm. */
       
  3525 static gint
       
  3526 gst_greatest_common_divisor (gint a, gint b)
       
  3527 {
       
  3528   while (b != 0) {
       
  3529     int temp = a;
       
  3530 
       
  3531     a = b;
       
  3532     b = temp % b;
       
  3533   }
       
  3534 
       
  3535   return ABS (a);
       
  3536 }
       
  3537 
       
  3538 static void
       
  3539 gst_value_init_fraction (GValue * value)
       
  3540 {
       
  3541   value->data[0].v_int = 0;
       
  3542   value->data[1].v_int = 1;
       
  3543 }
       
  3544 
       
  3545 static void
       
  3546 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
       
  3547 {
       
  3548   dest_value->data[0].v_int = src_value->data[0].v_int;
       
  3549   dest_value->data[1].v_int = src_value->data[1].v_int;
       
  3550 }
       
  3551 
       
  3552 static gchar *
       
  3553 gst_value_collect_fraction (GValue * value, guint n_collect_values,
       
  3554     GTypeCValue * collect_values, guint collect_flags)
       
  3555 {
       
  3556   gst_value_set_fraction (value,
       
  3557       collect_values[0].v_int, collect_values[1].v_int);
       
  3558 
       
  3559   return NULL;
       
  3560 }
       
  3561 
       
  3562 static gchar *
       
  3563 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
       
  3564     GTypeCValue * collect_values, guint collect_flags)
       
  3565 {
       
  3566   gint *numerator = collect_values[0].v_pointer;
       
  3567   gint *denominator = collect_values[1].v_pointer;
       
  3568 
       
  3569   if (!numerator)
       
  3570     return g_strdup_printf ("numerator for `%s' passed as NULL",
       
  3571         G_VALUE_TYPE_NAME (value));
       
  3572   if (!denominator)
       
  3573     return g_strdup_printf ("denominator for `%s' passed as NULL",
       
  3574         G_VALUE_TYPE_NAME (value));
       
  3575 
       
  3576   *numerator = value->data[0].v_int;
       
  3577   *denominator = value->data[1].v_int;
       
  3578 
       
  3579   return NULL;
       
  3580 }
       
  3581 
       
  3582 /**
       
  3583  * gst_value_set_fraction:
       
  3584  * @value: a GValue initialized to #GST_TYPE_FRACTION
       
  3585  * @numerator: the numerator of the fraction
       
  3586  * @denominator: the denominator of the fraction
       
  3587  *
       
  3588  * Sets @value to the fraction specified by @numerator over @denominator.
       
  3589  * The fraction gets reduced to the smallest numerator and denominator,
       
  3590  * and if necessary the sign is moved to the numerator.
       
  3591  */
       
  3592 #ifdef __SYMBIAN32__
       
  3593 EXPORT_C
       
  3594 #endif
       
  3595 
       
  3596 void
       
  3597 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
       
  3598 {
       
  3599   gint gcd = 0;
       
  3600 
       
  3601   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
       
  3602   g_return_if_fail (denominator != 0);
       
  3603   g_return_if_fail (denominator >= -G_MAXINT);
       
  3604   g_return_if_fail (numerator >= -G_MAXINT);
       
  3605 
       
  3606   /* normalize sign */
       
  3607   if (denominator < 0) {
       
  3608     numerator = -numerator;
       
  3609     denominator = -denominator;
       
  3610   }
       
  3611 
       
  3612   /* check for reduction */
       
  3613   gcd = gst_greatest_common_divisor (numerator, denominator);
       
  3614   if (gcd) {
       
  3615     numerator /= gcd;
       
  3616     denominator /= gcd;
       
  3617   }
       
  3618 
       
  3619   g_assert (denominator > 0);
       
  3620 
       
  3621   value->data[0].v_int = numerator;
       
  3622   value->data[1].v_int = denominator;
       
  3623 }
       
  3624 
       
  3625 /**
       
  3626  * gst_value_get_fraction_numerator:
       
  3627  * @value: a GValue initialized to #GST_TYPE_FRACTION
       
  3628  *
       
  3629  * Gets the numerator of the fraction specified by @value.
       
  3630  *
       
  3631  * Returns: the numerator of the fraction.
       
  3632  */
       
  3633 #ifdef __SYMBIAN32__
       
  3634 EXPORT_C
       
  3635 #endif
       
  3636 
       
  3637 gint
       
  3638 gst_value_get_fraction_numerator (const GValue * value)
       
  3639 {
       
  3640   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
       
  3641 
       
  3642   return value->data[0].v_int;
       
  3643 }
       
  3644 
       
  3645 /**
       
  3646  * gst_value_get_fraction_denominator:
       
  3647  * @value: a GValue initialized to #GST_TYPE_FRACTION
       
  3648  *
       
  3649  * Gets the denominator of the fraction specified by @value.
       
  3650  *
       
  3651  * Returns: the denominator of the fraction.
       
  3652  */
       
  3653 #ifdef __SYMBIAN32__
       
  3654 EXPORT_C
       
  3655 #endif
       
  3656 
       
  3657 gint
       
  3658 gst_value_get_fraction_denominator (const GValue * value)
       
  3659 {
       
  3660   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
       
  3661 
       
  3662   return value->data[1].v_int;
       
  3663 }
       
  3664 
       
  3665 /**
       
  3666  * gst_value_fraction_multiply:
       
  3667  * @product: a GValue initialized to #GST_TYPE_FRACTION
       
  3668  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
       
  3669  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
       
  3670  *
       
  3671  * Multiplies the two GValues containing a GstFraction and sets @product
       
  3672  * to the product of the two fractions.
       
  3673  *
       
  3674  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
       
  3675  */
       
  3676 #ifdef __SYMBIAN32__
       
  3677 EXPORT_C
       
  3678 #endif
       
  3679 
       
  3680 gboolean
       
  3681 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
       
  3682     const GValue * factor2)
       
  3683 {
       
  3684   gint gcd, n1, n2, d1, d2;
       
  3685 
       
  3686   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
       
  3687   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
       
  3688 
       
  3689   n1 = factor1->data[0].v_int;
       
  3690   n2 = factor2->data[0].v_int;
       
  3691   d1 = factor1->data[1].v_int;
       
  3692   d2 = factor2->data[1].v_int;
       
  3693 
       
  3694   gcd = gst_greatest_common_divisor (n1, d2);
       
  3695   n1 /= gcd;
       
  3696   d2 /= gcd;
       
  3697   gcd = gst_greatest_common_divisor (n2, d1);
       
  3698   n2 /= gcd;
       
  3699   d1 /= gcd;
       
  3700 
       
  3701   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (n2), FALSE);
       
  3702   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
       
  3703 
       
  3704   gst_value_set_fraction (product, n1 * n2, d1 * d2);
       
  3705 
       
  3706   return TRUE;
       
  3707 }
       
  3708 
       
  3709 /**
       
  3710  * gst_value_fraction_subtract:
       
  3711  * @dest: a GValue initialized to #GST_TYPE_FRACTION
       
  3712  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
       
  3713  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
       
  3714  *
       
  3715  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
       
  3716  *
       
  3717  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
       
  3718  */
       
  3719 #ifdef __SYMBIAN32__
       
  3720 EXPORT_C
       
  3721 #endif
       
  3722 
       
  3723 gboolean
       
  3724 gst_value_fraction_subtract (GValue * dest,
       
  3725     const GValue * minuend, const GValue * subtrahend)
       
  3726 {
       
  3727   gint n1, n2, d1, d2;
       
  3728 
       
  3729   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
       
  3730   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
       
  3731 
       
  3732   n1 = minuend->data[0].v_int;
       
  3733   n2 = subtrahend->data[0].v_int;
       
  3734   d1 = minuend->data[1].v_int;
       
  3735   d2 = subtrahend->data[1].v_int;
       
  3736 
       
  3737   if (n1 == 0) {
       
  3738     gst_value_set_fraction (dest, -n2, d2);
       
  3739     return TRUE;
       
  3740   }
       
  3741   if (n2 == 0) {
       
  3742     gst_value_set_fraction (dest, n1, d1);
       
  3743     return TRUE;
       
  3744   }
       
  3745 
       
  3746   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (d2), FALSE);
       
  3747   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (n2), FALSE);
       
  3748   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
       
  3749 
       
  3750   gst_value_set_fraction (dest, (n1 * d2) - (n2 * d1), d1 * d2);
       
  3751 
       
  3752   return TRUE;
       
  3753 }
       
  3754 
       
  3755 static gchar *
       
  3756 gst_value_serialize_fraction (const GValue * value)
       
  3757 {
       
  3758   gint32 numerator = value->data[0].v_int;
       
  3759   gint32 denominator = value->data[1].v_int;
       
  3760   gboolean positive = TRUE;
       
  3761 
       
  3762   /* get the sign and make components absolute */
       
  3763   if (numerator < 0) {
       
  3764     numerator = -numerator;
       
  3765     positive = !positive;
       
  3766   }
       
  3767   if (denominator < 0) {
       
  3768     denominator = -denominator;
       
  3769     positive = !positive;
       
  3770   }
       
  3771 
       
  3772   return g_strdup_printf ("%s%d/%d",
       
  3773       positive ? "" : "-", numerator, denominator);
       
  3774 }
       
  3775 
       
  3776 static gboolean
       
  3777 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
       
  3778 {
       
  3779   gint num, den;
       
  3780 
       
  3781   if (G_UNLIKELY (s == NULL))
       
  3782     return FALSE;
       
  3783 
       
  3784   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
       
  3785     return FALSE;
       
  3786 
       
  3787   if (sscanf (s, "%d/%d", &num, &den) == 2) {
       
  3788     gst_value_set_fraction (dest, num, den);
       
  3789     return TRUE;
       
  3790   }
       
  3791   if (sscanf (s, "%d", &num) == 1) {
       
  3792     gst_value_set_fraction (dest, num, 1);
       
  3793     return TRUE;
       
  3794   }
       
  3795   if (g_ascii_strcasecmp (s, "min") == 0) {
       
  3796     gst_value_set_fraction (dest, -G_MAXINT, 1);
       
  3797     return TRUE;
       
  3798   } else if (g_ascii_strcasecmp (s, "max") == 0) {
       
  3799     gst_value_set_fraction (dest, G_MAXINT, 1);
       
  3800     return TRUE;
       
  3801   }
       
  3802 
       
  3803   return FALSE;
       
  3804 }
       
  3805 
       
  3806 static void
       
  3807 gst_value_transform_fraction_string (const GValue * src_value,
       
  3808     GValue * dest_value)
       
  3809 {
       
  3810   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
       
  3811 }
       
  3812 
       
  3813 static void
       
  3814 gst_value_transform_string_fraction (const GValue * src_value,
       
  3815     GValue * dest_value)
       
  3816 {
       
  3817   if (!gst_value_deserialize_fraction (dest_value,
       
  3818           src_value->data[0].v_pointer))
       
  3819     /* If the deserialize fails, ensure we leave the fraction in a
       
  3820      * valid, if incorrect, state */
       
  3821     gst_value_set_fraction (dest_value, 0, 1);
       
  3822 }
       
  3823 
       
  3824 #define MAX_TERMS       30
       
  3825 #define MIN_DIVISOR     1.0e-10
       
  3826 #define MAX_ERROR       1.0e-20
       
  3827 
       
  3828 /* use continued fractions to transform a double into a fraction,
       
  3829  * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
       
  3830  * This algorithm takes care of overflows.
       
  3831  */
       
  3832 static void
       
  3833 gst_value_transform_double_fraction (const GValue * src_value,
       
  3834     GValue * dest_value)
       
  3835 {
       
  3836   gdouble V, F;                 /* double being converted */
       
  3837   gint N, D;                    /* will contain the result */
       
  3838   gint A;                       /* current term in continued fraction */
       
  3839   gint64 N1, D1;                /* numerator, denominator of last approx */
       
  3840   gint64 N2, D2;                /* numerator, denominator of previous approx */
       
  3841   gint i;
       
  3842   gboolean negative = FALSE;
       
  3843 
       
  3844   /* initialize fraction being converted */
       
  3845   F = src_value->data[0].v_double;
       
  3846   if (F < 0.0) {
       
  3847     F = -F;
       
  3848     negative = TRUE;
       
  3849   }
       
  3850 
       
  3851   V = F;
       
  3852   /* initialize fractions with 1/0, 0/1 */
       
  3853   N1 = 1;
       
  3854   D1 = 0;
       
  3855   N2 = 0;
       
  3856   D2 = 1;
       
  3857   N = 1;
       
  3858   D = 1;
       
  3859 
       
  3860   for (i = 0; i < MAX_TERMS; i++) {
       
  3861     /* get next term */
       
  3862     A = (gint) F;               /* no floor() needed, F is always >= 0 */
       
  3863     /* get new divisor */
       
  3864     F = F - A;
       
  3865 
       
  3866     /* calculate new fraction in temp */
       
  3867     N2 = N1 * A + N2;
       
  3868     D2 = D1 * A + D2;
       
  3869 
       
  3870     /* guard against overflow */
       
  3871     if (N2 > G_MAXINT || D2 > G_MAXINT) {
       
  3872       break;
       
  3873     }
       
  3874 
       
  3875     N = N2;
       
  3876     D = D2;
       
  3877 
       
  3878     /* save last two fractions */
       
  3879     N2 = N1;
       
  3880     D2 = D1;
       
  3881     N1 = N;
       
  3882     D1 = D;
       
  3883 
       
  3884     /* quit if dividing by zero or close enough to target */
       
  3885     if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
       
  3886       break;
       
  3887     }
       
  3888 
       
  3889     /* Take reciprocal */
       
  3890     F = 1 / F;
       
  3891   }
       
  3892   /* fix for overflow */
       
  3893   if (D == 0) {
       
  3894     N = G_MAXINT;
       
  3895     D = 1;
       
  3896   }
       
  3897   /* fix for negative */
       
  3898   if (negative)
       
  3899     N = -N;
       
  3900 
       
  3901   /* will also simplify */
       
  3902   gst_value_set_fraction (dest_value, N, D);
       
  3903 }
       
  3904 
       
  3905 static void
       
  3906 gst_value_transform_fraction_double (const GValue * src_value,
       
  3907     GValue * dest_value)
       
  3908 {
       
  3909   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
       
  3910       ((double) src_value->data[1].v_int);
       
  3911 }
       
  3912 
       
  3913 static gint
       
  3914 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
       
  3915 {
       
  3916   gint n1, n2;
       
  3917   gint d1, d2;
       
  3918 
       
  3919   gint64 new_num_1;
       
  3920   gint64 new_num_2;
       
  3921 
       
  3922   n1 = value1->data[0].v_int;
       
  3923   n2 = value2->data[0].v_int;
       
  3924   d1 = value1->data[1].v_int;
       
  3925   d2 = value2->data[1].v_int;
       
  3926 
       
  3927   /* fractions are reduced when set, so we can quickly see if they're equal */
       
  3928   if (n1 == n2 && d1 == d2)
       
  3929     return GST_VALUE_EQUAL;
       
  3930 
       
  3931   /* extend to 64 bits */
       
  3932   new_num_1 = ((gint64) n1) * d2;
       
  3933   new_num_2 = ((gint64) n2) * d1;
       
  3934   if (new_num_1 < new_num_2)
       
  3935     return GST_VALUE_LESS_THAN;
       
  3936   if (new_num_1 > new_num_2)
       
  3937     return GST_VALUE_GREATER_THAN;
       
  3938 
       
  3939   /* new_num_1 == new_num_2 implies that both denominators must have 
       
  3940    * been 0, beause otherwise simplification would have caught the
       
  3941    * equivalence */
       
  3942   return GST_VALUE_UNORDERED;
       
  3943 }
       
  3944 
       
  3945 /*********
       
  3946  * GDate *
       
  3947  *********/
       
  3948 
       
  3949 /**
       
  3950  * gst_value_set_date:
       
  3951  * @value: a GValue initialized to GST_TYPE_DATE
       
  3952  * @date: the date to set the value to
       
  3953  *
       
  3954  * Sets the contents of @value to coorespond to @date.  The actual
       
  3955  * #GDate structure is copied before it is used.
       
  3956  */
       
  3957 #ifdef __SYMBIAN32__
       
  3958 EXPORT_C
       
  3959 #endif
       
  3960 
       
  3961 void
       
  3962 gst_value_set_date (GValue * value, const GDate * date)
       
  3963 {
       
  3964   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE);
       
  3965   g_return_if_fail (g_date_valid (date));
       
  3966 
       
  3967   g_value_set_boxed (value, date);
       
  3968 }
       
  3969 
       
  3970 /**
       
  3971  * gst_value_get_date:
       
  3972  * @value: a GValue initialized to GST_TYPE_DATE
       
  3973  *
       
  3974  * Gets the contents of @value.
       
  3975  *
       
  3976  * Returns: the contents of @value
       
  3977  */
       
  3978 #ifdef __SYMBIAN32__
       
  3979 EXPORT_C
       
  3980 #endif
       
  3981 
       
  3982 const GDate *
       
  3983 gst_value_get_date (const GValue * value)
       
  3984 {
       
  3985   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL);
       
  3986 
       
  3987   return (const GDate *) g_value_get_boxed (value);
       
  3988 }
       
  3989 
       
  3990 static gpointer
       
  3991 gst_date_copy (gpointer boxed)
       
  3992 {
       
  3993   const GDate *date = (const GDate *) boxed;
       
  3994 
       
  3995   if (!g_date_valid (date)) {
       
  3996     GST_WARNING ("invalid GDate");
       
  3997     return NULL;
       
  3998   }
       
  3999 
       
  4000   return g_date_new_julian (g_date_get_julian (date));
       
  4001 }
       
  4002 
       
  4003 static gint
       
  4004 gst_value_compare_date (const GValue * value1, const GValue * value2)
       
  4005 {
       
  4006   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
       
  4007   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
       
  4008   guint32 j1, j2;
       
  4009 
       
  4010   if (date1 == date2)
       
  4011     return GST_VALUE_EQUAL;
       
  4012 
       
  4013   if ((date1 == NULL || !g_date_valid (date1))
       
  4014       && (date2 != NULL && g_date_valid (date2))) {
       
  4015     return GST_VALUE_LESS_THAN;
       
  4016   }
       
  4017 
       
  4018   if ((date2 == NULL || !g_date_valid (date2))
       
  4019       && (date1 != NULL && g_date_valid (date1))) {
       
  4020     return GST_VALUE_GREATER_THAN;
       
  4021   }
       
  4022 
       
  4023   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
       
  4024       || !g_date_valid (date2)) {
       
  4025     return GST_VALUE_UNORDERED;
       
  4026   }
       
  4027 
       
  4028   j1 = g_date_get_julian (date1);
       
  4029   j2 = g_date_get_julian (date2);
       
  4030 
       
  4031   if (j1 == j2)
       
  4032     return GST_VALUE_EQUAL;
       
  4033   else if (j1 < j2)
       
  4034     return GST_VALUE_LESS_THAN;
       
  4035   else
       
  4036     return GST_VALUE_GREATER_THAN;
       
  4037 }
       
  4038 
       
  4039 static gchar *
       
  4040 gst_value_serialize_date (const GValue * val)
       
  4041 {
       
  4042   const GDate *date = (const GDate *) g_value_get_boxed (val);
       
  4043 
       
  4044   if (date == NULL || !g_date_valid (date))
       
  4045     return g_strdup ("9999-99-99");
       
  4046 
       
  4047   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
       
  4048       g_date_get_month (date), g_date_get_day (date));
       
  4049 }
       
  4050 
       
  4051 static gboolean
       
  4052 gst_value_deserialize_date (GValue * dest, const char *s)
       
  4053 {
       
  4054   guint year, month, day;
       
  4055 
       
  4056   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
       
  4057     return FALSE;
       
  4058 
       
  4059   if (!g_date_valid_dmy (day, month, year))
       
  4060     return FALSE;
       
  4061 
       
  4062   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
       
  4063   return TRUE;
       
  4064 }
       
  4065 
       
  4066 static void
       
  4067 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
       
  4068 {
       
  4069   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
       
  4070 }
       
  4071 
       
  4072 static void
       
  4073 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
       
  4074 {
       
  4075   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
       
  4076 }
       
  4077 
       
  4078 static void
       
  4079 gst_value_transform_object_string (const GValue * src_value,
       
  4080     GValue * dest_value)
       
  4081 {
       
  4082   GstObject *obj;
       
  4083   gchar *str;
       
  4084 
       
  4085   obj = g_value_get_object (src_value);
       
  4086   str = obj ? GST_OBJECT_NAME (obj) : "NULL";
       
  4087 
       
  4088   dest_value->data[0].v_pointer = g_strdup (str);
       
  4089 }
       
  4090 
       
  4091 static GTypeInfo _info = {
       
  4092   0,
       
  4093   NULL,
       
  4094   NULL,
       
  4095   NULL,
       
  4096   NULL,
       
  4097   NULL,
       
  4098   0,
       
  4099   0,
       
  4100   NULL,
       
  4101   NULL,
       
  4102 };
       
  4103 
       
  4104 static GTypeFundamentalInfo _finfo = {
       
  4105   0
       
  4106 };
       
  4107 
       
  4108 #define FUNC_VALUE_GET_TYPE(type, name)                         \
       
  4109 __declspec(dllexport)	GType gst_ ## type ## _get_type (void)                          \
       
  4110 {                                                               \
       
  4111   static GType gst_ ## type ## _type = 0;                       \
       
  4112                                                                 \
       
  4113   if (G_UNLIKELY (gst_ ## type ## _type == 0)) {		\
       
  4114     _info.value_table = & _gst_ ## type ## _value_table;        \
       
  4115     gst_ ## type ## _type = g_type_register_fundamental (       \
       
  4116         g_type_fundamental_next (),                             \
       
  4117         name, &_info, &_finfo, 0);                              \
       
  4118   }                                                             \
       
  4119                                                                 \
       
  4120   return gst_ ## type ## _type;                                 \
       
  4121 }
       
  4122 
       
  4123 static const GTypeValueTable _gst_fourcc_value_table = {
       
  4124   gst_value_init_fourcc,
       
  4125   NULL,
       
  4126   gst_value_copy_fourcc,
       
  4127   NULL,
       
  4128   "i",
       
  4129   gst_value_collect_fourcc,
       
  4130   "p",
       
  4131   gst_value_lcopy_fourcc
       
  4132 };
       
  4133 
       
  4134 FUNC_VALUE_GET_TYPE (fourcc, "GstFourcc");
       
  4135 
       
  4136 static const GTypeValueTable _gst_int_range_value_table = {
       
  4137   gst_value_init_int_range,
       
  4138   NULL,
       
  4139   gst_value_copy_int_range,
       
  4140   NULL,
       
  4141   "ii",
       
  4142   gst_value_collect_int_range,
       
  4143   "pp",
       
  4144   gst_value_lcopy_int_range
       
  4145 };
       
  4146 
       
  4147 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
       
  4148 
       
  4149 static const GTypeValueTable _gst_double_range_value_table = {
       
  4150   gst_value_init_double_range,
       
  4151   NULL,
       
  4152   gst_value_copy_double_range,
       
  4153   NULL,
       
  4154   "dd",
       
  4155   gst_value_collect_double_range,
       
  4156   "pp",
       
  4157   gst_value_lcopy_double_range
       
  4158 };
       
  4159 
       
  4160 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
       
  4161 
       
  4162 static const GTypeValueTable _gst_fraction_range_value_table = {
       
  4163   gst_value_init_fraction_range,
       
  4164   gst_value_free_fraction_range,
       
  4165   gst_value_copy_fraction_range,
       
  4166   NULL,
       
  4167   "iiii",
       
  4168   gst_value_collect_fraction_range,
       
  4169   "pppp",
       
  4170   gst_value_lcopy_fraction_range
       
  4171 };
       
  4172 
       
  4173 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
       
  4174 
       
  4175 static const GTypeValueTable _gst_value_list_value_table = {
       
  4176   gst_value_init_list_or_array,
       
  4177   gst_value_free_list_or_array,
       
  4178   gst_value_copy_list_or_array,
       
  4179   gst_value_list_or_array_peek_pointer,
       
  4180   "p",
       
  4181   gst_value_collect_list_or_array,
       
  4182   "p",
       
  4183   gst_value_lcopy_list_or_array
       
  4184 };
       
  4185 
       
  4186 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
       
  4187 
       
  4188 static const GTypeValueTable _gst_value_array_value_table = {
       
  4189   gst_value_init_list_or_array,
       
  4190   gst_value_free_list_or_array,
       
  4191   gst_value_copy_list_or_array,
       
  4192   gst_value_list_or_array_peek_pointer,
       
  4193   "p",
       
  4194   gst_value_collect_list_or_array,
       
  4195   "p",
       
  4196   gst_value_lcopy_list_or_array
       
  4197 };
       
  4198 
       
  4199 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
       
  4200 
       
  4201 static const GTypeValueTable _gst_fraction_value_table = {
       
  4202   gst_value_init_fraction,
       
  4203   NULL,
       
  4204   gst_value_copy_fraction,
       
  4205   NULL,
       
  4206   "ii",
       
  4207   gst_value_collect_fraction,
       
  4208   "pp",
       
  4209   gst_value_lcopy_fraction
       
  4210 };
       
  4211 
       
  4212 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
       
  4213 #ifdef __SYMBIAN32__
       
  4214 EXPORT_C
       
  4215 #endif
       
  4216 
       
  4217 
       
  4218 
       
  4219 GType
       
  4220 gst_date_get_type (void)
       
  4221 {
       
  4222   static GType gst_date_type = 0;
       
  4223 
       
  4224   if (G_UNLIKELY (gst_date_type == 0)) {
       
  4225     /* FIXME 0.11: we require GLib 2.8 already
       
  4226      * Not using G_TYPE_DATE here on purpose, even if we could
       
  4227      * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the
       
  4228      * serialised strings to have different type strings depending
       
  4229      * on what version is used, so FIXME when we require GLib-2.8 */
       
  4230     gst_date_type = g_boxed_type_register_static ("GstDate",
       
  4231         (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free);
       
  4232   }
       
  4233 
       
  4234   return gst_date_type;
       
  4235 }
       
  4236 #ifdef __SYMBIAN32__
       
  4237 EXPORT_C
       
  4238 #endif
       
  4239 
       
  4240 
       
  4241 void
       
  4242 _gst_value_initialize (void)
       
  4243 {
       
  4244   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
       
  4245   gst_value_union_funcs = g_array_new (FALSE, FALSE,
       
  4246       sizeof (GstValueUnionInfo));
       
  4247   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
       
  4248       sizeof (GstValueIntersectInfo));
       
  4249   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
       
  4250       sizeof (GstValueSubtractInfo));
       
  4251 
       
  4252   {
       
  4253     static GstValueTable gst_value = {
       
  4254       0,
       
  4255       gst_value_compare_fourcc,
       
  4256       gst_value_serialize_fourcc,
       
  4257       gst_value_deserialize_fourcc,
       
  4258     };
       
  4259 
       
  4260     gst_value.type = gst_fourcc_get_type ();
       
  4261     gst_value_register (&gst_value);
       
  4262   }
       
  4263 
       
  4264   {
       
  4265     static GstValueTable gst_value = {
       
  4266       0,
       
  4267       gst_value_compare_int_range,
       
  4268       gst_value_serialize_int_range,
       
  4269       gst_value_deserialize_int_range,
       
  4270     };
       
  4271 
       
  4272     gst_value.type = gst_int_range_get_type ();
       
  4273     gst_value_register (&gst_value);
       
  4274   }
       
  4275 
       
  4276   {
       
  4277     static GstValueTable gst_value = {
       
  4278       0,
       
  4279       gst_value_compare_double_range,
       
  4280       gst_value_serialize_double_range,
       
  4281       gst_value_deserialize_double_range,
       
  4282     };
       
  4283 
       
  4284     gst_value.type = gst_double_range_get_type ();
       
  4285     gst_value_register (&gst_value);
       
  4286   }
       
  4287 
       
  4288   {
       
  4289     static GstValueTable gst_value = {
       
  4290       0,
       
  4291       gst_value_compare_fraction_range,
       
  4292       gst_value_serialize_fraction_range,
       
  4293       gst_value_deserialize_fraction_range,
       
  4294     };
       
  4295 
       
  4296     gst_value.type = gst_fraction_range_get_type ();
       
  4297     gst_value_register (&gst_value);
       
  4298   }
       
  4299 
       
  4300   {
       
  4301     static GstValueTable gst_value = {
       
  4302       0,
       
  4303       gst_value_compare_list,
       
  4304       gst_value_serialize_list,
       
  4305       gst_value_deserialize_list,
       
  4306     };
       
  4307 
       
  4308     gst_value.type = gst_value_list_get_type ();
       
  4309     gst_value_register (&gst_value);
       
  4310   }
       
  4311 
       
  4312   {
       
  4313     static GstValueTable gst_value = {
       
  4314       0,
       
  4315       gst_value_compare_array,
       
  4316       gst_value_serialize_array,
       
  4317       gst_value_deserialize_array,
       
  4318     };
       
  4319 
       
  4320     gst_value.type = gst_value_array_get_type ();;
       
  4321     gst_value_register (&gst_value);
       
  4322   }
       
  4323 
       
  4324   {
       
  4325 #if 0
       
  4326     static const GTypeValueTable value_table = {
       
  4327       gst_value_init_buffer,
       
  4328       NULL,
       
  4329       gst_value_copy_buffer,
       
  4330       NULL,
       
  4331       "i",
       
  4332       NULL,                     /*gst_value_collect_buffer, */
       
  4333       "p",
       
  4334       NULL                      /*gst_value_lcopy_buffer */
       
  4335     };
       
  4336 #endif
       
  4337     static GstValueTable gst_value = {
       
  4338       0,
       
  4339       gst_value_compare_buffer,
       
  4340       gst_value_serialize_buffer,
       
  4341       gst_value_deserialize_buffer,
       
  4342     };
       
  4343 
       
  4344     gst_value.type = GST_TYPE_BUFFER;
       
  4345     gst_value_register (&gst_value);
       
  4346   }
       
  4347   {
       
  4348     static GstValueTable gst_value = {
       
  4349       0,
       
  4350       gst_value_compare_fraction,
       
  4351       gst_value_serialize_fraction,
       
  4352       gst_value_deserialize_fraction,
       
  4353     };
       
  4354 
       
  4355     gst_value.type = gst_fraction_get_type ();
       
  4356     gst_value_register (&gst_value);
       
  4357   }
       
  4358   {
       
  4359     static GstValueTable gst_value = {
       
  4360       0,
       
  4361       NULL,
       
  4362       gst_value_serialize_caps,
       
  4363       gst_value_deserialize_caps,
       
  4364     };
       
  4365 
       
  4366     gst_value.type = GST_TYPE_CAPS;
       
  4367     gst_value_register (&gst_value);
       
  4368   }
       
  4369   {
       
  4370     static GstValueTable gst_value = {
       
  4371       0,
       
  4372       NULL,
       
  4373       gst_value_serialize_structure,
       
  4374       gst_value_deserialize_structure,
       
  4375     };
       
  4376 
       
  4377     gst_value.type = GST_TYPE_STRUCTURE;
       
  4378     gst_value_register (&gst_value);
       
  4379   }
       
  4380   {
       
  4381     static GstValueTable gst_value = {
       
  4382       0,
       
  4383       gst_value_compare_date,
       
  4384       gst_value_serialize_date,
       
  4385       gst_value_deserialize_date,
       
  4386     };
       
  4387 
       
  4388     gst_value.type = gst_date_get_type ();
       
  4389     gst_value_register (&gst_value);
       
  4390   }
       
  4391 
       
  4392   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
       
  4393   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
       
  4394 
       
  4395   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
       
  4396   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
       
  4397   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
       
  4398 
       
  4399   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
       
  4400 
       
  4401   REGISTER_SERIALIZATION (G_TYPE_INT, int);
       
  4402 
       
  4403   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
       
  4404   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
       
  4405 
       
  4406   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
       
  4407   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
       
  4408   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
       
  4409 
       
  4410   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
       
  4411       gst_value_transform_fourcc_string);
       
  4412   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
       
  4413       gst_value_transform_int_range_string);
       
  4414   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
       
  4415       gst_value_transform_double_range_string);
       
  4416   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
       
  4417       gst_value_transform_fraction_range_string);
       
  4418   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
       
  4419       gst_value_transform_list_string);
       
  4420   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
       
  4421       gst_value_transform_array_string);
       
  4422   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
       
  4423       gst_value_transform_fraction_string);
       
  4424   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
       
  4425       gst_value_transform_string_fraction);
       
  4426   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
       
  4427       gst_value_transform_fraction_double);
       
  4428   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
       
  4429       gst_value_transform_double_fraction);
       
  4430   g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING,
       
  4431       gst_value_transform_date_string);
       
  4432   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE,
       
  4433       gst_value_transform_string_date);
       
  4434   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
       
  4435       gst_value_transform_object_string);
       
  4436 
       
  4437   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
       
  4438       gst_value_intersect_int_int_range);
       
  4439   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
       
  4440       gst_value_intersect_int_range_int_range);
       
  4441   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
       
  4442       gst_value_intersect_double_double_range);
       
  4443   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
       
  4444       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
       
  4445   gst_value_register_intersect_func (GST_TYPE_ARRAY,
       
  4446       GST_TYPE_ARRAY, gst_value_intersect_array);
       
  4447   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
       
  4448       gst_value_intersect_fraction_fraction_range);
       
  4449   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
       
  4450       GST_TYPE_FRACTION_RANGE,
       
  4451       gst_value_intersect_fraction_range_fraction_range);
       
  4452 
       
  4453   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
       
  4454       gst_value_subtract_int_int_range);
       
  4455   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
       
  4456       gst_value_subtract_int_range_int);
       
  4457   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
       
  4458       gst_value_subtract_int_range_int_range);
       
  4459   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
       
  4460       gst_value_subtract_double_double_range);
       
  4461   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
       
  4462       gst_value_subtract_double_range_double);
       
  4463   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
       
  4464       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
       
  4465 
       
  4466   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
       
  4467       gst_value_subtract_fraction_fraction_range);
       
  4468   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
       
  4469       gst_value_subtract_fraction_range_fraction);
       
  4470   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
       
  4471       GST_TYPE_FRACTION_RANGE,
       
  4472       gst_value_subtract_fraction_range_fraction_range);
       
  4473 
       
  4474   /* see bug #317246, #64994, #65041 */
       
  4475   {
       
  4476     volatile GType date_type = G_TYPE_DATE;
       
  4477 
       
  4478     g_type_name (date_type);
       
  4479   }
       
  4480 
       
  4481   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
       
  4482       gst_value_union_int_int_range);
       
  4483   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
       
  4484       gst_value_union_int_range_int_range);
       
  4485 
       
  4486 #if 0
       
  4487   /* Implement these if needed */
       
  4488   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
       
  4489       gst_value_union_fraction_fraction_range);
       
  4490   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
       
  4491       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
       
  4492 #endif
       
  4493 }