From 56d4650789e113c2184ed955ed19b9457b41769a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 12 Nov 2015 17:15:37 +0100 Subject: [PATCH] pad: Implement GstPadEventFullFunction API: GstPadEventFullFunction Returns a GstFlowReturn, allows asynchronous elements to properly propagate flow returns https://bugzilla.gnome.org/show_bug.cgi?id=757821 --- gst/gstpad.c | 54 ++++++++++++++++++++++++++++++-- gst/gstpad.h | 37 ++++++++++++++++++++++ plugins/elements/gstmultiqueue.c | 24 +++++++++----- plugins/elements/gstqueue.c | 19 ++++++----- win32/common/libgstreamer.def | 1 + 5 files changed, 119 insertions(+), 16 deletions(-) diff --git a/gst/gstpad.c b/gst/gstpad.c index 34dafe515e..aed3af7180 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -1826,6 +1826,51 @@ gst_pad_set_event_function_full (GstPad * pad, GstPadEventFunction event, GST_DEBUG_FUNCPTR_NAME (event)); } +static gboolean +event_wrap (GstPad * pad, GstObject * object, GstEvent * event) +{ + GstFlowReturn ret; + + ret = GST_PAD_EVENTFULLFUNC (pad) (pad, object, event); + if (ret == GST_FLOW_OK) + return TRUE; + return FALSE; +} + +/** + * gst_pad_set_event_full_function: + * @p: a #GstPad of either direction. + * @f: the #GstPadEventFullFunction to set. + * + * Calls gst_pad_set_event_full_function_full() with %NULL for the user_data and + * notify. + */ +/** + * gst_pad_set_event_full_function_full: + * @pad: a #GstPad of either direction. + * @event: the #GstPadEventFullFunction to set. + * @user_data: user_data passed to @notify + * @notify: notify called when @event will not be used anymore. + * + * Sets the given event handler for the pad. + */ +void +gst_pad_set_event_full_function_full (GstPad * pad, + GstPadEventFullFunction event, gpointer user_data, GDestroyNotify notify) +{ + g_return_if_fail (GST_IS_PAD (pad)); + + if (pad->eventnotify) + pad->eventnotify (pad->eventdata); + GST_PAD_EVENTFULLFUNC (pad) = event; + GST_PAD_EVENTFUNC (pad) = event_wrap; + pad->eventdata = user_data; + pad->eventnotify = notify; + + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "eventfullfunc for set to %s", + GST_DEBUG_FUNCPTR_NAME (event)); +} + /** * gst_pad_set_query_function: * @p: a #GstPad of either direction. @@ -5389,6 +5434,7 @@ gst_pad_send_event_unchecked (GstPad * pad, GstEvent * event, GstEventType event_type; gboolean serialized, need_unlock = FALSE, sticky; GstPadEventFunction eventfunc; + GstPadEventFullFunction eventfullfunc = NULL; GstObject *parent; GST_OBJECT_LOCK (pad); @@ -5486,7 +5532,9 @@ gst_pad_send_event_unchecked (GstPad * pad, GstEvent * event, PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped); - if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL)) + eventfullfunc = GST_PAD_EVENTFULLFUNC (pad); + eventfunc = GST_PAD_EVENTFUNC (pad); + if (G_UNLIKELY (eventfunc == NULL && eventfullfunc == NULL)) goto no_function; ACQUIRE_PARENT (pad, parent, no_parent); @@ -5499,7 +5547,9 @@ gst_pad_send_event_unchecked (GstPad * pad, GstEvent * event, if (sticky) gst_event_ref (event); - if (eventfunc (pad, parent, event)) { + if (eventfullfunc) { + ret = eventfullfunc (pad, parent, event); + } else if (eventfunc (pad, parent, event)) { ret = GST_FLOW_OK; } else { /* something went wrong */ diff --git a/gst/gstpad.h b/gst/gstpad.h index 5f9311285d..539dcfb824 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -362,6 +362,26 @@ typedef GstFlowReturn (*GstPadGetRangeFunction) (GstPad *pad, GstObject *parent typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstObject *parent, GstEvent *event); +/** + * GstPadEventFullFunction: + * @pad: the #GstPad to handle the event. + * @parent: (allow-none): the parent of @pad. If the #GST_PAD_FLAG_NEED_PARENT + * flag is set, @parent is guaranteed to be not-%NULL and remain valid + * during the execution of this function. + * @event: (transfer full): the #GstEvent to handle. + * + * Function signature to handle an event for the pad. + * + * This variant is for specific elements that will take into account the + * last downstream flow return (from a pad push), in which case they can + * return it. + * + * Returns: %GST_FLOW_OK if the event was handled properly, or any other + * #GstFlowReturn dependent on downstream state. + */ +typedef GstFlowReturn (*GstPadEventFullFunction) (GstPad *pad, GstObject *parent, + GstEvent *event); + /* internal links */ /** @@ -756,6 +776,7 @@ struct _GstPad { gpointer _gst_reserved[GST_PADDING]; struct { GstFlowReturn last_flowret; + GstPadEventFullFunction eventfullfunc; } abi; } ABI; }; @@ -880,6 +901,17 @@ struct _GstPadClass { * class, use the base class's virtual functions instead. */ #define GST_PAD_EVENTFUNC(pad) (GST_PAD_CAST(pad)->eventfunc) +/** + * GST_PAD_EVENTFULLFUNC: + * @pad: a #GstPad + * + * Get the #GstPadEventFullFunction from the given @pad, which + * is the function that handles events on the pad. You can + * use this to set your own event handling function on a pad + * after you create it. If your element derives from a base + * class, use the base class's virtual functions instead. + */ +#define GST_PAD_EVENTFULLFUNC(pad) (GST_PAD_CAST(pad)->ABI.abi.eventfullfunc) /** * GST_PAD_QUERYFUNC: * @pad: a #GstPad @@ -1306,6 +1338,10 @@ void gst_pad_set_event_function_full (GstPad *pad, GstPadEventFunction event, gpointer user_data, GDestroyNotify notify); +void gst_pad_set_event_full_function_full (GstPad *pad, + GstPadEventFullFunction event, + gpointer user_data, + GDestroyNotify notify); #define gst_pad_set_activate_function(p,f) gst_pad_set_activate_function_full((p),(f),NULL,NULL) #define gst_pad_set_activatemode_function(p,f) gst_pad_set_activatemode_function_full((p),(f),NULL,NULL) @@ -1313,6 +1349,7 @@ void gst_pad_set_event_function_full (GstPad *pad, #define gst_pad_set_chain_list_function(p,f) gst_pad_set_chain_list_function_full((p),(f),NULL,NULL) #define gst_pad_set_getrange_function(p,f) gst_pad_set_getrange_function_full((p),(f),NULL,NULL) #define gst_pad_set_event_function(p,f) gst_pad_set_event_function_full((p),(f),NULL,NULL) +#define gst_pad_set_event_full_function(p,f) gst_pad_set_event_full_function_full((p),(f),NULL,NULL) /* pad links */ void gst_pad_set_link_function_full (GstPad *pad, diff --git a/plugins/elements/gstmultiqueue.c b/plugins/elements/gstmultiqueue.c index db9f445dbe..d98bd6dff5 100644 --- a/plugins/elements/gstmultiqueue.c +++ b/plugins/elements/gstmultiqueue.c @@ -1941,14 +1941,15 @@ gst_multi_queue_sink_activate_mode (GstPad * pad, GstObject * parent, return res; } -static gboolean +static GstFlowReturn gst_multi_queue_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstSingleQueue *sq; GstMultiQueue *mq; guint32 curid; GstMultiQueueItem *item; - gboolean res; + gboolean res = TRUE; + GstFlowReturn flowret = GST_FLOW_OK; GstEventType type; GstEvent *sref = NULL; @@ -2088,8 +2089,17 @@ gst_multi_queue_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) default: break; } + done: - return res; + if (res == FALSE) { + if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) + flowret = GST_FLOW_NOT_NEGOTIATED; + else + flowret = GST_FLOW_ERROR; + } + GST_DEBUG_OBJECT (mq, "SingleQueue %d : returning %s", sq->id, + gst_flow_get_name (flowret)); + return flowret; flushing: { @@ -2098,14 +2108,14 @@ flushing: if (sref) gst_event_unref (sref); gst_multi_queue_item_destroy (item); - goto done; + return sq->srcresult; } was_eos: { - GST_DEBUG_OBJECT (mq, "we are EOS, dropping event, return FALSE"); + GST_DEBUG_OBJECT (mq, "we are EOS, dropping event, return GST_FLOW_EOS"); gst_event_unref (event); res = FALSE; - goto done; + return GST_FLOW_EOS; } } @@ -2676,7 +2686,7 @@ gst_single_queue_new (GstMultiQueue * mqueue, guint id) GST_DEBUG_FUNCPTR (gst_multi_queue_chain)); gst_pad_set_activatemode_function (sq->sinkpad, GST_DEBUG_FUNCPTR (gst_multi_queue_sink_activate_mode)); - gst_pad_set_event_function (sq->sinkpad, + gst_pad_set_event_full_function (sq->sinkpad, GST_DEBUG_FUNCPTR (gst_multi_queue_sink_event)); gst_pad_set_query_function (sq->sinkpad, GST_DEBUG_FUNCPTR (gst_multi_queue_sink_query)); diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index 44714e8eb4..6d9810f73d 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -200,8 +200,8 @@ static GstFlowReturn gst_queue_chain_list (GstPad * pad, GstObject * parent, static GstFlowReturn gst_queue_push_one (GstQueue * queue); static void gst_queue_loop (GstPad * pad); -static gboolean gst_queue_handle_sink_event (GstPad * pad, GstObject * parent, - GstEvent * event); +static GstFlowReturn gst_queue_handle_sink_event (GstPad * pad, + GstObject * parent, GstEvent * event); static gboolean gst_queue_handle_sink_query (GstPad * pad, GstObject * parent, GstQuery * query); @@ -431,7 +431,7 @@ gst_queue_init (GstQueue * queue) gst_pad_set_chain_list_function (queue->sinkpad, gst_queue_chain_list); gst_pad_set_activatemode_function (queue->sinkpad, gst_queue_sink_activate_mode); - gst_pad_set_event_function (queue->sinkpad, gst_queue_handle_sink_event); + gst_pad_set_event_full_function (queue->sinkpad, gst_queue_handle_sink_event); gst_pad_set_query_function (queue->sinkpad, gst_queue_handle_sink_query); GST_PAD_SET_PROXY_CAPS (queue->sinkpad); gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad); @@ -897,7 +897,7 @@ no_item: } } -static gboolean +static GstFlowReturn gst_queue_handle_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean ret = TRUE; @@ -985,7 +985,12 @@ gst_queue_handle_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) } break; } - return ret; + if (ret == FALSE) { + if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) + return GST_FLOW_NOT_NEGOTIATED; + return GST_FLOW_ERROR; + } + return GST_FLOW_OK; /* ERRORS */ out_eos: @@ -993,7 +998,7 @@ out_eos: GST_CAT_LOG_OBJECT (queue_dataflow, queue, "refusing event, we are EOS"); GST_QUEUE_MUTEX_UNLOCK (queue); gst_event_unref (event); - return FALSE; + return GST_FLOW_EOS; } out_flow_error: { @@ -1001,7 +1006,7 @@ out_flow_error: "refusing event, we have a downstream flow error: %s", gst_flow_get_name (queue->srcresult)); gst_event_unref (event); - return FALSE; + return queue->srcresult; } } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 10dad7ae30..ce553fa625 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -895,6 +895,7 @@ EXPORTS gst_pad_set_chain_function_full gst_pad_set_chain_list_function_full gst_pad_set_element_private + gst_pad_set_event_full_function_full gst_pad_set_event_function_full gst_pad_set_getrange_function_full gst_pad_set_iterate_internal_links_function_full