GstValueSubtractFunc func;
};
+struct _GstFlagSetClass
+{
+ GTypeClass parent;
+ GType flags_type; /* Type of the GFlags this flagset carries (can be 0) */
+};
+
+typedef struct _GstFlagSetClass GstFlagSetClass;
+
#define FUNDAMENTAL_TYPE_ID_MAX \
(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT)
#define FUNDAMENTAL_TYPE_ID(type) \
continue;
v2 = &g_array_index (array2, GValue, j);
if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
- /* mark item as removed now that we found it in array2 and
+ /* mark item as removed now that we found it in array2 and
* decrement the number of remaining items in array2. */
removed[j] = 1;
to_remove--;
/* we just compare the value here */
static gint
-gst_value_compare_flags (const GValue * value1, const GValue * value2)
+gst_value_compare_gflags (const GValue * value1, const GValue * value2)
{
guint fl1, fl2;
GFlagsClass *klass1 =
/* the different flags are serialized separated with a + */
static gchar *
-gst_value_serialize_flags (const GValue * value)
+gst_value_serialize_gflags (const GValue * value)
{
guint flags;
GFlagsValue *fl;
}
static gboolean
-gst_value_deserialize_flags (GValue * dest, const gchar * s)
+gst_value_gflags_str_to_flags (GFlagsClass * klass, const gchar * s,
+ guint * out_flags, guint * out_mask)
{
GFlagsValue *fl;
- gchar *endptr = NULL;
- GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
- gchar **split;
- guint flags;
- gint i;
+ gchar delimiter;
+ const gchar *pos = NULL;
+ const gchar *next;
+ gchar *cur_str, *endptr;
+
+ guint flags = 0;
+ guint mask = 0;
+ guint val;
g_return_val_if_fail (klass, FALSE);
- /* split into parts delimited with + */
- split = g_strsplit (s, "+", 0);
+ /* split into parts delimited with + or / and
+ * compose the set of flags and mask. */
+ pos = s;
- flags = 0;
- i = 0;
- /* loop over each part */
- while (split[i]) {
- if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
- if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
- gint val = strtol (split[i], &endptr, 0);
+ if (*pos == '\0')
+ goto done; /* Empty string, nothing to do */
- /* just or numeric value */
- if (endptr && *endptr == '\0') {
- flags |= val;
- }
- }
+ /* As a special case if the first char isn't a delimiter, assume
+ * it's a '+' - for GFlags strings, which don't start with a
+ * delimiter, while GFlagSet always will */
+ if (*pos == '/' || *pos == '+') {
+ delimiter = *pos;
+ pos++;
+ } else {
+ delimiter = '+';
+ }
+
+ do {
+ /* Find the next delimiter */
+ next = pos;
+ while (*next != '\0' && *next != '+' && *next != '/')
+ next++;
+ cur_str = g_strndup (pos, next - pos);
+
+ if ((fl = g_flags_get_value_by_name (klass, cur_str)))
+ val = fl->value;
+ else if ((fl = g_flags_get_value_by_nick (klass, cur_str)))
+ val = fl->value;
+ else {
+ val = strtoul (cur_str, &endptr, 0);
+ /* direct numeric value */
+ if (endptr == NULL || *endptr != '\0')
+ val = 0; /* Invalid numeric, ignore it */
}
- if (fl) {
- flags |= fl->value;
+ g_free (cur_str);
+
+ if (val) {
+ mask |= val;
+ if (delimiter == '+')
+ flags |= val;
}
- i++;
+
+ /* Advance to the next delimiter */
+ pos = next;
+ delimiter = *pos;
+ pos++;
+ } while (delimiter != '\0');
+
+done:
+ if (out_flags)
+ *out_flags = flags;
+ if (out_mask)
+ *out_mask = mask;
+
+ return TRUE;
+}
+
+
+static gboolean
+gst_value_deserialize_gflags (GValue * dest, const gchar * s)
+{
+ GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
+ gboolean res = FALSE;
+ guint flags = 0;
+
+ if (gst_value_gflags_str_to_flags (klass, s, &flags, NULL)) {
+ g_value_set_flags (dest, flags);
+ res = TRUE;
}
- g_strfreev (split);
+
g_type_class_unref (klass);
- g_value_set_flags (dest, flags);
- return TRUE;
+ return res;
}
/****************
return FALSE;
}
+static gboolean
+gst_value_union_flagset_flagset (GValue * dest, const GValue * src1,
+ const GValue * src2)
+{
+ /* We can union 2 flag sets where they do not disagree on
+ * required (masked) flag bits */
+ guint64 f1, f2;
+ guint64 m1, m2;
+
+ g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
+ g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
+
+ f1 = src1->data[0].v_uint;
+ f2 = src2->data[0].v_uint;
+
+ m1 = src1->data[1].v_uint;
+ m2 = src2->data[1].v_uint;
+
+ /* Can't union if masked bits disagree */
+ if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
+ return FALSE;
+
+ if (dest) {
+ g_value_init (dest, GST_TYPE_FLAG_SET);
+ /* Copy masked bits from src2 to src1 */
+ f1 &= ~m2;
+ f1 |= (f2 & m2);
+ m1 |= m2;
+ gst_value_set_flagset (dest, f1, m1);
+ }
+
+ return TRUE;
+}
+
/****************
* intersection *
****************/
return FALSE;
}
+/* Two flagsets intersect if the masked bits in both
+ * flagsets are exactly equal */
+static gboolean
+gst_value_intersect_flagset_flagset (GValue * dest,
+ const GValue * src1, const GValue * src2)
+{
+ guint f1, f2;
+ guint m1, m2;
+ GType type1, type2, flagset_type;
+
+ g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
+ g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
+
+ f1 = src1->data[0].v_uint;
+ f2 = src2->data[0].v_uint;
+
+ m1 = src1->data[1].v_uint;
+ m2 = src2->data[1].v_uint;
+
+ /* Don't intersect if masked bits disagree */
+ if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
+ return FALSE;
+
+ /* Allow intersection with the generic FlagSet type, on one
+ * side, but not 2 different subtypes - that makes no sense */
+ type1 = G_VALUE_TYPE (src1);
+ type2 = G_VALUE_TYPE (src2);
+ flagset_type = GST_TYPE_FLAG_SET;
+
+ if (type1 != type2 && type1 != flagset_type && type2 != flagset_type)
+ return FALSE;
+
+ if (dest) {
+ GType dest_type;
+
+ /* Prefer an output type that matches a sub-type,
+ * rather than the generic type */
+ if (type1 != flagset_type)
+ dest_type = type1;
+ else
+ dest_type = type2;
+
+ g_value_init (dest, dest_type);
+
+ /* The compatible set is all the bits from src1 that it
+ * cares about and all the bits from src2 that it cares
+ * about. */
+ dest->data[0].v_uint = (f1 & m1) | (f2 & m2);
+ dest->data[1].v_uint = m1 | m2;
+ }
+
+ return TRUE;
+}
+
/***************
* subtraction *
***************/
*
* Compares @value1 and @value2 using the @compare function. Works like
* gst_value_compare() but allows to save time determining the compare function
- * a multiple times.
+ * a multiple times.
*
* Returns: comparison result
*/
return intersect_info->func (dest, value2, value1);
}
}
+
+ /* Failed to find a direct intersection, check if these are
+ * GstFlagSet sub-types. */
+ if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
+ GST_VALUE_HOLDS_FLAG_SET (value2))) {
+ return gst_value_intersect_flagset_flagset (dest, value1, value2);
+ }
+
return FALSE;
}
return FALSE;
}
return TRUE;
+ } else if (GST_VALUE_HOLDS_FLAG_SET (value)) {
+ /* Flagsets are only fixed if there are no 'don't care' bits */
+ return (gst_value_get_flagset_mask (value) == GST_FLAG_SET_MASK_EXACT);
}
return gst_type_is_fixed (type);
}
g_value_unset (dest);
return res;
+ } else if (GST_VALUE_HOLDS_FLAG_SET (src)) {
+ guint flags;
+
+ if (gst_value_get_flagset_mask (src) == GST_FLAG_SET_MASK_EXACT)
+ return FALSE; /* Already fixed */
+
+ flags = gst_value_get_flagset_flags (src);
+ g_value_init (dest, G_VALUE_TYPE (src));
+ gst_value_set_flagset (dest, flags, GST_FLAG_SET_MASK_EXACT);
+ return TRUE;
} else {
return FALSE;
}
return GST_VALUE_UNORDERED;
}
+/************
+ * flagset *
+ ************/
+
+/* helper functions */
+static void
+gst_value_init_flagset (GValue * value)
+{
+ value->data[0].v_uint = 0;
+ value->data[1].v_uint = 0;
+}
+
+static void
+gst_value_copy_flagset (const GValue * src_value, GValue * dest_value)
+{
+ dest_value->data[0].v_uint = src_value->data[0].v_uint;
+ dest_value->data[1].v_uint = src_value->data[1].v_uint;
+}
+
+static gchar *
+gst_value_collect_flagset (GValue * value, guint n_collect_values,
+ GTypeCValue * collect_values, guint collect_flags)
+{
+ if (n_collect_values != 2)
+ return g_strdup_printf ("not enough value locations for `%s' passed",
+ G_VALUE_TYPE_NAME (value));
+
+ gst_value_set_flagset (value,
+ (guint) collect_values[0].v_int, (guint) collect_values[1].v_int);
+
+ return NULL;
+}
+
+static gchar *
+gst_value_lcopy_flagset (const GValue * value, guint n_collect_values,
+ GTypeCValue * collect_values, guint collect_flags)
+{
+ guint *flags = collect_values[0].v_pointer;
+ guint *mask = collect_values[1].v_pointer;
+
+ *flags = value->data[0].v_uint;
+ *mask = value->data[1].v_uint;
+
+ return NULL;
+}
+
+/**
+ * gst_value_set_flagset:
+ * @value: a GValue initialized to #GST_TYPE_FLAGS
+ * @flags: The value of the flags set or unset
+ * @mask: The mask indicate which flags bits must match for comparisons
+ *
+ * Sets @value to the flags and mask values provided in @flags and @mask.
+ * The @flags value indicates the values of flags, the @mask represents
+ * which bits in the flag value have been set, and which are "don't care"
+ *
+ * Since: 1.6
+ */
+void
+gst_value_set_flagset (GValue * value, guint flags, guint mask)
+{
+ g_return_if_fail (GST_VALUE_HOLDS_FLAG_SET (value));
+
+ /* Normalise and only keep flags mentioned in the mask */
+ value->data[0].v_uint = flags & mask;
+ value->data[1].v_uint = mask;
+}
+
+/**
+ * gst_value_get_flagset_flags:
+ * @value: a GValue initialized to #GST_TYPE_FLAG_SET
+ *
+ * Retrieve the flags field of a GstFlagSet @value.
+ *
+ * Returns: the flags field of the flagset instance.
+ *
+ * Since: 1.6
+ */
+guint
+gst_value_get_flagset_flags (const GValue * value)
+{
+ g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 0);
+
+ return value->data[0].v_uint;
+}
+
+/**
+ * gst_value_get_flagset_mask:
+ * @value: a GValue initialized to #GST_TYPE_FLAG_SET
+ *
+ * Retrieve the mask field of a GstFlagSet @value.
+ *
+ * Returns: the mask field of the flagset instance.
+ *
+ * Since: 1.6
+ */
+guint
+gst_value_get_flagset_mask (const GValue * value)
+{
+ g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 1);
+
+ return value->data[1].v_uint;
+}
+
+static gchar *
+gst_value_serialize_flagset (const GValue * value)
+{
+ guint flags = value->data[0].v_uint;
+ guint mask = value->data[1].v_uint;
+ GstFlagSetClass *set_klass =
+ (GstFlagSetClass *) g_type_class_ref (G_VALUE_TYPE (value));
+ gchar *result;
+
+ result = g_strdup_printf ("%x:%x", flags, mask);
+
+ /* If this flag set class has an associated GFlags GType, and some
+ * bits in the mask, serialize the bits in human-readable form to
+ * aid debugging */
+ if (mask && set_klass->flags_type) {
+ GFlagsClass *flags_klass =
+ (GFlagsClass *) (g_type_class_ref (set_klass->flags_type));
+ GFlagsValue *fl;
+ gchar *tmp;
+ gboolean first = TRUE;
+
+ g_return_val_if_fail (flags_klass, NULL);
+
+ /* some bits in the mask are set, so serialize one by one, according
+ * to whether that bit is set or cleared in the flags value */
+ while (mask) {
+ fl = g_flags_get_first_value (flags_klass, mask);
+ if (fl == NULL) {
+ /* No more bits match in the flags mask - time to stop */
+ mask = 0;
+ break;
+ }
+
+ tmp = g_strconcat (result,
+ first ? ":" : "",
+ (flags & fl->value) ? "+" : "/", fl->value_nick, NULL);
+ g_free (result);
+ result = tmp;
+ first = FALSE;
+
+ /* clear flag */
+ mask &= ~fl->value;
+ }
+ g_type_class_unref (flags_klass);
+
+ }
+ g_type_class_unref (set_klass);
+
+ return result;
+}
+
+static gboolean
+gst_value_deserialize_flagset (GValue * dest, const gchar * s)
+{
+ gboolean res = FALSE;
+ guint flags, mask;
+ gchar *cur, *next;
+
+ if (G_UNLIKELY (s == NULL))
+ return FALSE;
+
+ if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FLAG_SET (dest)))
+ return FALSE;
+
+ /* Flagset strings look like %x:%x - hex flags : hex bitmask,
+ * 32-bit each, or like a concatenated list of flag nicks,
+ * with either '+' or '/' in front. The first form
+ * may optionally be followed by ':' and a set of text flag descriptions
+ * for easier debugging */
+
+ /* Try and interpret as hex form first, as it's the most efficient */
+ /* Read the flags first */
+ flags = strtoul (s, &next, 16);
+ if (G_UNLIKELY ((flags == 0 && errno == EINVAL) || s == next))
+ goto try_as_flags_string;
+ /* Next char should be a colon */
+ if (next[0] == ':')
+ next++;
+
+ /* Read the mask */
+ cur = next;
+ mask = strtoul (cur, &next, 16);
+ if (G_UNLIKELY ((mask == 0 && errno == EINVAL) || cur == next))
+ goto try_as_flags_string;
+
+ /* Next char should be NULL terminator, or a ':' */
+ if (G_UNLIKELY (next[0] != 0 && next[0] != ':'))
+ goto try_as_flags_string;
+
+ res = TRUE;
+
+try_as_flags_string:
+
+ if (!res) {
+ const gchar *set_class = g_type_name (G_VALUE_TYPE (dest));
+ GFlagsClass *flags_klass = NULL;
+ const gchar *end;
+
+ if (g_str_equal (set_class, "GstFlagSet"))
+ goto done; /* There's no hope to parse a generic flag set */
+
+ /* Flags class is the FlagSet class with 'Set' removed from the end */
+ end = g_strrstr (set_class, "Set");
+
+ if (end != NULL) {
+ gchar *class_name = g_strndup (set_class, end - set_class);
+ GType flags_type = g_type_from_name (class_name);
+
+ g_free (class_name);
+
+ if (flags_type != 0)
+ flags_klass = g_type_class_ref (flags_type);
+ }
+
+ if (flags_klass) {
+ res = gst_value_gflags_str_to_flags (flags_klass, s, &flags, &mask);
+ g_type_class_unref (flags_klass);
+ }
+ }
+
+ if (res)
+ gst_value_set_flagset (dest, flags, mask);
+done:
+ return res;
+
+}
+
+static void
+gst_value_transform_flagset_string (const GValue * src_value,
+ GValue * dest_value)
+{
+ dest_value->data[0].v_pointer = gst_value_serialize_flagset (src_value);
+}
+
+static void
+gst_value_transform_string_flagset (const GValue * src_value,
+ GValue * dest_value)
+{
+ if (!gst_value_deserialize_flagset (dest_value, src_value->data[0].v_pointer)) {
+ /* If the deserialize fails, ensure we leave the flags in a
+ * valid, if incorrect, state */
+ gst_value_set_flagset (dest_value, 0, 0);
+ }
+}
+
+static gint
+gst_value_compare_flagset (const GValue * value1, const GValue * value2)
+{
+ guint v1, v2;
+ guint m1, m2;
+
+ v1 = value1->data[0].v_uint;
+ v2 = value2->data[0].v_uint;
+
+ m1 = value1->data[1].v_uint;
+ m2 = value2->data[1].v_uint;
+
+ if (v1 == v2 && m1 == m2)
+ return GST_VALUE_EQUAL;
+
+ return GST_VALUE_UNORDERED;
+}
/***********************
* GstAllocationParams *
}
static GTypeInfo _info = {
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- 0,
- NULL,
- NULL,
+ 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL,
};
static GTypeFundamentalInfo _finfo = {
0
};
-#define FUNC_VALUE_GET_TYPE(type, name) \
+#define FUNC_VALUE_GET_TYPE_CLASSED(type, name, csize, flags) \
GType _gst_ ## type ## _type = 0; \
\
GType gst_ ## type ## _get_type (void) \
\
if (g_once_init_enter (&gst_ ## type ## _type)) { \
GType _type; \
+ _info.class_size = csize; \
+ _finfo.type_flags = flags; \
_info.value_table = & _gst_ ## type ## _value_table; \
_type = g_type_register_fundamental ( \
g_type_fundamental_next (), \
name, &_info, &_finfo, 0); \
- _gst_ ## type ## _type = _type; \
+ _gst_ ## type ## _type = _type; \
g_once_init_leave(&gst_ ## type ## _type, _type); \
} \
\
return gst_ ## type ## _type; \
}
+#define FUNC_VALUE_GET_TYPE(type, name) \
+ FUNC_VALUE_GET_TYPE_CLASSED(type, name, 0, 0)
+
static const GTypeValueTable _gst_int_range_value_table = {
gst_value_init_int_range,
NULL,
gst_value_copy_int_range,
NULL,
(char *) "ii",
- gst_value_collect_int_range,
- (char *) "pp",
- gst_value_lcopy_int_range
+ gst_value_collect_int_range, (char *) "pp", gst_value_lcopy_int_range
};
FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
NULL,
(char *) "qq",
gst_value_collect_int64_range,
- (char *) "pp",
- gst_value_lcopy_int64_range
+ (char *) "pp", gst_value_lcopy_int64_range
};
FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
NULL,
(char *) "dd",
gst_value_collect_double_range,
- (char *) "pp",
- gst_value_lcopy_double_range
+ (char *) "pp", gst_value_lcopy_double_range
};
FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
NULL,
(char *) "iiii",
gst_value_collect_fraction_range,
- (char *) "pppp",
- gst_value_lcopy_fraction_range
+ (char *) "pppp", gst_value_lcopy_fraction_range
};
FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
gst_value_list_or_array_peek_pointer,
(char *) "p",
gst_value_collect_list_or_array,
- (char *) "p",
- gst_value_lcopy_list_or_array
+ (char *) "p", gst_value_lcopy_list_or_array
};
FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
gst_value_list_or_array_peek_pointer,
(char *) "p",
gst_value_collect_list_or_array,
- (char *) "p",
- gst_value_lcopy_list_or_array
+ (char *) "p", gst_value_lcopy_list_or_array
};
FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
gst_value_copy_fraction,
NULL,
(char *) "ii",
- gst_value_collect_fraction,
- (char *) "pp",
- gst_value_lcopy_fraction
+ gst_value_collect_fraction, (char *) "pp", gst_value_lcopy_fraction
};
FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
gst_value_copy_bitmask,
NULL,
(char *) "q",
- gst_value_collect_bitmask,
- (char *) "p",
- gst_value_lcopy_bitmask
+ gst_value_collect_bitmask, (char *) "p", gst_value_lcopy_bitmask
};
FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
+static const GTypeValueTable _gst_flagset_value_table = {
+ gst_value_init_flagset,
+ NULL,
+ gst_value_copy_flagset,
+ NULL,
+ (char *) "ii",
+ gst_value_collect_flagset, (char *) "pp", gst_value_lcopy_flagset
+};
+
+FUNC_VALUE_GET_TYPE_CLASSED (flagset, "GstFlagSet",
+ sizeof (GstFlagSetClass), G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE);
+
GType
gst_g_thread_get_type (void)
{
if (g_once_init_enter (&type_id)) {
GType tmp =
g_boxed_type_register_static (g_intern_static_string ("GstGThread"),
- (GBoxedCopyFunc) g_thread_ref,
- (GBoxedFreeFunc) g_thread_unref);
+ (GBoxedCopyFunc) g_thread_ref, (GBoxedFreeFunc) g_thread_unref);
g_once_init_leave (&type_id, tmp);
}
gst_value_register (&gst_value); \
} G_STMT_END
-static const gint GST_VALUE_TABLE_DEFAULT_SIZE = 32;
-static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 2;
-static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 9;
+/* These initial sizes are used for the tables
+ * below, and save a couple of reallocs at startup */
+static const gint GST_VALUE_TABLE_DEFAULT_SIZE = 33;
+static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 3;
+static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 10;
static const gint GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE = 12;
void
REGISTER_SERIALIZATION (gst_date_time_get_type (), date_time);
REGISTER_SERIALIZATION (gst_bitmask_get_type (), bitmask);
REGISTER_SERIALIZATION (gst_structure_get_type (), structure);
+ REGISTER_SERIALIZATION (gst_flagset_get_type (), flagset);
REGISTER_SERIALIZATION_NO_COMPARE (gst_segment_get_type (), segment);
REGISTER_SERIALIZATION_NO_COMPARE (gst_caps_features_get_type (),
REGISTER_SERIALIZATION_CONST (G_TYPE_BOOLEAN, boolean);
REGISTER_SERIALIZATION_CONST (G_TYPE_ENUM, enum);
- REGISTER_SERIALIZATION_CONST (G_TYPE_FLAGS, flags);
+ REGISTER_SERIALIZATION_CONST (G_TYPE_FLAGS, gflags);
REGISTER_SERIALIZATION_CONST (G_TYPE_INT, int);
g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
gst_value_transform_string_bitmask);
+ g_value_register_transform_func (GST_TYPE_FLAG_SET, G_TYPE_STRING,
+ gst_value_transform_flagset_string);
+ g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FLAG_SET,
+ gst_value_transform_string_flagset);
+
gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
gst_value_intersect_int_int_range);
gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
gst_value_intersect_int_range_int_range);
gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
gst_value_intersect_int64_int64_range);
- gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
- gst_value_intersect_int64_range_int64_range);
+ gst_value_register_intersect_func (GST_TYPE_INT64_RANGE,
+ GST_TYPE_INT64_RANGE, gst_value_intersect_int64_range_int64_range);
gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
gst_value_intersect_double_double_range);
gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
- gst_value_register_intersect_func (GST_TYPE_ARRAY,
- GST_TYPE_ARRAY, gst_value_intersect_array);
- gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
- gst_value_intersect_fraction_fraction_range);
+ gst_value_register_intersect_func (GST_TYPE_ARRAY, GST_TYPE_ARRAY,
+ gst_value_intersect_array);
+ gst_value_register_intersect_func (GST_TYPE_FRACTION,
+ GST_TYPE_FRACTION_RANGE, gst_value_intersect_fraction_fraction_range);
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_FLAG_SET, GST_TYPE_FLAG_SET,
+ gst_value_intersect_flagset_flagset);
gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
gst_value_subtract_int_int_range);
gst_value_subtract_int64_int64_range);
gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
gst_value_subtract_int64_range_int64);
- gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
- gst_value_subtract_int64_range_int64_range);
+ gst_value_register_subtract_func (GST_TYPE_INT64_RANGE,
+ GST_TYPE_INT64_RANGE, gst_value_subtract_int64_range_int64_range);
gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
gst_value_subtract_double_double_range);
gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
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,
- gst_value_subtract_fraction_range_fraction);
+ 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, gst_value_subtract_fraction_range_fraction);
gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
GST_TYPE_FRACTION_RANGE,
gst_value_subtract_fraction_range_fraction_range);
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_FLAG_SET, GST_TYPE_FLAG_SET,
+ gst_value_union_flagset_flagset);
#if GST_VERSION_NANO == 1
/* If building from git master, check starting array sizes matched actual size
GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
#endif
}
+
+static void
+gst_flagset_class_init (gpointer g_class, gpointer class_data)
+{
+ GstFlagSetClass *f_class = (GstFlagSetClass *) (g_class);
+ f_class->flags_type = (GType) GPOINTER_TO_SIZE (class_data);
+}
+
+/**
+ * gst_flagset_register:
+ * @flags_type: a #GType of a #G_TYPE_FLAGS type.
+ *
+ * Create a new sub-class of #GST_TYPE_FLAG_SET
+ * which will pretty-print the human-readable flags
+ * when serializing, for easier debugging.
+ *
+ * Since: 1.6
+ */
+GType
+gst_flagset_register (GType flags_type)
+{
+ GTypeInfo info = {
+ sizeof (GstFlagSetClass),
+ NULL, NULL,
+ (GClassInitFunc) gst_flagset_class_init,
+ NULL, GSIZE_TO_POINTER (flags_type), 0, 0, NULL, NULL
+ };
+ GType t;
+ gchar *class_name;
+
+ g_return_val_if_fail (G_TYPE_IS_FLAGS (flags_type), 0);
+
+ class_name = g_strdup_printf ("%sSet", g_type_name (flags_type));
+
+ t = g_type_register_static (GST_TYPE_FLAG_SET,
+ g_intern_string (class_name), &info, 0);
+ g_free (class_name);
+
+ return t;
+}
GST_END_TEST;
+static void
+check_flagset_mask_serialisation (GValue * value, guint test_flags,
+ guint test_mask)
+{
+ gchar *string;
+ gst_value_set_flagset (value, test_flags, test_mask);
+
+ /* Normalise our test flags against the mask now for easier testing,
+ * as that's what we expect to get back from the flagset after it
+ * normalises internally */
+ test_flags &= test_mask;
+
+ /* Check the values got stored correctly */
+ fail_unless (gst_value_get_flagset_flags (value) == test_flags,
+ "resulting flags value is 0x%u, not 0x%x",
+ gst_value_get_flagset_flags (value), test_flags);
+ fail_unless (gst_value_get_flagset_mask (value) == test_mask,
+ "resulting mask is 0x%u, not 0x%x",
+ gst_value_get_flagset_mask (value), test_mask);
+
+ string = gst_value_serialize (value);
+ fail_if (string == NULL, "could not serialize flagset");
+
+ GST_DEBUG ("Serialized flagset to: %s", string);
+
+ fail_unless (gst_value_deserialize (value, string),
+ "could not deserialize %s", string);
+
+ fail_unless (gst_value_get_flagset_flags (value) == test_flags,
+ "resulting flags value is 0x%u, not 0x%x, for string %s",
+ gst_value_get_flagset_flags (value), test_flags, string);
+
+ fail_unless (gst_value_get_flagset_mask (value) == test_mask,
+ "resulting mask is 0x%u, not 0x%x, for string %s",
+ gst_value_get_flagset_mask (value), test_mask, string);
+
+ g_free (string);
+}
+
+GST_START_TEST (test_flagset)
+{
+ GValue value = G_VALUE_INIT;
+ GValue value2 = G_VALUE_INIT;
+ GValue dest = G_VALUE_INIT;
+ gchar *string;
+ GType test_flagset_type;
+ guint test_flags, test_mask;
+
+ /* Test serialisation of abstract type */
+ g_value_init (&value, GST_TYPE_FLAG_SET);
+
+ test_flags = 0xf1f1;
+ test_mask = 0xffff;
+
+ gst_value_set_flagset (&value, test_flags, test_mask);
+ string = gst_value_serialize (&value);
+ fail_if (string == NULL, "could not serialize flagset");
+
+ fail_unless (gst_value_deserialize (&value, string),
+ "could not deserialize %s", string);
+
+ fail_unless (gst_value_get_flagset_flags (&value) == test_flags,
+ "resulting value is 0x%u, not 0x%x, for string %s",
+ gst_value_get_flagset_flags (&value), test_flags, string);
+
+ fail_unless (gst_value_get_flagset_mask (&value) == test_mask,
+ "resulting value is 0x%u, not 0x%x, for string %s",
+ gst_value_get_flagset_mask (&value), test_mask, string);
+
+ g_free (string);
+ g_value_unset (&value);
+
+ /* Check we can't wrap a random non-flags type */
+ ASSERT_CRITICAL (gst_flagset_register (GST_TYPE_OBJECT));
+
+ test_flagset_type = gst_flagset_register (GST_TYPE_SEEK_FLAGS);
+
+ fail_unless (g_type_is_a (test_flagset_type, GST_TYPE_FLAG_SET));
+
+ g_value_init (&value, test_flagset_type);
+
+ test_flags =
+ GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_TRICKMODE |
+ GST_SEEK_FLAG_TRICKMODE_KEY_UNITS;
+ test_mask =
+ GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_TRICKMODE |
+ GST_SEEK_FLAG_TRICKMODE_NO_AUDIO;
+
+ check_flagset_mask_serialisation (&value, test_flags, test_mask);
+ /* Check serialisation works with the generic 'exact' flag */
+ check_flagset_mask_serialisation (&value, test_flags,
+ GST_FLAG_SET_MASK_EXACT);
+
+ /* Check deserialisation of flagset in 'flags' form, without
+ * the hex strings at the start */
+ test_flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_TRICKMODE;
+ test_mask = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_TRICKMODE |
+ GST_SEEK_FLAG_TRICKMODE_NO_AUDIO;
+ string = g_strdup ("+flush+trickmode/trickmode-no-audio");
+
+ fail_unless (gst_value_deserialize (&value, string),
+ "could not deserialize %s", string);
+
+ GST_DEBUG ("Deserialized %s to 0x%x:0x%x", string,
+ gst_value_get_flagset_flags (&value),
+ gst_value_get_flagset_mask (&value));
+
+ fail_unless (gst_value_get_flagset_flags (&value) == test_flags,
+ "resulting flags value is 0x%u, not 0x%x, for string %s",
+ gst_value_get_flagset_flags (&value), (test_flags & test_mask), string);
+
+ fail_unless (gst_value_get_flagset_mask (&value) == test_mask,
+ "resulting mask is 0x%u, not 0x%x, for string %s",
+ gst_value_get_flagset_mask (&value), test_mask, string);
+
+ g_free (string);
+ g_value_unset (&value);
+
+ /* Test that fixating don't-care fields works, using our
+ * sub-type flagset for good measure */
+ g_value_init (&value, test_flagset_type);
+ gst_value_set_flagset (&value, test_flags, test_mask);
+
+ fail_unless (gst_value_fixate (&dest, &value));
+ fail_unless (gst_value_get_flagset_flags (&dest) == test_flags);
+ fail_unless (gst_value_get_flagset_mask (&dest) == GST_FLAG_SET_MASK_EXACT);
+
+ g_value_unset (&value);
+
+ /* Intersection tests */
+ g_value_init (&value, GST_TYPE_FLAG_SET);
+ g_value_init (&value2, test_flagset_type);
+
+ /* We want Accurate, but not Snap-Before */
+ gst_value_set_flagset (&value, GST_SEEK_FLAG_ACCURATE,
+ GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SNAP_BEFORE);
+
+ /* This only cares that things are flushing */
+ gst_value_set_flagset (&value2, GST_SEEK_FLAG_FLUSH, GST_SEEK_FLAG_FLUSH);
+
+ test_flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH;
+ test_mask =
+ GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SNAP_BEFORE;
+
+ /* GstFlagSet should always intersect with itself */
+ g_value_unset (&dest);
+ fail_unless (gst_value_intersect (&dest, &value, &value));
+
+ /* GstFlagSet subtype should intersect with itself */
+ g_value_unset (&dest);
+ fail_unless (gst_value_intersect (&dest, &value2, &value2));
+
+ /* Check we can intersect custom flagset subtype with flagset */
+ g_value_unset (&dest);
+ fail_unless (gst_value_intersect (&dest, &value2, &value));
+
+ g_value_unset (&dest);
+ fail_unless (gst_value_intersect (&dest, &value, &value2));
+
+ fail_unless (gst_value_get_flagset_flags (&dest) == test_flags,
+ "resulting flags value is 0x%u, not 0x%x",
+ gst_value_get_flagset_flags (&dest), test_flags);
+
+ fail_unless (gst_value_get_flagset_mask (&dest) == test_mask,
+ "resulting mask is 0x%u, not 0x%x",
+ gst_value_get_flagset_mask (&dest), test_mask);
+
+ g_value_unset (&dest);
+ g_value_unset (&value);
+}
+
+GST_END_TEST;
+
+
GST_START_TEST (test_string)
{
const gchar *try[] = {
tcase_add_test (tc_chain, test_stepped_range_collection);
tcase_add_test (tc_chain, test_stepped_int_range_parsing);
tcase_add_test (tc_chain, test_stepped_int_range_ops);
+ tcase_add_test (tc_chain, test_flagset);
return s;
}