mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-25 11:11:08 +00:00
gstvalue: Add GstFlagSet type
GstFlagSet is a new type designed for negotiating sets of boolean capabilities flags, consisting of a 32-bit flags bitfield and 32-bit mask field. The mask field indicates which of the flags bits an element needs to have as specific values, and which it doesn't care about. This allows efficient negotiation of arrays of boolean capabilities. The standard serialisation format is FLAGS:MASK, with flags and mask fields expressed in hexadecimal, however GstFlagSet has a gst_register_flagset() function, which associates a new GstFlagSet derived type with an existing GFlags gtype. When serializing a GstFlagSet with an associated set of GFlags, it also serializes a human-readable form of the flags for easier debugging. It is possible to parse a GFlags style serialisation of a flagset, without the hex portion on the front. ie, +flag1/flag2/flag3+flag4, to indicate that flag1 & flag4 must be set, and flag2/flag3 must be unset, and any other flags are don't-care. https://bugzilla.gnome.org/show_bug.cgi?id=746373
This commit is contained in:
parent
99d3179634
commit
f9e5178dd1
10 changed files with 971 additions and 85 deletions
|
@ -3285,6 +3285,15 @@ GST_TYPE_BITMASK
|
|||
gst_value_set_bitmask
|
||||
gst_value_get_bitmask
|
||||
|
||||
<SUBSECTION flagset>
|
||||
GST_VALUE_HOLDS_FLAG_SET
|
||||
GST_TYPE_FLAG_SET
|
||||
gst_structure_get_flagset
|
||||
gst_value_get_flagset_flags
|
||||
gst_value_get_flagset_mask
|
||||
gst_value_set_flagset
|
||||
GST_FLAG_SET_MASK_EXACT
|
||||
|
||||
<SUBSECTION int64range>
|
||||
GST_VALUE_HOLDS_INT64_RANGE
|
||||
GST_TYPE_INT64_RANGE
|
||||
|
@ -3408,6 +3417,7 @@ gst_int64_range_get_type
|
|||
gst_value_array_get_type
|
||||
gst_value_list_get_type
|
||||
gst_bitmask_get_type
|
||||
gst_flagset_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
|
|
@ -1720,6 +1720,44 @@ gst_structure_get_fraction (const GstStructure * structure,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_structure_get_flagset:
|
||||
* @structure: a #GstStructure
|
||||
* @fieldname: the name of a field
|
||||
* @value_flags: (out) (allow-none): a pointer to a guint for the flags field
|
||||
* @value_mask: (out) (allow-none): a pointer to a guint for the mask field
|
||||
*
|
||||
* Read the GstFlagSet flags and mask out of the structure into the
|
||||
* provided pointers.
|
||||
*
|
||||
* Returns: %TRUE if the values could be set correctly. If there was no field
|
||||
* with @fieldname or the existing field did not contain a GstFlagSet, this
|
||||
* function returns %FALSE.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
gboolean
|
||||
gst_structure_get_flagset (const GstStructure * structure,
|
||||
const gchar * fieldname, guint * value_flags, guint * value_mask)
|
||||
{
|
||||
GstStructureField *field;
|
||||
|
||||
g_return_val_if_fail (structure != NULL, FALSE);
|
||||
g_return_val_if_fail (fieldname != NULL, FALSE);
|
||||
|
||||
field = gst_structure_get_field (structure, fieldname);
|
||||
|
||||
if (field == NULL || !GST_VALUE_HOLDS_FLAG_SET (&field->value))
|
||||
return FALSE;
|
||||
|
||||
if (value_flags)
|
||||
*value_flags = gst_value_get_flagset_flags (&field->value);
|
||||
if (value_mask)
|
||||
*value_mask = gst_value_get_flagset_mask (&field->value);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct _GstStructureAbbreviation
|
||||
{
|
||||
const gchar *type_name;
|
||||
|
@ -2296,8 +2334,8 @@ gst_structure_parse_value (gchar * str,
|
|||
|
||||
if (G_UNLIKELY (type == G_TYPE_INVALID)) {
|
||||
GType try_types[] =
|
||||
{ G_TYPE_INT, G_TYPE_DOUBLE, GST_TYPE_FRACTION, G_TYPE_BOOLEAN,
|
||||
G_TYPE_STRING
|
||||
{ G_TYPE_INT, G_TYPE_DOUBLE, GST_TYPE_FRACTION, GST_TYPE_FLAG_SET,
|
||||
G_TYPE_BOOLEAN, G_TYPE_STRING
|
||||
};
|
||||
int i;
|
||||
|
||||
|
|
|
@ -288,6 +288,11 @@ gboolean gst_structure_get_fraction (const GstStructure *
|
|||
gint * value_numerator,
|
||||
gint * value_denominator);
|
||||
|
||||
gboolean gst_structure_get_flagset (const GstStructure * structure,
|
||||
const gchar * fieldname,
|
||||
guint * value_flags,
|
||||
guint * value_mask);
|
||||
|
||||
gchar * gst_structure_to_string (const GstStructure * structure) G_GNUC_MALLOC;
|
||||
|
||||
GstStructure * gst_structure_from_string (const gchar * string,
|
||||
|
|
643
gst/gstvalue.c
643
gst/gstvalue.c
|
@ -116,6 +116,14 @@ struct _GstValueSubtractInfo
|
|||
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) \
|
||||
|
@ -871,7 +879,7 @@ gst_value_compare_value_list (const GValue * value1, const GValue * value2)
|
|||
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--;
|
||||
|
@ -3158,7 +3166,7 @@ gst_value_deserialize_enum (GValue * dest, const gchar * s)
|
|||
|
||||
/* 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 =
|
||||
|
@ -3182,7 +3190,7 @@ gst_value_compare_flags (const GValue * value1, const GValue * value2)
|
|||
|
||||
/* 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;
|
||||
|
@ -3223,46 +3231,96 @@ gst_value_serialize_flags (const GValue * value)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fl) {
|
||||
flags |= fl->value;
|
||||
}
|
||||
i++;
|
||||
/* 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 = '+';
|
||||
}
|
||||
g_strfreev (split);
|
||||
g_type_class_unref (klass);
|
||||
g_value_set_flags (dest, flags);
|
||||
|
||||
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 */
|
||||
}
|
||||
g_free (cur_str);
|
||||
|
||||
if (val) {
|
||||
mask |= val;
|
||||
if (delimiter == '+')
|
||||
flags |= val;
|
||||
}
|
||||
|
||||
/* 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_type_class_unref (klass);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/****************
|
||||
* subset *
|
||||
****************/
|
||||
|
@ -3515,6 +3573,40 @@ gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
|
|||
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 *
|
||||
****************/
|
||||
|
@ -3840,6 +3932,60 @@ gst_value_intersect_fraction_range_fraction_range (GValue * dest,
|
|||
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 *
|
||||
***************/
|
||||
|
@ -4623,7 +4769,7 @@ gst_value_compare (const GValue * value1, const GValue * value2)
|
|||
*
|
||||
* 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
|
||||
*/
|
||||
|
@ -4847,6 +4993,14 @@ gst_value_intersect (GValue * dest, const GValue * value1,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -5195,6 +5349,9 @@ gst_value_is_fixed (const GValue * value)
|
|||
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);
|
||||
}
|
||||
|
@ -5260,6 +5417,16 @@ gst_value_fixate (GValue * dest, const GValue * src)
|
|||
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;
|
||||
}
|
||||
|
@ -5906,6 +6073,272 @@ gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
|
|||
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 *
|
||||
|
@ -5971,23 +6404,14 @@ gst_value_transform_object_string (const GValue * src_value,
|
|||
}
|
||||
|
||||
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) \
|
||||
|
@ -5996,26 +6420,29 @@ 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");
|
||||
|
@ -6027,8 +6454,7 @@ static const GTypeValueTable _gst_int64_range_value_table = {
|
|||
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");
|
||||
|
@ -6040,8 +6466,7 @@ static const GTypeValueTable _gst_double_range_value_table = {
|
|||
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");
|
||||
|
@ -6053,8 +6478,7 @@ static const GTypeValueTable _gst_fraction_range_value_table = {
|
|||
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");
|
||||
|
@ -6066,8 +6490,7 @@ static const GTypeValueTable _gst_value_list_value_table = {
|
|||
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");
|
||||
|
@ -6079,8 +6502,7 @@ static const GTypeValueTable _gst_value_array_value_table = {
|
|||
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");
|
||||
|
@ -6091,9 +6513,7 @@ static const GTypeValueTable _gst_fraction_value_table = {
|
|||
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");
|
||||
|
@ -6104,13 +6524,23 @@ static const GTypeValueTable _gst_bitmask_value_table = {
|
|||
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)
|
||||
{
|
||||
|
@ -6122,8 +6552,7 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -6168,9 +6597,11 @@ G_STMT_START { \
|
|||
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
|
||||
|
@ -6202,6 +6633,7 @@ _priv_gst_value_initialize (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 (),
|
||||
|
@ -6218,7 +6650,7 @@ _priv_gst_value_initialize (void)
|
|||
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);
|
||||
|
||||
|
@ -6270,25 +6702,32 @@ _priv_gst_value_initialize (void)
|
|||
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);
|
||||
|
@ -6300,18 +6739,18 @@ _priv_gst_value_initialize (void)
|
|||
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);
|
||||
|
@ -6327,6 +6766,8 @@ _priv_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_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
|
||||
|
@ -6361,3 +6802,43 @@ _priv_gst_value_initialize (void)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -200,6 +200,26 @@ G_BEGIN_DECLS
|
|||
*/
|
||||
#define GST_VALUE_HOLDS_BITMASK(x) ((x) != NULL && G_VALUE_TYPE(x) == _gst_bitmask_type)
|
||||
|
||||
/**
|
||||
* GST_VALUE_HOLDS_FLAG_SET:
|
||||
* @x: the #GValue to check
|
||||
*
|
||||
* Checks if the given #GValue contains a #GST_TYPE_FLAG_SET value.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
#define GST_VALUE_HOLDS_FLAG_SET(x) (G_TYPE_CHECK_VALUE_TYPE ((x), GST_TYPE_FLAG_SET))
|
||||
|
||||
/*
|
||||
* GST_FLAG_SET_MASK_EXACT:
|
||||
* A mask value with all bits set, for use as a
|
||||
* #GstFlagSet mask where all flag bits must match
|
||||
* exactly
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
#define GST_FLAG_SET_MASK_EXACT ((guint)(-1))
|
||||
|
||||
GST_EXPORT GType _gst_int_range_type;
|
||||
|
||||
/**
|
||||
|
@ -300,6 +320,21 @@ GST_EXPORT GType _gst_bitmask_type;
|
|||
|
||||
#define GST_TYPE_BITMASK (_gst_bitmask_type)
|
||||
|
||||
GST_EXPORT GType _gst_flagset_type;
|
||||
|
||||
/**
|
||||
* GST_TYPE_FLAG_SET:
|
||||
*
|
||||
* a #GValue type that represents a 32-bit flag bitfield, with 32-bit
|
||||
* mask indicating which of the bits in the field are explicitly set.
|
||||
* Useful for negotiation.
|
||||
*
|
||||
* Returns: the #GType of GstFlags (which is not explicitly typed)
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
#define GST_TYPE_FLAG_SET (_gst_flagset_type)
|
||||
|
||||
/**
|
||||
* GST_TYPE_G_THREAD:
|
||||
*
|
||||
|
@ -407,6 +442,7 @@ GType gst_fraction_get_type (void);
|
|||
GType gst_value_list_get_type (void);
|
||||
GType gst_value_array_get_type (void);
|
||||
GType gst_bitmask_get_type (void);
|
||||
GType gst_flagset_get_type (void);
|
||||
|
||||
/* Hide this compatibility type from introspection */
|
||||
#ifndef __GI_SCANNER__
|
||||
|
@ -526,6 +562,10 @@ const GValue *gst_value_get_fraction_range_max (const GValue *value);
|
|||
guint64 gst_value_get_bitmask (const GValue *value);
|
||||
void gst_value_set_bitmask (GValue *value,
|
||||
guint64 bitmask);
|
||||
/* flagset */
|
||||
void gst_value_set_flagset (GValue * value, guint flags, guint mask);
|
||||
guint gst_value_get_flagset_flags (const GValue * value);
|
||||
guint gst_value_get_flagset_mask (const GValue * value);
|
||||
|
||||
/* compare */
|
||||
gint gst_value_compare (const GValue *value1,
|
||||
|
@ -561,6 +601,9 @@ gboolean gst_value_is_fixed (const GValue *value);
|
|||
gboolean gst_value_fixate (GValue *dest,
|
||||
const GValue *src);
|
||||
|
||||
/* Flagset registration wrapper */
|
||||
GType gst_flagset_register (GType flags_type);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,9 @@ static const gchar *caps_list[] = {
|
|||
/* Test lists of fractions and fraction ranges */
|
||||
"test/gst-fraction-range, fraction = (fraction) { [ 1/4, 1/3 ], 1/8 }",
|
||||
"test/gst-fraction-range, fraction = (fraction) { [ 1/4, 1/3 ], [ 1/8, 2/8 ] }",
|
||||
|
||||
/* FlagSet */
|
||||
"test/gst-flags,thingy=1f394:00ff8ff",
|
||||
"test/gst-flags,thingy=101ffff1f394:fff00ff00ff8ff",
|
||||
/* Some random checks */
|
||||
"video/x-raw, format = (string) { I420, Y42B, Y444 }, framerate = (fraction) [1/MAX, MAX], width = (int) [ 1, MAX ], height = (int) [ 1, MAX ]",
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ GST_START_TEST (test_from_string)
|
|||
to_str = gst_caps_to_string (caps);
|
||||
fail_if (to_str == NULL,
|
||||
"Could not convert caps back to string %s\n", caps_list[i]);
|
||||
caps2 = gst_caps_from_string (caps_list[i]);
|
||||
caps2 = gst_caps_from_string (to_str);
|
||||
fail_if (caps2 == NULL, "Could not create caps from string %s\n", to_str);
|
||||
|
||||
fail_unless (gst_caps_is_equal (caps, caps));
|
||||
|
@ -934,6 +934,104 @@ GST_START_TEST (test_intersect_duplication)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_intersect_flagset)
|
||||
{
|
||||
GstCaps *c1, *c2, *test;
|
||||
GType test_flagset_type;
|
||||
GstSeekFlags test_flags, test_mask;
|
||||
gchar *test_string;
|
||||
|
||||
/* Test that matching bits inside the mask intersect,
|
||||
* and bits outside the mask don't matter */
|
||||
c1 = gst_caps_from_string ("test/x-caps,field=ffd81d:fffff0");
|
||||
c2 = gst_caps_from_string ("test/x-caps,field=0fd81f:0ffff0");
|
||||
|
||||
test = gst_caps_intersect_full (c1, c2, GST_CAPS_INTERSECT_FIRST);
|
||||
fail_unless_equals_int (gst_caps_get_size (test), 1);
|
||||
fail_unless (gst_caps_is_equal (c1, test));
|
||||
gst_caps_unref (c1);
|
||||
gst_caps_unref (c2);
|
||||
gst_caps_unref (test);
|
||||
|
||||
/* Test that non-matching bits in the mask don't intersect */
|
||||
c1 = gst_caps_from_string ("test/x-caps,field=ff001d:0ffff0");
|
||||
c2 = gst_caps_from_string ("test/x-caps,field=0fd81f:0ffff0");
|
||||
|
||||
test = gst_caps_intersect_full (c1, c2, GST_CAPS_INTERSECT_FIRST);
|
||||
fail_unless (gst_caps_is_empty (test));
|
||||
gst_caps_unref (c1);
|
||||
gst_caps_unref (c2);
|
||||
gst_caps_unref (test);
|
||||
|
||||
/* Check custom flags type serialisation and de-serialisation */
|
||||
test_flagset_type = gst_flagset_register (GST_TYPE_SEEK_FLAGS);
|
||||
fail_unless (g_type_is_a (test_flagset_type, GST_TYPE_FLAG_SET));
|
||||
|
||||
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;
|
||||
|
||||
c1 = gst_caps_new_simple ("test/x-caps", "field", test_flagset_type,
|
||||
(guint64) (test_flags), (guint64) (test_mask), NULL);
|
||||
|
||||
test_string = gst_caps_to_string (c1);
|
||||
fail_if (test_string == NULL);
|
||||
|
||||
GST_DEBUG ("Serialised caps to %s", test_string);
|
||||
c2 = gst_caps_from_string (test_string);
|
||||
|
||||
fail_unless (gst_caps_is_equal (c1, c2));
|
||||
|
||||
gst_caps_unref (c1);
|
||||
gst_caps_unref (c2);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_union)
|
||||
{
|
||||
GstCaps *c1, *c2, *test, *expect;
|
||||
|
||||
/* Test that matching bits inside the masks union OK, */
|
||||
c1 = gst_caps_from_string ("test/x-caps,field=ffd81d:0ffff0");
|
||||
c2 = gst_caps_from_string ("test/x-caps,field=0fd81f:0ffff0");
|
||||
|
||||
test = gst_caps_merge (c1, c2);
|
||||
test = gst_caps_simplify (test);
|
||||
/* c1, c2 now invalid */
|
||||
fail_unless_equals_int (gst_caps_get_size (test), 1);
|
||||
gst_caps_unref (test);
|
||||
|
||||
/* Test that non-intersecting sets of masked bits are OK */
|
||||
c1 = gst_caps_from_string ("test/x-caps,field=ff001d:0ffff0");
|
||||
c2 = gst_caps_from_string ("test/x-caps,field=4fd81f:f00000");
|
||||
expect = gst_caps_from_string ("test/x-caps,field=4f001d:fffff0");
|
||||
test = gst_caps_simplify (gst_caps_merge (c1, c2));
|
||||
/* c1, c2 now invalid */
|
||||
GST_LOG ("Expected caps %" GST_PTR_FORMAT " got %" GST_PTR_FORMAT "\n",
|
||||
expect, test);
|
||||
fail_unless (gst_caps_is_equal (test, expect));
|
||||
gst_caps_unref (test);
|
||||
gst_caps_unref (expect);
|
||||
|
||||
/* Test that partially-intersecting sets of masked bits that match are OK */
|
||||
c1 = gst_caps_from_string ("test/x-caps,field=ff001d:0ffff0");
|
||||
c2 = gst_caps_from_string ("test/x-caps,field=4fd81f:ff0000");
|
||||
expect = gst_caps_from_string ("test/x-caps,field=4f001d:fffff0");
|
||||
test = gst_caps_simplify (gst_caps_merge (c1, c2));
|
||||
/* c1, c2 now invalid */
|
||||
GST_LOG ("Expected caps %" GST_PTR_FORMAT " got %" GST_PTR_FORMAT "\n",
|
||||
expect, test);
|
||||
fail_unless (gst_caps_is_equal (test, expect));
|
||||
gst_caps_unref (test);
|
||||
gst_caps_unref (expect);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static gboolean
|
||||
_caps_is_fixed_foreach (GQuark field_id, const GValue * value, gpointer unused)
|
||||
{
|
||||
|
@ -1311,6 +1409,8 @@ gst_caps_suite (void)
|
|||
tcase_add_test (tc_chain, test_intersect_first);
|
||||
tcase_add_test (tc_chain, test_intersect_first2);
|
||||
tcase_add_test (tc_chain, test_intersect_duplication);
|
||||
tcase_add_test (tc_chain, test_intersect_flagset);
|
||||
tcase_add_test (tc_chain, test_union);
|
||||
tcase_add_test (tc_chain, test_normalize);
|
||||
tcase_add_test (tc_chain, test_broken);
|
||||
tcase_add_test (tc_chain, test_features);
|
||||
|
|
|
@ -749,6 +749,30 @@ GST_START_TEST (test_filter_and_map_in_place)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_flagset)
|
||||
{
|
||||
GstStructure *s;
|
||||
GType test_flagset_type;
|
||||
guint test_flags =
|
||||
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP | GST_SEEK_FLAG_SNAP_AFTER;
|
||||
guint test_mask = GST_FLAG_SET_MASK_EXACT;
|
||||
guint out_flags, out_mask;
|
||||
|
||||
test_flagset_type = gst_flagset_register (GST_TYPE_SEEK_FLAGS);
|
||||
fail_unless (g_type_is_a (test_flagset_type, GST_TYPE_FLAG_SET));
|
||||
|
||||
/* Check that we can retrieve a non-standard flagset from the structure */
|
||||
s = gst_structure_new ("test-struct", "test-flagset", test_flagset_type,
|
||||
test_flags, test_mask, NULL);
|
||||
fail_unless (gst_structure_get_flagset (s, "test-flagset", &out_flags,
|
||||
&out_mask));
|
||||
|
||||
fail_unless (out_flags == test_flags);
|
||||
fail_unless (out_mask == test_mask);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_structure_suite (void)
|
||||
{
|
||||
|
@ -774,6 +798,7 @@ gst_structure_suite (void)
|
|||
tcase_add_test (tc_chain, test_foreach);
|
||||
tcase_add_test (tc_chain, test_map_in_place);
|
||||
tcase_add_test (tc_chain, test_filter_and_map_in_place);
|
||||
tcase_add_test (tc_chain, test_flagset);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
@ -497,6 +497,180 @@ GST_START_TEST (test_deserialize_bitmask)
|
|||
|
||||
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[] = {
|
||||
|
@ -2904,6 +3078,7 @@ gst_value_suite (void)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ EXPORTS
|
|||
_gst_double_range_type DATA
|
||||
_gst_element_error_printf
|
||||
_gst_event_type DATA
|
||||
_gst_flagset_type DATA
|
||||
_gst_fraction_range_type DATA
|
||||
_gst_fraction_type DATA
|
||||
_gst_int64_range_type DATA
|
||||
|
@ -601,6 +602,8 @@ EXPORTS
|
|||
gst_event_type_to_quark
|
||||
gst_event_writable_structure
|
||||
gst_filename_to_uri
|
||||
gst_flagset_get_type
|
||||
gst_flagset_register
|
||||
gst_flow_get_name
|
||||
gst_flow_return_get_type
|
||||
gst_flow_to_quark
|
||||
|
@ -1175,6 +1178,7 @@ EXPORTS
|
|||
gst_structure_get_double
|
||||
gst_structure_get_enum
|
||||
gst_structure_get_field_type
|
||||
gst_structure_get_flagset
|
||||
gst_structure_get_fraction
|
||||
gst_structure_get_int
|
||||
gst_structure_get_int64
|
||||
|
@ -1465,6 +1469,8 @@ EXPORTS
|
|||
gst_value_get_caps_features
|
||||
gst_value_get_double_range_max
|
||||
gst_value_get_double_range_min
|
||||
gst_value_get_flagset_flags
|
||||
gst_value_get_flagset_mask
|
||||
gst_value_get_fraction_denominator
|
||||
gst_value_get_fraction_numerator
|
||||
gst_value_get_fraction_range_max
|
||||
|
@ -1494,6 +1500,7 @@ EXPORTS
|
|||
gst_value_set_caps
|
||||
gst_value_set_caps_features
|
||||
gst_value_set_double_range
|
||||
gst_value_set_flagset
|
||||
gst_value_set_fraction
|
||||
gst_value_set_fraction_range
|
||||
gst_value_set_fraction_range_full
|
||||
|
|
Loading…
Reference in a new issue