xml-formatter: Serialize groups

They were not serialized until now.

That implies several changes:

* Override GESTimelineElement [start, inpoint, duration] properties in
  GESGroup to ensure that those properties are not serialized as they
  should not be.

* Rename GESBaseXmlContainer->clips field to
  GESBaseXmlContainer->containers as the hashtable now contains Groups

https://bugzilla.gnome.org/show_bug.cgi?id=709148
This commit is contained in:
Thibault Saunier 2014-10-27 16:51:42 +01:00
parent e36c4c2bf7
commit 5665e3abb1
9 changed files with 433 additions and 47 deletions

View file

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

View file

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

View file

@ -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,

View file

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

View file

@ -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 (" <clip id='%i' asset-id='%s'"
" type-name='%s' layer-priority='%i' track-types='%i' start='%"
G_GUINT64_FORMAT "' duration='%" G_GUINT64_FORMAT "' inpoint='%"
G_GUINT64_FORMAT "' rate='%d' properties='%s' >\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, " </clip>\n");
nbclips++;
priv->nbelements++;
}
g_string_append (str, " </layer>\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, " <group id='%d' properties='%s'>\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, " <child id='%d' name='%s'/>\n", id,
GES_TIMELINE_ELEMENT_NAME (tmp->data));
}
g_string_append (str, " </group>\n");
}
static void
_save_groups (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
{
GList *tmp;
GList *seen_groups = NULL;
g_string_append (str, " <groups>\n");
for (tmp = timeline_get_groups (timeline); tmp; tmp = tmp->next) {
_save_group (self, str, &seen_groups, tmp->data);
}
g_string_append (str, " </groups>\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
(" <timeline properties='%s' metadatas='%s'>\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, " </timeline>\n");
@ -1277,7 +1379,7 @@ _save (GESFormatter * formatter, GESTimeline * timeline, GError ** error)
_save_assets (str, project);
g_string_append (str, " </ressources>\n");
_save_timeline (str, timeline);
_save_timeline (GES_XML_FORMATTER (formatter), str, timeline);
g_string_append (str, "</project>\n</ges>");
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;

View file

@ -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;
}

View file

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

View file

@ -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;
}

View file

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