+ int i;
+ GstValueAbbreviation *abbrs;
+ gint n_abbrs;
+ GType ret;
+
+ g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID);
+
+ abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
+
+ for (i = 0; i < n_abbrs; i++) {
+ if (strcmp (type_name, abbrs[i].type_name) == 0) {
+ return abbrs[i].type;
+ }
+ }
+
+ /* this is the fallback */
+ ret = g_type_from_name (type_name);
+ /* If not found, try it as a dynamic type */
+ if (G_UNLIKELY (ret == 0))
+ ret = gst_dynamic_type_factory_load (type_name);
+ return ret;
+
+}
+
+const char *
+_priv_gst_value_gtype_to_abbr (GType type)
+{
+ int i;
+ GstValueAbbreviation *abbrs;
+ gint n_abbrs;
+
+ g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
+
+ abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
+
+ for (i = 0; i < n_abbrs; i++) {
+ if (type == abbrs[i].type) {
+ return abbrs[i].type_name;
+ }
+ }
+
+ return g_type_name (type);
+}
+
+/*
+ * _priv_gst_value_parse_string:
+ * @s: string to parse
+ * @end: out-pointer to char behind end of string
+ * @next: out-pointer to start of unread data
+ * @unescape: @TRUE if the substring is escaped.
+ *
+ * Find the end of a sub-string. If end == next, the string will not be
+ * null-terminated. In all other cases it will be.
+ *
+ * Note: This function modifies the string in @s (if unescape == @TRUE).
+ *
+ * Returns: @TRUE if a sub-string was found and @FALSE if the string is not
+ * terminated.
+ */
+gboolean
+_priv_gst_value_parse_string (gchar * s, gchar ** end, gchar ** next,
+ gboolean unescape)
+{
+ gchar *w;
+
+ if (*s == 0)
+ return FALSE;
+
+ if (*s != '"') {
+ int ret = _priv_gst_value_parse_simple_string (s, end);
+ *next = *end;
+
+ return ret;
+ }
+
+ /* Find the closing quotes */
+ if (unescape) {
+ w = s;
+ s++;
+ while (*s != '"') {
+ if (G_UNLIKELY (*s == 0))
+ return FALSE;
+ if (G_UNLIKELY (*s == '\\')) {
+ s++;
+ if (G_UNLIKELY (*s == 0))
+ return FALSE;
+ }
+ *w = *s;
+ w++;
+ s++;
+ }
+ s++;
+ } else {
+ s++;
+ while (*s != '"') {
+ if (G_UNLIKELY (*s == 0))
+ return FALSE;
+ if (G_UNLIKELY (*s == '\\')) {
+ s++;
+ if (G_UNLIKELY (*s == 0))
+ return FALSE;
+ }
+ s++;
+ }
+ s++;
+ w = s;
+ }
+
+ *end = w;
+ *next = s;
+
+ return TRUE;
+}
+
+static gboolean
+_priv_gst_value_parse_range (gchar * s, gchar ** after, GValue * value,
+ GType type)
+{
+ GValue value1 = { 0 };
+ GValue value2 = { 0 };
+ GValue value3 = { 0 };
+ GType range_type;
+ gboolean ret, have_step = FALSE;
+
+ if (*s != '[')
+ return FALSE;
+ s++;
+
+ ret = _priv_gst_value_parse_value (s, &s, &value1, type);
+ if (!ret)
+ return FALSE;
+
+ while (g_ascii_isspace (*s))
+ s++;
+
+ if (*s != ',')
+ return FALSE;
+ s++;
+
+ while (g_ascii_isspace (*s))
+ s++;
+
+ ret = _priv_gst_value_parse_value (s, &s, &value2, type);
+ if (!ret)
+ return FALSE;
+
+ while (g_ascii_isspace (*s))
+ s++;
+
+ /* optional step for int and int64 */
+ if (G_VALUE_TYPE (&value1) == G_TYPE_INT
+ || G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
+ if (*s == ',') {
+ s++;
+
+ while (g_ascii_isspace (*s))
+ s++;
+
+ ret = _priv_gst_value_parse_value (s, &s, &value3, type);
+ if (!ret)
+ return FALSE;
+
+ while (g_ascii_isspace (*s))
+ s++;
+
+ have_step = TRUE;
+ }
+ }
+
+ if (*s != ']')
+ return FALSE;
+ s++;
+
+ if (G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value2))
+ return FALSE;
+ if (have_step && G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value3))
+ return FALSE;
+
+ if (G_VALUE_TYPE (&value1) == G_TYPE_DOUBLE) {
+ range_type = GST_TYPE_DOUBLE_RANGE;
+ g_value_init (value, range_type);
+ gst_value_set_double_range (value,
+ gst_g_value_get_double_unchecked (&value1),
+ gst_g_value_get_double_unchecked (&value2));
+ } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT) {
+ range_type = GST_TYPE_INT_RANGE;
+ g_value_init (value, range_type);
+ if (have_step)
+ gst_value_set_int_range_step (value,
+ gst_g_value_get_int_unchecked (&value1),
+ gst_g_value_get_int_unchecked (&value2),
+ gst_g_value_get_int_unchecked (&value3));
+ else
+ gst_value_set_int_range (value, gst_g_value_get_int_unchecked (&value1),
+ gst_g_value_get_int_unchecked (&value2));
+ } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
+ range_type = GST_TYPE_INT64_RANGE;
+ g_value_init (value, range_type);
+ if (have_step)
+ gst_value_set_int64_range_step (value,
+ gst_g_value_get_int64_unchecked (&value1),
+ gst_g_value_get_int64_unchecked (&value2),
+ gst_g_value_get_int64_unchecked (&value3));
+ else
+ gst_value_set_int64_range (value,
+ gst_g_value_get_int64_unchecked (&value1),
+ gst_g_value_get_int64_unchecked (&value2));
+ } else if (G_VALUE_TYPE (&value1) == GST_TYPE_FRACTION) {
+ range_type = GST_TYPE_FRACTION_RANGE;
+ g_value_init (value, range_type);
+ gst_value_set_fraction_range (value, &value1, &value2);
+ } else {
+ return FALSE;
+ }
+
+ *after = s;
+ return TRUE;
+}
+
+static gboolean
+_priv_gst_value_parse_any_list (gchar * s, gchar ** after, GValue * value,
+ GType type, char begin, char end)
+{
+ GValue list_value = { 0 };
+ gboolean ret;
+ GArray *array;
+
+ array = g_value_peek_pointer (value);
+
+ if (*s != begin)
+ return FALSE;
+ s++;
+
+ while (g_ascii_isspace (*s))
+ s++;
+ if (*s == end) {
+ s++;
+ *after = s;
+ return TRUE;
+ }
+
+ ret = _priv_gst_value_parse_value (s, &s, &list_value, type);
+ if (!ret)
+ return FALSE;
+
+ g_array_append_val (array, list_value);
+
+ while (g_ascii_isspace (*s))
+ s++;
+
+ while (*s != end) {
+ if (*s != ',')
+ return FALSE;
+ s++;
+
+ while (g_ascii_isspace (*s))
+ s++;
+
+ memset (&list_value, 0, sizeof (list_value));
+ ret = _priv_gst_value_parse_value (s, &s, &list_value, type);
+ if (!ret)
+ return FALSE;
+
+ g_array_append_val (array, list_value);
+ while (g_ascii_isspace (*s))
+ s++;
+ }
+
+ s++;
+
+ *after = s;
+ return TRUE;
+}
+
+static gboolean
+_priv_gst_value_parse_list (gchar * s, gchar ** after, GValue * value,
+ GType type)
+{
+ return _priv_gst_value_parse_any_list (s, after, value, type, '{', '}');
+}
+
+static gboolean
+_priv_gst_value_parse_array (gchar * s, gchar ** after, GValue * value,
+ GType type)
+{
+ return _priv_gst_value_parse_any_list (s, after, value, type, '<', '>');
+}
+
+gboolean
+_priv_gst_value_parse_simple_string (gchar * str, gchar ** end)
+{
+ char *s = str;
+
+ while (G_LIKELY (GST_ASCII_IS_STRING (*s))) {
+ s++;
+ }
+
+ *end = s;
+
+ return (s != str);
+}
+
+gboolean
+_priv_gst_value_parse_value (gchar * str,
+ gchar ** after, GValue * value, GType default_type)
+{
+ gchar *type_name;
+ gchar *type_end;
+ gchar *value_s;
+ gchar *value_end;
+ gchar *s;
+ gchar c;
+ int ret = 0;
+ GType type = default_type;
+
+ s = str;
+ while (g_ascii_isspace (*s))
+ s++;
+
+ /* check if there's a (type_name) 'cast' */
+ type_name = NULL;
+ if (*s == '(') {
+ s++;
+ while (g_ascii_isspace (*s))
+ s++;
+ type_name = s;
+ if (G_UNLIKELY (!_priv_gst_value_parse_simple_string (s, &type_end)))
+ return FALSE;
+ s = type_end;
+ while (g_ascii_isspace (*s))
+ s++;
+ if (G_UNLIKELY (*s != ')'))
+ return FALSE;
+ s++;
+ while (g_ascii_isspace (*s))
+ s++;
+
+ c = *type_end;
+ *type_end = 0;
+ type = _priv_gst_value_gtype_from_abbr (type_name);
+ GST_DEBUG ("trying type name '%s'", type_name);
+ *type_end = c;
+
+ if (G_UNLIKELY (type == G_TYPE_INVALID)) {
+ GST_WARNING ("invalid type");
+ return FALSE;
+ }
+ }
+
+ while (g_ascii_isspace (*s))
+ s++;
+ if (*s == '[') {
+ ret = _priv_gst_value_parse_range (s, &s, value, type);
+ } else if (*s == '{') {
+ g_value_init (value, GST_TYPE_LIST);
+ ret = _priv_gst_value_parse_list (s, &s, value, type);
+ } else if (*s == '<') {
+ g_value_init (value, GST_TYPE_ARRAY);
+ ret = _priv_gst_value_parse_array (s, &s, value, type);
+ } else {
+ value_s = s;
+
+ if (G_UNLIKELY (type == G_TYPE_INVALID)) {
+ GType try_types[] =
+ { G_TYPE_INT, G_TYPE_DOUBLE, GST_TYPE_FRACTION, GST_TYPE_FLAG_SET,
+ G_TYPE_BOOLEAN, G_TYPE_STRING
+ };
+ int i;
+
+ if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, TRUE)))
+ return FALSE;
+ /* Set NULL terminator for deserialization */
+ c = *value_end;
+ *value_end = '\0';
+
+ for (i = 0; i < G_N_ELEMENTS (try_types); i++) {
+ g_value_init (value, try_types[i]);
+ ret = gst_value_deserialize (value, value_s);
+ if (ret)
+ break;
+ g_value_unset (value);
+ }
+ } else {
+ g_value_init (value, type);
+
+ if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s,
+ (type != G_TYPE_STRING))))
+ return FALSE;
+ /* Set NULL terminator for deserialization */
+ c = *value_end;
+ *value_end = '\0';
+
+ ret = gst_value_deserialize (value, value_s);
+ if (G_UNLIKELY (!ret))
+ g_value_unset (value);
+ }
+ *value_end = c;
+ }
+
+ *after = s;
+
+ return ret;
+}
+
+/**************
+ * GstSegment *
+ **************/
+
+static gchar *
+gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
+{
+ 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,
+ "offset", G_TYPE_UINT64, seg->offset,
+ "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);
+ if (escape) {
+ res = g_strdup_printf ("\"%s\"", t);
+ g_free (t);
+ } else {
+ res = t;
+ }
+ gst_structure_free (s);
+
+ return res;
+}
+
+static gchar *
+gst_value_serialize_segment (const GValue * value)
+{
+ return gst_value_serialize_segment_internal (value, TRUE);
+}
+
+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,
+ "offset", G_TYPE_UINT64, &seg.offset,
+ "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 *
+ ****************/
+
+/**
+ * gst_value_set_structure:
+ * @value: a GValue initialized to GST_TYPE_STRUCTURE
+ * @structure: the structure to set the value to
+ *
+ * Sets the contents of @value to @structure.
+ */
+void
+gst_value_set_structure (GValue * value, const GstStructure * structure)
+{
+ g_return_if_fail (G_IS_VALUE (value));
+ g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
+ g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));