From ff8f94c41fcaead906d97c8b61f42e16366c5901 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 21:57:49 +0200 Subject: composition: Implement a separate probe to drop data. It ensures that all data that still flows while we update the pipeline is dropped, otherwise we have races where we could get buffer from the old pipeline flowing into elements that are already fully flushed (and have no segment caps, etc... set) Also validate the stack a little later. This commits finnishes what had been started with a24a3be13b81c5d0080c061edf61daece6341f95 --- gnl/gnlcomposition.c | 72 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/gnl/gnlcomposition.c b/gnl/gnlcomposition.c index 006ed4e..376e483 100644 --- a/gnl/gnlcomposition.c +++ b/gnl/gnlcomposition.c @@ -258,6 +258,7 @@ static void update_start_stop_duration (GnlComposition * comp); struct _GnlCompositionEntry { GnlObject *object; + GnlComposition *comp; /* handler id for 'no-more-pads' signal */ gulong nomorepadshandler; @@ -266,6 +267,7 @@ struct _GnlCompositionEntry /* handler id for block probe */ gulong probeid; + gulong dataprobeid; }; static void @@ -339,11 +341,28 @@ gnl_composition_class_init (GnlCompositionClass * klass) static void 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; + } + + if (entry->dataprobeid) { + gst_pad_remove_probe (srcpad, entry->dataprobeid); + entry->dataprobeid = 0; + } + gst_object_unref (srcpad); + } + g_slice_free (GnlCompositionEntry, entry); } @@ -1210,12 +1229,20 @@ pad_blocked (GstPad * pad, GstPadProbeInfo * info, GnlComposition * comp) { GST_DEBUG_OBJECT (comp, "Pad : %s:%s", GST_DEBUG_PAD_NAME (pad)); + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +drop_data (GstPad * pad, GstPadProbeInfo * info, GnlCompositionEntry * entry) +{ + GnlCompositionPrivate *priv = entry->comp->priv; + /* When updating the pipeline, do not let data flowing */ - if (comp->priv->stackvalid == FALSE && - GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info))) + if (priv->stackvalid == FALSE || priv->childseek != NULL) return GST_PAD_PROBE_DROP; - return GST_PAD_PROBE_OK; + entry->dataprobeid = 0; + return GST_PAD_PROBE_REMOVE; } static inline void @@ -1296,6 +1323,12 @@ gnl_composition_ghost_pad_set_target (GnlComposition * comp, GstPad * target, (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, + (GstPadProbeCallback) drop_data, priv->toplevelentry, NULL); + } + /* remove event probe */ if (priv->ghosteventprobe) { gst_pad_remove_probe (ptarget, priv->ghosteventprobe); @@ -2219,6 +2252,11 @@ compare_relink_single_node (GnlComposition * comp, GNode * node, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE, (GstPadProbeCallback) pad_blocked, comp, NULL); } + if (!oldentry->dataprobeid) { + oldentry->dataprobeid = gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) drop_data, oldentry, NULL); + } } entry = COMP_ENTRY (comp, newobj); @@ -2371,6 +2409,11 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node, 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, + (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 @@ -2674,8 +2717,6 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, if (priv->current) { GstEvent *event; - priv->stackvalid = TRUE; - /* 7.1. Create new seek event for newly configured timeline stack */ if (samestack && (startchanged || stopchanged)) event = @@ -2734,6 +2775,7 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, priv->childseek = event; ret = TRUE; } + priv->stackvalid = TRUE; } else { if ((!priv->objects_start) && priv->ghostpad) { GST_DEBUG_OBJECT (comp, "composition is now empty, removing ghostpad"); @@ -2770,6 +2812,10 @@ object_pad_removed (GnlObject * object, GstPad * pad, GnlComposition * comp) gst_pad_remove_probe (pad, entry->probeid); entry->probeid = 0; } + if (entry && entry->dataprobeid) { + gst_pad_remove_probe (pad, entry->dataprobeid); + entry->dataprobeid = 0; + } } } } @@ -2793,6 +2839,12 @@ object_pad_added (GnlObject * object G_GNUC_UNUSED, GstPad * 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, + (GstPadProbeCallback) drop_data, entry, NULL); + } } static gboolean @@ -2841,6 +2893,7 @@ gnl_composition_add_object (GstBin * bin, GstElement * element) /* wrap new element in a GnlCompositionEntry ... */ entry = g_slice_new0 (GnlCompositionEntry); entry->object = (GnlObject *) element; + entry->comp = comp; if (GNL_OBJECT_IS_EXPANDABLE (element)) { /* Only react on non-default objects properties */ @@ -2911,8 +2964,6 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element) gboolean ret = FALSE; gboolean update_required; GnlCompositionEntry *entry; - GstPad *srcpad; - gulong probeid; GST_DEBUG_OBJECT (bin, "element %s", GST_OBJECT_NAME (element)); @@ -2941,8 +2992,6 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element) GST_LOG_OBJECT (element, "Removed from the objects start/stop list"); } - probeid = entry->probeid; - g_hash_table_remove (priv->objects_hash, element); update_required = OBJECT_IN_ACTIVE_SEGMENT (comp, element) || (GNL_OBJECT_PRIORITY (element) == G_MAXUINT32) || @@ -2957,11 +3006,6 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element) GST_LOG_OBJECT (element, "Done removing from the composition, now updating"); COMP_OBJECTS_UNLOCK (comp); - /* unblock source pad */ - if (probeid && (srcpad = get_src_pad (element))) { - gst_pad_remove_probe (srcpad, probeid); - gst_object_unref (srcpad); - } /* Make it possible to reuse the same object later */ gnl_object_reset (GNL_OBJECT (element)); -- cgit v1.2.3