formatter: Fix saving/loading project with clip speed rate control

We need to ensure that clips duration is set after time effects are
added and we now need to serialize effects inpoints and max duration.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/177>
This commit is contained in:
Thibault Saunier 2020-05-21 17:22:18 -04:00 committed by Henry Wilkes
parent e142f49177
commit db5c62ad4c
5 changed files with 56 additions and 16 deletions

View file

@ -94,6 +94,7 @@ struct _GESBaseXmlFormatterPrivate
GESTrackElement *current_track_element;
GESClip *current_clip;
GstClockTime current_clip_duration;
gboolean timeline_auto_transition;
@ -416,6 +417,7 @@ ges_base_xml_formatter_init (GESBaseXmlFormatter * self)
g_direct_equal, NULL, (GDestroyNotify) _free_layer_entry);
priv->current_track_element = NULL;
priv->current_clip = NULL;
priv->current_clip_duration = GST_CLOCK_TIME_NONE;
priv->timeline_auto_transition = FALSE;
}
@ -636,8 +638,16 @@ _add_track_element (GESFormatter * self, GESClip * clip,
(GstStructureForeachFunc) _set_child_property, trackelement);
if (properties) {
gboolean has_internal_source;
/* We do not serialize the priority anymore, and we should never have. */
gst_structure_remove_field (properties, "priority");
/* Ensure that has-internal-source is set before inpoint as otherwise
* the inpoint will be ignored */
if (gst_structure_get_boolean (properties, "has-internal-source",
&has_internal_source) && has_internal_source)
g_object_set (trackelement, "has-internal-source", has_internal_source,
NULL);
gst_structure_foreach (properties,
(GstStructureForeachFunc) set_property_foreach, trackelement);
}
@ -915,6 +925,7 @@ ges_base_xml_formatter_add_clip (GESBaseXmlFormatter * self,
if (!nclip)
return;
priv->current_clip_duration = duration;
priv->current_clip = nclip;
}
@ -1335,3 +1346,24 @@ ges_base_xml_formatter_last_group_add_child (GESBaseXmlFormatter * self,
GST_DEBUG_OBJECT (self, "Adding %s to %s", child_id,
GES_TIMELINE_ELEMENT_NAME (((PendingGroup *) priv->groups->data)->group));
}
void
ges_base_xml_formatter_end_current_clip (GESBaseXmlFormatter * self)
{
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (priv->state != STATE_LOADING_CLIPS) {
GST_DEBUG_OBJECT (self, "Not ending clip in %s state.",
loading_state_name (priv->state));
return;
}
g_return_if_fail (priv->current_clip);
if (_DURATION (priv->current_clip) != priv->current_clip_duration)
_set_duration0 (GES_TIMELINE_ELEMENT (priv->current_clip),
priv->current_clip_duration);
priv->current_clip = NULL;
priv->current_clip_duration = GST_CLOCK_TIME_NONE;
}

View file

@ -377,7 +377,10 @@ G_GNUC_INTERNAL void ges_base_xml_formatter_set_timeline_properties(GESBaseXmlFo
GESTimeline *timeline,
const gchar *properties,
const gchar *metadatas);
G_GNUC_INTERNAL void ges_xml_formatter_deinit (void);
G_GNUC_INTERNAL void ges_base_xml_formatter_end_current_clip (GESBaseXmlFormatter *self);
G_GNUC_INTERNAL void ges_xml_formatter_deinit (void);
G_GNUC_INTERNAL gboolean set_property_foreach (GQuark field_id,
const GValue * value,

View file

@ -1021,6 +1021,9 @@ _parse_element_end (GMarkupParseContext * context,
if (!priv->subproject_depth) {
g_clear_pointer (&priv->subproject, g_free);
}
} else if (!g_strcmp0 (element_name, "clip")) {
if (!priv->subproject)
ges_base_xml_formatter_end_current_clip (GES_BASE_XML_FORMATTER (self));
}
}
@ -1553,8 +1556,7 @@ _save_effect (GString * str, guint clip_id, GESTrackElement * trackelement,
g_list_free_full (tracks, gst_object_unref);
properties = _serialize_properties (G_OBJECT (trackelement), NULL, "start",
"in-point", "duration", "locked", "max-duration", "name", "priority",
NULL);
"duration", "locked", "name", "priority", NULL);
metas =
ges_meta_container_metas_to_string (GES_META_CONTAINER (trackelement));
extractable_id = ges_extractable_get_id (GES_EXTRACTABLE (trackelement));

View file

@ -213,11 +213,11 @@ class GESSimpleTimelineTest(GESTest):
return clip
def append_clip(self, layer=0, asset_type=GES.TestClip):
def append_clip(self, layer=0, asset_type=GES.TestClip, asset_id=None):
while len(self.timeline.get_layers()) < layer + 1:
self.timeline.append_layer()
layer = self.timeline.get_layers()[layer]
clip = GES.Asset.request(asset_type, None).extract()
clip = GES.Asset.request(asset_type, asset_id).extract()
clip.props.start = layer.get_duration()
clip.props.duration = 10
self.assertTrue(layer.add_clip(clip))
@ -231,16 +231,16 @@ class GESSimpleTimelineTest(GESTest):
and not GObject.type_is_a(p.value_type, GObject.Object)]
for p in props:
pname = p.name
v0 = GObject.Value()
v0.init(p.value_type)
v0.set_value(ref.get_property(pname))
refval = GObject.Value()
refval.init(p.value_type)
refval.set_value(ref.get_property(pname))
v1 = GObject.Value()
v1.init(p.value_type)
v1.set_value(element.get_property(pname))
value = GObject.Value()
value.init(p.value_type)
value.set_value(element.get_property(pname))
self.assertTrue(Gst.value_compare(v0, v1) == Gst.VALUE_EQUAL,
"%s are not equal: %s != %s" % (pname, v0, v1))
self.assertTrue(Gst.value_compare(refval, value) == Gst.VALUE_EQUAL,
"%s are not equal: %s != %s\n %s != %s" % (pname, value, refval, element, ref))
if isinstance(ref, GES.TrackElement):
self.assertElementAreEqual(ref.get_nleobject(), element.get_nleobject())
@ -275,7 +275,7 @@ class GESSimpleTimelineTest(GESTest):
if not isinstance(ref_child, GES.Effect):
child = tmpchild
break
elif ref_child.props.bin_description == child.props.bin_description:
elif ref_child.props.bin_description == tmpchild.props.bin_description:
child = tmpchild
break

View file

@ -613,9 +613,8 @@ class TestEditing(common.GESSimpleTimelineTest):
def test_trim_time_effects(self):
self.track_types = [GES.TrackType.VIDEO]
super().setUp()
clip = self.append_clip()
clip = self.append_clip(asset_id="max-duration=30")
self.assertTrue(clip.set_inpoint(12))
self.assertTrue(clip.set_max_duration(30))
self.assertEqual(clip.get_duration_limit(), 18)
children = clip.get_children(False)
@ -646,6 +645,7 @@ class TestEditing(common.GESSimpleTimelineTest):
self.assertEqual(clip.get_duration_limit(), 36)
self.assertTrue(clip.set_start(40))
self.assertTrue(clip.set_duration(10))
self.check_reload_timeline()
# cannot trim to a 16 because overlay would have a negative in-point
error = None
@ -662,6 +662,8 @@ class TestEditing(common.GESSimpleTimelineTest):
self.assertEqual(overlay.get_inpoint(), 5)
self.assertEqual(overlay.get_max_duration(), 16)
self.check_reload_timeline()
# trim backwards to 20
self.assertTrue(
clip.edit_full(-1, GES.EditMode.EDIT_TRIM, GES.Edge.EDGE_START, 20))
@ -686,6 +688,7 @@ class TestEditing(common.GESSimpleTimelineTest):
# increased by 2
self.assertEqual(overlay.get_inpoint(), 2)
self.assertEqual(overlay.get_max_duration(), 16)
self.check_reload_timeline()
def test_ripple_end(self):
clip = self.append_clip()