gnl: Add the srcpad directly to GnlObject
authorMathieu Duponchelle <mathieu.duponchelle@opencreed.com>
Tue, 24 Jun 2014 11:44:13 +0000 (13:44 +0200)
committerThibault Saunier <tsaunier@gnome.org>
Fri, 31 Oct 2014 10:58:07 +0000 (11:58 +0100)
Starting from now we will not claim that we support GnlObject that have
several source pads as this is
1- Not true at all;
2- the design of priorities in the GnlComposition tree does not allow that;
3- Not very useful in most of the cases and it complexifies quite a lot the code
   in the composition.

Conflicts:
configure.ac
tests/check/Makefile.am

14 files changed:
gnl/gnlcomposition.c
gnl/gnlghostpad.c
gnl/gnlghostpad.h
gnl/gnlobject.c
gnl/gnlobject.h
gnl/gnloperation.c
gnl/gnloperation.h
gnl/gnlsource.c
tests/check/gnl/complex.c
tests/check/gnl/gnlcomposition.c
tests/check/gnl/gnloperation.c
tests/check/gnl/gnlsource.c
tests/check/gnl/seek.c
tests/check/gnl/simple.c

index d9a0877..179bf29 100644 (file)
@@ -34,7 +34,7 @@
 static GstStaticPadTemplate gnl_composition_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
-    GST_PAD_SOMETIMES,
+    GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
 GST_DEBUG_CATEGORY_STATIC (gnlcomposition_debug);
@@ -96,7 +96,6 @@ struct _GnlCompositionPrivate
   gboolean flushing;
 
   /* source top-level ghostpad, probe and entry */
-  GstPad *ghostpad;
   gulong ghosteventprobe;
   GnlCompositionEntry *toplevelentry;
 
@@ -120,9 +119,6 @@ struct _GnlCompositionPrivate
   GstClockTime segment_start;
   GstClockTime segment_stop;
 
-  /* pending child seek */
-  GstEvent *childseek;
-
   /* Seek segment handler */
   GstSegment *segment;
   GstSegment *outside_segment;
@@ -130,9 +126,6 @@ struct _GnlCompositionPrivate
   /* Next running base_time to set on outgoing segment */
   guint64 next_base_time;
 
-  /* number of pads we are waiting to appear so be can do proper linking */
-  guint waitingpads;
-
   /*
      OUR sync_handler on the child_bus
      We are called before gnl_object_sync_handler
@@ -178,10 +171,9 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element);
 static GstStateChangeReturn
 gnl_composition_change_state (GstElement * element, GstStateChange transition);
 
-static GstPad *get_src_pad (GstElement * element);
 static GstPadProbeReturn pad_blocked (GstPad * pad, GstPadProbeInfo * info,
     GnlComposition * comp);
-static inline void gnl_composition_remove_ghostpad (GnlComposition * comp);
+static inline void gnl_composition_reset_target_pad (GnlComposition * comp);
 
 static gboolean
 seek_handling (GnlComposition * comp, gboolean initial, gboolean update);
@@ -191,12 +183,14 @@ static GstClockTime get_current_position (GnlComposition * comp);
 
 static gboolean update_pipeline (GnlComposition * comp,
     GstClockTime currenttime, gboolean initial, gboolean modify);
-static void no_more_pads_object_cb (GstElement * element,
-    GnlComposition * comp);
 static gboolean gnl_composition_commit_func (GnlObject * object,
     gboolean recurse);
 static void update_start_stop_duration (GnlComposition * comp);
 
+static gboolean
+gnl_composition_event_handler (GstPad * ghostpad, GstObject * parent,
+    GstEvent * event);
+
 
 /* COMP_REAL_START: actual position to start current playback at. */
 #define COMP_REAL_START(comp)                                                  \
@@ -263,11 +257,6 @@ struct _GnlCompositionEntry
   GnlObject *object;
   GnlComposition *comp;
 
-  /* handler id for 'no-more-pads' signal */
-  gulong nomorepadshandler;
-  gulong padaddedhandler;
-  gulong padremovedhandler;
-
   /* handler id for block probe */
   gulong probeid;
   gulong dataprobeid;
@@ -368,23 +357,15 @@ hash_value_destroy (GnlCompositionEntry * entry)
   GstPad *srcpad;
   GstElement *element = GST_ELEMENT (entry->object);
 
-  g_signal_handler_disconnect (entry->object, entry->padremovedhandler);
-  g_signal_handler_disconnect (entry->object, entry->padaddedhandler);
-
-  if (entry->nomorepadshandler)
-    g_signal_handler_disconnect (entry->object, entry->nomorepadshandler);
-
-  if ((srcpad = get_src_pad (element))) {
-    if (entry->probeid) {
-      gst_pad_remove_probe (srcpad, entry->probeid);
-      entry->probeid = 0;
-    }
+  srcpad = GNL_OBJECT_SRC (element);
+  if (entry->probeid) {
+    gst_pad_remove_probe (srcpad, entry->probeid);
+    entry->probeid = 0;
+  }
 
-    if (entry->dataprobeid) {
-      gst_pad_remove_probe (srcpad, entry->dataprobeid);
-      entry->dataprobeid = 0;
-    }
-    gst_object_unref (srcpad);
+  if (entry->dataprobeid) {
+    gst_pad_remove_probe (srcpad, entry->dataprobeid);
+    entry->dataprobeid = 0;
   }
 
   g_slice_free (GnlCompositionEntry, entry);
@@ -410,8 +391,6 @@ gnl_composition_init (GnlComposition * comp)
   priv->segment = gst_segment_new ();
   priv->outside_segment = gst_segment_new ();
 
-  priv->waitingpads = 0;
-
   priv->reset_time = FALSE;
 
   priv->objects_hash = g_hash_table_new_full
@@ -423,6 +402,10 @@ gnl_composition_init (GnlComposition * comp)
   comp->priv = priv;
 
   gnl_composition_reset (comp);
+
+  priv->gnl_event_pad_func = GST_PAD_EVENTFUNC (GNL_OBJECT_SRC (comp));
+  gst_pad_set_event_function (GNL_OBJECT_SRC (comp),
+      GST_DEBUG_FUNCPTR (gnl_composition_event_handler));
 }
 
 static void
@@ -436,14 +419,6 @@ gnl_composition_dispose (GObject * object)
 
   priv->dispose_has_run = TRUE;
 
-  if (priv->ghostpad)
-    gnl_composition_remove_ghostpad (comp);
-
-  if (priv->childseek) {
-    gst_event_unref (priv->childseek);
-    priv->childseek = NULL;
-  }
-
   if (priv->current) {
     g_node_destroy (priv->current);
     priv->current = NULL;
@@ -453,6 +428,7 @@ gnl_composition_dispose (GObject * object)
     g_list_free (priv->expandables);
     priv->expandables = NULL;
   }
+  gnl_composition_reset_target_pad (comp);
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -514,32 +490,10 @@ gnl_composition_get_property (GObject * object, guint prop_id,
   }
 }
 
-static void
-wait_no_more_pads (GnlComposition * comp, gpointer object,
-    GnlCompositionEntry * entry, gboolean wait)
-{
-  if (wait) {
-    GST_INFO_OBJECT (object, "no existing pad, connecting to 'no-more-pads'");
-    entry->nomorepadshandler = g_signal_connect
-        (G_OBJECT (object), "no-more-pads",
-        G_CALLBACK (no_more_pads_object_cb), comp);
-    comp->priv->waitingpads++;
-  } else {
-    GST_INFO_OBJECT (object, "disconnecting from 'no-more-pads'");
-    g_signal_handler_disconnect (object, entry->nomorepadshandler);
-    entry->nomorepadshandler = 0;
-    comp->priv->waitingpads--;
-  }
-
-  GST_INFO_OBJECT (comp, "the number of waiting pads is now %d",
-      comp->priv->waitingpads);
-}
-
 /* signal_duration_change
  * Creates a new GST_MESSAGE_DURATION_CHANGED with the currently configured
  * composition duration and sends that on the bus.
  */
-
 static inline void
 signal_duration_change (GnlComposition * comp)
 {
@@ -557,13 +511,10 @@ unblock_child_pads (GValue * item, GValue * ret G_GNUC_UNUSED,
 
   GST_DEBUG_OBJECT (child, "unblocking pads");
 
-  pad = get_src_pad (child);
-  if (pad) {
-    if (entry->probeid) {
-      gst_pad_remove_probe (pad, entry->probeid);
-      entry->probeid = 0;
-    }
-    gst_object_unref (pad);
+  pad = GNL_OBJECT_SRC (child);
+  if (entry->probeid) {
+    gst_pad_remove_probe (pad, entry->probeid);
+    entry->probeid = 0;
   }
   return TRUE;
 }
@@ -592,13 +543,20 @@ reset_child (GValue * item, GValue * ret G_GNUC_UNUSED, gpointer user_data)
   GnlCompositionEntry *entry;
   GstElement *child = g_value_get_object (item);
   GnlComposition *comp = GNL_COMPOSITION (user_data);
+  GnlObject *object;
+  GstPad *srcpad, *peerpad;
 
   GST_DEBUG_OBJECT (child, "unlocking state");
   gst_element_set_locked_state (child, FALSE);
 
   entry = COMP_ENTRY (comp, child);
-  if (entry->nomorepadshandler)
-    wait_no_more_pads (comp, child, entry, FALSE);
+  object = entry->object;
+  srcpad = object->srcpad;
+  peerpad = gst_pad_get_peer (srcpad);
+  if (peerpad) {
+    gst_pad_unlink (srcpad, peerpad);
+    gst_object_unref (peerpad);
+  }
 
   return TRUE;
 }
@@ -651,13 +609,7 @@ gnl_composition_reset (GnlComposition * comp)
 
   priv->stackvalid = FALSE;
 
-  if (priv->ghostpad)
-    gnl_composition_remove_ghostpad (comp);
-
-  if (priv->childseek) {
-    gst_event_unref (priv->childseek);
-    priv->childseek = NULL;
-  }
+  gnl_composition_reset_target_pad (comp);
 
   reset_children (comp);
 
@@ -992,27 +944,26 @@ get_current_position (GnlComposition * comp)
   gboolean res;
   gint64 value = GST_CLOCK_TIME_NONE;
 
+  GstPad *peer = gst_pad_get_peer (GNL_OBJECT (comp)->srcpad);
+
   /* 1. Try querying position downstream */
-  if (priv->ghostpad) {
-    GstPad *peer = gst_pad_get_peer (priv->ghostpad);
 
-    if (peer) {
-      res = gst_pad_query_position (peer, GST_FORMAT_TIME, &value);
-      gst_object_unref (peer);
+  if (peer) {
+    res = gst_pad_query_position (peer, GST_FORMAT_TIME, &value);
+    gst_object_unref (peer);
 
-      if (res) {
-        GST_LOG_OBJECT (comp,
-            "Successfully got downstream position %" GST_TIME_FORMAT,
-            GST_TIME_ARGS ((guint64) value));
-        goto beach;
-      }
+    if (res) {
+      GST_LOG_OBJECT (comp,
+          "Successfully got downstream position %" GST_TIME_FORMAT,
+          GST_TIME_ARGS ((guint64) value));
+      goto beach;
     }
+  }
 
-    GST_DEBUG_OBJECT (comp, "Downstream position query failed");
+  GST_DEBUG_OBJECT (comp, "Downstream position query failed");
 
-    /* resetting format/value */
-    value = GST_CLOCK_TIME_NONE;
-  }
+  /* resetting format/value */
+  value = GST_CLOCK_TIME_NONE;
 
   /* 2. If downstream fails , try within the current stack */
   if (!priv->current) {
@@ -1022,14 +973,11 @@ get_current_position (GnlComposition * comp)
 
   obj = (GnlObject *) priv->current->data;
 
-  if (!(pad = get_src_pad ((GstElement *) obj)))
-    goto beach;
-
+  pad = GNL_OBJECT_SRC (obj);
   res = gst_pad_query_position (pad, GST_FORMAT_TIME, &value);
 
   if (G_UNLIKELY (res == FALSE)) {
-    GST_WARNING_OBJECT (comp,
-        "query failed or returned a format different from TIME");
+    GST_WARNING_OBJECT (comp, "query position failed");
     value = GST_CLOCK_TIME_NONE;
   } else {
     GST_LOG_OBJECT (comp, "Query returned %" GST_TIME_FORMAT,
@@ -1098,7 +1046,7 @@ seek_handling (GnlComposition * comp, gboolean initial, gboolean update)
   return TRUE;
 }
 
-static void
+static gboolean
 handle_seek_event (GnlComposition * comp, GstEvent * event)
 {
   gdouble rate;
@@ -1122,6 +1070,14 @@ handle_seek_event (GnlComposition * comp, GstEvent * event)
 
   GST_DEBUG_OBJECT (comp, "Segment now has flags:%d", priv->segment->flags);
 
+  if (priv->segment->start >= GNL_OBJECT_STOP (comp)) {
+    GST_INFO_OBJECT (comp,
+        "Start %" GST_TIME_FORMAT " > comp->stop: %" GST_TIME_FORMAT
+        " Not seeking", GST_TIME_ARGS (priv->segment->start),
+        GST_TIME_ARGS (GNL_OBJECT_STOP (comp)));
+    return FALSE;
+  }
+
   /* crop the segment start/stop values */
   /* Only crop segment start value if we don't have a default object */
   if (priv->expandables == NULL)
@@ -1131,6 +1087,7 @@ handle_seek_event (GnlComposition * comp, GstEvent * event)
   comp->priv->next_base_time = 0;
 
   seek_handling (comp, TRUE, FALSE);
+  return TRUE;
 }
 
 static gboolean
@@ -1148,7 +1105,11 @@ gnl_composition_event_handler (GstPad * ghostpad, GstObject * parent,
     {
       GstEvent *nevent;
 
-      handle_seek_event (comp, event);
+      if ((res = handle_seek_event (comp, event)) == FALSE) {
+        gst_event_unref (event);
+        event = NULL;
+        break;
+      }
 
       /* the incoming event might not be quite correct, we get a new proper
        * event to pass on to the children. */
@@ -1238,23 +1199,12 @@ gnl_composition_event_handler (GstPad * ghostpad, GstObject * parent,
       break;
   }
 
-  if (res && priv->ghostpad) {
-    COMP_OBJECTS_LOCK (comp);
-
-    /* If the timeline isn't entirely reconstructed, we silently ignore the
-     * event. In the case of seeks the pipeline will already be correctly
-     * configured at this point*/
-    if (priv->waitingpads == 0) {
-      COMP_OBJECTS_UNLOCK (comp);
-      GST_DEBUG_OBJECT (comp, "About to call gnl_event_pad_func()");
-      res = priv->gnl_event_pad_func (priv->ghostpad, parent, event);
-      priv->reset_time = FALSE;
-      GST_DEBUG_OBJECT (comp, "Done calling gnl_event_pad_func() %d", res);
-    } else {
-      COMP_OBJECTS_UNLOCK (comp);
-      gst_event_unref (event);
-    }
-
+  if (res) {
+    GST_DEBUG_OBJECT (comp, "About to call gnl_event_pad_func: %p",
+        priv->gnl_event_pad_func);
+    res = priv->gnl_event_pad_func (GNL_OBJECT (comp)->srcpad, parent, event);
+    priv->reset_time = FALSE;
+    GST_DEBUG_OBJECT (comp, "Done calling gnl_event_pad_func() %d", res);
   }
 
 beach:
@@ -1269,6 +1219,29 @@ pad_blocked (GstPad * pad, GstPadProbeInfo * info, GnlComposition * comp)
   return GST_PAD_PROBE_OK;
 }
 
+static inline void
+gnl_composition_reset_target_pad (GnlComposition * comp)
+{
+  GnlCompositionPrivate *priv = comp->priv;
+
+  GST_DEBUG_OBJECT (comp, "Removing ghostpad");
+
+  if (priv->ghosteventprobe) {
+    GstPad *target;
+
+    target = gst_ghost_pad_get_target ((GstGhostPad *) GNL_OBJECT_SRC (comp));
+    if (target)
+      gst_pad_remove_probe (target, priv->ghosteventprobe);
+    priv->ghosteventprobe = 0;
+  }
+
+  gnl_object_ghost_pad_set_target (GNL_OBJECT (comp),
+      GNL_OBJECT_SRC (comp), NULL);
+  priv->toplevelentry = NULL;
+  GST_ERROR ("NEED STRAM START");
+  priv->send_stream_start = TRUE;
+}
+
 static GstPadProbeReturn
 drop_data (GstPad * pad, GstPadProbeInfo * info, GnlCompositionEntry * entry)
 {
@@ -1296,104 +1269,64 @@ drop_data (GstPad * pad, GstPadProbeInfo * info, GnlCompositionEntry * entry)
   return GST_PAD_PROBE_OK;
 }
 
-static inline void
-gnl_composition_remove_ghostpad (GnlComposition * comp)
-{
-  GnlCompositionPrivate *priv = comp->priv;
-
-  GST_DEBUG_OBJECT (comp, "Removing ghostpad");
-
-  if (priv->ghosteventprobe) {
-    GstPad *target;
-
-    target = gst_ghost_pad_get_target ((GstGhostPad *) priv->ghostpad);
-    if (target)
-      gst_pad_remove_probe (target, priv->ghosteventprobe);
-    priv->ghosteventprobe = 0;
-  }
-
-  gnl_object_remove_ghost_pad (GNL_OBJECT (comp), priv->ghostpad);
-  priv->ghostpad = NULL;
-  priv->toplevelentry = NULL;
-  priv->send_stream_start = TRUE;
-}
-
 /* gnl_composition_ghost_pad_set_target:
  * target: The target #GstPad. The refcount will be decremented (given to the ghostpad).
  * entry: The GnlCompositionEntry to which the pad belongs
  */
-
 static void
 gnl_composition_ghost_pad_set_target (GnlComposition * comp, GstPad * target,
     GnlCompositionEntry * entry)
 {
+  GstPad *ptarget;
   GnlCompositionPrivate *priv = comp->priv;
-  gboolean hadghost = priv->ghostpad ? TRUE : FALSE;
 
   if (target)
-    GST_DEBUG_OBJECT (comp, "target:%s:%s , hadghost:%d",
-        GST_DEBUG_PAD_NAME (target), hadghost);
+    GST_DEBUG_OBJECT (comp, "target:%s:%s", GST_DEBUG_PAD_NAME (target));
   else
-    GST_DEBUG_OBJECT (comp, "Removing target, hadghost:%d", hadghost);
+    GST_DEBUG_OBJECT (comp, "Removing target");
 
-  if (!hadghost) {
-    /* Create new ghostpad */
-    GstPad *ghostpad =
-        gnl_object_ghost_pad_no_target ((GnlObject *) comp, "src", GST_PAD_SRC);
 
-    if (!priv->gnl_event_pad_func) {
-      GST_DEBUG_OBJECT (ghostpad, "About to replace event_pad_func");
-      priv->gnl_event_pad_func = GST_PAD_EVENTFUNC (ghostpad);
-    }
-
-    gst_pad_set_event_function (ghostpad,
-        GST_DEBUG_FUNCPTR (gnl_composition_event_handler));
-    GST_DEBUG_OBJECT (ghostpad, "eventfunc is now %s",
-        GST_DEBUG_FUNCPTR_NAME (GST_PAD_EVENTFUNC (ghostpad)));
+  ptarget =
+      gst_ghost_pad_get_target (GST_GHOST_PAD (GNL_OBJECT (comp)->srcpad));
+  if (ptarget && ptarget == target) {
+    GST_DEBUG_OBJECT (comp,
+        "Target of srcpad is the same as existing one, not changing");
+    gst_object_unref (ptarget);
+    return;
+  }
 
-    priv->ghostpad = ghostpad;
-  } else {
-    GstPad *ptarget = gst_ghost_pad_get_target (GST_GHOST_PAD (priv->ghostpad));
+  /* Unset previous target */
+  if (ptarget) {
+    GST_DEBUG_OBJECT (comp, "Previous target was %s:%s",
+        GST_DEBUG_PAD_NAME (ptarget));
 
-    if (ptarget && ptarget == target) {
-      GST_DEBUG_OBJECT (comp,
-          "Target of ghostpad is the same as existing one, not changing");
-      gst_object_unref (ptarget);
-      return;
+    if (!priv->toplevelentry->probeid) {
+      /* If it's not blocked, block it */
+      priv->toplevelentry->probeid =
+          gst_pad_add_probe (ptarget,
+          GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE,
+          (GstPadProbeCallback) pad_blocked, comp, NULL);
     }
 
-    /* Unset previous target */
-    if (ptarget) {
-      GST_DEBUG_OBJECT (comp, "Previous target was %s:%s",
-          GST_DEBUG_PAD_NAME (ptarget));
-
-      if (!priv->toplevelentry->probeid) {
-        /* If it's not blocked, block it */
-        priv->toplevelentry->probeid =
-            gst_pad_add_probe (ptarget,
-            GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE,
-            (GstPadProbeCallback) pad_blocked, comp, NULL);
-      }
-
-      if (!priv->toplevelentry->dataprobeid) {
-        priv->toplevelentry->dataprobeid = gst_pad_add_probe (ptarget,
-            GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST |
-            GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data,
-            priv->toplevelentry, NULL);
-      }
-
-      /* remove event probe */
-      if (priv->ghosteventprobe) {
-        gst_pad_remove_probe (ptarget, priv->ghosteventprobe);
-        priv->ghosteventprobe = 0;
-      }
-      gst_object_unref (ptarget);
+    if (!priv->toplevelentry->dataprobeid) {
+      priv->toplevelentry->dataprobeid = gst_pad_add_probe (ptarget,
+          GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST |
+          GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data,
+          priv->toplevelentry, NULL);
+    }
 
+    /* remove event probe */
+    if (priv->ghosteventprobe) {
+      gst_pad_remove_probe (ptarget, priv->ghosteventprobe);
+      priv->ghosteventprobe = 0;
     }
+    gst_object_unref (ptarget);
+
   }
 
   /* Actually set the target */
-  gnl_object_ghost_pad_set_target ((GnlObject *) comp, priv->ghostpad, target);
+  gnl_object_ghost_pad_set_target ((GnlObject *) comp,
+      GNL_OBJECT (comp)->srcpad, target);
 
   /* Set top-level entry (will be NULL if unsetting) */
   priv->toplevelentry = entry;
@@ -1406,17 +1339,6 @@ gnl_composition_ghost_pad_set_target (GnlComposition * comp, GstPad * target,
     GST_DEBUG_OBJECT (comp, "added event probe %lu", priv->ghosteventprobe);
   }
 
-  if (!hadghost) {
-    gst_pad_set_active (priv->ghostpad, TRUE);
-
-    COMP_OBJECTS_UNLOCK (comp);
-    if (!gst_element_add_pad (GST_ELEMENT (comp), priv->ghostpad))
-      GST_WARNING ("Couldn't add the ghostpad");
-    else
-      gst_element_no_more_pads (GST_ELEMENT (comp));
-    COMP_OBJECTS_LOCK (comp);
-  }
-
   GST_DEBUG_OBJECT (comp, "END");
 }
 
@@ -1780,52 +1702,6 @@ get_clean_toplevel_stack (GnlComposition * comp, GstClockTime * timestamp,
 }
 
 
-/*
- *
- * UTILITY FUNCTIONS
- *
- */
-
-/*
- * get_src_pad:
- * element: a #GstElement
- *
- * Returns: The src pad for the given element. A reference was added to the
- * returned pad, remove it when you don't need that pad anymore.
- * Returns NULL if there's no source pad.
- */
-static GstPad *
-get_src_pad (GstElement * element)
-{
-  GstIterator *it;
-  GstIteratorResult itres;
-  GValue item = { 0, };
-  GstPad *srcpad;
-
-  it = gst_element_iterate_src_pads (element);
-
-  itres = gst_iterator_next (it, &item);
-  if (itres != GST_ITERATOR_OK) {
-    GST_DEBUG ("%s doesn't have a src pad !", GST_ELEMENT_NAME (element));
-    srcpad = NULL;
-  } else {
-    srcpad = g_value_get_object (&item);
-    gst_object_ref (srcpad);
-    g_value_reset (&item);
-  }
-
-  gst_iterator_free (it);
-
-  return srcpad;
-}
-
-
-/*
- *
- * END OF UTILITY FUNCTIONS
- *
- */
-
 static gboolean
 set_child_caps (GValue * item, GValue * ret G_GNUC_UNUSED, GnlObject * comp)
 {
@@ -1866,8 +1742,7 @@ update_pipeline_func (GnlComposition * comp)
       /* If we're at the end, post SEGMENT_DONE, or push EOS */
       GST_DEBUG_OBJECT (comp, "Nothing else to play");
 
-      if (!(priv->segment->flags & GST_SEEK_FLAG_SEGMENT)
-          && priv->ghostpad) {
+      if (!(priv->segment->flags & GST_SEEK_FLAG_SEGMENT)) {
         GST_DEBUG_OBJECT (comp, "Real EOS should be sent now");
       } else if (priv->segment->flags & GST_SEEK_FLAG_SEGMENT) {
         gint64 epos;
@@ -1882,7 +1757,7 @@ update_pipeline_func (GnlComposition * comp)
         gst_element_post_message (GST_ELEMENT_CAST (comp),
             gst_message_new_segment_done (GST_OBJECT (comp),
                 priv->segment->format, epos));
-        gst_pad_push_event (priv->ghostpad,
+        gst_pad_push_event (GNL_OBJECT (comp)->srcpad,
             gst_event_new_segment_done (priv->segment->format, epos));
       }
     }
@@ -2118,144 +1993,6 @@ update_start_stop_duration (GnlComposition * comp)
       GST_TIME_ARGS (cobj->stop), GST_TIME_ARGS (cobj->duration));
 }
 
-static void
-no_more_pads_object_cb (GstElement * element, GnlComposition * comp)
-{
-  GnlCompositionPrivate *priv = comp->priv;
-  GnlObject *object = (GnlObject *) element;
-  GNode *tmp;
-  GstPad *pad = NULL;
-  GnlCompositionEntry *entry;
-
-  GST_LOG_OBJECT (comp, "no more pads on element %s",
-      GST_ELEMENT_NAME (element));
-
-  if (!(pad = get_src_pad (element)))
-    goto no_source;
-
-  COMP_OBJECTS_LOCK (comp);
-
-  if (G_UNLIKELY (priv->current == NULL)) {
-    GST_DEBUG_OBJECT (comp, "current stack is empty !");
-    goto done;
-  }
-
-  tmp = g_node_find (priv->current, G_IN_ORDER, G_TRAVERSE_ALL, object);
-
-  if (G_UNLIKELY (tmp == NULL))
-    goto not_in_stack;
-
-  entry = COMP_ENTRY (comp, object);
-  wait_no_more_pads (comp, object, entry, FALSE);
-
-  if (tmp->parent) {
-    GstElement *parent = (GstElement *) tmp->parent->data;
-    GstPad *sinkpad;
-
-    /* Get an unlinked sinkpad from the parent */
-    sinkpad = get_unlinked_sink_ghost_pad ((GnlOperation *) parent);
-
-    if (G_UNLIKELY (sinkpad == NULL)) {
-      GST_WARNING_OBJECT (comp,
-          "Couldn't find an unlinked sinkpad from %s",
-          GST_ELEMENT_NAME (parent));
-      goto done;
-    }
-
-    /* Link pad to parent sink pad */
-    if (G_UNLIKELY (gst_pad_link_full (pad, sinkpad,
-                GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) {
-      GST_WARNING_OBJECT (comp, "Failed to link pads %s:%s - %s:%s",
-          GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (sinkpad));
-      gst_object_unref (sinkpad);
-      goto done;
-    }
-
-    /* inform operation of incoming stream priority */
-    gnl_operation_signal_input_priority_changed ((GnlOperation *) parent,
-        sinkpad, object->priority);
-    gst_object_unref (sinkpad);
-    gst_pad_remove_probe (pad, entry->probeid);
-    entry->probeid = 0;
-  }
-
-  /* If there are no more waiting pads, activate the current stack */
-  if (priv->current && (priv->waitingpads == 0)
-      && priv->stackvalid) {
-    GnlCompositionEntry *topentry = COMP_ENTRY (comp, priv->current->data);
-    GstPad *tpad = NULL;
-
-    /* There are no more waiting pads for the currently configured timeline */
-    /* stack. */
-    tpad = get_src_pad (GST_ELEMENT (priv->current->data));
-    GST_LOG_OBJECT (comp,
-        "top-level pad %s:%s, Setting target of ghostpad to it",
-        GST_DEBUG_PAD_NAME (tpad));
-
-    /* 2. send pending seek */
-    if (priv->childseek) {
-      GstEvent *childseek = priv->childseek;
-
-      priv->childseek = NULL;
-      GST_INFO_OBJECT (comp, "Sending pending seek on %s:%s",
-          GST_DEBUG_PAD_NAME (tpad));
-
-      COMP_OBJECTS_UNLOCK (comp);
-
-      if (!(gst_pad_send_event (tpad, childseek)))
-        GST_ERROR_OBJECT (comp, "Sending seek event failed!");
-
-      COMP_OBJECTS_LOCK (comp);
-    }
-    priv->childseek = NULL;
-
-    /* 1. set target of ghostpad to toplevel element src pad */
-    gnl_composition_ghost_pad_set_target (comp, tpad, topentry);
-
-    /* Check again if the top-level element is still in the stack */
-    if (priv->current &&
-        g_node_find (priv->current, G_IN_ORDER, G_TRAVERSE_ALL, object)) {
-
-      /* 3. unblock ghostpad */
-      if (topentry->probeid) {
-        GST_LOG_OBJECT (comp, "About to unblock top-level pad : %s:%s",
-            GST_DEBUG_PAD_NAME (tpad));
-        gst_pad_remove_probe (tpad, topentry->probeid);
-        topentry->probeid = 0;
-        GST_LOG_OBJECT (comp, "Unblocked top-level pad");
-      }
-    } else
-      GST_DEBUG ("Element went away from currently configured stack");
-
-    if (tpad)
-      gst_object_unref (tpad);
-  }
-
-done:
-  COMP_OBJECTS_UNLOCK (comp);
-
-  if (pad)
-    gst_object_unref (pad);
-
-  GST_DEBUG_OBJECT (comp, "end");
-
-  return;
-
-no_source:
-  {
-    GST_LOG_OBJECT (comp, "no source pad");
-    return;
-  }
-
-not_in_stack:
-  {
-    GST_LOG_OBJECT (comp,
-        "The following object is not in currently configured stack : %s",
-        GST_ELEMENT_NAME (object));
-    goto done;
-  }
-}
-
 /*
  * recursive depth-first relink stack function on new stack
  *
@@ -2265,7 +2002,6 @@ not_in_stack:
  *
  * WITH OBJECTS LOCK TAKEN
  */
-
 static void
 compare_relink_single_node (GnlComposition * comp, GNode * node,
     GNode * oldstack)
@@ -2292,10 +2028,11 @@ compare_relink_single_node (GnlComposition * comp, GNode * node,
 
   GST_DEBUG_OBJECT (comp, "newobj:%s",
       GST_ELEMENT_NAME ((GstElement *) newobj));
-  srcpad = get_src_pad ((GstElement *) newobj);
+
+  srcpad = GNL_OBJECT_SRC (newobj);
 
   /* 1. Make sure the source pad is blocked for new objects */
-  if (G_UNLIKELY (!oldnode && srcpad)) {
+  if (G_UNLIKELY (!oldnode)) {
     GnlCompositionEntry *oldentry = COMP_ENTRY (comp, newobj);
     if (!oldentry->probeid) {
       GST_LOG_OBJECT (comp, "block_async(%s:%s, TRUE)",
@@ -2314,59 +2051,48 @@ compare_relink_single_node (GnlComposition * comp, GNode * node,
   }
 
   entry = COMP_ENTRY (comp, newobj);
-  /* 2. link to parent if needed.
-   *
-   * If entry->nomorepadshandler is not zero, it means that srcpad didn't exist
-   * before and so we connected to no-more-pads. This can happen since there's a
-   * window of time between gnlsource adds its srcpad and then emits
-   * no-more-pads. In that case, we just wait for no-more-pads to be emitted.
-   */
-  if (srcpad && entry->nomorepadshandler == 0) {
-    GST_LOG_OBJECT (comp, "has a valid source pad");
-    /* POST PROCESSING */
-    if ((oldparent != newparent) ||
-        (oldparent && newparent &&
-            (g_node_child_index (node,
-                    newobj) != g_node_child_index (oldnode, newobj)))) {
-      GST_LOG_OBJECT (comp,
-          "not same parent, or same parent but in different order");
-      /* relink to new parent in required order */
-      if (newparent) {
-        GstPad *sinkpad;
-        GST_LOG_OBJECT (comp, "Linking %s and %s",
-            GST_ELEMENT_NAME (GST_ELEMENT (newobj)),
-            GST_ELEMENT_NAME (GST_ELEMENT (newparent)));
-        sinkpad = get_unlinked_sink_ghost_pad ((GnlOperation *) newparent);
-        if (G_UNLIKELY (sinkpad == NULL)) {
-          GST_WARNING_OBJECT (comp,
-              "Couldn't find an unlinked sinkpad from %s",
-              GST_ELEMENT_NAME (newparent));
-        } else {
-          if (G_UNLIKELY (gst_pad_link_full (srcpad, sinkpad,
-                      GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) {
-            GST_WARNING_OBJECT (comp, "Failed to link pads %s:%s - %s:%s",
-                GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
-          }
-          gst_object_unref (sinkpad);
+  /* 2. link to parent if needed.  */
+  GST_LOG_OBJECT (comp, "has a valid source pad");
+  /* POST PROCESSING */
+  if ((oldparent != newparent) ||
+      (oldparent && newparent &&
+          (g_node_child_index (node,
+                  newobj) != g_node_child_index (oldnode, newobj)))) {
+    GST_LOG_OBJECT (comp,
+        "not same parent, or same parent but in different order");
+    /* relink to new parent in required order */
+    if (newparent) {
+      GstPad *sinkpad;
+      GST_LOG_OBJECT (comp, "Linking %s and %s",
+          GST_ELEMENT_NAME (GST_ELEMENT (newobj)),
+          GST_ELEMENT_NAME (GST_ELEMENT (newparent)));
+      sinkpad = get_unlinked_sink_ghost_pad ((GnlOperation *) newparent);
+      if (G_UNLIKELY (sinkpad == NULL)) {
+        GST_WARNING_OBJECT (comp,
+            "Couldn't find an unlinked sinkpad from %s",
+            GST_ELEMENT_NAME (newparent));
+      } else {
+        if (G_UNLIKELY (gst_pad_link_full (srcpad, sinkpad,
+                    GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) {
+          GST_WARNING_OBJECT (comp, "Failed to link pads %s:%s - %s:%s",
+              GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
         }
+        gst_object_unref (sinkpad);
       }
-    } else
-      GST_LOG_OBJECT (newobj, "Same parent and same position in the new stack");
-    /* If there's an operation, inform it about priority changes */
-    if (newparent) {
-      sinkpad = gst_pad_get_peer (srcpad);
-      gnl_operation_signal_input_priority_changed ((GnlOperation *)
-          newparent, sinkpad, newobj->priority);
-      gst_object_unref (sinkpad);
     }
-
-  } else if (entry->nomorepadshandler) {
-    GST_INFO_OBJECT (newobj,
-        "we have a pad but we are connected to 'no-more-pads'");
   } else {
-    wait_no_more_pads (comp, newobj, entry, TRUE);
+    GST_LOG_OBJECT (newobj, "Same parent and same position in the new stack");
   }
 
+  /* If there's an operation, inform it about priority changes */
+  if (newparent) {
+    sinkpad = gst_pad_get_peer (srcpad);
+    gnl_operation_signal_input_priority_changed ((GnlOperation *)
+        newparent, sinkpad, newobj->priority);
+    gst_object_unref (sinkpad);
+  }
+
+
   /* 3. Handle children */
   if (GNL_IS_OPERATION (newobj)) {
     guint nbchildren = g_node_n_children (node);
@@ -2391,15 +2117,12 @@ compare_relink_single_node (GnlComposition * comp, GNode * node,
   }
 
   /* 4. Unblock source pad */
-  if ((srcpad && entry->nomorepadshandler == 0) && !G_NODE_IS_ROOT (node) &&
-      entry->probeid) {
+  if (!G_NODE_IS_ROOT (node) && entry->probeid) {
     GST_LOG_OBJECT (comp, "Unblocking pad %s:%s", GST_DEBUG_PAD_NAME (srcpad));
     gst_pad_remove_probe (srcpad, entry->probeid);
     entry->probeid = 0;
   }
 
-  if (G_LIKELY (srcpad))
-    gst_object_unref (srcpad);
   GST_LOG_OBJECT (comp, "done with object %s",
       GST_ELEMENT_NAME (GST_ELEMENT (newobj)));
 }
@@ -2416,7 +2139,6 @@ compare_relink_single_node (GnlComposition * comp, GNode * node,
  *
  * WITH OBJECTS LOCK TAKEN
  */
-
 static GList *
 compare_deactivate_single_node (GnlComposition * comp, GNode * node,
     GNode * newstack, gboolean modify)
@@ -2427,6 +2149,8 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node,
   GList *deactivate = NULL;
   GnlObject *oldobj = NULL;
   GstPad *srcpad = NULL;
+  GstPad *peerpad = NULL;
+  GnlCompositionEntry *entry;
 
   if (G_UNLIKELY (!node))
     return NULL;
@@ -2443,46 +2167,40 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node,
 
   GST_DEBUG_OBJECT (comp, "oldobj:%s",
       GST_ELEMENT_NAME ((GstElement *) oldobj));
-  srcpad = get_src_pad ((GstElement *) oldobj);
-
-  if (G_LIKELY (srcpad)) {
-    GstPad *peerpad = NULL;
-    GnlCompositionEntry *entry = COMP_ENTRY (comp, oldobj);
-
-    /* 1. Block source pad
-     *   This makes sure that no data/event flow will come out of this element after this
-     *   point.
-     *
-     * If entry is NULL, this means the element is in the process of being removed.
-     */
-    if (entry && !entry->probeid) {
-      GST_LOG_OBJECT (comp, "Setting BLOCKING probe on %s:%s",
-          GST_DEBUG_PAD_NAME (srcpad));
-      entry->probeid =
-          gst_pad_add_probe (srcpad,
-          GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE,
-          (GstPadProbeCallback) pad_blocked, comp, NULL);
-    }
-    if (entry && !entry->dataprobeid) {
-      entry->dataprobeid = gst_pad_add_probe (srcpad,
-          GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST |
-          GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry,
-          NULL);
-    }
+  srcpad = GNL_OBJECT_SRC (oldobj);
 
-    /* 2. If we have to modify or we have a parent, flush downstream
-     *   This ensures the streaming thread going through the current object has
-     *   either stopped or is blocking against the source pad. */
-    if ((modify || oldparent) && (peerpad = gst_pad_get_peer (srcpad))) {
-      GST_LOG_OBJECT (comp, "Sending flush start/stop downstream ");
-      gst_pad_send_event (peerpad, gst_event_new_flush_start ());
-      gst_pad_send_event (peerpad, gst_event_new_flush_stop (TRUE));
-      GST_DEBUG_OBJECT (comp, "DONE Sending flush events downstream");
-      gst_object_unref (peerpad);
-    }
+  entry = COMP_ENTRY (comp, oldobj);
 
-  } else {
-    GST_LOG_OBJECT (comp, "No source pad available");
+  /* 1. Block source pad
+   *   This makes sure that no data/event flow will come out of this element after this
+   *   point.
+   *
+   * If entry is NULL, this means the element is in the process of being removed.
+   */
+  if (entry && !entry->probeid) {
+    GST_LOG_OBJECT (comp, "Setting BLOCKING probe on %s:%s",
+        GST_DEBUG_PAD_NAME (srcpad));
+    entry->probeid =
+        gst_pad_add_probe (srcpad,
+        GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE,
+        (GstPadProbeCallback) pad_blocked, comp, NULL);
+  }
+  if (entry && !entry->dataprobeid) {
+    entry->dataprobeid = gst_pad_add_probe (srcpad,
+        GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST |
+        GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry,
+        NULL);
+  }
+
+  /* 2. If we have to modify or we have a parent, flush downstream
+   *   This ensures the streaming thread going through the current object has
+   *   either stopped or is blocking against the source pad. */
+  if ((modify || oldparent) && (peerpad = gst_pad_get_peer (srcpad))) {
+    GST_LOG_OBJECT (comp, "Sending flush start/stop downstream ");
+    gst_pad_send_event (peerpad, gst_event_new_flush_start ());
+    gst_pad_send_event (peerpad, gst_event_new_flush_stop (TRUE));
+    GST_DEBUG_OBJECT (comp, "DONE Sending flush events downstream");
+    gst_object_unref (peerpad);
   }
 
   /* 3. Unlink from the parent if we've changed position */
@@ -2492,11 +2210,7 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node,
   if (G_UNLIKELY (!oldparent)) {
     GST_LOG_OBJECT (comp, "Top-level object");
     /* for top-level objects we just set the ghostpad target to NULL */
-    if (comp->priv->ghostpad) {
-      GST_LOG_OBJECT (comp, "Setting ghostpad target to NULL");
-      gnl_composition_ghost_pad_set_target (comp, NULL, NULL);
-    } else
-      GST_LOG_OBJECT (comp, "No ghostpad");
+    gnl_composition_ghost_pad_set_target (comp, NULL, NULL);
   } else {
     GnlObject *newparent = NULL;
 
@@ -2514,7 +2228,7 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node,
 
       GST_LOG_OBJECT (comp, "Topology changed, unlinking from downstream");
 
-      if (srcpad && (peerpad = gst_pad_get_peer (srcpad))) {
+      if ((peerpad = gst_pad_get_peer (srcpad))) {
         GST_LOG_OBJECT (peerpad, "Sending flush start/stop");
         gst_pad_send_event (peerpad, gst_event_new_flush_start ());
         gst_pad_send_event (peerpad, gst_event_new_flush_stop (TRUE));
@@ -2544,8 +2258,6 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node,
     deactivate = g_list_prepend (deactivate, oldobj);
   }
 
-  if (G_LIKELY (srcpad))
-    gst_object_unref (srcpad);
   GST_LOG_OBJECT (comp, "done with object %s",
       GST_ELEMENT_NAME (GST_ELEMENT (oldobj)));
 
@@ -2717,23 +2429,14 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime,
     priv->segment_stop = currenttime;
   }
 
-  /* 4. Clear pending child seek
-   *    We'll be creating a new one */
-  if (priv->childseek) {
-    GST_DEBUG ("unreffing event %p", priv->childseek);
-    gst_event_unref (priv->childseek);
-    priv->childseek = NULL;
-  }
-
   /* Invalidate current stack */
   if (priv->current)
     g_node_destroy (priv->current);
   priv->current = NULL;
 
-  /* 5. deactivate unused elements */
+  /* 4. deactivate unused elements */
   if (todeactivate) {
     GList *tmp;
-    GnlCompositionEntry *entry;
     GstElement *element;
 
     GST_DEBUG_OBJECT (comp, "De-activating objects no longer used");
@@ -2744,13 +2447,6 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime,
 
       gst_element_set_state (element, priv->deactivated_elements_state);
       gst_element_set_locked_state (element, TRUE);
-      entry = COMP_ENTRY (comp, element);
-
-      /* entry can be NULL here if update_pipeline was called by
-       * gnl_composition_remove_object (comp, tmp->data)
-       */
-      if (entry && entry->nomorepadshandler)
-        wait_no_more_pads (comp, element, entry, FALSE);
     }
 
     g_list_free (todeactivate);
@@ -2758,7 +2454,7 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime,
     GST_DEBUG_OBJECT (comp, "Finished de-activating objects no longer used");
   }
 
-  /* 6. Unlock all elements in new stack */
+  /* 5. Unlock all elements in new stack */
   GST_DEBUG_OBJECT (comp, "Setting current stack");
   priv->current = stack;
 
@@ -2769,13 +2465,16 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime,
     GST_DEBUG_OBJECT (comp, "Finished activating objects in new stack");
   }
 
-  /* 7. Activate stack (might happen asynchronously) */
+  /* 6. Activate stack (might happen asynchronously) */
   if (priv->current) {
     GstEvent *event;
+    GstPad *pad;
+    GstElement *topelement;
+    GnlCompositionEntry *topentry;
 
     priv->stackvalid = TRUE;
 
-    /* 7.1. Create new seek event for newly configured timeline stack */
+    /* 6.1. Create new seek event for newly configured timeline stack */
     if (samestack && (startchanged || stopchanged))
       event =
           get_new_seek_event (comp,
@@ -2783,60 +2482,38 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime,
     else
       event = get_new_seek_event (comp, initial, FALSE);
 
-    /* 7.2.a If the stack entirely ready, send seek out synchronously */
-    if (priv->waitingpads == 0) {
-      GstPad *pad;
-      GstElement *topelement = GST_ELEMENT (priv->current->data);
-
-      /* Get toplevel object source pad */
-      if ((pad = get_src_pad (topelement))) {
-        GnlCompositionEntry *topentry = COMP_ENTRY (comp, topelement);
-
-        GST_DEBUG_OBJECT (comp,
-            "We have a valid toplevel element pad %s:%s",
-            GST_DEBUG_PAD_NAME (pad));
-
-        /* Send seek event */
-        GST_LOG_OBJECT (comp, "sending seek event");
-        if (gst_pad_send_event (pad, event)) {
-          /* Unconditionnaly set the ghostpad target to pad */
-          GST_LOG_OBJECT (comp,
-              "Setting the composition's ghostpad target to %s:%s",
-              GST_DEBUG_PAD_NAME (pad));
+    /* 6.2 The stack is entirely ready, send seek out synchronously */
+    topelement = GST_ELEMENT (priv->current->data);
+    /* Get toplevel object source pad */
+    pad = GNL_OBJECT_SRC (topelement);
+    topentry = COMP_ENTRY (comp, topelement);
 
-          gnl_composition_ghost_pad_set_target (comp, pad, topentry);
+    GST_DEBUG_OBJECT (comp,
+        "We have a valid toplevel element pad %s:%s", GST_DEBUG_PAD_NAME (pad));
 
-          if (topentry->probeid) {
+    /* Send seek event */
+    GST_LOG_OBJECT (comp, "sending seek event");
+    if (gst_pad_send_event (pad, event)) {
+      /* Unconditionnaly set the ghostpad target to pad */
+      GST_LOG_OBJECT (comp,
+          "Setting the composition's ghostpad target to %s:%s",
+          GST_DEBUG_PAD_NAME (pad));
 
-            /* unblock top-level pad */
-            GST_LOG_OBJECT (comp, "About to unblock top-level srcpad");
-            gst_pad_remove_probe (pad, topentry->probeid);
-            topentry->probeid = 0;
-          }
-        } else {
-          ret = FALSE;
-        }
-        gst_object_unref (pad);
+      gnl_composition_ghost_pad_set_target (comp, pad, topentry);
 
-      } else {
-        GST_WARNING_OBJECT (comp,
-            "Timeline is entirely linked, but couldn't get top-level element's source pad");
+      if (topentry->probeid) {
 
-        ret = FALSE;
+        /* unblock top-level pad */
+        GST_LOG_OBJECT (comp, "About to unblock top-level srcpad");
+        gst_pad_remove_probe (pad, topentry->probeid);
+        topentry->probeid = 0;
       }
     } else {
-      /* 7.2.b. Stack isn't entirely ready, save seek event for later on */
-      GST_LOG_OBJECT (comp,
-          "The timeline stack isn't entirely linked, delaying sending seek event (waitingpads:%d)",
-          priv->waitingpads);
-
-      priv->childseek = event;
-      ret = TRUE;
+      ret = FALSE;
     }
   } else {
-    if ((!priv->objects_start) && priv->ghostpad) {
-      GST_DEBUG_OBJECT (comp, "composition is now empty, removing ghostpad");
-      gnl_composition_remove_ghostpad (comp);
+    if ((!priv->objects_start)) {
+      gnl_composition_reset_target_pad (comp);
       priv->segment_start = 0;
       priv->segment_stop = GST_CLOCK_TIME_NONE;
     }
@@ -2846,65 +2523,6 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime,
   return ret;
 }
 
-/*
- * Child modification updates
- */
-
-static void
-object_pad_removed (GnlObject * object, GstPad * pad, GnlComposition * comp)
-{
-  GnlCompositionPrivate *priv = comp->priv;
-
-  GST_DEBUG_OBJECT (comp, "pad %s:%s was removed", GST_DEBUG_PAD_NAME (pad));
-
-  if (GST_PAD_IS_SRC (pad)) {
-    /* remove ghostpad if it's the current top stack object */
-    if (priv->current && GNL_OBJECT (priv->current->data) == object
-        && priv->ghostpad)
-      gnl_composition_remove_ghostpad (comp);
-    else {
-      GnlCompositionEntry *entry = COMP_ENTRY (comp, object);
-
-      if (entry && entry->probeid) {
-        gst_pad_remove_probe (pad, entry->probeid);
-        entry->probeid = 0;
-      }
-      if (entry && entry->dataprobeid) {
-        gst_pad_remove_probe (pad, entry->dataprobeid);
-        entry->dataprobeid = 0;
-      }
-    }
-  }
-}
-
-static void
-object_pad_added (GnlObject * object G_GNUC_UNUSED, GstPad * pad,
-    GnlComposition * comp)
-{
-  GnlCompositionEntry *entry;
-
-  if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK)
-    return;
-
-  entry = COMP_ENTRY (comp, object);
-
-  if (!entry->probeid) {
-    GST_DEBUG_OBJECT (comp, "pad %s:%s was added, blocking it",
-        GST_DEBUG_PAD_NAME (pad));
-    entry->probeid =
-        gst_pad_add_probe (pad,
-        GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE,
-        (GstPadProbeCallback) pad_blocked, comp, NULL);
-  }
-
-  if (!entry->dataprobeid) {
-    entry->dataprobeid = gst_pad_add_probe (pad,
-        GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST |
-        GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry,
-        NULL);
-  }
-}
-
 static gboolean
 gnl_composition_add_object (GstBin * bin, GstElement * element)
 {
@@ -2967,10 +2585,15 @@ gnl_composition_add_object (GstBin * bin, GstElement * element)
   /* ...and add it to the hash table */
   g_hash_table_insert (priv->objects_hash, element, entry);
 
-  entry->padremovedhandler = g_signal_connect (G_OBJECT (element),
-      "pad-removed", G_CALLBACK (object_pad_removed), comp);
-  entry->padaddedhandler = g_signal_connect (G_OBJECT (element),
-      "pad-added", G_CALLBACK (object_pad_added), comp);
+  entry->dataprobeid = gst_pad_add_probe (entry->object->srcpad,
+      GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST |
+      GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry,
+      NULL);
+
+  entry->probeid =
+      gst_pad_add_probe (entry->object->srcpad,
+      GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE,
+      (GstPadProbeCallback) pad_blocked, comp, NULL);
 
   /* Set the caps of the composition */
   if (G_UNLIKELY (!gst_caps_is_any (((GnlObject *) comp)->caps)))
@@ -3034,8 +2657,6 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element)
     goto out;
   }
 
-  if (entry->nomorepadshandler)
-    wait_no_more_pads (comp, element, entry, FALSE);
   gst_object_ref (element);
   gst_element_set_locked_state (element, FALSE);
 
@@ -3069,6 +2690,7 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element)
   /* Make it possible to reuse the same object later */
   gnl_object_reset (GNL_OBJECT (element));
   gst_object_unref (element);
+
 out:
   return ret;
 }
index 5db4e44..2902726 100644 (file)
@@ -35,6 +35,8 @@ struct _GnlPadPrivate
   GstPadDirection dir;
   GstPadEventFunction eventfunc;
   GstPadQueryFunction queryfunc;
+
+  GstEvent *pending_seek;
 };
 
 static GstEvent *
@@ -489,7 +491,18 @@ ghostpad_event_function (GstPad * ghostpad, GstObject * parent,
     {
       switch (GST_EVENT_TYPE (event)) {
         case GST_EVENT_SEEK:
+        {
+          GstPad *target;
+
           event = translate_incoming_seek (object, event);
+          if (!(target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghostpad)))) {
+            priv->pending_seek = event;
+            GST_INFO_OBJECT (ghostpad, "No target set yet, "
+                "Will send the seek event when the target is set");
+            ret = TRUE;
+            event = NULL;
+          }
+        }
           break;
         default:
           break;
@@ -661,7 +674,7 @@ gnl_object_ghost_pad (GnlObject * object, const gchar * name, GstPad * target)
   g_return_val_if_fail (target, FALSE);
   g_return_val_if_fail ((dir != GST_PAD_UNKNOWN), FALSE);
 
-  ghost = gnl_object_ghost_pad_no_target (object, name, dir);
+  ghost = gnl_object_ghost_pad_no_target (object, name, dir, NULL);
   if (!ghost) {
     GST_WARNING_OBJECT (object, "Couldn't create ghostpad");
     return NULL;
@@ -692,17 +705,19 @@ gnl_object_ghost_pad (GnlObject * object, const gchar * name, GstPad * target)
  */
 GstPad *
 gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name,
-    GstPadDirection dir)
+    GstPadDirection dir, GstPadTemplate * template)
 {
   GstPad *ghost;
   GnlPadPrivate *priv;
 
   /* create a no_target ghostpad */
-  ghost = gst_ghost_pad_new_no_target (name, dir);
+  if (template)
+    ghost = gst_ghost_pad_new_no_target_from_template (name, template);
+  else
+    ghost = gst_ghost_pad_new_no_target (name, dir);
   if (!ghost)
     return NULL;
 
-  GST_DEBUG ("grabbing existing pad functions");
 
   /* remember the existing ghostpad event/query/link/unlink functions */
   priv = g_slice_new0 (GnlPadPrivate);
@@ -726,6 +741,8 @@ gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name,
   return ghost;
 }
 
+
+
 void
 gnl_object_remove_ghost_pad (GnlObject * object, GstPad * ghost)
 {
@@ -747,16 +764,32 @@ gnl_object_ghost_pad_set_target (GnlObject * object, GstPad * ghost,
   GnlPadPrivate *priv = gst_pad_get_element_private (ghost);
 
   g_return_val_if_fail (priv, FALSE);
+  g_return_val_if_fail (GST_IS_PAD (ghost), FALSE);
 
-  if (target)
-    GST_DEBUG_OBJECT (object, "setting target %s:%s on ghostpad",
-        GST_DEBUG_PAD_NAME (target));
-  else
-    GST_DEBUG_OBJECT (object, "removing target from ghostpad");
+  if (target) {
+    GST_DEBUG_OBJECT (object, "setting target %s:%s on %s:%s",
+        GST_DEBUG_PAD_NAME (target), GST_DEBUG_PAD_NAME (ghost));
+  } else {
+    GST_ERROR_OBJECT (object, "removing target from ghostpad");
+    priv->pending_seek = NULL;
+  }
 
   /* set target */
-  if (!(gst_ghost_pad_set_target (GST_GHOST_PAD (ghost), target)))
+  if (!(gst_ghost_pad_set_target (GST_GHOST_PAD (ghost), target))) {
+    GST_WARNING_OBJECT (priv->object, "Could not set ghost %s:%s "
+        "target to: %s:%s", GST_DEBUG_PAD_NAME (ghost),
+        GST_DEBUG_PAD_NAME (target));
     return FALSE;
+  }
+
+  if (target && priv->pending_seek) {
+    gboolean res = gst_pad_send_event (ghost, priv->pending_seek);
+
+    GST_INFO_OBJECT (object, "Sending our pending seek event: %" GST_PTR_FORMAT
+        " -- Result is %i", priv->pending_seek, res);
+
+    priv->pending_seek = NULL;
+  }
 
   return TRUE;
 }
index f43ab0d..a49924d 100644 (file)
@@ -33,7 +33,7 @@ GstPad *gnl_object_ghost_pad (GnlObject * object,
     const gchar * name, GstPad * target);
 
 GstPad *gnl_object_ghost_pad_no_target (GnlObject * object,
-    const gchar * name, GstPadDirection dir);
+    const gchar * name, GstPadDirection dir, GstPadTemplate *templ);
 
 gboolean gnl_object_ghost_pad_set_target (GnlObject * object,
     GstPad * ghost, GstPad * target);
index 0b749cd..5915817 100644 (file)
 GST_DEBUG_CATEGORY_STATIC (gnlobject_debug);
 #define GST_CAT_DEFAULT gnlobject_debug
 
-#define _do_init \
-  GST_DEBUG_CATEGORY_INIT (gnlobject_debug, "gnlobject", GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin Object base class");
-#define gnl_object_parent_class parent_class
-G_DEFINE_TYPE_WITH_CODE (GnlObject, gnl_object, GST_TYPE_BIN, _do_init);
+static GObjectClass *parent_class = NULL;
 
 /****************************************************
  *              Helper macros                       *
@@ -117,6 +114,9 @@ gnl_object_class_init (GnlObjectClass * klass)
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
   gnlobject_class = (GnlObjectClass *) klass;
+  GST_DEBUG_CATEGORY_INIT (gnlobject_debug, "gnlobject",
+      GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin object");
+  parent_class = g_type_class_ref (GST_TYPE_BIN);
 
   gobject_class->set_property = GST_DEBUG_FUNCPTR (gnl_object_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR (gnl_object_get_property);
@@ -243,7 +243,7 @@ gnl_object_class_init (GnlObjectClass * klass)
 }
 
 static void
-gnl_object_init (GnlObject * object)
+gnl_object_init (GnlObject * object, GnlObjectClass * klass)
 {
   object->start = object->pending_start = 0;
   object->duration = object->pending_duration = 0;
@@ -258,6 +258,12 @@ gnl_object_init (GnlObject * object)
   object->segment_rate = 1.0;
   object->segment_start = -1;
   object->segment_stop = -1;
+
+  object->srcpad = gnl_object_ghost_pad_no_target (object,
+      "src", GST_PAD_SRC,
+      gst_element_class_get_pad_template ((GstElementClass *) klass, "src"));
+
+  gst_element_add_pad (GST_ELEMENT (object), object->srcpad);
 }
 
 static void
@@ -653,3 +659,30 @@ gnl_object_reset (GnlObject * object)
   object->priority = 0;
   object->active = TRUE;
 }
+
+GType
+gnl_object_get_type (void)
+{
+  static volatile gsize type = 0;
+
+  if (g_once_init_enter (&type)) {
+    GType _type;
+    static const GTypeInfo info = {
+      sizeof (GnlObjectClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gnl_object_class_init,
+      NULL,
+      NULL,
+      sizeof (GnlObject),
+      0,
+      (GInstanceInitFunc) gnl_object_init,
+    };
+
+    _type = g_type_register_static (GST_TYPE_BIN,
+        "GnlObject", &info, G_TYPE_FLAG_ABSTRACT);
+    g_once_init_leave (&type, _type);
+  }
+  return type;
+
+}
index 4ba7dd8..d27bed6 100644 (file)
@@ -43,6 +43,8 @@ G_BEGIN_DECLS
 #define GNL_IS_OBJECT_CLASS(obj) \
   (G_TYPE_CHECK_CLASS_TYPE((klass),GNL_TYPE_OBJECT))
 
+#define GNL_OBJECT_SRC(obj) (((GnlObject *) obj)->srcpad)
+
 /**
  * GnlObjectFlags:
  * @GNL_OBJECT_IS_SOURCE:
@@ -84,6 +86,8 @@ struct _GnlObject
 {
   GstBin parent;
 
+  GstPad *srcpad;
+
   /* Time positionning */
   GstClockTime start;
   GstClockTime inpoint;
index dcc811f..77c8f6c 100644 (file)
@@ -40,7 +40,7 @@
 static GstStaticPadTemplate gnl_operation_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
-    GST_PAD_SOMETIMES,
+    GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
 static GstStaticPadTemplate gnl_operation_sink_template =
@@ -163,10 +163,9 @@ gnl_operation_dispose (GObject * object)
   GnlOperation *oper = (GnlOperation *) object;
 
   GST_DEBUG_OBJECT (object, "Disposing of source pad");
-  if (oper->ghostpad) {
-    gnl_object_remove_ghost_pad (GNL_OBJECT (oper), oper->ghostpad);
-    oper->ghostpad = NULL;
-  }
+
+  gnl_object_ghost_pad_set_target (GNL_OBJECT (object),
+      GNL_OBJECT (object)->srcpad, NULL);
 
   GST_DEBUG_OBJECT (object, "Disposing of sink pad(s)");
   while (oper->sinks) {
@@ -190,7 +189,6 @@ static void
 gnl_operation_init (GnlOperation * operation)
 {
   gnl_operation_reset (operation);
-  operation->ghostpad = NULL;
   operation->element = NULL;
 }
 
@@ -362,13 +360,8 @@ gnl_operation_add_element (GstBin * bin, GstElement * element)
         operation->element = element;
         operation->dynamicsinks = isdynamic;
 
-        /* Source ghostpad */
-        if (operation->ghostpad)
-          gnl_object_ghost_pad_set_target (GNL_OBJECT (operation),
-              operation->ghostpad, srcpad);
-        else
-          operation->ghostpad = gnl_object_ghost_pad (GNL_OBJECT (operation),
-              GST_PAD_NAME (srcpad), srcpad);
+        gnl_object_ghost_pad_set_target (GNL_OBJECT (operation),
+            GNL_OBJECT (operation)->srcpad, srcpad);
 
         /* Remove the reference get_src_pad gave us */
         gst_object_unref (srcpad);
index 3d6454b..52ed82a 100644 (file)
@@ -59,8 +59,6 @@ G_BEGIN_DECLS
   /* FIXME : We might need to use a lock to access this list */
   GList * sinks;               /* The sink ghostpads */
   
-  GstPad *ghostpad;            /* src ghostpad */
-
   GstElement *element;         /* controlled element */
 
   GstClockTime next_base_time;
index 47ee8c7..5a5680f 100644 (file)
@@ -35,7 +35,7 @@
 static GstStaticPadTemplate gnl_source_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
-    GST_PAD_SOMETIMES,
+    GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
 GST_DEBUG_CATEGORY_STATIC (gnlsource);
@@ -51,7 +51,6 @@ struct _GnlSourcePrivate
   gboolean dispose_has_run;
 
   gboolean dynamicpads;         /* TRUE if the controlled element has dynamic pads */
-  GstPad *ghostpad;             /* The source ghostpad */
   GstEvent *event;              /* queued event */
 
   gulong padremovedid;          /* signal handler for element pad-removed signal */
@@ -59,9 +58,10 @@ struct _GnlSourcePrivate
   gulong probeid;               /* source pad probe id */
 
   gboolean pendingblock;        /* We have a pending pad_block */
-  gboolean areblocked;          /* We already got blocked */
+  gboolean is_blocked;          /* We already got blocked */
   GstPad *ghostedpad;           /* Pad (to be) ghosted */
   GstPad *staticpad;            /* The only pad. We keep an extra ref */
+  gboolean got_seeked;
 };
 
 static gboolean gnl_source_prepare (GnlObject * object);
@@ -136,6 +136,7 @@ gnl_source_init (GnlSource * source)
 static void
 gnl_source_dispose (GObject * object)
 {
+  GnlObject *gnlobject = (GnlObject *) object;
   GnlSource *source = (GnlSource *) object;
   GnlSourcePrivate *priv = source->priv;
 
@@ -153,9 +154,8 @@ gnl_source_dispose (GObject * object)
   if (priv->event)
     gst_event_unref (priv->event);
 
-  if (priv->ghostpad)
-    gnl_object_remove_ghost_pad ((GnlObject *) object, priv->ghostpad);
-  priv->ghostpad = NULL;
+  if (priv->ghostedpad)
+    gnl_object_ghost_pad_set_target (gnlobject, gnlobject->srcpad, NULL);
 
   if (priv->staticpad) {
     gst_object_unref (priv->staticpad);
@@ -171,19 +171,20 @@ element_pad_added_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad,
 {
   GstCaps *srccaps;
   GnlSourcePrivate *priv = source->priv;
+  GnlObject *gnlobject = (GnlObject *) source;
 
   GST_DEBUG_OBJECT (source, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
 
-  if (priv->ghostpad || priv->pendingblock) {
+  if (priv->pendingblock) {
     GST_WARNING_OBJECT (source,
-        "We already have (pending) ghost-ed a valid source pad (ghostpad:%s:%s, pendingblock:%d",
-        GST_DEBUG_PAD_NAME (priv->ghostpad), priv->pendingblock);
+        "We already have (pending) ghost-ed a valid source pad (srcpad:%s:%s, pendingblock:%d",
+        GST_DEBUG_PAD_NAME (gnlobject->srcpad), priv->pendingblock);
     return;
   }
 
   /* FIXME: pass filter caps to query_caps directly */
   srccaps = gst_pad_query_caps (pad, NULL);
-  if (!gst_caps_can_intersect (srccaps, GNL_OBJECT (source)->caps)) {
+  if (gnlobject->caps && !gst_caps_can_intersect (srccaps, gnlobject->caps)) {
     gst_caps_unref (srccaps);
     GST_DEBUG_OBJECT (source, "Pad doesn't have valid caps, ignoring");
     return;
@@ -210,6 +211,7 @@ element_pad_removed_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad,
     GnlSource * source)
 {
   GnlSourcePrivate *priv = source->priv;
+  GnlObject *gnlobject = (GnlObject *) source;
 
   GST_DEBUG_OBJECT (source, "pad %s:%s (controlled pad %s:%s)",
       GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (priv->ghostedpad));
@@ -218,19 +220,17 @@ element_pad_removed_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad,
     GST_DEBUG_OBJECT (source,
         "The removed pad is the controlled pad, clearing up");
 
-    if (priv->ghostpad) {
-      GST_DEBUG_OBJECT (source, "Clearing up ghostpad");
+    GST_DEBUG_OBJECT (source, "Clearing up ghostpad");
 
-      priv->areblocked = FALSE;
-      if (priv->probeid) {
-        gst_pad_remove_probe (pad, priv->probeid);
-        priv->probeid = 0;
-      }
-
-      gnl_object_remove_ghost_pad ((GnlObject *) source, priv->ghostpad);
-      priv->ghostpad = NULL;
+    priv->is_blocked = FALSE;
+    if (priv->probeid) {
+      gst_pad_remove_probe (pad, priv->probeid);
+      priv->probeid = 0;
     }
 
+    gnl_object_ghost_pad_set_target (GNL_OBJECT (source), gnlobject->srcpad,
+        NULL);
+
     priv->pendingblock = FALSE;
     priv->ghostedpad = NULL;
   } else {
@@ -292,20 +292,24 @@ ghost_seek_pad (GnlSource * source)
 {
   GnlSourcePrivate *priv = source->priv;
   GstPad *pad = priv->ghostedpad;
+  GnlObject *gnlobject = (GnlObject *) source;
 
-  if (priv->ghostpad || !pad)
+  priv->got_seeked = TRUE;
+
+  if (!pad)
     goto beach;
 
   GST_DEBUG_OBJECT (source, "ghosting %s:%s", GST_DEBUG_PAD_NAME (pad));
 
-  priv->ghostpad = gnl_object_ghost_pad ((GnlObject *) source,
-      GST_PAD_NAME (pad), pad);
+  gnl_object_ghost_pad_set_target (gnlobject, gnlobject->srcpad, pad);
   GST_DEBUG_OBJECT (source, "emitting no more pads");
-  gst_pad_set_active (priv->ghostpad, TRUE);
+
+  /*FIXME : do that when going to PAUSED */
+  gst_pad_set_active (gnlobject->srcpad, TRUE);
 
   if (priv->event) {
     GST_DEBUG_OBJECT (source, "sending queued seek event");
-    if (!(gst_pad_send_event (priv->ghostpad, priv->event)))
+    if (!(gst_pad_send_event (gnlobject->srcpad, priv->event)))
       GST_ELEMENT_ERROR (source, RESOURCE, SEEK,
           (NULL), ("Sending initial seek to upstream element failed"));
     else
@@ -314,7 +318,7 @@ ghost_seek_pad (GnlSource * source)
   }
 
   GST_DEBUG_OBJECT (source, "about to unblock %s:%s", GST_DEBUG_PAD_NAME (pad));
-  priv->areblocked = FALSE;
+  priv->is_blocked = FALSE;
   if (priv->probeid) {
     gst_pad_remove_probe (pad, priv->probeid);
     priv->probeid = 0;
@@ -332,10 +336,10 @@ pad_blocked_cb (GstPad * pad, GstPadProbeInfo * info, GnlSource * source)
 {
   GST_DEBUG_OBJECT (pad, "probe callback");
 
-  if (!source->priv->ghostpad && !source->priv->areblocked) {
+  if (!source->priv->got_seeked && !source->priv->is_blocked) {
     GThread *lthread;
 
-    source->priv->areblocked = TRUE;
+    source->priv->is_blocked = TRUE;
     GST_DEBUG_OBJECT (pad, "starting thread to call ghost_seek_pad");
     lthread =
         g_thread_new ("gnlsourceseek", (GThreadFunc) ghost_seek_pad, source);
@@ -439,6 +443,7 @@ static gboolean
 gnl_source_remove_element (GstBin * bin, GstElement * element)
 {
   GnlSource *source = (GnlSource *) bin;
+  GnlObject *gnlobject = (GnlObject *) element;
   GnlSourcePrivate *priv = source->priv;
   gboolean pret;
 
@@ -452,11 +457,9 @@ gnl_source_remove_element (GstBin * bin, GstElement * element)
   }
 
   if (pret) {
-    /* remove ghostpad */
-    if (priv->ghostpad) {
-      gnl_object_remove_ghost_pad ((GnlObject *) bin, priv->ghostpad);
-      priv->ghostpad = NULL;
-    }
+    gnl_object_ghost_pad_set_target (GNL_OBJECT (source), gnlobject->srcpad,
+        NULL);
+    priv->got_seeked = FALSE;
 
     /* discard events */
     if (priv->event) {
@@ -485,12 +488,13 @@ static gboolean
 gnl_source_send_event (GstElement * element, GstEvent * event)
 {
   GnlSource *source = (GnlSource *) element;
+  GnlObject *gnlobject = (GnlObject *) element;
   gboolean res = TRUE;
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
-      if (source->priv->ghostpad)
-        res = gst_pad_send_event (source->priv->ghostpad, event);
+      if (source->priv->ghostedpad)
+        res = gst_pad_send_event (gnlobject->srcpad, event);
       else {
         if (source->priv->event)
           gst_event_unref (source->priv->event);
@@ -516,13 +520,15 @@ gnl_source_prepare (GnlObject * object)
   if (!source->element) {
     GST_WARNING_OBJECT (source,
         "GnlSource doesn't have an element to control !");
+    if (parent)
+      gst_object_unref (parent);
     return FALSE;
   }
 
-  GST_LOG_OBJECT (source, "ghostpad:%p, dynamicpads:%d",
-      priv->ghostpad, priv->dynamicpads);
+  GST_LOG_OBJECT (source, "srcpad:%p, dynamicpads:%d",
+      object->srcpad, priv->dynamicpads);
 
-  if (!(priv->ghostpad) && !priv->pendingblock) {
+  if (!(priv->got_seeked) && !priv->pendingblock) {
     GstPad *pad;
 
     GST_LOG_OBJECT (source, "no ghostpad and no dynamic pads");
@@ -568,22 +574,22 @@ gnl_source_cleanup (GnlObject * object)
   GnlSource *source = GNL_SOURCE (object);
   GnlSourcePrivate *priv = source->priv;
 
-  if (priv->ghostpad) {
-    GstPad *target = gst_ghost_pad_get_target ((GstGhostPad *) priv->ghostpad);
+  /* FIXME : should just be ghostedpad */
+  GstPad *target = gst_ghost_pad_get_target ((GstGhostPad *) object->srcpad);
 
-    if (target) {
-      if (priv->probeid) {
-        gst_pad_remove_probe (target, priv->probeid);
-        priv->probeid = 0;
-      }
-      gst_object_unref (target);
+  if (target) {
+    if (priv->probeid) {
+      gst_pad_remove_probe (target, priv->probeid);
+      priv->probeid = 0;
     }
-    gnl_object_remove_ghost_pad ((GnlObject *) source, priv->ghostpad);
-    priv->ghostpad = NULL;
-    priv->ghostedpad = NULL;
-    priv->areblocked = FALSE;
-    priv->pendingblock = FALSE;
+    gst_object_unref (target);
   }
 
+  gnl_object_ghost_pad_set_target (GNL_OBJECT (source), object->srcpad, NULL);
+  priv->got_seeked = FALSE;
+  priv->ghostedpad = NULL;
+  priv->is_blocked = FALSE;
+  priv->pendingblock = FALSE;
+
   return TRUE;
 }
index f4b7eb8..2f32a31 100644 (file)
@@ -26,8 +26,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments,
   /* Expected segments */
   collect->expected_segments = segments;
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (comp, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
@@ -562,8 +561,7 @@ GST_START_TEST (test_renegotiation)
       segment_new (1.0, GST_FORMAT_TIME,
           2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND));
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (comp, audioconvert);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
index 1710e2f..dab8ba3 100644 (file)
@@ -24,12 +24,7 @@ typedef struct
   GstElement *source3;
 } TestClosure;
 
-static int composition_pad_added;
-static int composition_pad_removed;
 static int seek_events;
-static gulong blockprobeid = 0;
-static GMutex pad_added_lock;
-static GCond pad_added_cond;
 
 static GstPadProbeReturn
 on_source1_pad_event_cb (GstPad * pad, GstPadProbeInfo * info,
@@ -41,35 +36,9 @@ on_source1_pad_event_cb (GstPad * pad, GstPadProbeInfo * info,
   return GST_PAD_PROBE_OK;
 }
 
-static void
-on_source1_pad_added_cb (GstElement * source, GstPad * pad, gpointer user_data)
-{
-  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
-      (GstPadProbeCallback) on_source1_pad_event_cb, NULL, NULL);
-}
-
-static void
-on_composition_pad_added_cb (GstElement * composition, GstPad * pad,
-    GstElement * sink)
-{
-  GstPad *s = gst_element_get_static_pad (sink, "sink");
-  gst_pad_link (pad, s);
-  ++composition_pad_added;
-  g_mutex_lock (&pad_added_lock);
-  g_cond_broadcast (&pad_added_cond);
-  g_mutex_unlock (&pad_added_lock);
-  gst_object_unref (s);
-}
-
-static void
-on_composition_pad_removed_cb (GstElement * composition, GstPad * pad,
-    GstElement * sink)
-{
-  ++composition_pad_removed;
-}
-
 GST_START_TEST (test_change_object_start_stop_in_current_stack)
 {
+  GstPad *srcpad;
   GstElement *pipeline;
   GstElement *comp, *source1, *def, *sink;
   GstBus *bus;
@@ -84,11 +53,7 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack)
   sink = gst_element_factory_make_or_warn ("fakesink", "sink");
   gst_bin_add_many (GST_BIN (pipeline), comp, sink, NULL);
 
-  /* connect to pad-added */
-  g_object_connect (comp, "signal::pad-added",
-      on_composition_pad_added_cb, sink, NULL);
-  g_object_connect (comp, "signal::pad-removed",
-      on_composition_pad_removed_cb, NULL, NULL);
+  gst_element_link (comp, sink);
 
   /*
      source1
@@ -98,8 +63,9 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack)
    */
 
   source1 = videotest_gnl_src ("source1", 0, 2 * GST_SECOND, 2, 2);
-  g_object_connect (source1, "signal::pad-added",
-      on_source1_pad_added_cb, NULL, NULL);
+  srcpad = gst_element_get_static_pad (source1, "src");
+  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
+      (GstPadProbeCallback) on_source1_pad_event_cb, NULL, NULL);
 
   /*
      def (default source)
@@ -161,9 +127,6 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack)
     }
   }
 
-  fail_unless_equals_int (composition_pad_added, 1);
-  fail_unless_equals_int (composition_pad_removed, 0);
-
   seek_events_before = seek_events;
 
   /* pipeline is paused at this point */
@@ -171,15 +134,13 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack)
   /* move source1 out of the active segment */
   g_object_set (source1, "start", (guint64) 4 * GST_SECOND, NULL);
   g_signal_emit_by_name (comp, "commit", TRUE, &ret);
-  fail_unless (seek_events > seek_events_before);
+  fail_unless (seek_events > seek_events_before, "%i > %i", seek_events,
+      seek_events_before);
 
   /* remove source1 from the composition, which will become empty and remove the
    * ghostpad */
   gst_bin_remove (GST_BIN (comp), source1);
 
-  fail_unless_equals_int (composition_pad_added, 1);
-  fail_unless_equals_int (composition_pad_removed, 1);
-
   g_object_set (source1, "start", (guint64) 0 * GST_SECOND, NULL);
   /* add the source again and check that the ghostpad is added again */
   gst_bin_add (GST_BIN (comp), source1);
@@ -234,177 +195,6 @@ GST_START_TEST (test_remove_invalid_object)
 
 GST_END_TEST;
 
-static GstPadProbeReturn
-pad_block (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
-{
-  GstPad *ghost;
-  GstBin *bin;
-
-  bin = GST_BIN (user_data);
-
-  GST_DEBUG_OBJECT (pad, "probe type:0x%x", GST_PAD_PROBE_INFO_TYPE (info));
-
-  ghost = gst_ghost_pad_new ("src", pad);
-  gst_pad_set_active (ghost, TRUE);
-
-  gst_element_add_pad (GST_ELEMENT (bin), ghost);
-
-  return GST_PAD_PROBE_REMOVE;
-}
-
-static void
-no_more_pads_test_cb (GObject * object, TestClosure * c)
-{
-  gboolean ret;
-
-  GST_WARNING ("NO MORE PADS");
-  gst_bin_add (GST_BIN (c->composition), c->source3);
-  g_signal_emit_by_name (c->composition, "commit", TRUE, &ret);
-}
-
-GST_START_TEST (test_no_more_pads_race)
-{
-  gboolean ret;
-  GstElement *source1, *source2, *source3;
-  GstBin *bin;
-  GstElement *videotestsrc1, *videotestsrc2;
-  GstElement *operation;
-  GstElement *composition;
-  GstElement *videomixer, *fakesink;
-  GstElement *pipeline;
-  GstBus *bus;
-  GstMessage *message;
-  GstPad *pad;
-  TestClosure closure;
-
-  /* We create a composition with an operation and three sources. The operation
-   * contains a videomixer instance and the three sources are videotestsrc's.
-   *
-   * One of the sources, source2, contains videotestsrc inside a bin. Initially
-   * the bin doesn't have a source pad. We do this to exercise the dynamic src
-   * pad code path in gnlcomposition. We block on the videotestsrc srcpad and in
-   * the pad block callback we ghost the pad and add the ghost to the parent
-   * bin. This makes gnlsource emit no-more-pads, which is used by
-   * gnlcomposition to link the source2:src pad to videomixer.
-   *
-   * We start with the composition containing operation and source1. We preroll
-   * and then add source2. Source2 will do what described above and emit
-   * no-more-pads. We connect to that no-more-pads and from there we add source3 to
-   * the composition. Adding a new source will make gnlcomposition deactivate
-   * the old stack and activate a new one. The new one contains operation,
-   * source1, source2 and source3. Source2 was active in the old stack as well and
-   * gnlcomposition is *still waiting* for no-more-pads to be emitted on it
-   * (since the no-more-pads emission is now blocked in our test's no-more-pads
-   * callback, calling gst_bin_add). In short, here, we're simulating a race between
-   * no-more-pads and someone modifying the composition.
-   *
-   * Activating the new stack, gnlcomposition calls compare_relink_single_node,
-   * which finds an existing source pad for source2 this time since we have
-   * already blocked and ghosted. It takes another code path that assumes that
-   * source2 doesn't have dynamic pads and *BOOM*.
-   */
-
-  pipeline = GST_ELEMENT (gst_pipeline_new (NULL));
-  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
-
-  composition = gst_element_factory_make ("gnlcomposition", "composition");
-  fakesink = gst_element_factory_make ("fakesink", NULL);
-  fail_unless (fakesink != NULL);
-  g_object_set (fakesink, "sync", TRUE, NULL);
-
-  /* operation */
-  operation = gst_element_factory_make ("gnloperation", "operation");
-  videomixer = gst_element_factory_make ("videomixer", "videomixer");
-  fail_unless (videomixer != NULL);
-  gst_bin_add (GST_BIN (operation), videomixer);
-  g_object_set (operation, "start", (guint64) 0 * GST_SECOND,
-      "duration", (guint64) 10 * GST_SECOND,
-      "inpoint", (guint64) 0 * GST_SECOND, "priority", 10, NULL);
-  gst_bin_add (GST_BIN (composition), operation);
-
-  /* source 1 */
-  source1 = gst_element_factory_make ("gnlsource", "source1");
-  videotestsrc1 = gst_element_factory_make ("videotestsrc", "videotestsrc1");
-  gst_bin_add (GST_BIN (source1), videotestsrc1);
-  g_object_set (source1, "start", (guint64) 0 * GST_SECOND, "duration",
-      (guint64) 5 * GST_SECOND, "inpoint", (guint64) 0 * GST_SECOND, "priority",
-      20, NULL);
-
-  /* source2 */
-  source2 = gst_element_factory_make ("gnlsource", "source2");
-  bin = GST_BIN (gst_bin_new (NULL));
-  videotestsrc2 = gst_element_factory_make ("videotestsrc", "videotestsrc2");
-  pad = gst_element_get_static_pad (videotestsrc2, "src");
-  blockprobeid =
-      gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
-      (GstPadProbeCallback) pad_block, bin, NULL);
-  gst_bin_add (bin, videotestsrc2);
-  gst_bin_add (GST_BIN (source2), GST_ELEMENT (bin));
-  g_object_set (source2, "start", (guint64) 0 * GST_SECOND, "duration",
-      (guint64) 5 * GST_SECOND, "inpoint", (guint64) 0 * GST_SECOND, "priority",
-      20, NULL);
-
-  /* source3 */
-  source3 = gst_element_factory_make ("gnlsource", "source3");
-  videotestsrc2 = gst_element_factory_make ("videotestsrc", "videotestsrc3");
-  gst_bin_add (GST_BIN (source3), videotestsrc2);
-  g_object_set (source3, "start", (guint64) 0 * GST_SECOND, "duration",
-      (guint64) 5 * GST_SECOND, "inpoint", (guint64) 0 * GST_SECOND, "priority",
-      20, NULL);
-
-  closure.composition = composition;
-  closure.source3 = source3;
-  g_object_connect (source2, "signal::no-more-pads",
-      no_more_pads_test_cb, &closure, NULL);
-
-  gst_bin_add (GST_BIN (composition), source1);
-  g_signal_emit_by_name (composition, "commit", TRUE, &ret);
-  g_object_connect (composition, "signal::pad-added",
-      on_composition_pad_added_cb, fakesink, NULL);
-  g_object_connect (composition, "signal::pad-removed",
-      on_composition_pad_removed_cb, NULL, NULL);
-
-  GST_DEBUG ("Adding composition to pipeline");
-
-  gst_bin_add_many (GST_BIN (pipeline), composition, fakesink, NULL);
-
-  GST_DEBUG ("Setting pipeline to PAUSED");
-
-  fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED)
-      == GST_STATE_CHANGE_FAILURE);
-
-  message = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
-      GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR);
-  if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
-    fail_error_message (message);
-  }
-  gst_message_unref (message);
-
-  GST_DEBUG ("Adding second source");
-
-  /* FIXME: maybe slow down the videotestsrc steaming thread */
-  gst_bin_add (GST_BIN (composition), source2);
-  g_signal_emit_by_name (composition, "commit", TRUE, &ret);
-
-  message =
-      gst_bus_timed_pop_filtered (bus, GST_SECOND / 10, GST_MESSAGE_ERROR);
-  if (message) {
-    if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
-      fail_error_message (message);
-    } else {
-      fail_if (TRUE);
-    }
-
-    gst_message_unref (message);
-  }
-
-  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
-  gst_object_unref (pipeline);
-  gst_object_unref (bus);
-}
-
-GST_END_TEST;
-
 GST_START_TEST (test_simple_adder)
 {
   GstBus *bus;
@@ -452,19 +242,13 @@ GST_START_TEST (test_simple_adder)
   g_object_set (gnlsource2, "start", (guint64) 0 * GST_SECOND,
       "duration", total_time, "inpoint", (guint64) 0 * GST_SECOND, "priority",
       2, NULL);
-  fail_unless (gst_bin_add (GST_BIN (composition), gnlsource2));
-
-  /* Connecting signals */
-  g_object_connect (composition, "signal::pad-added",
-      on_composition_pad_added_cb, fakesink, NULL);
-  g_object_connect (composition, "signal::pad-removed",
-      on_composition_pad_removed_cb, NULL, NULL);
-
 
   GST_DEBUG ("Adding composition to pipeline");
-
   gst_bin_add_many (GST_BIN (pipeline), composition, fakesink, NULL);
 
+  fail_unless (gst_bin_add (GST_BIN (composition), gnlsource2));
+  fail_unless (gst_element_link (composition, fakesink) == TRUE);
+
   GST_DEBUG ("Setting pipeline to PAUSED");
 
   g_signal_emit_by_name (composition, "commit", TRUE, &ret);
@@ -536,16 +320,8 @@ gnonlin_suite (void)
 
   suite_add_tcase (s, tc_chain);
 
-  g_cond_init (&pad_added_cond);
-  g_mutex_init (&pad_added_lock);
   tcase_add_test (tc_chain, test_change_object_start_stop_in_current_stack);
   tcase_add_test (tc_chain, test_remove_invalid_object);
-  if (gst_registry_check_feature_version (gst_registry_get (), "videomixer", 0,
-          11, 0)) {
-    tcase_add_test (tc_chain, test_no_more_pads_race);
-  } else {
-    GST_WARNING ("videomixer element not available, skipping 1 test");
-  }
 
   if (gst_registry_check_feature_version (gst_registry_get (), "adder", 1,
           0, 0)) {
index d6f7a78..72d6e43 100644 (file)
@@ -25,8 +25,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments)
   /* Expected segments */
   collect->expected_segments = segments;
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (comp, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
index e2d568a..e10cc4b 100644 (file)
@@ -39,8 +39,7 @@ GST_START_TEST (test_simple_videotestsrc)
       segment_new (1.0, GST_FORMAT_TIME,
           1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND));
 
-  g_signal_connect (G_OBJECT (gnlsource), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (gnlsource, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   fail_if (sinkpad == NULL);
@@ -139,8 +138,7 @@ GST_START_TEST (test_videotestsrc_in_bin)
   collect->expected_segments = g_list_append (collect->expected_segments,
       segment_new (1.0, GST_FORMAT_TIME, 0, 1 * GST_SECOND, 0));
 
-  g_signal_connect (G_OBJECT (gnlsource), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (gnlsource, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   fail_if (sinkpad == NULL);
index a3471d8..71240bf 100644 (file)
@@ -1,4 +1,5 @@
 #include "common.h"
+static const gchar *compositor_element = NULL;
 
 typedef struct _SeekInfo
 {
@@ -48,8 +49,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments, GList * seeks)
   collect->expected_segments = segments;
   collect->keep_expected_segments = TRUE;
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (comp, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
@@ -521,7 +521,8 @@ GST_START_TEST (test_complex_operations)
    */
 
   oper =
-      new_operation ("oper", "videomixer", 2 * GST_SECOND, 2 * GST_SECOND, 1);
+      new_operation ("oper", compositor_element, 2 * GST_SECOND, 2 * GST_SECOND,
+      1);
   fail_if (oper == NULL);
   check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND,
       2 * GST_SECOND);
@@ -639,7 +640,8 @@ GST_START_TEST (test_complex_operations_bis)
    */
 
   oper =
-      new_operation ("oper", "videomixer", 2 * GST_SECOND, 2 * GST_SECOND, 1);
+      new_operation ("oper", compositor_element, 2 * GST_SECOND, 2 * GST_SECOND,
+      1);
   fail_if (oper == NULL);
   check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND,
       2 * GST_SECOND);
@@ -751,12 +753,26 @@ gnonlin_suite (void)
 
   suite_add_tcase (s, tc_chain);
 
+  if (gst_registry_check_feature_version (gst_registry_get (), "compositor", 1,
+          0, 0)) {
+    compositor_element = "compositor";
+  } else if (gst_registry_check_feature_version (gst_registry_get (),
+          "videomixer", 1, 0, 0)) {
+    compositor_element = "videomixer";
+
+  }
+
   tcase_add_test (tc_chain, test_simplest);
   tcase_add_test (tc_chain, test_one_after_other);
   tcase_add_test (tc_chain, test_one_under_another);
   tcase_add_test (tc_chain, test_one_bin_after_other);
-  tcase_add_test (tc_chain, test_complex_operations);
-  tcase_add_test (tc_chain, test_complex_operations_bis);
+
+  if (compositor_element) {
+    tcase_add_test (tc_chain, test_complex_operations);
+    tcase_add_test (tc_chain, test_complex_operations_bis);
+  } else {
+    GST_WARNING ("No compositor element, can not run operations tests");
+  }
 
   return s;
 }
index c305a6c..47800a1 100644 (file)
@@ -52,9 +52,7 @@ test_simplest_full (void)
   collect->expected_segments = g_list_append (collect->expected_segments,
       segment_new (1.0, GST_FORMAT_TIME, 5 * GST_SECOND, 6 * GST_SECOND, 0));
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
-
+  gst_element_link (comp, sink);
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
       (GstPadProbeCallback) sinkpad_probe, collect, NULL);
@@ -282,8 +280,7 @@ test_one_after_other_full (void)
       segment_new (1.0, GST_FORMAT_TIME,
           2 * GST_SECOND, 3 * GST_SECOND, 1 * GST_SECOND));
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (comp, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
@@ -485,8 +482,7 @@ test_one_under_another_full (void)
       segment_new (1.0, GST_FORMAT_TIME,
           2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND));
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (comp, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
@@ -634,8 +630,7 @@ test_one_bin_after_other_full (void)
       segment_new (1.0, GST_FORMAT_TIME,
           1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND));
 
-  g_signal_connect (G_OBJECT (comp), "pad-added",
-      G_CALLBACK (composition_pad_added_cb), collect);
+  gst_element_link (comp, sink);
 
   sinkpad = gst_element_get_static_pad (sink, "sink");
   gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,