diff --git a/ges/ges-base-xml-formatter.c b/ges/ges-base-xml-formatter.c
index 8ed84c45f0..3741c41e8c 100644
--- a/ges/ges-base-xml-formatter.c
+++ b/ges/ges-base-xml-formatter.c
@@ -21,9 +21,6 @@
#include "ges.h"
#include "ges-internal.h"
-/* TODO:
- * + Handle Groups
- **/
#define parent_class ges_base_xml_formatter_parent_class
G_DEFINE_ABSTRACT_TYPE (GESBaseXmlFormatter, ges_base_xml_formatter,
GES_TYPE_FORMATTER);
@@ -57,6 +54,13 @@ typedef struct PendingChildProperties
GstStructure *structure;
} PendingChildProperties;
+typedef struct PendingGroup
+{
+ GESGroup *group;
+
+ GList *pending_children;
+} PendingGroup;
+
typedef struct PendingClip
{
gchar *id;
@@ -106,7 +110,7 @@ struct _GESBaseXmlFormatterPrivate
GHashTable *clipid_pendings;
/* Clip.ID -> Clip */
- GHashTable *clips;
+ GHashTable *containers;
/* ID -> track */
GHashTable *tracks;
@@ -124,6 +128,8 @@ struct _GESBaseXmlFormatterPrivate
PendingClip *current_pending_clip;
gboolean timeline_auto_transition;
+
+ GList *groups;
};
static void
@@ -333,7 +339,7 @@ _dispose (GObject * object)
g_clear_pointer (&priv->assetid_pendingclips,
(GDestroyNotify) g_hash_table_unref);
- g_clear_pointer (&priv->clips, (GDestroyNotify) g_hash_table_unref);
+ g_clear_pointer (&priv->containers, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&priv->clipid_pendings, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&priv->tracks, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&priv->layers, (GDestroyNotify) g_hash_table_unref);
@@ -371,7 +377,7 @@ ges_base_xml_formatter_init (GESBaseXmlFormatter * self)
g_str_equal, g_free, NULL);
priv->clipid_pendings = g_hash_table_new_full (g_str_hash,
g_str_equal, g_free, NULL);
- priv->clips = g_hash_table_new_full (g_str_hash,
+ priv->containers = g_hash_table_new_full (g_str_hash,
g_str_equal, g_free, gst_object_unref);
priv->tracks = g_hash_table_new_full (g_str_hash,
g_str_equal, g_free, gst_object_unref);
@@ -422,11 +428,37 @@ _set_auto_transition (gpointer prio, LayerEntry * entry, gpointer udata)
ges_layer_set_auto_transition (entry->layer, entry->auto_trans);
}
+static void
+_add_all_groups (GESFormatter * self)
+{
+ GList *tmp;
+ GESTimelineElement *child;
+ GESBaseXmlFormatterPrivate *priv = GES_BASE_XML_FORMATTER (self)->priv;
+
+ for (tmp = priv->groups; tmp; tmp = tmp->next) {
+ GList *lchild;
+ PendingGroup *pgroup = tmp->data;
+
+ for (lchild = ((PendingGroup *) tmp->data)->pending_children; lchild;
+ lchild = lchild->next) {
+ child = g_hash_table_lookup (priv->containers, lchild->data);
+
+ GST_DEBUG_OBJECT (tmp->data, "Adding %s child %" GST_PTR_FORMAT " %s",
+ (const gchar *) lchild->data, child,
+ GES_TIMELINE_ELEMENT_NAME (child));
+ ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (pgroup->group), self->timeline);
+ ges_container_add (GES_CONTAINER (pgroup->group), child);
+ }
+ }
+}
+
static void
_loading_done (GESFormatter * self)
{
GESBaseXmlFormatterPrivate *priv = GES_BASE_XML_FORMATTER (self)->priv;
+ _add_all_groups (self);
+
if (priv->parsecontext)
g_markup_parse_context_free (priv->parsecontext);
priv->parsecontext = NULL;
@@ -494,7 +526,7 @@ _add_object_to_layer (GESBaseXmlFormatterPrivate * priv, const gchar * id,
gst_structure_foreach (properties,
(GstStructureForeachFunc) set_property_foreach, clip);
- g_hash_table_insert (priv->clips, g_strdup (id), gst_object_ref (clip));
+ g_hash_table_insert (priv->containers, g_strdup (id), gst_object_ref (clip));
return clip;
}
@@ -982,7 +1014,8 @@ ges_base_xml_formatter_add_track (GESBaseXmlFormatter * self,
gst_structure_get (properties, "restriction-caps", G_TYPE_STRING,
&restriction, NULL);
- gst_structure_remove_fields (properties, "restriction-caps", "caps", "message-forward", NULL);
+ gst_structure_remove_fields (properties, "restriction-caps", "caps",
+ "message-forward", NULL);
if (g_strcmp0 (restriction, "NULL")) {
caps = gst_caps_from_string (restriction);
ges_track_set_restriction_caps (track, caps);
@@ -1069,10 +1102,9 @@ ges_base_xml_formatter_add_source (GESBaseXmlFormatter * self,
priv->current_pending_clip->children_props =
g_list_append (priv->current_pending_clip->children_props, pchildprops);
return;
- }
-
- else
+ } else {
element = priv->current_track_element;
+ }
if (element == NULL) {
GST_WARNING
@@ -1127,7 +1159,7 @@ ges_base_xml_formatter_add_track_element (GESBaseXmlFormatter * self,
ges_meta_container_add_metas_from_string (GES_META_CONTAINER
(trackelement), metadatas);
- clip = g_hash_table_lookup (priv->clips, timeline_obj_id);
+ clip = g_hash_table_lookup (priv->containers, timeline_obj_id);
if (clip) {
_add_track_element (GES_FORMATTER (self), clip, trackelement, track_id,
children_properties, properties);
@@ -1230,3 +1262,44 @@ done:
if (restriction)
gst_caps_unref (restriction);
}
+
+void
+ges_base_xml_formatter_add_group (GESBaseXmlFormatter * self,
+ const gchar * id, const gchar * properties)
+{
+ PendingGroup *pgroup;
+ GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
+
+ if (priv->check_only)
+ return;
+
+ pgroup = g_slice_new0 (PendingGroup);
+ pgroup->group = ges_group_new ();
+
+ g_hash_table_insert (priv->containers, g_strdup (id),
+ gst_object_ref (pgroup->group));
+ priv->groups = g_list_prepend (priv->groups, pgroup);
+
+ return;
+}
+
+void
+ges_base_xml_formatter_last_group_add_child (GESBaseXmlFormatter * self,
+ const gchar * child_id, const gchar * name)
+{
+ PendingGroup *pgroup;
+ GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
+
+ if (priv->check_only)
+ return;
+
+ g_return_if_fail (priv->groups);
+
+ pgroup = priv->groups->data;
+
+ pgroup->pending_children =
+ g_list_prepend (pgroup->pending_children, g_strdup (child_id));
+
+ GST_DEBUG_OBJECT (self, "Adding %s to %s", child_id,
+ GES_TIMELINE_ELEMENT_NAME (((PendingGroup *) priv->groups->data)->group));
+}
diff --git a/ges/ges-group.c b/ges/ges-group.c
index 698e93df7c..2b43383cb0 100644
--- a/ges/ges-group.c
+++ b/ges/ges-group.c
@@ -56,10 +56,15 @@ struct _GESGroupPrivate
enum
{
PROP_0,
+ PROP_START,
+ PROP_INPOINT,
+ PROP_DURATION,
+ PROP_MAX_DURATION,
+ PROP_PRIORITY,
PROP_LAST
};
-/* static GParamSpec *properties[PROP_LAST]; */
+static GParamSpec *properties[PROP_LAST] = { NULL, };
/****************************************************
* Our listening of children *
@@ -511,9 +516,26 @@ static void
ges_group_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
+ GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
+
switch (property_id) {
+ case PROP_START:
+ g_value_set_uint64 (value, self->start);
+ break;
+ case PROP_INPOINT:
+ g_value_set_uint64 (value, self->inpoint);
+ break;
+ case PROP_DURATION:
+ g_value_set_uint64 (value, self->duration);
+ break;
+ case PROP_MAX_DURATION:
+ g_value_set_uint64 (value, self->maxduration);
+ break;
+ case PROP_PRIORITY:
+ g_value_set_uint (value, self->priority);
+ break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
}
}
@@ -521,9 +543,26 @@ static void
ges_group_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
+ GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
+
switch (property_id) {
+ case PROP_START:
+ ges_timeline_element_set_start (self, g_value_get_uint64 (value));
+ break;
+ case PROP_INPOINT:
+ ges_timeline_element_set_inpoint (self, g_value_get_uint64 (value));
+ break;
+ case PROP_DURATION:
+ ges_timeline_element_set_duration (self, g_value_get_uint64 (value));
+ break;
+ case PROP_PRIORITY:
+ ges_timeline_element_set_priority (self, g_value_get_uint (value));
+ break;
+ case PROP_MAX_DURATION:
+ ges_timeline_element_set_max_duration (self, g_value_get_uint64 (value));
+ break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
}
}
@@ -544,7 +583,62 @@ ges_group_class_init (GESGroupClass * klass)
element_class->set_inpoint = _set_inpoint;
element_class->set_start = _set_start;
element_class->set_priority = _set_priority;
- /* TODO implement the deep_copy Virtual method */
+
+ /* We override start, inpoint, duration and max-duration from GESTimelineElement
+ * in order to makes sure those fields are not serialized.
+ */
+ /**
+ * GESGroup:start:
+ *
+ * The position of the object in its container (in nanoseconds).
+ */
+ properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
+ "The position in the container", 0, G_MAXUINT64, 0,
+ G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
+
+ /**
+ * GESGroup:in-point:
+ *
+ * The in-point at which this #GESGroup will start outputting data
+ * from its contents (in nanoseconds).
+ *
+ * Ex : an in-point of 5 seconds means that the first outputted buffer will
+ * be the one located 5 seconds in the controlled resource.
+ */
+ properties[PROP_INPOINT] =
+ g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
+ G_MAXUINT64, 0, G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
+
+ /**
+ * GESGroup:duration:
+ *
+ * The duration (in nanoseconds) which will be used in the container
+ */
+ properties[PROP_DURATION] =
+ g_param_spec_uint64 ("duration", "Duration", "The duration to use", 0,
+ G_MAXUINT64, GST_CLOCK_TIME_NONE,
+ G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
+
+ /**
+ * GESGroup:max-duration:
+ *
+ * The maximum duration (in nanoseconds) of the #GESGroup.
+ */
+ properties[PROP_MAX_DURATION] =
+ g_param_spec_uint64 ("max-duration", "Maximum duration",
+ "The maximum duration of the object", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | GES_PARAM_NO_SERIALIZATION);
+
+ /**
+ * GESTGroup:priority:
+ *
+ * The priority of the object.
+ */
+ properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
+ "The priority of the object", 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
+
+ g_object_class_install_properties (object_class, PROP_LAST, properties);
container_class->add_child = _add_child;
container_class->child_added = _child_added;
diff --git a/ges/ges-internal.h b/ges/ges-internal.h
index 6e30f507e0..d2ad1b370b 100644
--- a/ges/ges-internal.h
+++ b/ges/ges-internal.h
@@ -104,6 +104,9 @@ G_GNUC_INTERNAL
void
timeline_fill_gaps (GESTimeline *timeline);
+G_GNUC_INTERNAL GList *
+timeline_get_groups (GESTimeline * timeline);
+
G_GNUC_INTERNAL
void
track_resort_and_fill_gaps (GESTrack *track);
@@ -220,7 +223,7 @@ G_GNUC_INTERNAL void ges_base_xml_formatter_add_track (GESBaseXmlForma
GstStructure *properties,
const gchar *metadatas,
GError **error);
-void ges_base_xml_formatter_add_encoding_profile (GESBaseXmlFormatter * self,
+G_GNUC_INTERNAL void ges_base_xml_formatter_add_encoding_profile(GESBaseXmlFormatter * self,
const gchar *type,
const gchar *parent,
const gchar * name,
@@ -249,6 +252,14 @@ G_GNUC_INTERNAL void ges_base_xml_formatter_add_source (GESBaseXmlForma
const gchar * track_id,
GstStructure *children_properties);
+G_GNUC_INTERNAL void ges_base_xml_formatter_add_group (GESBaseXmlFormatter *self,
+ const gchar *name,
+ const gchar *properties);
+
+G_GNUC_INTERNAL void ges_base_xml_formatter_last_group_add_child(GESBaseXmlFormatter *self,
+ const gchar * id,
+ const gchar * name);
+
G_GNUC_INTERNAL void ges_base_xml_formatter_add_control_binding (GESBaseXmlFormatter * self,
const gchar * binding_type,
const gchar * source_type,
diff --git a/ges/ges-timeline.c b/ges/ges-timeline.c
index c73864b748..4f0c89bda4 100644
--- a/ges/ges-timeline.c
+++ b/ges/ges-timeline.c
@@ -1958,6 +1958,12 @@ timeline_remove_group (GESTimeline * timeline, GESGroup * group)
gst_object_unref (group);
}
+GList *
+timeline_get_groups (GESTimeline * timeline)
+{
+ return timeline->priv->groups;
+}
+
static GPtrArray *
select_tracks_for_object_default (GESTimeline * timeline,
GESClip * clip, GESTrackElement * tr_object, gpointer user_data)
diff --git a/ges/ges-xml-formatter.c b/ges/ges-xml-formatter.c
index 3bccc682f4..871fd41122 100644
--- a/ges/ges-xml-formatter.c
+++ b/ges/ges-xml-formatter.c
@@ -45,6 +45,10 @@ struct _GESXmlFormatterPrivate
gboolean project_opened;
GString *str;
+
+ GHashTable *element_id;
+
+ guint nbelements;
};
static inline void
@@ -671,6 +675,44 @@ wrong_type:
"element '%s', %s not a GESBaseEffect'", element_name, strtype);
}
+
+static inline void
+_parse_group (GMarkupParseContext * context, const gchar * element_name,
+ const gchar ** attribute_names, const gchar ** attribute_values,
+ GESXmlFormatter * self, GError ** error)
+{
+ const gchar *id, *properties;
+
+ if (!g_markup_collect_attributes (element_name, attribute_names,
+ attribute_values, error,
+ G_MARKUP_COLLECT_STRING, "id", &id,
+ G_MARKUP_COLLECT_STRING, "properties", &properties,
+ G_MARKUP_COLLECT_INVALID)) {
+ return;
+ }
+
+ ges_base_xml_formatter_add_group (GES_BASE_XML_FORMATTER (self), id,
+ properties);
+}
+
+static inline void
+_parse_group_child (GMarkupParseContext * context, const gchar * element_name,
+ const gchar ** attribute_names, const gchar ** attribute_values,
+ GESXmlFormatter * self, GError ** error)
+{
+ const gchar *child_id, *name;
+
+ if (!g_markup_collect_attributes (element_name, attribute_names,
+ attribute_values, error,
+ G_MARKUP_COLLECT_STRING, "id", &child_id,
+ G_MARKUP_COLLECT_STRING, "name", &name, G_MARKUP_COLLECT_INVALID)) {
+ return;
+ }
+
+ ges_base_xml_formatter_last_group_add_child (GES_BASE_XML_FORMATTER (self),
+ child_id, name);
+}
+
static void
_parse_element_start (GMarkupParseContext * context, const gchar * element_name,
const gchar ** attribute_names, const gchar ** attribute_values,
@@ -714,6 +756,12 @@ _parse_element_start (GMarkupParseContext * context, const gchar * element_name,
else if (g_strcmp0 (element_name, "binding") == 0)
_parse_binding (context, element_name, attribute_names,
attribute_values, self, error);
+ else if (g_strcmp0 (element_name, "group") == 0)
+ _parse_group (context, element_name, attribute_names,
+ attribute_values, self, error);
+ else if (g_strcmp0 (element_name, "child") == 0)
+ _parse_group_child (context, element_name, attribute_names,
+ attribute_values, self, error);
else
GST_LOG_OBJECT (self, "Element %s not handled", element_name);
}
@@ -862,7 +910,7 @@ _save_assets (GString * str, GESProject * project)
}
static inline void
-_save_tracks (GString * str, GESTimeline * timeline)
+_save_tracks (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
{
gchar *strtmp, *metas;
GESTrack *track;
@@ -1020,14 +1068,13 @@ _save_effect (GString * str, guint clip_id, GESTrackElement * trackelement,
}
static inline void
-_save_layers (GString * str, GESTimeline * timeline)
+_save_layers (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
{
gchar *properties, *metas;
GESLayer *layer;
GESClip *clip;
GList *tmplayer, *tmpclip, *clips;
-
- guint nbclips = 0;
+ GESXmlFormatterPrivate *priv = self->priv;
for (tmplayer = timeline->layers; tmplayer; tmplayer = tmplayer->next) {
guint priority;
@@ -1061,16 +1108,19 @@ _save_layers (GString * str, GESTimeline * timeline)
g_markup_printf_escaped (" \n", nbclips,
- ges_extractable_get_id (GES_EXTRACTABLE (clip)),
+ G_GUINT64_FORMAT "' rate='%d' properties='%s' >\n",
+ priv->nbelements, ges_extractable_get_id (GES_EXTRACTABLE (clip)),
g_type_name (G_OBJECT_TYPE (clip)), priority,
ges_clip_get_supported_formats (clip), _START (clip),
_DURATION (clip), _INPOINT (clip), 0, properties));
g_free (properties);
+ g_hash_table_insert (self->priv->element_id, clip,
+ GINT_TO_POINTER (priv->nbelements));
+
for (tmpeffect = effects; tmpeffect; tmpeffect = tmpeffect->next)
- _save_effect (str, nbclips, GES_TRACK_ELEMENT (tmpeffect->data),
- timeline);
+ _save_effect (str, priv->nbelements,
+ GES_TRACK_ELEMENT (tmpeffect->data), timeline);
tracks = ges_timeline_get_tracks (timeline);
@@ -1096,15 +1146,66 @@ _save_layers (GString * str, GESTimeline * timeline)
g_string_append (str, " \n");
- nbclips++;
+ priv->nbelements++;
}
g_string_append (str, " \n");
}
}
+static void
+_save_group (GESXmlFormatter * self, GString * str, GList ** seen_groups,
+ GESGroup * group)
+{
+ GList *tmp;
+ gchar *properties;
+
+ if (g_list_find (*seen_groups, group)) {
+ GST_DEBUG_OBJECT (group, "Already serialized");
+
+ return;
+ }
+
+ *seen_groups = g_list_prepend (*seen_groups, group);
+ for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
+ if (GES_IS_GROUP (tmp->data)) {
+ _save_group (self, str, seen_groups,
+ GES_GROUP (GES_TIMELINE_ELEMENT (tmp->data)));
+ }
+ }
+
+ properties = _serialize_properties (G_OBJECT (group), NULL);
+ g_string_append_printf (str, " \n",
+ self->priv->nbelements, properties);
+ g_free (properties);
+ g_hash_table_insert (self->priv->element_id, group,
+ GINT_TO_POINTER (self->priv->nbelements));
+ self->priv->nbelements++;
+
+ for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
+ gint id = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->element_id,
+ tmp->data));
+
+ g_string_append_printf (str, " \n", id,
+ GES_TIMELINE_ELEMENT_NAME (tmp->data));
+ }
+ g_string_append (str, " \n");
+}
+
+static void
+_save_groups (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
+{
+ GList *tmp;
+ GList *seen_groups = NULL;
+
+ g_string_append (str, " \n");
+ for (tmp = timeline_get_groups (timeline); tmp; tmp = tmp->next) {
+ _save_group (self, str, &seen_groups, tmp->data);
+ }
+ g_string_append (str, " \n");
+}
static inline void
-_save_timeline (GString * str, GESTimeline * timeline)
+_save_timeline (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
{
gchar *properties = NULL, *metas = NULL;
@@ -1118,8 +1219,9 @@ _save_timeline (GString * str, GESTimeline * timeline)
g_markup_printf_escaped
(" \n", properties, metas));
- _save_tracks (str, timeline);
- _save_layers (str, timeline);
+ _save_tracks (self, str, timeline);
+ _save_layers (self, str, timeline);
+ _save_groups (self, str, timeline);
g_string_append (str, " \n");
@@ -1277,7 +1379,7 @@ _save (GESFormatter * formatter, GESTimeline * timeline, GError ** error)
_save_assets (str, project);
g_string_append (str, " \n");
- _save_timeline (str, timeline);
+ _save_timeline (GES_XML_FORMATTER (formatter), str, timeline);
g_string_append (str, "\n");
priv->str = NULL;
@@ -1309,6 +1411,16 @@ ges_xml_formatter_init (GESXmlFormatter * self)
GESXmlFormatterPrivate *priv = _GET_PRIV (self);
priv->project_opened = FALSE;
+ priv->element_id = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ self->priv = priv;
+}
+
+static void
+_dispose (GObject * object)
+{
+ g_clear_pointer (&GES_XML_FORMATTER (object)->priv->element_id,
+ (GDestroyNotify) g_hash_table_unref);
}
static void
@@ -1322,6 +1434,7 @@ ges_xml_formatter_class_init (GESXmlFormatterClass * self_class)
g_type_class_add_private (self_class, sizeof (GESXmlFormatterPrivate));
object_class->get_property = _get_property;
object_class->set_property = _set_property;
+ object_class->dispose = _dispose;
basexmlformatter_class->content_parser.start_element = _parse_element_start;
basexmlformatter_class->content_parser.end_element = _parse_element_end;
diff --git a/tests/check/ges/group.c b/tests/check/ges/group.c
index f8b588d2c5..f3919e4e7e 100644
--- a/tests/check/ges/group.c
+++ b/tests/check/ges/group.c
@@ -525,6 +525,93 @@ GST_START_TEST (test_group_in_self)
GST_END_TEST;
+static void
+project_loaded_cb (GESProject * project, GESTimeline * timeline,
+ GMainLoop * mainloop)
+{
+ GST_ERROR ("LOADED!");
+ g_main_loop_quit (mainloop);
+}
+
+GST_START_TEST (test_group_serialization)
+{
+ gchar *tmpuri;
+ GESLayer *layer;
+ GESClip *c, *c1, *c2, *c3;
+ GESAsset *asset;
+ GESTimeline *timeline;
+ GESGroup *group;
+ GESProject *project;
+ GMainLoop *mainloop;
+
+ GError *err = NULL;
+ GList *tmp, *clips = NULL;
+
+ ges_init ();
+
+ timeline = ges_timeline_new_audio_video ();
+
+ layer = ges_timeline_append_layer (timeline);
+ asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL);
+
+ c = ges_layer_add_asset (layer, asset, 0, 0, 10, GES_TRACK_TYPE_UNKNOWN);
+
+ c1 = ges_layer_add_asset (layer, asset, 10, 0, 10, GES_TRACK_TYPE_UNKNOWN);
+
+ clips = g_list_prepend (clips, c);
+ clips = g_list_prepend (clips, c1);
+
+ c2 = ges_layer_add_asset (layer, asset, 20, 0, 10, GES_TRACK_TYPE_UNKNOWN);
+
+ c3 = ges_layer_add_asset (layer, asset, 30, 0, 10, GES_TRACK_TYPE_UNKNOWN);
+
+ group = GES_GROUP (ges_container_group (clips));
+ fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
+ g_list_free (clips);
+
+
+ clips = g_list_append (NULL, group);
+ clips = g_list_append (clips, c2);
+ group = GES_GROUP (ges_container_group (clips));
+ fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
+ g_list_free (clips);
+
+ clips = g_list_append (NULL, group);
+ clips = g_list_append (clips, c3);
+ group = GES_GROUP (ges_container_group (clips));
+ fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
+ g_list_free (clips);
+
+ project =
+ GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE (timeline)));
+
+ tmpuri = ges_test_get_tmp_uri ("test-auto-transition-save.xges");
+ fail_unless (ges_project_save (project, timeline, tmpuri, NULL, TRUE, NULL));
+ gst_object_unref (timeline);
+ gst_object_unref (asset);
+
+ project = ges_project_new (tmpuri);
+ mainloop = g_main_loop_new (NULL, FALSE);
+ g_signal_connect (project, "loaded", (GCallback) project_loaded_cb, mainloop);
+ timeline = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &err));
+ g_main_loop_run (mainloop);
+
+ fail_unless (err == NULL, "%s", err ? err->message : "Nothing");
+ fail_unless (timeline != NULL);
+
+ layer = timeline->layers->data;
+ for (tmp = ges_layer_get_clips (layer); tmp; tmp = tmp->next) {
+ fail_unless (GES_IS_GROUP (GES_TIMELINE_ELEMENT_PARENT (tmp->data)),
+ "%s parent is %p, NOT a group", GES_TIMELINE_ELEMENT_NAME (tmp->data),
+ GES_TIMELINE_ELEMENT_PARENT (tmp->data));
+ }
+
+
+ g_free (tmpuri);
+}
+
+GST_END_TEST;
+
static Suite *
ges_suite (void)
{
@@ -536,6 +623,7 @@ ges_suite (void)
tcase_add_test (tc_chain, test_move_group);
tcase_add_test (tc_chain, test_group_in_group);
tcase_add_test (tc_chain, test_group_in_self);
+ tcase_add_test (tc_chain, test_group_serialization);
return s;
}
diff --git a/tests/check/ges/project.c b/tests/check/ges/project.c
index 65e621084a..7325e5b040 100644
--- a/tests/check/ges/project.c
+++ b/tests/check/ges/project.c
@@ -33,20 +33,6 @@ project_loaded_cb (GESProject * project, GESTimeline * timeline,
g_main_loop_quit (mainloop);
}
-static gchar *
-get_tmp_uri (const gchar * filename)
-{
- gchar *location, *uri;
-
- location = g_build_filename (g_get_tmp_dir (),
- "test-keyframes-save.xges", NULL);
-
- uri = g_strconcat ("file://", location, NULL);
- g_free (location);
-
- return uri;
-}
-
GST_START_TEST (test_project_simple)
{
gchar *id;
@@ -459,7 +445,7 @@ GST_START_TEST (test_project_add_properties)
_add_properties (timeline);
- uri = get_tmp_uri ("test-properties-save.xges");
+ uri = ges_test_get_tmp_uri ("test-properties-save.xges");
formatter_asset = ges_asset_request (GES_TYPE_FORMATTER, "ges", NULL);
saved =
ges_project_save (project, timeline, uri, formatter_asset, TRUE, NULL);
@@ -526,7 +512,7 @@ GST_START_TEST (test_project_load_xges)
_test_project (project, timeline);
g_free (uri);
- uri = get_tmp_uri ("test-project_TMP.xges");
+ uri = ges_test_get_tmp_uri ("test-project_TMP.xges");
formatter_asset = ges_asset_request (GES_TYPE_FORMATTER, "ges", NULL);
saved =
ges_project_save (project, timeline, uri, formatter_asset, TRUE, NULL);
@@ -597,7 +583,7 @@ GST_START_TEST (test_project_auto_transition)
/* Set timeline and layers auto-transition to TRUE */
ges_timeline_set_auto_transition (timeline, TRUE);
- tmpuri = get_tmp_uri ("test-auto-transition-save.xges");
+ tmpuri = ges_test_get_tmp_uri ("test-auto-transition-save.xges");
formatter_asset = ges_asset_request (GES_TYPE_FORMATTER, "ges", NULL);
saved =
ges_project_save (project, timeline, tmpuri, formatter_asset, TRUE, NULL);
diff --git a/tests/check/ges/test-utils.c b/tests/check/ges/test-utils.c
index f92c9b1a7b..106e877658 100644
--- a/tests/check/ges/test-utils.c
+++ b/tests/check/ges/test-utils.c
@@ -277,3 +277,17 @@ play_timeline (GESTimeline * timeline)
return TRUE;
}
+
+gchar *
+ges_test_get_tmp_uri (const gchar * filename)
+{
+ gchar *location, *uri;
+
+ location = g_build_filename (g_get_tmp_dir (),
+ "test-keyframes-save.xges", NULL);
+
+ uri = g_strconcat ("file://", location, NULL);
+ g_free (location);
+
+ return uri;
+}
diff --git a/tests/check/ges/test-utils.h b/tests/check/ges/test-utils.h
index 879c119bbe..b8cbcb479a 100644
--- a/tests/check/ges/test-utils.h
+++ b/tests/check/ges/test-utils.h
@@ -34,6 +34,7 @@ GESPipeline * ges_test_create_pipeline (GESTimeline *timeline);
#define LAYER_HEIGHT 1000
+gchar * ges_test_get_tmp_uri (const gchar * filename);
gchar * ges_test_get_audio_only_uri (void);
gchar * ges_test_get_audio_video_uri (void);
gchar * ges_test_get_image_uri (void);