From c6f92562b666d09a01545bee4fce7536d44fc5cc Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 23 May 2014 13:25:35 -0300 Subject: [PATCH] pad: store last flow return and provide acessor function Stores the last result of a gst_pad_push or a pull on the GstPad and provides a getter and a macro to access this field. Whenever the pad is inactive it is set to FLUSHING API: gst_pad_get_last_flow_return https://bugzilla.gnome.org/show_bug.cgi?id=709224 --- gst/gstpad.c | 64 ++++++++++++- gst/gstpad.h | 15 +++- tests/check/gst/gstpad.c | 165 ++++++++++++++++++++++++++++++++++ win32/common/libgstreamer.def | 1 + 4 files changed, 241 insertions(+), 4 deletions(-) diff --git a/gst/gstpad.c b/gst/gstpad.c index 8a91ad8a11..d702ea640b 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -389,6 +389,7 @@ gst_pad_init (GstPad * pad) pad->priv->events = g_array_sized_new (FALSE, TRUE, sizeof (PadEvent), 16); pad->priv->events_cookie = 0; pad->priv->last_cookie = -1; + pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING; } /* called when setting the pad inactive. It removes all sticky events from @@ -908,6 +909,7 @@ pre_activate (GstPad * pad, GstPadMode new_mode) GST_OBJECT_LOCK (pad); GST_DEBUG_OBJECT (pad, "setting PAD_MODE NONE, set flushing"); GST_PAD_SET_FLUSHING (pad); + pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING; GST_PAD_MODE (pad) = new_mode; /* unlock blocked pads so element can resume and stop */ GST_PAD_BLOCK_BROADCAST (pad); @@ -919,6 +921,7 @@ pre_activate (GstPad * pad, GstPadMode new_mode) GST_DEBUG_OBJECT (pad, "setting pad into %s mode, unset flushing", gst_pad_mode_get_name (new_mode)); GST_PAD_UNSET_FLUSHING (pad); + pad->ABI.abi.last_flowret = GST_FLOW_OK; GST_PAD_MODE (pad) = new_mode; if (GST_PAD_IS_SINK (pad)) { GstPad *peer; @@ -1002,6 +1005,8 @@ gst_pad_set_active (GstPad * pad, gboolean active) if (old == GST_PAD_MODE_NONE) { GST_DEBUG_OBJECT (pad, "activating pad from none"); ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad, parent); + if (ret) + pad->ABI.abi.last_flowret = GST_FLOW_OK; } else { GST_DEBUG_OBJECT (pad, "pad was active in %s mode", gst_pad_mode_get_name (old)); @@ -1015,6 +1020,8 @@ gst_pad_set_active (GstPad * pad, gboolean active) GST_DEBUG_OBJECT (pad, "deactivating pad from %s mode", gst_pad_mode_get_name (old)); ret = gst_pad_activate_mode (pad, old, FALSE); + if (ret) + pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING; } } @@ -4055,6 +4062,7 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data) gst_object_unref (peer); GST_OBJECT_LOCK (pad); + pad->ABI.abi.last_flowret = ret; pad->priv->using--; if (pad->priv->using == 0) { /* pad is not active anymore, trigger idle callbacks */ @@ -4071,6 +4079,7 @@ flushing: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but pad was flushing"); + pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING; GST_OBJECT_UNLOCK (pad); gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); return GST_FLOW_FLUSHING; @@ -4078,6 +4087,7 @@ flushing: eos: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but pad was EOS"); + pad->ABI.abi.last_flowret = GST_FLOW_EOS; GST_OBJECT_UNLOCK (pad); gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); return GST_FLOW_EOS; @@ -4086,6 +4096,7 @@ wrong_mode: { g_critical ("pushing on pad %s:%s but it was not activated in push mode", GST_DEBUG_PAD_NAME (pad)); + pad->ABI.abi.last_flowret = GST_FLOW_ERROR; GST_OBJECT_UNLOCK (pad); gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); return GST_FLOW_ERROR; @@ -4094,6 +4105,7 @@ events_error: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "error pushing events, return %s", gst_flow_get_name (ret)); + pad->ABI.abi.last_flowret = ret; GST_OBJECT_UNLOCK (pad); gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); return ret; @@ -4101,6 +4113,8 @@ events_error: probe_stopped: { GST_OBJECT_UNLOCK (pad); + pad->ABI.abi.last_flowret = + ret == GST_FLOW_CUSTOM_SUCCESS ? GST_FLOW_OK : ret; gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); switch (ret) { @@ -4118,6 +4132,7 @@ not_linked: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but it was not linked"); + pad->ABI.abi.last_flowret = GST_FLOW_NOT_LINKED; GST_OBJECT_UNLOCK (pad); gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); return GST_FLOW_NOT_LINKED; @@ -4240,14 +4255,15 @@ gst_pad_get_range_unchecked (GstPad * pad, guint64 offset, guint size, RELEASE_PARENT (parent); + GST_OBJECT_LOCK (pad); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto get_range_failed; /* can only fire the signal if we have a valid buffer */ - GST_OBJECT_LOCK (pad); probed_data: PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER, res_buf, offset, size, probe_stopped_unref); + pad->ABI.abi.last_flowret = ret; GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); @@ -4261,6 +4277,7 @@ flushing: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "getrange, but pad was flushing"); + pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING; GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); return GST_FLOW_FLUSHING; @@ -4269,6 +4286,7 @@ wrong_mode: { g_critical ("getrange on pad %s:%s but it was not activated in pull mode", GST_DEBUG_PAD_NAME (pad)); + pad->ABI.abi.last_flowret = GST_FLOW_ERROR; GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); return GST_FLOW_ERROR; @@ -4276,6 +4294,7 @@ wrong_mode: events_error: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "error pushing events"); + pad->ABI.abi.last_flowret = ret; GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); return ret; @@ -4283,6 +4302,7 @@ events_error: no_parent: { GST_DEBUG_OBJECT (pad, "no parent"); + pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING; GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); return GST_FLOW_FLUSHING; @@ -4312,6 +4332,7 @@ probe_stopped: ret = GST_FLOW_EOS; } } + pad->ABI.abi.last_flowret = ret; GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); @@ -4324,6 +4345,7 @@ probe_stopped_unref: /* if we drop here, it signals EOS */ if (ret == GST_FLOW_CUSTOM_SUCCESS) ret = GST_FLOW_EOS; + pad->ABI.abi.last_flowret = ret; GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); if (*buffer == NULL) @@ -4332,6 +4354,8 @@ probe_stopped_unref: } get_range_failed: { + pad->ABI.abi.last_flowret = ret; + GST_OBJECT_UNLOCK (pad); GST_PAD_STREAM_UNLOCK (pad); GST_CAT_LEVEL_LOG (GST_CAT_SCHEDULING, (ret >= GST_FLOW_EOS) ? GST_LEVEL_INFO : GST_LEVEL_WARNING, @@ -4472,6 +4496,7 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size, GST_OBJECT_LOCK (pad); pad->priv->using--; + pad->ABI.abi.last_flowret = ret; if (pad->priv->using == 0) { /* pad is not active anymore, trigger idle callbacks */ PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_IDLE, @@ -4496,6 +4521,7 @@ flushing: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pullrange, but pad was flushing"); + pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING; GST_OBJECT_UNLOCK (pad); return GST_FLOW_FLUSHING; } @@ -4503,6 +4529,7 @@ wrong_mode: { g_critical ("pullrange on pad %s:%s but it was not activated in pull mode", GST_DEBUG_PAD_NAME (pad)); + pad->ABI.abi.last_flowret = GST_FLOW_ERROR; GST_OBJECT_UNLOCK (pad); return GST_FLOW_ERROR; } @@ -4523,6 +4550,7 @@ probe_stopped: ret = GST_FLOW_EOS; } } + pad->ABI.abi.last_flowret = ret; GST_OBJECT_UNLOCK (pad); return ret; } @@ -4530,11 +4558,13 @@ not_linked: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pulling range, but it was not linked"); + pad->ABI.abi.last_flowret = GST_FLOW_NOT_LINKED; GST_OBJECT_UNLOCK (pad); return GST_FLOW_NOT_LINKED; } pull_range_failed: { + pad->ABI.abi.last_flowret = ret; GST_OBJECT_UNLOCK (pad); GST_CAT_LEVEL_LOG (GST_CAT_SCHEDULING, (ret >= GST_FLOW_EOS) ? GST_LEVEL_INFO : GST_LEVEL_WARNING, @@ -4545,10 +4575,14 @@ probe_stopped_unref: { GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "post probe returned %s", gst_flow_get_name (ret)); - GST_OBJECT_UNLOCK (pad); + /* if we drop here, it signals EOS */ if (ret == GST_FLOW_CUSTOM_SUCCESS) ret = GST_FLOW_EOS; + + pad->ABI.abi.last_flowret = ret; + GST_OBJECT_UNLOCK (pad); + if (*buffer == NULL) gst_buffer_unref (res_buf); return ret; @@ -4646,8 +4680,10 @@ store_sticky_event (GstPad * pad, GstEvent * event) break; } } - if (type == GST_EVENT_EOS) + if (type == GST_EVENT_EOS) { GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_EOS); + pad->ABI.abi.last_flowret = GST_FLOW_EOS; + } return GST_PAD_IS_FLUSHING (pad) ? GST_FLOW_FLUSHING : GST_FLOW_OK; @@ -4736,6 +4772,7 @@ gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event, remove_event_by_type (pad, GST_EVENT_EOS); remove_event_by_type (pad, GST_EVENT_SEGMENT); GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS); + pad->ABI.abi.last_flowret = GST_FLOW_OK; type |= GST_PAD_PROBE_TYPE_EVENT_FLUSH; break; @@ -5034,6 +5071,7 @@ gst_pad_send_event_unchecked (GstPad * pad, GstEvent * event, remove_event_by_type (pad, GST_EVENT_EOS); remove_event_by_type (pad, GST_EVENT_SEGMENT); GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS); + pad->ABI.abi.last_flowret = GST_FLOW_OK; GST_OBJECT_UNLOCK (pad); /* grab stream lock */ @@ -5674,3 +5712,23 @@ gst_pad_probe_info_get_buffer_list (GstPadProbeInfo * info) return GST_PAD_PROBE_INFO_BUFFER_LIST (info); } + +/** + * gst_pad_get_last_flowreturn: + * @pad: the #GstPad + * + * Gets the #GstFlowReturn return from the last data passed by this pad. + * + * Since: 1.4 + */ +GstFlowReturn +gst_pad_get_last_flow_return (GstPad * pad) +{ + GstFlowReturn ret; + + GST_OBJECT_LOCK (pad); + ret = GST_PAD_LAST_FLOW_RETURN (pad); + GST_OBJECT_UNLOCK (pad); + + return ret; +} diff --git a/gst/gstpad.h b/gst/gstpad.h index e024ad4758..103253fc50 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -726,7 +726,12 @@ struct _GstPad { GstPadPrivate *priv; - gpointer _gst_reserved[GST_PADDING]; + union { + gpointer _gst_reserved[GST_PADDING]; + struct { + GstFlowReturn last_flowret; + } abi; + } ABI; }; struct _GstPadClass { @@ -1140,6 +1145,13 @@ struct _GstPadClass { * Release the pad's stream lock. */ #define GST_PAD_STREAM_UNLOCK(pad) g_rec_mutex_unlock(GST_PAD_GET_STREAM_LOCK(pad)) +/** + * GST_PAD_LAST_FLOW_RETURN: + * @pad: a #GstPad + * + * Gets the last flow return on this pad + */ +#define GST_PAD_LAST_FLOW_RETURN(pad) (GST_PAD_CAST(pad)->ABI.abi.last_flowret) #define GST_PAD_BLOCK_GET_COND(pad) (&GST_PAD_CAST(pad)->block_cond) #define GST_PAD_BLOCK_WAIT(pad) (g_cond_wait(GST_PAD_BLOCK_GET_COND (pad), GST_OBJECT_GET_LOCK (pad))) @@ -1282,6 +1294,7 @@ GstFlowReturn gst_pad_pull_range (GstPad *pad, guint64 offset, guint size, gboolean gst_pad_push_event (GstPad *pad, GstEvent *event); gboolean gst_pad_event_default (GstPad *pad, GstObject *parent, GstEvent *event); +GstFlowReturn gst_pad_get_last_flow_return (GstPad *pad); /* data passing functions on pad */ GstFlowReturn gst_pad_chain (GstPad *pad, GstBuffer *buffer); diff --git a/tests/check/gst/gstpad.c b/tests/check/gst/gstpad.c index 2b193b170d..cf4586d4f5 100644 --- a/tests/check/gst/gstpad.c +++ b/tests/check/gst/gstpad.c @@ -1813,6 +1813,169 @@ GST_START_TEST (test_sticky_events) GST_END_TEST; +static GstFlowReturn next_return; + +static GstFlowReturn +test_lastflow_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) +{ + gst_buffer_unref (buffer); + return next_return; +} + +GST_START_TEST (test_last_flow_return_push) +{ + GstPad *srcpad, *sinkpad; + GstSegment seg; + + srcpad = gst_pad_new ("src", GST_PAD_SRC); + fail_unless (srcpad != NULL); + sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + fail_unless (sinkpad != NULL); + gst_pad_set_chain_function (sinkpad, test_lastflow_chain); + gst_pad_link (srcpad, sinkpad); + + /* initial value is flushing */ + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_FLUSHING); + + /* when active it goes to ok */ + gst_pad_set_active (srcpad, TRUE); + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_OK); + gst_pad_set_active (sinkpad, TRUE); + + /* startup events */ + gst_pad_push_event (srcpad, gst_event_new_stream_start ("test")); + gst_segment_init (&seg, GST_FORMAT_TIME); + gst_pad_push_event (srcpad, gst_event_new_segment (&seg)); + + + /* push Ok */ + next_return = GST_FLOW_OK; + fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK); + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_OK); + + /* push not-linked */ + next_return = GST_FLOW_NOT_LINKED; + fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_NOT_LINKED); + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_NOT_LINKED); + + /* push not-linked */ + next_return = GST_FLOW_NOT_NEGOTIATED; + fail_unless (gst_pad_push (srcpad, + gst_buffer_new ()) == GST_FLOW_NOT_NEGOTIATED); + fail_unless (gst_pad_get_last_flow_return (srcpad) == + GST_FLOW_NOT_NEGOTIATED); + + /* push error */ + next_return = GST_FLOW_ERROR; + fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_ERROR); + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_ERROR); + + /* back to ok */ + next_return = GST_FLOW_OK; + fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK); + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_OK); + + /* unlinked push */ + gst_pad_unlink (srcpad, sinkpad); + fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_NOT_LINKED); + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_NOT_LINKED); + + gst_pad_link (srcpad, sinkpad); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ())); + fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_EOS); + + gst_object_unref (srcpad); + gst_object_unref (sinkpad); +} + +GST_END_TEST; + +static GstFlowReturn +test_lastflow_getrange (GstPad * pad, GstObject * parent, guint64 offset, + guint length, GstBuffer ** buf) +{ + if (next_return == GST_FLOW_OK) + *buf = gst_buffer_new (); + else + *buf = NULL; + return next_return; +} + +static gboolean +test_lastflow_activate_pull_func (GstPad * pad, GstObject * object) +{ + return gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE); +} + +GST_START_TEST (test_last_flow_return_pull) +{ + GstPad *srcpad, *sinkpad; + GstBuffer *buf = NULL; + + srcpad = gst_pad_new ("src", GST_PAD_SRC); + fail_unless (srcpad != NULL); + sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + fail_unless (sinkpad != NULL); + gst_pad_set_getrange_function (srcpad, test_lastflow_getrange); + gst_pad_set_activate_function (sinkpad, test_lastflow_activate_pull_func); + gst_pad_link (srcpad, sinkpad); + + /* initial value is flushing */ + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_FLUSHING); + + /* when active it goes to ok */ + gst_pad_set_active (sinkpad, TRUE); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_OK); + gst_pad_set_active (srcpad, TRUE); + + /* pull Ok */ + next_return = GST_FLOW_OK; + fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_OK); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_OK); + gst_buffer_unref (buf); + buf = NULL; + + /* pull not-linked */ + next_return = GST_FLOW_NOT_LINKED; + fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_NOT_LINKED); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_NOT_LINKED); + + /* pull error */ + next_return = GST_FLOW_ERROR; + fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_ERROR); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_ERROR); + + /* pull not-nego */ + next_return = GST_FLOW_NOT_NEGOTIATED; + fail_unless (gst_pad_pull_range (sinkpad, 0, 1, + &buf) == GST_FLOW_NOT_NEGOTIATED); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == + GST_FLOW_NOT_NEGOTIATED); + + /* pull ok again */ + next_return = GST_FLOW_OK; + fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_OK); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_OK); + gst_buffer_unref (buf); + buf = NULL; + + /* unlinked pads */ + gst_pad_unlink (srcpad, sinkpad); + fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_NOT_LINKED); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_NOT_LINKED); + + /* eos */ + gst_pad_link (srcpad, sinkpad); + next_return = GST_FLOW_EOS; + fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_EOS); + fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_EOS); + + gst_object_unref (srcpad); + gst_object_unref (sinkpad); +} + +GST_END_TEST; + static Suite * gst_pad_suite (void) { @@ -1856,6 +2019,8 @@ gst_pad_suite (void) tcase_add_test (tc_chain, test_block_async_full_destroy_dispose); tcase_add_test (tc_chain, test_block_async_replace_callback_no_flush); tcase_add_test (tc_chain, test_sticky_events); + tcase_add_test (tc_chain, test_last_flow_return_push); + tcase_add_test (tc_chain, test_last_flow_return_pull); return s; } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 1fa5caaca8..405885b504 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -785,6 +785,7 @@ EXPORTS gst_pad_get_current_caps gst_pad_get_direction gst_pad_get_element_private + gst_pad_get_last_flow_return gst_pad_get_offset gst_pad_get_pad_template gst_pad_get_pad_template_caps