GESKeyFileFormatter: New GKeyFile GESFormatter
authorBrandon Lewis <brandon@collabora.co.uk>
Thu, 7 Oct 2010 12:49:15 +0000 (13:49 +0100)
committerEdward Hervey <edward.hervey@collabora.co.uk>
Sat, 27 Nov 2010 17:08:20 +0000 (18:08 +0100)
docs/libs/ges-docs.sgml
docs/libs/ges-sections.txt
docs/libs/ges.types
ges/Makefile.am
ges/ges-formatter.c
ges/ges-formatter.h
ges/ges-keyfile-formatter.c [new file with mode: 0644]
ges/ges-keyfile-formatter.h [new file with mode: 0644]
ges/ges-types.h
ges/ges.h

index 284d8ea..50e85cb 100644 (file)
@@ -80,6 +80,7 @@ platform as well as Windows. It is released under the GNU Library General Public
   <chapter>
     <title>Serialization Classes</title>
     <xi:include href="xml/ges-formatter.xml"/>
+    <xi:include href="xml/ges-keyfile-formatter.xml"/>
   </chapter>
 
   <chapter id="ges-hierarchy">
index 599c61a..ee9af24 100644 (file)
@@ -536,7 +536,7 @@ GES_TYPE_TRACK_TEXT_OVERLAY
 <TITLE>GESFormatter</TITLE>
 GESFormatter
 GESFormatterClass
-ges_formatter_new
+ges_default_formatter_new
 ges_formatter_load_from_uri
 ges_formatter_save_to_uri
 ges_formatter_new_for_uri
@@ -553,3 +553,19 @@ GES_IS_FORMATTER
 GES_IS_FORMATTER_CLASS
 GES_TYPE_FORMATTER
 </SECTION>
+
+<SECTION>
+<FILE>ges-keyfile-formatter</FILE>
+<TITLE>GESFormatter</TITLE>
+GESKeyfileFormatter
+GESKeyfileFormatterClass
+ges_keyfile_formatter_new
+<SUBSECTION Standard>
+GES_IS_KEYFILE_FORMATTER
+GES_IS_KEYFILE_FORMATTER_CLASS
+GES_KEYFILE_FORMATTER
+GES_KEYFILE_FORMATTER_CLASS
+GES_KEYFILE_FORMATTER_GET_CLASS
+GES_TYPE_KEYFILE_FORMATTER
+ges_keyfile_formatter_get_type
+</SECTION>
index aa2a79b..cee331b 100644 (file)
@@ -31,3 +31,4 @@ ges_text_halign_get_type
 ges_video_test_pattern_get_type
 ges_track_operation_get_type
 ges_formatter_get_type
+ges_keyfile_formatter_get_type
index 2dd6d6e..5efb4f3 100644 (file)
@@ -39,6 +39,7 @@ libges_@GST_MAJORMINOR@_la_SOURCES =          \
        ges-track-text-overlay.c                \
        ges-screenshot.c                        \
        ges-formatter.c                         \
+       ges-keyfile-formatter.c                 \
        ges-utils.c
 
 libges_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/ges/
@@ -76,6 +77,7 @@ libges_@GST_MAJORMINOR@include_HEADERS =      \
        ges-track-text-overlay.h                \
        ges-screenshot.h                        \
        ges-formatter.h                         \
+       ges-keyfile-formatter.h                 \
        ges-utils.h
 
 libges_@GST_MAJORMINOR@_la_CFLAGS = -I$(top_srcdir) $(GST_PROFILE_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) $(GST_CONTROLLER_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
index 48607af..8d36e1d 100644 (file)
@@ -37,10 +37,6 @@ G_DEFINE_TYPE (GESFormatter, ges_formatter, G_TYPE_OBJECT);
 static void ges_formatter_dispose (GObject * object);
 static void ges_formatter_finalize (GObject * object);
 
-/* for ini format */
-static gboolean save_ini (GESFormatter * formatter, GESTimeline * timeline);
-static gboolean load_ini (GESFormatter * formatter, GESTimeline * timeline);
-
 static void
 ges_formatter_class_init (GESFormatterClass * klass)
 {
@@ -48,9 +44,6 @@ ges_formatter_class_init (GESFormatterClass * klass)
 
   object_class->dispose = ges_formatter_dispose;
   object_class->finalize = ges_formatter_finalize;
-
-  klass->save = save_ini;
-  klass->load = load_ini;
 }
 
 static void
@@ -74,12 +67,6 @@ ges_formatter_finalize (GObject * formatter)
 {
 }
 
-GESFormatter *
-ges_formatter_new (void)
-{
-  return g_object_new (GES_TYPE_FORMATTER, NULL);
-}
-
 /**
  * ges_formatter_new_for_uri:
  * @uri: a #gchar * pointing to the uri
@@ -94,11 +81,26 @@ GESFormatter *
 ges_formatter_new_for_uri (gchar * uri)
 {
   if (ges_formatter_can_load_uri (uri))
-    return ges_formatter_new ();
+    return GES_FORMATTER (ges_keyfile_formatter_new ());
   return NULL;
 }
 
 /**
+ * ges_formatter_default_new:
+ *
+ * Creates a new instance of the default GESFormatter type on this system
+ * (currently #GESKeyFileFormatter).
+ *
+ * Returns: a #GESFormatter instance or NULL 
+ */
+
+GESFormatter *
+ges_default_formatter_new (void)
+{
+  return GES_FORMATTER (ges_keyfile_formatter_new ());
+}
+
+/**
  * ges_formatter_can_load_uri:
  * @uri: a #gchar * pointing to the URI
  * 
@@ -187,6 +189,7 @@ ges_formatter_load (GESFormatter * formatter, GESTimeline * timeline)
 
   if (klass->load)
     return klass->load (formatter, timeline);
+  GST_ERROR ("not implemented!");
   return FALSE;
 }
 
@@ -213,6 +216,7 @@ ges_formatter_save (GESFormatter * formatter, GESTimeline * timeline)
 
   if (klass->save)
     return klass->save (formatter, timeline);
+  GST_ERROR ("not implemented!");
   return FALSE;
 }
 
@@ -315,392 +319,3 @@ ges_formatter_save_to_uri (GESFormatter * formatter, GESTimeline * timeline,
 
   return ret;
 }
-
-static gboolean
-save_ini (GESFormatter * formatter, GESTimeline * timeline)
-{
-  GKeyFile *kf;
-  GList *tmp, *tracks;
-  int i = 0;
-  int n_objects = 0;
-  gchar buffer[255];
-
-  GST_DEBUG ("saving formatter");
-
-  kf = g_key_file_new ();
-
-  g_key_file_set_value (kf, "General", "version", "1");
-
-  tracks = ges_timeline_get_tracks (timeline);
-
-  for (i = 0, tmp = tracks; tmp; i++, tmp = tmp->next) {
-    GESTrack *track;
-    gchar *type;
-    gchar *caps;
-    GValue v = { 0 };
-
-    track = GES_TRACK (tmp->data);
-
-    g_snprintf (buffer, 255, "Track%d", i);
-    g_value_init (&v, GES_TYPE_TRACK_TYPE);
-    g_object_get_property (G_OBJECT (track), "track-type", &v);
-
-    type = gst_value_serialize (&v);
-    caps = gst_caps_to_string (track->caps);
-
-    g_key_file_set_value (kf, buffer, "type", type);
-    g_key_file_set_string (kf, buffer, "caps", caps);
-
-    g_free (caps);
-    g_free (type);
-    gst_object_unref (track);
-    tmp->data = NULL;
-  }
-
-  g_list_free (tracks);
-
-  for (i = 0, tmp = timeline->layers; tmp; i++, tmp = tmp->next) {
-    const gchar *type;
-    GESTimelineLayer *layer;
-    GList *objs, *cur;
-    layer = tmp->data;
-
-    g_snprintf (buffer, 255, "Layer%d", i);
-
-    if (GES_IS_SIMPLE_TIMELINE_LAYER (tmp->data)) {
-      type = "simple";
-    } else {
-      type = "default";
-    }
-
-    g_key_file_set_integer (kf, buffer, "priority", layer->priority);
-    g_key_file_set_value (kf, buffer, "type", type);
-
-    objs = ges_timeline_layer_get_objects (layer);
-
-    for (cur = objs; cur; cur = cur->next) {
-      GESTimelineObject *obj;
-      GParamSpec **properties;
-      guint i, n;
-
-      obj = GES_TIMELINE_OBJECT (cur->data);
-      properties =
-          g_object_class_list_properties (G_OBJECT_GET_CLASS (obj), &n);
-
-      g_snprintf (buffer, 255, "Object%d", n_objects);
-      n_objects++;
-
-      g_key_file_set_value (kf, buffer, "type",
-          G_OBJECT_TYPE_NAME (G_OBJECT (obj)));
-
-      for (i = 0; i < n; i++) {
-        GValue v = { 0 };
-        gchar *serialized;
-        GParamSpec *p = properties[i];
-
-        g_value_init (&v, p->value_type);
-        g_object_get_property (G_OBJECT (obj), p->name, &v);
-
-        /* FIXME: does this work for properties marked G_PARAM_CONSTRUCT_ONLY?
-         * */
-
-        if ((p->flags & G_PARAM_READABLE) && (p->flags & G_PARAM_WRITABLE)) {
-          if (!(serialized = gst_value_serialize (&v)))
-            continue;
-
-          g_key_file_set_string (kf, buffer, p->name, serialized);
-          g_free (serialized);
-        }
-
-        g_value_unset (&v);
-      }
-
-      g_free (properties);
-      g_object_unref (obj);
-      cur->data = NULL;
-    }
-
-    g_list_free (objs);
-  }
-
-  if (formatter->data) {
-    g_free (formatter->data);
-  }
-
-  formatter->data = g_key_file_to_data (kf, &formatter->length, NULL);
-  g_key_file_free (kf);
-
-  return TRUE;
-}
-
-static gboolean
-create_track (GKeyFile * kf, gchar * group, GESTimeline * timeline)
-{
-  GESTrack *track;
-  GstCaps *caps;
-  gchar *caps_field, *type_field;
-  GValue v = { 0 };
-
-  if (!(caps_field = g_key_file_get_string (kf, group, "caps", NULL)))
-    return FALSE;
-
-  caps = gst_caps_from_string (caps_field);
-  g_free (caps_field);
-
-  if (!(type_field = g_key_file_get_value (kf, group, "type", NULL)))
-    return FALSE;
-
-  g_value_init (&v, GES_TYPE_TRACK_TYPE);
-  gst_value_deserialize (&v, type_field);
-  g_free (type_field);
-
-  if (!caps)
-    return FALSE;
-
-  track = ges_track_new (g_value_get_flags (&v), caps);
-
-  if (!ges_timeline_add_track (timeline, track)) {
-    g_object_unref (track);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-static GESTimelineLayer *
-create_layer (GKeyFile * kf, gchar * group, GESTimeline * timeline)
-{
-  GESTimelineLayer *ret = NULL;
-  gchar *type_field, *priority_field;
-  gboolean is_simple;
-  guint priority;
-
-  if (!(type_field = g_key_file_get_value (kf, group, "type", NULL)))
-    return FALSE;
-
-  is_simple = g_str_equal (type_field, "simple");
-  g_free (type_field);
-
-  if (!(priority_field = g_key_file_get_value (kf, group, "priority", NULL)))
-    return FALSE;
-
-  priority = strtoul (priority_field, NULL, 10);
-  g_free (priority_field);
-
-  if (is_simple) {
-    GESSimpleTimelineLayer *simple;
-    simple = ges_simple_timeline_layer_new ();
-    ret = (GESTimelineLayer *) simple;
-  } else {
-    ret = ges_timeline_layer_new ();
-  }
-
-  ges_timeline_layer_set_priority (ret, priority);
-  if (!ges_timeline_add_layer (timeline, ret)) {
-    g_object_unref (ret);
-    ret = NULL;
-  }
-
-  return ret;
-}
-
-static gboolean
-create_object (GKeyFile * kf, gchar * group, GESTimelineLayer * layer)
-{
-  GType type;
-  gchar *type_name;
-  GObject *obj;
-  GESTimelineObject *timeline_obj;
-  gchar **keys;
-  gsize n_keys, i;
-  GParamSpec *pspec;
-  GObjectClass *klass;
-  GParameter *params, *p;
-  gboolean ret = FALSE;
-
-  GST_INFO ("processing '%s'", group);
-
-  /* get a reference to the object class */
-
-  if (!(type_name = g_key_file_get_value (kf, group, "type", NULL))) {
-    GST_ERROR ("no type name for object '%s'", group);
-    return FALSE;
-  }
-
-  if (!(type = g_type_from_name (type_name))) {
-    GST_ERROR ("invalid type name '%s'", type_name);
-    goto fail_free_type_name;
-  }
-
-  if (!(klass = g_type_class_ref (type))) {
-    GST_ERROR ("couldn't get class ref");
-    goto fail_free_type_name;
-  }
-
-  if (!(keys = g_key_file_get_keys (kf, group, &n_keys, NULL)))
-    goto fail_unref_class;
-
-  /* create an array of parameters for the call to g_new0 */
-  /* skip first field 'type' */
-
-  if (!(params = g_new0 (GParameter, (n_keys - 1)))) {
-    GST_ERROR ("couldn't allocate parameter list");
-    goto fail_free_keys;
-  }
-
-  GST_DEBUG ("processing parameter list", group);
-
-  for (p = params, i = 1; i < n_keys; i++, p++) {
-    gchar *value;
-    gchar *key;
-
-    key = keys[i];
-
-    GST_DEBUG ("processing key '%s'", key);
-
-    /* find the param spec for this property */
-    if (!(pspec = g_object_class_find_property (klass, key))) {
-      GST_ERROR ("Object type %s has no property %s", type_name, key);
-      goto fail_free_params;
-    }
-
-    p->name = key;
-    g_value_init (&p->value, pspec->value_type);
-
-    /* assume this is going to work */
-    value = g_key_file_get_string (kf, group, key, NULL);
-
-    if (!gst_value_deserialize (&p->value, value)) {
-      GST_ERROR ("Couldn't read property value '%s' for property '%s'",
-          key, value);
-      goto fail_free_params;
-    }
-
-    g_free (value);
-  }
-
-  /* create the object from the supplied type name */
-
-  if (!(obj = g_object_newv (type, (n_keys - 1), params))) {
-    GST_ERROR ("couldn't create object");
-    goto fail_free_type_name;
-  }
-
-  /* check that we have a subclass of GESTimelineObject */
-
-  if (!GES_IS_TIMELINE_OBJECT (obj)) {
-    GST_ERROR ("'%s' is not a subclass of GESTimelineObject!", type_name);
-    goto fail_unref_obj;
-  }
-  timeline_obj = (GESTimelineObject *) obj;
-
-  /* add the object to the layer */
-
-  if (GES_IS_SIMPLE_TIMELINE_LAYER (layer)) {
-    if (!ges_simple_timeline_layer_add_object ((GESSimpleTimelineLayer *)
-            layer, timeline_obj, -1)) {
-      goto fail_unref_obj;
-    }
-  } else {
-    if (!ges_timeline_layer_add_object (layer, timeline_obj)) {
-      goto fail_unref_obj;
-    }
-  }
-
-  ret = TRUE;
-
-fail_unref_obj:
-  if (!ret)
-    g_object_unref (obj);
-
-fail_free_params:
-  for (p = params, i = 1; i < n_keys; i++, p++) {
-    g_value_unset (&p->value);
-  }
-  g_free (params);
-
-fail_free_keys:
-  g_strfreev (keys);
-
-fail_unref_class:
-  g_type_class_unref (klass);
-
-fail_free_type_name:
-  g_free (type_name);
-
-  return ret;
-}
-
-static gboolean
-load_ini (GESFormatter * formatter, GESTimeline * timeline)
-{
-  GKeyFile *kf;
-  GError *error = NULL;
-  gboolean ret = TRUE;
-  gchar **groups;
-  gsize n_groups, i;
-  GESTimelineLayer *cur_layer = NULL;
-
-  kf = g_key_file_new ();
-  if (!g_key_file_load_from_data (kf, formatter->data, formatter->length,
-          G_KEY_FILE_NONE, &error)) {
-    ret = FALSE;
-    GST_ERROR (error->message);
-    GST_INFO (formatter->data);
-    goto free_kf;
-  }
-
-  if (!(groups = g_key_file_get_groups (kf, &n_groups))) {
-    goto free_kf;
-  }
-
-  for (i = 0; i < n_groups; i++) {
-    gchar *group = groups[i];
-
-    if (g_str_has_prefix (group, "Track")) {
-      if (!create_track (kf, group, timeline)) {
-        GST_ERROR ("couldn't create object for %s", group);
-        ret = FALSE;
-        break;
-      }
-    }
-
-    else if (g_str_has_prefix (group, "Layer")) {
-      if (!(cur_layer = create_layer (kf, group, timeline))) {
-        GST_ERROR ("couldn't create object for %s", group);
-        ret = FALSE;
-        break;
-      }
-    }
-
-    else if (g_str_has_prefix (group, "Object")) {
-      if (!cur_layer) {
-        GST_ERROR ("Group %s occurs outside of Layer", group);
-        ret = FALSE;
-        break;
-      }
-
-      if (!create_object (kf, group, cur_layer)) {
-        GST_ERROR ("couldn't create object for %s", group);
-        ret = FALSE;
-        break;
-      }
-    }
-
-    else if (g_str_equal (group, "General")) {
-      continue;
-    }
-
-    else {
-      GST_ERROR ("Unrecognized group name %s", group);
-      ret = FALSE;
-      break;
-    }
-  }
-
-  g_strfreev (groups);
-
-free_kf:
-  g_key_file_free (kf);
-  return ret;
-}
index 01beac5..d35f22b 100644 (file)
@@ -79,8 +79,8 @@ struct _GESFormatterClass {
 
 GType ges_formatter_get_type (void);
 
-GESFormatter *ges_formatter_new (void);
 GESFormatter *ges_formatter_new_for_uri (gchar *uri);
+GESFormatter *ges_default_formatter_new (void);
 
 gboolean ges_formatter_can_load_uri (gchar * uri);
 gboolean ges_formatter_can_save_uri (gchar * uri);
diff --git a/ges/ges-keyfile-formatter.c b/ges/ges-keyfile-formatter.c
new file mode 100644 (file)
index 0000000..0dfdf0c
--- /dev/null
@@ -0,0 +1,471 @@
+/* GStreamer Editing Services
+ * Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
+ *               2010 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:ges-keyfile-formatter
+ * @short_description: Base Class for loading and saving #GESTimeline data.
+ *
+ * Responsible for loading and/or saving the contents of a #GESTimeline to/from
+ * various formats.
+ **/
+
+#include <gst/gst.h>
+#include <stdlib.h>
+#include "ges.h"
+#include "ges-internal.h"
+
+G_DEFINE_TYPE (GESKeyfileFormatter, ges_keyfile_formatter, GES_TYPE_FORMATTER);
+
+static void ges_keyfile_formatter_dispose (GObject * object);
+static void ges_keyfile_formatter_finalize (GObject * object);
+
+/* for ini format */
+static gboolean save_keyfile (GESFormatter * keyfile_formatter,
+    GESTimeline * timeline);
+static gboolean load_keyfile (GESFormatter * keyfile_formatter,
+    GESTimeline * timeline);
+
+static void
+ges_keyfile_formatter_class_init (GESKeyfileFormatterClass * klass)
+{
+  GESFormatterClass *formatter_klass;
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (klass);
+  formatter_klass = GES_FORMATTER_CLASS (klass);
+
+
+  object_class->dispose = ges_keyfile_formatter_dispose;
+  object_class->finalize = ges_keyfile_formatter_finalize;
+
+  formatter_klass->save = save_keyfile;
+  formatter_klass->load = load_keyfile;
+}
+
+static void
+ges_keyfile_formatter_init (GESKeyfileFormatter * object)
+{
+}
+
+static void
+ges_keyfile_formatter_dispose (GObject * object)
+{
+}
+
+static void
+ges_keyfile_formatter_finalize (GObject * keyfile_formatter)
+{
+}
+
+GESKeyfileFormatter *
+ges_keyfile_formatter_new (void)
+{
+  return g_object_new (GES_TYPE_KEYFILE_FORMATTER, NULL);
+}
+
+static gboolean
+save_keyfile (GESFormatter * keyfile_formatter, GESTimeline * timeline)
+{
+  GKeyFile *kf;
+  GList *tmp, *tracks;
+  int i = 0;
+  int n_objects = 0;
+  gchar buffer[255];
+
+  GST_DEBUG ("saving keyfile_formatter");
+
+  kf = g_key_file_new ();
+
+  g_key_file_set_value (kf, "General", "version", "1");
+
+  tracks = ges_timeline_get_tracks (timeline);
+
+  for (i = 0, tmp = tracks; tmp; i++, tmp = tmp->next) {
+    GESTrack *track;
+    gchar *type;
+    gchar *caps;
+    GValue v = { 0 };
+
+    track = GES_TRACK (tmp->data);
+
+    g_snprintf (buffer, 255, "Track%d", i);
+    g_value_init (&v, GES_TYPE_TRACK_TYPE);
+    g_object_get_property (G_OBJECT (track), "track-type", &v);
+
+    type = gst_value_serialize (&v);
+    caps = gst_caps_to_string (track->caps);
+
+    g_key_file_set_value (kf, buffer, "type", type);
+    g_key_file_set_string (kf, buffer, "caps", caps);
+
+    g_free (caps);
+    g_free (type);
+    gst_object_unref (track);
+    tmp->data = NULL;
+  }
+
+  g_list_free (tracks);
+
+  for (i = 0, tmp = timeline->layers; tmp; i++, tmp = tmp->next) {
+    const gchar *type;
+    GESTimelineLayer *layer;
+    GList *objs, *cur;
+    layer = tmp->data;
+
+    g_snprintf (buffer, 255, "Layer%d", i);
+
+    if (GES_IS_SIMPLE_TIMELINE_LAYER (tmp->data)) {
+      type = "simple";
+    } else {
+      type = "default";
+    }
+
+    g_key_file_set_integer (kf, buffer, "priority", layer->priority);
+    g_key_file_set_value (kf, buffer, "type", type);
+
+    objs = ges_timeline_layer_get_objects (layer);
+
+    for (cur = objs; cur; cur = cur->next) {
+      GESTimelineObject *obj;
+      GParamSpec **properties;
+      guint i, n;
+
+      obj = GES_TIMELINE_OBJECT (cur->data);
+      properties =
+          g_object_class_list_properties (G_OBJECT_GET_CLASS (obj), &n);
+
+      g_snprintf (buffer, 255, "Object%d", n_objects);
+      n_objects++;
+
+      g_key_file_set_value (kf, buffer, "type",
+          G_OBJECT_TYPE_NAME (G_OBJECT (obj)));
+
+      for (i = 0; i < n; i++) {
+        GValue v = { 0 };
+        gchar *serialized;
+        GParamSpec *p = properties[i];
+
+        g_value_init (&v, p->value_type);
+        g_object_get_property (G_OBJECT (obj), p->name, &v);
+
+        /* FIXME: does this work for properties marked G_PARAM_CONSTRUCT_ONLY?
+         * */
+
+        if ((p->flags & G_PARAM_READABLE) && (p->flags & G_PARAM_WRITABLE)) {
+          if (!(serialized = gst_value_serialize (&v)))
+            continue;
+
+          g_key_file_set_string (kf, buffer, p->name, serialized);
+          g_free (serialized);
+        }
+
+        g_value_unset (&v);
+      }
+
+      g_free (properties);
+      g_object_unref (obj);
+      cur->data = NULL;
+    }
+
+    g_list_free (objs);
+  }
+
+  if (keyfile_formatter->data) {
+    g_free (keyfile_formatter->data);
+  }
+
+  keyfile_formatter->data =
+      g_key_file_to_data (kf, &keyfile_formatter->length, NULL);
+  g_key_file_free (kf);
+
+  return TRUE;
+}
+
+static gboolean
+create_track (GKeyFile * kf, gchar * group, GESTimeline * timeline)
+{
+  GESTrack *track;
+  GstCaps *caps;
+  gchar *caps_field, *type_field;
+  GValue v = { 0 };
+
+  if (!(caps_field = g_key_file_get_string (kf, group, "caps", NULL)))
+    return FALSE;
+
+  caps = gst_caps_from_string (caps_field);
+  g_free (caps_field);
+
+  if (!(type_field = g_key_file_get_value (kf, group, "type", NULL)))
+    return FALSE;
+
+  g_value_init (&v, GES_TYPE_TRACK_TYPE);
+  gst_value_deserialize (&v, type_field);
+  g_free (type_field);
+
+  if (!caps)
+    return FALSE;
+
+  track = ges_track_new (g_value_get_flags (&v), caps);
+
+  if (!ges_timeline_add_track (timeline, track)) {
+    g_object_unref (track);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static GESTimelineLayer *
+create_layer (GKeyFile * kf, gchar * group, GESTimeline * timeline)
+{
+  GESTimelineLayer *ret = NULL;
+  gchar *type_field, *priority_field;
+  gboolean is_simple;
+  guint priority;
+
+  if (!(type_field = g_key_file_get_value (kf, group, "type", NULL)))
+    return FALSE;
+
+  is_simple = g_str_equal (type_field, "simple");
+  g_free (type_field);
+
+  if (!(priority_field = g_key_file_get_value (kf, group, "priority", NULL)))
+    return FALSE;
+
+  priority = strtoul (priority_field, NULL, 10);
+  g_free (priority_field);
+
+  if (is_simple) {
+    GESSimpleTimelineLayer *simple;
+    simple = ges_simple_timeline_layer_new ();
+    ret = (GESTimelineLayer *) simple;
+  } else {
+    ret = ges_timeline_layer_new ();
+  }
+
+  ges_timeline_layer_set_priority (ret, priority);
+  if (!ges_timeline_add_layer (timeline, ret)) {
+    g_object_unref (ret);
+    ret = NULL;
+  }
+
+  return ret;
+}
+
+static gboolean
+create_object (GKeyFile * kf, gchar * group, GESTimelineLayer * layer)
+{
+  GType type;
+  gchar *type_name;
+  GObject *obj;
+  GESTimelineObject *timeline_obj;
+  gchar **keys;
+  gsize n_keys, i;
+  GParamSpec *pspec;
+  GObjectClass *klass;
+  GParameter *params, *p;
+  gboolean ret = FALSE;
+
+  GST_INFO ("processing '%s'", group);
+
+  /* get a reference to the object class */
+
+  if (!(type_name = g_key_file_get_value (kf, group, "type", NULL))) {
+    GST_ERROR ("no type name for object '%s'", group);
+    return FALSE;
+  }
+
+  if (!(type = g_type_from_name (type_name))) {
+    GST_ERROR ("invalid type name '%s'", type_name);
+    goto fail_free_type_name;
+  }
+
+  if (!(klass = g_type_class_ref (type))) {
+    GST_ERROR ("couldn't get class ref");
+    goto fail_free_type_name;
+  }
+
+  if (!(keys = g_key_file_get_keys (kf, group, &n_keys, NULL)))
+    goto fail_unref_class;
+
+  /* create an array of parameters for the call to g_new0 */
+  /* skip first field 'type' */
+
+  if (!(params = g_new0 (GParameter, (n_keys - 1)))) {
+    GST_ERROR ("couldn't allocate parameter list");
+    goto fail_free_keys;
+  }
+
+  GST_DEBUG ("processing parameter list", group);
+
+  for (p = params, i = 1; i < n_keys; i++, p++) {
+    gchar *value;
+    gchar *key;
+
+    key = keys[i];
+
+    GST_DEBUG ("processing key '%s'", key);
+
+    /* find the param spec for this property */
+    if (!(pspec = g_object_class_find_property (klass, key))) {
+      GST_ERROR ("Object type %s has no property %s", type_name, key);
+      goto fail_free_params;
+    }
+
+    p->name = key;
+    g_value_init (&p->value, pspec->value_type);
+
+    /* assume this is going to work */
+    value = g_key_file_get_string (kf, group, key, NULL);
+
+    if (!gst_value_deserialize (&p->value, value)) {
+      GST_ERROR ("Couldn't read property value '%s' for property '%s'",
+          key, value);
+      goto fail_free_params;
+    }
+
+    g_free (value);
+  }
+
+  /* create the object from the supplied type name */
+
+  if (!(obj = g_object_newv (type, (n_keys - 1), params))) {
+    GST_ERROR ("couldn't create object");
+    goto fail_free_type_name;
+  }
+
+  /* check that we have a subclass of GESTimelineObject */
+
+  if (!GES_IS_TIMELINE_OBJECT (obj)) {
+    GST_ERROR ("'%s' is not a subclass of GESTimelineObject!", type_name);
+    goto fail_unref_obj;
+  }
+  timeline_obj = (GESTimelineObject *) obj;
+
+  /* add the object to the layer */
+
+  if (GES_IS_SIMPLE_TIMELINE_LAYER (layer)) {
+    if (!ges_simple_timeline_layer_add_object ((GESSimpleTimelineLayer *)
+            layer, timeline_obj, -1)) {
+      goto fail_unref_obj;
+    }
+  } else {
+    if (!ges_timeline_layer_add_object (layer, timeline_obj)) {
+      goto fail_unref_obj;
+    }
+  }
+
+  ret = TRUE;
+
+fail_unref_obj:
+  if (!ret)
+    g_object_unref (obj);
+
+fail_free_params:
+  for (p = params, i = 1; i < n_keys; i++, p++) {
+    g_value_unset (&p->value);
+  }
+  g_free (params);
+
+fail_free_keys:
+  g_strfreev (keys);
+
+fail_unref_class:
+  g_type_class_unref (klass);
+
+fail_free_type_name:
+  g_free (type_name);
+
+  return ret;
+}
+
+static gboolean
+load_keyfile (GESFormatter * keyfile_formatter, GESTimeline * timeline)
+{
+  GKeyFile *kf;
+  GError *error = NULL;
+  gboolean ret = TRUE;
+  gchar **groups;
+  gsize n_groups, i;
+  GESTimelineLayer *cur_layer = NULL;
+
+  kf = g_key_file_new ();
+  if (!g_key_file_load_from_data (kf, keyfile_formatter->data,
+          keyfile_formatter->length, G_KEY_FILE_NONE, &error)) {
+    ret = FALSE;
+    GST_ERROR (error->message);
+    GST_INFO (keyfile_formatter->data);
+    goto free_kf;
+  }
+
+  if (!(groups = g_key_file_get_groups (kf, &n_groups))) {
+    goto free_kf;
+  }
+
+  for (i = 0; i < n_groups; i++) {
+    gchar *group = groups[i];
+
+    if (g_str_has_prefix (group, "Track")) {
+      if (!create_track (kf, group, timeline)) {
+        GST_ERROR ("couldn't create object for %s", group);
+        ret = FALSE;
+        break;
+      }
+    }
+
+    else if (g_str_has_prefix (group, "Layer")) {
+      if (!(cur_layer = create_layer (kf, group, timeline))) {
+        GST_ERROR ("couldn't create object for %s", group);
+        ret = FALSE;
+        break;
+      }
+    }
+
+    else if (g_str_has_prefix (group, "Object")) {
+      if (!cur_layer) {
+        GST_ERROR ("Group %s occurs outside of Layer", group);
+        ret = FALSE;
+        break;
+      }
+
+      if (!create_object (kf, group, cur_layer)) {
+        GST_ERROR ("couldn't create object for %s", group);
+        ret = FALSE;
+        break;
+      }
+    }
+
+    else if (g_str_equal (group, "General")) {
+      continue;
+    }
+
+    else {
+      GST_ERROR ("Unrecognized group name %s", group);
+      ret = FALSE;
+      break;
+    }
+  }
+
+  g_strfreev (groups);
+
+free_kf:
+  g_key_file_free (kf);
+  return ret;
+}
diff --git a/ges/ges-keyfile-formatter.h b/ges/ges-keyfile-formatter.h
new file mode 100644 (file)
index 0000000..45c31d3
--- /dev/null
@@ -0,0 +1,72 @@
+/* GStreamer Editing Services
+ * Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
+ *               2010 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GES_KEYFILE_FORMATTER
+#define _GES_KEYFILE_FORMATTER
+
+#include <glib-object.h>
+#include <ges/ges-timeline.h>
+
+#define GES_TYPE_KEYFILE_FORMATTER ges_keyfile_formatter_get_type()
+
+#define GES_KEYFILE_FORMATTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GES_TYPE_KEYFILE_FORMATTER, GESKeyfileFormatter))
+
+#define GES_KEYFILE_FORMATTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GES_TYPE_KEYFILE_FORMATTER, GESKeyfileFormatterClass))
+
+#define GES_IS_KEYFILE_FORMATTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GES_TYPE_KEYFILE_FORMATTER))
+
+#define GES_IS_KEYFILE_FORMATTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GES_TYPE_KEYFILE_FORMATTER))
+
+#define GES_KEYFILE_FORMATTER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_KEYFILE_FORMATTER, GESKeyfileFormatterClass))
+
+/**
+ * GESKeyfileFormatter:
+ * @parent: parent
+ *
+ * Serializes a #GESTimeline to a file using #GKeyFile
+ */
+
+struct _GESKeyfileFormatter {
+  GESFormatter parent;
+
+  /*< public >*/
+};
+
+/**
+ * GESKeyfileFormatterClass:
+ * @parent_class: parent class
+ */
+
+struct _GESKeyfileFormatterClass {
+  GESFormatterClass parent_class;
+
+  /*< public >*/
+};
+
+GType ges_keyfile_formatter_get_type (void);
+
+GESKeyfileFormatter *ges_keyfile_formatter_new (void);
+
+#endif /* _GES_KEYFILE_FORMATTER */
index 1351d2d..003eba8 100644 (file)
@@ -108,4 +108,8 @@ typedef struct _GESTrackTextOverlayClass
 typedef struct _GESFormatter GESFormatter;
 typedef struct _GESFormatterClass GESFormatterClass;
 
+typedef struct _GESKeyfileFormatter GESKeyfileFormatter;
+typedef struct _GESKeyfileFormatterClass GESKeyfileFormatterClass;
+
+
 #endif /* __GES_TYPES_H__ */
index 4bcfe52..8be9a34 100644 (file)
--- a/ges/ges.h
+++ b/ges/ges.h
@@ -55,6 +55,7 @@
 #include <ges/ges-track-audio-transition.h>
 
 #include <ges/ges-formatter.h>
+#include <ges/ges-keyfile-formatter.h>
 
 #include <ges/ges-utils.h>