+
+/************
+ * 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;
+}
+