*
* The #GESTimelineElement:in-point of the clip will control the
* #GESTimelineElement:in-point of these core elements to be the same
- * value.
+ * value if their #GESTrackElement:has-internal-source is set to %TRUE.
+ * The #GESTimelineElement:max-duration of the clip is the minimum
+ * #GESTimelineElement:max-duration of its children. If you set its value
+ * to anything other than its current value, this will also set the
+ * #GESTimelineElement:max-duration of all its core children to the same
+ * value if their #GESTrackElement:has-internal-source is set to %TRUE.
*
* ## Effects
*
gboolean prevent_priority_offset_update;
gboolean prevent_resort;
+ gboolean updating_max_duration;
+ gboolean prevent_max_duration_update;
+ gboolean setting_inpoint;
+
/* The formats supported by this Clip */
GESTrackType supportedformats;
};
}
}
+static void
+_child_inpoint_changed_cb (GESTimelineElement * child, GParamSpec * pspec,
+ GESContainer * container)
+{
+ if (GES_CLIP (container)->priv->setting_inpoint)
+ return;
+
+ /* ignore non-core */
+ if (!ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE))
+ return;
+
+ /* if the track element has no internal content, then this means its
+ * in-point has been set (back) to 0, we can ignore this update */
+ if (!ges_track_element_has_internal_source (GES_TRACK_ELEMENT (child)))
+ return;
+
+ /* If the child->inpoint is the same as our own, set_inpoint will do
+ * nothing. For example, when we set them in add_child (the notifies for
+ * this are released after child_added is called because
+ * ges_container_add freezes them) */
+ _set_inpoint0 (GES_TIMELINE_ELEMENT (container), child->inpoint);
+}
+
+/* called when a child is added, removed or their max-duration changes */
+static void
+_update_max_duration (GESContainer * container)
+{
+ GList *tmp;
+ GstClockTime min = GST_CLOCK_TIME_NONE;
+ GESClipPrivate *priv = GES_CLIP (container)->priv;
+
+ if (priv->prevent_max_duration_update)
+ return;
+
+ for (tmp = container->children; tmp; tmp = tmp->next) {
+ GESTimelineElement *child = tmp->data;
+ if (ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE)
+ && GST_CLOCK_TIME_IS_VALID (child->maxduration))
+ min = GST_CLOCK_TIME_IS_VALID (min) ? MIN (min, child->maxduration) :
+ child->maxduration;
+ }
+ priv->updating_max_duration = TRUE;
+ ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (container), min);
+ priv->updating_max_duration = FALSE;
+}
+
+static void
+_child_max_duration_changed_cb (GESTimelineElement * child,
+ GParamSpec * pspec, GESContainer * container)
+{
+ /* ignore non-core */
+ if (!ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE))
+ return;
+
+ _update_max_duration (container);
+}
+
+static void
+_child_has_internal_source_changed_cb (GESTimelineElement * child,
+ GParamSpec * pspec, GESContainer * container)
+{
+ /* ignore non-core */
+ if (!ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE))
+ return;
+
+ /* if the track element is now registered to have no internal content,
+ * we don't have to do anything */
+ if (!ges_track_element_has_internal_source (GES_TRACK_ELEMENT (child)))
+ return;
+
+ /* otherwise, we need to make its in-point match ours */
+ _set_inpoint0 (child, _INPOINT (container));
+}
+
+
/*****************************************************
* *
* GESTimelineElement virtual methods implementation *
static gboolean
_set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
{
- GList *tmp, *children;
- GESContainer *container = GES_CONTAINER (element);
+ GList *tmp;
+ GESClipPrivate *priv = GES_CLIP (element)->priv;
- children = ges_container_get_children (container, FALSE);
- container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
- for (tmp = children; tmp; tmp = g_list_next (tmp)) {
- GESTimelineElement *child = (GESTimelineElement *) tmp->data;
+ priv->setting_inpoint = TRUE;
+ for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
+ GESTimelineElement *child = tmp->data;
- /* FIXME: we should allow the inpoint to be different for children
- * that are *not* the core track elements of the clip. E.g. if we
- * add a GESEffect to a clip, we should not be editing its inpoint */
- if (child != container->initiated_move)
+ if (ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE)
+ && ges_track_element_has_internal_source (GES_TRACK_ELEMENT (child)))
_set_inpoint0 (child, inpoint);
}
- container->children_control_mode = GES_CHILDREN_UPDATE;
- g_list_free_full (children, gst_object_unref);
+ priv->setting_inpoint = FALSE;
return TRUE;
}
_set_max_duration (GESTimelineElement * element, GstClockTime maxduration)
{
GList *tmp;
+ GESClipPrivate *priv = GES_CLIP (element)->priv;
+ GstClockTime new_min = GST_CLOCK_TIME_NONE;
+
+ /* if we are setting based on a change in the minimum */
+ if (priv->updating_max_duration)
+ return TRUE;
+
+ /* else, we set every core child to have the same max duration */
- for (tmp = GES_CONTAINER (element)->children; tmp; tmp = g_list_next (tmp))
- ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (tmp->data),
- maxduration);
+ priv->prevent_max_duration_update = TRUE;
+ for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
+ GESTimelineElement *child = tmp->data;
+
+ if (ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE)
+ && ges_track_element_has_internal_source (GES_TRACK_ELEMENT (child))) {
+ ges_timeline_element_set_max_duration (child, maxduration);
+ if (GST_CLOCK_TIME_IS_VALID (child->maxduration)) {
+ new_min = GST_CLOCK_TIME_IS_VALID (new_min) ?
+ MIN (new_min, child->maxduration) : child->maxduration;
+ }
+ }
+ }
+ priv->prevent_max_duration_update = FALSE;
+
+ if (new_min != maxduration) {
+ if (GST_CLOCK_TIME_IS_VALID (new_min))
+ GST_WARNING_OBJECT (element, "Failed to set the max-duration of the "
+ "clip to %" GST_TIME_FORMAT " because it was not possible to "
+ "match this with the actual minimum of %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (maxduration), GST_TIME_ARGS (new_min));
+ else
+ GST_WARNING_OBJECT (element, "Failed to set the max-duration of the "
+ "clip to %" GST_TIME_FORMAT " because it has no core children "
+ "whose max-duration could be set to anything other than "
+ "GST_CLOCK_TIME_NONE", GST_TIME_ARGS (maxduration));
+ priv->updating_max_duration = TRUE;
+ ges_timeline_element_set_max_duration (element, new_min);
+ priv->updating_max_duration = FALSE;
+ return FALSE;
+ }
return TRUE;
}
/* Set the core element to have the same in-point, which we don't
* apply to effects */
- _set_inpoint0 (element, GES_TIMELINE_ELEMENT_INPOINT (container));
+ if (ges_track_element_has_internal_source (GES_TRACK_ELEMENT (element)))
+ _set_inpoint0 (element, _INPOINT (container));
} else if (GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass)
&& GES_IS_BASE_EFFECT (element)) {
GList *tmp;
static void
_child_added (GESContainer * container, GESTimelineElement * element)
{
- /* FIXME: adjust the max-duration according to the new child */
g_signal_connect (G_OBJECT (element), "notify::priority",
G_CALLBACK (_child_priority_changed_cb), container);
+ g_signal_connect (G_OBJECT (element), "notify::in-point",
+ G_CALLBACK (_child_inpoint_changed_cb), container);
+ g_signal_connect (G_OBJECT (element), "notify::max-duration",
+ G_CALLBACK (_child_max_duration_changed_cb), container);
+ g_signal_connect (G_OBJECT (element), "notify::has-internal-source",
+ G_CALLBACK (_child_has_internal_source_changed_cb), container);
_child_priority_changed_cb (element, NULL, container);
+ _update_max_duration (container);
}
static void
{
g_signal_handlers_disconnect_by_func (element, _child_priority_changed_cb,
container);
+ g_signal_handlers_disconnect_by_func (element, _child_inpoint_changed_cb,
+ container);
+ g_signal_handlers_disconnect_by_func (element,
+ _child_max_duration_changed_cb, container);
+ g_signal_handlers_disconnect_by_func (element,
+ _child_has_internal_source_changed_cb, container);
+
+ _update_max_duration (container);
}
static void
static void
ges_clip_init (GESClip * self)
{
- self->priv = ges_clip_get_instance_private (self);
- self->priv->layer = NULL;
- self->priv->nb_effects = 0;
+ GESClipPrivate *priv;
+ priv = self->priv = ges_clip_get_instance_private (self);
+ priv->layer = NULL;
+ priv->nb_effects = 0;
+ priv->prevent_priority_offset_update = FALSE;
+ priv->prevent_resort = FALSE;
+ priv->updating_max_duration = FALSE;
+ priv->prevent_max_duration_update = FALSE;
+ priv->setting_inpoint = FALSE;
}
/**
for (tmp = track_elements; tmp; tmp = tmp->next) {
GESTimelineElement *elem = tmp->data;
ELEMENT_SET_FLAG (elem, GES_TRACK_ELEMENT_IS_CORE);
-
- /* FIXME: we should set the max duration of the clip based on the
- * max duration of the child. Not the other way around. */
- if (GST_CLOCK_TIME_IS_VALID (GES_TIMELINE_ELEMENT_MAX_DURATION (clip)))
- ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (elem),
- GES_TIMELINE_ELEMENT_MAX_DURATION (clip));
}
result = g_list_concat (track_elements, result);
}
continue;
}
+ /* FIXME: in-point for non-core track elements should be shifted by
+ * the split (adding them to the new clip will not set their in-point)
+ * Handle this once generic time effects are supported in splitting */
ges_container_add (GES_CONTAINER (new_object),
GES_TIMELINE_ELEMENT (new_trackelement));
ges_track_element_copy_properties (GES_TIMELINE_ELEMENT (trackelement),
}
static void
-_test_children_time_setting_on_clip (GESClip * clip, GESTimelineElement * child)
+_test_children_time_setting_on_clip (GESClip * clip, GESTrackElement * child)
{
- /* FIXME: Don't necessarily want to change the inpoint of all the
- * children if the clip inpoint changes. Really, we would only expect
- * the inpoint to change for the source elements within a clip.
- * Setting the inpoint of an operation may be irrelevant, and for
- * operations where it *is* relevant, we would ideally want it to be
- * independent from the source element's inpoint (unlike the start and
- * duration values).
- * However, this is the current behaviour, but if this is changed this
- * test should be changed to only check that source elements have
- * their inpoint changed, and operation elements have their inpoint
- * unchanged */
_assert_children_time_setter (clip, child, "in-point",
ges_timeline_element_set_inpoint, 11, 101);
_assert_children_time_setter (clip, child, "in-point",
GESClip *clip = clips[i];
GESContainer *group = GES_CONTAINER (ges_group_new ());
GList *children;
- GESTimelineElement *child;
+ GESTrackElement *child;
/* no children */
_test_children_time_setting_on_clip (clip, NULL);
/* child in timeline */
fail_unless (ges_layer_add_clip (layer, clip));
children = GES_CONTAINER_CHILDREN (clip);
fail_unless (children);
- child = GES_TIMELINE_ELEMENT (children->data);
+ child = GES_TRACK_ELEMENT (children->data);
+ /* make sure the child can have its in-point set */
+ ges_track_element_set_has_internal_source (child, TRUE);
_test_children_time_setting_on_clip (clip, child);
/* clip in a group */
ges_container_add (group, GES_TIMELINE_ELEMENT (clip));
fail_unless (ges_layer_remove_clip (layer, clip));
children = GES_CONTAINER_CHILDREN (clip);
fail_unless (children);
- child = GES_TIMELINE_ELEMENT (children->data);
+ child = GES_TRACK_ELEMENT (children->data);
+ ges_track_element_set_has_internal_source (child, TRUE);
_test_children_time_setting_on_clip (clip, child);
gst_object_unref (clip);
}
GST_END_TEST;
+GST_START_TEST (test_children_inpoint)
+{
+ GESTimeline *timeline;
+ GESLayer *layer;
+ GESTimelineElement *clip, *child0, *child1, *effect;
+ GList *children;
+
+ ges_init ();
+
+ timeline = ges_timeline_new_audio_video ();
+ fail_unless (timeline);
+
+ layer = ges_timeline_append_layer (timeline);
+
+ clip = GES_TIMELINE_ELEMENT (ges_test_clip_new ());
+
+ fail_unless (ges_timeline_element_set_start (clip, 5));
+ fail_unless (ges_timeline_element_set_duration (clip, 20));
+ fail_unless (ges_timeline_element_set_inpoint (clip, 30));
+
+ CHECK_OBJECT_PROPS (clip, 5, 30, 20);
+
+ fail_unless (ges_layer_add_clip (layer, GES_CLIP (clip)));
+
+ /* clip now has children */
+ children = GES_CONTAINER_CHILDREN (clip);
+ fail_unless (children);
+ child0 = children->data;
+ fail_unless (children->next);
+ child1 = children->next->data;
+ fail_unless (children->next->next == NULL);
+
+ fail_unless (ges_track_element_has_internal_source (GES_TRACK_ELEMENT
+ (child0)));
+ fail_unless (ges_track_element_has_internal_source (GES_TRACK_ELEMENT
+ (child1)));
+
+ CHECK_OBJECT_PROPS (clip, 5, 30, 20);
+ CHECK_OBJECT_PROPS (child0, 5, 30, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 30, 20);
+
+ /* add a non-core element */
+ effect = GES_TIMELINE_ELEMENT (ges_effect_new ("agingtv"));
+ fail_if (ges_track_element_has_internal_source (GES_TRACK_ELEMENT (effect)));
+ /* allow us to choose our own in-point */
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (effect), TRUE);
+ fail_unless (ges_timeline_element_set_start (effect, 104));
+ fail_unless (ges_timeline_element_set_duration (effect, 53));
+ fail_unless (ges_timeline_element_set_inpoint (effect, 67));
+
+ /* adding the effect will change its start and duration, but not its
+ * in-point */
+ fail_unless (ges_container_add (GES_CONTAINER (clip), effect));
+
+ CHECK_OBJECT_PROPS (clip, 5, 30, 20);
+ CHECK_OBJECT_PROPS (child0, 5, 30, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 30, 20);
+ CHECK_OBJECT_PROPS (effect, 5, 67, 20);
+
+ /* register child0 as having no internal source, which means its
+ * in-point will be set to 0 */
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child0), FALSE);
+
+ CHECK_OBJECT_PROPS (clip, 5, 30, 20);
+ CHECK_OBJECT_PROPS (child0, 5, 0, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 30, 20);
+ 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));
+
+ CHECK_OBJECT_PROPS (clip, 5, 30, 20);
+ CHECK_OBJECT_PROPS (child0, 5, 0, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 30, 20);
+ CHECK_OBJECT_PROPS (effect, 5, 67, 20);
+
+ /* when we set the in-point on a core-child with an internal source we
+ * also set the clip and siblings with the same features */
+ fail_unless (ges_timeline_element_set_inpoint (child1, 50));
+
+ CHECK_OBJECT_PROPS (clip, 5, 50, 20);
+ /* child with no internal source not changed */
+ CHECK_OBJECT_PROPS (child0, 5, 0, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 50, 20);
+ /* non-core no changed */
+ CHECK_OBJECT_PROPS (effect, 5, 67, 20);
+
+ /* setting back to having internal source will put in sync with the
+ * in-point of the clip */
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child0), TRUE);
+
+ CHECK_OBJECT_PROPS (clip, 5, 50, 20);
+ CHECK_OBJECT_PROPS (child0, 5, 50, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 50, 20);
+ CHECK_OBJECT_PROPS (effect, 5, 67, 20);
+
+ fail_unless (ges_timeline_element_set_inpoint (child0, 40));
+
+ CHECK_OBJECT_PROPS (clip, 5, 40, 20);
+ CHECK_OBJECT_PROPS (child0, 5, 40, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 40, 20);
+ CHECK_OBJECT_PROPS (effect, 5, 67, 20);
+
+ /* setting in-point on effect shouldn't change any other siblings */
+ fail_unless (ges_timeline_element_set_inpoint (effect, 77));
+
+ CHECK_OBJECT_PROPS (clip, 5, 40, 20);
+ CHECK_OBJECT_PROPS (child0, 5, 40, 20);
+ CHECK_OBJECT_PROPS (child1, 5, 40, 20);
+ CHECK_OBJECT_PROPS (effect, 5, 77, 20);
+
+ gst_object_unref (timeline);
+
+ ges_deinit ();
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_children_max_duration)
+{
+ GESTimeline *timeline;
+ GESLayer *layer;
+ gchar *uri;
+ GESTimelineElement *clips[] = { NULL, NULL };
+ GESTimelineElement *child0, *child1, *effect;
+ guint i;
+ GstClockTime max_duration, new_max;
+ GList *children;
+
+ ges_init ();
+
+ timeline = ges_timeline_new_audio_video ();
+ fail_unless (timeline);
+
+ layer = ges_timeline_append_layer (timeline);
+
+ uri = ges_test_get_audio_video_uri ();
+ clips[0] = GES_TIMELINE_ELEMENT (ges_uri_clip_new (uri));
+ fail_unless (clips[0]);
+ g_free (uri);
+
+ clips[1] = GES_TIMELINE_ELEMENT (ges_test_clip_new ());
+
+ for (i = 0; i < G_N_ELEMENTS (clips); i++) {
+ GESTimelineElement *clip = clips[i];
+ fail_unless (_MAX_DURATION (clip) == GST_CLOCK_TIME_NONE);
+
+ fail_unless (ges_timeline_element_set_start (clip, 5));
+ fail_unless (ges_timeline_element_set_duration (clip, 20));
+ fail_unless (ges_timeline_element_set_inpoint (clip, 30));
+ /* can not set the max duration when we have no children */
+ fail_if (ges_timeline_element_set_max_duration (clip, 150));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, GST_CLOCK_TIME_NONE);
+
+ fail_unless (ges_layer_add_clip (layer, GES_CLIP (clip)));
+
+ /* clip now has children */
+ children = GES_CONTAINER_CHILDREN (clip);
+ fail_unless (children);
+ child0 = children->data;
+ fail_unless (children->next);
+ child1 = children->next->data;
+ fail_unless (children->next->next == NULL);
+
+ fail_unless (ges_track_element_has_internal_source (GES_TRACK_ELEMENT
+ (child0)));
+ fail_unless (ges_track_element_has_internal_source (GES_TRACK_ELEMENT
+ (child1)));
+
+ if (GES_IS_URI_CLIP (clip)) {
+ /* uri clip children should be created with a max-duration set */
+ /* each created child has the same max-duration */
+ max_duration = _MAX_DURATION (child0);
+ fail_unless (max_duration != GST_CLOCK_TIME_NONE);
+ new_max = max_duration;
+ } else {
+ max_duration = GST_CLOCK_TIME_NONE;
+ /* need a valid clock time that is not too large */
+ new_max = 500;
+ }
+
+ /* added children do not change the clip's max-duration, but will
+ * instead set it to the minimum value of its children */
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, max_duration);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, max_duration);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, max_duration);
+
+ /* add a non-core element */
+ effect = GES_TIMELINE_ELEMENT (ges_effect_new ("agingtv"));
+ fail_if (ges_track_element_has_internal_source (GES_TRACK_ELEMENT
+ (effect)));
+ /* allow us to choose our own max-duration */
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (effect),
+ TRUE);
+ fail_unless (ges_timeline_element_set_start (effect, 104));
+ fail_unless (ges_timeline_element_set_duration (effect, 53));
+ fail_unless (ges_timeline_element_set_max_duration (effect, 1));
+
+ /* adding the effect will change its start and duration, but not its
+ * max-duration (or in-point) */
+ fail_unless (ges_container_add (GES_CONTAINER (clip), effect));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, max_duration);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, max_duration);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, max_duration);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* when setting max_duration of core children, clip will take the
+ * minimum value */
+ fail_unless (ges_timeline_element_set_max_duration (child0, new_max - 1));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, new_max - 1);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, new_max - 1);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, max_duration);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ fail_unless (ges_timeline_element_set_max_duration (child1, new_max - 2));
+
+ 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, 1);
+
+ fail_unless (ges_timeline_element_set_max_duration (child0, 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 (child1, 5, 30, 20, new_max - 2);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* non-core has no effect */
+ fail_unless (ges_timeline_element_set_max_duration (effect, new_max - 4));
+
+ 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, new_max - 4);
+
+ fail_unless (ges_timeline_element_set_max_duration (effect, 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 (child1, 5, 30, 20, new_max - 2);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* setting on the clip will set all the core children to the same
+ * value */
+ fail_unless (ges_timeline_element_set_max_duration (clip, 180));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 180);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, 180);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, 180);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* register child0 as having no internal source, which means its
+ * in-point will be set to 0 and max-duration set to
+ * GST_CLOCK_TIME_NONE */
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child0),
+ FALSE);
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 180);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, 180);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* should not be able to set the max-duration to a valid time */
+ fail_if (ges_timeline_element_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);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, 180);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* same with child1 */
+ /* clock time of the clip should now be GST_CLOCK_TIME_NONE */
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child1),
+ FALSE);
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* 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));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* setting back to having an internal source will not immediately
+ * change the max-duration (unlike in-point) */
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child0),
+ TRUE);
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* can now set the max-duration, which will effect the clip */
+ fail_unless (ges_timeline_element_set_max_duration (child0, 140));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 0, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child1),
+ TRUE);
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ fail_unless (ges_timeline_element_set_max_duration (child1, 130));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 130);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, 130);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* removing a child may change the max_duration of the clip */
+ gst_object_ref (child0);
+ gst_object_ref (child1);
+ gst_object_ref (effect);
+
+ /* removing non-core does nothing */
+ fail_unless (ges_container_remove (GES_CONTAINER (clip), effect));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 130);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, 130);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* new minimum max-duration for the clip when we remove child1 */
+ fail_unless (ges_container_remove (GES_CONTAINER (clip), child1));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, 130);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ /* with no core-children, the max-duration of the clip is set to
+ * GST_CLOCK_TIME_NONE */
+ fail_unless (ges_container_remove (GES_CONTAINER (clip), child0));
+
+ CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, GST_CLOCK_TIME_NONE);
+ CHECK_OBJECT_PROPS_MAX (child0, 5, 30, 20, 140);
+ CHECK_OBJECT_PROPS_MAX (child1, 5, 30, 20, 130);
+ CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 1);
+
+ fail_unless (ges_layer_remove_clip (layer, GES_CLIP (clip)));
+
+ gst_object_unref (child0);
+ gst_object_unref (child1);
+ gst_object_unref (effect);
+ }
+
+ gst_object_unref (timeline);
+
+ ges_deinit ();
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_children_properties_contain)
{
GESTimeline *timeline;
tcase_add_test (tc_chain, test_effects_priorities);
tcase_add_test (tc_chain, test_children_time_setters);
tcase_add_test (tc_chain, test_can_add_effect);
+ tcase_add_test (tc_chain, test_children_inpoint);
+ tcase_add_test (tc_chain, test_children_max_duration);
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);