diff --git a/gst/gstpad.c b/gst/gstpad.c index 91ed54115c..5f540e88cb 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -121,7 +121,7 @@ static void gst_pad_set_property (GObject * object, guint prop_id, static void gst_pad_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstFlowReturn handle_pad_block (GstPad * pad); +static GstFlowReturn handle_pad_block (GstPad * pad, GstBlockType type); static GstCaps *gst_pad_get_caps_unlocked (GstPad * pad, GstCaps * filter); static void gst_pad_set_pad_template (GstPad * pad, GstPadTemplate * templ); static gboolean gst_pad_activate_default (GstPad * pad); @@ -1070,24 +1070,16 @@ gst_pad_is_active (GstPad * pad) } /** - * gst_pad_set_blocked: + * gst_pad_block: * @pad: the #GstPad to block or unblock - * @blocked: boolean indicating whether the pad should be blocked or unblocked - * @callback: #GstPadBlockCallback that will be called when the - * operation succeeds + * @type: the different pad block states + * @callback: #GstPadBlockCallback that will be called with notifications of + * the pad block state * @user_data: (closure): user data passed to the callback * @destroy_data: #GDestroyNotify for user_data * - * Blocks or unblocks the dataflow on a pad. The provided callback - * is called when the operation succeeds; this happens right before the next - * attempt at pushing a buffer on the pad. - * - * This can take a while as the pad can only become blocked when real dataflow - * is happening. - * When the pipeline is stalled, for example in PAUSED, this can - * take an indeterminate amount of time. - * You can pass NULL as the callback to make this call block. Be careful with - * this blocking call as it might not return for reasons stated above. + * Blocks the dataflow on a pad. The provided callback is called with + * notifications about the different stages in the pad block. * * <note> * Pad block handlers are only called for source pads in push mode @@ -1095,89 +1087,106 @@ gst_pad_is_active (GstPad * pad) * </note> * * Returns: TRUE if the pad could be blocked. This function can fail if the - * wrong parameters were passed or the pad was already in the requested state. + * wrong parameters were passed or the pad was already blocked. * * MT safe. */ gboolean -gst_pad_set_blocked (GstPad * pad, gboolean blocked, +gst_pad_block (GstPad * pad, GstBlockType type, GstPadBlockCallback callback, gpointer user_data, GDestroyNotify destroy_data) { - gboolean was_blocked = FALSE; - g_return_val_if_fail (GST_IS_PAD (pad), FALSE); + g_return_val_if_fail (callback != NULL, FALSE); GST_OBJECT_LOCK (pad); - was_blocked = GST_PAD_IS_BLOCKED (pad); + if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) + goto was_blocked; - if (G_UNLIKELY (was_blocked == blocked)) - goto had_right_state; + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocking pad"); - if (blocked) { - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocking pad"); + GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKED); - GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKED); + if (pad->block_destroy_data && pad->block_data) + pad->block_destroy_data (pad->block_data); - if (pad->block_destroy_data && pad->block_data) - pad->block_destroy_data (pad->block_data); + /* always store the block_cb */ + pad->block_type = type; + pad->block_callback = callback; + pad->block_data = user_data; + pad->block_destroy_data = destroy_data; + pad->block_callback_called = FALSE; - pad->block_callback = callback; - pad->block_data = user_data; - pad->block_destroy_data = destroy_data; - pad->block_callback_called = FALSE; - if (!callback) { - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "waiting for block"); - GST_PAD_BLOCK_WAIT (pad); - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocked"); - } + if (pad->priv->using > 0) { + /* the pad is in use, we can't signal the idle callback yet. Since we set the + * flag above, the last thread to leave the push will do the callback. New + * threads going into the push will block. */ + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pad is in use"); + GST_OBJECT_UNLOCK (pad); } else { - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocking pad"); + /* the pad is idle now, we can signal the idle callback now */ + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pad is idle"); + GST_OBJECT_UNLOCK (pad); - if (GST_PAD_IS_SRC (pad)) { - GstPad *peer; - /* a pad block dropped all events, make sure we copy any new events on the - * srcpad to the sinkpad and schedule an update on the sinkpad */ - if ((peer = GST_PAD_PEER (pad))) { - GST_OBJECT_LOCK (peer); - prepare_event_update (pad, peer); - GST_OBJECT_UNLOCK (peer); - } - } - - GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKED); - - if (pad->block_destroy_data && pad->block_data) - pad->block_destroy_data (pad->block_data); - - pad->block_callback = callback; - pad->block_data = user_data; - pad->block_destroy_data = destroy_data; - pad->block_callback_called = FALSE; - - GST_PAD_BLOCK_BROADCAST (pad); - if (!callback) { - /* no callback, wait for the unblock to happen */ - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "waiting for unblock"); - GST_PAD_BLOCK_WAIT (pad); - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocked"); - } + /* call the callback if we need to be called for idle callbacks */ + if (type & GST_BLOCK_TYPE_IDLE) + callback (pad, GST_BLOCK_TYPE_IDLE, user_data); } - GST_OBJECT_UNLOCK (pad); - return TRUE; -had_right_state: +was_blocked: { - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, - "pad was in right state (%d)", was_blocked); + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pad was blocked"); GST_OBJECT_UNLOCK (pad); return FALSE; } } +/** + * gst_pad_unblock: + * @pad: the #GstPad to unblock + * + * Unblock @pad. All pending and current pad blocks, if any, are canceled. After + * this method, dataflow will continue on @pad. + * + * MT safe. + */ +void +gst_pad_unblock (GstPad * pad) +{ + g_return_if_fail (GST_IS_PAD (pad)); + + GST_OBJECT_LOCK (pad); + + if (G_UNLIKELY (!GST_PAD_IS_BLOCKED (pad))) + goto had_right_state; + + /* cleanup */ + if (pad->block_destroy_data && pad->block_data) + pad->block_destroy_data (pad->block_data); + + pad->block_type = 0; + pad->block_callback = NULL; + pad->block_data = NULL; + pad->block_destroy_data = NULL; + + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocking pad"); + GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKED); + GST_PAD_BLOCK_BROADCAST (pad); + GST_OBJECT_UNLOCK (pad); + + return; + +had_right_state: + { + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pad was unblocked"); + GST_OBJECT_UNLOCK (pad); + return; + } +} + /** * gst_pad_is_blocked: * @pad: the #GstPad to query @@ -2694,7 +2703,7 @@ gst_pad_set_caps (GstPad * pad, GstCaps * caps) event = gst_event_new_caps (caps); if (GST_PAD_IS_SRC (pad)) - gst_pad_push_event (pad, event); + res = gst_pad_push_event (pad, event); else res = gst_pad_send_event (pad, event); @@ -3466,7 +3475,7 @@ gst_pad_query_default (GstPad * pad, GstQuery * query) * MT safe. */ static GstFlowReturn -handle_pad_block (GstPad * pad) +handle_pad_block (GstPad * pad, GstBlockType type) { GstPadBlockCallback callback; gpointer user_data; @@ -3493,22 +3502,19 @@ handle_pad_block (GstPad * pad) * some other thread is doing a GCond wait. */ callback = pad->block_callback; pad->block_callback_called = TRUE; - if (callback) { - /* there is a callback installed, call it. We release the - * lock so that the callback can do something usefull with the - * pad */ + if ((pad->block_type & type) == pad->block_type) { user_data = pad->block_data; GST_OBJECT_UNLOCK (pad); - callback (pad, TRUE, user_data); - GST_OBJECT_LOCK (pad); + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "calling block callback"); + /* Call the callback. We release the lock so that the callback can + * do something usefull with the pad */ + callback (pad, type, user_data); + + GST_OBJECT_LOCK (pad); /* we released the lock, recheck flushing */ if (GST_PAD_IS_FLUSHING (pad)) goto flushing; - } else { - /* no callback, signal the thread that is doing a GCond wait - * if any. */ - GST_PAD_BLOCK_BROADCAST (pad); } } while (pad->block_callback_called == FALSE && GST_PAD_IS_BLOCKED (pad)); @@ -3535,20 +3541,6 @@ handle_pad_block (GstPad * pad) GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "got unblocked"); - /* when we get here, the pad is unblocked again and we perform - * the needed unblock code. */ - callback = pad->block_callback; - if (callback) { - /* we need to call the callback */ - user_data = pad->block_data; - GST_OBJECT_UNLOCK (pad); - callback (pad, FALSE, user_data); - GST_OBJECT_LOCK (pad); - } else { - /* we need to signal the thread waiting on the GCond */ - GST_PAD_BLOCK_BROADCAST (pad); - } - gst_object_unref (pad); return ret; @@ -3684,6 +3676,8 @@ gst_pad_emit_have_data_signal (GstPad * pad, GstMiniObject * obj) else detail = 0; + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "Emiting have-data signal"); + /* actually emit */ g_signal_emitv (args, gst_pad_signals[PAD_HAVE_DATA], detail, &ret); res = g_value_get_boolean (&ret); @@ -3952,22 +3946,24 @@ static GstFlowReturn pad_pre_push (GstPad * pad, GstPad ** peer, gpointer data) { GstFlowReturn ret; - gboolean need_probes, did_probes = FALSE; + gboolean need_probes, do_probes = TRUE; again: GST_OBJECT_LOCK (pad); /* FIXME: this check can go away; pad_set_blocked could be implemented with * probes completely or probes with an extended pad block. */ while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) - if ((ret = handle_pad_block (pad)) != GST_FLOW_OK) + if ((ret = + handle_pad_block (pad, + GST_BLOCK_TYPE_PUSH | GST_BLOCK_TYPE_DATA) != GST_FLOW_OK)) goto flushed; need_probes = GST_PAD_DO_BUFFER_SIGNALS (pad) > 0; /* we emit signals on the pad arg, the peer will have a chance to * emit in the _chain() function */ - if (G_UNLIKELY (need_probes && !did_probes)) { - did_probes = TRUE; + if (G_UNLIKELY (need_probes && do_probes)) { + do_probes = FALSE; /* unlock before emitting */ GST_OBJECT_UNLOCK (pad); @@ -4015,6 +4011,23 @@ pad_post_push (GstPad * pad) { GST_OBJECT_LOCK (pad); pad->priv->using--; + if (pad->priv->using == 0) { + /* pad is not active anymore, check if we need to trigger the block */ + if (GST_PAD_IS_BLOCKED (pad)) { + GstPadBlockCallback callback; + gpointer user_data; + + callback = pad->block_callback; + user_data = pad->block_data; + GST_PAD_BLOCK_BROADCAST (pad); + GST_OBJECT_UNLOCK (pad); + + if (callback) + callback (pad, GST_BLOCK_TYPE_IDLE, user_data); + + return; + } + } GST_OBJECT_UNLOCK (pad); } @@ -4290,7 +4303,8 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size, GST_OBJECT_LOCK (pad); while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) - handle_pad_block (pad); + if ((ret = handle_pad_block (pad, GST_BLOCK_TYPE_PULL) != GST_FLOW_OK)) + goto flushed; if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL)) goto not_connected; @@ -4309,6 +4323,12 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size, if (G_UNLIKELY (ret != GST_FLOW_OK)) goto pull_range_failed; + while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) + if ((ret = + handle_pad_block (pad, + GST_BLOCK_TYPE_PULL | GST_BLOCK_TYPE_DATA) != GST_FLOW_OK)) + goto flushed; + /* can only fire the signal if we have a valid buffer */ if (G_UNLIKELY (emit_signal)) { if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT_CAST (*buffer))) @@ -4331,6 +4351,12 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size, return ret; /* ERROR recovery here */ +flushed: + { + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "we are flushing"); + GST_OBJECT_UNLOCK (pad); + return GST_FLOW_NOT_LINKED; + } not_connected: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, @@ -4385,8 +4411,8 @@ gboolean gst_pad_push_event (GstPad * pad, GstEvent * event) { GstPad *peerpad; - gboolean result, need_probes, did_probes = FALSE, did_event_actions = FALSE; - gint64 offset; + gboolean result, need_probes, do_probes = TRUE, do_event_actions = TRUE; + gboolean stored = FALSE; g_return_val_if_fail (GST_IS_PAD (pad), FALSE); g_return_val_if_fail (event != NULL, FALSE); @@ -4397,6 +4423,9 @@ gst_pad_push_event (GstPad * pad, GstEvent * event) again: GST_OBJECT_LOCK (pad); + peerpad = GST_PAD_PEER (pad); + need_probes = do_probes && (GST_PAD_DO_EVENT_SIGNALS (pad) > 0); + /* Two checks to be made: * . (un)set the FLUSHING flag for flushing events, * . handle pad blocking */ @@ -4416,89 +4445,92 @@ again: break; case GST_EVENT_FLUSH_STOP: GST_PAD_UNSET_FLUSHING (pad); + if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) { + GST_LOG_OBJECT (pad, "Pad is blocked, not forwarding flush-stop"); + goto flushed; + } break; default: - break; - } + { + /* store the event on the pad, but only on srcpads */ + if (GST_PAD_IS_SRC (pad) && GST_EVENT_IS_STICKY (event)) { + guint idx; - /* store the event on the pad, but only on srcpads */ - if (GST_PAD_IS_SRC (pad) && GST_EVENT_IS_STICKY (event)) { - if (GST_PAD_IS_FLUSHING (pad)) { - goto flushing; - } else { - guint idx; + idx = GST_EVENT_STICKY_IDX (event); + GST_LOG_OBJECT (pad, "storing sticky event %s at index %u", + GST_EVENT_TYPE_NAME (event), idx); - idx = GST_EVENT_STICKY_IDX (event); - GST_LOG_OBJECT (pad, "storing sticky event %s at index %u", - GST_EVENT_TYPE_NAME (event), idx); + /* srcpad sticky events always become active immediately */ + gst_event_replace (&pad->priv->events[idx].event, event); - /* srcpad sticky events always become active immediately */ - gst_event_replace (&pad->priv->events[idx].event, event); - } - } - - /* drop all events when blocking. Sticky events will stay on the pad and will - * be activated on the peer when unblocking. */ - if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) { - GST_LOG_OBJECT (pad, "Pad is blocked, not forwarding event"); - goto flushed; - } - - offset = pad->offset; - need_probes = !did_probes && (GST_PAD_DO_EVENT_SIGNALS (pad) > 0); - peerpad = GST_PAD_PEER (pad); - - /* backwards compatibility mode for caps */ - if (!did_event_actions) { - did_event_actions = TRUE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS: - { - GstCaps *caps; - - GST_OBJECT_UNLOCK (pad); - - gst_event_parse_caps (event, &caps); - /* FIXME, this is awkward because we don't check flushing here which means - * that we can call the setcaps functions on flushing pads, this is not - * quite what we want, otoh, this code should just go away and elements - * that set caps on their srcpad should just setup stuff themselves. */ - gst_pad_call_setcaps (pad, caps); - - /* recheck everything, we released the lock */ - goto again; + stored = TRUE; } - case GST_EVENT_SEGMENT: - /* check if we need to adjust the segment */ - if (offset != 0 && (need_probes || peerpad != NULL)) { - GstSegment segment; - /* copy segment values */ - gst_event_copy_segment (event, &segment); - gst_event_unref (event); + /* backwards compatibility mode for caps */ + if (do_event_actions) { + do_event_actions = FALSE; - /* adjust and make a new event with the offset applied */ - segment.base += offset; - event = gst_event_new_segment (&segment); + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + GST_OBJECT_UNLOCK (pad); + + gst_event_parse_caps (event, &caps); + /* FIXME, this is awkward because we don't check flushing here which means + * that we can call the setcaps functions on flushing pads, this is not + * quite what we want, otoh, this code should just go away and elements + * that set caps on their srcpad should just setup stuff themselves. */ + gst_pad_call_setcaps (pad, caps); + + /* recheck everything, we released the lock */ + goto again; + } + case GST_EVENT_SEGMENT: + { + gint64 offset; + + offset = pad->offset; + /* check if we need to adjust the segment */ + if (offset != 0 && (need_probes || peerpad != NULL)) { + GstSegment segment; + + /* copy segment values */ + gst_event_copy_segment (event, &segment); + gst_event_unref (event); + + /* adjust and make a new event with the offset applied */ + segment.base += offset; + event = gst_event_new_segment (&segment); + } + break; + } + case GST_EVENT_RECONFIGURE: + if (GST_PAD_IS_SINK (pad)) + GST_OBJECT_FLAG_SET (pad, GST_PAD_NEED_RECONFIGURE); + break; + default: + break; } - break; - case GST_EVENT_RECONFIGURE: - if (GST_PAD_IS_SINK (pad)) - GST_OBJECT_FLAG_SET (pad, GST_PAD_NEED_RECONFIGURE); - break; - default: - break; + } + + while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) + if (handle_pad_block (pad, + GST_BLOCK_TYPE_PUSH | GST_BLOCK_TYPE_DATA) != GST_FLOW_OK) + goto flushed; + + break; } } /* send probes after modifying the events above */ if (G_UNLIKELY (need_probes)) { - did_probes = TRUE; + do_probes = FALSE; GST_OBJECT_UNLOCK (pad); if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT_CAST (event))) - goto dropping; + goto dropped; /* retry, we released the lock */ goto again; @@ -4523,11 +4555,9 @@ again: gst_object_unref (peerpad); - GST_OBJECT_LOCK (pad); - pad->priv->using--; - GST_OBJECT_UNLOCK (pad); + pad_post_push (pad); - return result; + return result | stored; /* ERROR handling */ flushed: @@ -4535,28 +4565,20 @@ flushed: GST_DEBUG_OBJECT (pad, "We're flushing"); GST_OBJECT_UNLOCK (pad); gst_event_unref (event); - GST_OBJECT_UNLOCK (pad); - return TRUE; + return stored; } -dropping: +dropped: { GST_DEBUG_OBJECT (pad, "Dropping event after FALSE probe return"); gst_event_unref (event); - return FALSE; + return stored; } not_linked: { GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked"); GST_OBJECT_UNLOCK (pad); gst_event_unref (event); - return FALSE; - } -flushing: - { - GST_DEBUG_OBJECT (pad, "Dropping event because pad is flushing"); - GST_OBJECT_UNLOCK (pad); - gst_event_unref (event); - return FALSE; + return stored; } } diff --git a/gst/gstpad.h b/gst/gstpad.h index 970e1ef51b..850957fbe1 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -470,16 +470,33 @@ typedef void (*GstPadFixateCapsFunction) (GstPad *pad, GstCaps *caps); */ typedef gboolean (*GstPadDispatcherFunction) (GstPad *pad, gpointer data); +/** + * GstBlockType: + * @GST_BLOCK_TYPE_IDLE: The pad is idle + * @GST_BLOCK_TYPE_DATA: Data is queued on the pad + * @GST_BLOCK_TYPE_PUSH: Blocked on a push operation + * @GST_BLOCK_TYPE_PULL: Blocked on a pull operation + * + * The different blocking types that can occur. + */ +typedef enum +{ + GST_BLOCK_TYPE_IDLE = (1 << 0), + GST_BLOCK_TYPE_DATA = (1 << 1), + GST_BLOCK_TYPE_PUSH = (1 << 2), + GST_BLOCK_TYPE_PULL = (1 << 3), +} GstBlockType; + /** * GstPadBlockCallback: - * @pad: the #GstPad that is blockend or unblocked. - * @blocked: blocking state for the pad + * @pad: the #GstPad that is blocked + * @type: the current blocking type * @user_data: the gpointer to optional user data. * - * Callback used by gst_pad_set_blocked_async(). Gets called when the blocking - * operation succeeds. + * Callback used by gst_pad_block(). Gets called to notify about the current + * blocking type. */ -typedef void (*GstPadBlockCallback) (GstPad *pad, gboolean blocked, gpointer user_data); +typedef void (*GstPadBlockCallback) (GstPad *pad, GstBlockType type, gpointer user_data); /** * GstPadStickyEventsForeachFunction: @@ -600,6 +617,7 @@ struct _GstPad { /*< public >*/ /* with LOCK */ /* block cond, mutex is from the object */ GCond *block_cond; + GstBlockType block_type; GstPadBlockCallback block_callback; gpointer block_data; GDestroyNotify block_destroy_data; @@ -804,9 +822,13 @@ gboolean gst_pad_is_active (GstPad *pad); gboolean gst_pad_activate_pull (GstPad *pad, gboolean active); gboolean gst_pad_activate_push (GstPad *pad, gboolean active); -gboolean gst_pad_set_blocked (GstPad *pad, gboolean blocked, - GstPadBlockCallback callback, gpointer user_data, +gboolean gst_pad_block (GstPad *pad, + GstBlockType type, + GstPadBlockCallback callback, + gpointer user_data, GDestroyNotify destroy_data); +void gst_pad_unblock (GstPad *pad); + gboolean gst_pad_is_blocked (GstPad *pad); gboolean gst_pad_is_blocking (GstPad *pad); diff --git a/tests/check/generic/sinks.c b/tests/check/generic/sinks.c index 3aca7f7c4f..9bbe7221aa 100644 --- a/tests/check/generic/sinks.c +++ b/tests/check/generic/sinks.c @@ -764,10 +764,10 @@ static GMutex *blocked_lock; static GCond *blocked_cond; static void -pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data) +pad_blocked_cb (GstPad * pad, GstBlockType type, gpointer user_data) { g_mutex_lock (blocked_lock); - GST_DEBUG ("srcpad blocked: %d, sending signal", blocked); + GST_DEBUG ("srcpad blocked: %d, sending signal", type); g_cond_signal (blocked_cond); g_mutex_unlock (blocked_lock); } @@ -799,7 +799,7 @@ GST_START_TEST (test_add_live2) GST_DEBUG ("blocking srcpad"); /* block source pad */ srcpad = gst_element_get_static_pad (src, "src"); - gst_pad_set_blocked (srcpad, TRUE, pad_blocked_cb, NULL, NULL); + gst_pad_block (srcpad, GST_BLOCK_TYPE_DATA, pad_blocked_cb, NULL, NULL); /* set source to PAUSED without adding it to the pipeline */ ret = gst_element_set_state (src, GST_STATE_PAUSED); @@ -827,7 +827,7 @@ GST_START_TEST (test_add_live2) GST_DEBUG ("unblocking srcpad"); /* and unblock */ - gst_pad_set_blocked (srcpad, FALSE, pad_blocked_cb, NULL, NULL); + gst_pad_unblock (srcpad); GST_DEBUG ("getting state"); diff --git a/tests/check/gst/gstevent.c b/tests/check/gst/gstevent.c index 4e80ccf9aa..3f2ba10945 100644 --- a/tests/check/gst/gstevent.c +++ b/tests/check/gst/gstevent.c @@ -307,6 +307,55 @@ event_probe (GstPad * pad, GstMiniObject ** data, gpointer user_data) return TRUE; } + +typedef struct +{ + GMutex *lock; + GCond *cond; + gboolean signaled; +} SignalData; + +static void +signal_data_init (SignalData * data) +{ + data->lock = g_mutex_new (); + data->cond = g_cond_new (); + data->signaled = FALSE; +} + +static void +signal_data_cleanup (SignalData * data) +{ + g_mutex_free (data->lock); + g_cond_free (data->cond); +} + +static void +signal_data_signal (SignalData * data) +{ + g_mutex_lock (data->lock); + data->signaled = TRUE; + g_cond_broadcast (data->cond); + g_mutex_unlock (data->lock); +} + +static void +signal_data_wait (SignalData * data) +{ + g_mutex_lock (data->lock); + while (!data->signaled) + g_cond_wait (data->cond, data->lock); + g_mutex_unlock (data->lock); +} + +static void +signal_blocked (GstPad * pad, GstBlockType type, gpointer user_data) +{ + SignalData *data = (SignalData *) user_data; + + signal_data_signal (data); +} + static void test_event (GstBin * pipeline, GstEventType type, GstPad * pad, gboolean expect_before_q, GstPad * fake_srcpad) @@ -314,6 +363,7 @@ static void test_event GstEvent *event; GstPad *peer; gint i; + SignalData data; got_event_before_q = got_event_after_q = NULL; @@ -329,17 +379,21 @@ static void test_event got_event_time.tv_sec = 0; got_event_time.tv_usec = 0; + signal_data_init (&data); + /* We block the pad so the stream lock is released and we can send the event */ - fail_unless (gst_pad_set_blocked (fake_srcpad, TRUE, NULL, NULL, - NULL) == TRUE); + fail_unless (gst_pad_block (fake_srcpad, GST_BLOCK_TYPE_DATA, + signal_blocked, &data, NULL) == TRUE); + + signal_data_wait (&data); /* We send on the peer pad, since the pad is blocked */ fail_unless ((peer = gst_pad_get_peer (pad)) != NULL); gst_pad_send_event (peer, event); gst_object_unref (peer); - fail_unless (gst_pad_set_blocked (fake_srcpad, FALSE, NULL, NULL, - NULL) == TRUE); + gst_pad_unblock (fake_srcpad); + signal_data_cleanup (&data); if (expect_before_q) { /* Wait up to 5 seconds for the event to appear */ diff --git a/tests/check/gst/gstghostpad.c b/tests/check/gst/gstghostpad.c index bd5080fb49..9dfebb1b24 100644 --- a/tests/check/gst/gstghostpad.c +++ b/tests/check/gst/gstghostpad.c @@ -479,7 +479,7 @@ typedef struct } BlockData; static void -block_callback (GstPad * pad, gboolean blocked, gpointer user_data) +block_callback (GstPad * pad, GstBlockType type, gpointer user_data) { BlockData *block_data = (BlockData *) user_data; @@ -514,7 +514,8 @@ GST_START_TEST (test_ghost_pads_block) block_data.cond = g_cond_new (); g_mutex_lock (block_data.mutex); - gst_pad_set_blocked (srcghost, TRUE, block_callback, &block_data, NULL); + gst_pad_block (srcghost, GST_BLOCK_TYPE_DATA, block_callback, &block_data, + NULL); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); /* and wait now */ g_cond_wait (block_data.cond, block_data.mutex); @@ -555,7 +556,8 @@ GST_START_TEST (test_ghost_pads_probes) block_data.cond = g_cond_new (); g_mutex_lock (block_data.mutex); - gst_pad_set_blocked (srcghost, TRUE, block_callback, &block_data, NULL); + gst_pad_block (srcghost, GST_BLOCK_TYPE_DATA, block_callback, &block_data, + NULL); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); /* and wait now */ g_cond_wait (block_data.cond, block_data.mutex); diff --git a/tests/check/gst/gstpad.c b/tests/check/gst/gstpad.c index 8d0bbbf3e1..c16b194c0a 100644 --- a/tests/check/gst/gstpad.c +++ b/tests/check/gst/gstpad.c @@ -682,29 +682,20 @@ GST_START_TEST (test_sink_unref_unlink) GST_END_TEST; static void -unblock_async_cb (GstPad * pad, gboolean blocked, gpointer user_data) +block_async_cb (GstPad * pad, GstBlockType type, gpointer user_data) { gboolean *bool_user_data = (gboolean *) user_data; - /* here we should have blocked == 1 unblocked == 0 */ - fail_unless (bool_user_data[0] == TRUE); - fail_unless (bool_user_data[1] == FALSE); - - bool_user_data[1] = TRUE; -} - -static void -block_async_cb (GstPad * pad, gboolean blocked, gpointer user_data) -{ - gboolean *bool_user_data = (gboolean *) user_data; + fail_unless ((type & GST_BLOCK_TYPE_DATA) != 0); /* here we should have blocked == 0 unblocked == 0 */ fail_unless (bool_user_data[0] == FALSE); fail_unless (bool_user_data[1] == FALSE); - bool_user_data[0] = blocked; + bool_user_data[0] = TRUE; - gst_pad_set_blocked (pad, FALSE, unblock_async_cb, user_data, NULL); + gst_pad_unblock (pad); + bool_user_data[1] = TRUE; } GST_START_TEST (test_block_async) @@ -718,7 +709,7 @@ GST_START_TEST (test_block_async) fail_unless (pad != NULL); gst_pad_set_active (pad, TRUE); - gst_pad_set_blocked (pad, TRUE, block_async_cb, &data, NULL); + gst_pad_block (pad, GST_BLOCK_TYPE_DATA, block_async_cb, &data, NULL); fail_unless (data[0] == FALSE); fail_unless (data[1] == FALSE); @@ -796,9 +787,9 @@ block_async_full_destroy (gpointer user_data) } static void -block_async_full_cb (GstPad * pad, gboolean blocked, gpointer user_data) +block_async_full_cb (GstPad * pad, GstBlockType type, gpointer user_data) { - *(gint *) user_data = (gint) blocked; + *(gint *) user_data = (gint) TRUE; gst_pad_push_event (pad, gst_event_new_flush_start ()); GST_DEBUG ("setting state to 1"); @@ -814,7 +805,7 @@ GST_START_TEST (test_block_async_full_destroy) fail_unless (pad != NULL); gst_pad_set_active (pad, TRUE); - gst_pad_set_blocked (pad, TRUE, block_async_full_cb, + gst_pad_block (pad, GST_BLOCK_TYPE_DATA, block_async_full_cb, &state, block_async_full_destroy); fail_unless (state == 0); @@ -825,26 +816,24 @@ GST_START_TEST (test_block_async_full_destroy) gst_pad_push_event (pad, gst_event_new_flush_stop ()); /* pad was already blocked so nothing happens */ - gst_pad_set_blocked (pad, TRUE, block_async_full_cb, + gst_pad_block (pad, GST_BLOCK_TYPE_DATA, block_async_full_cb, &state, block_async_full_destroy); fail_unless (state == 1); - /* unblock with the same data, callback is called */ - gst_pad_set_blocked (pad, FALSE, block_async_full_cb, - &state, block_async_full_destroy); + /* unblock callback is called */ + gst_pad_unblock (pad); fail_unless (state == 2); - /* block with the same data, callback is called */ + /* block with the same data, nothing is called */ state = 1; - gst_pad_set_blocked (pad, TRUE, block_async_full_cb, + gst_pad_block (pad, GST_BLOCK_TYPE_DATA, block_async_full_cb, &state, block_async_full_destroy); - fail_unless (state == 2); + fail_unless (state == 1); /* now change user_data (to NULL in this case) so destroy_notify should be * called */ state = 1; - gst_pad_set_blocked (pad, FALSE, block_async_full_cb, - NULL, block_async_full_destroy); + gst_pad_unblock (pad); fail_unless (state == 2); gst_object_unref (pad); @@ -862,7 +851,7 @@ GST_START_TEST (test_block_async_full_destroy_dispose) fail_unless (pad != NULL); gst_pad_set_active (pad, TRUE); - gst_pad_set_blocked (pad, TRUE, block_async_full_cb, + gst_pad_block (pad, GST_BLOCK_TYPE_DATA, block_async_full_cb, &state, block_async_full_destroy); gst_pad_push (pad, gst_buffer_new ()); @@ -880,6 +869,7 @@ GST_START_TEST (test_block_async_full_destroy_dispose) GST_END_TEST; +#if 0 static void unblock_async_no_flush_cb (GstPad * pad, gboolean blocked, gpointer user_data) { @@ -895,20 +885,24 @@ unblock_async_no_flush_cb (GstPad * pad, gboolean blocked, gpointer user_data) bool_user_data[2] = TRUE; } +#endif +#if 0 static void unblock_async_not_called (GstPad * pad, gboolean blocked, gpointer user_data) { g_warn_if_reached (); } +#endif static void -block_async_second_no_flush (GstPad * pad, gboolean blocked, gpointer user_data) +block_async_second_no_flush (GstPad * pad, GstBlockType type, + gpointer user_data) { gboolean *bool_user_data = (gboolean *) user_data; - fail_unless (blocked == TRUE); + fail_unless (type & GST_BLOCK_TYPE_DATA); fail_unless (bool_user_data[0] == TRUE); fail_unless (bool_user_data[1] == FALSE); @@ -916,34 +910,32 @@ block_async_second_no_flush (GstPad * pad, gboolean blocked, gpointer user_data) bool_user_data[1] = TRUE; - fail_unless (gst_pad_set_blocked (pad, FALSE, unblock_async_no_flush_cb, - user_data, NULL)); + gst_pad_unblock (pad); } static void -block_async_first_no_flush (GstPad * pad, gboolean blocked, gpointer user_data) +block_async_first_no_flush (GstPad * pad, GstBlockType type, gpointer user_data) { static int n_calls = 0; gboolean *bool_user_data = (gboolean *) user_data; - fail_unless (blocked == TRUE); + fail_unless (type & GST_BLOCK_TYPE_DATA); if (++n_calls > 1) /* we expect this callback to be called only once */ g_warn_if_reached (); - *bool_user_data = blocked; + *bool_user_data = TRUE; fail_unless (bool_user_data[0] == TRUE); fail_unless (bool_user_data[1] == FALSE); fail_unless (bool_user_data[2] == FALSE); - fail_unless (gst_pad_set_blocked (pad, FALSE, unblock_async_not_called, - NULL, NULL)); + gst_pad_unblock (pad); /* replace block_async_first with block_async_second so next time the pad is * blocked the latter should be called */ - fail_unless (gst_pad_set_blocked (pad, TRUE, + fail_unless (gst_pad_block (pad, GST_BLOCK_TYPE_DATA, block_async_second_no_flush, user_data, NULL)); } @@ -956,13 +948,13 @@ GST_START_TEST (test_block_async_replace_callback_no_flush) fail_unless (pad != NULL); gst_pad_set_active (pad, TRUE); - fail_unless (gst_pad_set_blocked (pad, TRUE, block_async_first_no_flush, - bool_user_data, NULL)); + fail_unless (gst_pad_block (pad, GST_BLOCK_TYPE_DATA, + block_async_first_no_flush, bool_user_data, NULL)); gst_pad_push (pad, gst_buffer_new ()); fail_unless (bool_user_data[0] == TRUE); fail_unless (bool_user_data[1] == TRUE); - fail_unless (bool_user_data[2] == TRUE); + fail_unless (bool_user_data[2] == FALSE); gst_object_unref (pad); }