clip: re-handle child in-point and max-duration
authorHenry Wilkes <hwilkes@igalia.com>
Tue, 10 Mar 2020 11:38:58 +0000 (11:38 +0000)
committerHenry Wilkes <hwilkes@igalia.com>
Mon, 16 Mar 2020 14:19:52 +0000 (14:19 +0000)
The in-point of a clip is kept in sync with its core children, unless they
have no has-internal-source.

The max-duration is defined as the minimum max-duration amongst the
clip's core children. If it is set to a new value, this sets the
max-duration of its core children to the same value if they have
has-internal-source set as TRUE.

Non-core children (such as effects on a source clip) do not influence
these values.

As part of this, we no longer track in-point in GESContainer. Unlike start
and duration, the in-point of a timeline element does not refer to its
extent in the timeline. As such, it has little meaning for most
collections of timeline-elements, in particular GESGroups. As such, there
is no generic way to relate the in-point of a container to its children.

ges/ges-clip.c
ges/ges-container.c
ges/ges-transition-clip.c
ges/ges-uri-clip.c
tests/check/ges/clip.c
tests/check/ges/overlays.c
tests/check/ges/test-utils.h
tests/check/ges/titles.c
tests/check/ges/transition.c

index 533ab22..11b58ee 100644 (file)
  *
  * 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
  *
@@ -100,6 +105,10 @@ struct _GESClipPrivate
   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;
 };
@@ -178,6 +187,81 @@ _child_priority_changed_cb (GESTimelineElement * child,
   }
 }
 
+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 *
@@ -211,22 +295,18 @@ _set_start (GESTimelineElement * element, GstClockTime start)
 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;
 }
@@ -260,10 +340,46 @@ static gboolean
 _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;
 }
@@ -384,7 +500,8 @@ _add_child (GESContainer * container, GESTimelineElement * element)
 
     /* 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;
@@ -471,11 +588,17 @@ _remove_child (GESContainer * container, GESTimelineElement * element)
 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
@@ -483,6 +606,14 @@ _child_removed (GESContainer * container, GESTimelineElement * element)
 {
   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
@@ -928,9 +1059,15 @@ ges_clip_class_init (GESClipClass * klass)
 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;
 }
 
 /**
@@ -1061,12 +1198,6 @@ ges_clip_create_track_elements (GESClip * clip, GESTrackType type)
     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);
   }
@@ -1583,6 +1714,9 @@ ges_clip_split (GESClip * clip, guint64 position)
       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),
index d6b2487..cf093b2 100644 (file)
@@ -58,12 +58,10 @@ typedef struct
 
   GstClockTime start_offset;
   GstClockTime duration_offset;
-  GstClockTime inpoint_offset;
   gint32 priority_offset;
 
   gulong start_notifyid;
   gulong duration_notifyid;
-  gulong inpoint_notifyid;
   gulong child_property_added_notifyid;
   gulong child_property_removed_notifyid;
 } ChildMapping;
@@ -120,8 +118,6 @@ _free_mapping (ChildMapping * mapping)
     g_signal_handler_disconnect (child, mapping->start_notifyid);
   if (mapping->duration_notifyid)
     g_signal_handler_disconnect (child, mapping->duration_notifyid);
-  if (mapping->inpoint_notifyid)
-    g_signal_handler_disconnect (child, mapping->inpoint_notifyid);
   if (mapping->child_property_added_notifyid)
     g_signal_handler_disconnect (child, mapping->child_property_added_notifyid);
   if (mapping->child_property_removed_notifyid)
@@ -187,22 +183,6 @@ _set_start (GESTimelineElement * element, GstClockTime start)
 }
 
 static gboolean
-_set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
-{
-  GList *tmp;
-  GESContainer *container = GES_CONTAINER (element);
-
-  for (tmp = container->children; tmp; tmp = g_list_next (tmp)) {
-    GESTimelineElement *child = (GESTimelineElement *) tmp->data;
-    ChildMapping *map = g_hash_table_lookup (container->priv->mappings, child);
-
-    map->inpoint_offset = inpoint - _INPOINT (child);
-  }
-
-  return TRUE;
-}
-
-static gboolean
 _set_duration (GESTimelineElement * element, GstClockTime duration)
 {
   GList *tmp;
@@ -369,7 +349,6 @@ _deep_copy (GESTimelineElement * element, GESTimelineElement * copy)
             tmp->data));
     map->child = ges_timeline_element_copy (tmp->data, TRUE);
     map->start_notifyid = 0;
-    map->inpoint_notifyid = 0;
     map->duration_notifyid = 0;
 
     ccopy->priv->copied_children = g_list_prepend (ccopy->priv->copied_children,
@@ -532,7 +511,6 @@ ges_container_class_init (GESContainerClass * klass)
 
   element_class->set_start = _set_start;
   element_class->set_duration = _set_duration;
-  element_class->set_inpoint = _set_inpoint;
   element_class->lookup_child = _lookup_child;
   element_class->get_track_types = _get_track_types;
   element_class->paste = _paste;
@@ -626,34 +604,6 @@ _child_start_changed_cb (GESTimelineElement * child,
 }
 
 static void
-_child_inpoint_changed_cb (GESTimelineElement * child,
-    GParamSpec * arg G_GNUC_UNUSED, GESContainer * container)
-{
-  ChildMapping *map;
-
-  GESContainerPrivate *priv = container->priv;
-  GESTimelineElement *element = GES_TIMELINE_ELEMENT (container);
-
-  if (container->children_control_mode == GES_CHILDREN_IGNORE_NOTIFIES)
-    return;
-
-  map = g_hash_table_lookup (priv->mappings, child);
-  g_assert (map);
-
-  if (container->children_control_mode == GES_CHILDREN_UPDATE_OFFSETS
-      || ELEMENT_FLAG_IS_SET (child, GES_TIMELINE_ELEMENT_SET_SIMPLE)) {
-    map->inpoint_offset = _INPOINT (container) - _INPOINT (child);
-
-    return;
-  }
-
-  /* We update all the children calling our set_inpoint method */
-  container->initiated_move = child;
-  _set_inpoint0 (element, _INPOINT (child) + map->inpoint_offset);
-  container->initiated_move = NULL;
-}
-
-static void
 _child_duration_changed_cb (GESTimelineElement * child,
     GParamSpec * arg G_GNUC_UNUSED, GESContainer * container)
 {
@@ -838,7 +788,6 @@ ges_container_add (GESContainer * container, GESTimelineElement * child)
   mapping->child = gst_object_ref (child);
   mapping->start_offset = _START (container) - _START (child);
   mapping->duration_offset = _DURATION (container) - _DURATION (child);
-  mapping->inpoint_offset = _INPOINT (container) - _INPOINT (child);
 
   g_hash_table_insert (priv->mappings, child, mapping);
 
@@ -853,9 +802,6 @@ ges_container_add (GESContainer * container, GESTimelineElement * child)
   mapping->duration_notifyid =
       g_signal_connect (G_OBJECT (child), "notify::duration",
       G_CALLBACK (_child_duration_changed_cb), container);
-  mapping->inpoint_notifyid =
-      g_signal_connect (G_OBJECT (child), "notify::in-point",
-      G_CALLBACK (_child_inpoint_changed_cb), container);
 
   if (ges_timeline_element_set_parent (child, GES_TIMELINE_ELEMENT (container))
       == FALSE) {
index d0fb494..3da69e1 100644 (file)
@@ -303,6 +303,9 @@ _child_removed (GESContainer * container, GESTimelineElement * element)
     priv->video_transitions = g_slist_remove (priv->video_transitions, element);
     gst_object_unref (element);
   }
+  /* call parent method */
+  GES_CONTAINER_CLASS (ges_transition_clip_parent_class)->child_removed
+      (container, element);
 }
 
 static void
@@ -322,6 +325,9 @@ _child_added (GESContainer * container, GESTimelineElement * element)
     ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT (container),
         g_object_class_find_property (eklass, "border"), G_OBJECT (element));
   }
+  /* call parent method */
+  GES_CONTAINER_CLASS (ges_transition_clip_parent_class)->child_added
+      (container, element);
 }
 
 static GESTrackElement *
index 8ec8085..de704d8 100644 (file)
@@ -302,8 +302,6 @@ extractable_set_asset (GESExtractable * self, GESAsset * asset)
     _set_duration0 (GES_TIMELINE_ELEMENT (uriclip),
         ges_uri_clip_asset_get_duration (uri_clip_asset));
 
-  ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (uriclip),
-      ges_uri_clip_asset_get_max_duration (uri_clip_asset));
   ges_uri_clip_set_is_image (uriclip,
       ges_uri_clip_asset_is_image (uri_clip_asset));
 
@@ -421,6 +419,7 @@ uri_clip_set_max_duration (GESTimelineElement * element,
 {
   if (_DURATION (element) == GST_CLOCK_TIME_NONE || _DURATION (element) == 0)
     /* If we don't have a valid duration, use the max duration */
+    /* FIXME: don't do this when we have time effects */
     _set_duration0 (element, maxduration - _INPOINT (element));
 
   return
@@ -488,17 +487,28 @@ ges_uri_clip_create_track_elements (GESClip * clip, GESTrackType type)
 {
   GList *res = NULL;
   const GList *tmp, *stream_assets;
+  GESAsset *asset = GES_TIMELINE_ELEMENT (clip)->asset;
+  GESUriClipAsset *uri_asset;
+  GstClockTime max_duration;
 
-  g_return_val_if_fail (GES_TIMELINE_ELEMENT (clip)->asset, NULL);
+  g_return_val_if_fail (asset, NULL);
 
-  stream_assets =
-      ges_uri_clip_asset_get_stream_assets (GES_URI_CLIP_ASSET
-      (GES_TIMELINE_ELEMENT (clip)->asset));
-  for (tmp = stream_assets; tmp; tmp = tmp->next) {
-    GESTrackElementAsset *asset = GES_TRACK_ELEMENT_ASSET (tmp->data);
+  uri_asset = GES_URI_CLIP_ASSET (asset);
+
+  max_duration = ges_uri_clip_asset_get_max_duration (uri_asset);
+  stream_assets = ges_uri_clip_asset_get_stream_assets (uri_asset);
 
-    if (ges_track_element_asset_get_track_type (asset) == type)
-      res = g_list_prepend (res, ges_asset_extract (GES_ASSET (asset), NULL));
+  for (tmp = stream_assets; tmp; tmp = tmp->next) {
+    GESTrackElementAsset *element_asset = GES_TRACK_ELEMENT_ASSET (tmp->data);
+
+    if (ges_track_element_asset_get_track_type (element_asset) == type) {
+      GESTrackElement *element =
+          GES_TRACK_ELEMENT (ges_asset_extract (GES_ASSET (element_asset),
+              NULL));
+      ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (element),
+          max_duration);
+      res = g_list_prepend (res, element);
+    }
   }
 
   return res;
index 3a4f1ee..0cc00cc 100644 (file)
@@ -792,19 +792,8 @@ _count_cb (GObject * obj, GParamSpec * pspec, gint * count)
 }
 
 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",
@@ -842,14 +831,16 @@ GST_START_TEST (test_children_time_setters)
     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));
@@ -861,7 +852,8 @@ GST_START_TEST (test_children_time_setters)
     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);
   }
@@ -926,6 +918,376 @@ GST_START_TEST (test_can_add_effect)
 
 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;
@@ -1444,6 +1806,8 @@ ges_suite (void)
   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);
index a9b041b..b169e41 100644 (file)
@@ -79,10 +79,11 @@ GST_START_TEST (test_overlay_properties)
   /* Check that trackelement has the same properties */
   assert_equals_uint64 (_START (trackelement), 42);
   assert_equals_uint64 (_DURATION (trackelement), 51);
-  assert_equals_uint64 (_INPOINT (trackelement), 12);
+  /* in-point is 0 since it does not have has-internal-source */
+  assert_equals_uint64 (_INPOINT (trackelement), 0);
 
   /* And let's also check that it propagated correctly to GNonLin */
-  nle_object_check (ges_track_element_get_nleobject (trackelement), 42, 51, 12,
+  nle_object_check (ges_track_element_get_nleobject (trackelement), 42, 51, 0,
       51, MIN_NLE_PRIO + TRANSITIONS_HEIGHT, TRUE);
 
   /* Change more properties, see if they propagate */
@@ -94,11 +95,11 @@ GST_START_TEST (test_overlay_properties)
   assert_equals_uint64 (_INPOINT (clip), 120);
   assert_equals_uint64 (_START (trackelement), 420);
   assert_equals_uint64 (_DURATION (trackelement), 510);
-  assert_equals_uint64 (_INPOINT (trackelement), 120);
+  assert_equals_uint64 (_INPOINT (trackelement), 0);
 
   /* And let's also check that it propagated correctly to GNonLin */
   nle_object_check (ges_track_element_get_nleobject (trackelement), 420, 510,
-      120, 510, MIN_NLE_PRIO + TRANSITIONS_HEIGHT + 0, TRUE);
+      0, 510, MIN_NLE_PRIO + TRANSITIONS_HEIGHT + 0, TRUE);
 
   ges_container_remove (GES_CONTAINER (clip),
       GES_TIMELINE_ELEMENT (trackelement));
index 3f426f4..d98b4fb 100644 (file)
@@ -88,6 +88,7 @@ G_STMT_START {                                          \
 #define _START(obj) GES_TIMELINE_ELEMENT_START (obj)
 #define _DURATION(obj) GES_TIMELINE_ELEMENT_DURATION (obj)
 #define _INPOINT(obj) GES_TIMELINE_ELEMENT_INPOINT (obj)
+#define _MAX_DURATION(obj) GES_TIMELINE_ELEMENT_MAX_DURATION (obj)
 #define _PRIORITY(obj) GES_TIMELINE_ELEMENT_PRIORITY (obj)
 #ifndef _END
 #define _END(obj) (_START(obj) + _DURATION(obj))
@@ -99,6 +100,14 @@ G_STMT_START {                                          \
   fail_unless (_DURATION (obj) == duration, "%s duration is %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, GES_TIMELINE_ELEMENT_NAME(obj), GST_TIME_ARGS (_DURATION(obj)), GST_TIME_ARGS (duration));\
 }
 
+#define CHECK_OBJECT_PROPS_MAX(obj, start, inpoint, duration, max_duration) {\
+  CHECK_OBJECT_PROPS (obj, start, inpoint, duration); \
+  fail_unless (_MAX_DURATION(obj) == max_duration, "%s max-duration is " \
+      "%" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, \
+      GES_TIMELINE_ELEMENT_NAME(obj), \
+      GST_TIME_ARGS (_MAX_DURATION(obj)), GST_TIME_ARGS (max_duration)); \
+}
+
 /* assert that the time property (start, duration or in-point) is the
  * same as @cmp for the clip and all its children */
 #define assert_clip_children_time_val(clip, property, cmp) \
@@ -106,6 +115,7 @@ G_STMT_START {                                          \
   GList *tmp; \
   GstClockTime read_val; \
   gchar *name = GES_TIMELINE_ELEMENT (clip)->name; \
+  gboolean is_inpoint = (g_strcmp0 (property, "in-point") == 0); \
   g_object_get (clip, property, &read_val, NULL); \
   fail_unless (read_val == cmp, "The %s property for clip %s is %" \
       GST_TIME_FORMAT ", rather than the expected value of %" \
@@ -115,10 +125,16 @@ G_STMT_START {                                          \
       tmp = tmp->next) { \
     GESTimelineElement *child = tmp->data; \
     g_object_get (child, property, &read_val, NULL); \
-    fail_unless (read_val == cmp, "The %s property for the child %s " \
-        "of clip %s is %" GST_TIME_FORMAT ", rather than the expected " \
-        "value of %" GST_TIME_FORMAT, property, child->name, name, \
-        GST_TIME_ARGS (read_val), GST_TIME_ARGS (cmp)); \
+    if (!is_inpoint || ges_track_element_has_internal_source ( \
+          GES_TRACK_ELEMENT (child))) \
+      fail_unless (read_val == cmp, "The %s property for the child %s " \
+          "of clip %s is %" GST_TIME_FORMAT ", rather than the expected" \
+          " value of %" GST_TIME_FORMAT, property, child->name, name, \
+          GST_TIME_ARGS (read_val), GST_TIME_ARGS (cmp)); \
+    else \
+      fail_unless (read_val == 0, "The %s property for the child %s " \
+          "of clip %s is %" GST_TIME_FORMAT ", rather than 0", \
+          property, child->name, name, GST_TIME_ARGS (read_val)); \
   } \
 }
 
index b9bf4a6..e5b19df 100644 (file)
@@ -65,7 +65,10 @@ GST_START_TEST (test_title_source_properties)
       "in-point", (guint64) 12, NULL);
   assert_equals_uint64 (_START (clip), 42);
   assert_equals_uint64 (_DURATION (clip), 51);
-  assert_equals_uint64 (_INPOINT (clip), 0);
+  /* the clip can have a non-zero in-point, but this won't affect any
+   * of the core children because they have their has-internal-source set
+   * to FALSE */
+  assert_equals_uint64 (_INPOINT (clip), 12);
 
   ges_layer_add_clip (layer, GES_CLIP (clip));
   ges_timeline_commit (timeline);
@@ -91,7 +94,7 @@ GST_START_TEST (test_title_source_properties)
   ges_timeline_commit (timeline);
   assert_equals_uint64 (_START (clip), 420);
   assert_equals_uint64 (_DURATION (clip), 510);
-  assert_equals_uint64 (_INPOINT (clip), 0);
+  assert_equals_uint64 (_INPOINT (clip), 120);
   assert_equals_uint64 (_START (trackelement), 420);
   assert_equals_uint64 (_DURATION (trackelement), 510);
   assert_equals_uint64 (_INPOINT (trackelement), 0);
index 9c826d4..16b2880 100644 (file)
@@ -109,10 +109,11 @@ GST_START_TEST (test_transition_properties)
   /* Check that trackelement has the same properties */
   assert_equals_uint64 (_START (trackelement), 42);
   assert_equals_uint64 (_DURATION (trackelement), 51);
-  assert_equals_uint64 (_INPOINT (trackelement), 12);
+  /* in-point is 0 since it does not have has-internal-source */
+  assert_equals_uint64 (_INPOINT (trackelement), 0);
 
   /* And let's also check that it propagated correctly to GNonLin */
-  nle_object_check (ges_track_element_get_nleobject (trackelement), 42, 51, 12,
+  nle_object_check (ges_track_element_get_nleobject (trackelement), 42, 51, 0,
       51, MIN_NLE_PRIO, TRUE);
 
   /* Change more properties, see if they propagate */
@@ -124,11 +125,11 @@ GST_START_TEST (test_transition_properties)
   assert_equals_uint64 (_INPOINT (clip), 120);
   assert_equals_uint64 (_START (trackelement), 420);
   assert_equals_uint64 (_DURATION (trackelement), 510);
-  assert_equals_uint64 (_INPOINT (trackelement), 120);
+  assert_equals_uint64 (_INPOINT (trackelement), 0);
 
   /* And let's also check that it propagated correctly to GNonLin */
   nle_object_check (ges_track_element_get_nleobject (trackelement), 420, 510,
-      120, 510, MIN_NLE_PRIO + 0, TRUE);
+      0, 510, MIN_NLE_PRIO + 0, TRUE);
 
   /* test changing vtype */
   GST_DEBUG ("Setting to crossfade");