Index: docs/design/part-block.txt
===================================================================
RCS file: /cvs/gstreamer/gstreamer/docs/design/part-block.txt,v
retrieving revision 1.2
diff -u -p -r1.2 part-block.txt
--- docs/design/part-block.txt	3 Jul 2006 17:44:09 -0000	1.2
+++ docs/design/part-block.txt	2 Oct 2006 13:24:43 -0000
@@ -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:
 ----------
Index: docs/gst/gstreamer-sections.txt
===================================================================
RCS file: /cvs/gstreamer/gstreamer/docs/gst/gstreamer-sections.txt,v
retrieving revision 1.274
diff -u -p -r1.274 gstreamer-sections.txt
--- docs/gst/gstreamer-sections.txt	15 Sep 2006 08:39:56 -0000	1.274
+++ docs/gst/gstreamer-sections.txt	2 Oct 2006 13:24:44 -0000
@@ -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
Index: gst/gstpad.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstpad.c,v
retrieving revision 1.526
diff -u -p -r1.526 gstpad.c
--- gst/gstpad.c	1 Sep 2006 15:55:20 -0000	1.526
+++ gst/gstpad.c	2 Oct 2006 13:24:44 -0000
@@ -962,6 +962,9 @@ gst_pad_set_blocked_async (GstPad * pad,
   if (blocked) {
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocking pad");
 
+    /* make sure the blocking flag is properly unset before using it */
+    GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING);
+
     GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKED);
     pad->block_callback = callback;
     pad->block_data = user_data;
@@ -1049,6 +1052,35 @@ gst_pad_is_blocked (GstPad * pad)
 }
 
 /**
+ * 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.
@@ -3141,7 +3176,7 @@ gst_ghost_pad_save_thyself (GstPad * pad
 
 /*
  * 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 +3198,11 @@ gst_ghost_pad_save_thyself (GstPad * pad
  * - 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 +3255,8 @@ 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 */
@@ -3821,9 +3868,9 @@ gst_pad_push_event (GstPad * pad, GstEve
     case GST_EVENT_FLUSH_START:
       GST_PAD_SET_FLUSHING (pad);
 
-      if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
+      if (G_UNLIKELY (GST_PAD_IS_BLOCKED(pad) && 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 +3879,13 @@ gst_pad_push_event (GstPad * pad, GstEve
     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_BLOCKED (pad) && 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;
+      }
       break;
     default:
       if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
Index: gst/gstpad.h
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstpad.h,v
retrieving revision 1.210
diff -u -p -r1.210 gstpad.h
--- gst/gstpad.h	6 Jul 2006 15:21:46 -0000	1.210
+++ gst/gstpad.h	2 Oct 2006 13:24:44 -0000
@@ -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 +793,7 @@ gboolean		gst_pad_set_blocked			(GstPad 
 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);
