clip: allow arbitrary max-duration when no core children
authorHenry Wilkes <hwilkes@igalia.com>
Wed, 25 Mar 2020 19:35:11 +0000 (19:35 +0000)
committerHenry Wilkes <hwilkes@igalia.com>
Tue, 7 Apr 2020 10:17:54 +0000 (11:17 +0100)
Before the max-duration could be set arbitrarily when the clip was empty,
to indicate what the max-duration would be once the core children were
created. Now, we can also do this whilst the clip only contains non-core
children.

ges/ges-clip.c
ges/ges-uri-clip.c
tests/check/ges/clip.c

index 9bc86a31ee8baab6405f97225373984394810830..7e6c2951609ce616257f885c6d5cbd580d6c353e 100644 (file)
  * The #GESTimelineElement:in-point of the clip will control the
  * #GESTimelineElement:in-point of these core elements to be the same
  * 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.
+ * As a special case, whilst a clip does not yet have any core children,
+ * its #GESTimelineElement:max-duration may be set to indicate what its
+ * value will be once they are created.
  *
  * ## Effects
  *
@@ -397,41 +401,45 @@ _set_max_duration (GESTimelineElement * element, GstClockTime maxduration)
   GList *tmp;
   GESClipPrivate *priv = GES_CLIP (element)->priv;
   GstClockTime new_min = GST_CLOCK_TIME_NONE;
+  gboolean has_core = FALSE;
 
   /* if we are setting based on a change in the minimum */
   if (priv->updating_max_duration)
     return TRUE;
 
-  if (!GES_CONTAINER_CHILDREN (element)) {
-    /* If any child added later on has a lower max duration, this max duration
-     * will be used instead anyway */
-    GST_INFO_OBJECT (element,
-        "Setting max duration %" GST_TIME_FORMAT " as %" GES_FORMAT
-        " doesn't have any child yet",
-        GST_TIME_ARGS (maxduration), GES_ARGS (element));
-    return TRUE;
-  }
-
   /* else, we set every core child to have the same max duration */
 
   priv->prevent_max_duration_update = TRUE;
   for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
     GESTimelineElement *child = tmp->data;
 
-    if (_IS_CORE_INTERNAL_SOURCE_CHILD (child)) {
-      if (!ges_timeline_element_set_max_duration (child, maxduration)) {
-        GST_ERROR_OBJECT ("Could not set the max-duration of child %"
-            GES_FORMAT " to %" GST_TIME_FORMAT, GES_ARGS (child),
-            GST_TIME_ARGS (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;
+    if (_IS_CORE_CHILD (child)) {
+      has_core = TRUE;
+      if (ges_track_element_has_internal_source (GES_TRACK_ELEMENT (child))) {
+        if (!ges_timeline_element_set_max_duration (child, maxduration))
+          GST_ERROR_OBJECT ("Could not set the max-duration of child %"
+              GES_FORMAT " to %" GST_TIME_FORMAT, GES_ARGS (child),
+              GST_TIME_ARGS (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 (!has_core) {
+    /* allow max-duration to be set arbitrarily when we have no
+     * core children, even though there is no actual minimum max-duration
+     * when it has no core children */
+    if (GST_CLOCK_TIME_IS_VALID (maxduration))
+      GST_INFO_OBJECT (element,
+          "Allowing max-duration of the clip to be set to %" GST_TIME_FORMAT
+          " because it has no core children", GST_TIME_ARGS (maxduration));
+    return TRUE;
+  }
+
   if (new_min != maxduration) {
     if (GST_CLOCK_TIME_IS_VALID (new_min))
       GST_WARNING_OBJECT (element, "Failed to set the max-duration of the "
@@ -703,7 +711,9 @@ _child_added (GESContainer * container, GESTimelineElement * element)
       G_CALLBACK (_child_has_internal_source_changed_cb), container);
 
   _child_priority_changed_cb (element, NULL, container);
-  _update_max_duration (container);
+
+  if (_IS_CORE_CHILD (element))
+    _update_max_duration (container);
 }
 
 static void
@@ -718,7 +728,8 @@ _child_removed (GESContainer * container, GESTimelineElement * element)
   g_signal_handlers_disconnect_by_func (element,
       _child_has_internal_source_changed_cb, container);
 
-  _update_max_duration (container);
+  if (_IS_CORE_CHILD (element))
+    _update_max_duration (container);
 }
 
 static void
index 39a6d7033fcbca654071903eadb325d2549d637b..7b0a535fc461def62d326c2a24f7d3ff380eb569 100644 (file)
@@ -227,12 +227,12 @@ extractable_get_id (GESExtractable * self)
 static gboolean
 extractable_set_asset (GESExtractable * self, GESAsset * asset)
 {
-  gboolean res = TRUE;
+  gboolean res = TRUE, contains_core;
   GESUriClip *uriclip = GES_URI_CLIP (self);
   GESUriClipAsset *uri_clip_asset;
   GESClip *clip = GES_CLIP (self);
   GESLayer *layer = ges_clip_get_layer (clip);
-  GList *tmp;
+  GList *tmp, *children;
   GESTimelineElement *audio_source = NULL, *video_source = NULL;
 
   g_return_val_if_fail (GES_IS_URI_CLIP_ASSET (asset), FALSE);
@@ -270,24 +270,26 @@ extractable_set_asset (GESExtractable * self, GESAsset * asset)
 
   GES_TIMELINE_ELEMENT (uriclip)->asset = asset;
 
-  if (layer) {
-    GList *children = ges_container_get_children (GES_CONTAINER (self), TRUE);
+  children = ges_container_get_children (GES_CONTAINER (self), TRUE);
 
-    for (tmp = children; tmp; tmp = tmp->next) {
-      if (GES_IS_SOURCE (tmp->data)) {
-        GESTrack *track = ges_track_element_get_track (tmp->data);
+  for (tmp = children; tmp; tmp = tmp->next) {
+    if (GES_IS_SOURCE (tmp->data)) {
+      GESTrack *track = ges_track_element_get_track (tmp->data);
 
-        if (track->type == GES_TRACK_TYPE_AUDIO)
-          audio_source = gst_object_ref (tmp->data);
-        else if (track->type == GES_TRACK_TYPE_VIDEO)
-          video_source = gst_object_ref (tmp->data);
+      if (track->type == GES_TRACK_TYPE_AUDIO)
+        audio_source = gst_object_ref (tmp->data);
+      else if (track->type == GES_TRACK_TYPE_VIDEO)
+        video_source = gst_object_ref (tmp->data);
 
-        ges_track_remove_element (track, tmp->data);
-        ges_container_remove (GES_CONTAINER (self), tmp->data);
-      }
+      ges_track_remove_element (track, tmp->data);
+      ges_container_remove (GES_CONTAINER (self), tmp->data);
     }
-    g_list_free_full (children, g_object_unref);
+  }
+  g_list_free_full (children, g_object_unref);
+
+  contains_core = FALSE;
 
+  if (layer) {
     gst_object_ref (clip);
 
     ges_layer_remove_clip (layer, clip);
@@ -296,6 +298,7 @@ extractable_set_asset (GESExtractable * self, GESAsset * asset)
     for (tmp = GES_CONTAINER_CHILDREN (self); tmp; tmp = tmp->next) {
       if (GES_IS_SOURCE (tmp->data)) {
         GESTrack *track = ges_track_element_get_track (tmp->data);
+        contains_core = TRUE;
 
         if (track->type == GES_TRACK_TYPE_AUDIO && audio_source) {
           ges_track_element_copy_properties (audio_source, tmp->data);
@@ -308,19 +311,18 @@ extractable_set_asset (GESExtractable * self, GESAsset * asset)
         }
       }
     }
-
-    g_clear_object (&audio_source);
-    g_clear_object (&video_source);
     gst_object_unref (clip);
     gst_object_unref (layer);
   }
+  g_clear_object (&audio_source);
+  g_clear_object (&video_source);
 
   if (res) {
     g_free (uriclip->priv->uri);
     uriclip->priv->uri = g_strdup (ges_asset_get_id (asset));
   }
 
-  if (!GES_CONTAINER_CHILDREN (uriclip))
+  if (!contains_core)
     ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (uriclip),
         ges_uri_clip_asset_get_max_duration (uri_clip_asset));
 
index 2d9252dd5ba12c9f17d5c091d0948bca80dd786c..c231b11a4a34a22d34c85f5678f8a5d246b5897a 100644 (file)
@@ -1083,20 +1083,61 @@ GST_START_TEST (test_children_max_duration)
     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 the max duration the clip has no child */
+
+    /* can set the max duration the clip to anything whilst it has
+     * no core child */
     fail_unless (ges_timeline_element_set_max_duration (clip, 150));
 
     CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 150);
 
+    /* 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, 400));
+
+    /* 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, 150);
+    CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
+
+    /* only non-core, so can still set the max-duration */
+    fail_unless (ges_timeline_element_set_max_duration (clip, 200));
+
+    CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 200);
+    CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
+
+    /* removing should not change the max-duration we set on the clip */
+    gst_object_ref (effect);
+    fail_unless (ges_container_remove (GES_CONTAINER (clip), effect));
+
+    CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 200);
+    CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
+
+    fail_unless (ges_container_add (GES_CONTAINER (clip), effect));
+    gst_object_unref (effect);
+
+    CHECK_OBJECT_PROPS_MAX (clip, 5, 30, 20, 200);
+    CHECK_OBJECT_PROPS_MAX (effect, 5, 0, 20, 400);
+
+    /* now add to a layer to create the core children */
     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 (GES_TIMELINE_ELEMENT (children->data) == effect);
     fail_unless (children->next);
-    child1 = children->next->data;
-    fail_unless (children->next->next == NULL);
+    child0 = children->next->data;
+    fail_unless (children->next->next);
+    child1 = children->next->next->data;
+    fail_unless (children->next->next->next == NULL);
 
     fail_unless (ges_track_element_has_internal_source (GES_TRACK_ELEMENT
             (child0)));
@@ -1114,25 +1155,6 @@ GST_START_TEST (test_children_max_duration)
     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, 400));
-
-    /* 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, 400);
 
     /* when setting max_duration of core children, clip will take the