gboolean prevent_resort;
gboolean updating_max_duration;
- gboolean prevent_max_duration_update;
+ gboolean setting_max_duration;
gboolean setting_inpoint;
+ gboolean setting_priority;
+ gboolean setting_active;
gboolean allow_any_track;
GstClockTime duration_limit;
gboolean prevent_duration_limit_update;
+
+ gboolean allow_any_remove;
};
enum
ges_extractable_interface_init));
/****************************************************
+ * *
* Listen to our children *
+ * and restrict them *
+ * *
****************************************************/
#define _IS_CORE_CHILD(child) GES_TRACK_ELEMENT_IS_CORE(child)
(GST_CLOCK_TIME_IS_VALID (first) && (!GST_CLOCK_TIME_IS_VALID (second) \
|| first < second))
+/****************************************************
+ * duration-limit *
+ ****************************************************/
typedef struct _DurationLimitData
{
return list;
}
+/* transfer-full of data */
+static GList *
+_duration_limit_data_list_with_data (GESClip * clip, DurationLimitData * data)
+{
+ GList *tmp, *list = g_list_append (NULL, data);
+
+ for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
+ GESTrackElement *child = tmp->data;
+ if (data->child == child)
+ continue;
+ list = g_list_prepend (list, _duration_limit_data_new (child));
+ }
+
+ return list;
+}
+
static gint
_cmp_by_track_then_priority (gconstpointer a_p, gconstpointer b_p)
{
((data->active && GST_CLOCK_TIME_IS_VALID (data->max_duration)) ? \
data->max_duration - data->inpoint : GST_CLOCK_TIME_NONE)
+/* transfer-full of child_data */
static GstClockTime
_calculate_duration_limit (GESClip * self, GList * child_data)
{
}
}
+/* transfer full of child_data */
+static gboolean
+_can_update_duration_limit (GESClip * self, GList * child_data)
+{
+ GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (self);
+ GstClockTime duration = _calculate_duration_limit (self, child_data);
+ GESTimelineElement *element = GES_TIMELINE_ELEMENT (self);
+
+ if (_CLOCK_TIME_IS_LESS (duration, element->duration)) {
+ /* NOTE: timeline would normally not be NULL at this point */
+ if (timeline
+ && !timeline_tree_can_move_element (timeline_get_tree (timeline),
+ element, ges_timeline_element_get_layer_priority (element),
+ element->start, duration)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/****************************************************
+ * priority *
+ ****************************************************/
+
/* @min_priority: The absolute minimum priority a child of @container should have
* @max_priority: The absolute maximum priority a child of @container should have
*/
_PRIORITY (container));
}
+gboolean
+ges_clip_can_set_priority_of_child (GESClip * clip, GESTrackElement * child,
+ guint32 priority)
+{
+ GList *child_data;
+ DurationLimitData *data;
+
+ if (clip->priv->setting_priority)
+ return TRUE;
+
+ data = _duration_limit_data_new (child);
+ data->priority = priority;
+
+ child_data = _duration_limit_data_list_with_data (clip, data);
+
+ if (!_can_update_duration_limit (clip, child_data)) {
+ GST_INFO_OBJECT (clip, "Cannot move the child %" GES_FORMAT " from "
+ "priority %" G_GUINT32_FORMAT " to %" G_GUINT32_FORMAT " because "
+ "the duration-limit cannot be adjusted", GES_ARGS (child),
+ _PRIORITY (child), priority);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void
_child_priority_changed (GESContainer * container, GESTimelineElement * child)
{
}
}
+/****************************************************
+ * in-point *
+ ****************************************************/
+
+static gboolean
+_can_set_inpoint_of_core_children (GESClip * clip, GstClockTime inpoint)
+{
+ GList *tmp;
+ GList *child_data = NULL;
+
+ if (GES_TIMELINE_ELEMENT_BEING_EDITED (clip))
+ return TRUE;
+
+ /* setting the in-point of a core child will shift the in-point of all
+ * core children with an internal source */
+ for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
+ GESTimelineElement *child = tmp->data;
+ DurationLimitData *data =
+ _duration_limit_data_new (GES_TRACK_ELEMENT (child));
+
+ if (_IS_CORE_INTERNAL_SOURCE_CHILD (child)) {
+ if (GST_CLOCK_TIME_IS_VALID (child->maxduration)
+ && child->maxduration < inpoint) {
+ GST_INFO_OBJECT (clip, "Cannot set the in-point from %"
+ G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT " because it would "
+ "cause the in-point of its core child %" GES_FORMAT
+ " to exceed its max-duration", _INPOINT (clip), inpoint,
+ GES_ARGS (child));
+
+ _duration_limit_data_free (data);
+ g_list_free_full (child_data, _duration_limit_data_free);
+ return FALSE;
+ }
+
+ data->inpoint = inpoint;
+ }
+
+ child_data = g_list_prepend (child_data, data);
+ }
+
+ if (!_can_update_duration_limit (clip, child_data)) {
+ GST_INFO_OBJECT (clip, "Cannot set the in-point from %" G_GUINT64_FORMAT
+ " to %" G_GUINT64_FORMAT " because the duration-limit cannot be "
+ "adjusted", _INPOINT (clip), inpoint);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Whether @clip can have its in-point set to @inpoint because none of
+ * its children have a max-duration below it */
+gboolean
+ges_clip_can_set_inpoint_of_child (GESClip * clip, GESTrackElement * child,
+ GstClockTime inpoint)
+{
+ /* don't bother checking if we are setting the value */
+ if (clip->priv->setting_inpoint)
+ return TRUE;
+
+ if (GES_TIMELINE_ELEMENT_BEING_EDITED (child))
+ return TRUE;
+
+ if (!_IS_CORE_CHILD (child)) {
+ /* no other sibling will move */
+ GList *child_data;
+ DurationLimitData *data = _duration_limit_data_new (child);
+ data->inpoint = inpoint;
+
+ child_data = _duration_limit_data_list_with_data (clip, data);
+
+ if (!_can_update_duration_limit (clip, child_data)) {
+ GST_INFO_OBJECT (clip, "Cannot set the in-point of non-core child %"
+ GES_FORMAT " from %" G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT
+ " because the duration-limit cannot be adjusted", GES_ARGS (child),
+ _INPOINT (child), inpoint);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ /* setting the in-point of a core child will shift the in-point of all
+ * core children with an internal source */
+ return _can_set_inpoint_of_core_children (clip, inpoint);
+}
+
/* returns TRUE if duration-limit needs to be updated */
static gboolean
_child_inpoint_changed (GESClip * self, GESTimelineElement * child)
return FALSE;
}
-/* called when a child is added, removed or their max-duration changes */
+/****************************************************
+ * max-duration *
+ ****************************************************/
+
static void
_update_max_duration (GESContainer * container)
{
GstClockTime min = GST_CLOCK_TIME_NONE;
GESClipPrivate *priv = GES_CLIP (container)->priv;
- if (priv->prevent_max_duration_update)
+ if (priv->setting_max_duration)
return;
for (tmp = container->children; tmp; tmp = tmp->next) {
priv->updating_max_duration = FALSE;
}
+gboolean
+ges_clip_can_set_max_duration_of_child (GESClip * clip, GESTrackElement * child,
+ GstClockTime max_duration)
+{
+ GList *child_data;
+ DurationLimitData *data;
+
+ if (clip->priv->setting_max_duration)
+ return TRUE;
+
+ data = _duration_limit_data_new (child);
+ data->max_duration = max_duration;
+
+ child_data = _duration_limit_data_list_with_data (clip, data);
+
+ if (!_can_update_duration_limit (clip, child_data)) {
+ GST_INFO_OBJECT (clip, "Cannot set the max-duration of child %"
+ GES_FORMAT " from %" G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT
+ " because the duration-limit cannot be adjusted", GES_ARGS (child),
+ _MAXDURATION (child), max_duration);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void
_child_max_duration_changed (GESContainer * container,
GESTimelineElement * child)
_update_max_duration (container);
}
+/****************************************************
+ * has-internal-source *
+ ****************************************************/
+
static void
_child_has_internal_source_changed (GESClip * self, GESTimelineElement * child)
{
/* ignore non-core */
/* if the track element is now registered to have no internal content,
- * we don't have to do anything */
+ * we don't have to do anything
+ * Note that the change in max-duration and in-point will already trigger
+ * a change in the duration-limit, which can only increase since the
+ * max-duration is now GST_CLOCK_TIME_NONE */
if (!_IS_CORE_INTERNAL_SOURCE_CHILD (child))
return;
- /* otherwise, we need to make its in-point match ours */
+ /* otherwise, we need to make its in-point match ours
+ * Note that the duration-limit will be GST_CLOCK_TIME_NONE, so this
+ * should not change the duration-limit */
_set_inpoint0 (child, _INPOINT (self));
}
-#define _IS_PROP(prop) (g_strcmp0 (name, prop) == 0)
+/****************************************************
+ * active *
+ ****************************************************/
+
+gboolean
+ges_clip_can_set_active_of_child (GESClip * clip, GESTrackElement * child,
+ gboolean active)
+{
+ GESTrack *track = ges_track_element_get_track (child);
+ gboolean is_core = _IS_CORE_CHILD (child);
+ GList *child_data = NULL;
+ DurationLimitData *data;
+
+ if (clip->priv->setting_active)
+ return TRUE;
+
+ /* We want to ensure that each active non-core element has a
+ * corresponding active core element in the same track */
+ if (!track || is_core == active) {
+ /* only the one child will change */
+ data = _duration_limit_data_new (child);
+ data->active = active;
+ child_data = _duration_limit_data_list_with_data (clip, data);
+ } else {
+ GList *tmp;
+ /* If we are core, make all the non-core elements in-active
+ * If we are non-core, make the core element active */
+ for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
+ GESTrackElement *sibling = tmp->data;
+ data = _duration_limit_data_new (sibling);
+
+ if (sibling == child)
+ data->active = active;
+
+ if (ges_track_element_get_track (sibling) == track
+ && _IS_CORE_CHILD (sibling) != is_core
+ && ges_track_element_is_active (sibling) != active)
+ data->active = active;
+
+ child_data = g_list_prepend (child_data, data);
+ }
+ }
+
+ if (!_can_update_duration_limit (clip, child_data)) {
+ GST_INFO_OBJECT (clip, "Cannot set the active of child %" GES_FORMAT
+ " from %i to %i because the duration-limit cannot be adjusted",
+ GES_ARGS (child), ges_track_element_is_active (child), active);
+ return FALSE;
+ }
+
+ return TRUE;
+}
static void
_child_active_changed (GESClip * self, GESTrackElement * child)
if (self->priv->setting_active || !track || is_core == active)
return;
+ self->priv->setting_active = TRUE;
self->priv->prevent_duration_limit_update = TRUE;
/* If we are core, make all the non-core elements in-active
}
}
+ self->priv->setting_active = FALSE;
self->priv->prevent_duration_limit_update = prev_prevent;
}
/****************************************************
- * Restrict our children *
+ * track *
****************************************************/
static GESTrackElement *
ges_clip_can_set_track_of_child (GESClip * clip, GESTrackElement * child,
GESTrack * track)
{
+ GList *child_data;
+ DurationLimitData *data;
GESTrack *current_track = ges_track_element_get_track (child);
GESTrackElement *core = NULL;
}
}
}
+
+ data = _duration_limit_data_new (child);
+ gst_clear_object (&data->track);
+ data->track = track ? gst_object_ref (track) : NULL;
+ if (core && !ges_track_element_is_active (core)) {
+ /* if core is set, then we are adding a non-core to a track containing
+ * a core track element. If this happens, but the core is in-active
+ * then we will make the non-core element also inactive upon setting
+ * its track */
+ data->active = FALSE;
+ }
+
+ child_data = _duration_limit_data_list_with_data (clip, data);
+
+ if (!_can_update_duration_limit (clip, child_data)) {
+ GST_INFO_OBJECT (clip, "Cannot move the child %" GES_FORMAT " from "
+ "track %" GST_PTR_FORMAT " to track %" GST_PTR_FORMAT " because "
+ "the duration-limit cannot be adjusted", GES_ARGS (child),
+ current_track, track);
+ return FALSE;
+ }
+
return TRUE;
}
" since the core child in the same track %" GST_PTR_FORMAT " is "
"not active", GES_ARGS (child), track);
+ self->priv->setting_active = TRUE;
self->priv->prevent_duration_limit_update = TRUE;
if (!ges_track_element_set_active (child, FALSE))
GST_ERROR_OBJECT (self, "Failed to de-activate child %" GES_FORMAT,
GES_ARGS (child));
+ self->priv->setting_active = FALSE;
self->priv->prevent_duration_limit_update = prev_prevent;
}
}
return TRUE;
}
-/* Whether @clip can have its in-point set to @inpoint because none of
- * its children have a max-duration below it */
-gboolean
-ges_clip_can_set_inpoint_of_child (GESClip * clip, GESTimelineElement * child,
- GstClockTime inpoint)
-{
- GList *tmp;
-
- /* don't bother checking if we are setting the value */
- if (clip->priv->setting_inpoint)
- return TRUE;
-
- /* non-core children do not effect our in-point */
- if (!_IS_CORE_CHILD (child))
- return TRUE;
-
- for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
- GESTimelineElement *child = tmp->data;
-
- if (_IS_CORE_INTERNAL_SOURCE_CHILD (child)
- && GST_CLOCK_TIME_IS_VALID (child->maxduration)
- && child->maxduration < inpoint)
- return FALSE;
- }
- return TRUE;
-}
-
/* returns TRUE if we did not break early */
static gboolean
_set_childrens_inpoint (GESTimelineElement * element, GstClockTime inpoint,
static gboolean
_set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
{
+ if (!_can_set_inpoint_of_core_children (GES_CLIP (element), inpoint)) {
+ GST_WARNING_OBJECT (element, "Cannot set the in-point to %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (inpoint));
+ return FALSE;
+ }
+
if (!_set_childrens_inpoint (element, inpoint, TRUE)) {
_set_childrens_inpoint (element, element->inpoint, FALSE);
return FALSE;
_set_max_duration (GESTimelineElement * element, GstClockTime maxduration)
{
GList *tmp;
+ GList *child_data = NULL;
GESClip *self = GES_CLIP (element);
GESClipPrivate *priv = self->priv;
GstClockTime new_min = GST_CLOCK_TIME_NONE;
/* else, we set every core child to have the same max duration */
+ /* check that the duration-limit can be changed */
+ for (tmp = GES_CONTAINER_CHILDREN (self); tmp; tmp = tmp->next) {
+ GESTrackElement *child = tmp->data;
+ DurationLimitData *data = _duration_limit_data_new (child);
+
+ if (_IS_CORE_INTERNAL_SOURCE_CHILD (child))
+ data->max_duration = maxduration;
+
+ child_data = g_list_prepend (child_data, data);
+ }
+
+ if (!_can_update_duration_limit (self, child_data)) {
+ GST_WARNING_OBJECT (self, "Cannot set the max-duration from %"
+ G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT " because the "
+ "duration-limit cannot be adjusted", element->maxduration, maxduration);
+ return FALSE;
+ }
+
priv->prevent_duration_limit_update = TRUE;
- priv->prevent_max_duration_update = TRUE;
+ priv->setting_max_duration = TRUE;
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
GESTimelineElement *child = tmp->data;
}
}
}
- priv->prevent_max_duration_update = FALSE;
+ priv->setting_max_duration = FALSE;
priv->prevent_duration_limit_update = prev_prevent;
if (!has_core) {
/* offsets will remain constant for the children */
priv->prevent_resort = TRUE;
priv->prevent_duration_limit_update = TRUE;
+ priv->setting_priority = TRUE;
for (tmp = container->children; tmp; tmp = g_list_next (tmp)) {
GESTimelineElement *child = tmp->data;
guint32 track_element_prio = min_prio + (child->priority - min_child_prio);
* offsets. As such, the height and duration-limit remains the same as
* well. */
priv->prevent_resort = FALSE;
+ priv->setting_priority = FALSE;
priv->prevent_duration_limit_update = prev_prevent;
return TRUE;
/* NOTE: Core track elements that are base effects are added like any
* other core elements. In particular, they are *not* added to the
* list of added effects, so we do not increase nb_effects. */
- GESTrackElement *core = (track && !priv->allow_any_track) ?
- _find_core_in_track (self, track) : NULL;
-
- if (core) {
- GST_WARNING_OBJECT (self, "Cannot add the core child %" GES_FORMAT
- " because it is in the same track %" GST_PTR_FORMAT " as an "
- "existing core child %" GES_FORMAT, GES_ARGS (element), track,
- GES_ARGS (core));
- return FALSE;
- }
/* Set the core element to have the same in-point, which we don't
* apply to effects */
- if (ges_track_element_has_internal_source (track_el)) {
- /* adding can fail if the max-duration of the element is smaller
- * than the current in-point of the clip */
- if (!_set_inpoint0 (element, _INPOINT (self))) {
- GST_ERROR_OBJECT (element, "Could not set the in-point of the "
- "element %" GES_FORMAT " to %" GST_TIME_FORMAT ". Not adding "
- "as a child", GES_ARGS (element), GST_TIME_ARGS (_INPOINT (self)));
- return FALSE;
- }
- }
+ GstClockTime new_inpoint;
+ if (ges_track_element_has_internal_source (track_el))
+ new_inpoint = _INPOINT (self);
+ else
+ new_inpoint = 0;
/* new priority is that of the lowest priority core child. Usually
* each core child has the same priority.
* Also must be lower than all effects */
+
new_prio = min_prio;
for (tmp = container->children; tmp; tmp = tmp->next) {
if (_IS_CORE_CHILD (tmp->data))
else if (_IS_TOP_EFFECT (tmp->data))
new_prio = MAX (new_prio, _PRIORITY (tmp->data) + 1);
}
+
+ if (track && !priv->allow_any_track) {
+ GList *child_data;
+ DurationLimitData *data;
+ GESTrackElement *core = _find_core_in_track (self, track);
+
+ if (core) {
+ GST_WARNING_OBJECT (self, "Cannot add the core child %" GES_FORMAT
+ " because it is in the same track %" GST_PTR_FORMAT " as an "
+ "existing core child %" GES_FORMAT, GES_ARGS (element), track,
+ GES_ARGS (core));
+ return FALSE;
+ }
+
+ data = _duration_limit_data_new (track_el);
+ data->inpoint = new_inpoint;
+ data->priority = new_prio;
+
+ child_data = _duration_limit_data_list_with_data (self, data);
+
+ if (!_can_update_duration_limit (self, child_data)) {
+ GST_WARNING_OBJECT (self, "Cannot add core %" GES_FORMAT " as a "
+ "child because the duration-limit cannot be adjusted",
+ GES_ARGS (element));
+ return FALSE;
+ }
+ }
+
+ /* adding can fail if the max-duration of the element is smaller
+ * than the current in-point of the clip */
+ if (!_set_inpoint0 (element, new_inpoint)) {
+ GST_WARNING_OBJECT (self, "Could not set the in-point of the "
+ "element %" GES_FORMAT " to %" GST_TIME_FORMAT ". Not adding "
+ "as a child", GES_ARGS (element), GST_TIME_ARGS (new_inpoint));
+ return FALSE;
+ }
+
_set_priority0 (element, new_prio);
+
} else if (GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass) && _IS_TOP_EFFECT (element)) {
/* Add the effect at the lowest priority among effects (just after
* the core elements). Need to shift the core elements up by 1
* to make room. */
- if (track && !priv->allow_any_track && !_find_core_in_track (self, track)) {
- GST_WARNING_OBJECT (self, "Cannot add the effect %" GES_FORMAT
- " because its track %" GST_PTR_FORMAT " does not contain one "
- "of the clip's core children", GES_ARGS (element), track);
- return FALSE;
- }
- _update_active_for_track (self, track_el);
-
/* new priority is the lowest priority effect */
new_prio = min_prio;
for (tmp = container->children; tmp; tmp = tmp->next) {
new_prio = MIN (new_prio, _PRIORITY (tmp->data));
}
+ if (track && !priv->allow_any_track) {
+ GList *child_data, *tmp;
+ DurationLimitData *data;
+ GESTrackElement *core = _find_core_in_track (self, track);
+
+ if (!core) {
+ GST_WARNING_OBJECT (self, "Cannot add the effect %" GES_FORMAT
+ " because its track %" GST_PTR_FORMAT " does not contain one "
+ "of the clip's core children", GES_ARGS (element), track);
+ return FALSE;
+ }
+
+ data = _duration_limit_data_new (track_el);
+ data->priority = new_prio;
+ if (!ges_track_element_is_active (core))
+ data->active = FALSE;
+
+ child_data = _duration_limit_data_list_with_data (self, data);
+
+ for (tmp = child_data; tmp; tmp = tmp->next) {
+ data = tmp->data;
+ if (data->priority >= new_prio)
+ data->priority++;
+ }
+
+ if (!_can_update_duration_limit (self, child_data)) {
+ GST_WARNING_OBJECT (self, "Cannot add effect %" GES_FORMAT " as "
+ "a child because the duration-limit cannot be adjusted",
+ GES_ARGS (element));
+ return FALSE;
+ }
+ }
+
+ _update_active_for_track (self, track_el);
+
priv->nb_effects++;
GST_DEBUG_OBJECT (self, "Adding %ith effect: %" GES_FORMAT
" Priority %i", priv->nb_effects, GES_ARGS (element), new_prio);
/* changing priorities, and updating their offset */
priv->prevent_resort = TRUE;
+ priv->setting_priority = TRUE;
priv->prevent_duration_limit_update = TRUE;
/* increase the priority of anything with a lower priority */
_set_priority0 (element, new_prio);
priv->prevent_resort = FALSE;
+ priv->setting_priority = FALSE;
priv->prevent_duration_limit_update = prev_prevent;
/* no need to call _ges_container_sort_children (container) since
* there is no change to the ordering yet (this happens after the
static gboolean
_remove_child (GESContainer * container, GESTimelineElement * element)
{
- GESClipPrivate *priv = GES_CLIP (container)->priv;
+ GESTrackElement *el = GES_TRACK_ELEMENT (element);
+ GESClip *self = GES_CLIP (container);
+ GESClipPrivate *priv = self->priv;
+
+ /* check that the duration-limit can be changed */
+ /* If we are removing a core child, then all other children in the
+ * same track will be removed from the track, which will make the
+ * duration-limit increase, which is safe
+ * Similarly, if it has no track, the duration-limit will not change */
+ if (!priv->allow_any_remove && !_IS_CORE_CHILD (element) &&
+ ges_track_element_get_track (el)) {
+ GList *child_data = NULL;
+ GList *tmp;
+
+ for (tmp = container->children; tmp; tmp = tmp->next) {
+ GESTrackElement *child = tmp->data;
+ if (child == el)
+ continue;
+ child_data =
+ g_list_prepend (child_data, _duration_limit_data_new (child));
+ }
+
+ if (!_can_update_duration_limit (self, child_data)) {
+ GST_WARNING_OBJECT (self, "Cannot remove the child %" GES_FORMAT
+ " because the duration-limit cannot be adjusted", GES_ARGS (el));
+ return FALSE;
+ }
+ }
/* NOTE: notifies are currently frozen by ges_container_add */
if (_IS_TOP_EFFECT (element)) {
/* changing priorities, so preventing a re-sort */
priv->prevent_resort = TRUE;
+ priv->setting_priority = TRUE;
priv->prevent_duration_limit_update = TRUE;
for (tmp = container->children; tmp; tmp = tmp->next) {
guint32 sibling_prio = GES_TIMELINE_ELEMENT_PRIORITY (tmp->data);
}
priv->nb_effects--;
priv->prevent_resort = FALSE;
+ priv->setting_priority = FALSE;
priv->prevent_duration_limit_update = prev_prevent;
/* no need to re-sort the children since the rest keep the same
* relative priorities */
from_clip->priv->prevent_duration_limit_update = TRUE;
to_clip->priv->prevent_duration_limit_update = TRUE;
+ from_clip->priv->allow_any_remove = TRUE;
ges_container_remove (GES_CONTAINER (from_clip),
GES_TIMELINE_ELEMENT (child));
+ from_clip->priv->allow_any_remove = FALSE;
to_clip->priv->allow_any_track = TRUE;
if (!ges_container_add (GES_CONTAINER (to_clip),
{
GESClip *self = GES_CLIP (object);
+ self->priv->allow_any_remove = TRUE;
+
g_list_free_full (self->priv->copied_track_elements, gst_object_unref);
self->priv->copied_track_elements = NULL;
g_clear_object (&self->priv->copied_layer);
else
inc = +1;
+ /* check that the duration-limit can be changed */
+ for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
+ GESTimelineElement *child = tmp->data;
+ guint32 priority = child->priority;
+ DurationLimitData *data =
+ _duration_limit_data_new (GES_TRACK_ELEMENT (child));
+
+ if (child == element)
+ data->priority = new_prio;
+ else if ((inc == +1 && priority >= new_prio && priority < current_prio)
+ || (inc == -1 && priority <= new_prio && priority > current_prio))
+ data->priority = child->priority + inc;
+
+ child_data = g_list_prepend (child_data, data);
+ }
+
+ if (!_can_update_duration_limit (clip, child_data)) {
+ GST_WARNING_OBJECT (clip, "Cannot move top effect %" GES_FORMAT
+ " to index %i because the duration-limit cannot adjust",
+ GES_ARGS (effect), newindex);
+ return FALSE;
+ }
+
GST_DEBUG_OBJECT (clip, "Setting top effect %" GST_PTR_FORMAT "priority: %i",
effect, new_prio);
/* prevent a re-sort of the list whilst we are traversing it! */
clip->priv->prevent_resort = TRUE;
+ clip->priv->setting_priority = TRUE;
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
GESTimelineElement *child = tmp->data;
guint32 priority = child->priority;
_set_priority0 (element, new_prio);
clip->priv->prevent_resort = FALSE;
+ clip->priv->setting_priority = FALSE;
_ges_container_sort_children (GES_CONTAINER (clip));
/* height should have stayed the same */
CHECK_OBJECT_PROPS (effect, 5, 67, 20);
/* should not be able to set the in-point to non-zero */
- fail_if (ges_timeline_element_set_inpoint (child0, 40));
+ assert_fail_set_inpoint (child0, 40);
CHECK_OBJECT_PROPS (clip, 5, 30, 20);
CHECK_OBJECT_PROPS (child0, 5, 0, 20);
/* can not set in-point above max_duration, nor max_duration below
* in-point */
- fail_if (ges_timeline_element_set_max_duration (child0, 29));
+ assert_fail_set_max_duration (child0, 29);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
- fail_if (ges_timeline_element_set_max_duration (child1, 29));
+ assert_fail_set_max_duration (child1, 29);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
- fail_if (ges_timeline_element_set_max_duration (clip, 29));
+ assert_fail_set_max_duration (clip, 29);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
/* can't set the inpoint to (new_max), even though it is lower than
* our own max-duration (new_max + 1) because it is too high for our
* sibling child1 */
- fail_if (ges_timeline_element_set_inpoint (child0, new_max));
+ assert_fail_set_inpoint (child0, new_max);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
- fail_if (ges_timeline_element_set_inpoint (child1, new_max));
+ assert_fail_set_inpoint (child1, new_max);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
- fail_if (ges_timeline_element_set_inpoint (clip, new_max));
+ assert_fail_set_inpoint (clip, new_max);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
CHECK_OBJECT_PROPS_MAX (effect, 5, new_max + 2, 20, new_max + 500);
/* but not higher than our own */
- fail_if (ges_timeline_element_set_inpoint (effect, new_max + 501));
+ assert_fail_set_inpoint (effect, new_max + 501);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (effect, 5, new_max + 2, 20, new_max + 500);
- fail_if (ges_timeline_element_set_max_duration (effect, new_max + 1));
+ assert_fail_set_max_duration (effect, new_max + 1);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 2);
CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max + 1);
CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
/* should not be able to set the max-duration to a valid time */
- fail_if (ges_timeline_element_set_max_duration (child0, 40));
+ assert_fail_set_max_duration (child0, 40);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 180);
CHECK_OBJECT_PROPS_MAX (child0, 5, 0, 20, GST_CLOCK_TIME_NONE);
/* should not be able to set the max of the clip to anything else
* when it has no core children with an internal source */
- fail_if (ges_timeline_element_set_max_duration (clip, 150));
+ assert_fail_set_max_duration (clip, 150);
CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, GST_CLOCK_TIME_NONE);
CHECK_OBJECT_PROPS_MAX (child0, 5, 0, 20, GST_CLOCK_TIME_NONE);
GST_END_TEST;
+GST_START_TEST (test_can_set_duration_limit)
+{
+ GESTimeline *timeline;
+ GESLayer *layer;
+ GESClip *clip;
+ GESTrackElement *source0, *source1;
+ GESTrackElement *effect0, *effect1, *effect2;
+ GESTrack *track0, *track1;
+ gint limit_notify_count = 0;
+
+ ges_init ();
+
+ timeline = ges_timeline_new ();
+ track0 = GES_TRACK (ges_video_track_new ());
+ track1 = GES_TRACK (ges_audio_track_new ());
+
+ fail_unless (ges_timeline_add_track (timeline, track0));
+ fail_unless (ges_timeline_add_track (timeline, track1));
+ /* add track3 later */
+
+ layer = ges_timeline_append_layer (timeline);
+
+ /* place a dummy clip at the start of the layer */
+ clip = GES_CLIP (ges_test_clip_new ());
+ assert_set_start (clip, 0);
+ assert_set_duration (clip, 20);
+
+ fail_unless (ges_layer_add_clip (layer, clip));
+
+ /* the clip we will be editing overlaps the first clip at its start */
+ clip = GES_CLIP (ges_test_clip_new ());
+
+ g_signal_connect (clip, "notify::duration-limit", G_CALLBACK (_count_cb),
+ &limit_notify_count);
+
+ assert_set_start (clip, 10);
+ assert_set_duration (clip, 20);
+
+ fail_unless (ges_layer_add_clip (layer, clip));
+
+ source0 =
+ ges_clip_find_track_element (clip, track0, GES_TYPE_VIDEO_TEST_SOURCE);
+ source1 =
+ ges_clip_find_track_element (clip, track1, GES_TYPE_AUDIO_TEST_SOURCE);
+
+ fail_unless (source0);
+ fail_unless (source1);
+
+ gst_object_unref (source0);
+ gst_object_unref (source1);
+
+ assert_equals_int (limit_notify_count, 0);
+ _assert_duration_limit (clip, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+
+ assert_set_inpoint (clip, 16);
+
+ assert_equals_int (limit_notify_count, 0);
+ _assert_duration_limit (clip, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, GST_CLOCK_TIME_NONE);
+
+ assert_set_max_duration (clip, 36);
+
+ assert_equals_int (limit_notify_count, 1);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+
+ /* add effects */
+ effect0 = GES_TRACK_ELEMENT (ges_effect_new ("agingtv"));
+ effect1 = GES_TRACK_ELEMENT (ges_effect_new ("vertigotv"));
+ effect2 = GES_TRACK_ELEMENT (ges_effect_new ("alpha"));
+
+ ges_track_element_set_has_internal_source (effect0, TRUE);
+ fail_unless (ges_track_element_has_internal_source (effect1) == FALSE);
+ ges_track_element_set_has_internal_source (effect2, TRUE);
+
+ assert_set_max_duration (effect0, 10);
+ /* already set the track */
+ fail_unless (ges_track_add_element (track0, effect0));
+ /* cannot add because it would cause the duration-limit to go to 10,
+ * causing a full overlap with the clip at the beginning of the layer */
+
+ gst_object_ref (effect0);
+ fail_if (ges_container_add (GES_CONTAINER (clip),
+ GES_TIMELINE_ELEMENT (effect0)));
+
+ assert_equals_int (limit_notify_count, 1);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+
+ /* removing from the track and adding will work, but track selection
+ * will fail */
+ fail_unless (ges_track_remove_element (track0, effect0));
+
+ _assert_add (clip, effect0);
+ fail_if (ges_track_element_get_track (effect0));
+ gst_object_unref (effect0);
+
+ assert_equals_int (limit_notify_count, 1);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 10);
+
+ fail_if (ges_clip_add_child_to_track (clip, effect0, track0, NULL));
+
+ /* set max-duration to 11 and we are fine to select a track */
+ assert_set_max_duration (effect0, 11);
+ assert_equals_int (limit_notify_count, 1);
+ _assert_duration_limit (clip, 20);
+
+ fail_unless (ges_clip_add_child_to_track (clip, effect0, track0,
+ NULL) == effect0);
+
+ assert_equals_int (limit_notify_count, 2);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 11);
+
+ /* cannot set duration above the limit */
+ assert_fail_set_duration (clip, 12);
+ assert_fail_set_duration (source0, 12);
+ assert_fail_set_duration (effect0, 12);
+
+ /* allow the max_duration to increase again */
+ assert_set_max_duration (effect0, 25);
+
+ assert_equals_int (limit_notify_count, 3);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+
+ assert_set_duration (clip, 20);
+
+ assert_equals_int (limit_notify_count, 3);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+
+ /* add another effect */
+ _assert_add (clip, effect1);
+ fail_unless (ges_track_element_get_track (effect1) == track0);
+
+ assert_equals_int (limit_notify_count, 3);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+
+ /* make source0 inactive and reduce its max-duration
+ * note that this causes effect0 and effect1 to also become in-active */
+ _assert_set_active (source0, FALSE);
+ _assert_active (source0, FALSE);
+ _assert_active (effect0, FALSE);
+ _assert_active (effect1, FALSE);
+
+ assert_equals_int (limit_notify_count, 3);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+
+ /* can set a low max duration whilst the source is inactive */
+ assert_set_max_duration (source0, 26);
+
+ assert_equals_int (limit_notify_count, 3);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+
+ /* add the last effect */
+ assert_set_inpoint (effect2, 7);
+ assert_set_max_duration (effect2, 17);
+ _assert_active (effect2, TRUE);
+
+ /* safe to add because the source is inactive */
+ assert_equals_int (limit_notify_count, 3);
+ _assert_add (clip, effect2);
+ assert_equals_int (limit_notify_count, 3);
+ _assert_active (source0, FALSE);
+ _assert_active (effect0, FALSE);
+ _assert_active (effect1, FALSE);
+ _assert_active (effect2, FALSE);
+
+ fail_unless (ges_track_element_get_track (effect2) == track0);
+
+ assert_equals_int (limit_notify_count, 3);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 16, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 16, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 16, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 17);
+
+ /* want to make the source and its effects active again */
+ assert_set_inpoint (source0, 6);
+ assert_set_max_duration (effect2, 33);
+
+ assert_equals_int (limit_notify_count, 4);
+ _assert_duration_limit (clip, 30);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ _assert_set_active (source0, TRUE);
+ _assert_set_active (effect0, TRUE);
+ _assert_set_active (effect1, TRUE);
+ _assert_set_active (effect2, TRUE);
+
+ assert_equals_int (limit_notify_count, 5);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ /* cannot set in-point of clip to 16, nor of either source */
+ assert_fail_set_inpoint (clip, 16);
+ assert_fail_set_inpoint (source0, 16);
+ assert_fail_set_inpoint (source1, 16);
+
+ assert_equals_int (limit_notify_count, 5);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ /* can set just below */
+ assert_set_inpoint (source1, 15);
+
+ assert_equals_int (limit_notify_count, 6);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 15, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 15, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 15, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 11, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 11, 33);
+
+ assert_set_inpoint (clip, 6);
+ assert_set_duration (clip, 20);
+
+ assert_equals_int (limit_notify_count, 7);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ /* cannot set in-point of non-core in a way that would cause limit to
+ * drop */
+ assert_fail_set_inpoint (effect2, 23);
+ assert_fail_set_inpoint (effect0, 15);
+
+ assert_equals_int (limit_notify_count, 7);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ /* can set just below */
+ assert_set_inpoint (effect2, 22);
+
+ assert_equals_int (limit_notify_count, 8);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 11, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 11, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 22, 11, 33);
+
+ assert_set_inpoint (effect2, 7);
+ assert_set_duration (clip, 20);
+
+ assert_equals_int (limit_notify_count, 9);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ /* same but with max-duration */
+
+ /* core */
+ assert_fail_set_max_duration (clip, 16);
+ assert_fail_set_max_duration (source0, 16);
+ assert_fail_set_max_duration (source1, 16);
+
+ assert_equals_int (limit_notify_count, 9);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 36);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ assert_set_max_duration (source1, 17);
+
+ assert_equals_int (limit_notify_count, 10);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 11, 17);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 11, 17);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 11, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 11, 33);
+
+ assert_set_max_duration (source1, 30);
+ assert_set_duration (clip, 20);
+
+ assert_equals_int (limit_notify_count, 11);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 30);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ assert_set_max_duration (clip, 17);
+
+ assert_equals_int (limit_notify_count, 12);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 11, 17);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 11, 17);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 11, 17);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 11, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 11, 33);
+
+ assert_set_max_duration (clip, 26);
+ assert_set_duration (clip, 20);
+
+ assert_equals_int (limit_notify_count, 13);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ /* non-core */
+ assert_fail_set_max_duration (effect0, 10);
+ assert_fail_set_max_duration (effect2, 17);
+
+ assert_equals_int (limit_notify_count, 13);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ assert_set_max_duration (effect2, 18);
+
+ assert_equals_int (limit_notify_count, 14);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 11, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 11, 18);
+
+ assert_set_max_duration (effect2, 33);
+ assert_set_duration (clip, 20);
+
+ assert_equals_int (limit_notify_count, 15);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 33);
+
+ /* test setting active */
+ _assert_active (effect2, TRUE);
+ _assert_set_active (effect2, FALSE);
+ assert_set_max_duration (effect2, 17);
+
+ assert_equals_int (limit_notify_count, 15);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 17);
+
+ fail_if (ges_track_element_set_active (effect2, TRUE));
+
+ assert_equals_int (limit_notify_count, 15);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 7, 20, 17);
+
+ assert_set_inpoint (effect2, 6);
+ _assert_set_active (effect2, TRUE);
+
+ assert_equals_int (limit_notify_count, 16);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 11, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 6, 11, 17);
+
+ /* make source0 in-active */
+ _assert_active (source0, TRUE);
+ _assert_set_active (source0, FALSE);
+ _assert_active (source0, FALSE);
+ _assert_active (effect0, FALSE);
+ _assert_active (effect1, FALSE);
+ _assert_active (effect2, FALSE);
+
+ assert_set_duration (source0, 20);
+
+ assert_equals_int (limit_notify_count, 17);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 6, 20, 17);
+
+ /* lower duration-limit for source for when it becomes active */
+ assert_set_max_duration (source0, 16);
+
+ assert_equals_int (limit_notify_count, 17);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 6, 20, 17);
+
+ /* cannot make the source active */
+ fail_if (ges_track_element_set_active (source0, TRUE));
+
+ assert_equals_int (limit_notify_count, 17);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 6, 20, 17);
+
+ /* nor can we make the effects active because this would activate the
+ * source */
+ fail_if (ges_track_element_set_active (effect0, TRUE));
+ fail_if (ges_track_element_set_active (effect1, TRUE));
+ fail_if (ges_track_element_set_active (effect2, TRUE));
+
+ assert_equals_int (limit_notify_count, 17);
+ _assert_duration_limit (clip, 20);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 6, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 6, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 6, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 6, 20, 17);
+
+ /* allow it to just succeed */
+ assert_set_inpoint (source0, 5);
+
+ assert_equals_int (limit_notify_count, 18);
+ _assert_duration_limit (clip, 21);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 5, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 5, 20, 16);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 5, 20, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 20, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 6, 20, 17);
+
+ _assert_set_active (effect1, TRUE);
+
+ assert_equals_int (limit_notify_count, 19);
+ _assert_duration_limit (clip, 11);
+ CHECK_OBJECT_PROPS_MAX (clip, 10, 5, 11, 16);
+ CHECK_OBJECT_PROPS_MAX (source0, 10, 5, 11, 16);
+ CHECK_OBJECT_PROPS_MAX (source1, 10, 5, 11, 26);
+ CHECK_OBJECT_PROPS_MAX (effect0, 10, 0, 11, 25);
+ CHECK_OBJECT_PROPS_MAX (effect1, 10, 0, 11, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect2, 10, 6, 11, 17);
+
+ gst_object_unref (timeline);
+
+ ges_deinit ();
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_children_properties_contain)
{
GESTimeline *timeline;
tcase_add_test (tc_chain, test_children_inpoint);
tcase_add_test (tc_chain, test_children_max_duration);
tcase_add_test (tc_chain, test_duration_limit);
+ tcase_add_test (tc_chain, test_can_set_duration_limit);
tcase_add_test (tc_chain, test_children_properties_contain);
tcase_add_test (tc_chain, test_children_properties_change);
tcase_add_test (tc_chain, test_copy_paste_children_properties);