Port to the new NLE API
authorThibault Saunier <tsaunier@gnome.org>
Tue, 21 Oct 2014 08:59:43 +0000 (10:59 +0200)
committerThibault Saunier <tsaunier@gnome.org>
Fri, 31 Oct 2014 10:58:12 +0000 (11:58 +0100)
Port the timeline, track and pipeline to the new NLE API where
all objects have static src pads.

ges/ges-pipeline.c
ges/ges-timeline.c
ges/ges-track.c

index d66c590..dd4f1b3 100644 (file)
 #include "ges-audio-track.h"
 #include "ges-video-track.h"
 
+GST_DEBUG_CATEGORY_STATIC (ges_pipeline_debug);
+#undef GST_CAT_DEFAULT
+#define GST_CAT_DEFAULT ges_pipeline_debug
+
 #define DEFAULT_TIMELINE_MODE  GES_PIPELINE_MODE_PREVIEW
 
 /* Structure corresponding to a timeline - sink link */
@@ -48,8 +52,6 @@ typedef struct
   GstPad *srcpad;               /* Timeline source pad */
   GstPad *playsinkpad;
   GstPad *encodebinpad;
-  GstPad *blocked_pad;
-  gulong probe_id;
 } OutputChain;
 
 
@@ -88,6 +90,8 @@ static OutputChain *get_output_chain_for_track (GESPipeline * self,
     GESTrack * track);
 static OutputChain *new_output_chain_for_track (GESPipeline * self,
     GESTrack * track);
+static void _link_track (GESPipeline * self, GESTrack * track);
+static void _unlink_track (GESPipeline * self, GESTrack * track);
 
 /****************************************************
  *    Video Overlay vmethods implementation         *
@@ -234,6 +238,9 @@ ges_pipeline_class_init (GESPipelineClass * klass)
 
   g_type_class_add_private (klass, sizeof (GESPipelinePrivate));
 
+  GST_DEBUG_CATEGORY_INIT (ges_pipeline_debug, "gespipeline",
+      GST_DEBUG_FG_YELLOW, "ges pipeline");
+
   object_class->dispose = ges_pipeline_dispose;
   object_class->get_property = ges_pipeline_get_property;
   object_class->set_property = ges_pipeline_set_property;
@@ -434,6 +441,39 @@ done:
   return TRUE;
 }
 
+static void
+_link_tracks (GESPipeline * pipeline)
+{
+  GList *tmp;
+
+  GST_DEBUG_OBJECT (pipeline, "Linking tracks");
+
+  if (!pipeline->priv->timeline) {
+    GST_INFO_OBJECT (pipeline, "Not timeline set yet, doing nothing");
+
+    return;
+  }
+
+  for (tmp = pipeline->priv->timeline->tracks; tmp; tmp = tmp->next)
+    _link_track (pipeline, tmp->data);
+}
+
+static void
+_unlink_tracks (GESPipeline * pipeline)
+{
+  GList *tmp;
+
+  GST_DEBUG_OBJECT (pipeline, "Disconnecting all tracks");
+  if (!pipeline->priv->timeline) {
+    GST_INFO_OBJECT (pipeline, "Not timeline set yet, doing nothing");
+
+    return;
+  }
+
+  for (tmp = pipeline->priv->timeline->tracks; tmp; tmp = tmp->next)
+    _unlink_track (pipeline, tmp->data);
+}
+
 static GstStateChangeReturn
 ges_pipeline_change_state (GstElement * element, GstStateChange transition)
 {
@@ -453,12 +493,13 @@ ges_pipeline_change_state (GstElement * element, GstStateChange transition)
       if (self->priv->mode & (GES_PIPELINE_MODE_RENDER |
               GES_PIPELINE_MODE_SMART_RENDER))
         GST_DEBUG ("rendering => Updating pipeline caps");
+      /* Set caps on all tracks according to profile if present */
       if (!ges_pipeline_update_caps (self)) {
         GST_ERROR_OBJECT (element, "Error setting the caps for rendering");
         ret = GST_STATE_CHANGE_FAILURE;
         goto done;
       }
-      /* Set caps on all tracks according to profile if present */
+      _link_tracks (self);
       break;
     default:
       break;
@@ -468,6 +509,14 @@ ges_pipeline_change_state (GstElement * element, GstStateChange transition)
       GST_ELEMENT_CLASS (ges_pipeline_parent_class)->change_state
       (element, transition);
 
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      _unlink_tracks (self);
+      break;
+    default:
+      break;
+  }
+
 done:
   return ret;
 }
@@ -500,25 +549,21 @@ get_output_chain_for_track (GESPipeline * self, GESTrack * track)
 /* Fetches a compatible pad on the target element which isn't already
  * linked */
 static GstPad *
-get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
+get_compatible_unlinked_pad (GstElement * element, GESTrack * track)
 {
   GstPad *res = NULL;
   GstIterator *pads;
   gboolean done = FALSE;
-  GstCaps *srccaps;
+  const GstCaps *srccaps;
   GValue paditem = { 0, };
 
-  if (G_UNLIKELY (pad == NULL))
-    goto no_pad;
+  if (G_UNLIKELY (track == NULL))
+    goto no_track;
 
-  GST_DEBUG ("element : %s, pad %s:%s",
-      GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));
+  GST_DEBUG_OBJECT (element, " track %" GST_PTR_FORMAT, track);
 
-  if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
-    pads = gst_element_iterate_sink_pads (element);
-  else
-    pads = gst_element_iterate_src_pads (element);
-  srccaps = gst_pad_query_caps (pad, NULL);
+  pads = gst_element_iterate_sink_pads (element);
+  srccaps = ges_track_get_caps (track);
 
   GST_DEBUG ("srccaps %" GST_PTR_FORMAT, srccaps);
 
@@ -553,34 +598,27 @@ get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
   }
   g_value_reset (&paditem);
   gst_iterator_free (pads);
-  gst_caps_unref (srccaps);
 
   return res;
 
-no_pad:
+no_track:
   {
-    GST_ERROR ("No pad to check against");
+    GST_ERROR ("No track to check against");
     return NULL;
   }
 }
 
-static GstPadProbeReturn
-pad_blocked (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
-{
-  /* no nothing */
-  GST_DEBUG_OBJECT (pad, "blocked callback, blocked");
-  return GST_PAD_PROBE_OK;
-}
-
 static void
-pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
+_link_track (GESPipeline * self, GESTrack * track)
 {
+  GstPad *pad;
   OutputChain *chain;
-  GESTrack *track;
   GstPad *sinkpad;
   GstCaps *caps;
+  GstPadLinkReturn lret;
   gboolean reconfigured = FALSE;
 
+  pad = ges_timeline_get_pad_for_track (self->priv->timeline, track);
   caps = gst_pad_query_caps (pad, NULL);
 
   GST_DEBUG_OBJECT (self, "new pad %s:%s , caps:%" GST_PTR_FORMAT,
@@ -588,8 +626,6 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
 
   gst_caps_unref (caps);
 
-  track = ges_timeline_get_track_for_pad (self->priv->timeline, pad);
-
   if (G_UNLIKELY (!track)) {
     GST_WARNING_OBJECT (self, "Couldn't find coresponding track !");
     return;
@@ -613,15 +649,23 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
   if (!(chain = get_output_chain_for_track (self, track)))
     chain = new_output_chain_for_track (self, track);
   chain->srcpad = pad;
+  gst_object_unref (pad);
 
   /* Adding tee */
-  chain->tee = gst_element_factory_make ("tee", NULL);
-  gst_bin_add (GST_BIN_CAST (self), chain->tee);
-  gst_element_sync_state_with_parent (chain->tee);
+  if (!chain->tee) {
+    chain->tee = gst_element_factory_make ("tee", NULL);
+    gst_bin_add (GST_BIN_CAST (self), chain->tee);
+    gst_element_sync_state_with_parent (chain->tee);
+  }
 
   /* Linking pad to tee */
   sinkpad = gst_element_get_static_pad (chain->tee, "sink");
-  gst_pad_link_full (pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING);
+  lret = gst_pad_link (pad, sinkpad);
+  if (lret != GST_PAD_LINK_OK) {
+    GST_ERROR_OBJECT (self, "Could not link the tee (%i)", lret);
+    goto error;
+  }
+
   gst_object_unref (sinkpad);
 
   /* Connect playsink */
@@ -658,14 +702,10 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
     tmppad = gst_element_get_request_pad (chain->tee, "src_%u");
     if (G_UNLIKELY (gst_pad_link_full (tmppad, sinkpad,
                 GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) {
-      GST_ERROR_OBJECT (self, "Couldn't link track pad to playsink");
+      GST_ERROR_OBJECT (self, "Couldn't link track pad to encodebin");
       gst_object_unref (tmppad);
       goto error;
     }
-    chain->blocked_pad = tmppad;
-    GST_DEBUG_OBJECT (tmppad, "blocking pad");
-    chain->probe_id = gst_pad_add_probe (tmppad,
-        GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_blocked, NULL, NULL);
 
     GST_DEBUG ("Reconfiguring playsink");
 
@@ -685,7 +725,7 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
 
     if (!chain->encodebinpad) {
       /* Check for unused static pads */
-      sinkpad = get_compatible_unlinked_pad (self->priv->encodebin, pad);
+      sinkpad = get_compatible_unlinked_pad (self->priv->encodebin, track);
 
       if (sinkpad == NULL) {
         GstCaps *caps = gst_pad_query_caps (pad, NULL);
@@ -704,10 +744,9 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
     }
 
     tmppad = gst_element_get_request_pad (chain->tee, "src_%u");
-    if (G_UNLIKELY (gst_pad_link_full (tmppad,
-                chain->encodebinpad,
+    if (G_UNLIKELY (gst_pad_link_full (tmppad, chain->encodebinpad,
                 GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) {
-      GST_WARNING_OBJECT (self, "Couldn't link track pad to playsink");
+      GST_ERROR_OBJECT (self, "Couldn't link track pad to encodebin");
       goto error;
     }
     gst_object_unref (tmppad);
@@ -733,25 +772,19 @@ error:
 }
 
 static void
-pad_removed_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
+_unlink_track (GESPipeline * self, GESTrack * track)
 {
   OutputChain *chain;
-  GESTrack *track;
-  GstPad *peer;
-
-  GST_DEBUG_OBJECT (self, "pad removed %s:%s", GST_DEBUG_PAD_NAME (pad));
+  GstPad *pad, *peer;
 
-  if (G_UNLIKELY (!(track =
-              ges_timeline_get_track_for_pad (self->priv->timeline, pad)))) {
-    GST_WARNING_OBJECT (self, "Couldn't find coresponding track !");
-    return;
-  }
+  GST_DEBUG_OBJECT (self, "Unlinking removed %" GST_PTR_FORMAT, track);
 
   if (G_UNLIKELY (!(chain = get_output_chain_for_track (self, track)))) {
-    GST_DEBUG_OBJECT (self, "Pad wasn't used");
+    GST_DEBUG_OBJECT (self, "Track wasn't used");
     return;
   }
 
+  pad = ges_timeline_get_pad_for_track (self->priv->timeline, track);
   /* Unlink encodebin */
   if (chain->encodebinpad) {
     peer = gst_pad_get_peer (chain->encodebinpad);
@@ -771,14 +804,6 @@ pad_removed_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
     gst_object_unref (chain->playsinkpad);
   }
 
-  if (chain->blocked_pad) {
-    GST_DEBUG_OBJECT (chain->blocked_pad, "unblocking pad");
-    gst_pad_remove_probe (chain->blocked_pad, chain->probe_id);
-    gst_object_unref (chain->blocked_pad);
-    chain->blocked_pad = NULL;
-    chain->probe_id = 0;
-  }
-
   /* Unlike/remove tee */
   peer = gst_element_get_static_pad (chain->tee, "sink");
   gst_pad_unlink (pad, peer);
@@ -788,29 +813,11 @@ pad_removed_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
 
   self->priv->chains = g_list_remove (self->priv->chains, chain);
   g_free (chain);
+  gst_object_unref (pad);
 
   GST_DEBUG ("done");
 }
 
-static void
-no_more_pads_cb (GstElement * timeline, GESPipeline * self)
-{
-  GList *tmp;
-
-  GST_DEBUG ("received no-more-pads");
-  for (tmp = self->priv->chains; tmp; tmp = g_list_next (tmp)) {
-    OutputChain *chain = (OutputChain *) tmp->data;
-
-    if (chain->blocked_pad) {
-      GST_DEBUG_OBJECT (chain->blocked_pad, "unblocking pad");
-      gst_pad_remove_probe (chain->blocked_pad, chain->probe_id);
-      gst_object_unref (chain->blocked_pad);
-      chain->blocked_pad = NULL;
-      chain->probe_id = 0;
-    }
-  }
-}
-
 /**
  * ges_pipeline_set_timeline:
  * @pipeline: a #GESPipeline
@@ -826,6 +833,7 @@ no_more_pads_cb (GstElement * timeline, GESPipeline * self)
 gboolean
 ges_pipeline_set_timeline (GESPipeline * pipeline, GESTimeline * timeline)
 {
+
   g_return_val_if_fail (GES_IS_PIPELINE (pipeline), FALSE);
   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
   g_return_val_if_fail (pipeline->priv->timeline == NULL, FALSE);
@@ -838,13 +846,6 @@ ges_pipeline_set_timeline (GESPipeline * pipeline, GESTimeline * timeline)
   }
   pipeline->priv->timeline = timeline;
 
-  /* Connect to pipeline */
-  g_signal_connect (timeline, "pad-added", (GCallback) pad_added_cb, pipeline);
-  g_signal_connect (timeline, "pad-removed", (GCallback) pad_removed_cb,
-      pipeline);
-  g_signal_connect (timeline, "no-more-pads", (GCallback) no_more_pads_cb,
-      pipeline);
-
   /* FIXME Check if we should rollback if we can't sync state */
   gst_element_sync_state_with_parent (GST_ELEMENT (timeline));
 
index 686c9d2..5c221a3 100644 (file)
@@ -2400,18 +2400,17 @@ _pad_probe_cb (GstPad * mixer_pad, GstPadProbeInfo * info,
 }
 
 static void
-pad_added_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
+_ghost_track_srcpad (TrackPrivate * tr_priv)
 {
+  GstPad *pad;
   gchar *padname;
   gboolean no_more;
   GList *tmp;
+  GESTrack *track = tr_priv->track;
 
-  GST_DEBUG ("track:%p, pad:%s:%s", track, GST_DEBUG_PAD_NAME (pad));
+  pad = gst_element_get_static_pad (GST_ELEMENT (track), "src");
 
-  if (G_UNLIKELY (tr_priv->pad)) {
-    GST_WARNING ("We are already controlling a pad for this track");
-    return;
-  }
+  GST_DEBUG ("track:%p, pad:%s:%s", track, GST_DEBUG_PAD_NAME (pad));
 
   /* Remember the pad */
   LOCK_DYN (tr_priv->timeline);
@@ -2449,28 +2448,6 @@ pad_added_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
   UNLOCK_DYN (tr_priv->timeline);
 }
 
-static void
-pad_removed_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
-{
-  GST_DEBUG ("track:%p, pad:%s:%s", track, GST_DEBUG_PAD_NAME (pad));
-
-  if (G_UNLIKELY (tr_priv->pad != pad)) {
-    GST_WARNING ("Not the pad we're controlling");
-    return;
-  }
-
-  if (G_UNLIKELY (tr_priv->ghostpad == NULL)) {
-    GST_WARNING ("We don't have a ghostpad for this pad !");
-    return;
-  }
-
-  GST_DEBUG ("Removing ghostpad");
-  gst_pad_set_active (tr_priv->ghostpad, FALSE);
-  gst_element_remove_pad (GST_ELEMENT (tr_priv->timeline), tr_priv->ghostpad);
-  tr_priv->ghostpad = NULL;
-  tr_priv->pad = NULL;
-}
-
 gboolean
 timeline_add_element (GESTimeline * timeline, GESTimelineElement * element)
 {
@@ -2809,10 +2786,6 @@ ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
   UNLOCK_DYN (timeline);
   timeline->tracks = g_list_append (timeline->tracks, track);
 
-  /* Listen to pad-added/-removed */
-  g_signal_connect (track, "pad-added", (GCallback) pad_added_cb, tr_priv);
-  g_signal_connect (track, "pad-removed", (GCallback) pad_removed_cb, tr_priv);
-
   /* Inform the track that it's currently being used by ourself */
   ges_track_set_timeline (track, timeline);
 
@@ -2843,6 +2816,8 @@ ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
     g_list_free (objects);
   }
 
+  _ghost_track_srcpad (tr_priv);
+
   /* FIXME Check if we should rollback if we can't sync state */
   gst_element_sync_state_with_parent (GST_ELEMENT (track));
   g_object_set (track, "message-forward", TRUE, NULL);
@@ -2904,8 +2879,6 @@ ges_timeline_remove_track (GESTimeline * timeline, GESTrack * track)
   }
 
   /* Remove pad-added/-removed handlers */
-  g_signal_handlers_disconnect_by_func (track, pad_added_cb, tr_priv);
-  g_signal_handlers_disconnect_by_func (track, pad_removed_cb, tr_priv);
   g_signal_handlers_disconnect_by_func (track, track_element_added_cb,
       timeline);
   g_signal_handlers_disconnect_by_func (track, track_element_removed_cb,
index cb17037..6840fde 100644 (file)
 G_DEFINE_TYPE_WITH_CODE (GESTrack, ges_track, GST_TYPE_BIN,
     G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER, NULL));
 
+static GstStaticPadTemplate ges_track_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
 /* Structure that represents gaps and keep knowledge
  * of the gaps filled in the track */
 typedef struct
@@ -92,9 +98,6 @@ static guint ges_track_signals[LAST_SIGNAL] = { 0 };
 
 static GParamSpec *properties[ARG_LAST];
 
-static void pad_added_cb (GstElement * element, GstPad * pad, GESTrack * track);
-static void
-pad_removed_cb (GstElement * element, GstPad * pad, GESTrack * track);
 static void composition_duration_cb (GstElement * composition, GParamSpec * arg
     G_GNUC_UNUSED, GESTrack * obj);
 
@@ -256,9 +259,10 @@ sort_track_elements_cb (GESTrackElement * child,
 static void
 _ghost_nlecomposition_srcpad (GESTrack * track)
 {
-  GESTrackPrivate *priv = track->priv;
   GstPad *capsfilter_sink;
   GstPad *capsfilter_src;
+  GESTrackPrivate *priv = track->priv;
+  GstPad *pad = gst_element_get_static_pad (priv->composition, "src");
 
   capsfilter_sink = gst_element_get_static_pad (priv->capsfilter, "sink");
 
@@ -278,22 +282,6 @@ _ghost_nlecomposition_srcpad (GESTrack * track)
 }
 
 static void
-pad_removed_cb (GstElement * element, GstPad * pad, GESTrack * track)
-{
-  GESTrackPrivate *priv = track->priv;
-
-  GST_DEBUG ("track:%p, pad %s:%s", track, GST_DEBUG_PAD_NAME (pad));
-
-  if (G_LIKELY (priv->srcpad)) {
-    gst_pad_set_active (priv->srcpad, FALSE);
-    gst_element_remove_pad (GST_ELEMENT (track), priv->srcpad);
-    priv->srcpad = NULL;
-  }
-
-  GST_DEBUG ("done");
-}
-
-static void
 composition_duration_cb (GstElement * composition,
     GParamSpec * arg G_GNUC_UNUSED, GESTrack * track)
 {
@@ -423,6 +411,7 @@ ges_track_dispose (GObject * object)
 {
   GESTrack *track = (GESTrack *) object;
   GESTrackPrivate *priv = track->priv;
+  gboolean ret;
 
   /* Remove all TrackElements and drop our reference */
   g_hash_table_unref (priv->trackelements_iter);
@@ -430,11 +419,13 @@ ges_track_dispose (GObject * object)
       (GFunc) dispose_trackelements_foreach, track);
   g_sequence_free (priv->trackelements_by_start);
   g_list_free_full (priv->gaps, (GDestroyNotify) free_gap);
+  g_signal_emit_by_name (track->priv->composition, "commit", TRUE, &ret);
 
   if (priv->mixing_operation)
     gst_object_unref (priv->mixing_operation);
 
   if (priv->composition) {
+    gst_element_remove_pad (GST_ELEMENT (track), priv->srcpad);
     gst_bin_remove (GST_BIN (object), priv->composition);
     priv->composition = NULL;
   }
@@ -508,6 +499,7 @@ static void
 ges_track_class_init (GESTrackClass * klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
 
   g_type_class_add_private (klass, sizeof (GESTrackPrivate));
 
@@ -586,6 +578,9 @@ ges_track_class_init (GESTrackClass * klass)
   g_object_class_install_property (object_class, ARG_MIXING,
       properties[ARG_MIXING]);
 
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&ges_track_src_pad_template));
+
   /**
    * GESTrack::track-element-added:
    * @object: the #GESTrack
@@ -632,10 +627,6 @@ ges_track_init (GESTrack * self)
 
   g_signal_connect (G_OBJECT (self->priv->composition), "notify::duration",
       G_CALLBACK (composition_duration_cb), self);
-  g_signal_connect (self->priv->composition, "pad-added",
-      (GCallback) pad_added_cb, self);
-  g_signal_connect (self->priv->composition, "pad-removed",
-      (GCallback) pad_removed_cb, self);
 }
 
 /**