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
This commit is contained in:
Thiago Santos 2014-05-23 13:25:35 -03:00
parent 103a40b6ce
commit c6f92562b6
4 changed files with 241 additions and 4 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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