From 8923a57a6f5d22baaf74437b8981d388424e59b7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Oct 2006 16:01:54 +0000 Subject: [PATCH] docs/design/part-block.txt: Further explain the use of flushing on blocked pads. Original commit message from CVS: * docs/design/part-block.txt: Further explain the use of flushing on blocked pads. * docs/gst/gstreamer-sections.txt: * gst/gstpad.c: (gst_pad_is_blocking), (handle_pad_block), (gst_pad_push_event): * gst/gstpad.h: Added new GstPadFlag : GST_PAD_BLOCKING. Adds the notion of pads really blocking, which enables to properly handle FLUSH_START/FLUSH_STOP events on blocked pads. Fixes #358999 API: gst_pad_is_blocking() API: GST_PAD_IS_BLOCKING() macro API: GST_PAD_BLOCKING GstPadFlag --- ChangeLog | 17 ++++++++++ docs/design/part-block.txt | 35 +++++++++++++++++++++ docs/gst/gstreamer-sections.txt | 2 ++ gst/gstpad.c | 56 ++++++++++++++++++++++++++++++--- gst/gstpad.h | 4 +++ 5 files changed, 110 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 198cf57401..2740c66d11 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2006-10-02 Edward Hervey + + * docs/design/part-block.txt: + Further explain the use of flushing on blocked pads. + * docs/gst/gstreamer-sections.txt: + * gst/gstpad.c: (gst_pad_is_blocking), (handle_pad_block), + (gst_pad_push_event): + * gst/gstpad.h: + Added new GstPadFlag : GST_PAD_BLOCKING. + Adds the notion of pads really blocking, which enables to properly + handle FLUSH_START/FLUSH_STOP events on blocked pads. + Fixes #358999 + API: gst_pad_is_blocking() + API: GST_PAD_IS_BLOCKING() macro + API: GST_PAD_BLOCKING GstPadFlag + + 2006-10-02 Wim Taymans Patch by: mrcgran diff --git a/docs/design/part-block.txt b/docs/design/part-block.txt index c5a3edda37..c53a700953 100644 --- a/docs/design/part-block.txt +++ b/docs/design/part-block.txt @@ -23,6 +23,8 @@ Flushing The flushing event is used to clear any data out of the downstream elements. +* Generic case + Consider the following pipeline: .-----. .-------. .-------. @@ -48,6 +50,39 @@ Flushing fr the same reason. From then on, the new data after the flushing seek will be queued when the pad block is taken again. +* Case where the stream is blocking downstream + + The example above is only valid if the elem1.src pad is really blocking + (callback called or sync block returned). + + In the case where the stream is blocking further downstream (on elem2.src + for example, or on a blocking queue), extra care has to be taken. + + Consider the following pipeline: + + .-----. .-------. .-------. + | src | | elem1 |\/ | elem2 | + | src -> sink src -> sink src .... Blocking somewhere downstream + '-----' '-------'/\ '-------' + + A pad block has been requested by the user on elem1.src , but since the stream + is blocking somewhere downstream, the callback is not called or the sync block + does not return. + + In order for the block to happen, a FLUSH_START needs to be: + _ either sent directly on the downstream blocking element/pad so that it + release the stream lock, and it gives a chance for the elem1.src pad to + block. + _ A FLUSH_START is sent downstream from an upstream element, causing all the + pads down to the blocking element/pad (including elem1.src) to go to the + FLUSHING state. A FLUSH_STOP can now be sent downstream, causing all the + pads down to the previously blocking element to unset their FLUSHING state. + The next push will then properly block on elem1.src. + + In this case, the pads have to be careful when handling the FLUSH events + forwarding. Those events should only be forwarded downstream is the BLOCKED + pad was previously BLOCKING. + Use cases: ---------- diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 2c260bdf1d..072e6892e3 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -1183,6 +1183,7 @@ gst_pad_set_blocked gst_pad_set_blocked_async GstPadBlockCallback gst_pad_is_blocked +gst_pad_is_blocking gst_pad_add_data_probe gst_pad_add_buffer_probe @@ -1345,6 +1346,7 @@ GST_PAD_ACTIVATE_MODE GST_PAD_DO_BUFFER_SIGNALS GST_PAD_DO_EVENT_SIGNALS GST_PAD_IS_BLOCKED +GST_PAD_IS_BLOCKING GST_PAD_IS_IN_SETCAPS GST_PAD_SET_FLUSHING GST_PAD_TASK diff --git a/gst/gstpad.c b/gst/gstpad.c index 689a42a46c..54c1c57c1d 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -1048,6 +1048,35 @@ gst_pad_is_blocked (GstPad * pad) return result; } +/** + * gst_pad_is_blocking: + * @pad: the #GstPad to query + * + * Checks if the pad is blocking or not. This is a guaranteed state + * of whether the pad is actually blocking on a #GstBuffer or a #GstEvent. + * + * Returns: TRUE if the pad is blocking. + * + * MT safe. + */ +gboolean +gst_pad_is_blocking (GstPad * pad) +{ + gboolean result = FALSE; + + g_return_val_if_fail (GST_IS_PAD (pad), result); + + GST_OBJECT_LOCK (pad); + + /* the blocking flag is only valid if the pad is not flushing */ + + result = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKING) && + !GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLUSHING); + GST_OBJECT_UNLOCK (pad); + + return result; +} + /** * gst_pad_set_activate_function: * @pad: a #GstPad. @@ -3141,7 +3170,7 @@ gst_ghost_pad_save_thyself (GstPad * pad, xmlNodePtr parent) /* * should be called with pad OBJECT_LOCK and STREAM_LOCK held. - * GST_PAD_IS_BLOCK (pad) == TRUE when this function is + * GST_PAD_IS_BLOCKED (pad) == TRUE when this function is * called. * * This function perform the pad blocking when an event, buffer push @@ -3163,6 +3192,11 @@ gst_ghost_pad_save_thyself (GstPad * pad, xmlNodePtr parent) * - the GCond signal method, which makes any thread unblock when * the pad block happens. * + * During the actual blocking state, the GST_PAD_BLOCKING flag is set. + * The GST_PAD_BLOCKING flag is unset when the GST_PAD_FLUSHING flag is + * unset. This is to know whether the pad was blocking when GST_PAD_FLUSHING + * was set. + * * MT safe. */ static GstFlowReturn @@ -3215,6 +3249,9 @@ handle_pad_block (GstPad * pad) * deactivate the pad (which will also set the FLUSHING flag) or * when the pad is unblocked. A flushing event will also unblock * the pad after setting the FLUSHING flag. */ + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "Waiting to be unblocked or set flushing"); + GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKING); GST_PAD_BLOCK_WAIT (pad); /* see if we got unlocked by a flush or not */ @@ -3222,6 +3259,10 @@ handle_pad_block (GstPad * pad) goto flushing; } + /* If we made it here we either never blocked, or were unblocked because we + * weren't flushing, it is therefore safe to remove the BLOCKING flag */ + GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING); + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "got unblocked"); /* when we get here, the pad is unblocked again and we perform @@ -3821,9 +3862,9 @@ gst_pad_push_event (GstPad * pad, GstEvent * event) case GST_EVENT_FLUSH_START: GST_PAD_SET_FLUSHING (pad); - if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) { + if (G_UNLIKELY (GST_PAD_IS_BLOCKING (pad))) { /* flush start will have set the FLUSHING flag and will then - * unlock all threads doing a GCond wait on the blocked pad. This + * unlock all threads doing a GCond wait on the blocking pad. This * will typically unblock the STREAMING thread blocked on a pad. */ GST_PAD_BLOCK_SIGNAL (pad); goto flushed; @@ -3832,8 +3873,15 @@ gst_pad_push_event (GstPad * pad, GstEvent * event) case GST_EVENT_FLUSH_STOP: GST_PAD_UNSET_FLUSHING (pad); - if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) + /* If pad was blocking on something when the pad received flush-start, we + * don't forward the flush-stop event either. */ + if (G_UNLIKELY (GST_PAD_IS_BLOCKING (pad))) { + GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING); + GST_LOG_OBJECT (pad, + "Pad was previously blocking, not forwarding flush-stop"); goto flushed; + } + GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING); break; default: if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) { diff --git a/gst/gstpad.h b/gst/gstpad.h index 8079ee6a91..9d1e751041 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -479,6 +479,7 @@ typedef enum { * @GST_PAD_FLUSHING: is pad refusing buffers * @GST_PAD_IN_GETCAPS: GstPadGetCapsFunction() is running now * @GST_PAD_IN_SETCAPS: GstPadSetCapsFunction() is running now + * @GST_PAD_BLOCKING: is pad currently blocking on a buffer or event * @GST_PAD_FLAG_LAST: offset to define more flags * * Pad state flags @@ -488,6 +489,7 @@ typedef enum { GST_PAD_FLUSHING = (GST_OBJECT_FLAG_LAST << 1), GST_PAD_IN_GETCAPS = (GST_OBJECT_FLAG_LAST << 2), GST_PAD_IN_SETCAPS = (GST_OBJECT_FLAG_LAST << 3), + GST_PAD_BLOCKING = (GST_OBJECT_FLAG_LAST << 4), /* padding */ GST_PAD_FLAG_LAST = (GST_OBJECT_FLAG_LAST << 8) } GstPadFlags; @@ -655,6 +657,7 @@ struct _GstPadClass { #define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL) #define GST_PAD_IS_BLOCKED(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKED)) +#define GST_PAD_IS_BLOCKING(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKING)) #define GST_PAD_IS_FLUSHING(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLUSHING)) #define GST_PAD_IS_IN_GETCAPS(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_IN_GETCAPS)) #define GST_PAD_IS_IN_SETCAPS(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_IN_SETCAPS)) @@ -771,6 +774,7 @@ gboolean gst_pad_set_blocked (GstPad *pad, gboolean blocked); gboolean gst_pad_set_blocked_async (GstPad *pad, gboolean blocked, GstPadBlockCallback callback, gpointer user_data); gboolean gst_pad_is_blocked (GstPad *pad); +gboolean gst_pad_is_blocking (GstPad *pad); void gst_pad_set_element_private (GstPad *pad, gpointer priv); gpointer gst_pad_get_element_private (GstPad *pad);