mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-10 17:35:59 +00:00
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:
parent
e36c4c2bf7
commit
5665e3abb1
9 changed files with 433 additions and 47 deletions
|
@ -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));
|
||||
}
|
||||
|
|
102
ges/ges-group.c
102
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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue