* SECTION:gstpad
* @short_description: Object contained by elements that allows links to
* other elements
- * @see_also: #GstPadTemplate, #GstElement, #GstEvent
+ * @see_also: #GstPadTemplate, #GstElement, #GstEvent, #GstQuery, #GstBuffer
*
* A #GstElement is linked to other elements via "pads", which are extremely
* light-weight generic link points.
- * After two pads are retrieved from an element with gst_element_get_pad(),
- * the pads can be link with gst_pad_link(). (For quick links,
- * you can also use gst_element_link(), which will make the obvious
- * link for you if it's straightforward.)
*
- * Pads are typically created from a #GstPadTemplate with
- * gst_pad_new_from_template().
+ * Pads have a #GstPadDirection, source pads produce data, sink pads consume
+ * data.
*
- * Pads have #GstCaps attached to it to describe the media type they are
- * capable of dealing with. gst_pad_query_caps() and gst_pad_set_caps() are
- * used to manipulate the caps of the pads.
- * Pads created from a pad template cannot set capabilities that are
- * incompatible with the pad template capabilities.
+ * Pads are typically created from a #GstPadTemplate with
+ * gst_pad_new_from_template() and are then added to a #GstElement. This usually
+ * happens when the element is created but it can also happen dynamically based
+ * on the data that the element is processing or based on the pads that the
+ * application requests.
*
* Pads without pad templates can be created with gst_pad_new(),
* which takes a direction and a name as an argument. If the name is NULL,
* then a guaranteed unique name will be assigned to it.
*
+ * A #GstElement creating a pad will typically use the various
+ * gst_pad_set_*_function() calls to register callbacks for events, queries or
+ * dataflow on the pads.
+ *
* gst_pad_get_parent() will retrieve the #GstElement that owns the pad.
*
- * A #GstElement creating a pad will typically use the various
- * gst_pad_set_*_function() calls to register callbacks for various events
- * on the pads.
+ * After two pads are retrieved from an element with gst_element_get_pad(),
+ * the pads can be linked with gst_pad_link(). (For quick links,
+ * you can also use gst_element_link(), which will make the obvious
+ * link for you if it's straightforward.). Pads can be unlinked again with
+ * gst_pad_unlink(). gst_pad_get_peer() can be used to check what the pad is
+ * linked to.
+ *
+ * Before dataflow is possible on the pads, they need to be activated with
+ * gst_pad_set_active().
+ *
+ * gst_pad_query() and gst_pad_peer_query() can be used to query various
+ * properties of the pad and the stream.
+ *
+ * To send a #GstEvent on a pad, use gst_pad_send_event() and
+ * gst_pad_push_event(). Some events will be sticky on the pad, meaning that
+ * after they pass on the pad they can be queried later with
+ * gst_pad_get_sticky_event() and gst_pad_sticky_events_foreach().
+ * gst_pad_get_current_caps() and gst_pad_has_current_caps() are convenience
+ * functions to query the current sticky CAPS event on a pad.
*
* GstElements will use gst_pad_push() and gst_pad_pull_range() to push out
* or pull in a buffer.
*
- * To send a #GstEvent on a pad, use gst_pad_send_event() and
- * gst_pad_push_event().
+ * The dataflow, events and queries that happen on a pad can be monitored with
+ * probes that can be installed with gst_pad_add_probe(). gst_pad_is_blocked()
+ * can be used to check if a block probe is installed on the pad.
+ * gst_pad_is_blocking() checks if the blocking probe is currently blocking the
+ * pad. gst_pad_remove_probe() is used to remove a previously installed probe
+ * and unblock blocking probes if any.
+ *
+ * Pad have an offset that can be retrieved with gst_pad_get_offset(). This
+ * offset will be applied to the running_time of all data passing over the pad.
+ * gst_pad_set_offset() can be used to change the offset.
*
- * Last reviewed on 2006-07-06 (0.10.9)
+ * Convenience functions exist to start, pause and stop the task on a pad with
+ * gst_pad_start_task(), gst_pad_pause_task() and gst_pad_stop_task()
+ * respectively.
+ *
+ * Last reviewed on 2012-03-29 (0.11.3)
*/
#include "gst_private.h"
static GstFlowReturn gst_pad_send_event_unchecked (GstPad * pad,
GstEvent * event, GstPadProbeType type);
static GstFlowReturn gst_pad_push_event_unchecked (GstPad * pad,
- GstEvent * event, GstPadProbeType type, gboolean * stored);
+ GstEvent * event, GstPadProbeType type);
static guint gst_pad_signals[LAST_SIGNAL] = { 0 };
}
}
+/* check all events on srcpad against those on sinkpad. All events that are not
+ * on sinkpad are marked as received=FALSE and the PENDING_EVENTS is set on the
+ * srcpad so that the events will be sent next time */
static void
schedule_events (GstPad * srcpad, GstPad * sinkpad)
{
typedef gboolean (*PadEventFunction) (GstPad * pad, PadEvent * ev,
gpointer user_data);
+/* should be called with pad LOCK */
static void
events_foreach (GstPad * pad, PadEventFunction func, gpointer user_data)
{
goto restart;
}
+ /* store the received state */
+ ev->received = ev_ret.received;
+
/* if the event changed, we need to do something */
if (G_UNLIKELY (ev->event != ev_ret.event)) {
if (G_UNLIKELY (ev_ret.event == NULL)) {
}
/**
+ * gst_pad_set_activate_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadActivateFunction to set.
+ *
+ * Calls gst_pad_set_activate_function_full() with NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_activate_function_full:
* @pad: a #GstPad.
* @activate: the #GstPadActivateFunction to set.
}
/**
+ * gst_pad_set_activatemode_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadActivateModeFunction to set.
+ *
+ * Calls gst_pad_set_activatemode_function_full() with NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_activatemode_function_full:
* @pad: a #GstPad.
* @activatemode: the #GstPadActivateModeFunction to set.
}
/**
+ * gst_pad_set_chain_function:
+ * @p: a sink #GstPad.
+ * @f: the #GstPadChainFunction to set.
+ *
+ * Calls gst_pad_set_chain_function_full() with NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_chain_function_full:
* @pad: a sink #GstPad.
* @chain: the #GstPadChainFunction to set.
}
/**
+ * gst_pad_set_chain_list_function:
+ * @p: a sink #GstPad.
+ * @f: the #GstPadChainListFunction to set.
+ *
+ * Calls gst_pad_set_chain_list_function_full() with NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_chain_list_function_full:
* @pad: a sink #GstPad.
* @chainlist: the #GstPadChainListFunction to set.
}
/**
+ * gst_pad_set_getrange_function:
+ * @p: a source #GstPad.
+ * @f: the #GstPadGetRangeFunction to set.
+ *
+ * Calls gst_pad_set_getrange_function_full() with NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_getrange_function_full:
* @pad: a source #GstPad.
* @get: the #GstPadGetRangeFunction to set.
}
/**
+ * gst_pad_set_event_function:
+ * @p: a #GstPad of either direction.
+ * @f: the #GstPadEventFunction to set.
+ *
+ * Calls gst_pad_set_event_function_full() with NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_event_function_full:
* @pad: a #GstPad of either direction.
* @event: the #GstPadEventFunction to set.
}
/**
+ * gst_pad_set_query_function:
+ * @p: a #GstPad of either direction.
+ * @f: the #GstPadQueryFunction to set.
+ *
+ * Calls gst_pad_set_query_function_full() with NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_query_function_full:
* @pad: a #GstPad of either direction.
* @query: the #GstPadQueryFunction to set.
}
/**
+ * gst_pad_set_iterate_internal_links_function:
+ * @p: a #GstPad of either direction.
+ * @f: the #GstPadIterIntLinkFunction to set.
+ *
+ * Calls gst_pad_set_iterate_internal_links_function_full() with NULL
+ * for the user_data and notify.
+ */
+/**
* gst_pad_set_iterate_internal_links_function_full:
* @pad: a #GstPad of either direction.
* @iterintlink: the #GstPadIterIntLinkFunction to set.
}
/**
+ * gst_pad_set_link_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadLinkFunction to set.
+ *
+ * Calls gst_pad_set_link_function_full() with NULL
+ * for the user_data and notify.
+ */
+/**
* gst_pad_set_link_function_full:
* @pad: a #GstPad.
* @link: the #GstPadLinkFunction to set.
}
/**
+ * gst_pad_set_unlink_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadUnlinkFunction to set.
+ *
+ * Calls gst_pad_set_unlink_function_full() with NULL
+ * for the user_data and notify.
+ */
+/**
* gst_pad_set_unlink_function_full:
* @pad: a #GstPad.
* @unlink: the #GstPadUnlinkFunction to set.
GstCaps *
gst_pad_get_pad_template_caps (GstPad * pad)
{
- static GstStaticCaps anycaps = GST_STATIC_CAPS ("ANY");
-
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
if (GST_PAD_PAD_TEMPLATE (pad))
return gst_pad_template_get_caps (GST_PAD_PAD_TEMPLATE (pad));
- return gst_static_caps_get (&anycaps);
+ return gst_caps_ref (GST_CAPS_ANY);
}
/**
GST_LOG_OBJECT (pad, "default event handler");
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- {
- GST_DEBUG_OBJECT (pad, "pausing task because of eos");
- gst_pad_pause_task (pad);
- break;
- }
case GST_EVENT_CAPS:
forward = GST_PAD_IS_PROXY_CAPS (pad);
result = TRUE;
if ((result = get_pad_caps (pad)))
goto filter_done_unlock;
}
- GST_OBJECT_UNLOCK (pad);
/* this almost never happens */
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad has no caps");
- result = gst_caps_new_empty ();
-
- goto done;
+ result = GST_CAPS_ANY;
filter_done_unlock:
GST_OBJECT_UNLOCK (pad);
result = gst_caps_ref (result);
}
-done:
gst_query_set_caps_result (query, result);
gst_caps_unref (result);
return TRUE;
}
+typedef struct
+{
+ GstQuery *query;
+ gboolean result;
+ gboolean dispatched;
+} QueryData;
+
+static gboolean
+query_forward_func (GstPad * pad, QueryData * data)
+{
+ GST_LOG_OBJECT (pad, "query peer %p (%s) of %s:%s",
+ data->query, GST_EVENT_TYPE_NAME (data->query), GST_DEBUG_PAD_NAME (pad));
+
+ data->result |= gst_pad_peer_query (pad, data->query);
+
+ data->dispatched = TRUE;
+
+ /* stop on first successful reply */
+ return data->result;
+}
+
/**
* gst_pad_query_default:
* @pad: a #GstPad to call the default query handler on.
break;
}
+ GST_DEBUG_OBJECT (pad, "%sforwarding %p (%s) query", (forward ? "" : "not "),
+ query, GST_QUERY_TYPE_NAME (query));
+
if (forward) {
- ret = gst_pad_forward
- (pad, (GstPadForwardFunction) gst_pad_peer_query, query);
+ QueryData data;
+
+ data.query = query;
+ data.dispatched = FALSE;
+ data.result = FALSE;
+
+ gst_pad_forward (pad, (GstPadForwardFunction) query_forward_func, &data);
+
+ if (data.dispatched) {
+ ret = data.result;
+ } else {
+ /* nothing dispatched, assume drained */
+ if (GST_QUERY_TYPE (query) == GST_QUERY_DRAIN)
+ ret = TRUE;
+ else
+ ret = FALSE;
+ }
}
return ret;
}
}
}
-#define PROBE_PRE_PULL(pad,mask,data,offs,size,label,probed,defaultval) \
- G_STMT_START { \
- if (G_UNLIKELY (pad->num_probes)) { \
- /* we start with passing NULL as the data item */ \
- GstPadProbeInfo info = { mask, 0, 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 { \
} \
} G_STMT_END
-#define PROBE_FULL(pad,mask,data,offs,size,label,defaultval) \
+#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, defaultval); \
+ ret = do_probe_callbacks (pad, &info, GST_FLOW_OK); \
+ /* store the possibly updated data item */ \
data = GST_PAD_PROBE_INFO_DATA (&info); \
- if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK)) \
+ /* if something went wrong, exit */ \
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) \
goto label; \
} \
} G_STMT_END
-#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);
+#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);
static GstFlowReturn
do_probe_callbacks (GstPad * pad, GstPadProbeInfo * info,
GST_OBJECT_UNLOCK (pad);
}
+typedef struct
+{
+ GstFlowReturn ret;
+
+ /* If TRUE and ret is not OK this means
+ * that pushing the EOS event failed
+ */
+ gboolean was_eos;
+} PushStickyData;
+
+/* should be called with pad LOCK */
+static gboolean
+push_sticky (GstPad * pad, PadEvent * ev, gpointer user_data)
+{
+ PushStickyData *data = user_data;
+ GstEvent *event = ev->event;
+
+ if (ev->received) {
+ GST_DEBUG_OBJECT (pad, "event %s was already received",
+ GST_EVENT_TYPE_NAME (event));
+ return TRUE;
+ }
+
+ data->ret = gst_pad_push_event_unchecked (pad, gst_event_ref (event),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+
+ switch (data->ret) {
+ case GST_FLOW_OK:
+ ev->received = TRUE;
+ GST_DEBUG_OBJECT (pad, "event %s marked received",
+ GST_EVENT_TYPE_NAME (event));
+ break;
+ case GST_FLOW_NOT_LINKED:
+ /* not linked is not a problem, we are sticky so the event will be
+ * sent later but only for non-EOS events */
+ GST_DEBUG_OBJECT (pad, "pad was not linked");
+ if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
+ data->ret = GST_FLOW_OK;
+ /* fallthrough */
+ default:
+ GST_DEBUG_OBJECT (pad, "mark pending events");
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+ break;
+ }
+
+ if (data->ret != GST_FLOW_OK && GST_EVENT_TYPE (event) == GST_EVENT_EOS)
+ data->was_eos = TRUE;
+
+ return data->ret == GST_FLOW_OK;
+}
+
+/* check sticky events and push them when needed. should be called
+ * with pad LOCK */
+static inline GstFlowReturn
+check_sticky (GstPad * pad)
+{
+ PushStickyData data = { GST_FLOW_OK, FALSE };
+
+ if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+
+ GST_DEBUG_OBJECT (pad, "pushing all sticky events");
+ events_foreach (pad, push_sticky, &data);
+
+ /* If there's an EOS event we must push it downstream
+ * even if sending a previous sticky event failed.
+ * Otherwise the pipeline might wait forever for EOS.
+ *
+ * Only do this if pushing another event than the EOS
+ * event failed.
+ */
+ if (data.ret != GST_FLOW_OK && !data.was_eos) {
+ PadEvent *ev = find_event_by_type (pad, GST_EVENT_EOS, 0);
+
+ if (ev && !ev->received) {
+ data.ret = gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+ }
+ }
+ }
+ return data.ret;
+}
+
/**
* gst_pad_query:
gst_pad_query (GstPad * pad, GstQuery * query)
{
GstObject *parent;
- gboolean res;
+ gboolean res, serialized;
GstPadQueryFunction func;
GstPadProbeType type;
GstFlowReturn ret;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
- GST_DEBUG_OBJECT (pad, "sending query %p (%s)", query,
- GST_QUERY_TYPE_NAME (query));
-
- if (GST_PAD_IS_SRC (pad))
+ if (GST_PAD_IS_SRC (pad)) {
+ if (G_UNLIKELY (!GST_QUERY_IS_UPSTREAM (query)))
+ goto wrong_direction;
type = GST_PAD_PROBE_TYPE_QUERY_UPSTREAM;
- else
+ } else if (GST_PAD_IS_SINK (pad)) {
+ if (G_UNLIKELY (!GST_QUERY_IS_DOWNSTREAM (query)))
+ goto wrong_direction;
type = GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM;
+ } else
+ goto unknown_direction;
+
+ GST_DEBUG_OBJECT (pad, "doing query %p (%s)", query,
+ GST_QUERY_TYPE_NAME (query));
+
+ serialized = GST_QUERY_IS_SERIALIZED (query);
+ if (G_UNLIKELY (serialized))
+ GST_PAD_STREAM_LOCK (pad);
GST_OBJECT_LOCK (pad);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH |
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PULL, query, probe_stopped);
GST_OBJECT_UNLOCK (pad);
+ if (G_UNLIKELY (serialized))
+ GST_PAD_STREAM_UNLOCK (pad);
+
return res;
/* ERRORS */
+wrong_direction:
+ {
+ g_warning ("pad %s:%s query %s in wrong direction",
+ GST_DEBUG_PAD_NAME (pad), GST_QUERY_TYPE_NAME (query));
+ return FALSE;
+ }
+unknown_direction:
+ {
+ g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
+ return FALSE;
+ }
no_parent:
{
GST_DEBUG_OBJECT (pad, "had no parent");
GST_OBJECT_UNLOCK (pad);
+ if (G_UNLIKELY (serialized))
+ GST_PAD_STREAM_UNLOCK (pad);
return FALSE;
}
no_func:
{
GST_DEBUG_OBJECT (pad, "had no query function");
RELEASE_PARENT (parent);
+ if (G_UNLIKELY (serialized))
+ GST_PAD_STREAM_UNLOCK (pad);
return FALSE;
}
query_failed:
{
GST_DEBUG_OBJECT (pad, "query failed");
+ if (G_UNLIKELY (serialized))
+ GST_PAD_STREAM_UNLOCK (pad);
return FALSE;
}
probe_stopped:
{
GST_DEBUG_OBJECT (pad, "probe stopped: %s", gst_flow_get_name (ret));
GST_OBJECT_UNLOCK (pad);
- return FALSE;
+ if (G_UNLIKELY (serialized))
+ GST_PAD_STREAM_UNLOCK (pad);
+
+ /* if a probe dropped, we don't sent it further but assume that the probe
+ * answered the query and return TRUE */
+ if (ret == GST_FLOW_CUSTOM_SUCCESS)
+ res = TRUE;
+ else
+ res = FALSE;
+
+ return res;
}
}
{
GstPad *peerpad;
GstPadProbeType type;
- gboolean res;
+ gboolean res, serialized;
GstFlowReturn ret;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
- if (GST_PAD_IS_SRC (pad))
+ if (GST_PAD_IS_SRC (pad)) {
+ if (G_UNLIKELY (!GST_QUERY_IS_DOWNSTREAM (query)))
+ goto wrong_direction;
type = GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM;
- else
+ } else if (GST_PAD_IS_SINK (pad)) {
+ if (G_UNLIKELY (!GST_QUERY_IS_UPSTREAM (query)))
+ goto wrong_direction;
type = GST_PAD_PROBE_TYPE_QUERY_UPSTREAM;
+ } else
+ goto unknown_direction;
GST_DEBUG_OBJECT (pad, "peer query %p (%s)", query,
GST_QUERY_TYPE_NAME (query));
+ serialized = GST_QUERY_IS_SERIALIZED (query);
+
GST_OBJECT_LOCK (pad);
+ if (GST_PAD_IS_SRC (pad) && serialized) {
+ /* all serialized queries on the srcpad trigger push of
+ * sticky events */
+ if (!check_sticky (pad) == GST_FLOW_OK)
+ goto sticky_failed;
+ }
+
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH |
GST_PAD_PROBE_TYPE_BLOCK, query, probe_stopped);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, query, probe_stopped);
return res;
/* ERRORS */
+wrong_direction:
+ {
+ g_warning ("pad %s:%s query %s in wrong direction",
+ GST_DEBUG_PAD_NAME (pad), GST_QUERY_TYPE_NAME (query));
+ return FALSE;
+ }
+unknown_direction:
+ {
+ g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
+ return FALSE;
+ }
+sticky_failed:
+ {
+ GST_WARNING_OBJECT (pad, "could not send sticky events");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
no_peer:
{
GST_WARNING_OBJECT (pad, "pad has no peer");
{
GST_DEBUG_OBJECT (pad, "probe stopped: %s", gst_flow_get_name (ret));
GST_OBJECT_UNLOCK (pad);
- return FALSE;
+
+ /* if a probe dropped, we don't sent it further but assume that the probe
+ * answered the query and return TRUE */
+ if (ret == GST_FLOW_CUSTOM_SUCCESS)
+ res = TRUE;
+ else
+ res = FALSE;
+
+ return res;
}
}
* Data passing functions
*/
-static gboolean
-push_sticky (GstPad * pad, PadEvent * ev, gpointer user_data)
-{
- GstFlowReturn *data = user_data;
- gboolean stored;
-
- if (ev->received) {
- GST_DEBUG_OBJECT (pad, "event %s was already received",
- GST_EVENT_TYPE_NAME (ev->event));
- return TRUE;
- }
- GST_OBJECT_UNLOCK (pad);
-
- *data = gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
- GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, &stored);
-
- GST_OBJECT_LOCK (pad);
- return *data == GST_FLOW_OK;
-}
-
/* this is the chain function that does not perform the additional argument
* checking for that little extra speed.
*/
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
goto wrong_mode;
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return GST_FLOW_FLUSHING;
}
+eos:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "chaining, but pad was EOS");
+ GST_OBJECT_UNLOCK (pad);
+ GST_PAD_STREAM_UNLOCK (pad);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+ return GST_FLOW_EOS;
+ }
wrong_mode:
{
g_critical ("chain on pad %s:%s but it was not in push mode",
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
goto wrong_mode;
- if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-
- GST_DEBUG_OBJECT (pad, "pushing all sticky events");
-
- ret = GST_FLOW_OK;
- events_foreach (pad, push_sticky, &ret);
- if (ret != GST_FLOW_OK)
- goto events_error;
- }
+ if (G_UNLIKELY ((ret = check_sticky (pad))) != GST_FLOW_OK)
+ goto events_error;
/* do block probes */
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return GST_FLOW_FLUSHING;
}
+eos:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but pad was EOS");
+ GST_OBJECT_UNLOCK (pad);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+ return GST_FLOW_EOS;
+ }
wrong_mode:
{
g_critical ("pushing on pad %s:%s but it was not activated in push mode",
GstFlowReturn ret;
GstPadGetRangeFunction getrangefunc;
GstObject *parent;
+ GstBuffer *res_buf;
GST_PAD_STREAM_LOCK (pad);
if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PULL))
goto wrong_mode;
- if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-
- GST_DEBUG_OBJECT (pad, "pushing all sticky events");
+ if (G_UNLIKELY ((ret = check_sticky (pad))) != GST_FLOW_OK)
+ goto events_error;
- ret = GST_FLOW_OK;
- events_foreach (pad, push_sticky, &ret);
- if (ret != GST_FLOW_OK)
- goto events_error;
- }
+ res_buf = *buffer;
- /* 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);
+ /* when one of the probes returns DROPPED, probe_stopped will be called
+ * and we skip calling the getrange function, res_buf should then contain a
+ * valid result buffer */
+ PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
+ res_buf, offset, size, probe_stopped);
ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
G_GUINT64_FORMAT ", size %u",
GST_DEBUG_FUNCPTR_NAME (getrangefunc), offset, size);
- ret = getrangefunc (pad, parent, offset, size, buffer);
+ ret = getrangefunc (pad, parent, offset, size, &res_buf);
RELEASE_PARENT (parent);
GST_OBJECT_LOCK (pad);
probed_data:
PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER,
- *buffer, offset, size, probe_stopped_unref);
+ res_buf, offset, size, probe_stopped_unref);
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
+ *buffer = res_buf;
+
return ret;
/* ERRORS */
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"probe returned %s", gst_flow_get_name (ret));
+ if (ret == GST_FLOW_CUSTOM_SUCCESS) {
+ if (res_buf) {
+ /* the probe filled the buffer and asks us to not call the getrange
+ * anymore, we continue with the post probes then. */
+ GST_DEBUG_OBJECT (pad, "handled buffer");
+ ret = GST_FLOW_OK;
+ goto probed_data;
+ } else {
+ /* no buffer, we are EOS */
+ GST_DEBUG_OBJECT (pad, "no buffer, return EOS");
+ ret = GST_FLOW_EOS;
+ }
+ }
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
+
return ret;
}
probe_stopped_unref:
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"probe returned %s", gst_flow_get_name (ret));
+ /* if we drop here, it signals EOS */
+ if (ret == GST_FLOW_CUSTOM_SUCCESS)
+ ret = GST_FLOW_EOS;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
- gst_buffer_unref (*buffer);
- *buffer = NULL;
+ if (*buffer == NULL)
+ gst_buffer_unref (res_buf);
return ret;
}
get_range_failed:
{
GST_PAD_STREAM_UNLOCK (pad);
- *buffer = NULL;
GST_CAT_LEVEL_LOG (GST_CAT_SCHEDULING,
(ret >= GST_FLOW_EOS) ? GST_LEVEL_INFO : GST_LEVEL_WARNING,
pad, "getrange failed, flow: %s", gst_flow_get_name (ret));
* installed (see gst_pad_set_getrange_function()) this function returns
* #GST_FLOW_NOT_SUPPORTED.
*
+ * If @buffer points to a variable holding NULL, a valid new #GstBuffer will be
+ * placed in @buffer when this function returns #GST_FLOW_OK. The new buffer
+ * must be freed with gst_buffer_unref() after usage.
+ *
+ * When @buffer points to a variable that points to a valid #GstBuffer, the
+ * buffer will be filled with the result data when this function returns
+ * #GST_FLOW_OK. If the provided buffer is larger than @size, only
+ * @size bytes will be filled in the result buffer and its size will be updated
+ * accordingly.
+ *
+ * Note that less than @size bytes can be returned in @buffer when, for example,
+ * an EOS condition is near or when @buffer is not large enough to hold @size
+ * bytes. The caller should check the result buffer size to get the result size.
+ *
+ * When this function returns any other result value than #GST_FLOW_OK, @buffer
+ * will be unchanged.
+ *
* This is a lowlevel function. Usualy gst_pad_pull_range() is used.
*
* Returns: a #GstFlowReturn from the pad.
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+ g_return_val_if_fail (*buffer == NULL
+ || GST_IS_BUFFER (*buffer), GST_FLOW_ERROR);
return gst_pad_get_range_unchecked (pad, offset, size, buffer);
}
* @buffer: (out callee-allocates): a pointer to hold the #GstBuffer, returns
* GST_FLOW_ERROR if %NULL.
*
- * Pulls a @buffer from the peer pad.
+ * Pulls a @buffer from the peer pad or fills up a provided buffer.
*
* This function will first trigger the pad block signal if it was
* installed.
* See gst_pad_get_range() for a list of return values and for the
* semantics of the arguments of this function.
*
+ * If @buffer points to a variable holding NULL, a valid new #GstBuffer will be
+ * placed in @buffer when this function returns #GST_FLOW_OK. The new buffer
+ * must be freed with gst_buffer_unref() after usage. When this function
+ * returns any other result value, @buffer will still point to NULL.
+ *
+ * When @buffer points to a variable that points to a valid #GstBuffer, the
+ * buffer will be filled with the result data when this function returns
+ * #GST_FLOW_OK. When this function returns any other result value,
+ * @buffer will be unchanged. If the provided buffer is larger than @size, only
+ * @size bytes will be filled in the result buffer and its size will be updated
+ * accordingly.
+ *
+ * Note that less than @size bytes can be returned in @buffer when, for example,
+ * an EOS condition is near or when @buffer is not large enough to hold @size
+ * bytes. The caller should check the result buffer size to get the result size.
+ *
* Returns: a #GstFlowReturn from the peer pad.
- * When this function returns #GST_FLOW_OK, @buffer will contain a valid
- * #GstBuffer that should be freed with gst_buffer_unref() after usage.
- * @buffer may not be used or freed when any other return value than
- * #GST_FLOW_OK is returned.
*
* MT safe.
*/
{
GstPad *peer;
GstFlowReturn ret;
+ GstBuffer *res_buf;
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+ g_return_val_if_fail (*buffer == NULL
+ || GST_IS_BUFFER (*buffer), GST_FLOW_ERROR);
GST_OBJECT_LOCK (pad);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PULL))
goto wrong_mode;
- /* 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);
+ res_buf = *buffer;
+
+ /* when one of the probes returns DROPPED, probe_stopped will be
+ * called and we skip calling the peer getrange function. *buffer should then
+ * contain a valid buffer */
+ PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
+ res_buf, offset, size, probe_stopped);
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto not_linked;
pad->priv->using++;
GST_OBJECT_UNLOCK (pad);
- ret = gst_pad_get_range_unchecked (peer, offset, size, buffer);
+ ret = gst_pad_get_range_unchecked (peer, offset, size, &res_buf);
gst_object_unref (peer);
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,
- post_probe_stopped, ret);
+ probe_stopped_unref, ret);
}
if (G_UNLIKELY (ret != GST_FLOW_OK))
probed_data:
PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER,
- *buffer, offset, size, post_probe_stopped);
+ res_buf, offset, size, probe_stopped_unref);
GST_OBJECT_UNLOCK (pad);
+ *buffer = res_buf;
+
return ret;
/* ERROR recovery here */
GST_OBJECT_UNLOCK (pad);
return GST_FLOW_ERROR;
}
-pre_probe_stopped:
+probe_stopped:
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pre probe returned %s",
gst_flow_get_name (ret));
+ if (ret == GST_FLOW_CUSTOM_SUCCESS) {
+ if (res_buf) {
+ /* the probe filled the buffer and asks us to not forward to the peer
+ * anymore, we continue with the post probes then */
+ GST_DEBUG_OBJECT (pad, "handled buffer");
+ ret = GST_FLOW_OK;
+ goto probed_data;
+ } else {
+ /* no buffer, we are EOS then */
+ GST_DEBUG_OBJECT (pad, "no buffer, return EOS");
+ ret = GST_FLOW_EOS;
+ }
+ }
GST_OBJECT_UNLOCK (pad);
return ret;
}
}
pull_range_failed:
{
- *buffer = NULL;
GST_OBJECT_UNLOCK (pad);
GST_CAT_LEVEL_LOG (GST_CAT_SCHEDULING,
(ret >= GST_FLOW_EOS) ? GST_LEVEL_INFO : GST_LEVEL_WARNING,
pad, "pullrange failed, flow: %s", gst_flow_get_name (ret));
return ret;
}
-post_probe_stopped:
+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 (ret == GST_FLOW_OK)
- gst_buffer_unref (*buffer);
- *buffer = NULL;
+ /* if we drop here, it signals EOS */
+ if (ret == GST_FLOW_CUSTOM_SUCCESS)
+ ret = GST_FLOW_EOS;
+ if (*buffer == NULL)
+ gst_buffer_unref (res_buf);
return ret;
}
}
return res;
}
+/* should be called with pad LOCK */
static GstFlowReturn
gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
- GstPadProbeType type, gboolean * stored)
+ GstPadProbeType type)
{
GstFlowReturn ret;
GstPad *peerpad;
GstEventType event_type;
- gboolean sticky;
-
- sticky = GST_EVENT_IS_STICKY (event);
-
- GST_OBJECT_LOCK (pad);
/* Two checks to be made:
* . (un)set the FLUSHING flag for flushing events,
* . handle pad blocking */
event_type = GST_EVENT_TYPE (event);
- *stored = FALSE;
switch (event_type) {
case GST_EVENT_FLUSH_START:
GST_PAD_SET_FLUSHING (pad);
/* Remove sticky EOS events */
GST_LOG_OBJECT (pad, "Removing pending EOS events");
remove_event_by_type (pad, GST_EVENT_EOS);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS);
type |= GST_PAD_PROBE_TYPE_EVENT_FLUSH;
break;
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushed;
- /* store the event on the pad, but only on srcpads. We always store the
- * event exactly how it was sent */
- if (sticky) {
- /* srcpad sticky events are store immediately, the received flag is set
- * to FALSE and will be set to TRUE when we can successfully push the
- * event to the peer pad */
- if (gst_pad_store_sticky_event (pad, event, TRUE)) {
- GST_DEBUG_OBJECT (pad, "event %s updated",
- GST_EVENT_TYPE_NAME (event));
- }
- *stored = TRUE;
- }
+ /* No need to check for EOS here as either the caller (gst_pad_push_event())
+ * checked already or this is called as part of pushing sticky events,
+ * in which case we still want to forward the EOS event downstream.
+ */
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEGMENT:
gst_object_unref (peerpad);
GST_OBJECT_LOCK (pad);
- if (sticky) {
- if (ret == GST_FLOW_OK) {
- PadEvent *ev;
-
- if ((ev = find_event (pad, event)))
- ev->received = TRUE;
-
- GST_DEBUG_OBJECT (pad, "event marked received");
- } else {
- GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
- GST_DEBUG_OBJECT (pad, "mark pending events");
- }
- }
pad->priv->using--;
if (pad->priv->using == 0) {
/* pad is not active anymore, trigger idle callbacks */
PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
idle_probe_stopped, ret);
}
- GST_OBJECT_UNLOCK (pad);
-
return ret;
/* ERROR handling */
flushed:
{
GST_DEBUG_OBJECT (pad, "We're flushing");
- GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
return GST_FLOW_FLUSHING;
}
probe_stopped:
{
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
- GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
switch (ret) {
{
GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked");
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
- GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
- return sticky ? GST_FLOW_OK : GST_FLOW_NOT_LINKED;
+
+ /* unlinked pads should not influence latency configuration */
+ if (event_type == GST_EVENT_LATENCY)
+ return GST_FLOW_OK;
+
+ return GST_FLOW_NOT_LINKED;
}
idle_probe_stopped:
{
GST_DEBUG_OBJECT (pad, "Idle probe returned %s", gst_flow_get_name (ret));
- GST_OBJECT_UNLOCK (pad);
return ret;
}
}
gboolean
gst_pad_push_event (GstPad * pad, GstEvent * event)
{
- gboolean res;
+ gboolean res = FALSE;
GstPadProbeType type;
- gboolean stored;
+ gboolean sticky, serialized;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
if (GST_PAD_IS_SRC (pad)) {
} else
goto unknown_direction;
- if (gst_pad_push_event_unchecked (pad, event, type, &stored) != GST_FLOW_OK)
- res = stored ? TRUE : FALSE;
- else
- res = TRUE;
+ GST_OBJECT_LOCK (pad);
+ sticky = GST_EVENT_IS_STICKY (event);
+ serialized = GST_EVENT_IS_SERIALIZED (event);
+
+ if (sticky) {
+ /* can't store on flushing pads */
+ if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
+ goto flushed;
+
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
+ /* srcpad sticky events are store immediately, the received flag is set
+ * to FALSE and will be set to TRUE when we can successfully push the
+ * event to the peer pad */
+ if (gst_pad_store_sticky_event (pad, event, TRUE)) {
+ GST_DEBUG_OBJECT (pad, "event %s updated", GST_EVENT_TYPE_NAME (event));
+ }
+ if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_EOS);
+ }
+ if (GST_PAD_IS_SRC (pad) && (serialized || sticky)) {
+ /* all serialized or sticky events on the srcpad trigger push of
+ * sticky events */
+ res = (check_sticky (pad) == GST_FLOW_OK);
+ }
+ if (!sticky) {
+ /* other events are pushed right away */
+ res = (gst_pad_push_event_unchecked (pad, event, type) == GST_FLOW_OK);
+ } else {
+ /* Errors in sticky event pushing are no problem and ignored here
+ * as they will cause more meaningful errors during data flow.
+ * For EOS events, that are not followed by data flow, we still
+ * return FALSE here though.
+ */
+ if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
+ res = TRUE;
+ gst_event_unref (event);
+ }
+ GST_OBJECT_UNLOCK (pad);
return res;
gst_event_unref (event);
return FALSE;
}
+flushed:
+ {
+ GST_DEBUG_OBJECT (pad, "We're flushing");
+ GST_OBJECT_UNLOCK (pad);
+ gst_event_unref (event);
+ return FALSE;
+ }
+eos:
+ {
+ GST_DEBUG_OBJECT (pad, "We're EOS");
+ GST_OBJECT_UNLOCK (pad);
+ gst_event_unref (event);
+ return FALSE;
+ }
}
/* Check if we can call the event function with the given event */
static GstFlowReturn
pre_eventfunc_check (GstPad * pad, GstEvent * event)
{
- GstCaps *caps, *templ;
+ GstCaps *caps;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
/* backwards compatibility mode for caps */
gst_event_parse_caps (event, &caps);
- /* See if pad accepts the caps */
- templ = gst_pad_get_pad_template_caps (pad);
- if (!gst_caps_is_subset (caps, templ))
+ if (!gst_pad_query_accept_caps (pad, caps))
goto not_accepted;
-
- gst_caps_unref (templ);
break;
}
default:
/* ERRORS */
not_accepted:
{
- gst_caps_unref (templ);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"caps %" GST_PTR_FORMAT " not accepted", caps);
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "no intersection with template %" GST_PTR_FORMAT, templ);
return GST_FLOW_NOT_NEGOTIATED;
}
}
/* Remove pending EOS events */
GST_LOG_OBJECT (pad, "Removing pending EOS events");
remove_event_by_type (pad, GST_EVENT_EOS);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS);
GST_OBJECT_UNLOCK (pad);
/* grab stream lock */
goto flushing;
if (serialized) {
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
/* lock order: STREAM_LOCK, LOCK, recheck flushing. */
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_LOCK (pad);
GST_OBJECT_LOCK (pad);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
}
switch (GST_EVENT_TYPE (event)) {
/* after the event function accepted the event, we can store the sticky
* event on the pad */
gst_pad_store_sticky_event (pad, event, FALSE);
+ if (event_type == GST_EVENT_EOS)
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_EOS);
}
gst_event_unref (event);
}
gst_event_unref (event);
return GST_FLOW_FLUSHING;
}
+eos:
+ {
+ GST_OBJECT_UNLOCK (pad);
+ if (need_unlock)
+ GST_PAD_STREAM_UNLOCK (pad);
+ GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad,
+ "Received event on EOS pad. Discarding");
+ gst_event_unref (event);
+ return GST_FLOW_EOS;
+ }
probe_stopped:
{
GST_OBJECT_UNLOCK (pad);
task = gst_task_new (func, data);
gst_task_set_lock (task, GST_PAD_GET_STREAM_LOCK (pad));
gst_task_set_thread_callbacks (task, &thr_callbacks, pad, NULL);
- GST_DEBUG_OBJECT (pad, "created task");
+ GST_INFO_OBJECT (pad, "created task %p", task);
GST_PAD_TASK (pad) = task;
gst_object_ref (task);
/* release lock to post the message */