mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
ges: Make setting start/duration move or trim generic
We were implementing the logic for moving/trimming elements specific to SourceClip but this was not correct ass the new timeline tree allows us to handle that for all element types in a generic and nice way. This make us need to have groups trimming properly implemented in the timeline tree, leading to some fixes in the group tests. This adds tests for the various cases known to not be handled properly by the previous code. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/92
This commit is contained in:
parent
b66290d1be
commit
6b7c658b6a
9 changed files with 338 additions and 92 deletions
|
@ -91,9 +91,11 @@ neighbour_changed_cb (GESClip * clip, GParamSpec * arg G_GNUC_UNUSED,
|
|||
}
|
||||
|
||||
self->positioning = TRUE;
|
||||
ELEMENT_SET_FLAG (self->transition_clip, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
_set_start0 (GES_TIMELINE_ELEMENT (self->transition_clip),
|
||||
_START (self->next_source));
|
||||
_set_duration0 (GES_TIMELINE_ELEMENT (self->transition_clip), new_duration);
|
||||
ELEMENT_SET_FLAG (self->transition_clip, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
self->positioning = FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -218,8 +218,11 @@ _set_duration (GESTimelineElement * element, GstClockTime duration)
|
|||
for (tmp = container->children; tmp; tmp = g_list_next (tmp)) {
|
||||
GESTimelineElement *child = (GESTimelineElement *) tmp->data;
|
||||
|
||||
if (child != container->initiated_move)
|
||||
if (child != container->initiated_move) {
|
||||
ELEMENT_SET_FLAG (child, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
_set_duration0 (GES_TIMELINE_ELEMENT (child), duration);
|
||||
ELEMENT_UNSET_FLAG (child, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
}
|
||||
}
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
|
||||
|
|
|
@ -46,49 +46,6 @@ enum
|
|||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GESSourceClip, ges_source_clip, GES_TYPE_CLIP);
|
||||
|
||||
static gboolean
|
||||
_set_start (GESTimelineElement * element, GstClockTime start)
|
||||
{
|
||||
GESTimelineElement *toplevel =
|
||||
ges_timeline_element_get_toplevel_parent (element);
|
||||
|
||||
gst_object_unref (toplevel);
|
||||
if (element->timeline
|
||||
&& !ELEMENT_FLAG_IS_SET (element, GES_TIMELINE_ELEMENT_SET_SIMPLE)
|
||||
&& !ELEMENT_FLAG_IS_SET (toplevel, GES_TIMELINE_ELEMENT_SET_SIMPLE)) {
|
||||
if (!ges_timeline_move_object_simple (element->timeline, element, NULL,
|
||||
GES_EDGE_NONE, start))
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return
|
||||
GES_TIMELINE_ELEMENT_CLASS (ges_source_clip_parent_class)->set_start
|
||||
(element, start);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_set_duration (GESTimelineElement * element, GstClockTime duration)
|
||||
{
|
||||
GESTimelineElement *toplevel =
|
||||
ges_timeline_element_get_toplevel_parent (element);
|
||||
|
||||
gst_object_unref (toplevel);
|
||||
if (element->timeline
|
||||
&& !ELEMENT_FLAG_IS_SET (element, GES_TIMELINE_ELEMENT_SET_SIMPLE)
|
||||
&& !ELEMENT_FLAG_IS_SET (toplevel, GES_TIMELINE_ELEMENT_SET_SIMPLE)) {
|
||||
if (!timeline_trim_object (element->timeline, element,
|
||||
GES_TIMELINE_ELEMENT_LAYER_PRIORITY (element), NULL, GES_EDGE_END,
|
||||
element->start + duration))
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return
|
||||
GES_TIMELINE_ELEMENT_CLASS (ges_source_clip_parent_class)->set_duration
|
||||
(element, duration);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_source_clip_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
|
@ -119,14 +76,10 @@ static void
|
|||
ges_source_clip_class_init (GESSourceClipClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GESTimelineElementClass *element_class = GES_TIMELINE_ELEMENT_CLASS (klass);
|
||||
|
||||
object_class->get_property = ges_source_clip_get_property;
|
||||
object_class->set_property = ges_source_clip_set_property;
|
||||
object_class->finalize = ges_source_clip_finalize;
|
||||
|
||||
element_class->set_start = _set_start;
|
||||
element_class->set_duration = _set_duration;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -972,6 +972,7 @@ ges_timeline_element_get_timeline (GESTimelineElement * self)
|
|||
gboolean
|
||||
ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
|
||||
{
|
||||
gboolean emit_notify = TRUE;
|
||||
GESTimelineElementClass *klass;
|
||||
GESTimelineElement *toplevel_container, *parent;
|
||||
|
||||
|
@ -980,13 +981,24 @@ ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
|
|||
if (self->start == start)
|
||||
return TRUE;
|
||||
|
||||
klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
|
||||
" new start: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
|
||||
|
||||
toplevel_container = ges_timeline_element_get_toplevel_parent (self);
|
||||
|
||||
if (self->timeline
|
||||
&& !ELEMENT_FLAG_IS_SET (self, GES_TIMELINE_ELEMENT_SET_SIMPLE)
|
||||
&& !ELEMENT_FLAG_IS_SET (toplevel_container,
|
||||
GES_TIMELINE_ELEMENT_SET_SIMPLE)) {
|
||||
if (!ges_timeline_move_object_simple (self->timeline, self, NULL,
|
||||
GES_EDGE_NONE, start)) {
|
||||
gst_object_unref (toplevel_container);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
emit_notify = FALSE;
|
||||
}
|
||||
parent = self->parent;
|
||||
|
||||
/* FIXME This should not belong to GESTimelineElement */
|
||||
|
@ -1003,9 +1015,10 @@ ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
|
|||
}
|
||||
|
||||
gst_object_unref (toplevel_container);
|
||||
klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
|
||||
if (klass->set_start) {
|
||||
gint res = klass->set_start (self, start);
|
||||
if (res == TRUE) {
|
||||
if (res == TRUE && emit_notify) {
|
||||
self->start = start;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
|
||||
}
|
||||
|
@ -1126,19 +1139,40 @@ ges_timeline_element_set_duration (GESTimelineElement * self,
|
|||
GstClockTime duration)
|
||||
{
|
||||
GESTimelineElementClass *klass;
|
||||
gboolean emit_notify = TRUE;
|
||||
GESTimelineElement *toplevel;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
|
||||
|
||||
klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
|
||||
toplevel = ges_timeline_element_get_toplevel_parent (self);
|
||||
if (self->timeline &&
|
||||
!ELEMENT_FLAG_IS_SET (self, GES_TIMELINE_ELEMENT_SET_SIMPLE) &&
|
||||
!ELEMENT_FLAG_IS_SET (toplevel, GES_TIMELINE_ELEMENT_SET_SIMPLE)) {
|
||||
gboolean res;
|
||||
|
||||
res = timeline_trim_object (self->timeline, self,
|
||||
GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self), NULL,
|
||||
GES_EDGE_END, self->start + duration);
|
||||
|
||||
if (!res) {
|
||||
gst_object_unref (toplevel);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
emit_notify = res == -1;
|
||||
}
|
||||
gst_object_unref (toplevel);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
|
||||
" new duration: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
|
||||
GST_TIME_ARGS (duration));
|
||||
|
||||
klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
|
||||
if (klass->set_duration) {
|
||||
gint res = klass->set_duration (self, duration);
|
||||
if (res == TRUE) {
|
||||
if (res == TRUE && emit_notify) {
|
||||
self->duration = duration;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,10 @@ struct _TreeIterationData
|
|||
GHashTable *moved_clips;
|
||||
|
||||
GList *neighbours;
|
||||
|
||||
/* Data related to trimming groups */
|
||||
GstClockTime trim_group_start;
|
||||
GstClockTime trim_group_end;
|
||||
} tree_iteration_data_init = {
|
||||
.root = NULL,
|
||||
.res = TRUE,
|
||||
|
@ -91,6 +95,8 @@ struct _TreeIterationData
|
|||
.edge = GES_EDGE_NONE,
|
||||
.moved_clips = NULL,
|
||||
.neighbours = NULL,
|
||||
.trim_group_start = GST_CLOCK_TIME_NONE,
|
||||
.trim_group_end = GST_CLOCK_TIME_NONE,
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
|
@ -783,6 +789,47 @@ error:
|
|||
goto done;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
trim_group_get_vals (TreeIterationData * data, GESTimelineElement * e,
|
||||
GstClockTimeDiff * n_start, GstClockTimeDiff * n_inpoint,
|
||||
GstClockTimeDiff * n_duration)
|
||||
{
|
||||
GstClockTimeDiff offset;
|
||||
GstClockTimeDiff group_nstart =
|
||||
GST_CLOCK_DIFF (data->start_diff, data->trim_group_start);
|
||||
GstClockTimeDiff group_nend =
|
||||
GST_CLOCK_DIFF (data->duration_diff, data->trim_group_end);
|
||||
|
||||
if (data->edge == GES_EDGE_START &&
|
||||
((group_nstart >= e->start) || (e->start == data->trim_group_start))) {
|
||||
|
||||
offset = GST_CLOCK_DIFF (group_nstart, e->start);
|
||||
*n_start = group_nstart;
|
||||
*n_inpoint = GST_CLOCK_DIFF (offset, e->inpoint);
|
||||
*n_duration =
|
||||
GST_CLOCK_DIFF (*n_start, (GstClockTimeDiff) e->start + e->duration);
|
||||
|
||||
GST_DEBUG_OBJECT (data->element, "Trimming %" GES_FORMAT " start",
|
||||
GES_ARGS (e));
|
||||
return TRUE;
|
||||
} else if (data->edge == GES_EDGE_END &&
|
||||
((group_nend <= _END (e)) || (_END (e) == data->trim_group_end))) {
|
||||
|
||||
offset = GST_CLOCK_DIFF (group_nend, _END (e));
|
||||
*n_start = e->start;
|
||||
*n_inpoint = e->inpoint;
|
||||
*n_duration = GST_CLOCK_DIFF (offset, e->duration);
|
||||
|
||||
GST_DEBUG_OBJECT (data->element, "Trimming %" GES_FORMAT " end",
|
||||
GES_ARGS (e));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Ignoring child */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_trim_child (GNode * node, TreeIterationData * data)
|
||||
{
|
||||
|
@ -793,6 +840,12 @@ check_trim_child (GNode * node, TreeIterationData * data)
|
|||
GST_CLOCK_DIFF (data->duration_diff, e->duration) :
|
||||
GST_CLOCK_DIFF (n_start, (GstClockTimeDiff) e->start + e->duration);
|
||||
|
||||
if (GST_CLOCK_TIME_IS_VALID (data->trim_group_start)
|
||||
&& !trim_group_get_vals (data, e, &n_start, &n_inpoint, &n_duration)) {
|
||||
GST_DEBUG_OBJECT (data->element, "Not trimming");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!timeline_tree_can_move_element_internal (data->root, e,
|
||||
(gint64) ges_timeline_element_get_layer_priority (e) -
|
||||
data->priority_diff, n_start, n_inpoint, n_duration, NULL,
|
||||
|
@ -823,21 +876,33 @@ timeline_tree_can_trim_element_internal (GNode * root, TreeIterationData * data)
|
|||
|
||||
static void
|
||||
trim_simple (GESTimelineElement * element, GstClockTimeDiff offset,
|
||||
GESEdge edge)
|
||||
GESEdge edge, TreeIterationData * data)
|
||||
{
|
||||
GESTimelineElement *toplevel =
|
||||
ges_timeline_element_get_toplevel_parent (element);
|
||||
|
||||
GstClockTimeDiff n_start = GST_CLOCK_DIFF (offset, element->start);
|
||||
GstClockTimeDiff n_inpoint = GST_CLOCK_DIFF (offset, element->inpoint);
|
||||
GstClockTimeDiff n_duration = edge == GES_EDGE_END
|
||||
? GST_CLOCK_DIFF (offset, element->duration)
|
||||
: element->duration + offset;
|
||||
|
||||
if (data && GST_CLOCK_TIME_IS_VALID (data->trim_group_start))
|
||||
g_assert (trim_group_get_vals (data, element, &n_start, &n_inpoint,
|
||||
&n_duration));
|
||||
|
||||
ELEMENT_SET_FLAG (element, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
if (edge == GES_EDGE_END) {
|
||||
ges_timeline_element_set_duration (element, GST_CLOCK_DIFF (offset,
|
||||
element->duration));
|
||||
} else {
|
||||
ges_timeline_element_set_start (element, GST_CLOCK_DIFF (offset,
|
||||
element->start));
|
||||
ges_timeline_element_set_inpoint (element, GST_CLOCK_DIFF (offset,
|
||||
element->inpoint));
|
||||
ges_timeline_element_set_duration (element, element->duration + offset);
|
||||
ELEMENT_SET_FLAG (toplevel, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
if (edge != GES_EDGE_END) {
|
||||
ges_timeline_element_set_start (element, n_start);
|
||||
ges_timeline_element_set_inpoint (element, n_inpoint);
|
||||
}
|
||||
ges_timeline_element_set_duration (element, n_duration);
|
||||
|
||||
GST_LOG ("Trimmed %" GES_FORMAT, GES_ARGS (element));
|
||||
ELEMENT_UNSET_FLAG (element, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
ELEMENT_UNSET_FLAG (toplevel, GES_TIMELINE_ELEMENT_SET_SIMPLE);
|
||||
gst_object_unref (toplevel);
|
||||
}
|
||||
|
||||
#define SET_TRIMMING_DATA(data, _edge, offset) G_STMT_START { \
|
||||
|
@ -845,6 +910,10 @@ trim_simple (GESTimelineElement * element, GstClockTimeDiff offset,
|
|||
data.start_diff = (_edge) == GES_EDGE_END ? 0 : (offset); \
|
||||
data.inpoint_diff = (_edge) == GES_EDGE_END ? 0 : (offset); \
|
||||
data.duration_diff = (_edge) == GES_EDGE_END ? (offset) : -(offset); \
|
||||
if (GES_IS_GROUP (data.element)) {\
|
||||
data.trim_group_start = data.element->start;\
|
||||
data.trim_group_end = _END (data.element); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
|
||||
|
@ -869,6 +938,10 @@ timeline_tree_trim (GNode * root, GESTimelineElement * element,
|
|||
};
|
||||
TreeIterationData data = tree_iteration_data_init;
|
||||
|
||||
/* Make sure to check all children of clips */
|
||||
if (GES_IS_TRACK_ELEMENT (element) && element->parent)
|
||||
element = element->parent;
|
||||
|
||||
data.root = root;
|
||||
data.element = element;
|
||||
data.priority_diff =
|
||||
|
@ -876,13 +949,12 @@ timeline_tree_trim (GNode * root, GESTimelineElement * element,
|
|||
new_layer_priority;
|
||||
data.snapping = snapping_distance ? &snapping : NULL;
|
||||
data.moved_clips = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
SET_TRIMMING_DATA (data, edge, offset);
|
||||
GST_INFO ("%" GES_FORMAT " trimming %s with offset %" G_GINT64_FORMAT "",
|
||||
GES_ARGS (element), edge == GES_EDGE_END ? "end" : "start", offset);
|
||||
g_node_traverse (find_node (root, element), G_IN_ORDER,
|
||||
G_TRAVERSE_LEAVES, -1, (GNodeTraverseFunc) add_element_to_list,
|
||||
&data.movings);
|
||||
g_node_traverse (find_node (root, get_toplevel_container (element)),
|
||||
G_IN_ORDER, G_TRAVERSE_LEAVES, -1,
|
||||
(GNodeTraverseFunc) add_element_to_list, &data.movings);
|
||||
|
||||
if (!timeline_tree_can_trim_element_internal (root, &data)) {
|
||||
GST_INFO ("Can not trim object.");
|
||||
|
@ -909,7 +981,7 @@ timeline_tree_trim (GNode * root, GESTimelineElement * element,
|
|||
|
||||
g_hash_table_iter_init (&iter, data.moved_clips);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) & elem, NULL))
|
||||
trim_simple (elem, offset, edge);
|
||||
trim_simple (elem, offset, edge, &data);
|
||||
|
||||
timeline_tree_create_transitions (root, ges_timeline_find_auto_transition);
|
||||
timeline_update_transition (root->data);
|
||||
|
@ -1155,9 +1227,9 @@ timeline_tree_roll (GNode * root, GESTimelineElement * element,
|
|||
}
|
||||
}
|
||||
|
||||
trim_simple (element, offset, edge);
|
||||
trim_simple (element, offset, edge, NULL);
|
||||
for (tmp = data.neighbours; tmp; tmp = tmp->next)
|
||||
trim_simple (tmp->data, offset, data.edge);
|
||||
trim_simple (tmp->data, offset, data.edge, NULL);
|
||||
|
||||
done:
|
||||
timeline_update_duration (root->data);
|
||||
|
|
|
@ -1096,8 +1096,10 @@ _trim_transition (GESTimeline * timeline, GESTimelineElement * element,
|
|||
GESLayer *layer = ges_timeline_get_layer (timeline,
|
||||
GES_TIMELINE_ELEMENT_LAYER_PRIORITY (element));
|
||||
|
||||
if (!ges_layer_get_auto_transition (layer))
|
||||
goto fail;
|
||||
if (!ges_layer_get_auto_transition (layer)) {
|
||||
gst_object_unref (layer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gst_object_unref (layer);
|
||||
for (tmp = timeline->priv->auto_transitions; tmp; tmp = tmp->next) {
|
||||
|
@ -1123,10 +1125,6 @@ _trim_transition (GESTimeline * timeline, GESTimelineElement * element,
|
|||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
fail:
|
||||
gst_object_unref (layer);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -195,40 +195,67 @@ GST_START_TEST (test_move_group)
|
|||
* |----------------------------------|
|
||||
* | 7--------- 2----------|
|
||||
* layer1: | | clip1 | | clip2 |
|
||||
* | 22--------30 62----------|
|
||||
* | 20--------30 60----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 12);
|
||||
CHECK_OBJECT_PROPS (clip, 12, 2, 3);
|
||||
CHECK_OBJECT_PROPS (clip1, 22, 7, 8);
|
||||
CHECK_OBJECT_PROPS (clip2, 62, 2, 48);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 12, 0, 98);
|
||||
ASSERT_OBJECT_REFCOUNT (group, "2 ref for the timeline", 2);
|
||||
|
||||
/* Setting the duration would lead to overlaps */
|
||||
ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (group), 10);
|
||||
fail_if (ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (group),
|
||||
10));
|
||||
CHECK_OBJECT_PROPS (clip, 12, 2, 3);
|
||||
CHECK_OBJECT_PROPS (clip1, 22, 7, 8);
|
||||
CHECK_OBJECT_PROPS (clip2, 62, 2, 48);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 12, 0, 98);
|
||||
ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (group), 100);
|
||||
CHECK_OBJECT_PROPS (clip, 12, 2, 3);
|
||||
CHECK_OBJECT_PROPS (clip1, 22, 7, 8);
|
||||
CHECK_OBJECT_PROPS (clip2, 62, 2, 50);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 52);
|
||||
CHECK_OBJECT_PROPS (group, 12, 0, 100);
|
||||
|
||||
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (group), 20);
|
||||
CHECK_OBJECT_PROPS (clip, 20, 2, 3);
|
||||
CHECK_OBJECT_PROPS (clip1, 30, 7, 8);
|
||||
CHECK_OBJECT_PROPS (clip2, 70, 2, 50);
|
||||
CHECK_OBJECT_PROPS (clip1, 28, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 68, 0, 52);
|
||||
CHECK_OBJECT_PROPS (group, 20, 0, 100);
|
||||
|
||||
/* Trim fails because clip inpoint would become negative */
|
||||
fail_if (ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 10));
|
||||
CHECK_OBJECT_PROPS (clip, 20, 2, 3);
|
||||
CHECK_OBJECT_PROPS (clip1, 30, 7, 8);
|
||||
CHECK_OBJECT_PROPS (clip2, 70, 2, 50);
|
||||
CHECK_OBJECT_PROPS (clip1, 28, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 68, 0, 52);
|
||||
CHECK_OBJECT_PROPS (group, 20, 0, 100);
|
||||
|
||||
fail_unless (ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 18));
|
||||
CHECK_OBJECT_PROPS (clip, 18, 0, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 28, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 68, 0, 52);
|
||||
CHECK_OBJECT_PROPS (group, 18, 0, 102);
|
||||
|
||||
fail_unless (ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (clip),
|
||||
17));
|
||||
CHECK_OBJECT_PROPS (clip, 18, 0, 17);
|
||||
CHECK_OBJECT_PROPS (clip1, 28, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 68, 0, 52);
|
||||
CHECK_OBJECT_PROPS (group, 18, 0, 102);
|
||||
|
||||
fail_unless (ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 30));
|
||||
CHECK_OBJECT_PROPS (clip, 30, 12, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 30, 7, 8);
|
||||
CHECK_OBJECT_PROPS (clip2, 68, 0, 52);
|
||||
CHECK_OBJECT_PROPS (group, 30, 0, 90);
|
||||
|
||||
fail_unless (ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 25));
|
||||
CHECK_OBJECT_PROPS (clip, 25, 7, 10);
|
||||
CHECK_OBJECT_PROPS (clip1, 25, 2, 13);
|
||||
CHECK_OBJECT_PROPS (clip2, 68, 0, 52);
|
||||
CHECK_OBJECT_PROPS (group, 25, 0, 95);
|
||||
|
||||
ASSERT_OBJECT_REFCOUNT (group, "2 ref for the timeline", 2);
|
||||
check_destroyed (G_OBJECT (timeline), G_OBJECT (group), NULL);
|
||||
gst_object_unref (asset);
|
||||
|
|
|
@ -188,8 +188,8 @@ class GESSimpleTimelineTest(GESTest):
|
|||
len(self.track_types))
|
||||
self.layer = self.timeline.append_layer()
|
||||
|
||||
def add_clip(self, start, in_point, duration):
|
||||
clip = GES.TestClip()
|
||||
def add_clip(self, start, in_point, duration, asset_type=GES.TestClip):
|
||||
clip = GES.Asset.request(asset_type, None).extract()
|
||||
clip.props.start = start
|
||||
clip.props.in_point = in_point
|
||||
clip.props.duration = duration
|
||||
|
@ -197,11 +197,11 @@ class GESSimpleTimelineTest(GESTest):
|
|||
|
||||
return clip
|
||||
|
||||
def append_clip(self, layer=0):
|
||||
def append_clip(self, layer=0, asset_type=GES.TestClip):
|
||||
while len(self.timeline.get_layers()) < layer + 1:
|
||||
self.timeline.append_layer()
|
||||
layer = self.timeline.get_layers()[layer]
|
||||
clip = GES.TestClip()
|
||||
clip = GES.Asset.request(asset_type, None).extract()
|
||||
clip.props.start = layer.get_duration()
|
||||
clip.props.duration = 10
|
||||
self.assertTrue(layer.add_clip(clip))
|
||||
|
@ -215,6 +215,9 @@ class GESSimpleTimelineTest(GESTest):
|
|||
for clip in layer.get_clips():
|
||||
layer_timings.append(
|
||||
(type(clip), clip.props.start, clip.props.duration))
|
||||
for child in clip.get_children(True):
|
||||
self.assertEqual(child.props.start, clip.props.start)
|
||||
self.assertEqual(child.props.duration, clip.props.duration)
|
||||
|
||||
res.append(layer_timings)
|
||||
if topology != res:
|
||||
|
|
|
@ -505,6 +505,160 @@ class TestEditing(common.GESSimpleTimelineTest):
|
|||
]
|
||||
])
|
||||
|
||||
def test_illegal_effect_move(self):
|
||||
c0 = self.append_clip()
|
||||
self.append_clip()
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TestClip, 10, 10),
|
||||
]
|
||||
])
|
||||
|
||||
effect = GES.Effect.new("agingtv")
|
||||
c0.add(effect)
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TestClip, 10, 10),
|
||||
]
|
||||
])
|
||||
|
||||
self.assertFalse(effect.set_start(10))
|
||||
self.assertEqual(effect.props.start, 0)
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TestClip, 10, 10),
|
||||
]
|
||||
])
|
||||
|
||||
|
||||
self.assertFalse(effect.set_duration(20))
|
||||
self.assertEqual(effect.props.duration, 10)
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TestClip, 10, 10),
|
||||
]
|
||||
])
|
||||
|
||||
def test_moving_overlay_clip_in_group(self):
|
||||
c0 = self.append_clip()
|
||||
overlay = self.append_clip(asset_type=GES.TextOverlayClip)
|
||||
group = GES.Group.new()
|
||||
group.add(c0)
|
||||
group.add(overlay)
|
||||
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TextOverlayClip, 10, 10),
|
||||
]
|
||||
], groups=[(c0, overlay)])
|
||||
|
||||
self.assertTrue(overlay.set_start(20))
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 10, 10),
|
||||
(GES.TextOverlayClip, 20, 10),
|
||||
]
|
||||
], groups=[(c0, overlay)])
|
||||
|
||||
def test_moving_group_in_group(self):
|
||||
c0 = self.append_clip()
|
||||
overlay = self.append_clip(asset_type=GES.TextOverlayClip)
|
||||
group0 = GES.Group.new()
|
||||
group0.add(c0)
|
||||
group0.add(overlay)
|
||||
|
||||
c1 = self.append_clip()
|
||||
group1 = GES.Group.new()
|
||||
group1.add(group0)
|
||||
group1.add(c1)
|
||||
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TextOverlayClip, 10, 10),
|
||||
(GES.TestClip, 20, 10),
|
||||
]
|
||||
], groups=[(c1, group0), (c0, overlay)])
|
||||
|
||||
self.assertTrue(group0.set_start(10))
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 10, 10),
|
||||
(GES.TextOverlayClip, 20, 10),
|
||||
(GES.TestClip, 30, 10),
|
||||
]
|
||||
], groups=[(c1, group0), (c0, overlay)])
|
||||
self.check_element_values(group0, 10, 0, 20)
|
||||
self.check_element_values(group1, 10, 0, 30)
|
||||
|
||||
def test_illegal_group_child_move(self):
|
||||
clip0 = self.append_clip()
|
||||
_clip1 = self.add_clip(20, 0, 10)
|
||||
overlay = self.add_clip(20, 0, 10, asset_type=GES.TextOverlayClip)
|
||||
|
||||
group = GES.Group.new()
|
||||
group.add(clip0)
|
||||
group.add(overlay)
|
||||
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TextOverlayClip, 20, 10),
|
||||
(GES.TestClip, 20, 10),
|
||||
]
|
||||
], groups=[(clip0, overlay),])
|
||||
|
||||
# Can't move as clip0 and clip1 would fully overlap
|
||||
self.assertFalse(overlay.set_start(40))
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
(GES.TextOverlayClip, 20, 10),
|
||||
(GES.TestClip, 20, 10),
|
||||
]
|
||||
], groups=[(clip0, overlay)])
|
||||
|
||||
def test_child_duration_change(self):
|
||||
c0 = self.append_clip()
|
||||
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
]
|
||||
])
|
||||
self.assertTrue(c0.set_duration(40))
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 40),
|
||||
]
|
||||
])
|
||||
|
||||
c0.children[0].set_duration(10)
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 0, 10),
|
||||
]
|
||||
])
|
||||
|
||||
self.assertTrue(c0.set_start(40))
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 40, 10),
|
||||
]
|
||||
])
|
||||
|
||||
c0.children[0].set_start(10)
|
||||
self.assertTimelineTopology([
|
||||
[
|
||||
(GES.TestClip, 10, 10),
|
||||
]
|
||||
])
|
||||
|
||||
|
||||
class TestInvalidOverlaps(common.GESSimpleTimelineTest):
|
||||
|
||||
|
|
Loading…
Reference in a new issue