summaryrefslogtreecommitdiff
path: root/gst/gstpad.c
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@collabora.co.uk>2011-11-28 13:54:43 +0100
committerWim Taymans <wim.taymans@collabora.co.uk>2011-11-28 14:07:24 +0100
commitda74724fd57644fa94d0c3ec6a2bf6a039c419d7 (patch)
tree2a9c59adf279301a8d337cbadac9755b11164499 /gst/gstpad.c
parent948b1264b7b092b38b3e03b92f08586cf645e342 (diff)
downloadgstreamer-da74724fd57644fa94d0c3ec6a2bf6a039c419d7.tar.gz
pad: Handle sticky event errors
Use GstFlowReturn to internally pass events between pads. When we sticky events cause an error, translate this error into a GstFlowReturn. Caps events will, for example, generate a NOT_NEGOTIATED return when the event function returns an error. This allows us then to refuse sending buffers if one of the sticky events is refused and generate a correct error return value.
Diffstat (limited to 'gst/gstpad.c')
-rw-r--r--gst/gstpad.c391
1 files changed, 230 insertions, 161 deletions
diff --git a/gst/gstpad.c b/gst/gstpad.c
index af468de0fc..cf5ff47e08 100644
--- a/gst/gstpad.c
+++ b/gst/gstpad.c
@@ -145,6 +145,11 @@ static gboolean gst_pad_activate_default (GstPad * pad, GstObject * parent);
static GstFlowReturn gst_pad_chain_list_default (GstPad * pad,
GstObject * parent, GstBufferList * list);
+static GstFlowReturn gst_pad_send_event_unchecked (GstPad * pad,
+ GstEvent * event, GstPadProbeType type);
+static GstFlowReturn gst_pad_push_event_unchecked (GstPad * pad,
+ GstEvent * event, GstPadProbeType type, gboolean * stored);
+
static guint gst_pad_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *pspec_caps = NULL;
@@ -3238,8 +3243,8 @@ probe_stopped:
static gboolean
push_sticky (GstPad * pad, PadEvent * ev, gpointer user_data)
{
- gboolean res;
GstFlowReturn *data = user_data;
+ gboolean stored;
if (ev->received) {
GST_DEBUG_OBJECT (pad, "event %s was already received",
@@ -3248,13 +3253,11 @@ push_sticky (GstPad * pad, PadEvent * ev, gpointer user_data)
}
GST_OBJECT_UNLOCK (pad);
- res = gst_pad_push_event (pad, gst_event_ref (ev->event));
+ *data = gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, &stored);
GST_OBJECT_LOCK (pad);
- if (!res)
- *data = GST_FLOW_ERROR;
-
- return res;
+ return *data != GST_FLOW_OK;
}
/* this is the chain function that does not perform the additional argument
@@ -3524,7 +3527,8 @@ flushing:
}
events_error:
{
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "error pushing events");
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "error pushing events, return %s", gst_flow_get_name (ret));
GST_OBJECT_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return ret;
@@ -3962,56 +3966,25 @@ gst_pad_store_sticky_event (GstPad * pad, GstEvent * event, gboolean locked)
return res;
}
-/**
- * gst_pad_push_event:
- * @pad: a #GstPad to push the event to.
- * @event: (transfer full): the #GstEvent to send to the pad.
- *
- * Sends the event to the peer of the given pad. This function is
- * mainly used by elements to send events to their peer
- * elements.
- *
- * This function takes owership of the provided event so you should
- * gst_event_ref() it if you want to reuse the event after this call.
- *
- * Returns: TRUE if the event was handled.
- *
- * MT safe.
- */
-gboolean
-gst_pad_push_event (GstPad * pad, GstEvent * event)
+static GstFlowReturn
+gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
+ GstPadProbeType type, gboolean * stored)
{
GstFlowReturn ret;
GstPad *peerpad;
- gboolean result;
- gboolean stored = FALSE;
- GstPadProbeType type;
+ GstEventType event_type;
gboolean sticky;
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
- g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
-
- if (GST_PAD_IS_SRC (pad)) {
- if (G_UNLIKELY (!GST_EVENT_IS_DOWNSTREAM (event)))
- goto wrong_direction;
- sticky = GST_EVENT_IS_STICKY (event);
- type = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM;
- } else if (GST_PAD_IS_SINK (pad)) {
- if (G_UNLIKELY (!GST_EVENT_IS_UPSTREAM (event)))
- goto wrong_direction;
- /* events pushed on sinkpad never are sticky */
- sticky = FALSE;
- type = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
- } else
- goto unknown_direction;
+ sticky = GST_EVENT_IS_STICKY (event);
GST_OBJECT_LOCK (pad);
/* Two checks to be made:
* . (un)set the FLUSHING flag for flushing events,
* . handle pad blocking */
- switch (GST_EVENT_TYPE (event)) {
+ event_type = GST_EVENT_TYPE (event);
+ *stored = FALSE;
+ switch (event_type) {
case GST_EVENT_FLUSH_START:
GST_PAD_SET_FLUSHING (pad);
@@ -4052,7 +4025,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
GST_DEBUG_OBJECT (pad, "event %s updated",
GST_EVENT_TYPE_NAME (event));
}
- stored = TRUE;
+ *stored = TRUE;
}
switch (GST_EVENT_TYPE (event)) {
@@ -4089,19 +4062,19 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
GST_LOG_OBJECT (pad, "sending event %p (%s) to peerpad %" GST_PTR_FORMAT,
event, GST_EVENT_TYPE_NAME (event), peerpad);
- result = gst_pad_send_event (peerpad, event);
+ ret = gst_pad_send_event_unchecked (peerpad, event, type);
/* Note: we gave away ownership of the event at this point but we can still
* print the old pointer */
GST_LOG_OBJECT (pad,
- "sent event %p to peerpad %" GST_PTR_FORMAT ", result %d", event, peerpad,
- result);
+ "sent event %p to peerpad %" GST_PTR_FORMAT ", ret %s", event, peerpad,
+ gst_flow_get_name (ret));
gst_object_unref (peerpad);
GST_OBJECT_LOCK (pad);
if (sticky) {
- if (result) {
+ if (ret == GST_FLOW_OK) {
PadEvent *ev;
if ((ev = find_event (pad, event)))
@@ -4117,55 +4090,112 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
if (pad->priv->using == 0) {
/* pad is not active anymore, trigger idle callbacks */
PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
- idle_probe_stopped, GST_FLOW_OK);
+ idle_probe_stopped, ret);
}
GST_OBJECT_UNLOCK (pad);
- return result | stored;
+ return ret;
/* ERROR handling */
-wrong_direction:
- {
- g_warning ("pad %s:%s pushing %s event in wrong direction",
- GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
- gst_event_unref (event);
- return FALSE;
- }
-unknown_direction:
- {
- g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
- gst_event_unref (event);
- return FALSE;
- }
flushed:
{
GST_DEBUG_OBJECT (pad, "We're flushing");
GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
- return stored;
+ return GST_FLOW_WRONG_STATE;
}
probe_stopped:
{
- GST_DEBUG_OBJECT (pad, "Probe returned %s", gst_flow_get_name (ret));
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
- return stored;
+
+ switch (ret) {
+ case GST_FLOW_CUSTOM_SUCCESS:
+ GST_DEBUG_OBJECT (pad, "dropped event");
+ ret = GST_FLOW_OK;
+ break;
+ default:
+ GST_DEBUG_OBJECT (pad, "en error occured %s", gst_flow_get_name (ret));
+ break;
+ }
+ return ret;
+ }
+not_linked:
+ {
+ GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked");
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+ GST_OBJECT_UNLOCK (pad);
+ gst_event_unref (event);
+ return sticky ? GST_FLOW_OK : GST_FLOW_NOT_LINKED;
}
idle_probe_stopped:
{
GST_DEBUG_OBJECT (pad, "Idle probe returned %s", gst_flow_get_name (ret));
GST_OBJECT_UNLOCK (pad);
+ return ret;
+ }
+}
+
+/**
+ * gst_pad_push_event:
+ * @pad: a #GstPad to push the event to.
+ * @event: (transfer full): the #GstEvent to send to the pad.
+ *
+ * Sends the event to the peer of the given pad. This function is
+ * mainly used by elements to send events to their peer
+ * elements.
+ *
+ * This function takes owership of the provided event so you should
+ * gst_event_ref() it if you want to reuse the event after this call.
+ *
+ * Returns: TRUE if the event was handled.
+ *
+ * MT safe.
+ */
+gboolean
+gst_pad_push_event (GstPad * pad, GstEvent * event)
+{
+ gboolean res;
+ GstPadProbeType type;
+ gboolean stored;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
+
+ if (GST_PAD_IS_SRC (pad)) {
+ if (G_UNLIKELY (!GST_EVENT_IS_DOWNSTREAM (event)))
+ goto wrong_direction;
+ type = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM;
+ } else if (GST_PAD_IS_SINK (pad)) {
+ if (G_UNLIKELY (!GST_EVENT_IS_UPSTREAM (event)))
+ goto wrong_direction;
+ /* events pushed on sinkpad never are sticky */
+ type = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
+ } else
+ goto unknown_direction;
+
+ if (gst_pad_push_event_unchecked (pad, event, type, &stored) != GST_FLOW_OK)
+ res = stored ? TRUE : FALSE;
+ else
+ res = TRUE;
+
+ return res;
+
+ /* ERROR handling */
+wrong_direction:
+ {
+ g_warning ("pad %s:%s pushing %s event in wrong direction",
+ GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
gst_event_unref (event);
- return stored;
+ return FALSE;
}
-not_linked:
+unknown_direction:
{
- GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked");
- GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
- GST_OBJECT_UNLOCK (pad);
+ g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
gst_event_unref (event);
- return stored;
+ return FALSE;
}
}
@@ -4204,64 +4234,24 @@ not_accepted:
}
}
-/**
- * gst_pad_send_event:
- * @pad: a #GstPad to send the event to.
- * @event: (transfer full): the #GstEvent to send to the pad.
- *
- * Sends the event to the pad. This function can be used
- * by applications to send events in the pipeline.
- *
- * If @pad is a source pad, @event should be an upstream event. If @pad is a
- * sink pad, @event should be a downstream event. For example, you would not
- * send a #GST_EVENT_EOS on a src pad; EOS events only propagate downstream.
- * Furthermore, some downstream events have to be serialized with data flow,
- * like EOS, while some can travel out-of-band, like #GST_EVENT_FLUSH_START. If
- * the event needs to be serialized with data flow, this function will take the
- * pad's stream lock while calling its event function.
- *
- * To find out whether an event type is upstream, downstream, or downstream and
- * serialized, see #GstEventTypeFlags, gst_event_type_get_flags(),
- * #GST_EVENT_IS_UPSTREAM, #GST_EVENT_IS_DOWNSTREAM, and
- * #GST_EVENT_IS_SERIALIZED. Note that in practice that an application or
- * plugin doesn't need to bother itself with this information; the core handles
- * all necessary locks and checks.
- *
- * This function takes owership of the provided event so you should
- * gst_event_ref() it if you want to reuse the event after this call.
- *
- * Returns: TRUE if the event was handled.
- */
-gboolean
-gst_pad_send_event (GstPad * pad, GstEvent * event)
+static GstFlowReturn
+gst_pad_send_event_unchecked (GstPad * pad, GstEvent * event,
+ GstPadProbeType type)
{
GstFlowReturn ret;
- gboolean result = FALSE;
+ GstEventType event_type;
gboolean serialized, need_unlock = FALSE, sticky;
GstPadEventFunction eventfunc;
GstObject *parent;
- GstPadProbeType type;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
- if (GST_PAD_IS_SINK (pad)) {
- if (G_UNLIKELY (!GST_EVENT_IS_DOWNSTREAM (event)))
- goto wrong_direction;
- serialized = GST_EVENT_IS_SERIALIZED (event);
- sticky = GST_EVENT_IS_STICKY (event);
- type = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM;
- } else if (GST_PAD_IS_SRC (pad)) {
- if (G_UNLIKELY (!GST_EVENT_IS_UPSTREAM (event)))
- goto wrong_direction;
- /* events on srcpad never are serialized and sticky */
- serialized = sticky = FALSE;
- type = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
- } else
- goto unknown_direction;
GST_OBJECT_LOCK (pad);
- switch (GST_EVENT_TYPE (event)) {
+ if (GST_PAD_IS_SINK (pad))
+ serialized = GST_EVENT_IS_SERIALIZED (event);
+ else
+ serialized = FALSE;
+ sticky = GST_EVENT_IS_STICKY (event);
+ event_type = GST_EVENT_TYPE (event);
+ switch (event_type) {
case GST_EVENT_FLUSH_START:
GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad,
"have event type %d (FLUSH_START)", GST_EVENT_TYPE (event));
@@ -4333,45 +4323,72 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
- if (G_UNLIKELY (pre_eventfunc_check (pad, event) != GST_FLOW_OK))
+ ret = pre_eventfunc_check (pad, event);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
goto precheck_failed;
if (sticky)
gst_event_ref (event);
- result = eventfunc (pad, parent, event);
-
+ if (eventfunc (pad, parent, event)) {
+ ret = GST_FLOW_OK;
+ } else {
+ /* something went wrong */
+ switch (event_type) {
+ case GST_EVENT_CAPS:
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ break;
+ default:
+ ret = GST_FLOW_ERROR;
+ break;
+ }
+ }
RELEASE_PARENT (parent);
+ GST_DEBUG_OBJECT (pad, "sent event, ret %s", gst_flow_get_name (ret));
+
if (sticky) {
- if (result)
+ if (ret == GST_FLOW_OK) {
/* after the event function accepted the event, we can store the sticky
* event on the pad */
gst_pad_store_sticky_event (pad, event, FALSE);
-
+ }
gst_event_unref (event);
}
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
- GST_DEBUG_OBJECT (pad, "sent event, result %d", result);
-
- return result;
+ return ret;
/* ERROR handling */
-wrong_direction:
+flushing:
{
- g_warning ("pad %s:%s sending %s event in wrong direction",
- GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
+ GST_OBJECT_UNLOCK (pad);
+ if (need_unlock)
+ GST_PAD_STREAM_UNLOCK (pad);
+ GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad,
+ "Received event on flushing pad. Discarding");
gst_event_unref (event);
- return FALSE;
+ return GST_FLOW_WRONG_STATE;
}
-unknown_direction:
+probe_stopped:
{
- g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
+ GST_OBJECT_UNLOCK (pad);
+ if (need_unlock)
+ GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
- return FALSE;
+
+ switch (ret) {
+ case GST_FLOW_CUSTOM_SUCCESS:
+ GST_DEBUG_OBJECT (pad, "dropped event");
+ ret = GST_FLOW_OK;
+ break;
+ default:
+ GST_DEBUG_OBJECT (pad, "en error occured %s", gst_flow_get_name (ret));
+ break;
+ }
+ return ret;
}
no_function:
{
@@ -4381,16 +4398,7 @@ no_function:
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
- return FALSE;
- }
-precheck_failed:
- {
- GST_DEBUG_OBJECT (pad, "pre event check failed");
- RELEASE_PARENT (parent);
- if (need_unlock)
- GST_PAD_STREAM_UNLOCK (pad);
- gst_event_unref (event);
- return FALSE;
+ return GST_FLOW_NOT_SUPPORTED;
}
no_parent:
{
@@ -4399,24 +4407,85 @@ no_parent:
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
- return FALSE;
+ return GST_FLOW_WRONG_STATE;
}
-flushing:
+precheck_failed:
{
- GST_OBJECT_UNLOCK (pad);
+ GST_DEBUG_OBJECT (pad, "pre event check failed");
+ RELEASE_PARENT (parent);
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
- GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad,
- "Received event on flushing pad. Discarding");
+ gst_event_unref (event);
+ return ret;
+ }
+}
+
+/**
+ * gst_pad_send_event:
+ * @pad: a #GstPad to send the event to.
+ * @event: (transfer full): the #GstEvent to send to the pad.
+ *
+ * Sends the event to the pad. This function can be used
+ * by applications to send events in the pipeline.
+ *
+ * If @pad is a source pad, @event should be an upstream event. If @pad is a
+ * sink pad, @event should be a downstream event. For example, you would not
+ * send a #GST_EVENT_EOS on a src pad; EOS events only propagate downstream.
+ * Furthermore, some downstream events have to be serialized with data flow,
+ * like EOS, while some can travel out-of-band, like #GST_EVENT_FLUSH_START. If
+ * the event needs to be serialized with data flow, this function will take the
+ * pad's stream lock while calling its event function.
+ *
+ * To find out whether an event type is upstream, downstream, or downstream and
+ * serialized, see #GstEventTypeFlags, gst_event_type_get_flags(),
+ * #GST_EVENT_IS_UPSTREAM, #GST_EVENT_IS_DOWNSTREAM, and
+ * #GST_EVENT_IS_SERIALIZED. Note that in practice that an application or
+ * plugin doesn't need to bother itself with this information; the core handles
+ * all necessary locks and checks.
+ *
+ * This function takes owership of the provided event so you should
+ * gst_event_ref() it if you want to reuse the event after this call.
+ *
+ * Returns: TRUE if the event was handled.
+ */
+gboolean
+gst_pad_send_event (GstPad * pad, GstEvent * event)
+{
+ gboolean result;
+ GstPadProbeType type;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ if (GST_PAD_IS_SINK (pad)) {
+ if (G_UNLIKELY (!GST_EVENT_IS_DOWNSTREAM (event)))
+ goto wrong_direction;
+ type = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM;
+ } else if (GST_PAD_IS_SRC (pad)) {
+ if (G_UNLIKELY (!GST_EVENT_IS_UPSTREAM (event)))
+ goto wrong_direction;
+ type = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
+ } else
+ goto unknown_direction;
+
+ if (gst_pad_send_event_unchecked (pad, event, type) != GST_FLOW_OK)
+ result = FALSE;
+ else
+ result = TRUE;
+
+ return result;
+
+ /* ERROR handling */
+wrong_direction:
+ {
+ g_warning ("pad %s:%s sending %s event in wrong direction",
+ GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
gst_event_unref (event);
return FALSE;
}
-probe_stopped:
+unknown_direction:
{
- GST_DEBUG_OBJECT (pad, "probe returned %s", gst_flow_get_name (ret));
- GST_OBJECT_UNLOCK (pad);
- if (need_unlock)
- GST_PAD_STREAM_UNLOCK (pad);
+ g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
gst_event_unref (event);
return FALSE;
}