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);