X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstvalue.c;h=c9f344bef1ef4e3755f73d89fb6c60f7e6ef65ee;hb=066b515985897495cae32fca5b7eeeec260c40c9;hp=7073484d53d95f4a7c0b48a03b8612eeb7d423af;hpb=6f295dc2390d850ca321ccf78ddf4392d4c4bce9;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstvalue.c b/gst/gstvalue.c index 7073484..c9f344b 100644 --- a/gst/gstvalue.c +++ b/gst/gstvalue.c @@ -45,6 +45,55 @@ #include #include "gstutils.h" +/* GstValueUnionFunc: + * @dest: a #GValue for the result + * @value1: a #GValue operand + * @value2: a #GValue operand + * + * Used by gst_value_union() to perform unification for a specific #GValue + * type. Register a new implementation with gst_value_register_union_func(). + * + * Returns: %TRUE if a union was successful + */ +typedef gboolean (*GstValueUnionFunc) (GValue * dest, + const GValue * value1, const GValue * value2); + +/* GstValueIntersectFunc: + * @dest: (out caller-allocates): a #GValue for the result + * @value1: a #GValue operand + * @value2: a #GValue operand + * + * Used by gst_value_intersect() to perform intersection for a specific #GValue + * type. If the intersection is non-empty, the result is + * placed in @dest and TRUE is returned. If the intersection is + * empty, @dest is unmodified and FALSE is returned. + * Register a new implementation with gst_value_register_intersect_func(). + * + * Returns: %TRUE if the values can intersect + */ +typedef gboolean (*GstValueIntersectFunc) (GValue * dest, + const GValue * value1, const GValue * value2); + +/* GstValueSubtractFunc: + * @dest: (out caller-allocates): a #GValue for the result + * @minuend: a #GValue operand + * @subtrahend: a #GValue operand + * + * Used by gst_value_subtract() to perform subtraction for a specific #GValue + * type. Register a new implementation with gst_value_register_subtract_func(). + * + * Returns: %TRUE if the subtraction is not empty + */ +typedef gboolean (*GstValueSubtractFunc) (GValue * dest, + const GValue * minuend, const GValue * subtrahend); + +static void gst_value_register_union_func (GType type1, + GType type2, GstValueUnionFunc func); +static void gst_value_register_intersect_func (GType type1, + GType type2, GstValueIntersectFunc func); +static void gst_value_register_subtract_func (GType minuend_type, + GType subtrahend_type, GstValueSubtractFunc func); + typedef struct _GstValueUnionInfo GstValueUnionInfo; struct _GstValueUnionInfo { @@ -296,6 +345,63 @@ gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values, return NULL; } +static gboolean +gst_value_list_or_array_get_basic_type (const GValue * value, GType * type) +{ + if (G_UNLIKELY (value == NULL)) + return FALSE; + + if (GST_VALUE_HOLDS_LIST (value)) { + if (VALUE_LIST_SIZE (value) == 0) + return FALSE; + return gst_value_list_or_array_get_basic_type (VALUE_LIST_GET_VALUE (value, + 0), type); + } + if (GST_VALUE_HOLDS_ARRAY (value)) { + const GArray *array = (const GArray *) value->data[0].v_pointer; + if (array->len == 0) + return FALSE; + return gst_value_list_or_array_get_basic_type (&g_array_index (array, + GValue, 0), type); + } + + *type = G_VALUE_TYPE (value); + + return TRUE; +} + +#define IS_RANGE_COMPAT(type1,type2,t1,t2) \ + (((t1) == (type1) && (t2) == (type2)) || ((t2) == (type1) && (t1) == (type2))) + +static gboolean +gst_value_list_or_array_are_compatible (const GValue * value1, + const GValue * value2) +{ + GType basic_type1, basic_type2; + + /* empty or same type is OK */ + if (!gst_value_list_or_array_get_basic_type (value1, &basic_type1) || + !gst_value_list_or_array_get_basic_type (value2, &basic_type2) || + basic_type1 == basic_type2) + return TRUE; + + /* ranges are distinct types for each bound type... */ + if (IS_RANGE_COMPAT (G_TYPE_INT, GST_TYPE_INT_RANGE, basic_type1, + basic_type2)) + return TRUE; + if (IS_RANGE_COMPAT (G_TYPE_INT64, GST_TYPE_INT64_RANGE, basic_type1, + basic_type2)) + return TRUE; + if (IS_RANGE_COMPAT (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, basic_type1, + basic_type2)) + return TRUE; + if (IS_RANGE_COMPAT (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, basic_type1, + basic_type2)) + return TRUE; + + return FALSE; +} + /** * gst_value_list_append_value: * @value: a #GValue of type #GST_TYPE_LIST @@ -310,6 +416,8 @@ gst_value_list_append_value (GValue * value, const GValue * append_value) g_return_if_fail (GST_VALUE_HOLDS_LIST (value)); g_return_if_fail (G_IS_VALUE (append_value)); + g_return_if_fail (gst_value_list_or_array_are_compatible (value, + append_value)); gst_value_init_and_copy (&val, append_value); g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1); @@ -329,6 +437,8 @@ gst_value_list_prepend_value (GValue * value, const GValue * prepend_value) g_return_if_fail (GST_VALUE_HOLDS_LIST (value)); g_return_if_fail (G_IS_VALUE (prepend_value)); + g_return_if_fail (gst_value_list_or_array_are_compatible (value, + prepend_value)); gst_value_init_and_copy (&val, prepend_value); g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1); @@ -355,6 +465,7 @@ gst_value_list_concat (GValue * dest, const GValue * value1, g_return_if_fail (G_VALUE_TYPE (dest) == 0); g_return_if_fail (G_IS_VALUE (value1)); g_return_if_fail (G_IS_VALUE (value2)); + g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2)); value1_length = (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1); @@ -412,6 +523,7 @@ gst_value_list_merge (GValue * dest, const GValue * value1, g_return_if_fail (G_VALUE_TYPE (dest) == 0); g_return_if_fail (G_IS_VALUE (value1)); g_return_if_fail (G_IS_VALUE (value2)); + g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2)); value1_length = (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1); @@ -537,6 +649,8 @@ gst_value_array_append_value (GValue * value, const GValue * append_value) g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value)); g_return_if_fail (G_IS_VALUE (append_value)); + g_return_if_fail (gst_value_list_or_array_are_compatible (value, + append_value)); gst_value_init_and_copy (&val, append_value); g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1); @@ -556,6 +670,8 @@ gst_value_array_prepend_value (GValue * value, const GValue * prepend_value) g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value)); g_return_if_fail (G_IS_VALUE (prepend_value)); + g_return_if_fail (gst_value_list_or_array_are_compatible (value, + prepend_value)); gst_value_init_and_copy (&val, prepend_value); g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1); @@ -716,26 +832,56 @@ gst_value_deserialize_array (GValue * dest, const gchar * s) /************* * int range * + * + * Values in the range are defined as any value greater or equal + * to min*step, AND lesser or equal to max*step. + * For step == 1, this falls back to the traditional range semantics. *************/ +#define INT_RANGE_MIN(v) (((gint *)((v)->data[0].v_pointer))[0]) +#define INT_RANGE_MAX(v) (((gint *)((v)->data[0].v_pointer))[1]) +#define INT_RANGE_STEP(v) (((gint *)((v)->data[0].v_pointer))[2]) + static void gst_value_init_int_range (GValue * value) { - value->data[0].v_int = 0; - value->data[1].v_int = 0; + gint *vals = g_slice_alloc0 (3 * sizeof (gint)); + value->data[0].v_pointer = vals; + INT_RANGE_MIN (value) = 0; + INT_RANGE_MAX (value) = 0; + INT_RANGE_STEP (value) = 1; +} + +static void +gst_value_free_int_range (GValue * value) +{ + g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value)); + g_slice_free1 (3 * sizeof (gint), value->data[0].v_pointer); + value->data[0].v_pointer = NULL; } static void gst_value_copy_int_range (const GValue * src_value, GValue * dest_value) { - dest_value->data[0].v_int = src_value->data[0].v_int; - dest_value->data[1].v_int = src_value->data[1].v_int; + gint *vals = (gint *) dest_value->data[0].v_pointer; + gint *src_vals = (gint *) src_value->data[0].v_pointer; + + if (vals == NULL) { + gst_value_init_int_range (dest_value); + } + if (src_vals != NULL) { + INT_RANGE_MIN (dest_value) = INT_RANGE_MIN (src_value); + INT_RANGE_MAX (dest_value) = INT_RANGE_MAX (src_value); + INT_RANGE_STEP (dest_value) = INT_RANGE_STEP (src_value); + } } static gchar * gst_value_collect_int_range (GValue * value, guint n_collect_values, GTypeCValue * collect_values, guint collect_flags) { + gint *vals = value->data[0].v_pointer; + if (n_collect_values != 2) return g_strdup_printf ("not enough value locations for `%s' passed", G_VALUE_TYPE_NAME (value)); @@ -743,8 +889,12 @@ gst_value_collect_int_range (GValue * value, guint n_collect_values, return g_strdup_printf ("range start is not smaller than end for `%s'", G_VALUE_TYPE_NAME (value)); - value->data[0].v_int = collect_values[0].v_int; - value->data[1].v_int = collect_values[1].v_int; + if (vals == NULL) { + gst_value_init_int_range (value); + } + + gst_value_set_int_range_step (value, collect_values[0].v_int, + collect_values[1].v_int, 1); return NULL; } @@ -755,6 +905,8 @@ gst_value_lcopy_int_range (const GValue * value, guint n_collect_values, { guint32 *int_range_start = collect_values[0].v_pointer; guint32 *int_range_end = collect_values[1].v_pointer; + guint32 *int_range_step = collect_values[2].v_pointer; + gint *vals = (gint *) value->data[0].v_pointer; if (!int_range_start) return g_strdup_printf ("start value location for `%s' passed as NULL", @@ -762,29 +914,57 @@ gst_value_lcopy_int_range (const GValue * value, guint n_collect_values, if (!int_range_end) return g_strdup_printf ("end value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + if (!int_range_step) + return g_strdup_printf ("step value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + if (G_UNLIKELY (vals == NULL)) { + return g_strdup_printf ("Uninitialised `%s' passed", + G_VALUE_TYPE_NAME (value)); + } - *int_range_start = value->data[0].v_int; - *int_range_end = value->data[1].v_int; + *int_range_start = INT_RANGE_MIN (value); + *int_range_end = INT_RANGE_MAX (value); + *int_range_step = INT_RANGE_STEP (value); return NULL; } /** - * gst_value_set_int_range: + * gst_value_set_int_range_step: * @value: a GValue initialized to GST_TYPE_INT_RANGE * @start: the start of the range * @end: the end of the range + * @step: the step of the range * - * Sets @value to the range specified by @start and @end. + * Sets @value to the range specified by @start, @end and @step. */ void -gst_value_set_int_range (GValue * value, gint start, gint end) +gst_value_set_int_range_step (GValue * value, gint start, gint end, gint step) { g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value)); g_return_if_fail (start < end); + g_return_if_fail (step > 0); + g_return_if_fail (start % step == 0); + g_return_if_fail (end % step == 0); + + INT_RANGE_MIN (value) = start / step; + INT_RANGE_MAX (value) = end / step; + INT_RANGE_STEP (value) = step; +} - value->data[0].v_int = start; - value->data[1].v_int = end; +/** + * gst_value_set_int_range: + * @value: a GValue initialized to GST_TYPE_INT_RANGE + * @start: the start of the range + * @end: the end of the range + * + * Sets @value to the range specified by @start and @end. + */ +void +gst_value_set_int_range (GValue * value, gint start, gint end) +{ + gst_value_set_int_range_step (value, start, end, 1); } /** @@ -800,7 +980,7 @@ gst_value_get_int_range_min (const GValue * value) { g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); - return value->data[0].v_int; + return INT_RANGE_MIN (value) * INT_RANGE_STEP (value); } /** @@ -816,31 +996,81 @@ gst_value_get_int_range_max (const GValue * value) { g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); - return value->data[1].v_int; + return INT_RANGE_MAX (value) * INT_RANGE_STEP (value); +} + +/** + * gst_value_get_int_range_step: + * @value: a GValue initialized to GST_TYPE_INT_RANGE + * + * Gets the step of the range specified by @value. + * + * Returns: the step of the range + */ +gint +gst_value_get_int_range_step (const GValue * value) +{ + g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); + + return INT_RANGE_STEP (value); } static void gst_value_transform_int_range_string (const GValue * src_value, GValue * dest_value) { - dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]", - (int) src_value->data[0].v_int, (int) src_value->data[1].v_int); + if (INT_RANGE_STEP (src_value) == 1) + dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]", + INT_RANGE_MIN (src_value), INT_RANGE_MAX (src_value)); + else + dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d,%d]", + INT_RANGE_MIN (src_value) * INT_RANGE_STEP (src_value), + INT_RANGE_MAX (src_value) * INT_RANGE_STEP (src_value), + INT_RANGE_STEP (src_value)); } static gint gst_value_compare_int_range (const GValue * value1, const GValue * value2) { - if (value2->data[0].v_int == value1->data[0].v_int && - value2->data[1].v_int == value1->data[1].v_int) + /* calculate the number of values in each range */ + gint n1 = INT_RANGE_MAX (value1) - INT_RANGE_MIN (value1) + 1; + gint n2 = INT_RANGE_MAX (value2) - INT_RANGE_MIN (value2) + 1; + + /* they must be equal */ + if (n1 != n2) + return GST_VALUE_UNORDERED; + + /* if empty, equal */ + if (n1 == 0) return GST_VALUE_EQUAL; - return GST_VALUE_UNORDERED; + + /* if more than one value, then it is only equal if the step is equal + and bounds lie on the same value */ + if (n1 > 1) { + if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) && + INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) && + INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2)) { + return GST_VALUE_EQUAL; + } + return GST_VALUE_UNORDERED; + } else { + /* if just one, only if the value is equal */ + if (INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2)) + return GST_VALUE_EQUAL; + return GST_VALUE_UNORDERED; + } } static gchar * gst_value_serialize_int_range (const GValue * value) { - return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int, - value->data[1].v_int); + if (INT_RANGE_STEP (value) == 1) + return g_strdup_printf ("[ %d, %d ]", INT_RANGE_MIN (value), + INT_RANGE_MAX (value)); + else + return g_strdup_printf ("[ %d, %d, %d ]", + INT_RANGE_MIN (value) * INT_RANGE_STEP (value), + INT_RANGE_MAX (value) * INT_RANGE_STEP (value), INT_RANGE_STEP (value)); } static gboolean @@ -852,26 +1082,57 @@ gst_value_deserialize_int_range (GValue * dest, const gchar * s) /*************** * int64 range * + * + * Values in the range are defined as any value greater or equal + * to min*step, AND lesser or equal to max*step. + * For step == 1, this falls back to the traditional range semantics. ***************/ +#define INT64_RANGE_MIN(v) (((gint64 *)((v)->data[0].v_pointer))[0]) +#define INT64_RANGE_MAX(v) (((gint64 *)((v)->data[0].v_pointer))[1]) +#define INT64_RANGE_STEP(v) (((gint64 *)((v)->data[0].v_pointer))[2]) + static void gst_value_init_int64_range (GValue * value) { - value->data[0].v_int64 = 0; - value->data[1].v_int64 = 0; + gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64)); + value->data[0].v_pointer = vals; + INT64_RANGE_MIN (value) = 0; + INT64_RANGE_MAX (value) = 0; + INT64_RANGE_STEP (value) = 1; +} + +static void +gst_value_free_int64_range (GValue * value) +{ + g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value)); + g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer); + value->data[0].v_pointer = NULL; } static void gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value) { - dest_value->data[0].v_int64 = src_value->data[0].v_int64; - dest_value->data[1].v_int64 = src_value->data[1].v_int64; + gint64 *vals = (gint64 *) dest_value->data[0].v_pointer; + gint64 *src_vals = (gint64 *) src_value->data[0].v_pointer; + + if (vals == NULL) { + gst_value_init_int64_range (dest_value); + } + + if (src_vals != NULL) { + INT64_RANGE_MIN (dest_value) = INT64_RANGE_MIN (src_value); + INT64_RANGE_MAX (dest_value) = INT64_RANGE_MAX (src_value); + INT64_RANGE_STEP (dest_value) = INT64_RANGE_STEP (src_value); + } } static gchar * gst_value_collect_int64_range (GValue * value, guint n_collect_values, GTypeCValue * collect_values, guint collect_flags) { + gint64 *vals = value->data[0].v_pointer; + if (n_collect_values != 2) return g_strdup_printf ("not enough value locations for `%s' passed", G_VALUE_TYPE_NAME (value)); @@ -879,8 +1140,12 @@ gst_value_collect_int64_range (GValue * value, guint n_collect_values, return g_strdup_printf ("range start is not smaller than end for `%s'", G_VALUE_TYPE_NAME (value)); - value->data[0].v_int64 = collect_values[0].v_int64; - value->data[1].v_int64 = collect_values[1].v_int64; + if (vals == NULL) { + gst_value_init_int64_range (value); + } + + gst_value_set_int64_range_step (value, collect_values[0].v_int64, + collect_values[1].v_int64, 1); return NULL; } @@ -891,6 +1156,8 @@ gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values, { guint64 *int_range_start = collect_values[0].v_pointer; guint64 *int_range_end = collect_values[1].v_pointer; + guint64 *int_range_step = collect_values[2].v_pointer; + gint64 *vals = (gint64 *) value->data[0].v_pointer; if (!int_range_start) return g_strdup_printf ("start value location for `%s' passed as NULL", @@ -898,14 +1165,49 @@ gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values, if (!int_range_end) return g_strdup_printf ("end value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + if (!int_range_step) + return g_strdup_printf ("step value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); - *int_range_start = value->data[0].v_int64; - *int_range_end = value->data[1].v_int64; + if (G_UNLIKELY (vals == NULL)) { + return g_strdup_printf ("Uninitialised `%s' passed", + G_VALUE_TYPE_NAME (value)); + } + + *int_range_start = INT64_RANGE_MIN (value); + *int_range_end = INT64_RANGE_MAX (value); + *int_range_step = INT64_RANGE_STEP (value); return NULL; } /** + * gst_value_set_int64_range_step: + * @value: a GValue initialized to GST_TYPE_INT64_RANGE + * @start: the start of the range + * @end: the end of the range + * @step: the step of the range + * + * Sets @value to the range specified by @start, @end and @step. + * + * Since: 0.11.0 + */ +void +gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end, + gint64 step) +{ + g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value)); + g_return_if_fail (start < end); + g_return_if_fail (step > 0); + g_return_if_fail (start % step == 0); + g_return_if_fail (end % step == 0); + + INT64_RANGE_MIN (value) = start / step; + INT64_RANGE_MAX (value) = end / step; + INT64_RANGE_STEP (value) = step; +} + +/** * gst_value_set_int64_range: * @value: a GValue initialized to GST_TYPE_INT64_RANGE * @start: the start of the range @@ -918,11 +1220,7 @@ gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values, void gst_value_set_int64_range (GValue * value, gint64 start, gint64 end) { - g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value)); - g_return_if_fail (start < end); - - value->data[0].v_int64 = start; - value->data[1].v_int64 = end; + gst_value_set_int64_range_step (value, start, end, 1); } /** @@ -940,7 +1238,7 @@ gst_value_get_int64_range_min (const GValue * value) { g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); - return value->data[0].v_int64; + return INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value); } /** @@ -958,32 +1256,88 @@ gst_value_get_int64_range_max (const GValue * value) { g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); - return value->data[1].v_int64; + return INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value); +} + +/** + * gst_value_get_int64_range_step: + * @value: a GValue initialized to GST_TYPE_INT64_RANGE + * + * Gets the step of the range specified by @value. + * + * Returns: the step of the range + * + * Since: 0.11.0 + */ +gint64 +gst_value_get_int64_range_step (const GValue * value) +{ + g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); + + return INT64_RANGE_STEP (value); } static void gst_value_transform_int64_range_string (const GValue * src_value, GValue * dest_value) { - dest_value->data[0].v_pointer = - g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]", - src_value->data[0].v_int64, src_value->data[1].v_int64); + if (INT64_RANGE_STEP (src_value) == 1) + dest_value->data[0].v_pointer = + g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]", + INT64_RANGE_MIN (src_value), INT64_RANGE_MAX (src_value)); + else + dest_value->data[0].v_pointer = + g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT + ",%" G_GINT64_FORMAT "]", + INT64_RANGE_MIN (src_value) * INT64_RANGE_STEP (src_value), + INT64_RANGE_MAX (src_value) * INT64_RANGE_STEP (src_value), + INT64_RANGE_STEP (src_value)); } static gint gst_value_compare_int64_range (const GValue * value1, const GValue * value2) { - if (value2->data[0].v_int64 == value1->data[0].v_int64 && - value2->data[1].v_int64 == value1->data[1].v_int64) + /* calculate the number of values in each range */ + gint64 n1 = INT64_RANGE_MAX (value1) - INT64_RANGE_MIN (value1) + 1; + gint64 n2 = INT64_RANGE_MAX (value2) - INT64_RANGE_MIN (value2) + 1; + + /* they must be equal */ + if (n1 != n2) + return GST_VALUE_UNORDERED; + + /* if empty, equal */ + if (n1 == 0) return GST_VALUE_EQUAL; - return GST_VALUE_UNORDERED; + + /* if more than one value, then it is only equal if the step is equal + and bounds lie on the same value */ + if (n1 > 1) { + if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) && + INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) && + INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2)) { + return GST_VALUE_EQUAL; + } + return GST_VALUE_UNORDERED; + } else { + /* if just one, only if the value is equal */ + if (INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2)) + return GST_VALUE_EQUAL; + return GST_VALUE_UNORDERED; + } } static gchar * gst_value_serialize_int64_range (const GValue * value) { - return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]", - value->data[0].v_int64, value->data[1].v_int64); + if (INT64_RANGE_STEP (value) == 1) + return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]", + INT64_RANGE_MIN (value), INT64_RANGE_MAX (value)); + else + return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ", %" + G_GINT64_FORMAT " ]", + INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value), + INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value), + INT64_RANGE_STEP (value)); } static gboolean @@ -1161,8 +1515,9 @@ gst_value_free_fraction_range (GValue * value) GValue *vals = (GValue *) value->data[0].v_pointer; if (vals != NULL) { - g_value_unset (&vals[0]); - g_value_unset (&vals[1]); + /* we know the two values contain fractions without internal allocs */ + /* g_value_unset (&vals[0]); */ + /* g_value_unset (&vals[1]); */ g_slice_free1 (2 * sizeof (GValue), vals); value->data[0].v_pointer = NULL; } @@ -1311,8 +1666,9 @@ gst_value_set_fraction_range_full (GValue * value, gst_value_set_fraction (&end, numerator_end, denominator_end); gst_value_set_fraction_range (value, &start, &end); - g_value_unset (&start); - g_value_unset (&end); + /* we know the two values contain fractions without internal allocs */ + /* g_value_unset (&start); */ + /* g_value_unset (&end); */ } /** @@ -1485,6 +1841,65 @@ gst_value_deserialize_caps (GValue * dest, const gchar * s) return FALSE; } +/************** + * GstSegment * + **************/ +static gchar * +gst_value_serialize_segment (const GValue * value) +{ + GstSegment *seg = g_value_get_boxed (value); + gchar *t, *res; + GstStructure *s; + + s = gst_structure_new ("GstSegment", + "flags", GST_TYPE_SEGMENT_FLAGS, seg->flags, + "rate", G_TYPE_DOUBLE, seg->rate, + "applied-rate", G_TYPE_DOUBLE, seg->applied_rate, + "format", GST_TYPE_FORMAT, seg->format, + "base", G_TYPE_UINT64, seg->base, + "start", G_TYPE_UINT64, seg->start, + "stop", G_TYPE_UINT64, seg->stop, + "time", G_TYPE_UINT64, seg->time, + "position", G_TYPE_UINT64, seg->position, + "duration", G_TYPE_UINT64, seg->duration, NULL); + t = gst_structure_to_string (s); + res = g_strdup_printf ("\"%s\"", t); + g_free (t); + gst_structure_free (s); + + return res; +} + +static gboolean +gst_value_deserialize_segment (GValue * dest, const gchar * s) +{ + GstStructure *str; + GstSegment seg; + gboolean res; + + str = gst_structure_from_string (s, NULL); + if (str == NULL) + return FALSE; + + res = gst_structure_get (str, + "flags", GST_TYPE_SEGMENT_FLAGS, &seg.flags, + "rate", G_TYPE_DOUBLE, &seg.rate, + "applied-rate", G_TYPE_DOUBLE, &seg.applied_rate, + "format", GST_TYPE_FORMAT, &seg.format, + "base", G_TYPE_UINT64, &seg.base, + "start", G_TYPE_UINT64, &seg.start, + "stop", G_TYPE_UINT64, &seg.stop, + "time", G_TYPE_UINT64, &seg.time, + "position", G_TYPE_UINT64, &seg.position, + "duration", G_TYPE_UINT64, &seg.duration, NULL); + gst_structure_free (str); + + if (res) + g_value_set_boxed (dest, &seg); + + return res; +} + /**************** * GstStructure * ****************/ @@ -1569,7 +1984,7 @@ gst_value_compare_buffer (const GValue * value1, const GValue * value2) GstBuffer *buf1 = gst_value_get_buffer (value1); GstBuffer *buf2 = gst_value_get_buffer (value2); gsize size1, size2; - gpointer data1, data2; + GstMapInfo info1, info2; gint result = GST_VALUE_UNORDERED; size1 = gst_buffer_get_size (buf1); @@ -1581,16 +1996,19 @@ gst_value_compare_buffer (const GValue * value1, const GValue * value2) if (size1 == 0) return GST_VALUE_EQUAL; - data1 = gst_buffer_map (buf1, &size1, NULL, GST_MAP_READ); - data2 = gst_buffer_map (buf2, &size2, NULL, GST_MAP_READ); - g_assert (data1); - g_assert (data2); + if (!gst_buffer_map (buf1, &info1, GST_MAP_READ)) + return GST_VALUE_UNORDERED; + + if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) { + gst_buffer_unmap (buf1, &info2); + return GST_VALUE_UNORDERED; + } - if (memcmp (data1, data2, size1) == 0) + if (memcmp (info1.data, info2.data, info1.size) == 0) result = GST_VALUE_EQUAL; - gst_buffer_unmap (buf2, data2, size2); - gst_buffer_unmap (buf1, data1, size1); + gst_buffer_unmap (buf2, &info1); + gst_buffer_unmap (buf1, &info2); return result; } @@ -1598,9 +2016,9 @@ gst_value_compare_buffer (const GValue * value1, const GValue * value2) static gchar * gst_value_serialize_buffer (const GValue * value) { + GstMapInfo info; guint8 *data; gint i; - gsize size; gchar *string; GstBuffer *buffer; @@ -1608,15 +2026,18 @@ gst_value_serialize_buffer (const GValue * value) if (buffer == NULL) return NULL; - data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); + if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) + return NULL; + + data = info.data; - string = g_malloc (size * 2 + 1); - for (i = 0; i < size; i++) { + string = g_malloc (info.size * 2 + 1); + for (i = 0; i < info.size; i++) { sprintf (string + i * 2, "%02x", data[i]); } - string[size * 2] = 0; + string[info.size * 2] = 0; - gst_buffer_unmap (buffer, data, size); + gst_buffer_unmap (buffer, &info); return string; } @@ -1627,16 +2048,18 @@ gst_value_deserialize_buffer (GValue * dest, const gchar * s) GstBuffer *buffer; gint len; gchar ts[3]; + GstMapInfo info; guint8 *data; gint i; - gsize size; len = strlen (s); if (len & 1) goto wrong_length; - buffer = gst_buffer_new_allocate (NULL, len / 2, 0); - data = gst_buffer_map (buffer, &size, NULL, GST_MAP_WRITE); + buffer = gst_buffer_new_allocate (NULL, len / 2, NULL); + if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE)) + goto map_failed; + data = info.data; for (i = 0; i < len / 2; i++) { if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) @@ -1648,7 +2071,7 @@ gst_value_deserialize_buffer (GValue * dest, const gchar * s) data[i] = (guint8) strtoul (ts, NULL, 16); } - gst_buffer_unmap (buffer, data, size); + gst_buffer_unmap (buffer, &info); gst_value_take_buffer (dest, buffer); @@ -1659,10 +2082,14 @@ wrong_length: { return FALSE; } +map_failed: + { + return FALSE; + } wrong_char: { gst_buffer_unref (buffer); - gst_buffer_unmap (buffer, data, size); + gst_buffer_unmap (buffer, &info); return FALSE; } } @@ -2159,7 +2586,7 @@ gst_string_unwrap (const gchar * s) read += 3; } else { - /* if we run into a \0 here, we definately won't get a quote later */ + /* if we run into a \0 here, we definitely won't get a quote later */ if (*read == 0) goto beach; @@ -2252,7 +2679,7 @@ gst_value_serialize_enum (const GValue * value) if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) { const GstFormatDefinition *format_def; - format_def = gst_format_get_details (g_value_get_enum (value)); + format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value)); g_return_val_if_fail (format_def != NULL, NULL); return g_strdup (format_def->description); } @@ -2427,78 +2854,295 @@ gst_value_deserialize_flags (GValue * dest, const gchar * s) return TRUE; } -/********* - * union * - *********/ +/**************** + * subset * + ****************/ static gboolean -gst_value_union_int_int_range (GValue * dest, const GValue * src1, - const GValue * src2) +gst_value_is_subset_int_range_int_range (const GValue * value1, + const GValue * value2) { - if (src2->data[0].v_int <= src1->data[0].v_int && - src2->data[1].v_int >= src1->data[0].v_int) { - gst_value_init_and_copy (dest, src2); + gint gcd; + + g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE); + g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE); + + if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) < + INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) + return FALSE; + if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) > + INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2)) + return FALSE; + + if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) { + if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) % + INT_RANGE_STEP (value1)) + return FALSE; return TRUE; } - return FALSE; + + gcd = + gst_util_greatest_common_divisor (INT_RANGE_STEP (value1), + INT_RANGE_STEP (value2)); + if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2))) + return FALSE; + + return TRUE; } static gboolean -gst_value_union_int_range_int_range (GValue * dest, const GValue * src1, - const GValue * src2) +gst_value_is_subset_int64_range_int64_range (const GValue * value1, + const GValue * value2) { - gint min; - gint max; + gint64 gcd; + + g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE); + g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE); - min = MAX (src1->data[0].v_int, src2->data[0].v_int); - max = MIN (src1->data[1].v_int, src2->data[1].v_int); + if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2)) + return FALSE; + if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2)) + return FALSE; - if (min <= max) { - g_value_init (dest, GST_TYPE_INT_RANGE); - gst_value_set_int_range (dest, - MIN (src1->data[0].v_int, src2->data[0].v_int), - MAX (src1->data[1].v_int, src2->data[1].v_int)); + if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) { + if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) % + INT64_RANGE_STEP (value1)) + return FALSE; return TRUE; } + gcd = + gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1), + INT64_RANGE_STEP (value2)); + if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2))) + return FALSE; + + return TRUE; +} + +/** + * gst_value_is_subset: + * @value1: a #GValue + * @value2: a #GValue + * + * Check that @value1 is a subset of @value2. + * + * Return: %TRUE is @value1 is a subset of @value2 + */ +gboolean +gst_value_is_subset (const GValue * value1, const GValue * value2) +{ + /* special case for int/int64 ranges, since we cannot compute + the difference for those when they have different steps, + and it's actually a lot simpler to compute whether a range + is a subset of another. */ + if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) { + return gst_value_is_subset_int_range_int_range (value1, value2); + } else if (GST_VALUE_HOLDS_INT64_RANGE (value1) + && GST_VALUE_HOLDS_INT64_RANGE (value2)) { + return gst_value_is_subset_int64_range_int64_range (value1, value2); + } + + /* + * 1 - [1,2] = empty + * -> !subset + * + * [1,2] - 1 = 2 + * -> 1 - [1,2] = empty + * -> subset + * + * [1,3] - [1,2] = 3 + * -> [1,2] - [1,3] = empty + * -> subset + * + * {1,2} - {1,3} = 2 + * -> {1,3} - {1,2} = 3 + * -> !subset + * + * First caps subtraction needs to return a non-empty set, second + * subtractions needs to give en empty set. + * Both substractions are switched below, as it's faster that way. + */ + if (!gst_value_subtract (NULL, value1, value2)) { + if (gst_value_subtract (NULL, value2, value1)) { + return TRUE; + } + } return FALSE; } -/**************** - * intersection * - ****************/ +/********* + * union * + *********/ static gboolean -gst_value_intersect_int_int_range (GValue * dest, const GValue * src1, +gst_value_union_int_int_range (GValue * dest, const GValue * src1, const GValue * src2) { - if (src2->data[0].v_int <= src1->data[0].v_int && - src2->data[1].v_int >= src1->data[0].v_int) { - gst_value_init_and_copy (dest, src1); + gint v = src1->data[0].v_int; + + /* check if it's already in the range */ + if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v && + INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v && + v % INT_RANGE_STEP (src2) == 0) { + if (dest) + gst_value_init_and_copy (dest, src2); return TRUE; } - return FALSE; -} - + /* check if it extends the range */ + if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) { + if (dest) { + gst_value_init_and_copy (dest, src2); + --INT_RANGE_MIN (src2); + } + return TRUE; + } + if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) { + if (dest) { + gst_value_init_and_copy (dest, src2); + ++INT_RANGE_MAX (src2); + } + return TRUE; + } + + return FALSE; +} + +static gboolean +gst_value_union_int_range_int_range (GValue * dest, const GValue * src1, + const GValue * src2) +{ + /* We can union in several special cases: + 1 - one is a subset of another + 2 - same step and not disjoint + 3 - different step, at least one with one value which matches a 'next' or 'previous' + - anything else ? + */ + + /* 1 - subset */ + if (gst_value_is_subset_int_range_int_range (src1, src2)) { + if (dest) + gst_value_init_and_copy (dest, src2); + return TRUE; + } + if (gst_value_is_subset_int_range_int_range (src2, src1)) { + if (dest) + gst_value_init_and_copy (dest, src1); + return TRUE; + } + + /* 2 - same step and not disjoint */ + if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) { + if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 && + INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) || + (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 && + INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) { + if (dest) { + gint step = INT_RANGE_STEP (src1); + gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2)); + gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2)); + g_value_init (dest, GST_TYPE_INT_RANGE); + gst_value_set_int_range_step (dest, min, max, step); + } + return TRUE; + } + } + + /* 3 - single value matches next or previous */ + if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) { + gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1; + gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1; + if (n1 == 1 || n2 == 1) { + const GValue *range_value = NULL; + gint scalar = 0; + if (n1 == 1) { + range_value = src2; + scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1); + } else if (n2 == 1) { + range_value = src1; + scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2); + } + + if (scalar == + (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) { + if (dest) { + gst_value_init_and_copy (dest, range_value); + --INT_RANGE_MIN (range_value); + } + return TRUE; + } else if (scalar == + (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) { + if (dest) { + gst_value_init_and_copy (dest, range_value); + ++INT_RANGE_MIN (range_value); + } + return TRUE; + } + } + } + + /* If we get there, we did not find a way to make a union that can be + represented with our simplistic model. */ + return FALSE; +} + +/**************** + * intersection * + ****************/ + +static gboolean +gst_value_intersect_int_int_range (GValue * dest, const GValue * src1, + const GValue * src2) +{ + if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int && + INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int && + src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) { + if (dest) + gst_value_init_and_copy (dest, src1); + return TRUE; + } + + return FALSE; +} + static gboolean gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1, const GValue * src2) { gint min; gint max; + gint step; + + step = + INT_RANGE_STEP (src1) / + gst_util_greatest_common_divisor (INT_RANGE_STEP (src1), + INT_RANGE_STEP (src2)); + if (G_MAXINT32 / INT_RANGE_STEP (src2) < step) + return FALSE; + step *= INT_RANGE_STEP (src2); - min = MAX (src1->data[0].v_int, src2->data[0].v_int); - max = MIN (src1->data[1].v_int, src2->data[1].v_int); + min = + MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1), + INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2)); + min = (min + step - 1) / step * step; + max = + MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1), + INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2)); + max = max / step * step; if (min < max) { - g_value_init (dest, GST_TYPE_INT_RANGE); - gst_value_set_int_range (dest, min, max); + if (dest) { + g_value_init (dest, GST_TYPE_INT_RANGE); + gst_value_set_int_range_step (dest, min, max, step); + } return TRUE; } if (min == max) { - g_value_init (dest, G_TYPE_INT); - g_value_set_int (dest, min); + if (dest) { + g_value_init (dest, G_TYPE_INT); + g_value_set_int (dest, min); + } return TRUE; } @@ -2509,9 +3153,11 @@ static gboolean gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1, const GValue * src2) { - if (src2->data[0].v_int64 <= src1->data[0].v_int64 && - src2->data[1].v_int64 >= src1->data[0].v_int64) { - gst_value_init_and_copy (dest, src1); + if (INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2) <= src1->data[0].v_int && + INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2) >= src1->data[0].v_int && + src1->data[0].v_int % INT64_RANGE_STEP (src2) == 0) { + if (dest) + gst_value_init_and_copy (dest, src1); return TRUE; } @@ -2524,18 +3170,37 @@ gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1, { gint64 min; gint64 max; + gint64 step; + + step = + INT64_RANGE_STEP (src1) / + gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1), + INT64_RANGE_STEP (src2)); + if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step) + return FALSE; + step *= INT64_RANGE_STEP (src2); - min = MAX (src1->data[0].v_int64, src2->data[0].v_int64); - max = MIN (src1->data[1].v_int64, src2->data[1].v_int64); + min = + MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1), + INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2)); + min = (min + step - 1) / step * step; + max = + MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1), + INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2)); + max = max / step * step; if (min < max) { - g_value_init (dest, GST_TYPE_INT64_RANGE); - gst_value_set_int64_range (dest, min, max); + if (dest) { + g_value_init (dest, GST_TYPE_INT64_RANGE); + gst_value_set_int64_range_step (dest, min, max, step); + } return TRUE; } if (min == max) { - g_value_init (dest, G_TYPE_INT64); - g_value_set_int64 (dest, min); + if (dest) { + g_value_init (dest, G_TYPE_INT64); + g_value_set_int64 (dest, min); + } return TRUE; } @@ -2548,7 +3213,8 @@ gst_value_intersect_double_double_range (GValue * dest, const GValue * src1, { if (src2->data[0].v_double <= src1->data[0].v_double && src2->data[1].v_double >= src1->data[0].v_double) { - gst_value_init_and_copy (dest, src1); + if (dest) + gst_value_init_and_copy (dest, src1); return TRUE; } @@ -2566,13 +3232,17 @@ gst_value_intersect_double_range_double_range (GValue * dest, max = MIN (src1->data[1].v_double, src2->data[1].v_double); if (min < max) { - g_value_init (dest, GST_TYPE_DOUBLE_RANGE); - gst_value_set_double_range (dest, min, max); + if (dest) { + g_value_init (dest, GST_TYPE_DOUBLE_RANGE); + gst_value_set_double_range (dest, min, max); + } return TRUE; } if (min == max) { - g_value_init (dest, G_TYPE_DOUBLE); - g_value_set_int (dest, (int) min); + if (dest) { + g_value_init (dest, G_TYPE_DOUBLE); + g_value_set_int (dest, (int) min); + } return TRUE; } @@ -2591,6 +3261,15 @@ gst_value_intersect_list (GValue * dest, const GValue * value1, for (i = 0; i < size; i++) { const GValue *cur = VALUE_LIST_GET_VALUE (value1, i); + /* quicker version when we don't need the resulting set */ + if (!dest) { + if (gst_value_intersect (NULL, cur, value2)) { + ret = TRUE; + break; + } + continue; + } + if (gst_value_intersect (&intersection, cur, value2)) { /* append value */ if (!ret) { @@ -2625,6 +3304,18 @@ gst_value_intersect_array (GValue * dest, const GValue * src1, size = gst_value_array_get_size (src1); if (size != gst_value_array_get_size (src2)) return FALSE; + + /* quicker value when we don't need the resulting set */ + if (!dest) { + for (n = 0; n < size; n++) { + if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n), + gst_value_array_get_value (src2, n))) { + return FALSE; + } + } + return TRUE; + } + g_value_init (dest, GST_TYPE_ARRAY); for (n = 0; n < size; n++) { @@ -2659,7 +3350,8 @@ gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1, if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) && (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) { - gst_value_init_and_copy (dest, src1); + if (dest) + gst_value_init_and_copy (dest, src1); return TRUE; } } @@ -2701,14 +3393,17 @@ gst_value_intersect_fraction_range_fraction_range (GValue * dest, res = gst_value_compare_with_func (min, max, compare); g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE); if (res == GST_VALUE_LESS_THAN) { - g_value_init (dest, GST_TYPE_FRACTION_RANGE); - vals1 = dest->data[0].v_pointer; - g_value_copy (min, &vals1[0]); - g_value_copy (max, &vals1[1]); + if (dest) { + g_value_init (dest, GST_TYPE_FRACTION_RANGE); + vals1 = dest->data[0].v_pointer; + g_value_copy (min, &vals1[0]); + g_value_copy (max, &vals1[1]); + } return TRUE; } if (res == GST_VALUE_EQUAL) { - gst_value_init_and_copy (dest, min); + if (dest) + gst_value_init_and_copy (dest, min); return TRUE; } } @@ -2726,13 +3421,15 @@ gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend, { gint min = gst_value_get_int_range_min (subtrahend); gint max = gst_value_get_int_range_max (subtrahend); + gint step = gst_value_get_int_range_step (subtrahend); gint val = g_value_get_int (minuend); /* subtracting a range from an int only works if the int is not in the * range */ - if (val < min || val > max) { + if (val < min || val > max || val % step) { /* and the result is the int */ - gst_value_init_and_copy (dest, minuend); + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } return FALSE; @@ -2742,12 +3439,18 @@ gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend, */ static gboolean gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2, - gint max2) + gint max2, gint step) { GValue v1 = { 0, }; GValue v2 = { 0, }; GValue *pv1, *pv2; /* yeah, hungarian! */ + g_return_val_if_fail (step > 0, FALSE); + g_return_val_if_fail (min1 % step == 0, FALSE); + g_return_val_if_fail (max1 % step == 0, FALSE); + g_return_val_if_fail (min2 % step == 0, FALSE); + g_return_val_if_fail (max2 % step == 0, FALSE); + if (min1 <= max1 && min2 <= max2) { pv1 = &v1; pv2 = &v2; @@ -2761,16 +3464,19 @@ gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2, return FALSE; } + if (!dest) + return TRUE; + if (min1 < max1) { g_value_init (pv1, GST_TYPE_INT_RANGE); - gst_value_set_int_range (pv1, min1, max1); + gst_value_set_int_range_step (pv1, min1, max1, step); } else if (min1 == max1) { g_value_init (pv1, G_TYPE_INT); g_value_set_int (pv1, min1); } if (min2 < max2) { g_value_init (pv2, GST_TYPE_INT_RANGE); - gst_value_set_int_range (pv2, min2, max2); + gst_value_set_int_range_step (pv2, min2, max2, step); } else if (min2 == max2) { g_value_init (pv2, G_TYPE_INT); g_value_set_int (pv2, min2); @@ -2790,26 +3496,29 @@ gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend, { gint min = gst_value_get_int_range_min (minuend); gint max = gst_value_get_int_range_max (minuend); + gint step = gst_value_get_int_range_step (minuend); gint val = g_value_get_int (subtrahend); g_return_val_if_fail (min < max, FALSE); /* value is outside of the range, return range unchanged */ - if (val < min || val > max) { - gst_value_init_and_copy (dest, minuend); + if (val < min || val > max || val % step) { + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } else { /* max must be MAXINT too as val <= max */ - if (val == G_MAXINT) { - max--; - val--; + if (val >= G_MAXINT - step + 1) { + max -= step; + val -= step; } /* min must be MININT too as val >= max */ - if (val == G_MININT) { - min++; - val++; + if (val <= G_MININT + step - 1) { + min += step; + val += step; } - gst_value_create_new_range (dest, min, val - 1, val + 1, max); + if (dest) + gst_value_create_new_range (dest, min, val - step, val + step, max, step); } return TRUE; } @@ -2820,18 +3529,30 @@ gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend, { gint min1 = gst_value_get_int_range_min (minuend); gint max1 = gst_value_get_int_range_max (minuend); + gint step1 = gst_value_get_int_range_step (minuend); gint min2 = gst_value_get_int_range_min (subtrahend); gint max2 = gst_value_get_int_range_max (subtrahend); + gint step2 = gst_value_get_int_range_step (subtrahend); + gint step; + + if (step1 != step2) { + /* ENOIMPL */ + g_assert (FALSE); + return FALSE; + } + step = step1; - if (max2 == G_MAXINT && min2 == G_MININT) { + if (max2 >= max1 && min2 <= min1) { return FALSE; - } else if (max2 == G_MAXINT) { - return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0); - } else if (min2 == G_MININT) { - return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0); + } else if (max2 >= max1) { + return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1), + step, 0, step); + } else if (min2 <= min1) { + return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1, + step, 0, step); } else { - return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), - MAX (max2 + 1, min1), max1); + return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1), + MAX (max2 + step, min1), max1, step); } } @@ -2841,13 +3562,15 @@ gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend, { gint64 min = gst_value_get_int64_range_min (subtrahend); gint64 max = gst_value_get_int64_range_max (subtrahend); + gint64 step = gst_value_get_int64_range_step (subtrahend); gint64 val = g_value_get_int64 (minuend); /* subtracting a range from an int64 only works if the int64 is not in the * range */ - if (val < min || val > max) { + if (val < min || val > max || val % step) { /* and the result is the int64 */ - gst_value_init_and_copy (dest, minuend); + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } return FALSE; @@ -2857,12 +3580,18 @@ gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend, */ static gboolean gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1, - gint64 min2, gint64 max2) + gint64 min2, gint64 max2, gint64 step) { GValue v1 = { 0, }; GValue v2 = { 0, }; GValue *pv1, *pv2; /* yeah, hungarian! */ + g_return_val_if_fail (step > 0, FALSE); + g_return_val_if_fail (min1 % step == 0, FALSE); + g_return_val_if_fail (max1 % step == 0, FALSE); + g_return_val_if_fail (min2 % step == 0, FALSE); + g_return_val_if_fail (max2 % step == 0, FALSE); + if (min1 <= max1 && min2 <= max2) { pv1 = &v1; pv2 = &v2; @@ -2876,16 +3605,19 @@ gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1, return FALSE; } + if (!dest) + return TRUE; + if (min1 < max1) { g_value_init (pv1, GST_TYPE_INT64_RANGE); - gst_value_set_int64_range (pv1, min1, max1); + gst_value_set_int64_range_step (pv1, min1, max1, step); } else if (min1 == max1) { g_value_init (pv1, G_TYPE_INT64); g_value_set_int64 (pv1, min1); } if (min2 < max2) { g_value_init (pv2, GST_TYPE_INT64_RANGE); - gst_value_set_int64_range (pv2, min2, max2); + gst_value_set_int64_range_step (pv2, min2, max2, step); } else if (min2 == max2) { g_value_init (pv2, G_TYPE_INT64); g_value_set_int64 (pv2, min2); @@ -2905,26 +3637,30 @@ gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend, { gint64 min = gst_value_get_int64_range_min (minuend); gint64 max = gst_value_get_int64_range_max (minuend); + gint64 step = gst_value_get_int64_range_step (minuend); gint64 val = g_value_get_int64 (subtrahend); g_return_val_if_fail (min < max, FALSE); /* value is outside of the range, return range unchanged */ - if (val < min || val > max) { - gst_value_init_and_copy (dest, minuend); + if (val < min || val > max || val % step) { + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } else { /* max must be MAXINT64 too as val <= max */ - if (val == G_MAXINT64) { - max--; - val--; + if (val >= G_MAXINT64 - step + 1) { + max -= step; + val -= step; } /* min must be MININT64 too as val >= max */ - if (val == G_MININT64) { - min++; - val++; + if (val <= G_MININT64 + step - 1) { + min += step; + val += step; } - gst_value_create_new_int64_range (dest, min, val - 1, val + 1, max); + if (dest) + gst_value_create_new_int64_range (dest, min, val - step, val + step, max, + step); } return TRUE; } @@ -2935,20 +3671,30 @@ gst_value_subtract_int64_range_int64_range (GValue * dest, { gint64 min1 = gst_value_get_int64_range_min (minuend); gint64 max1 = gst_value_get_int64_range_max (minuend); + gint64 step1 = gst_value_get_int64_range_step (minuend); gint64 min2 = gst_value_get_int64_range_min (subtrahend); gint64 max2 = gst_value_get_int64_range_max (subtrahend); + gint64 step2 = gst_value_get_int64_range_step (subtrahend); + gint64 step; + + if (step1 != step2) { + /* ENOIMPL */ + g_assert (FALSE); + return FALSE; + } + step = step1; - if (max2 == G_MAXINT64 && min2 == G_MININT64) { + if (max2 >= max1 && min2 <= min1) { return FALSE; - } else if (max2 == G_MAXINT64) { - return gst_value_create_new_int64_range (dest, min1, MIN (min2 - 1, max1), - 1, 0); - } else if (min2 == G_MININT64) { - return gst_value_create_new_int64_range (dest, MAX (max2 + 1, min1), max1, - 1, 0); + } else if (max2 >= max1) { + return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step, + max1), step, 0, step); + } else if (min2 <= min1) { + return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1), + max1, step, 0, step); } else { - return gst_value_create_new_int64_range (dest, min1, MIN (min2 - 1, max1), - MAX (max2 + 1, min1), max1); + return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step, + max1), MAX (max2 + step, min1), max1, step); } } @@ -2961,7 +3707,8 @@ gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend, gdouble val = g_value_get_double (minuend); if (val < min || val > max) { - gst_value_init_and_copy (dest, minuend); + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } return FALSE; @@ -2973,7 +3720,8 @@ gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend, { /* since we don't have open ranges, we cannot create a hole in * a double range. We return the original range */ - gst_value_init_and_copy (dest, minuend); + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } @@ -3004,6 +3752,9 @@ gst_value_subtract_double_range_double_range (GValue * dest, return FALSE; } + if (!dest) + return TRUE; + if (min1 < max1) { g_value_init (pv1, GST_TYPE_DOUBLE_RANGE); gst_value_set_double_range (pv1, min1, max1); @@ -3036,6 +3787,15 @@ gst_value_subtract_from_list (GValue * dest, const GValue * minuend, for (i = 0; i < size; i++) { const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i); + /* quicker version when we can discard the result */ + if (!dest) { + if (gst_value_subtract (NULL, cur, subtrahend)) { + ret = TRUE; + break; + } + continue; + } + if (gst_value_subtract (&subtraction, cur, subtrahend)) { if (!ret) { gst_value_init_and_copy (dest, &subtraction); @@ -3081,7 +3841,8 @@ gst_value_subtract_list (GValue * dest, const GValue * minuend, return FALSE; } } - gst_value_init_and_copy (dest, result); + if (dest) + gst_value_init_and_copy (dest, result); g_value_unset (result); return TRUE; } @@ -3102,7 +3863,8 @@ gst_value_subtract_fraction_fraction_range (GValue * dest, gst_value_compare_with_func (minuend, max, compare) == GST_VALUE_GREATER_THAN) { /* and the result is the value */ - gst_value_init_and_copy (dest, minuend); + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } } @@ -3115,7 +3877,8 @@ gst_value_subtract_fraction_range_fraction (GValue * dest, { /* since we don't have open ranges, we cannot create a hole in * a range. We return the original range */ - gst_value_init_and_copy (dest, minuend); + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } @@ -3166,6 +3929,9 @@ gst_value_subtract_fraction_range_fraction_range (GValue * dest, return FALSE; } + if (!dest) + return TRUE; + if (cmp1 == GST_VALUE_LESS_THAN) { g_value_init (pv1, GST_TYPE_FRACTION_RANGE); gst_value_set_fraction_range (pv1, min1, max1); @@ -3249,6 +4015,61 @@ gst_value_can_compare (const GValue * value1, const GValue * value2) return gst_value_get_compare_func (value1) != NULL; } +static gboolean +gst_value_list_equals_range (const GValue * list, const GValue * value) +{ + const GValue *first; + guint list_size, n; + + g_return_val_if_fail (G_IS_VALUE (list), FALSE); + g_return_val_if_fail (G_IS_VALUE (value), FALSE); + g_return_val_if_fail (GST_VALUE_HOLDS_LIST (list), FALSE); + + /* TODO: compare against an empty list ? No type though... */ + list_size = VALUE_LIST_SIZE (list); + if (list_size == 0) + return FALSE; + + /* compare the basic types - they have to match */ + first = VALUE_LIST_GET_VALUE (list, 0); +#define CHECK_TYPES(type,prefix) \ + (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value)) + if (CHECK_TYPES (INT, G)) { + const gint rmin = gst_value_get_int_range_min (value); + const gint rmax = gst_value_get_int_range_max (value); + const gint rstep = gst_value_get_int_range_step (value); + /* note: this will overflow for min 0 and max INT_MAX, but this + would only be equal to a list of INT_MAX elements, which seems + very unlikely */ + if (list_size != rmax / rstep - rmin / rstep + 1) + return FALSE; + for (n = 0; n < list_size; ++n) { + gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n)); + if (v < rmin || v > rmax || v % rstep) { + return FALSE; + } + } + return TRUE; + } else if (CHECK_TYPES (INT64, G)) { + const gint64 rmin = gst_value_get_int64_range_min (value); + const gint64 rmax = gst_value_get_int64_range_max (value); + const gint64 rstep = gst_value_get_int64_range_step (value); + GST_DEBUG ("List/range of int64s"); + if (list_size != rmax / rstep - rmin / rstep + 1) + return FALSE; + for (n = 0; n < list_size; ++n) { + gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n)); + if (v < rmin || v > rmax || v % rstep) + return FALSE; + } + return TRUE; + } +#undef CHECK_TYPES + + /* other combinations don't make sense for equality */ + return FALSE; +} + /** * gst_value_compare: * @value1: a value to compare @@ -3271,21 +4092,28 @@ gst_value_compare (const GValue * value1, const GValue * value2) g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN); g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN); - /* Special case: lists and scalar values - * "{ 1 }" and "1" are equal */ + /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal), + as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */ ltype = gst_value_list_get_type (); - if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype) - && gst_value_list_get_size (value1) == 1) { - const GValue *elt; + if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype)) { - elt = gst_value_list_get_value (value1, 0); - return gst_value_compare (elt, value2); - } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype) - && gst_value_list_get_size (value2) == 1) { - const GValue *elt; + if (gst_value_list_equals_range (value1, value2)) { + return GST_VALUE_EQUAL; + } else if (gst_value_list_get_size (value1) == 1) { + const GValue *elt; - elt = gst_value_list_get_value (value2, 0); - return gst_value_compare (elt, value1); + elt = gst_value_list_get_value (value1, 0); + return gst_value_compare (elt, value2); + } + } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype)) { + if (gst_value_list_equals_range (value2, value1)) { + return GST_VALUE_EQUAL; + } else if (gst_value_list_get_size (value2) == 1) { + const GValue *elt; + + elt = gst_value_list_get_value (value2, 0); + return gst_value_compare (elt, value1); + } } if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) @@ -3375,34 +4203,32 @@ gst_value_can_union (const GValue * value1, const GValue * value2) * * Creates a GValue corresponding to the union of @value1 and @value2. * - * Returns: always returns %TRUE + * Returns: TRUE if the union suceeded. */ -/* FIXME: change return type to 'void'? */ gboolean gst_value_union (GValue * dest, const GValue * value1, const GValue * value2) { - GstValueUnionInfo *union_info; + const GstValueUnionInfo *union_info; guint i, len; + GType type1, type2; g_return_val_if_fail (dest != NULL, FALSE); g_return_val_if_fail (G_IS_VALUE (value1), FALSE); g_return_val_if_fail (G_IS_VALUE (value2), FALSE); + g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2), + FALSE); len = gst_value_union_funcs->len; + type1 = G_VALUE_TYPE (value1); + type2 = G_VALUE_TYPE (value2); for (i = 0; i < len; i++) { union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i); - if (union_info->type1 == G_VALUE_TYPE (value1) && - union_info->type2 == G_VALUE_TYPE (value2)) { - if (union_info->func (dest, value1, value2)) { - return TRUE; - } + if (union_info->type1 == type1 && union_info->type2 == type2) { + return union_info->func (dest, value1, value2); } - if (union_info->type1 == G_VALUE_TYPE (value2) && - union_info->type2 == G_VALUE_TYPE (value1)) { - if (union_info->func (dest, value2, value1)) { - return TRUE; - } + if (union_info->type1 == type2 && union_info->type2 == type1) { + return union_info->func (dest, value2, value1); } } @@ -3410,11 +4236,10 @@ gst_value_union (GValue * dest, const GValue * value1, const GValue * value2) return TRUE; } -/** - * gst_value_register_union_func: +/* gst_value_register_union_func: (skip) * @type1: a type to union * @type2: another type to union - * @func: a function that implments creating a union between the two types + * @func: a function that implements creating a union between the two types * * Registers a union function that can create a union between #GValue items * of the type @type1 and @type2. @@ -3423,7 +4248,7 @@ gst_value_union (GValue * dest, const GValue * value1, const GValue * value2) * started, as gst_value_register_union_func() is not thread-safe and cannot * be used at the same time as gst_value_union() or gst_value_can_union(). */ -void +static void gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func) { GstValueUnionInfo union_info; @@ -3488,15 +4313,15 @@ gst_value_can_intersect (const GValue * value1, const GValue * value2) /** * gst_value_intersect: - * @dest: (out caller-allocates): a uninitialized #GValue that will hold the calculated - * intersection value + * @dest: (out caller-allocates) (transfer full): a uninitialized #GValue that will hold the calculated + * intersection value. May be NULL if the resulting set if not needed. * @value1: a value to intersect * @value2: another value to intersect * * Calculates the intersection of two values. If the values have * a non-empty intersection, the value representing the intersection - * is placed in @dest. If the intersection is non-empty, @dest is - * not modified. + * is placed in @dest, unless NULL. If the intersection is non-empty, + * @dest is not modified. * * Returns: TRUE if the intersection is non-empty */ @@ -3508,7 +4333,6 @@ gst_value_intersect (GValue * dest, const GValue * value1, guint i, len; GType ltype, type1, type2; - g_return_val_if_fail (dest != NULL, FALSE); g_return_val_if_fail (G_IS_VALUE (value1), FALSE); g_return_val_if_fail (G_IS_VALUE (value2), FALSE); @@ -3521,7 +4345,8 @@ gst_value_intersect (GValue * dest, const GValue * value1, return gst_value_intersect_list (dest, value2, value1); if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) { - gst_value_init_and_copy (dest, value1); + if (dest) + gst_value_init_and_copy (dest, value1); return TRUE; } @@ -3542,8 +4367,9 @@ gst_value_intersect (GValue * dest, const GValue * value1, return FALSE; } -/** - * gst_value_register_intersect_func: + + +/* gst_value_register_intersect_func: (skip) * @type1: the first type to intersect * @type2: the second type to intersect * @func: the intersection function @@ -3556,7 +4382,7 @@ gst_value_intersect (GValue * dest, const GValue * value1, * cannot be used at the same time as gst_value_intersect() or * gst_value_can_intersect(). */ -void +static void gst_value_register_intersect_func (GType type1, GType type2, GstValueIntersectFunc func) { @@ -3575,7 +4401,8 @@ gst_value_register_intersect_func (GType type1, GType type2, /** * gst_value_subtract: * @dest: (out caller-allocates): the destination value for the result if the - * subtraction is not empty + * subtraction is not empty. May be NULL, in which case the resulting set + * will not be computed, which can give a fair speedup. * @minuend: the value to subtract from * @subtrahend: the value to subtract * @@ -3592,7 +4419,6 @@ gst_value_subtract (GValue * dest, const GValue * minuend, guint i, len; GType ltype, mtype, stype; - g_return_val_if_fail (dest != NULL, FALSE); g_return_val_if_fail (G_IS_VALUE (minuend), FALSE); g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE); @@ -3616,7 +4442,8 @@ gst_value_subtract (GValue * dest, const GValue * minuend, } if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) { - gst_value_init_and_copy (dest, minuend); + if (dest) + gst_value_init_and_copy (dest, minuend); return TRUE; } @@ -3675,8 +4502,7 @@ gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend) return gst_value_can_compare (minuend, subtrahend); } -/** - * gst_value_register_subtract_func: +/* gst_value_register_subtract_func: (skip) * @minuend_type: type of the minuend * @subtrahend_type: type of the subtrahend * @func: function to use @@ -3688,15 +4514,17 @@ gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend) * started, as gst_value_register_subtract_func() is not thread-safe and * cannot be used at the same time as gst_value_subtract(). */ -void +static void gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type, GstValueSubtractFunc func) { GstValueSubtractInfo info; - /* one type must be unfixed, other subtractions can be done as comparisons */ - g_return_if_fail (!gst_type_is_fixed (minuend_type) - || !gst_type_is_fixed (subtrahend_type)); + /* one type must be unfixed, other subtractions can be done as comparisons, + * special case: bitmasks */ + if (minuend_type != GST_TYPE_BITMASK) + g_return_if_fail (!gst_type_is_fixed (minuend_type) + || !gst_type_is_fixed (subtrahend_type)); info.minuend = minuend_type; info.subtrahend = subtrahend_type; @@ -4308,52 +5136,6 @@ gst_value_compare_fraction (const GValue * value1, const GValue * value2) * GDate * *********/ -/** - * gst_value_set_date: - * @value: a GValue initialized to GST_TYPE_DATE - * @date: the date to set the value to - * - * Sets the contents of @value to coorespond to @date. The actual - * #GDate structure is copied before it is used. - */ -void -gst_value_set_date (GValue * value, const GDate * date) -{ - g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE); - g_return_if_fail (g_date_valid (date)); - - g_value_set_boxed (value, date); -} - -/** - * gst_value_get_date: - * @value: a GValue initialized to GST_TYPE_DATE - * - * Gets the contents of @value. - * - * Returns: (transfer none): the contents of @value - */ -const GDate * -gst_value_get_date (const GValue * value) -{ - g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL); - - return (const GDate *) g_value_get_boxed (value); -} - -static gpointer -gst_date_copy (gpointer boxed) -{ - const GDate *date = (const GDate *) boxed; - - if (!g_date_valid (date)) { - GST_WARNING ("invalid GDate"); - return NULL; - } - - return g_date_new_julian (g_date_get_julian (date)); -} - static gint gst_value_compare_date (const GValue * value1, const GValue * value2) { @@ -4510,6 +5292,209 @@ gst_value_transform_string_date (const GValue * src_value, GValue * dest_value) gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer); } + +/************ + * bitmask * + ************/ + +/* helper functions */ +static void +gst_value_init_bitmask (GValue * value) +{ + value->data[0].v_uint64 = 0; +} + +static void +gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value) +{ + dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; +} + +static gchar * +gst_value_collect_bitmask (GValue * value, guint n_collect_values, + GTypeCValue * collect_values, guint collect_flags) +{ + if (n_collect_values != 1) + return g_strdup_printf ("not enough value locations for `%s' passed", + G_VALUE_TYPE_NAME (value)); + + gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64); + + return NULL; +} + +static gchar * +gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values, + GTypeCValue * collect_values, guint collect_flags) +{ + guint64 *bitmask = collect_values[0].v_pointer; + + if (!bitmask) + return g_strdup_printf ("value for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + *bitmask = value->data[0].v_uint64; + + return NULL; +} + +/** + * gst_value_set_bitmask: + * @value: a GValue initialized to #GST_TYPE_FRACTION + * @bitmask: the bitmask + * + * Sets @value to the bitmask specified by @bitmask. + */ +void +gst_value_set_bitmask (GValue * value, guint64 bitmask) +{ + g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value)); + + value->data[0].v_uint64 = bitmask; +} + +/** + * gst_value_get_bitmask: + * @value: a GValue initialized to #GST_TYPE_FRACTION + * + * Gets the bitmask specified by @value. + * + * Returns: the bitmask. + */ +guint64 +gst_value_get_bitmask (const GValue * value) +{ + g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0); + + return value->data[0].v_uint64; +} + +static gchar * +gst_value_serialize_bitmask (const GValue * value) +{ + guint64 bitmask = value->data[0].v_uint64; + + return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask); +} + +static gboolean +gst_value_deserialize_bitmask (GValue * dest, const gchar * s) +{ + gchar *endptr = NULL; + guint64 val; + + if (G_UNLIKELY (s == NULL)) + return FALSE; + + if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest))) + return FALSE; + + val = g_ascii_strtoull (s, &endptr, 16); + if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL)) + return FALSE; + if (val == 0 && endptr == s) + return FALSE; + + gst_value_set_bitmask (dest, val); + + return TRUE; +} + +static void +gst_value_transform_bitmask_string (const GValue * src_value, + GValue * dest_value) +{ + dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value); +} + +static void +gst_value_transform_string_bitmask (const GValue * src_value, + GValue * dest_value) +{ + if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer)) + gst_value_set_bitmask (dest_value, 0); +} + +static void +gst_value_transform_uint64_bitmask (const GValue * src_value, + GValue * dest_value) +{ + dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; +} + +static void +gst_value_transform_bitmask_uint64 (const GValue * src_value, + GValue * dest_value) +{ + dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; +} + +static gboolean +gst_value_intersect_bitmask_bitmask (GValue * dest, const GValue * src1, + const GValue * src2) +{ + guint64 s1, s2; + + s1 = gst_value_get_bitmask (src1); + s2 = gst_value_get_bitmask (src2); + + if (dest) { + g_value_init (dest, GST_TYPE_BITMASK); + gst_value_set_bitmask (dest, s1 & s2); + } + + return TRUE; +} + +static gboolean +gst_value_union_bitmask_bitmask (GValue * dest, const GValue * src1, + const GValue * src2) +{ + guint64 s1, s2; + + s1 = gst_value_get_bitmask (src1); + s2 = gst_value_get_bitmask (src2); + + g_value_init (dest, GST_TYPE_BITMASK); + gst_value_set_bitmask (dest, s1 | s2); + + return TRUE; +} + +static gboolean +gst_value_subtract_bitmask_bitmask (GValue * dest, + const GValue * minuend, const GValue * subtrahend) +{ + guint64 m, s, r; + + g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (minuend), FALSE); + g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (subtrahend), FALSE); + + m = minuend->data[0].v_uint64; + s = subtrahend->data[0].v_uint64; + r = m & (~s); + + if (dest) { + g_value_init (dest, GST_TYPE_BITMASK); + gst_value_set_bitmask (dest, r); + } + return (r != 0); +} + +static gint +gst_value_compare_bitmask (const GValue * value1, const GValue * value2) +{ + guint64 v1, v2; + + v1 = value1->data[0].v_uint64; + v2 = value2->data[0].v_uint64; + + if (v1 == v2) + return GST_VALUE_EQUAL; + + return GST_VALUE_UNORDERED; +} + static void gst_value_transform_object_string (const GValue * src_value, GValue * dest_value) @@ -4565,7 +5550,7 @@ GType gst_ ## type ## _get_type (void) \ static const GTypeValueTable _gst_int_range_value_table = { gst_value_init_int_range, - NULL, + gst_value_free_int_range, gst_value_copy_int_range, NULL, (char *) "ii", @@ -4578,7 +5563,7 @@ FUNC_VALUE_GET_TYPE (int_range, "GstIntRange"); static const GTypeValueTable _gst_int64_range_value_table = { gst_value_init_int64_range, - NULL, + gst_value_free_int64_range, gst_value_copy_int64_range, NULL, (char *) "qq", @@ -4654,42 +5639,25 @@ static const GTypeValueTable _gst_fraction_value_table = { FUNC_VALUE_GET_TYPE (fraction, "GstFraction"); +G_DEFINE_BOXED_TYPE (GstDateTime, gst_date_time, + (GBoxedCopyFunc) gst_date_time_ref, (GBoxedFreeFunc) gst_date_time_unref); -GType -gst_date_get_type (void) -{ - static GType gst_date_type = 0; - - if (G_UNLIKELY (gst_date_type == 0)) { - /* FIXME 0.11: we require GLib 2.8 already - * Not using G_TYPE_DATE here on purpose, even if we could - * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the - * serialised strings to have different type strings depending - * on what version is used, so FIXME when we require GLib-2.8 */ - gst_date_type = g_boxed_type_register_static ("GstDate", - (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free); - } - - return gst_date_type; -} - -GType -gst_date_time_get_type (void) -{ - static GType gst_date_time_type = 0; - - if (G_UNLIKELY (gst_date_time_type == 0)) { - gst_date_time_type = g_boxed_type_register_static ("GstDateTime", - (GBoxedCopyFunc) gst_date_time_ref, - (GBoxedFreeFunc) gst_date_time_unref); - } +static const GTypeValueTable _gst_bitmask_value_table = { + gst_value_init_bitmask, + NULL, + gst_value_copy_bitmask, + NULL, + (char *) "q", + gst_value_collect_bitmask, + (char *) "p", + gst_value_lcopy_bitmask +}; - return gst_date_time_type; -} +FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask"); void -_gst_value_initialize (void) +_priv_gst_value_initialize (void) { gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable)); gst_value_hash = g_hash_table_new (NULL, NULL); @@ -4821,6 +5789,17 @@ _gst_value_initialize (void) static GstValueTable gst_value = { 0, NULL, + gst_value_serialize_segment, + gst_value_deserialize_segment, + }; + + gst_value.type = GST_TYPE_SEGMENT; + gst_value_register (&gst_value); + } + { + static GstValueTable gst_value = { + 0, + NULL, gst_value_serialize_structure, gst_value_deserialize_structure, }; @@ -4836,7 +5815,7 @@ _gst_value_initialize (void) gst_value_deserialize_date, }; - gst_value.type = gst_date_get_type (); + gst_value.type = G_TYPE_DATE; gst_value_register (&gst_value); } { @@ -4851,6 +5830,18 @@ _gst_value_initialize (void) gst_value_register (&gst_value); } + { + static GstValueTable gst_value = { + 0, + gst_value_compare_bitmask, + gst_value_serialize_bitmask, + gst_value_deserialize_bitmask, + }; + + gst_value.type = gst_bitmask_get_type (); + gst_value_register (&gst_value); + } + REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double); REGISTER_SERIALIZATION (G_TYPE_FLOAT, float); @@ -4895,12 +5886,20 @@ _gst_value_initialize (void) gst_value_transform_double_fraction); g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION, gst_value_transform_float_fraction); - g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING, + g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING, gst_value_transform_date_string); - g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE, + g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE, gst_value_transform_string_date); g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING, gst_value_transform_object_string); + g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64, + gst_value_transform_bitmask_uint64); + g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING, + gst_value_transform_bitmask_string); + g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK, + gst_value_transform_uint64_bitmask); + g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK, + gst_value_transform_string_bitmask); gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE, gst_value_intersect_int_int_range); @@ -4921,6 +5920,8 @@ _gst_value_initialize (void) gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION_RANGE, gst_value_intersect_fraction_range_fraction_range); + gst_value_register_intersect_func (GST_TYPE_BITMASK, + GST_TYPE_BITMASK, gst_value_intersect_bitmask_bitmask); gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE, gst_value_subtract_int_int_range); @@ -4940,7 +5941,6 @@ _gst_value_initialize (void) gst_value_subtract_double_range_double); gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range); - gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, gst_value_subtract_fraction_fraction_range); gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION, @@ -4948,6 +5948,8 @@ _gst_value_initialize (void) gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION_RANGE, gst_value_subtract_fraction_range_fraction_range); + gst_value_register_subtract_func (GST_TYPE_BITMASK, + GST_TYPE_BITMASK, gst_value_subtract_bitmask_bitmask); /* see bug #317246, #64994, #65041 */ { @@ -4960,6 +5962,8 @@ _gst_value_initialize (void) gst_value_union_int_int_range); gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE, gst_value_union_int_range_int_range); + gst_value_register_union_func (GST_TYPE_BITMASK, + GST_TYPE_BITMASK, gst_value_union_bitmask_bitmask); #if 0 /* Implement these if needed */