+2006-10-02 Edward Hervey <edward@fluendo.com>
+
+ * 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 <wim@fluendo.com>
Patch by: mrcgran <mrc.gran at gmail dot com>
The flushing event is used to clear any data out of the
downstream elements.
+* Generic case
+
Consider the following pipeline:
.-----. .-------. .-------.
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:
----------
gst_pad_set_blocked_async
GstPadBlockCallback
gst_pad_is_blocked
+gst_pad_is_blocking
gst_pad_add_data_probe
gst_pad_add_buffer_probe
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
}
/**
+ * 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.
* @activate: the #GstPadActivateFunction to set.
/*
* 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
* - 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
* 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 */
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
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;
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))) {
* @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
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;
#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))
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);