sample: add serialisation/deserialisation functions for GstSample
authorTim-Philipp Müller <tim@centricular.net>
Sun, 16 Sep 2012 22:20:46 +0000 (23:20 +0100)
committerTim-Philipp Müller <tim@centricular.net>
Sun, 16 Sep 2012 22:20:46 +0000 (23:20 +0100)
Since these things are inside taglists now, it would be good to be
able to print them and deserialise them.

https://bugzilla.gnome.org/show_bug.cgi?id=681322

gst/gststructure.c
gst/gstvalue.c
tests/check/gst/gsttag.c

index 56b66bc..29fdf31 100644 (file)
@@ -1682,6 +1682,8 @@ gst_structure_get_abbrs (gint * n_abbrs)
       ,
       {"bitmask", GST_TYPE_BITMASK}
       ,
+      {"sample", GST_TYPE_SAMPLE}
+      ,
       {"taglist", GST_TYPE_TAG_LIST}
     };
     _num = G_N_ELEMENTS (dyn_abbrs);
index 997a5e1..80c59fe 100644 (file)
@@ -1837,8 +1837,9 @@ gst_value_deserialize_caps (GValue * dest, const gchar * s)
 /**************
  * GstSegment *
  **************/
+
 static gchar *
-gst_value_serialize_segment (const GValue * value)
+gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
 {
   GstSegment *seg = g_value_get_boxed (value);
   gchar *t, *res;
@@ -1857,13 +1858,23 @@ gst_value_serialize_segment (const GValue * value)
       "position", G_TYPE_UINT64, seg->position,
       "duration", G_TYPE_UINT64, seg->duration, NULL);
   t = gst_structure_to_string (s);
-  res = g_strdup_printf ("\"%s\"", t);
-  g_free (t);
+  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)
 {
@@ -2151,6 +2162,149 @@ gst_value_compare_sample (const GValue * value1, const GValue * value2)
   return compare_buffer (buf1, buf2);
 }
 
+static gchar *
+gst_value_serialize_sample (const GValue * value)
+{
+  const GstStructure *info_structure;
+  GstSegment *segment;
+  GstBuffer *buffer;
+  GstCaps *caps;
+  GstSample *sample;
+  GValue val = { 0, };
+  gchar *info_str, *caps_str, *tmp;
+  gchar *buf_str, *seg_str, *s;
+
+  sample = g_value_get_boxed (value);
+
+  buffer = gst_sample_get_buffer (sample);
+  if (buffer) {
+    g_value_init (&val, GST_TYPE_BUFFER);
+    g_value_set_boxed (&val, buffer);
+    buf_str = gst_value_serialize_buffer (&val);
+    g_value_unset (&val);
+  } else {
+    buf_str = g_strdup ("None");
+  }
+
+  caps = gst_sample_get_caps (sample);
+  if (caps) {
+    tmp = gst_caps_to_string (caps);
+    caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
+    g_strdelimit (caps_str, "=", '_');
+    g_free (tmp);
+  } else {
+    caps_str = g_strdup ("None");
+  }
+
+  segment = gst_sample_get_segment (sample);
+  if (segment) {
+    g_value_init (&val, GST_TYPE_SEGMENT);
+    g_value_set_boxed (&val, segment);
+    tmp = gst_value_serialize_segment_internal (&val, FALSE);
+    seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
+    g_strdelimit (seg_str, "=", '_');
+    g_free (tmp);
+    g_value_unset (&val);
+  } else {
+    seg_str = g_strdup ("None");
+  }
+
+  info_structure = gst_sample_get_info (sample);
+  if (info_structure) {
+    tmp = gst_structure_to_string (info_structure);
+    info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
+    g_strdelimit (info_str, "=", '_');
+    g_free (tmp);
+  } else {
+    info_str = g_strdup ("None");
+  }
+
+  s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
+  g_free (buf_str);
+  g_free (caps_str);
+  g_free (seg_str);
+  g_free (info_str);
+
+  return s;
+}
+
+static gboolean
+gst_value_deserialize_sample (GValue * dest, const gchar * s)
+{
+  GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
+  GstStructure *info;
+  GstSample *sample;
+  GstCaps *caps;
+  gboolean ret = FALSE;
+  gchar **fields;
+  gsize outlen;
+  gint len;
+
+  GST_TRACE ("deserialize '%s'", s);
+
+  fields = g_strsplit (s, ":", -1);
+  len = g_strv_length (fields);
+  if (len != 4)
+    goto wrong_length;
+
+  g_value_init (&bval, GST_TYPE_BUFFER);
+  g_value_init (&sval, GST_TYPE_SEGMENT);
+
+  if (!gst_value_deserialize_buffer (&bval, fields[0]))
+    goto fail;
+
+  if (strcmp (fields[1], "None") != 0) {
+    g_strdelimit (fields[1], "_", '=');
+    g_base64_decode_inplace (fields[1], &outlen);
+    GST_TRACE ("caps    : %s", fields[1]);
+    caps = gst_caps_from_string (fields[1]);
+    if (caps == NULL)
+      goto fail;
+  } else {
+    caps = NULL;
+  }
+
+  if (strcmp (fields[2], "None") != 0) {
+    g_strdelimit (fields[2], "_", '=');
+    g_base64_decode_inplace (fields[2], &outlen);
+    GST_TRACE ("segment : %s", fields[2]);
+    if (!gst_value_deserialize_segment (&sval, fields[2]))
+      goto fail;
+  }
+
+  if (strcmp (fields[3], "None") != 0) {
+    g_strdelimit (fields[3], "_", '=');
+    g_base64_decode_inplace (fields[3], &outlen);
+    GST_TRACE ("info    : %s", fields[3]);
+    info = gst_structure_from_string (fields[3], NULL);
+    if (info == NULL)
+      goto fail;
+  } else {
+    info = NULL;
+  }
+
+  sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
+      g_value_get_boxed (&sval), info);
+
+  g_value_take_boxed (dest, sample);
+
+  if (caps)
+    gst_caps_unref (caps);
+
+  ret = TRUE;
+
+fail:
+
+  g_value_unset (&bval);
+  g_value_unset (&sval);
+
+wrong_length:
+
+  g_strfreev (fields);
+
+  return ret;
+}
+
 /***********
  * boolean *
  ***********/
@@ -5801,8 +5955,8 @@ _priv_gst_value_initialize (void)
     static GstValueTable gst_value = {
       0,
       gst_value_compare_sample,
-      NULL,
-      NULL,
+      gst_value_serialize_sample,
+      gst_value_deserialize_sample,
     };
 
     gst_value.type = GST_TYPE_SAMPLE;
index 1e52a22..ed2e24b 100644 (file)
@@ -566,6 +566,48 @@ GST_START_TEST (test_writability)
 
 GST_END_TEST;
 
+/* this tests GstSample serialisation/deserialisation, esp. with multiple
+ * samples in a tag list */
+GST_START_TEST (test_serialization)
+{
+  GstTagList *tags, *tags2;
+  GstBuffer *b1, *b2;
+  GstSample *s1, *s2;
+  GstCaps *c2;
+  gchar *s;
+
+  b1 = gst_buffer_new_allocate (NULL, 1, NULL);
+  gst_buffer_memset (b1, 0, 0xb3, -1);
+  s1 = gst_sample_new (b1, NULL, NULL, NULL);
+  gst_buffer_unref (b1);
+
+  b2 = gst_buffer_new_allocate (NULL, 8, NULL);
+  gst_buffer_memset (b2, 0, 0x2f, -1);
+  c2 = gst_caps_new_empty_simple ("foo/bar");
+  s2 = gst_sample_new (b2, c2, NULL, NULL);
+  gst_buffer_unref (b2);
+  gst_caps_unref (c2);
+  c2 = NULL;
+
+  tags = gst_tag_list_new (GST_TAG_ATTACHMENT, s1, NULL);
+  gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_ATTACHMENT, s2, NULL);
+  GST_INFO ("tags: %" GST_PTR_FORMAT, tags);
+
+  s = gst_tag_list_to_string (tags);
+  GST_INFO ("taglist -> string: %s", s);
+  tags2 = gst_tag_list_new_from_string (s);
+  GST_INFO ("string -> taglist: %" GST_PTR_FORMAT, tags2);
+  fail_unless (gst_tag_list_is_equal (tags, tags2));
+  gst_tag_list_unref (tags2);
+  g_free (s);
+
+  gst_sample_unref (s1);
+  gst_sample_unref (s2);
+  gst_tag_list_unref (tags);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_tag_suite (void)
 {
@@ -585,6 +627,7 @@ gst_tag_suite (void)
   tcase_add_test (tc_chain, test_new_full);
   tcase_add_test (tc_chain, test_equal);
   tcase_add_test (tc_chain, test_writability);
+  tcase_add_test (tc_chain, test_serialization);
 
   return s;
 }