Commit ce090102 authored by Wim Taymans's avatar Wim Taymans

pad: add pull mode probes

Allow probes to inspect the offset and size from a probe in pull mode and allow
the probe to modify the buffer.
Update design doc a little.
parent ba3028ae
......@@ -45,20 +45,22 @@ Overview
typedef enum
{
GST_PAD_PROBE_TYPE_INVALID = 0,
GST_PAD_PROBE_TYPE_INVALID = 0,
/* flags to control blocking */
GST_PAD_PROBE_TYPE_IDLE = (1 << 0),
GST_PAD_PROBE_TYPE_BLOCK = (1 << 1),
GST_PAD_PROBE_TYPE_IDLE = (1 << 0),
GST_PAD_PROBE_TYPE_BLOCK = (1 << 1),
/* flags to select datatypes */
GST_PAD_PROBE_TYPE_BUFFER = (1 << 2),
GST_PAD_PROBE_TYPE_BUFFER_LIST = (1 << 3),
GST_PAD_PROBE_TYPE_EVENT = (1 << 4),
GST_PAD_PROBE_TYPE_BUFFER = (1 << 2),
GST_PAD_PROBE_TYPE_BUFFER_LIST = (1 << 3),
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM = (1 << 4),
GST_PAD_PROBE_TYPE_EVENT_UPSTREAM = (1 << 5),
/* flags to select scheduling mode */
GST_PAD_PROBE_TYPE_PUSH = (1 << 5),
GST_PAD_PROBE_TYPE_PULL = (1 << 6),
GST_PAD_PROBE_TYPE_PUSH = (1 << 6),
GST_PAD_PROBE_TYPE_PULL = (1 << 7),
} GstPadProbeType;
When adding a probe with the IDLE or BLOCK flag, the probe will become a
......@@ -71,14 +73,13 @@ Overview
The probe callback is defined as:
GstPadProbeReturn (*GstPadProbeCallback) (GstPad *pad, GstPadProbeType type,
gpointer type_data,
GstPadProbeReturn (*GstPadProbeCallback) (GstPad *pad, GstPadProbeInfo *info,
gpointer user_data);
The executing probe type is passed as an argument and is guaranteed to match
the mask that was used to register the callback. type_data contains type
specific data, which is usually the data item that is blocked or NULL when
no data item is present.
A probe info structure is passed as an argument and its type is guaranteed
to match the mask that was used to register the callback. The data item in the
info contains type specific data, which is usually the data item that is blocked
or NULL when no data item is present.
The probe can return any of the following return values:
......@@ -111,8 +112,8 @@ Blocking probes
thread.
The IDLE probe in useful to perform dynamic linking, it allows to wait for for
a safe moment when an unlink/link operation can be done. Since the event is a
blocking event, it will also make sure that the pad stays idle until the probe
a safe moment when an unlink/link operation can be done. Since the probe is a
blocking probe, it will also make sure that the pad stays idle until the probe
is removed.
When the BLOCK flag is set, the probe callback will be called when new data
......@@ -135,7 +136,7 @@ Non-Blocking probes
Push dataflow
-------------
All probes have the GST_PAD_PROBE_TYPE_PUSH flag set in the callbacks.
Push probes have the GST_PAD_PROBE_TYPE_PUSH flag set in the callbacks.
In push based scheduling, the blocking probe is called first with the data item.
Then the data probes are called before the peer pad chain or event function is
......@@ -144,13 +145,13 @@ called.
The data probes are called before the peer pad is checked. This allows for
linking the pad in either the BLOCK or DATA probes on the pad.
Before the peerpad chain or event function is called, the peer pad data probes
are called.
Before the peerpad chain or event function is called, the peer pad block and
data probes are called.
Finally, the IDLE probe is called on the pad after the data was sent to the
peer pad.
The push dataflow probe behavior is the same for buffers and biderectional events.
The push dataflow probe behavior is the same for buffers and bidirectional events.
pad peerpad
......@@ -191,19 +192,20 @@ The push dataflow probe behavior is the same for buffers and biderectional event
Pull dataflow
-------------
All probes have the GST_PAD_PROBE_TYPE_PULL flag set in the callbacks.
Pull probes have the GST_PAD_PROBE_TYPE_PULL flag set in the callbacks.
The gst_pad_pull_range() call will first trigger the BLOCK probes without a DATA
item. This allows the pad to be linked before the peer pad is resolved.
item. This allows the pad to be linked before the peer pad is resolved. It also
allows the callback to set a data item in the probe info.
After the getrange function is called on the peer pad and there is a data item,
the DATA probes are called.
After the blocking probe and the getrange function is called on the peer pad
and there is a data item, the DATA probes are called.
When control returns to the sinkpad, the IDLE callbacks are called. The IDLE
callback is called without a data item so that it will also be called when there
was an error.
It there is a valid DATA item, the DATA probes are called for the item.
If there is a valid DATA item, the DATA probes are called for the item.
srcpad sinkpad
......
......@@ -3400,20 +3400,40 @@ no_match:
}
}
#define PROBE_ND_FULL(pad,mask,label,defaultval) \
#define PROBE_PRE_PULL(pad,mask,data,offs,size,label,probed,defaultval) \
G_STMT_START { \
if (G_UNLIKELY (pad->num_probes)) { \
GstPadProbeInfo info = { mask, NULL }; \
/* we start with passing NULL as the data item */ \
GstPadProbeInfo info = { mask, NULL, offs, size }; \
ret = do_probe_callbacks (pad, &info, defaultval); \
/* store the possibly updated data item */ \
data = GST_PAD_PROBE_INFO_DATA (&info); \
/* if something went wrong, exit */ \
if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK)) \
goto label; \
/* otherwise check if the probe retured data */ \
if (G_UNLIKELY (data != NULL)) \
goto probed; \
} \
} G_STMT_END
/* a probe that does not take or return any data */
#define PROBE_NO_DATA(pad,mask,label,defaultval) \
G_STMT_START { \
if (G_UNLIKELY (pad->num_probes)) { \
/* pass NULL as the data item */ \
GstPadProbeInfo info = { mask, NULL, 0, 0 }; \
ret = do_probe_callbacks (pad, &info, defaultval); \
if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK)) \
goto label; \
} \
} G_STMT_END
#define PROBE_FULL(pad,mask,data,label,defaultval) \
#define PROBE_FULL(pad,mask,data,offs,size,label,defaultval) \
G_STMT_START { \
if (G_UNLIKELY (pad->num_probes)) { \
GstPadProbeInfo info = { mask, data }; \
GstPadProbeInfo info = { mask, data, offs, size }; \
ret = do_probe_callbacks (pad, &info, defaultval); \
data = GST_PAD_PROBE_INFO_DATA (&info); \
if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK)) \
......@@ -3421,10 +3441,10 @@ no_match:
} \
} G_STMT_END
#define PROBE(pad,mask,data,label) \
PROBE_FULL(pad, mask, data, label, GST_FLOW_OK);
#define PROBE_ND(pad,mask,label) \
PROBE_ND_FULL(pad, mask, label, GST_FLOW_OK);
#define PROBE_PUSH(pad,mask,data,label) \
PROBE_FULL(pad, mask, data, -1, -1, label, GST_FLOW_OK);
#define PROBE_PULL(pad,mask,data,offs,size,label) \
PROBE_FULL(pad, mask, data, offs, size, label, GST_FLOW_OK);
static GstFlowReturn
do_probe_callbacks (GstPad * pad, GstPadProbeInfo * info,
......@@ -3637,9 +3657,9 @@ gst_pad_chain_data_unchecked (GstPad * pad, GstPadProbeType type, void *data)
goto events_error;
}
PROBE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
PROBE (pad, type, data, probe_stopped);
PROBE_PUSH (pad, type, data, probe_stopped);
GST_OBJECT_UNLOCK (pad);
......@@ -3844,10 +3864,10 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
goto flushing;
/* do block probes */
PROBE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
/* do post-blocking probes */
PROBE (pad, type, data, probe_stopped);
PROBE_PUSH (pad, type, data, probe_stopped);
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto not_linked;
......@@ -3865,7 +3885,7 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
pad->priv->using--;
if (pad->priv->using == 0) {
/* pad is not active anymore, trigger idle callbacks */
PROBE_ND_FULL (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
probe_stopped, ret);
}
GST_OBJECT_UNLOCK (pad);
......@@ -3991,8 +4011,10 @@ gst_pad_get_range_unchecked (GstPad * pad, guint64 offset, guint size,
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
PROBE_ND (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
probe_stopped);
/* when one of the probes returns a buffer, probed_data will be called and we
* skip calling the getrange function */
PROBE_PRE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
*buffer, offset, size, probe_stopped, probed_data, GST_FLOW_OK);
GST_OBJECT_UNLOCK (pad);
if (G_UNLIKELY ((getrangefunc = GST_PAD_GETRANGEFUNC (pad)) == NULL))
......@@ -4010,8 +4032,9 @@ gst_pad_get_range_unchecked (GstPad * pad, guint64 offset, guint size,
/* can only fire the signal if we have a valid buffer */
GST_OBJECT_LOCK (pad);
PROBE (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER, *buffer,
probe_stopped_unref);
probed_data:
PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER,
*buffer, offset, size, probe_stopped_unref);
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
......@@ -4139,8 +4162,10 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
PROBE_ND (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
pre_probe_stopped);
/* when one of the probes returns a buffer, probed_data will be called and we
* skip calling the peer getrange function */
PROBE_PRE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
*buffer, offset, size, pre_probe_stopped, probed_data, GST_FLOW_OK);
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto not_linked;
......@@ -4157,15 +4182,16 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
pad->priv->using--;
if (pad->priv->using == 0) {
/* pad is not active anymore, trigger idle callbacks */
PROBE_ND (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_IDLE,
post_probe_stopped);
PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_IDLE,
post_probe_stopped, ret);
}
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto pull_range_failed;
PROBE (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER, buffer,
post_probe_stopped);
probed_data:
PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER,
*buffer, offset, size, post_probe_stopped);
needs_events = GST_PAD_NEEDS_EVENTS (pad);
if (G_UNLIKELY (needs_events)) {
......@@ -4360,7 +4386,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushed;
PROBE (pad, type | GST_PAD_PROBE_TYPE_PUSH |
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH |
GST_PAD_PROBE_TYPE_BLOCK, event, probe_stopped);
break;
......@@ -4368,7 +4394,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
}
/* send probes after modifying the events above */
PROBE (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
/* now check the peer pad */
if (peerpad == NULL)
......@@ -4395,8 +4421,8 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
pad->priv->using--;
if (pad->priv->using == 0) {
/* pad is not active anymore, trigger idle callbacks */
PROBE_ND (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
probe_stopped);
PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
probe_stopped, GST_FLOW_OK);
}
GST_OBJECT_UNLOCK (pad);
......@@ -4574,11 +4600,11 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
PROBE (pad,
PROBE_PUSH (pad,
type | GST_PAD_PROBE_TYPE_PUSH |
GST_PAD_PROBE_TYPE_BLOCK, event, probe_stopped);
PROBE (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
break;
}
......
......@@ -213,9 +213,9 @@ typedef enum {
/**
* GstPadActivateMode:
* @GST_PAD_ACTIVATE_NONE: Pad will not handle dataflow
* @GST_PAD_ACTIVATE_PUSH: Pad handles dataflow in downstream push mode
* @GST_PAD_ACTIVATE_PULL: Pad handles dataflow in upstream pull mode
* @GST_PAD_ACTIVATE_NONE: Pad will not handle dataflow
* @GST_PAD_ACTIVATE_PUSH: Pad handles dataflow in downstream push mode
* @GST_PAD_ACTIVATE_PULL: Pad handles dataflow in upstream pull mode
*
* The status of a GstPad. After activating a pad, which usually happens when the
* parent element goes from READY to PAUSED, the GstPadActivateMode defines if the
......@@ -531,7 +531,12 @@ typedef enum
/**
* GstPadProbeInfo:
* @type: the current probe type
* @data: type specific data
* @data: type specific data, check the @type field to know the datatype.
* This field can be NULL.
* @offset: offset of pull probe, this field is valid when @type contains
* #GST_PAD_PROBE_TYPE_PULL
* @size: size of pull probe, this field is valid when @type contains
* #GST_PAD_PROBE_TYPE_PULL
*
* Info passed in the #GstPadProbeCallback.
*/
......@@ -539,6 +544,8 @@ typedef struct
{
GstPadProbeType type;
gpointer data;
guint64 offset;
guint size;
} GstPadProbeInfo;
#define GST_PAD_PROBE_INFO_TYPE(d) ((d)->type)
......@@ -548,6 +555,9 @@ typedef struct
#define GST_PAD_PROBE_INFO_BUFFER_LIST(d) GST_BUFFER_LIST_CAST(GST_PAD_PROBE_INFO_DATA(d))
#define GST_PAD_PROBE_INFO_EVENT(d) GST_EVENT_CAST(GST_PAD_PROBE_INFO_DATA(d))
#define GST_PAD_PROBE_INFO_OFFSET(d) ((d)->offset)
#define GST_PAD_PROBE_INFO_SIZE(d) ((d)->size)
/**
* GstPadProbeCallback
* @pad: the #GstPad that is blocked
......@@ -556,9 +566,11 @@ typedef struct
*
* Callback used by gst_pad_add_probe(). Gets called to notify about the current
* blocking type.
*
* The callback is allowed to modify the data pointer in @info.
*/
typedef GstPadProbeReturn (*GstPadProbeCallback) (GstPad *pad, GstPadProbeInfo *info,
gpointer user_data);
typedef GstPadProbeReturn (*GstPadProbeCallback) (GstPad *pad, GstPadProbeInfo *info,
gpointer user_data);
/**
* GstPadStickyEventsForeachFunction:
......@@ -570,7 +582,8 @@ typedef GstPadProbeReturn (*GstPadProbeCallback) (GstPad *pad,
*
* Returns: GST_FLOW_OK if the iteration should continue
*/
typedef GstFlowReturn (*GstPadStickyEventsForeachFunction) (GstPad *pad, GstEvent *event, gpointer user_data);
typedef GstFlowReturn (*GstPadStickyEventsForeachFunction) (GstPad *pad, GstEvent *event,
gpointer user_data);
/**
* GstPadFlags:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment