summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
authorEdward Hervey <edward@centricular.com>2015-04-29 15:49:17 +0200
committerEdward Hervey <bilboed@bilboed.com>2015-08-15 17:00:12 +0200
commit7f0e0ff3ca4f3533e66843c084d084517cff4d47 (patch)
tree4fef69955f75fa32d1750ab39653ec641c239e5c /gst
parentafff60b0b59b15a29ade9d4e41aecee414bffe01 (diff)
gstpad: Add a new GST_PROBE_HANDLED return value for probes
In some cases, probes might want to handle the buffer/event/query themselves and stop the data from travelling further downstream. While this was somewhat possible with buffer/events and using GST_PROBE_DROP, it was not applicable to queries, and would result in the query failing. With this new GST_PROBE_HANDLED value, the buffer/event/query will be considered as successfully handled, will not be pushed further and the appropriate return value (TRUE or GST_FLOW_OK) will be returned This also allows probes to return a non-default GstFlowReturn when dealing with buffer push. This can be done by setting the GST_PAD_PROBE_INFO_FLOW_RETURN() field accordingly https://bugzilla.gnome.org/show_bug.cgi?id=748643
Diffstat (limited to 'gst')
-rw-r--r--gst/gstpad.c129
-rw-r--r--gst/gstpad.h17
2 files changed, 108 insertions, 38 deletions
diff --git a/gst/gstpad.c b/gst/gstpad.c
index 49a3e954b..5a7fc0ad2 100644
--- a/gst/gstpad.c
+++ b/gst/gstpad.c
@@ -163,6 +163,7 @@ typedef struct
GstPadProbeInfo *info;
gboolean dropped;
gboolean pass;
+ gboolean handled;
gboolean marshalled;
guint cookie;
} ProbeMarshall;
@@ -1420,6 +1421,9 @@ gst_pad_add_probe (GstPad * pad, GstPadProbeType mask,
case GST_PAD_PROBE_OK:
GST_DEBUG_OBJECT (pad, "probe returned OK");
break;
+ case GST_PAD_PROBE_HANDLED:
+ GST_DEBUG_OBJECT (pad, "probe handled the data");
+ break;
default:
GST_DEBUG_OBJECT (pad, "probe returned %d", ret);
break;
@@ -3363,6 +3367,10 @@ probe_hook_marshal (GHook * hook, ProbeMarshall * data)
info->type = GST_PAD_PROBE_TYPE_INVALID;
data->dropped = TRUE;
break;
+ case GST_PAD_PROBE_HANDLED:
+ GST_DEBUG_OBJECT (pad, "probe handled data");
+ data->handled = TRUE;
+ break;
case GST_PAD_PROBE_PASS:
/* inform the pad block to let things pass */
GST_DEBUG_OBJECT (pad, "asked to pass item");
@@ -3392,31 +3400,40 @@ no_match:
if (G_UNLIKELY (pad->num_probes)) { \
GstFlowReturn pval = defaultval; \
/* pass NULL as the data item */ \
- GstPadProbeInfo info = { mask, 0, NULL, 0, 0 }; \
+ GstPadProbeInfo info = { mask, 0, NULL, 0, 0 }; \
+ info.ABI.abi.flow_ret = defaultval; \
ret = do_probe_callbacks (pad, &info, defaultval); \
if (G_UNLIKELY (ret != pval && ret != GST_FLOW_OK)) \
goto label; \
} \
} G_STMT_END
-#define PROBE_FULL(pad,mask,data,offs,size,label) \
- G_STMT_START { \
- if (G_UNLIKELY (pad->num_probes)) { \
- /* pass the data item */ \
- GstPadProbeInfo info = { mask, 0, data, offs, size }; \
- ret = do_probe_callbacks (pad, &info, GST_FLOW_OK); \
- /* store the possibly updated data item */ \
- data = GST_PAD_PROBE_INFO_DATA (&info); \
- /* if something went wrong, exit */ \
- if (G_UNLIKELY (ret != GST_FLOW_OK)) \
- goto label; \
- } \
+#define PROBE_FULL(pad,mask,data,offs,size,label,handleable,handle_label) \
+ G_STMT_START { \
+ if (G_UNLIKELY (pad->num_probes)) { \
+ /* pass the data item */ \
+ GstPadProbeInfo info = { mask, 0, data, offs, size }; \
+ info.ABI.abi.flow_ret = GST_FLOW_OK; \
+ ret = do_probe_callbacks (pad, &info, GST_FLOW_OK); \
+ /* store the possibly updated data item */ \
+ data = GST_PAD_PROBE_INFO_DATA (&info); \
+ /* if something went wrong, exit */ \
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) { \
+ if (handleable && ret == GST_FLOW_CUSTOM_SUCCESS_1) { \
+ ret = info.ABI.abi.flow_ret; \
+ goto handle_label; \
+ } \
+ goto label; \
+ } \
+ } \
} G_STMT_END
-#define PROBE_PUSH(pad,mask,data,label) \
- PROBE_FULL(pad, mask, data, -1, -1, label);
-#define PROBE_PULL(pad,mask,data,offs,size,label) \
- PROBE_FULL(pad, mask, data, offs, size, label);
+#define PROBE_PUSH(pad,mask,data,label) \
+ PROBE_FULL(pad, mask, data, -1, -1, label, FALSE, label);
+#define PROBE_HANDLE(pad,mask,data,label,handle_label) \
+ PROBE_FULL(pad, mask, data, -1, -1, label, TRUE, handle_label);
+#define PROBE_PULL(pad,mask,data,offs,size,label) \
+ PROBE_FULL(pad, mask, data, offs, size, label, FALSE, label);
static GstFlowReturn
do_pad_idle_probe_wait (GstPad * pad)
@@ -3461,6 +3478,7 @@ do_probe_callbacks (GstPad * pad, GstPadProbeInfo * info,
data.pad = pad;
data.info = info;
data.pass = FALSE;
+ data.handled = FALSE;
data.marshalled = FALSE;
data.dropped = FALSE;
data.cookie = ++pad->priv->probe_cookie;
@@ -3493,6 +3511,11 @@ again:
if (data.dropped)
goto dropped;
+ /* If one handler took care of it, let the the item pass */
+ if (data.handled) {
+ goto handled;
+ }
+
/* if no handler matched and we are blocking, let the item pass */
if (!data.marshalled && is_block)
goto passed;
@@ -3554,6 +3577,11 @@ passed:
GST_DEBUG_OBJECT (pad, "data is passed");
return GST_FLOW_OK;
}
+handled:
+ {
+ GST_DEBUG_OBJECT (pad, "data was handled");
+ return GST_FLOW_CUSTOM_SUCCESS_1;
+ }
}
/* pad offsets */
@@ -3855,9 +3883,12 @@ probe_stopped:
if (G_UNLIKELY (serialized))
GST_PAD_STREAM_UNLOCK (pad);
- /* if a probe dropped, we don't sent it further but assume that the probe
- * did not answer the query and return FALSE */
- res = FALSE;
+ /* if a probe dropped without handling, we don't sent it further but assume
+ * that the probe did not answer the query and return FALSE */
+ if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+ res = FALSE;
+ else
+ res = TRUE;
return res;
}
@@ -3969,9 +4000,12 @@ probe_stopped:
GST_DEBUG_OBJECT (pad, "probe stopped: %s", gst_flow_get_name (ret));
GST_OBJECT_UNLOCK (pad);
- /* if a probe dropped, we don't sent it further but assume that the probe
- * did not answer the query and return FALSE */
- res = FALSE;
+ /* if a probe dropped without handling, we don't sent it further but
+ * assume that the probe did not answer the query and return FALSE */
+ if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+ res = FALSE;
+ else
+ res = TRUE;
return res;
}
@@ -3989,6 +4023,7 @@ gst_pad_chain_data_unchecked (GstPad * pad, GstPadProbeType type, void *data)
{
GstFlowReturn ret;
GstObject *parent;
+ gboolean handled = FALSE;
GST_PAD_STREAM_LOCK (pad);
@@ -4018,9 +4053,10 @@ gst_pad_chain_data_unchecked (GstPad * pad, GstPadProbeType type, void *data)
}
#endif
- PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
+ PROBE_HANDLE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped,
+ probe_handled);
- PROBE_PUSH (pad, type, data, probe_stopped);
+ PROBE_HANDLE (pad, type, data, probe_stopped, probe_handled);
ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
@@ -4095,15 +4131,21 @@ wrong_mode:
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return GST_FLOW_ERROR;
}
+probe_handled:
+ handled = TRUE;
+ /* PASSTHROUGH */
probe_stopped:
{
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
- gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+ /* We unref the buffer, except if the probe handled it (CUSTOM_SUCCESS_1) */
+ if (!handled)
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
switch (ret) {
case GST_FLOW_CUSTOM_SUCCESS:
- GST_DEBUG_OBJECT (pad, "dropped buffer");
+ case GST_FLOW_CUSTOM_SUCCESS_1:
+ GST_DEBUG_OBJECT (pad, "dropped or handled buffer");
ret = GST_FLOW_OK;
break;
default:
@@ -4236,6 +4278,7 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
{
GstPad *peer;
GstFlowReturn ret;
+ gboolean handled = FALSE;
GST_OBJECT_LOCK (pad);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
@@ -4267,14 +4310,15 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
goto events_error;
/* do block probes */
- PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
+ PROBE_HANDLE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped,
+ probe_handled);
/* recheck sticky events because the probe might have cause a relink */
if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
goto events_error;
/* do post-blocking probes */
- PROBE_PUSH (pad, type, data, probe_stopped);
+ PROBE_HANDLE (pad, type, data, probe_stopped, probe_handled);
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto not_linked;
@@ -4338,23 +4382,26 @@ events_error:
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return ret;
}
+probe_handled:
+ handled = TRUE;
+ /* PASSTHROUGH */
probe_stopped:
{
GST_OBJECT_UNLOCK (pad);
- pad->ABI.abi.last_flowret =
- ret == GST_FLOW_CUSTOM_SUCCESS ? GST_FLOW_OK : ret;
- if (data != NULL)
+ if (data != NULL && !handled)
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
switch (ret) {
case GST_FLOW_CUSTOM_SUCCESS:
- GST_DEBUG_OBJECT (pad, "dropped buffer");
+ case GST_FLOW_CUSTOM_SUCCESS_1:
+ GST_DEBUG_OBJECT (pad, "dropped or handled buffer");
ret = GST_FLOW_OK;
break;
default:
GST_DEBUG_OBJECT (pad, "an error occurred %s", gst_flow_get_name (ret));
break;
}
+ pad->ABI.abi.last_flowret = ret;
return ret;
}
not_linked:
@@ -5102,9 +5149,13 @@ inactive:
probe_stopped:
{
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
- gst_event_unref (event);
+ if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+ gst_event_unref (event);
switch (ret) {
+ case GST_FLOW_CUSTOM_SUCCESS_1:
+ GST_DEBUG_OBJECT (pad, "handled event");
+ break;
case GST_FLOW_CUSTOM_SUCCESS:
GST_DEBUG_OBJECT (pad, "dropped event");
break;
@@ -5200,7 +5251,8 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
/* other events are pushed right away */
ret = gst_pad_push_event_unchecked (pad, event, type);
/* dropped events by a probe are not an error */
- res = (ret == GST_FLOW_OK || ret == GST_FLOW_CUSTOM_SUCCESS);
+ res = (ret == GST_FLOW_OK || ret == GST_FLOW_CUSTOM_SUCCESS
+ || ret == GST_FLOW_CUSTOM_SUCCESS_1);
} else {
/* Errors in sticky event pushing are no problem and ignored here
* as they will cause more meaningful errors during data flow.
@@ -5467,11 +5519,14 @@ probe_stopped:
GST_OBJECT_UNLOCK (pad);
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
- gst_event_unref (event);
+ /* Only unref if unhandled */
+ if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+ gst_event_unref (event);
switch (ret) {
+ case GST_FLOW_CUSTOM_SUCCESS_1:
case GST_FLOW_CUSTOM_SUCCESS:
- GST_DEBUG_OBJECT (pad, "dropped event");
+ GST_DEBUG_OBJECT (pad, "dropped or handled event");
ret = GST_FLOW_OK;
break;
default:
diff --git a/gst/gstpad.h b/gst/gstpad.h
index 89a24d42a..157d147b7 100644
--- a/gst/gstpad.h
+++ b/gst/gstpad.h
@@ -514,6 +514,14 @@ typedef enum
* @GST_PAD_PROBE_REMOVE: remove this probe.
* @GST_PAD_PROBE_PASS: pass the data item in the block probe and block on the
* next item.
+ * @GST_PAD_PROBE_HANDLED: Data has been handled in the probe and will not be
+ * forwarded further. For events and buffers this is the same behaviour as
+ * @GST_PAD_PROBE_DROP (except that in this case you need to unref the buffer
+ * or event yourself). For queries it will also return %TRUE to the caller.
+ * The probe can also modify the #GstFlowReturn value by using the
+ * #GST_PAD_PROBE_INFO_FLOW_RETURN() accessor.
+ * Note that the resulting query must contain valid entries.
+ * Since: 1.6
*
* Different return values for the #GstPadProbeCallback.
*/
@@ -523,6 +531,7 @@ typedef enum
GST_PAD_PROBE_OK,
GST_PAD_PROBE_REMOVE,
GST_PAD_PROBE_PASS,
+ GST_PAD_PROBE_HANDLED
} GstPadProbeReturn;
@@ -548,12 +557,18 @@ struct _GstPadProbeInfo
guint size;
/*< private >*/
- gpointer _gst_reserved[GST_PADDING];
+ union {
+ gpointer _gst_reserved[GST_PADDING];
+ struct {
+ GstFlowReturn flow_ret;
+ } abi;
+ } ABI;
};
#define GST_PAD_PROBE_INFO_TYPE(d) ((d)->type)
#define GST_PAD_PROBE_INFO_ID(d) ((d)->id)
#define GST_PAD_PROBE_INFO_DATA(d) ((d)->data)
+#define GST_PAD_PROBE_INFO_FLOW_RETURN(d) ((d)->ABI.abi.flow_ret)
#define GST_PAD_PROBE_INFO_BUFFER(d) GST_BUFFER_CAST(GST_PAD_PROBE_INFO_DATA(d))
#define GST_PAD_PROBE_INFO_BUFFER_LIST(d) GST_BUFFER_LIST_CAST(GST_PAD_PROBE_INFO_DATA(d))