auto-transition: select track directly
authorHenry Wilkes <hwilkes@igalia.com>
Mon, 6 Apr 2020 11:16:11 +0000 (12:16 +0100)
committerHenry Wilkes <hwilkes@igalia.com>
Wed, 8 Apr 2020 13:35:28 +0000 (14:35 +0100)
By-pass the select-tracks-for-object signal for auto-transitions since
their track element must land in the same track as the elements it is
the auto-transition for.

ges/ges-timeline.c
tests/check/ges/basic.c

index ef50a9b5c23cc90b9c4097975792f1a15bd8a89b..af1ce6e9d12f400035e81c84cbcab1c4547fdc30 100644 (file)
@@ -150,6 +150,8 @@ struct _GESTimelinePrivate
    * and %FALSE otherwize */
   gboolean needs_transitions_update;
 
+  GESTrack *auto_transition_track;
+
   /* While we are creating and adding the TrackElements for a clip, we need to
    * ignore the child-added signal */
   gboolean track_elements_moving;
@@ -344,6 +346,8 @@ ges_timeline_dispose (GObject * object)
   g_hash_table_unref (priv->all_elements);
   gst_object_unref (priv->stream_collection);
 
+  gst_clear_object (&priv->auto_transition_track);
+
   G_OBJECT_CLASS (ges_timeline_parent_class)->dispose (object);
 }
 
@@ -897,25 +901,46 @@ ges_timeline_create_transition (GESTimeline * timeline,
     GESTrackElement * previous, GESTrackElement * next, GESClip * transition,
     GESLayer * layer, guint64 start, guint64 duration)
 {
-  GESAsset *asset;
   GESAutoTransition *auto_transition;
+  GESTrackElement *child;
+  /* track should not be NULL */
+  GESTrack *track = ges_track_element_get_track (next);
 
   if (transition == NULL) {
-    /* TODO make it possible to specify a Transition asset in the API */
+    GESAsset *asset;
+
+    LOCK_DYN (timeline);
+    timeline->priv->auto_transition_track = gst_object_ref (track);
+    UNLOCK_DYN (timeline);
+
     asset = ges_asset_request (GES_TYPE_TRANSITION_CLIP, "crossfade", NULL);
-    transition =
-        ges_layer_add_asset (layer, asset, start, 0, duration,
+    transition = ges_layer_add_asset (layer, asset, start, 0, duration,
         ges_track_element_get_track_type (next));
-    g_object_unref (asset);
+    gst_object_unref (asset);
+
+    LOCK_DYN (timeline);
+    /* should have been set to NULL, but clear just in case */
+    gst_clear_object (&timeline->priv->auto_transition_track);
+    UNLOCK_DYN (timeline);
   } else {
     GST_DEBUG_OBJECT (timeline,
         "Reusing already existing transition: %" GST_PTR_FORMAT, transition);
   }
 
+  g_return_val_if_fail (transition, NULL);
+  g_return_val_if_fail (g_list_length (GES_CONTAINER_CHILDREN (transition)) ==
+      1, NULL);
+  child = GES_CONTAINER_CHILDREN (transition)->data;
+  if (ges_track_element_get_track (child) != track) {
+    GST_ERROR_OBJECT (timeline, "The auto transition element %"
+        GES_FORMAT " for elements %" GES_FORMAT " and %" GES_FORMAT
+        " is not in the same track %" GST_PTR_FORMAT,
+        GES_ARGS (child), GES_ARGS (previous), GES_ARGS (next), track);
+    return NULL;
+  }
+
   /* We know there is only 1 TrackElement */
-  auto_transition =
-      ges_auto_transition_new (GES_CONTAINER_CHILDREN (transition)->data,
-      previous, next);
+  auto_transition = ges_auto_transition_new (child, previous, next);
 
   g_signal_connect (auto_transition, "destroy-me",
       G_CALLBACK (_destroy_auto_transition_cb), timeline);
@@ -1515,6 +1540,7 @@ static void
 clip_track_element_added_cb (GESClip * clip,
     GESTrackElement * track_element, GESTimeline * timeline)
 {
+  GESTrack *auto_trans_track;
   gboolean error = FALSE;
 
   if (timeline->priv->track_elements_moving) {
@@ -1531,8 +1557,23 @@ clip_track_element_added_cb (GESClip * clip,
     return;
   }
 
-  if (!_add_track_element_to_tracks (timeline, clip, track_element))
-    error = TRUE;
+  LOCK_DYN (timeline);
+  /* take ownership of auto_transition_track. For auto-transitions, this
+   * should be used exactly once! */
+  auto_trans_track = timeline->priv->auto_transition_track;
+  timeline->priv->auto_transition_track = NULL;
+  UNLOCK_DYN (timeline);
+
+  if (auto_trans_track) {
+    /* don't use track-selection */
+    if (!ges_clip_add_child_to_track (clip, track_element, auto_trans_track,
+            NULL))
+      error = TRUE;
+    gst_object_unref (auto_trans_track);
+  } else {
+    if (!_add_track_element_to_tracks (timeline, clip, track_element))
+      error = TRUE;
+  }
 
   if (error)
     _set_track_selection_error (timeline, TRUE);
index b50f87bedd35ec0e0c74cfb7192c4965be335ad4..d6634714b5c92b20c99a5cbf5b22073be69bd0ab 100644 (file)
@@ -536,7 +536,7 @@ GST_START_TEST (test_ges_timeline_multiple_tracks)
   GESTimeline *timeline;
   GESLayer *layer;
   GESTrack *track1, *track2;
-  GESClip *s1, *s2, *s3, *s4;
+  GESClip *s1, *s2, *s3, *s4, *transition;
   GESTrackElement *e1, *e2, *e3, *el, *el2, *e_copy;
   gboolean found_e1 = FALSE, found_e2 = FALSE, found_e3 = FALSE;
   GList *trackelements, *tmp, *layers;
@@ -549,6 +549,7 @@ GST_START_TEST (test_ges_timeline_multiple_tracks)
   GST_DEBUG ("Create a timeline");
   timeline = ges_timeline_new ();
   fail_unless (timeline != NULL);
+  ges_timeline_set_auto_transition (timeline, TRUE);
 
   GST_DEBUG ("Create a layer");
   layer = ges_layer_new ();
@@ -578,7 +579,7 @@ GST_START_TEST (test_ges_timeline_multiple_tracks)
   /* s1 and s3 can overlap since they are destined for different tracks */
   /* s2 will overlap both */
   /* s4 destined for no track */
-  _CREATE_SOURCE (layer, s1, 0, 10);
+  _CREATE_SOURCE (layer, s1, 0, 12);
   _CREATE_SOURCE (layer, s2, 5, 10);
   _CREATE_SOURCE (layer, s3, 0, 10);
   _CREATE_SOURCE (layer, s4, 0, 20);
@@ -648,6 +649,8 @@ GST_START_TEST (test_ges_timeline_multiple_tracks)
   fail_unless (g_list_find (layers, layer) != NULL);
   g_list_free_full (layers, gst_object_unref);
 
+  fail_unless (ges_layer_get_auto_transition (layer));
+
   assert_equals_int (st_data.num_unrecognised, 0);
 
   /* Make sure the associated TrackElements are in the Track */
@@ -756,11 +759,49 @@ GST_START_TEST (test_ges_timeline_multiple_tracks)
   /* called once for source (where no track was selected) */
   assert_equals_int (st_data.num_calls[0], 1);
 
-  /* 2 sources + 2 effects */
-  assert_num_in_track (track1, 4);
-  assert_num_in_track (track2, 4);
+  /* 2 sources + 1 transition + 2 effects */
+  assert_num_in_track (track1, 5);
+  assert_num_in_track (track2, 5);
+
+  el = NULL;
+  trackelements = ges_track_get_elements (track1);
+  for (tmp = trackelements; tmp; tmp = tmp->next) {
+    if (GES_IS_VIDEO_TRANSITION (tmp->data)) {
+      fail_if (el);
+      el = tmp->data;
+    }
+  }
+  g_list_free_full (trackelements, gst_object_unref);
+  fail_unless (GES_IS_CLIP (GES_TIMELINE_ELEMENT_PARENT (el)));
+  transition = GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (el));
+  assert_layer (transition, layer);
+
+  CHECK_OBJECT_PROPS (transition, 5, 0, 7);
+  CHECK_OBJECT_PROPS (el, 5, 0, 7);
+  fail_unless (ges_track_element_get_track (el) == track1);
+  /* make sure we can change the transition type */
+  fail_unless (ges_video_transition_set_transition_type (GES_VIDEO_TRANSITION
+          (el), GES_VIDEO_STANDARD_TRANSITION_TYPE_BARNDOOR_H));
 
+  el = NULL;
+  trackelements = ges_track_get_elements (track2);
+  for (tmp = trackelements; tmp; tmp = tmp->next) {
+    if (GES_IS_VIDEO_TRANSITION (tmp->data)) {
+      fail_if (el);
+      el = tmp->data;
+    }
+  }
+  g_list_free_full (trackelements, gst_object_unref);
+  fail_unless (GES_IS_CLIP (GES_TIMELINE_ELEMENT_PARENT (el)));
+  transition = GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (el));
+  assert_layer (transition, layer);
 
+  CHECK_OBJECT_PROPS (transition, 5, 0, 5);
+  CHECK_OBJECT_PROPS (el, 5, 0, 5);
+  fail_unless (ges_track_element_get_track (el) == track2);
+  /* make sure we can change the transition type */
+  fail_unless (ges_video_transition_set_transition_type (GES_VIDEO_TRANSITION
+          (el), GES_VIDEO_STANDARD_TRANSITION_TYPE_BARNDOOR_H));
 
   gst_object_unref (timeline);