* gst_pad_new_from_template().
*
* Pads have #GstCaps attached to it to describe the media type they are
- * capable of dealing with. gst_pad_get_caps() and gst_pad_set_caps() 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.
* moved to the active event when the eventfunc returned TRUE. */
typedef struct
{
- GstEvent *pending;
+ gboolean received;
GstEvent *event;
} PadEvent;
struct _GstPadPrivate
{
- PadEvent events[GST_EVENT_MAX_STICKY];
+ guint events_cookie;
+ GArray *events;
gint using;
guint probe_list_cookie;
static void gst_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static GstCaps *gst_pad_get_caps_unlocked (GstPad * pad, GstCaps * filter);
static void gst_pad_set_pad_template (GstPad * pad, GstPadTemplate * templ);
-static gboolean gst_pad_activate_default (GstPad * pad);
+static gboolean gst_pad_activate_default (GstPad * pad, GstObject * parent);
static GstFlowReturn gst_pad_chain_list_default (GstPad * pad,
- GstBufferList * list);
+ GstObject * parent, GstBufferList * list);
+
+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);
static guint gst_pad_signals[LAST_SIGNAL] = { 0 };
static GstFlowQuarks flow_quarks[] = {
{GST_FLOW_CUSTOM_SUCCESS, "custom-success", 0},
- {GST_FLOW_RESEND, "resend", 0},
{GST_FLOW_OK, "ok", 0},
{GST_FLOW_NOT_LINKED, "not-linked", 0},
- {GST_FLOW_WRONG_STATE, "wrong-state", 0},
+ {GST_FLOW_FLUSHING, "flushing", 0},
{GST_FLOW_EOS, "eos", 0},
{GST_FLOW_NOT_NEGOTIATED, "not-negotiated", 0},
{GST_FLOW_ERROR, "error", 0},
GST_PAD_SET_FLUSHING (pad);
- g_static_rec_mutex_init (&pad->stream_rec_lock);
+ g_rec_mutex_init (&pad->stream_rec_lock);
- pad->block_cond = g_cond_new ();
+ g_cond_init (&pad->block_cond);
g_hook_list_init (&pad->probes, sizeof (GstProbe));
+
+ pad->priv->events = g_array_sized_new (FALSE, TRUE, sizeof (PadEvent), 16);
}
+/* called when setting the pad inactive. It removes all sticky events from
+ * the pad */
static void
-clear_event (PadEvent events[], guint idx)
+remove_events (GstPad * pad)
{
- gst_event_replace (&events[idx].event, NULL);
- gst_event_replace (&events[idx].pending, NULL);
+ guint i, len;
+ GArray *events;
+
+ events = pad->priv->events;
+
+ len = events->len;
+ for (i = 0; i < len; i++) {
+ PadEvent *ev = &g_array_index (events, PadEvent, i);
+ gst_event_unref (ev->event);
+ }
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+ g_array_set_size (events, 0);
+ pad->priv->events_cookie++;
+}
+
+static PadEvent *
+find_event_by_type (GstPad * pad, GstEventType type, guint idx)
+{
+ guint i, len;
+ GArray *events;
+ PadEvent *ev;
+
+ events = pad->priv->events;
+ len = events->len;
+
+ for (i = 0; i < len; i++) {
+ ev = &g_array_index (events, PadEvent, i);
+ if (ev->event == NULL)
+ continue;
+
+ if (GST_EVENT_TYPE (ev->event) == type) {
+ if (idx == 0)
+ goto found;
+ idx--;
+ }
+ }
+ ev = NULL;
+found:
+ return ev;
+}
+
+static PadEvent *
+find_event (GstPad * pad, GstEvent * event)
+{
+ guint i, len;
+ GArray *events;
+ PadEvent *ev;
+
+ events = pad->priv->events;
+ len = events->len;
+
+ for (i = 0; i < len; i++) {
+ ev = &g_array_index (events, PadEvent, i);
+ if (event == ev->event)
+ goto found;
+ }
+ ev = NULL;
+found:
+ return ev;
}
-/* called when setting the pad inactive. It removes all sticky events from
- * the pad */
static void
-clear_events (PadEvent events[])
+remove_event_by_type (GstPad * pad, GstEventType type)
{
- guint i;
+ guint i, len;
+ GArray *events;
+ PadEvent *ev;
+
+ events = pad->priv->events;
+ len = events->len;
- for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
- clear_event (events, i);
+ i = 0;
+ while (i < len) {
+ ev = &g_array_index (events, PadEvent, i);
+ if (ev->event == NULL)
+ goto next;
+
+ if (GST_EVENT_TYPE (ev->event) != type)
+ goto next;
+
+ gst_event_unref (ev->event);
+ g_array_remove_index (events, i);
+ len--;
+ pad->priv->events_cookie++;
+ continue;
+
+ next:
+ i++;
+ }
}
-/* The sticky event with @idx from the srcpad is copied to the
- * pending event on the sinkpad (when different).
- * This function applies the pad offsets in case of segment events.
- * This will make sure that we send the event to the sinkpad event
- * function when the next buffer of event arrives.
- * Should be called with the OBJECT lock of both pads.
- * This function returns TRUE when there is a pending event on the
- * sinkpad */
-static gboolean
-replace_event (GstPad * srcpad, GstPad * sinkpad, guint idx)
+static void
+schedule_events (GstPad * srcpad, GstPad * sinkpad)
{
- PadEvent *srcev, *sinkev;
- GstEvent *event;
+ gint i, len;
+ GArray *events;
+ PadEvent *ev;
gboolean pending = FALSE;
- srcev = &srcpad->priv->events[idx];
+ events = srcpad->priv->events;
+ len = events->len;
- if ((event = srcev->event)) {
- sinkev = &sinkpad->priv->events[idx];
+ for (i = 0; i < len; i++) {
+ ev = &g_array_index (events, PadEvent, i);
+ if (ev->event == NULL)
+ continue;
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEGMENT:
- {
- GstSegment segment;
- gint64 offset;
-
- offset = srcpad->offset + sinkpad->offset;
- if (offset != 0) {
- gst_event_copy_segment (event, &segment);
- /* adjust the base time. FIXME, check negative times, try to tweak the
- * start to do clipping on negative times */
- segment.base += offset;
- /* make a new event from the updated segment */
- event = gst_event_new_segment (&segment);
- }
- break;
- }
- default:
- break;
- }
- if (sinkev->event != event) {
- /* put in the pending entry when different */
- GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, srcpad,
- "Putting event %p (%s) on pad %s:%s", event,
- GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (sinkpad));
- gst_event_replace (&sinkev->pending, event);
+ if (sinkpad == NULL || !find_event (sinkpad, ev->event)) {
+ ev->received = FALSE;
pending = TRUE;
}
}
- return pending;
+ if (pending)
+ GST_OBJECT_FLAG_SET (srcpad, GST_PAD_FLAG_PENDING_EVENTS);
}
+typedef gboolean (*PadEventFunction) (GstPad * pad, PadEvent * ev,
+ gpointer user_data);
static void
-prepare_event_update (GstPad * srcpad, GstPad * sinkpad)
+events_foreach (GstPad * pad, PadEventFunction func, gpointer user_data)
{
- gboolean pending;
- gint i;
+ guint i, len;
+ GArray *events;
+ gboolean ret;
+ guint cookie;
- /* make sure we push the events from the source to this new peer, for this we
- * copy the events on the sinkpad and mark EVENTS_PENDING */
- pending = FALSE;
- for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
- pending |= replace_event (srcpad, sinkpad, i);
+ events = pad->priv->events;
- /* we had some new pending events, set our flag */
- if (pending)
- GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_NEED_EVENTS);
+restart:
+ cookie = pad->priv->events_cookie;
+ i = 0;
+ len = events->len;
+ while (i < len) {
+ PadEvent *ev, ev_ret;
+
+ ev = &g_array_index (events, PadEvent, i);
+ if (G_UNLIKELY (ev->event == NULL))
+ goto next;
+
+ /* take aditional ref, func might release the lock */
+ ev_ret.event = gst_event_ref (ev->event);
+ ev_ret.received = ev->received;
+
+ ret = func (pad, &ev_ret, user_data);
+
+ /* recheck the cookie, lock might have been released and the list could have
+ * changed */
+ if (G_UNLIKELY (cookie != pad->priv->events_cookie)) {
+ if (G_LIKELY (ev_ret.event))
+ gst_event_unref (ev_ret.event);
+ goto restart;
+ }
+
+ /* if the event changed, we need to do something */
+ if (G_UNLIKELY (ev->event != ev_ret.event)) {
+ if (G_UNLIKELY (ev_ret.event == NULL)) {
+ /* function unreffed and set the event to NULL, remove it */
+ g_array_remove_index (events, i);
+ len--;
+ cookie = ++pad->priv->events_cookie;
+ continue;
+ } else {
+ /* function gave a new event for us */
+ gst_event_take (&ev->event, ev_ret.event);
+ }
+ } else {
+ /* just unref, nothing changed */
+ gst_event_unref (ev_ret.event);
+ }
+ if (!ret)
+ break;
+ next:
+ i++;
+ }
+}
+
+/* should be called with LOCK */
+static GstEvent *
+apply_pad_offset (GstPad * pad, GstEvent * event)
+{
+ /* check if we need to adjust the segment */
+ if (pad->offset != 0) {
+ GstSegment segment;
+
+ /* copy segment values */
+ gst_event_copy_segment (event, &segment);
+ gst_event_unref (event);
+
+ /* adjust and make a new event with the offset applied */
+ segment.base += pad->offset;
+ event = gst_event_new_segment (&segment);
+ }
+ return event;
}
/* should be called with the OBJECT_LOCK */
get_pad_caps (GstPad * pad)
{
GstCaps *caps = NULL;
- GstEvent *event;
- guint idx;
+ PadEvent *ev;
- idx = GST_EVENT_STICKY_IDX_TYPE (GST_EVENT_CAPS);
- /* we can only use the caps when we have successfully send the caps
- * event to the event function and is thus in the active entry */
- if ((event = pad->priv->events[idx].event))
- gst_event_parse_caps (event, &caps);
+ ev = find_event_by_type (pad, GST_EVENT_CAPS, 0);
+ if (ev && ev->event)
+ gst_event_parse_caps (ev->event, &caps);
return caps;
}
gst_pad_set_pad_template (pad, NULL);
- clear_events (pad->priv->events);
+ remove_events (pad);
g_hook_list_clear (&pad->probes);
gst_object_unref (task);
}
- g_static_rec_mutex_free (&pad->stream_rec_lock);
- g_cond_free (pad->block_cond);
+ if (pad->activatenotify)
+ pad->activatenotify (pad->activatedata);
+ if (pad->activatemodenotify)
+ pad->activatemodenotify (pad->activatemodedata);
+ if (pad->linknotify)
+ pad->linknotify (pad->linkdata);
+ if (pad->unlinknotify)
+ pad->unlinknotify (pad->unlinkdata);
+ if (pad->chainnotify)
+ pad->chainnotify (pad->chaindata);
+ if (pad->chainlistnotify)
+ pad->chainlistnotify (pad->chainlistdata);
+ if (pad->getrangenotify)
+ pad->getrangenotify (pad->getrangedata);
+ if (pad->eventnotify)
+ pad->eventnotify (pad->eventdata);
+ if (pad->querynotify)
+ pad->querynotify (pad->querydata);
+ if (pad->iterintlinknotify)
+ pad->iterintlinknotify (pad->iterintlinkdata);
+
+ g_rec_mutex_clear (&pad->stream_rec_lock);
+ g_cond_clear (&pad->block_cond);
+ g_array_free (pad->priv->events, TRUE);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
* will be assigned.
* This function makes a copy of the name so you can safely free the name.
*
- * Returns: (transfer full): a new #GstPad, or NULL in case of an error.
+ * Returns: (transfer floating): a new #GstPad, or NULL in case of an error.
*
* MT safe.
*/
return pad;
}
+#define ACQUIRE_PARENT(pad, parent, label) \
+ G_STMT_START { \
+ if (G_LIKELY ((parent = GST_OBJECT_PARENT (pad)))) \
+ gst_object_ref (parent); \
+ else if (G_LIKELY (GST_PAD_NEEDS_PARENT (pad))) \
+ goto label; \
+ } G_STMT_END
+
+#define RELEASE_PARENT(parent) \
+ G_STMT_START { \
+ if (G_LIKELY (parent)) \
+ gst_object_unref (parent); \
+ } G_STMT_END
+
/**
* gst_pad_get_direction:
* @pad: a #GstPad to get the direction of.
}
static gboolean
-gst_pad_activate_default (GstPad * pad)
+gst_pad_activate_default (GstPad * pad, GstObject * parent)
{
- return gst_pad_activate_push (pad, TRUE);
+ return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
}
static void
-pre_activate (GstPad * pad, GstPadActivateMode new_mode)
+pre_activate (GstPad * pad, GstPadMode new_mode)
{
switch (new_mode) {
- case GST_PAD_ACTIVATE_PUSH:
- case GST_PAD_ACTIVATE_PULL:
- GST_OBJECT_LOCK (pad);
- GST_DEBUG_OBJECT (pad, "setting ACTIVATE_MODE %d, unset flushing",
- new_mode);
- GST_PAD_UNSET_FLUSHING (pad);
- GST_PAD_ACTIVATE_MODE (pad) = new_mode;
- GST_OBJECT_UNLOCK (pad);
- break;
- case GST_PAD_ACTIVATE_NONE:
+ case GST_PAD_MODE_NONE:
GST_OBJECT_LOCK (pad);
- GST_DEBUG_OBJECT (pad, "setting ACTIVATE_MODE NONE, set flushing");
+ GST_DEBUG_OBJECT (pad, "setting PAD_MODE NONE, set flushing");
GST_PAD_SET_FLUSHING (pad);
- GST_PAD_ACTIVATE_MODE (pad) = new_mode;
+ GST_PAD_MODE (pad) = new_mode;
/* unlock blocked pads so element can resume and stop */
GST_PAD_BLOCK_BROADCAST (pad);
GST_OBJECT_UNLOCK (pad);
break;
+ case GST_PAD_MODE_PUSH:
+ case GST_PAD_MODE_PULL:
+ GST_OBJECT_LOCK (pad);
+ GST_DEBUG_OBJECT (pad, "setting PAD_MODE %d, unset flushing", new_mode);
+ GST_PAD_UNSET_FLUSHING (pad);
+ GST_PAD_MODE (pad) = new_mode;
+ if (GST_PAD_IS_SINK (pad)) {
+ GstPad *peer;
+ /* make sure the peer src pad sends us all events */
+ if ((peer = GST_PAD_PEER (pad))) {
+ gst_object_ref (peer);
+ GST_OBJECT_UNLOCK (pad);
+
+ GST_DEBUG_OBJECT (pad, "reschedule events on peer %s:%s",
+ GST_DEBUG_PAD_NAME (peer));
+
+ GST_OBJECT_LOCK (peer);
+ schedule_events (peer, NULL);
+ GST_OBJECT_UNLOCK (peer);
+
+ gst_object_unref (peer);
+ } else {
+ GST_OBJECT_UNLOCK (pad);
+ }
+ } else {
+ GST_OBJECT_UNLOCK (pad);
+ }
+ break;
}
}
static void
-post_activate (GstPad * pad, GstPadActivateMode new_mode)
+post_activate (GstPad * pad, GstPadMode new_mode)
{
switch (new_mode) {
- case GST_PAD_ACTIVATE_PUSH:
- case GST_PAD_ACTIVATE_PULL:
- /* nop */
- break;
- case GST_PAD_ACTIVATE_NONE:
+ case GST_PAD_MODE_NONE:
/* ensures that streaming stops */
GST_PAD_STREAM_LOCK (pad);
GST_DEBUG_OBJECT (pad, "stopped streaming");
GST_OBJECT_LOCK (pad);
- clear_events (pad->priv->events);
+ remove_events (pad);
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
break;
+ case GST_PAD_MODE_PUSH:
+ case GST_PAD_MODE_PULL:
+ /* NOP */
+ break;
}
}
gboolean
gst_pad_set_active (GstPad * pad, gboolean active)
{
- GstPadActivateMode old;
+ GstObject *parent;
+ GstPadMode old;
gboolean ret = FALSE;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
GST_OBJECT_LOCK (pad);
- old = GST_PAD_ACTIVATE_MODE (pad);
+ old = GST_PAD_MODE (pad);
+ ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
if (active) {
- switch (old) {
- case GST_PAD_ACTIVATE_PUSH:
- GST_DEBUG_OBJECT (pad, "activating pad from push");
- ret = TRUE;
- break;
- case GST_PAD_ACTIVATE_PULL:
- GST_DEBUG_OBJECT (pad, "activating pad from pull");
- ret = TRUE;
- break;
- case GST_PAD_ACTIVATE_NONE:
- GST_DEBUG_OBJECT (pad, "activating pad from none");
- ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad);
- break;
- default:
- GST_DEBUG_OBJECT (pad, "unknown activation mode!");
- break;
+ if (old == GST_PAD_MODE_NONE) {
+ GST_DEBUG_OBJECT (pad, "activating pad from none");
+ ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad, parent);
+ } else {
+ GST_DEBUG_OBJECT (pad, "pad was active in mode %d", old);
+ ret = TRUE;
}
} else {
- switch (old) {
- case GST_PAD_ACTIVATE_PUSH:
- GST_DEBUG_OBJECT (pad, "deactivating pad from push");
- ret = gst_pad_activate_push (pad, FALSE);
- break;
- case GST_PAD_ACTIVATE_PULL:
- GST_DEBUG_OBJECT (pad, "deactivating pad from pull");
- ret = gst_pad_activate_pull (pad, FALSE);
- break;
- case GST_PAD_ACTIVATE_NONE:
- GST_DEBUG_OBJECT (pad, "deactivating pad from none");
- ret = TRUE;
- break;
- default:
- GST_DEBUG_OBJECT (pad, "unknown activation mode!");
- break;
+ if (old == GST_PAD_MODE_NONE) {
+ GST_DEBUG_OBJECT (pad, "pad was inactive");
+ ret = TRUE;
+ } else {
+ GST_DEBUG_OBJECT (pad, "deactivating pad from mode %d", old);
+ ret = gst_pad_activate_mode (pad, old, FALSE);
}
}
- if (!ret) {
+ RELEASE_PARENT (parent);
+
+ if (G_UNLIKELY (!ret))
+ goto failed;
+
+ if (!active) {
+ GST_OBJECT_LOCK (pad);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
+ GST_OBJECT_UNLOCK (pad);
+ }
+ return ret;
+
+ /* ERRORS */
+no_parent:
+ {
+ GST_DEBUG_OBJECT (pad, "no parent");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
+failed:
+ {
GST_OBJECT_LOCK (pad);
if (!active) {
g_critical ("Failed to deactivate pad %s:%s, very bad",
GST_WARNING_OBJECT (pad, "Failed to activate pad");
}
GST_OBJECT_UNLOCK (pad);
- } else {
- if (!active) {
- GST_OBJECT_LOCK (pad);
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_NEED_RECONFIGURE);
- GST_OBJECT_UNLOCK (pad);
- }
+ return FALSE;
}
-
- return ret;
}
/**
- * gst_pad_activate_pull:
+ * gst_pad_activate_mode:
* @pad: the #GstPad to activate or deactivate.
+ * @mode: the requested activation mode
* @active: whether or not the pad should be active.
*
- * Activates or deactivates the given pad in pull mode via dispatching to the
- * pad's activatepullfunc. For use from within pad activation functions only.
- * When called on sink pads, will first proxy the call to the peer pad, which
- * is expected to activate its internally linked pads from within its
- * activate_pull function.
+ * Activates or deactivates the given pad in @mode via dispatching to the
+ * pad's activatemodefunc. For use from within pad activation functions only.
*
* If you don't know what this is, you probably don't want to call it.
*
* MT safe.
*/
gboolean
-gst_pad_activate_pull (GstPad * pad, gboolean active)
+gst_pad_activate_mode (GstPad * pad, GstPadMode mode, gboolean active)
{
- GstPadActivateMode old, new;
+ gboolean res = FALSE;
+ GstObject *parent;
+ GstPadMode old, new;
+ GstPadDirection dir;
GstPad *peer;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
GST_OBJECT_LOCK (pad);
- old = GST_PAD_ACTIVATE_MODE (pad);
+ old = GST_PAD_MODE (pad);
+ dir = GST_PAD_DIRECTION (pad);
+ ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
- if (active) {
- switch (old) {
- case GST_PAD_ACTIVATE_PULL:
- GST_DEBUG_OBJECT (pad, "activating pad from pull, was ok");
- goto was_ok;
- case GST_PAD_ACTIVATE_PUSH:
- GST_DEBUG_OBJECT (pad,
- "activating pad from push, deactivate push first");
- /* pad was activate in the wrong direction, deactivate it
- * and reactivate it in pull mode */
- if (G_UNLIKELY (!gst_pad_activate_push (pad, FALSE)))
- goto deactivate_failed;
- /* fallthrough, pad is deactivated now. */
- case GST_PAD_ACTIVATE_NONE:
- GST_DEBUG_OBJECT (pad, "activating pad from none");
- break;
- }
- } else {
- switch (old) {
- case GST_PAD_ACTIVATE_NONE:
- GST_DEBUG_OBJECT (pad, "deactivating pad from none, was ok");
- goto was_ok;
- case GST_PAD_ACTIVATE_PUSH:
- GST_DEBUG_OBJECT (pad, "deactivating pad from push, weird");
- /* pad was activated in the other direction, deactivate it
- * in push mode, this should not happen... */
- if (G_UNLIKELY (!gst_pad_activate_push (pad, FALSE)))
- goto deactivate_failed;
- /* everything is fine now */
- goto was_ok;
- case GST_PAD_ACTIVATE_PULL:
- GST_DEBUG_OBJECT (pad, "deactivating pad from pull");
- break;
- }
+ new = active ? mode : GST_PAD_MODE_NONE;
+
+ if (old == new)
+ goto was_ok;
+
+ if (active && old != mode) {
+ /* pad was activate in the wrong direction, deactivate it
+ * and reactivate it in the requested mode */
+ GST_DEBUG_OBJECT (pad, "deactivating pad from mode %d", old);
+ if (G_UNLIKELY (!gst_pad_activate_mode (pad, old, FALSE)))
+ goto deactivate_failed;
}
- if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
- if ((peer = gst_pad_get_peer (pad))) {
- GST_DEBUG_OBJECT (pad, "calling peer");
- if (G_UNLIKELY (!gst_pad_activate_pull (peer, active)))
- goto peer_failed;
- gst_object_unref (peer);
- } else {
- /* there is no peer, this is only fatal when we activate. When we
- * deactivate, we must assume the application has unlinked the peer and
- * will deactivate it eventually. */
- if (active)
- goto not_linked;
- else
- GST_DEBUG_OBJECT (pad, "deactivating unlinked pad");
- }
- } else {
- if (G_UNLIKELY (GST_PAD_GETRANGEFUNC (pad) == NULL))
- goto failure; /* Can't activate pull on a src without a
+ switch (mode) {
+ case GST_PAD_MODE_PULL:
+ {
+ if (dir == GST_PAD_SINK) {
+ if ((peer = gst_pad_get_peer (pad))) {
+ GST_DEBUG_OBJECT (pad, "calling peer");
+ if (G_UNLIKELY (!gst_pad_activate_mode (peer, mode, active)))
+ goto peer_failed;
+ gst_object_unref (peer);
+ } else {
+ /* there is no peer, this is only fatal when we activate. When we
+ * deactivate, we must assume the application has unlinked the peer and
+ * will deactivate it eventually. */
+ if (active)
+ goto not_linked;
+ else
+ GST_DEBUG_OBJECT (pad, "deactivating unlinked pad");
+ }
+ } else {
+ if (G_UNLIKELY (GST_PAD_GETRANGEFUNC (pad) == NULL))
+ goto failure; /* Can't activate pull on a src without a
getrange function */
+ }
+ break;
+ }
+ default:
+ break;
}
- new = active ? GST_PAD_ACTIVATE_PULL : GST_PAD_ACTIVATE_NONE;
pre_activate (pad, new);
- if (GST_PAD_ACTIVATEPULLFUNC (pad)) {
- if (G_UNLIKELY (!GST_PAD_ACTIVATEPULLFUNC (pad) (pad, active)))
+ if (GST_PAD_ACTIVATEMODEFUNC (pad)) {
+ if (G_UNLIKELY (!GST_PAD_ACTIVATEMODEFUNC (pad) (pad, parent, mode,
+ active)))
goto failure;
} else {
/* can happen for sinks of passthrough elements */
post_activate (pad, new);
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in pull mode",
- active ? "activated" : "deactivated");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in mode %d",
+ active ? "activated" : "deactivated", mode);
- return TRUE;
+exit_success:
+ res = TRUE;
+exit:
+ RELEASE_PARENT (parent);
+
+ return res;
+no_parent:
+ {
+ GST_DEBUG_OBJECT (pad, "no parent");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
was_ok:
{
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in pull mode",
- active ? "activated" : "deactivated");
- return TRUE;
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in mode %d",
+ active ? "activated" : "deactivated", mode);
+ goto exit_success;
}
deactivate_failed:
{
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
- "failed to %s in switch to pull from mode %d",
- (active ? "activate" : "deactivate"), old);
- return FALSE;
+ "failed to %s in switch to mode %d from mode %d",
+ (active ? "activate" : "deactivate"), mode, old);
+ goto exit;
}
peer_failed:
{
GST_OBJECT_LOCK (peer);
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
- "activate_pull on peer (%s:%s) failed", GST_DEBUG_PAD_NAME (peer));
+ "activate_mode on peer (%s:%s) failed", GST_DEBUG_PAD_NAME (peer));
GST_OBJECT_UNLOCK (peer);
gst_object_unref (peer);
- return FALSE;
+ goto exit;
}
not_linked:
{
GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "can't activate unlinked sink "
"pad in pull mode");
- return FALSE;
- }
-failure:
- {
- GST_OBJECT_LOCK (pad);
- GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in pull mode",
- active ? "activate" : "deactivate");
- GST_PAD_SET_FLUSHING (pad);
- GST_PAD_ACTIVATE_MODE (pad) = old;
- GST_OBJECT_UNLOCK (pad);
- return FALSE;
- }
-}
-
-/**
- * gst_pad_activate_push:
- * @pad: the #GstPad to activate or deactivate.
- * @active: whether the pad should be active or not.
- *
- * Activates or deactivates the given pad in push mode via dispatching to the
- * pad's activatepushfunc. For use from within pad activation functions only.
- *
- * If you don't know what this is, you probably don't want to call it.
- *
- * Returns: %TRUE if the operation was successful.
- *
- * MT safe.
- */
-gboolean
-gst_pad_activate_push (GstPad * pad, gboolean active)
-{
- GstPadActivateMode old, new;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "trying to set %s in push mode",
- active ? "activated" : "deactivated");
-
- GST_OBJECT_LOCK (pad);
- old = GST_PAD_ACTIVATE_MODE (pad);
- GST_OBJECT_UNLOCK (pad);
-
- if (active) {
- switch (old) {
- case GST_PAD_ACTIVATE_PUSH:
- GST_DEBUG_OBJECT (pad, "activating pad from push, was ok");
- goto was_ok;
- case GST_PAD_ACTIVATE_PULL:
- GST_DEBUG_OBJECT (pad,
- "activating pad from push, deactivating pull first");
- /* pad was activate in the wrong direction, deactivate it
- * an reactivate it in push mode */
- if (G_UNLIKELY (!gst_pad_activate_pull (pad, FALSE)))
- goto deactivate_failed;
- /* fallthrough, pad is deactivated now. */
- case GST_PAD_ACTIVATE_NONE:
- GST_DEBUG_OBJECT (pad, "activating pad from none");
- break;
- }
- } else {
- switch (old) {
- case GST_PAD_ACTIVATE_NONE:
- GST_DEBUG_OBJECT (pad, "deactivating pad from none, was ok");
- goto was_ok;
- case GST_PAD_ACTIVATE_PULL:
- GST_DEBUG_OBJECT (pad, "deactivating pad from pull, weird");
- /* pad was activated in the other direction, deactivate it
- * in pull mode, this should not happen... */
- if (G_UNLIKELY (!gst_pad_activate_pull (pad, FALSE)))
- goto deactivate_failed;
- /* everything is fine now */
- goto was_ok;
- case GST_PAD_ACTIVATE_PUSH:
- GST_DEBUG_OBJECT (pad, "deactivating pad from push");
- break;
- }
- }
-
- new = active ? GST_PAD_ACTIVATE_PUSH : GST_PAD_ACTIVATE_NONE;
- pre_activate (pad, new);
-
- if (GST_PAD_ACTIVATEPUSHFUNC (pad)) {
- if (G_UNLIKELY (!GST_PAD_ACTIVATEPUSHFUNC (pad) (pad, active))) {
- goto failure;
- }
- } else {
- /* quite ok, element relies on state change func to prepare itself */
- }
-
- post_activate (pad, new);
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in push mode",
- active ? "activated" : "deactivated");
- return TRUE;
-
-was_ok:
- {
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in push mode",
- active ? "activated" : "deactivated");
- return TRUE;
- }
-deactivate_failed:
- {
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
- "failed to %s in switch to push from mode %d",
- (active ? "activate" : "deactivate"), old);
- return FALSE;
+ goto exit;
}
failure:
{
GST_OBJECT_LOCK (pad);
- GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in push mode",
- active ? "activate" : "deactivate");
+ GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in mode %d",
+ active ? "activate" : "deactivate", mode);
GST_PAD_SET_FLUSHING (pad);
- GST_PAD_ACTIVATE_MODE (pad) = old;
+ GST_PAD_MODE (pad) = old;
GST_OBJECT_UNLOCK (pad);
- return FALSE;
+ goto exit;
}
}
if (mask & GST_PAD_PROBE_TYPE_BLOCKING) {
/* we have a block probe */
pad->num_blocked++;
- GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKED);
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_BLOCKED);
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "added blocking probe, "
"now %d blocking probes", pad->num_blocked);
}
"pad is in use, delay idle callback");
GST_OBJECT_UNLOCK (pad);
} else {
- GstPadProbeInfo info = { GST_PAD_PROBE_TYPE_IDLE, };
+ GstPadProbeInfo info = { GST_PAD_PROBE_TYPE_IDLE, res, };
/* the pad is idle now, we can signal the idle callback now */
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
pad->num_blocked);
if (pad->num_blocked == 0) {
GST_DEBUG_OBJECT (pad, "last blocking probe removed, unblocking");
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKED);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_BLOCKED);
GST_PAD_BLOCK_BROADCAST (pad);
}
}
g_return_val_if_fail (GST_IS_PAD (pad), result);
GST_OBJECT_LOCK (pad);
- result = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKED);
+ result = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_BLOCKED);
GST_OBJECT_UNLOCK (pad);
return result;
GST_OBJECT_LOCK (pad);
/* the blocking flag is only valid if the pad is not flushing */
- result = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKING) &&
- !GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLUSHING);
+ result = GST_PAD_IS_BLOCKING (pad) && !GST_PAD_IS_FLUSHING (pad);
GST_OBJECT_UNLOCK (pad);
return result;
* gst_pad_check_reconfigure:
* @pad: the #GstPad to check
*
- * Check and clear the #GST_PAD_NEED_RECONFIGURE flag on @pad and return %TRUE
+ * Check and clear the #GST_PAD_FLAG_NEED_RECONFIGURE flag on @pad and return %TRUE
* if the flag was set.
*
- * Returns: %TRUE is the GST_PAD_NEED_RECONFIGURE flag was set on @pad.
+ * Returns: %TRUE is the GST_PAD_FLAG_NEED_RECONFIGURE flag was set on @pad.
*/
gboolean
gst_pad_check_reconfigure (GstPad * pad)
GST_OBJECT_LOCK (pad);
reconfigure = GST_PAD_NEEDS_RECONFIGURE (pad);
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_NEED_RECONFIGURE);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
GST_OBJECT_UNLOCK (pad);
return reconfigure;
g_return_if_fail (GST_IS_PAD (pad));
GST_OBJECT_LOCK (pad);
- GST_OBJECT_FLAG_SET (pad, GST_PAD_NEED_RECONFIGURE);
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
GST_OBJECT_UNLOCK (pad);
}
/**
- * gst_pad_set_activate_function:
+ * gst_pad_set_activate_function_full:
* @pad: a #GstPad.
* @activate: the #GstPadActivateFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @activate will not be used anymore.
*
* Sets the given activate function for @pad. The activate function will
* dispatch to gst_pad_activate_push() or gst_pad_activate_pull() to perform
* Call this function if your sink pad can start a pull-based task.
*/
void
-gst_pad_set_activate_function (GstPad * pad, GstPadActivateFunction activate)
+gst_pad_set_activate_function_full (GstPad * pad,
+ GstPadActivateFunction activate, gpointer user_data, GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
+ if (pad->activatenotify)
+ pad->activatenotify (pad->activatedata);
GST_PAD_ACTIVATEFUNC (pad) = activate;
+ pad->activatedata = user_data;
+ pad->activatenotify = notify;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "activatefunc set to %s",
GST_DEBUG_FUNCPTR_NAME (activate));
}
/**
- * gst_pad_set_activatepull_function:
+ * gst_pad_set_activatemode_function_full:
* @pad: a #GstPad.
- * @activatepull: the #GstPadActivateModeFunction to set.
+ * @activatemode: the #GstPadActivateModeFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @activatemode will not be used anymore.
*
- * Sets the given activate_pull function for the pad. An activate_pull function
- * prepares the element and any upstream connections for pulling. See XXX
- * part-activation.txt for details.
+ * Sets the given activate_mode function for the pad. An activate_mode function
+ * prepares the element for data passing.
*/
void
-gst_pad_set_activatepull_function (GstPad * pad,
- GstPadActivateModeFunction activatepull)
+gst_pad_set_activatemode_function_full (GstPad * pad,
+ GstPadActivateModeFunction activatemode, gpointer user_data,
+ GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
- GST_PAD_ACTIVATEPULLFUNC (pad) = activatepull;
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "activatepullfunc set to %s",
- GST_DEBUG_FUNCPTR_NAME (activatepull));
-}
-
-/**
- * gst_pad_set_activatepush_function:
- * @pad: a #GstPad.
- * @activatepush: the #GstPadActivateModeFunction to set.
- *
- * Sets the given activate_push function for the pad. An activate_push function
- * prepares the element for pushing. See XXX part-activation.txt for details.
- */
-void
-gst_pad_set_activatepush_function (GstPad * pad,
- GstPadActivateModeFunction activatepush)
-{
- g_return_if_fail (GST_IS_PAD (pad));
+ if (pad->activatemodenotify)
+ pad->activatemodenotify (pad->activatemodedata);
+ GST_PAD_ACTIVATEMODEFUNC (pad) = activatemode;
+ pad->activatemodedata = user_data;
+ pad->activatemodenotify = notify;
- GST_PAD_ACTIVATEPUSHFUNC (pad) = activatepush;
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "activatepushfunc set to %s",
- GST_DEBUG_FUNCPTR_NAME (activatepush));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "activatemodefunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (activatemode));
}
/**
- * gst_pad_set_chain_function:
+ * gst_pad_set_chain_function_full:
* @pad: a sink #GstPad.
* @chain: the #GstPadChainFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @chain will not be used anymore.
*
* Sets the given chain function for the pad. The chain function is called to
* process a #GstBuffer input buffer. see #GstPadChainFunction for more details.
*/
void
-gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain)
+gst_pad_set_chain_function_full (GstPad * pad, GstPadChainFunction chain,
+ gpointer user_data, GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (GST_PAD_IS_SINK (pad));
+ if (pad->chainnotify)
+ pad->chainnotify (pad->chaindata);
GST_PAD_CHAINFUNC (pad) = chain;
+ pad->chaindata = user_data;
+ pad->chainnotify = notify;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "chainfunc set to %s",
GST_DEBUG_FUNCPTR_NAME (chain));
}
/**
- * gst_pad_set_chain_list_function:
+ * gst_pad_set_chain_list_function_full:
* @pad: a sink #GstPad.
* @chainlist: the #GstPadChainListFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @chainlist will not be used anymore.
*
* Sets the given chain list function for the pad. The chainlist function is
* called to process a #GstBufferList input buffer list. See
* Since: 0.10.24
*/
void
-gst_pad_set_chain_list_function (GstPad * pad,
- GstPadChainListFunction chainlist)
+gst_pad_set_chain_list_function_full (GstPad * pad,
+ GstPadChainListFunction chainlist, gpointer user_data,
+ GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (GST_PAD_IS_SINK (pad));
+ if (pad->chainlistnotify)
+ pad->chainlistnotify (pad->chainlistdata);
GST_PAD_CHAINLISTFUNC (pad) = chainlist;
+ pad->chainlistdata = user_data;
+ pad->chainlistnotify = notify;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "chainlistfunc set to %s",
GST_DEBUG_FUNCPTR_NAME (chainlist));
}
/**
- * gst_pad_set_getrange_function:
+ * gst_pad_set_getrange_function_full:
* @pad: a source #GstPad.
* @get: the #GstPadGetRangeFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @get will not be used anymore.
*
* Sets the given getrange function for the pad. The getrange function is
* called to produce a new #GstBuffer to start the processing pipeline. see
* #GstPadGetRangeFunction for a description of the getrange function.
*/
void
-gst_pad_set_getrange_function (GstPad * pad, GstPadGetRangeFunction get)
+gst_pad_set_getrange_function_full (GstPad * pad, GstPadGetRangeFunction get,
+ gpointer user_data, GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (GST_PAD_IS_SRC (pad));
+ if (pad->getrangenotify)
+ pad->getrangenotify (pad->getrangedata);
GST_PAD_GETRANGEFUNC (pad) = get;
+ pad->getrangedata = user_data;
+ pad->getrangenotify = notify;
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "getrangefunc set to %s",
GST_DEBUG_FUNCPTR_NAME (get));
}
/**
- * gst_pad_set_event_function:
+ * gst_pad_set_event_function_full:
* @pad: a #GstPad of either direction.
* @event: the #GstPadEventFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @event will not be used anymore.
*
* Sets the given event handler for the pad.
*/
void
-gst_pad_set_event_function (GstPad * pad, GstPadEventFunction event)
+gst_pad_set_event_function_full (GstPad * pad, GstPadEventFunction event,
+ gpointer user_data, GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
+ if (pad->eventnotify)
+ pad->eventnotify (pad->eventdata);
GST_PAD_EVENTFUNC (pad) = event;
+ pad->eventdata = user_data;
+ pad->eventnotify = notify;
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "eventfunc for set to %s",
GST_DEBUG_FUNCPTR_NAME (event));
}
/**
- * gst_pad_set_query_function:
+ * gst_pad_set_query_function_full:
* @pad: a #GstPad of either direction.
* @query: the #GstPadQueryFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @query will not be used anymore.
*
* Set the given query function for the pad.
*/
void
-gst_pad_set_query_function (GstPad * pad, GstPadQueryFunction query)
+gst_pad_set_query_function_full (GstPad * pad, GstPadQueryFunction query,
+ gpointer user_data, GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
+ if (pad->querynotify)
+ pad->querynotify (pad->querydata);
GST_PAD_QUERYFUNC (pad) = query;
+ pad->querydata = user_data;
+ pad->querynotify = notify;
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "queryfunc set to %s",
GST_DEBUG_FUNCPTR_NAME (query));
}
/**
- * gst_pad_set_iterate_internal_links_function:
+ * gst_pad_set_iterate_internal_links_function_full:
* @pad: a #GstPad of either direction.
* @iterintlink: the #GstPadIterIntLinkFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @iterintlink will not be used anymore.
*
* Sets the given internal link iterator function for the pad.
*
* Since: 0.10.21
*/
void
-gst_pad_set_iterate_internal_links_function (GstPad * pad,
- GstPadIterIntLinkFunction iterintlink)
+gst_pad_set_iterate_internal_links_function_full (GstPad * pad,
+ GstPadIterIntLinkFunction iterintlink, gpointer user_data,
+ GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
+ if (pad->iterintlinknotify)
+ pad->iterintlinknotify (pad->iterintlinkdata);
GST_PAD_ITERINTLINKFUNC (pad) = iterintlink;
+ pad->iterintlinkdata = user_data;
+ pad->iterintlinknotify = notify;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "internal link iterator set to %s",
GST_DEBUG_FUNCPTR_NAME (iterintlink));
}
/**
- * gst_pad_set_link_function:
+ * gst_pad_set_link_function_full:
* @pad: a #GstPad.
* @link: the #GstPadLinkFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @link will not be used anymore.
*
* Sets the given link function for the pad. It will be called when
* the pad is linked with another pad.
* of the peer sink pad, if present.
*/
void
-gst_pad_set_link_function (GstPad * pad, GstPadLinkFunction link)
+gst_pad_set_link_function_full (GstPad * pad, GstPadLinkFunction link,
+ gpointer user_data, GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
+ if (pad->linknotify)
+ pad->linknotify (pad->linkdata);
GST_PAD_LINKFUNC (pad) = link;
+ pad->linkdata = user_data;
+ pad->linknotify = notify;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "linkfunc set to %s",
GST_DEBUG_FUNCPTR_NAME (link));
}
/**
- * gst_pad_set_unlink_function:
+ * gst_pad_set_unlink_function_full:
* @pad: a #GstPad.
* @unlink: the #GstPadUnlinkFunction to set.
+ * @user_data: user_data passed to @notify
+ * @notify: notify called when @unlink will not be used anymore.
*
* Sets the given unlink function for the pad. It will be called
* when the pad is unlinked.
*/
void
-gst_pad_set_unlink_function (GstPad * pad, GstPadUnlinkFunction unlink)
+gst_pad_set_unlink_function_full (GstPad * pad, GstPadUnlinkFunction unlink,
+ gpointer user_data, GDestroyNotify notify)
{
g_return_if_fail (GST_IS_PAD (pad));
+ if (pad->unlinknotify)
+ pad->unlinknotify (pad->unlinkdata);
GST_PAD_UNLINKFUNC (pad) = unlink;
+ pad->unlinkdata = user_data;
+ pad->unlinknotify = notify;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "unlinkfunc set to %s",
GST_DEBUG_FUNCPTR_NAME (unlink));
}
/**
- * gst_pad_set_getcaps_function:
- * @pad: a #GstPad.
- * @getcaps: the #GstPadGetCapsFunction to set.
- *
- * Sets the given getcaps function for the pad. @getcaps should return the
- * allowable caps for a pad in the context of the element's state, its link to
- * other elements, and the devices or files it has opened. These caps must be a
- * subset of the pad template caps. In the NULL state with no links, @getcaps
- * should ideally return the same caps as the pad template. In rare
- * circumstances, an object property can affect the caps returned by @getcaps,
- * but this is discouraged.
- *
- * You do not need to call this function if @pad's allowed caps are always the
- * same as the pad template caps. This can only be true if the padtemplate
- * has fixed simple caps.
- *
- * For most filters, the caps returned by @getcaps is directly affected by the
- * allowed caps on other pads. For demuxers and decoders, the caps returned by
- * the srcpad's getcaps function is directly related to the stream data. Again,
- * @getcaps should return the most specific caps it reasonably can, since this
- * helps with autoplugging.
- *
- * Note that the return value from @getcaps is owned by the caller, so the
- * caller should unref the caps after usage.
- */
-void
-gst_pad_set_getcaps_function (GstPad * pad, GstPadGetCapsFunction getcaps)
-{
- g_return_if_fail (GST_IS_PAD (pad));
-
- GST_PAD_GETCAPSFUNC (pad) = getcaps;
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "getcapsfunc set to %s",
- GST_DEBUG_FUNCPTR_NAME (getcaps));
-}
-
-/**
* gst_pad_unlink:
* @srcpad: the source #GstPad to unlink.
* @sinkpad: the sink #GstPad to unlink.
{
gboolean result = FALSE;
GstElement *parent = NULL;
- gint i;
g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), FALSE);
GST_PAD_PEER (srcpad) = NULL;
GST_PAD_PEER (sinkpad) = NULL;
- /* clear pending caps if any */
- for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
- gst_event_replace (&sinkpad->priv->events[i].pending, NULL);
-
GST_OBJECT_UNLOCK (sinkpad);
GST_OBJECT_UNLOCK (srcpad);
/* Doing the expensive caps checking takes priority over only checking the template caps */
if (flags & GST_PAD_LINK_CHECK_CAPS) {
- srccaps = gst_pad_get_caps_unlocked (src, NULL);
- sinkcaps = gst_pad_get_caps_unlocked (sink, NULL);
+ GST_OBJECT_UNLOCK (sink);
+ GST_OBJECT_UNLOCK (src);
+
+ srccaps = gst_pad_query_caps (src, NULL);
+ sinkcaps = gst_pad_query_caps (sink, NULL);
+
+ GST_OBJECT_LOCK (src);
+ GST_OBJECT_LOCK (sink);
} else {
/* If one of the two pads doesn't have a template, consider the intersection
* as valid.*/
GST_PAD_PEER (srcpad) = sinkpad;
GST_PAD_PEER (sinkpad) = srcpad;
- /* make sure we update events */
- prepare_event_update (srcpad, sinkpad);
+ /* check events, when something is different, mark pending */
+ schedule_events (srcpad, sinkpad);
/* get the link functions */
srcfunc = GST_PAD_LINKFUNC (srcpad);
return (templ ? gst_object_ref (templ) : NULL);
}
-static GstCaps *
-caps_with_getcaps (GstPad * pad, GstCaps * filter)
-{
- GstCaps *result;
-
- if (GST_PAD_GETCAPSFUNC (pad) == NULL)
- return NULL;
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "dispatching to pad getcaps function with "
- "filter %" GST_PTR_FORMAT, filter);
-
- GST_OBJECT_FLAG_SET (pad, GST_PAD_IN_GETCAPS);
- GST_OBJECT_UNLOCK (pad);
- result = GST_PAD_GETCAPSFUNC (pad) (pad, filter);
- GST_OBJECT_LOCK (pad);
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_GETCAPS);
-
- if (G_UNLIKELY (result == NULL))
- goto null_caps;
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "pad getcaps returned %" GST_PTR_FORMAT, result);
-
-#ifndef G_DISABLE_ASSERT
- /* check that the returned caps are a real subset of the template caps */
- if (GST_PAD_PAD_TEMPLATE (pad)) {
- const GstCaps *templ_caps =
- GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
- if (!gst_caps_is_subset (result, templ_caps)) {
- GstCaps *temp;
-
- GST_CAT_ERROR_OBJECT (GST_CAT_CAPS, pad,
- "pad returned caps %" GST_PTR_FORMAT
- " which are not a real subset of its template caps %"
- GST_PTR_FORMAT, result, templ_caps);
- g_warning
- ("pad %s:%s returned caps which are not a real "
- "subset of its template caps", GST_DEBUG_PAD_NAME (pad));
- temp = gst_caps_intersect (templ_caps, result);
- gst_caps_unref (result);
- result = temp;
- }
- }
- if (filter) {
- if (!gst_caps_is_subset (result, filter)) {
- GstCaps *temp;
-
- GST_CAT_ERROR_OBJECT (GST_CAT_CAPS, pad,
- "pad returned caps %" GST_PTR_FORMAT
- " which are not a real subset of the filter caps %"
- GST_PTR_FORMAT, result, filter);
- g_warning ("pad %s:%s returned caps which are not a real "
- "subset of the filter caps", GST_DEBUG_PAD_NAME (pad));
- /* FIXME: Order? But shouldn't happen anyway... */
- temp = gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (result);
- result = temp;
- }
- }
-#endif
-
- return result;
-
- /* ERRORS */
-null_caps:
- {
- g_critical ("pad %s:%s returned NULL caps from getcaps function",
- GST_DEBUG_PAD_NAME (pad));
- return NULL;
- }
-}
-
-/* should be called with the pad LOCK held */
-/* refs the caps, so caller is responsible for getting it unreffed */
-static GstCaps *
-gst_pad_get_caps_unlocked (GstPad * pad, GstCaps * filter)
-{
- GstCaps *result = NULL;
- GstPadTemplate *templ;
- gboolean fixed_caps;
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
-
- fixed_caps = GST_PAD_IS_FIXED_CAPS (pad);
-
- if (fixed_caps) {
- /* fixed caps, try the negotiated caps first */
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "fixed pad caps: trying pad caps");
- if ((result = get_pad_caps (pad)))
- goto filter_done;
- }
-
- /* try the getcaps function next */
- if ((result = caps_with_getcaps (pad, filter)))
- goto done;
-
- if ((templ = GST_PAD_PAD_TEMPLATE (pad))) {
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "trying pad template caps");
- if ((result = GST_PAD_TEMPLATE_CAPS (templ)))
- goto filter_done;
- }
-
- if (!fixed_caps) {
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "non-fixed pad caps: trying pad caps");
- /* non fixed caps, try the negotiated caps */
- if ((result = get_pad_caps (pad)))
- goto filter_done;
- }
-
- /* this almost never happens */
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad has no caps");
- result = gst_caps_new_empty ();
- goto done;
-
-filter_done:
- /* run the filter on the result */
- if (filter) {
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "using caps %p %" GST_PTR_FORMAT " with filter %p %"
- GST_PTR_FORMAT, result, result, filter, filter);
- result = gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "result %p %" GST_PTR_FORMAT,
- result, result);
- } else {
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "using caps %p %" GST_PTR_FORMAT, result, result);
- result = gst_caps_ref (result);
- }
-done:
- return result;
-}
-
-/**
- * gst_pad_has_current_caps:
- * @pad: a #GstPad to check
- *
- * Check if @pad has caps set on it with a #GST_EVENT_CAPS event.
- *
- * Returns: TRUE when @pad has caps associated with it.
- */
-gboolean
-gst_pad_has_current_caps (GstPad * pad)
+/**
+ * gst_pad_has_current_caps:
+ * @pad: a #GstPad to check
+ *
+ * Check if @pad has caps set on it with a #GST_EVENT_CAPS event.
+ *
+ * Returns: TRUE when @pad has caps associated with it.
+ */
+gboolean
+gst_pad_has_current_caps (GstPad * pad)
{
gboolean result;
GstCaps *caps;
}
/**
- * gst_pad_get_caps:
- * @pad: a #GstPad to get the capabilities of.
- * @filter: suggested #GstCaps.
- *
- * Gets the capabilities this pad can produce or consume.
- * Note that this method doesn't necessarily return the caps set by
- * gst_pad_set_caps() - use gst_pad_get_current_caps() for that instead.
- * gst_pad_get_caps returns all possible caps a pad can operate with, using
- * the pad's get_caps function;
- * this returns the pad template caps if not explicitly set.
- *
- * When called on sinkpads @filter contains the caps that
- * upstream could produce in the order preferred by upstream. When
- * called on srcpads @filter contains the caps accepted by
- * downstream in the preffered order. @filter might be %NULL but
- * if it is not %NULL the returned caps will be a subset of @filter.
- *
- * Note that this function does not return writable #GstCaps, use
- * gst_caps_make_writable() before modifying the caps.
- *
- * Returns: (transfer full): the caps of the pad with incremented ref-count.
- */
-GstCaps *
-gst_pad_get_caps (GstPad * pad, GstCaps * filter)
-{
- GstCaps *result = NULL;
-
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- g_return_val_if_fail (filter == NULL || GST_IS_CAPS (filter), NULL);
-
- GST_OBJECT_LOCK (pad);
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
-
- result = gst_pad_get_caps_unlocked (pad, filter);
-
- GST_OBJECT_UNLOCK (pad);
-
- return result;
-}
-
-
-/**
- * gst_pad_peer_get_caps:
- * @pad: a #GstPad to get the capabilities of.
- * @filter: a #GstCaps filter.
- *
- * Gets the capabilities of the peer connected to this pad. Similar to
- * gst_pad_get_caps().
- *
- * When called on srcpads @filter contains the caps that
- * upstream could produce in the order preferred by upstream. When
- * called on sinkpads @filter contains the caps accepted by
- * downstream in the preffered order. @filter might be %NULL but
- * if it is not %NULL the returned caps will be a subset of @filter.
- *
- * Returns: the caps of the peer pad with incremented ref-count. This function
- * returns %NULL when there is no peer pad.
- */
-GstCaps *
-gst_pad_peer_get_caps (GstPad * pad, GstCaps * filter)
-{
- GstPad *peerpad;
- GstCaps *result = NULL;
-
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- g_return_val_if_fail (filter == NULL || GST_IS_CAPS (filter), NULL);
-
- GST_OBJECT_LOCK (pad);
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get peer caps");
-
- peerpad = GST_PAD_PEER (pad);
- if (G_UNLIKELY (peerpad == NULL))
- goto no_peer;
-
- gst_object_ref (peerpad);
- GST_OBJECT_UNLOCK (pad);
-
- result = gst_pad_get_caps (peerpad, filter);
-
- gst_object_unref (peerpad);
-
- return result;
-
-no_peer:
- {
- GST_OBJECT_UNLOCK (pad);
- return NULL;
- }
-}
-
-/**
- * gst_pad_accept_caps:
- * @pad: a #GstPad to check
- * @caps: a #GstCaps to check on the pad
- *
- * Check if the given pad accepts the caps.
- *
- * Returns: TRUE if the pad can accept the caps.
- */
-gboolean
-gst_pad_accept_caps (GstPad * pad, GstCaps * caps)
-{
- gboolean res;
- GstQuery *query;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "accept caps of %p", caps);
-
- query = gst_query_new_accept_caps (caps);
- res = gst_pad_query (pad, query);
- if (res) {
- GST_DEBUG_OBJECT (pad, "query returned %d", res);
- gst_query_parse_accept_caps_result (query, &res);
- }
- gst_query_unref (query);
-
- return res;
-}
-
-/**
- * gst_pad_peer_accept_caps:
- * @pad: a #GstPad to check the peer of
- * @caps: a #GstCaps to check on the pad
- *
- * Check if the peer of @pad accepts @caps. If @pad has no peer, this function
- * returns FALSE.
- *
- * Returns: TRUE if the peer of @pad can accept the caps or @pad has no peer.
- */
-gboolean
-gst_pad_peer_accept_caps (GstPad * pad, GstCaps * caps)
-{
- gboolean result;
- GstQuery *query;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
-
- query = gst_query_new_accept_caps (caps);
- result = gst_pad_peer_query (pad, query);
- gst_query_unref (query);
-
- return result;
-}
-
-/**
* gst_pad_set_caps:
* @pad: a #GstPad to set the capabilities of.
* @caps: (transfer none): a #GstCaps to set.
return res;
}
-static gboolean
-do_event_function (GstPad * pad, GstEvent * event,
- GstPadEventFunction eventfunc, gboolean * caps_notify)
-{
- gboolean result = TRUE, call_event = TRUE;
- GstCaps *caps, *old, *templ;
-
- 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))
- goto not_accepted;
-
- /* check if it changed */
- if ((old = gst_pad_get_current_caps (pad))) {
- call_event = !gst_caps_is_equal (caps, old);
- gst_caps_unref (old);
- }
- if (call_event)
- *caps_notify = TRUE;
- gst_caps_unref (templ);
- break;
- }
- default:
- break;
- }
-
- if (call_event) {
- GST_DEBUG_OBJECT (pad, "calling event function with event %p", event);
- result = eventfunc (pad, event);
- } else {
- gst_event_unref (event);
- }
- return result;
-
- /* ERRORS */
-not_accepted:
- {
- gst_caps_unref (templ);
- gst_event_unref (event);
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "caps %" GST_PTR_FORMAT " not accepted", caps);
- return FALSE;
- }
-}
-
-/* function to send all pending events on the sinkpad to the event
- * function and collect the results. This function should be called with
- * the object lock. The object lock might be released by this function.
- */
-static GstFlowReturn
-gst_pad_update_events (GstPad * pad)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- guint i;
- GstPadEventFunction eventfunc;
- GstEvent *event;
- gboolean caps_notify = FALSE;
-
- if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
- goto no_function;
-
- for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
- gboolean res;
- PadEvent *ev;
-
- ev = &pad->priv->events[i];
-
- /* skip without pending event */
- if ((event = gst_event_steal (&ev->pending)) == NULL)
- continue;
-
- gst_event_ref (event);
- GST_OBJECT_UNLOCK (pad);
-
- res = do_event_function (pad, event, eventfunc, &caps_notify);
-
- /* things could have changed while we release the lock, check if we still
- * are handling the same event, if we don't something changed and we have
- * to try again. FIXME. we need a cookie here. FIXME, we also want to remove
- * that lock eventually and then do the retry elsewhere. */
-
- if (res) {
- /* make the event active */
- gst_event_take (&ev->event, event);
-
- /* notify caps change when needed */
- if (caps_notify) {
- g_object_notify_by_pspec ((GObject *) pad, pspec_caps);
- caps_notify = FALSE;
- }
- } else {
- gst_event_unref (event);
- ret = GST_FLOW_ERROR;
- }
- GST_OBJECT_LOCK (pad);
- }
- /* when we get here all events were successfully updated. */
- return ret;
-
- /* ERRORS */
-no_function:
- {
- g_warning ("pad %s:%s has no event handler, file a bug.",
- GST_DEBUG_PAD_NAME (pad));
- return GST_FLOW_NOT_SUPPORTED;
- }
-}
-
/**
* gst_pad_get_pad_template_caps:
* @pad: a #GstPad to get the template capabilities from.
* @pad and its peer.
*
* The allowed capabilities is calculated as the intersection of the results of
- * calling gst_pad_get_caps() on @pad and its peer. The caller owns a reference
+ * calling gst_pad_query_caps() on @pad and its peer. The caller owns a reference
* on the resulting caps.
*
* Returns: (transfer full): the allowed #GstCaps of the pad link. Unref the
gst_object_ref (peer);
GST_OBJECT_UNLOCK (pad);
- mycaps = gst_pad_get_caps (pad, NULL);
+ mycaps = gst_pad_query_caps (pad, NULL);
- peercaps = gst_pad_get_caps (peer, NULL);
+ peercaps = gst_pad_query_caps (peer, NULL);
gst_object_unref (peer);
caps = gst_caps_intersect (mycaps, peercaps);
/**
* gst_pad_iterate_internal_links_default:
* @pad: the #GstPad to get the internal links of.
+ * @parent: the parent of @pad or NULL
*
* Iterate the list of pads to which the given pad is linked to inside of
* the parent element.
* Since: 0.10.21
*/
GstIterator *
-gst_pad_iterate_internal_links_default (GstPad * pad)
+gst_pad_iterate_internal_links_default (GstPad * pad, GstObject * parent)
{
GstIterator *res;
GList **padlist;
guint32 *cookie;
GMutex *lock;
gpointer owner;
+ GstElement *eparent;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- {
- GstElement *parent;
-
+ if (parent != NULL && GST_IS_ELEMENT (parent)) {
+ eparent = GST_ELEMENT_CAST (gst_object_ref (parent));
+ } else {
GST_OBJECT_LOCK (pad);
- parent = GST_PAD_PARENT (pad);
- if (!parent || !GST_IS_ELEMENT (parent))
+ eparent = GST_PAD_PARENT (pad);
+ if (!eparent || !GST_IS_ELEMENT (eparent))
goto no_parent;
- gst_object_ref (parent);
+ gst_object_ref (eparent);
GST_OBJECT_UNLOCK (pad);
+ }
- if (pad->direction == GST_PAD_SRC)
- padlist = &parent->sinkpads;
- else
- padlist = &parent->srcpads;
+ if (pad->direction == GST_PAD_SRC)
+ padlist = &eparent->sinkpads;
+ else
+ padlist = &eparent->srcpads;
- GST_DEBUG_OBJECT (pad, "Making iterator");
+ GST_DEBUG_OBJECT (pad, "Making iterator");
- cookie = &parent->pads_cookie;
- owner = parent;
- lock = GST_OBJECT_GET_LOCK (parent);
- }
+ cookie = &eparent->pads_cookie;
+ owner = eparent;
+ lock = GST_OBJECT_GET_LOCK (eparent);
res = gst_iterator_new_list (GST_TYPE_PAD,
lock, cookie, padlist, (GObject *) owner, NULL);
gst_pad_iterate_internal_links (GstPad * pad)
{
GstIterator *res = NULL;
+ GstObject *parent;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- if (GST_PAD_ITERINTLINKFUNC (pad))
- res = GST_PAD_ITERINTLINKFUNC (pad) (pad);
-
+ GST_OBJECT_LOCK (pad);
+ ACQUIRE_PARENT (pad, parent, no_parent);
+ GST_OBJECT_UNLOCK (pad);
+
+ if (GST_PAD_ITERINTLINKFUNC (pad))
+ res = GST_PAD_ITERINTLINKFUNC (pad) (pad, parent);
+
+ RELEASE_PARENT (parent);
+
return res;
+
+ /* ERRORS */
+no_parent:
+ {
+ GST_DEBUG_OBJECT (pad, "no parent");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
}
/**
intpad = g_value_get_object (&item);
/* if already pushed, skip. FIXME, find something faster to tag pads */
- if (g_list_find (pushed_pads, intpad)) {
+ if (intpad == NULL || g_list_find (pushed_pads, intpad)) {
g_value_reset (&item);
break;
}
/**
* gst_pad_event_default:
* @pad: a #GstPad to call the default event handler on.
+ * @parent: the parent of @pad or NULL
* @event: (transfer full): the #GstEvent to handle.
*
* Invokes the default event handler for the given pad.
* The EOS event will pause the task associated with @pad before it is forwarded
* to all internally linked pads,
*
- * The CAPS event will never be forwarded.
- *
* The the event is sent to all pads internally linked to @pad. This function
* takes ownership of @event.
*
* Returns: TRUE if the event was sent successfully.
*/
gboolean
-gst_pad_event_default (GstPad * pad, GstEvent * event)
+gst_pad_event_default (GstPad * pad, GstObject * parent, GstEvent * event)
{
- gboolean result;
- EventData data;
+ gboolean result, forward = TRUE;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
gst_pad_pause_task (pad);
break;
}
+ case GST_EVENT_CAPS:
+ forward = GST_PAD_IS_PROXY_CAPS (pad);
+ result = TRUE;
+ break;
default:
break;
}
- data.event = event;
- data.dispatched = FALSE;
- data.result = FALSE;
+ if (forward) {
+ EventData data;
- gst_pad_forward (pad, (GstPadForwardFunction) event_forward_func, &data);
+ data.event = event;
+ data.dispatched = FALSE;
+ data.result = FALSE;
- /* for sinkpads without a parent element or without internal links, nothing
- * will be dispatched but we still want to return TRUE. */
- if (data.dispatched)
- result = data.result;
- else
- result = TRUE;
+ gst_pad_forward (pad, (GstPadForwardFunction) event_forward_func, &data);
+
+ /* for sinkpads without a parent element or without internal links, nothing
+ * will be dispatched but we still want to return TRUE. */
+ if (data.dispatched)
+ result = data.result;
+ else
+ result = TRUE;
+ }
gst_event_unref (event);
/* Default accept caps implementation just checks against
* the allowed caps for the pad */
static gboolean
-gst_pad_query_accept_caps (GstPad * pad, GstQuery * query)
+gst_pad_query_accept_caps_default (GstPad * pad, GstQuery * query)
{
/* get the caps and see if it intersects to something not empty */
GstCaps *caps, *allowed;
gboolean result;
- gst_query_parse_accept_caps (query, &caps);
+ GST_DEBUG_OBJECT (pad, "query accept-caps %" GST_PTR_FORMAT, query);
- GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
+ /* first forward the query to internally linked pads when we are dealing with
+ * a PROXY CAPS */
+ if (GST_PAD_IS_PROXY_CAPS (pad)) {
+ if ((result = gst_pad_proxy_query_accept_caps (pad, query))) {
+ goto done;
+ }
+ }
+
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, pad,
+ "fallback ACCEPT_CAPS query, consider implementing a specialized version");
+
+ allowed = gst_pad_query_caps (pad, NULL);
+ gst_query_parse_accept_caps (query, &caps);
- allowed = gst_pad_get_caps (pad, NULL);
if (allowed) {
GST_DEBUG_OBJECT (pad, "allowed caps %" GST_PTR_FORMAT, allowed);
result = gst_caps_is_subset (caps, allowed);
}
gst_query_set_accept_caps_result (query, result);
+done:
+ return TRUE;
+}
+
+/* Default caps implementation */
+static gboolean
+gst_pad_query_caps_default (GstPad * pad, GstQuery * query)
+{
+ GstCaps *result = NULL, *filter;
+ GstPadTemplate *templ;
+ gboolean fixed_caps;
+
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
+
+ gst_query_parse_caps (query, &filter);
+
+ /* first try to proxy if we must */
+ if (GST_PAD_IS_PROXY_CAPS (pad)) {
+ if ((gst_pad_proxy_query_caps (pad, query))) {
+ gst_query_parse_caps_result (query, &result);
+ goto filter_done;
+ }
+ }
+
+ /* no proxy or it failed, do default handling */
+ fixed_caps = GST_PAD_IS_FIXED_CAPS (pad);
+
+ GST_OBJECT_LOCK (pad);
+ if (fixed_caps) {
+ /* fixed caps, try the negotiated caps first */
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "fixed pad caps: trying pad caps");
+ if ((result = get_pad_caps (pad)))
+ goto filter_done_unlock;
+ }
+
+ if ((templ = GST_PAD_PAD_TEMPLATE (pad))) {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "trying pad template caps");
+ if ((result = GST_PAD_TEMPLATE_CAPS (templ)))
+ goto filter_done_unlock;
+ }
+
+ if (!fixed_caps) {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+ "non-fixed pad caps: trying pad caps");
+ /* non fixed caps, try the negotiated caps */
+ 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;
+
+filter_done_unlock:
+ GST_OBJECT_UNLOCK (pad);
+
+filter_done:
+ /* run the filter on the result */
+ if (filter) {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+ "using caps %p %" GST_PTR_FORMAT " with filter %p %"
+ GST_PTR_FORMAT, result, result, filter, filter);
+ result = gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "result %p %" GST_PTR_FORMAT,
+ result, result);
+ } else {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+ "using caps %p %" GST_PTR_FORMAT, result, result);
+ result = gst_caps_ref (result);
+ }
+
+done:
+ gst_query_set_caps_result (query, result);
+ gst_caps_unref (result);
+
return TRUE;
}
/**
* gst_pad_query_default:
* @pad: a #GstPad to call the default query handler on.
+ * @parent: the parent of @pad or NULL
* @query: (transfer none): the #GstQuery to handle.
*
* Invokes the default query handler for the given pad.
* Returns: TRUE if the query was performed successfully.
*/
gboolean
-gst_pad_query_default (GstPad * pad, GstQuery * query)
+gst_pad_query_default (GstPad * pad, GstObject * parent, GstQuery * query)
{
- gboolean forward = TRUE, ret = FALSE;
+ gboolean forward, ret = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_SCHEDULING:
forward = FALSE;
break;
+ case GST_QUERY_ALLOCATION:
+ forward = GST_PAD_IS_PROXY_ALLOCATION (pad);
+ break;
case GST_QUERY_ACCEPT_CAPS:
- ret = gst_pad_query_accept_caps (pad, query);
+ ret = gst_pad_query_accept_caps_default (pad, query);
+ forward = FALSE;
+ break;
+ case GST_QUERY_CAPS:
+ ret = gst_pad_query_caps_default (pad, query);
forward = FALSE;
break;
case GST_QUERY_POSITION:
case GST_QUERY_JITTER:
case GST_QUERY_RATE:
case GST_QUERY_CONVERT:
- case GST_QUERY_ALLOCATION:
default:
+ forward = TRUE;
break;
}
GstPadProbeCallback callback;
GstPadProbeReturn ret;
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "hook %lu, cookie %u checking", hook->hook_id, PROBE_COOKIE (hook));
-
/* if we have called this callback, do nothing */
if (PROBE_COOKIE (hook) == data->cookie) {
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
/* one of the scheduling types */
if ((flags & GST_PAD_PROBE_TYPE_SCHEDULING & type) == 0)
goto no_match;
- /* all of the blocking types must match */
- if ((flags & GST_PAD_PROBE_TYPE_BLOCKING) !=
- (type & GST_PAD_PROBE_TYPE_BLOCKING))
+ /* one of the blocking types must match */
+ if ((type & GST_PAD_PROBE_TYPE_BLOCKING) &&
+ (flags & GST_PAD_PROBE_TYPE_BLOCKING & type) == 0)
+ goto no_match;
+ /* only probes that have GST_PAD_PROBE_TYPE_EVENT_FLUSH set */
+ if ((type & GST_PAD_PROBE_TYPE_EVENT_FLUSH) &&
+ (flags & GST_PAD_PROBE_TYPE_EVENT_FLUSH & type) == 0)
goto no_match;
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "hook %lu with flags 0x%08x matches", hook->hook_id, flags);
+ "hook %lu, cookie %u with flags 0x%08x matches", hook->hook_id,
+ PROBE_COOKIE (hook), flags);
callback = (GstPadProbeCallback) hook->func;
if (callback == NULL)
return;
+ info->id = hook->hook_id;
+
GST_OBJECT_UNLOCK (pad);
ret = callback (pad, info, hook->data);
no_match:
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "hook %lu with flags 0x%08x does not match %08x", hook->hook_id,
- flags, info->type);
+ "hook %lu, cookie %u with flags 0x%08x does not match %08x",
+ hook->hook_id, PROBE_COOKIE (hook), flags, info->type);
return;
}
}
G_STMT_START { \
if (G_UNLIKELY (pad->num_probes)) { \
/* we start with passing NULL as the data item */ \
- GstPadProbeInfo info = { mask, NULL, offs, size }; \
+ 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); \
G_STMT_START { \
if (G_UNLIKELY (pad->num_probes)) { \
/* pass NULL as the data item */ \
- GstPadProbeInfo info = { mask, NULL, 0, 0 }; \
+ GstPadProbeInfo info = { mask, 0, NULL, 0, 0 }; \
ret = do_probe_callbacks (pad, &info, defaultval); \
if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK)) \
goto label; \
#define PROBE_FULL(pad,mask,data,offs,size,label,defaultval) \
G_STMT_START { \
if (G_UNLIKELY (pad->num_probes)) { \
- GstPadProbeInfo info = { mask, data, offs, size }; \
+ GstPadProbeInfo info = { mask, 0, 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)) \
* the pad after setting the FLUSHING flag. */
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"Waiting to be unblocked or set flushing");
- GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKING);
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_BLOCKING);
GST_PAD_BLOCK_WAIT (pad);
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_BLOCKING);
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "We got unblocked");
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
flushing:
{
GST_DEBUG_OBJECT (pad, "pad is flushing");
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
dropped:
{
void
gst_pad_set_offset (GstPad * pad, gint64 offset)
{
- guint idx;
- GstPad *peer;
- GstPad *tmp = NULL;
+ PadEvent *ev;
g_return_if_fail (GST_IS_PAD (pad));
goto done;
pad->offset = offset;
+ GST_DEBUG_OBJECT (pad, "changed offset to %" G_GINT64_FORMAT, offset);
- /* if no peer, we just updated the offset */
- if ((peer = GST_PAD_PEER (pad)) == NULL)
+ /* sinkpads will apply their offset the next time a segment
+ * event is received. */
+ if (GST_PAD_IS_SINK (pad))
goto done;
- /* switch pads around when dealing with a sinkpad */
- if (GST_PAD_IS_SINK (pad)) {
- /* ref the peer so it doesn't go away when we release the lock */
- tmp = gst_object_ref (peer);
- /* make sure we get the peer (the srcpad) */
- GST_OBJECT_UNLOCK (pad);
-
- /* swap pads */
- peer = pad;
- pad = tmp;
-
- GST_OBJECT_LOCK (pad);
- /* check if the pad didn't get relinked */
- if (GST_PAD_PEER (pad) != peer)
- goto done;
-
- /* we can release the ref now */
- gst_object_unref (peer);
+ /* resend the last segment event on next buffer push */
+ if ((ev = find_event_by_type (pad, GST_EVENT_SEGMENT, 0))) {
+ ev->received = FALSE;
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
}
- /* the index of the segment event in the array */
- idx = GST_EVENT_STICKY_IDX_TYPE (GST_EVENT_SEGMENT);
-
- /* lock order is srcpad >> sinkpad */
- GST_OBJECT_LOCK (peer);
- /* take the current segment event, adjust it and then place
- * it on the sinkpad. events on the srcpad are always active. */
- if (replace_event (pad, peer, idx))
- GST_OBJECT_FLAG_SET (peer, GST_PAD_NEED_EVENTS);
-
- GST_OBJECT_UNLOCK (peer);
-
done:
GST_OBJECT_UNLOCK (pad);
}
gboolean
gst_pad_query (GstPad * pad, GstQuery * query)
{
+ GstObject *parent;
gboolean res;
GstPadQueryFunction func;
GstPadProbeType type;
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);
+
+ ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
if ((func = GST_PAD_QUERYFUNC (pad)) == NULL)
goto no_func;
- res = func (pad, query);
+ res = func (pad, parent, query);
+
+ RELEASE_PARENT (parent);
GST_DEBUG_OBJECT (pad, "sent query %p (%s), result %d", query,
GST_QUERY_TYPE_NAME (query), res);
return res;
+ /* ERRORS */
+no_parent:
+ {
+ GST_DEBUG_OBJECT (pad, "had no parent");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
no_func:
{
GST_DEBUG_OBJECT (pad, "had no query function");
+ RELEASE_PARENT (parent);
return FALSE;
}
query_failed:
* 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.
*/
gst_pad_chain_data_unchecked (GstPad * pad, GstPadProbeType type, void *data)
{
GstFlowReturn ret;
- gboolean needs_events;
+ GstObject *parent;
GST_PAD_STREAM_LOCK (pad);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
- needs_events = GST_PAD_NEEDS_EVENTS (pad);
- if (G_UNLIKELY (needs_events)) {
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_NEED_EVENTS);
-
- GST_DEBUG_OBJECT (pad, "need to update all events");
- ret = gst_pad_update_events (pad);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto events_error;
- }
+ if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
+ goto wrong_mode;
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
PROBE_PUSH (pad, type, data, probe_stopped);
+ parent = GST_OBJECT_PARENT (pad);
GST_OBJECT_UNLOCK (pad);
/* NOTE: we read the chainfunc unlocked.
"calling chainfunction &%s with buffer %" GST_PTR_FORMAT,
GST_DEBUG_FUNCPTR_NAME (chainfunc), GST_BUFFER (data));
- ret = chainfunc (pad, GST_BUFFER_CAST (data));
+ ret = chainfunc (pad, parent, GST_BUFFER_CAST (data));
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"called chainfunction &%s with buffer %p, returned %s",
"calling chainlistfunction &%s",
GST_DEBUG_FUNCPTR_NAME (chainlistfunc));
- ret = chainlistfunc (pad, GST_BUFFER_LIST_CAST (data));
+ ret = chainlistfunc (pad, parent, GST_BUFFER_LIST_CAST (data));
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"called chainlistfunction &%s, returned %s",
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
-events_error:
+wrong_mode:
{
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "events were not accepted");
+ GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
+ ("chain on pad %s:%s but it was not in push mode",
+ GST_DEBUG_PAD_NAME (pad)));
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
- return ret;
+ return GST_FLOW_ERROR;
}
probe_stopped:
{
no_function:
{
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pushing, but not chainhandler");
- GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
- ("push on pad %s:%s but it has no chainfunction",
+ GST_ELEMENT_ERROR (parent, CORE, PAD, (NULL),
+ ("chain on pad %s:%s but it has no chainfunction",
GST_DEBUG_PAD_NAME (pad)));
GST_PAD_STREAM_UNLOCK (pad);
return GST_FLOW_NOT_SUPPORTED;
*
* Chain a buffer to @pad.
*
- * The function returns #GST_FLOW_WRONG_STATE if the pad was flushing.
+ * The function returns #GST_FLOW_FLUSHING if the pad was flushing.
*
* If the buffer type is not acceptable for @pad (as negotiated with a
* preceeding GST_EVENT_CAPS event), this function returns
}
static GstFlowReturn
-gst_pad_chain_list_default (GstPad * pad, GstBufferList * list)
+gst_pad_chain_list_default (GstPad * pad, GstObject * parent,
+ GstBufferList * list)
{
guint i, len;
GstBuffer *buffer;
*
* Chain a bufferlist to @pad.
*
- * The function returns #GST_FLOW_WRONG_STATE if the pad was flushing.
+ * The function returns #GST_FLOW_FLUSHING if the pad was flushing.
*
* If @pad was not negotiated properly with a CAPS event, this function
* returns #GST_FLOW_NOT_NEGOTIATED.
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ 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;
+ }
+
/* do block probes */
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
"pushing, but pad was flushing");
GST_OBJECT_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
+ }
+wrong_mode:
+ {
+ GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
+ ("pushing on pad %s:%s but it was not activated in push mode",
+ GST_DEBUG_PAD_NAME (pad)));
+ GST_OBJECT_UNLOCK (pad);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+ return GST_FLOW_ERROR;
+ }
+events_error:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "error pushing events, return %s", gst_flow_get_name (ret));
+ GST_OBJECT_UNLOCK (pad);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+ return ret;
}
probe_stopped:
{
{
GstFlowReturn ret;
GstPadGetRangeFunction getrangefunc;
+ GstObject *parent;
GST_PAD_STREAM_LOCK (pad);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ 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");
+
+ ret = GST_FLOW_OK;
+ events_foreach (pad, push_sticky, &ret);
+ if (ret != GST_FLOW_OK)
+ goto events_error;
+ }
+
/* 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);
+
+ ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
if (G_UNLIKELY ((getrangefunc = GST_PAD_GETRANGEFUNC (pad)) == NULL))
G_GUINT64_FORMAT ", size %u",
GST_DEBUG_FUNCPTR_NAME (getrangefunc), offset, size);
- ret = getrangefunc (pad, offset, size, buffer);
+ ret = getrangefunc (pad, parent, offset, size, buffer);
+
+ RELEASE_PARENT (parent);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto get_range_failed;
"getrange, but pad was flushing");
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
-no_function:
+wrong_mode:
{
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
+ ("getrange on pad %s:%s but it was not activated in pull mode",
+ GST_DEBUG_PAD_NAME (pad)));
+ GST_OBJECT_UNLOCK (pad);
+ GST_PAD_STREAM_UNLOCK (pad);
+ return GST_FLOW_ERROR;
+ }
+events_error:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "error pushing events");
+ GST_OBJECT_UNLOCK (pad);
+ GST_PAD_STREAM_UNLOCK (pad);
+ return ret;
+ }
+no_parent:
+ {
+ GST_DEBUG_OBJECT (pad, "no parent");
+ GST_OBJECT_UNLOCK (pad);
+ GST_PAD_STREAM_UNLOCK (pad);
+ return GST_FLOW_FLUSHING;
+ }
+no_function:
+ {
+ GST_ELEMENT_ERROR (parent, CORE, PAD, (NULL),
("getrange on pad %s:%s but it has no getrangefunction",
GST_DEBUG_PAD_NAME (pad)));
+ RELEASE_PARENT (parent);
GST_PAD_STREAM_UNLOCK (pad);
return GST_FLOW_NOT_SUPPORTED;
}
* @buffer: (out callee-allocates): a pointer to hold the #GstBuffer,
* returns #GST_FLOW_ERROR if %NULL.
*
- * When @pad is flushing this function returns #GST_FLOW_WRONG_STATE
+ * When @pad is flushing this function returns #GST_FLOW_FLUSHING
* immediately and @buffer is %NULL.
*
* Calls the getrange function of @pad, see #GstPadGetRangeFunction for a
{
GstPad *peer;
GstFlowReturn ret;
- gboolean needs_events;
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);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ 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,
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)) {
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_NEED_EVENTS);
-
- GST_DEBUG_OBJECT (pad, "we need to update the events");
- ret = gst_pad_update_events (pad);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto events_error;
- }
GST_OBJECT_UNLOCK (pad);
return ret;
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"pullrange, but pad was flushing");
GST_OBJECT_UNLOCK (pad);
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
+ }
+wrong_mode:
+ {
+ GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
+ ("gpulltange on pad %s:%s but it was not activated in pull mode",
+ GST_DEBUG_PAD_NAME (pad)));
+ GST_OBJECT_UNLOCK (pad);
+ return GST_FLOW_ERROR;
}
pre_probe_stopped:
{
*buffer = NULL;
return ret;
}
-events_error:
- {
- GST_OBJECT_UNLOCK (pad);
- gst_buffer_unref (*buffer);
- *buffer = NULL;
- GST_CAT_WARNING_OBJECT (GST_CAT_SCHEDULING, pad,
- "pullrange returned events that were not accepted");
- return ret;
- }
}
-/**
- * gst_pad_push_event:
- * @pad: a #GstPad to push the event to.
- * @event: (transfer full): the #GstEvent to send to the pad.
- *
- * Sends the event to the peer of the given pad. This function is
- * mainly used by elements to send events to their peer
- * elements.
- *
- * This function takes owership of the provided event so you should
- * gst_event_ref() it if you want to reuse the event after this call.
- *
- * Returns: TRUE if the event was handled.
- *
- * MT safe.
- */
-gboolean
-gst_pad_push_event (GstPad * pad, GstEvent * event)
+static gboolean
+gst_pad_store_sticky_event (GstPad * pad, GstEvent * event, gboolean locked)
{
- GstFlowReturn ret;
- GstPad *peerpad;
- gboolean result;
- gboolean stored = FALSE;
- GstPadProbeType type;
+ guint i, len;
+ GstEventType type;
+ GArray *events;
+ gboolean res = FALSE;
+ const gchar *name = NULL;
- 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);
+ type = GST_EVENT_TYPE (event);
+ if (type & GST_EVENT_TYPE_STICKY_MULTI)
+ name = gst_structure_get_name (gst_event_get_structure (event));
- if (GST_EVENT_IS_DOWNSTREAM (event))
- type = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM;
- else
- type = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
+ events = pad->priv->events;
+ len = events->len;
- GST_OBJECT_LOCK (pad);
+ for (i = 0; i < len; i++) {
+ PadEvent *ev = &g_array_index (events, PadEvent, i);
- peerpad = GST_PAD_PEER (pad);
+ if (ev->event == NULL)
+ continue;
- /* Two checks to be made:
- * . (un)set the FLUSHING flag for flushing events,
- * . handle pad blocking */
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- GST_PAD_SET_FLUSHING (pad);
+ if (type == GST_EVENT_TYPE (ev->event)) {
+ /* matching types, check matching name if needed */
+ if (name && !gst_event_has_name (ev->event, name))
+ continue;
- if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
- /* flush start will have set the FLUSHING flag and will then
- * unlock all threads doing a GCond wait on the blocking pad. This
- * will typically unblock the STREAMING thread blocked on a pad. */
- GST_LOG_OBJECT (pad, "Pad is blocked, not forwarding flush-start, "
- "doing block signal.");
- GST_PAD_BLOCK_BROADCAST (pad);
- goto flushed;
- }
+ /* overwrite */
+ if ((res = gst_event_replace (&ev->event, event)))
+ ev->received = FALSE;
break;
- case GST_EVENT_FLUSH_STOP:
- GST_PAD_UNSET_FLUSHING (pad);
+ }
+ }
+ if (i == len) {
+ PadEvent ev;
+ ev.event = gst_event_ref (event);
+ ev.received = FALSE;
+ g_array_append_val (events, ev);
+ res = TRUE;
+ }
- /* Remove sticky EOS events */
- GST_LOG_OBJECT (pad, "Removing pending EOS events");
- clear_event (pad->priv->events,
- GST_EVENT_STICKY_IDX_TYPE (GST_EVENT_EOS));
+ if (res) {
+ pad->priv->events_cookie++;
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
- if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
- GST_LOG_OBJECT (pad, "Pad is blocked, not forwarding flush-stop");
- goto flushed;
- }
+ GST_LOG_OBJECT (pad, "stored sticky event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ if (locked)
+ GST_OBJECT_UNLOCK (pad);
+
+ GST_DEBUG_OBJECT (pad, "notify caps");
+ g_object_notify_by_pspec ((GObject *) pad, pspec_caps);
+
+ if (locked)
+ GST_OBJECT_LOCK (pad);
+ break;
+ default:
+ break;
+ }
+ }
+ return res;
+}
+
+static GstFlowReturn
+gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
+ GstPadProbeType type, gboolean * stored)
+{
+ 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);
+
+ GST_PAD_BLOCK_BROADCAST (pad);
+ type |= GST_PAD_PROBE_TYPE_EVENT_FLUSH;
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ GST_PAD_UNSET_FLUSHING (pad);
+
+ /* Remove sticky EOS events */
+ GST_LOG_OBJECT (pad, "Removing pending EOS events");
+ remove_event_by_type (pad, GST_EVENT_EOS);
+
+ type |= GST_PAD_PROBE_TYPE_EVENT_FLUSH;
break;
default:
{
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushed;
- /* store the event on the pad, but only on srcpads */
- if (GST_PAD_IS_SRC (pad) && GST_EVENT_IS_STICKY (event)) {
- guint idx;
-
- idx = GST_EVENT_STICKY_IDX (event);
- GST_LOG_OBJECT (pad, "storing sticky event %s at index %u",
- GST_EVENT_TYPE_NAME (event), idx);
-
- /* srcpad sticky events always become active immediately */
- gst_event_replace (&pad->priv->events[idx].event, event);
-
- stored = TRUE;
+ /* 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;
}
- /* backwards compatibility mode for caps */
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_CAPS:
- {
- GST_OBJECT_UNLOCK (pad);
-
- g_object_notify_by_pspec ((GObject *) pad, pspec_caps);
-
- GST_OBJECT_LOCK (pad);
- /* the peerpad might have changed. Things we checked above could not
- * have changed. */
- peerpad = GST_PAD_PEER (pad);
- break;
- }
case GST_EVENT_SEGMENT:
- {
- gint64 offset;
-
- offset = pad->offset;
- /* check if we need to adjust the segment */
- if (offset != 0 && (peerpad != NULL)) {
- GstSegment segment;
-
- /* copy segment values */
- gst_event_copy_segment (event, &segment);
- gst_event_unref (event);
-
- /* adjust and make a new event with the offset applied */
- segment.base += offset;
- event = gst_event_new_segment (&segment);
- }
+ /* pass the adjusted segment event on. We need to do this even if
+ * there is no peer pad because of the probes. */
+ event = apply_pad_offset (pad, event);
break;
- }
case GST_EVENT_RECONFIGURE:
if (GST_PAD_IS_SINK (pad))
- GST_OBJECT_FLAG_SET (pad, GST_PAD_NEED_RECONFIGURE);
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
break;
default:
break;
}
-
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH |
GST_PAD_PROBE_TYPE_BLOCK, event, probe_stopped);
-
break;
}
}
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
/* now check the peer pad */
+ peerpad = GST_PAD_PEER (pad);
if (peerpad == NULL)
goto not_linked;
GST_LOG_OBJECT (pad, "sending event %p (%s) to peerpad %" GST_PTR_FORMAT,
event, GST_EVENT_TYPE_NAME (event), peerpad);
- result = gst_pad_send_event (peerpad, event);
+ ret = gst_pad_send_event_unchecked (peerpad, event, type);
/* Note: we gave away ownership of the event at this point but we can still
* print the old pointer */
GST_LOG_OBJECT (pad,
- "sent event %p to peerpad %" GST_PTR_FORMAT ", result %d", event, peerpad,
- result);
+ "sent event %p to peerpad %" GST_PTR_FORMAT ", ret %s", event, peerpad,
+ gst_flow_get_name (ret));
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,
- probe_stopped, GST_FLOW_OK);
+ idle_probe_stopped, ret);
}
GST_OBJECT_UNLOCK (pad);
- return result | stored;
+ return ret;
/* ERROR handling */
flushed:
GST_DEBUG_OBJECT (pad, "We're flushing");
GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
- return stored;
+ return GST_FLOW_FLUSHING;
}
probe_stopped:
{
- GST_DEBUG_OBJECT (pad, "Probe returned %s", gst_flow_get_name (ret));
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
- return stored;
+
+ switch (ret) {
+ case GST_FLOW_CUSTOM_SUCCESS:
+ GST_DEBUG_OBJECT (pad, "dropped event");
+ ret = GST_FLOW_OK;
+ break;
+ default:
+ GST_DEBUG_OBJECT (pad, "en error occured %s", gst_flow_get_name (ret));
+ break;
+ }
+ return ret;
}
not_linked:
{
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 stored;
+ return sticky ? GST_FLOW_OK : 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;
}
}
/**
- * gst_pad_send_event:
- * @pad: a #GstPad to send the event to.
+ * gst_pad_push_event:
+ * @pad: a #GstPad to push the event to.
* @event: (transfer full): the #GstEvent to send to the pad.
*
- * Sends the event to the pad. This function can be used
- * by applications to send events in the pipeline.
- *
- * If @pad is a source pad, @event should be an upstream event. If @pad is a
- * sink pad, @event should be a downstream event. For example, you would not
- * send a #GST_EVENT_EOS on a src pad; EOS events only propagate downstream.
- * Furthermore, some downstream events have to be serialized with data flow,
- * like EOS, while some can travel out-of-band, like #GST_EVENT_FLUSH_START. If
- * the event needs to be serialized with data flow, this function will take the
- * pad's stream lock while calling its event function.
- *
- * To find out whether an event type is upstream, downstream, or downstream and
- * serialized, see #GstEventTypeFlags, gst_event_type_get_flags(),
- * #GST_EVENT_IS_UPSTREAM, #GST_EVENT_IS_DOWNSTREAM, and
- * #GST_EVENT_IS_SERIALIZED. Note that in practice that an application or
- * plugin doesn't need to bother itself with this information; the core handles
- * all necessary locks and checks.
+ * Sends the event to the peer of the given pad. This function is
+ * mainly used by elements to send events to their peer
+ * elements.
*
* This function takes owership of the provided event so you should
* gst_event_ref() it if you want to reuse the event after this call.
*
* Returns: TRUE if the event was handled.
+ *
+ * MT safe.
*/
gboolean
-gst_pad_send_event (GstPad * pad, GstEvent * event)
+gst_pad_push_event (GstPad * pad, GstEvent * event)
{
- GstFlowReturn ret;
- gboolean result = FALSE;
- gboolean serialized, need_unlock = FALSE, needs_events, sticky;
+ gboolean res;
GstPadProbeType type;
+ gboolean stored;
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);
- GST_OBJECT_LOCK (pad);
- if (GST_PAD_IS_SINK (pad)) {
+ if (GST_PAD_IS_SRC (pad)) {
if (G_UNLIKELY (!GST_EVENT_IS_DOWNSTREAM (event)))
goto wrong_direction;
- serialized = GST_EVENT_IS_SERIALIZED (event);
- sticky = GST_EVENT_IS_STICKY (event);
type = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM;
- } else if (GST_PAD_IS_SRC (pad)) {
+ } else if (GST_PAD_IS_SINK (pad)) {
if (G_UNLIKELY (!GST_EVENT_IS_UPSTREAM (event)))
goto wrong_direction;
- /* events on srcpad never are serialized and sticky */
- serialized = sticky = FALSE;
+ /* events pushed on sinkpad never are sticky */
type = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
} else
goto unknown_direction;
- /* get the flag first, we clear it when we have a FLUSH or a non-serialized
- * event. */
- needs_events = GST_PAD_NEEDS_EVENTS (pad);
+ if (gst_pad_push_event_unchecked (pad, event, type, &stored) != GST_FLOW_OK)
+ res = stored ? TRUE : FALSE;
+ else
+ res = TRUE;
+
+ return res;
+
+ /* ERROR handling */
+wrong_direction:
+ {
+ g_warning ("pad %s:%s pushing %s event in wrong direction",
+ GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
+ gst_event_unref (event);
+ return FALSE;
+ }
+unknown_direction:
+ {
+ g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (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;
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))
+ goto not_accepted;
+
+ gst_caps_unref (templ);
+ break;
+ }
+ default:
+ break;
+ }
+ return GST_FLOW_OK;
+
+ /* 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;
+ }
+}
+
+static GstFlowReturn
+gst_pad_send_event_unchecked (GstPad * pad, GstEvent * event,
+ GstPadProbeType type)
+{
+ GstFlowReturn ret;
+ GstEventType event_type;
+ gboolean serialized, need_unlock = FALSE, sticky;
+ GstPadEventFunction eventfunc;
+ GstObject *parent;
+
+ GST_OBJECT_LOCK (pad);
+ if (GST_PAD_IS_SINK (pad))
+ serialized = GST_EVENT_IS_SERIALIZED (event);
+ else
+ serialized = FALSE;
+ sticky = GST_EVENT_IS_STICKY (event);
+ event_type = GST_EVENT_TYPE (event);
+ switch (event_type) {
case GST_EVENT_FLUSH_START:
GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad,
"have event type %d (FLUSH_START)", GST_EVENT_TYPE (event));
GST_PAD_SET_FLUSHING (pad);
GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad, "set flush flag");
- needs_events = FALSE;
break;
case GST_EVENT_FLUSH_STOP:
- if (G_LIKELY (GST_PAD_ACTIVATE_MODE (pad) != GST_PAD_ACTIVATE_NONE)) {
+ if (G_LIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_NONE)) {
GST_PAD_UNSET_FLUSHING (pad);
GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad, "cleared flush flag");
}
/* Remove pending EOS events */
GST_LOG_OBJECT (pad, "Removing pending EOS events");
- clear_event (pad->priv->events,
- GST_EVENT_STICKY_IDX_TYPE (GST_EVENT_EOS));
+ remove_event_by_type (pad, GST_EVENT_EOS);
GST_OBJECT_UNLOCK (pad);
/* grab stream lock */
GST_PAD_STREAM_LOCK (pad);
need_unlock = TRUE;
GST_OBJECT_LOCK (pad);
- needs_events = FALSE;
+ if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
+ goto flushing;
break;
case GST_EVENT_RECONFIGURE:
if (GST_PAD_IS_SRC (pad))
- GST_OBJECT_FLAG_SET (pad, GST_PAD_NEED_RECONFIGURE);
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
default:
- GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad, "have event type %s",
- GST_EVENT_TYPE_NAME (event));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad,
+ "have event type %" GST_PTR_FORMAT, event);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
GST_PAD_STREAM_LOCK (pad);
need_unlock = TRUE;
GST_OBJECT_LOCK (pad);
- } else {
- /* don't forward events on non-serialized events */
- needs_events = FALSE;
+ if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
+ goto flushing;
}
- /* store the event on the pad, but only on srcpads. We need to store the
- * event before checking the flushing flag. */
- if (sticky) {
- guint idx;
- PadEvent *ev;
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEGMENT:
- if (pad->offset != 0) {
- GstSegment segment;
-
- /* copy segment values */
- gst_event_copy_segment (event, &segment);
- gst_event_unref (event);
-
- /* adjust and make a new event with the offset applied */
- segment.base += pad->offset;
- event = gst_event_new_segment (&segment);
- }
- break;
- default:
- break;
- }
-
- idx = GST_EVENT_STICKY_IDX (event);
- ev = &pad->priv->events[idx];
-
- if (ev->event != event) {
- GST_LOG_OBJECT (pad, "storing sticky event %s at index %u",
- GST_EVENT_TYPE_NAME (event), idx);
- gst_event_replace (&ev->pending, event);
- /* set the flag so that we update the events next time. We would
- * usually update below but we might be flushing too. */
- GST_OBJECT_FLAG_SET (pad, GST_PAD_NEED_EVENTS);
- needs_events = TRUE;
- }
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ event = apply_pad_offset (pad, event);
+ break;
+ default:
+ break;
}
+
/* now do the probe */
PROBE_PUSH (pad,
type | GST_PAD_PROBE_TYPE_PUSH |
GST_PAD_PROBE_TYPE_BLOCK, event, probe_stopped);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
-
break;
}
- if (G_UNLIKELY (needs_events)) {
- GstFlowReturn ret;
+ if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
+ goto no_function;
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_NEED_EVENTS);
+ ACQUIRE_PARENT (pad, parent, no_parent);
+ GST_OBJECT_UNLOCK (pad);
- GST_DEBUG_OBJECT (pad, "need to update all events");
- ret = gst_pad_update_events (pad);
- if (ret != GST_FLOW_OK)
- goto update_failed;
- GST_OBJECT_UNLOCK (pad);
+ ret = pre_eventfunc_check (pad, event);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto precheck_failed;
- gst_event_unref (event);
+ if (sticky)
+ gst_event_ref (event);
- result = TRUE;
+ if (eventfunc (pad, parent, event)) {
+ ret = GST_FLOW_OK;
+ } else {
+ /* something went wrong */
+ switch (event_type) {
+ case GST_EVENT_CAPS:
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ break;
+ default:
+ ret = GST_FLOW_ERROR;
+ break;
+ }
}
+ RELEASE_PARENT (parent);
- /* ensure to pass on event;
- * note that a sticky event has already been updated above */
- if (G_LIKELY (!needs_events || !sticky)) {
- GstPadEventFunction eventfunc;
-
- if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
- goto no_function;
-
- GST_OBJECT_UNLOCK (pad);
+ GST_DEBUG_OBJECT (pad, "sent event, ret %s", gst_flow_get_name (ret));
- result = eventfunc (pad, event);
+ if (sticky) {
+ if (ret == GST_FLOW_OK) {
+ /* after the event function accepted the event, we can store the sticky
+ * event on the pad */
+ gst_pad_store_sticky_event (pad, event, FALSE);
+ }
+ gst_event_unref (event);
}
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
- GST_DEBUG_OBJECT (pad, "sent event, result %d", result);
-
- return result;
+ return ret;
/* ERROR handling */
-wrong_direction:
+flushing:
{
- g_warning ("pad %s:%s sending %s event in wrong direction",
- GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
GST_OBJECT_UNLOCK (pad);
+ if (need_unlock)
+ GST_PAD_STREAM_UNLOCK (pad);
+ GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad,
+ "Received event on flushing pad. Discarding");
gst_event_unref (event);
- return FALSE;
+ return GST_FLOW_FLUSHING;
}
-unknown_direction:
+probe_stopped:
{
- g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
GST_OBJECT_UNLOCK (pad);
+ if (need_unlock)
+ GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
- return FALSE;
+
+ switch (ret) {
+ case GST_FLOW_CUSTOM_SUCCESS:
+ GST_DEBUG_OBJECT (pad, "dropped event");
+ ret = GST_FLOW_OK;
+ break;
+ default:
+ GST_DEBUG_OBJECT (pad, "en error occured %s", gst_flow_get_name (ret));
+ break;
+ }
+ return ret;
}
no_function:
{
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
- return FALSE;
+ return GST_FLOW_NOT_SUPPORTED;
}
-flushing:
+no_parent:
{
+ GST_DEBUG_OBJECT (pad, "no parent");
GST_OBJECT_UNLOCK (pad);
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
- GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad,
- "Received event on flushing pad. Discarding");
gst_event_unref (event);
- return FALSE;
+ return GST_FLOW_FLUSHING;
}
-probe_stopped:
+precheck_failed:
{
- GST_DEBUG_OBJECT (pad, "probe returned %s", gst_flow_get_name (ret));
- GST_OBJECT_UNLOCK (pad);
+ GST_DEBUG_OBJECT (pad, "pre event check failed");
+ RELEASE_PARENT (parent);
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
+ return ret;
+ }
+}
+
+/**
+ * gst_pad_send_event:
+ * @pad: a #GstPad to send the event to.
+ * @event: (transfer full): the #GstEvent to send to the pad.
+ *
+ * Sends the event to the pad. This function can be used
+ * by applications to send events in the pipeline.
+ *
+ * If @pad is a source pad, @event should be an upstream event. If @pad is a
+ * sink pad, @event should be a downstream event. For example, you would not
+ * send a #GST_EVENT_EOS on a src pad; EOS events only propagate downstream.
+ * Furthermore, some downstream events have to be serialized with data flow,
+ * like EOS, while some can travel out-of-band, like #GST_EVENT_FLUSH_START. If
+ * the event needs to be serialized with data flow, this function will take the
+ * pad's stream lock while calling its event function.
+ *
+ * To find out whether an event type is upstream, downstream, or downstream and
+ * serialized, see #GstEventTypeFlags, gst_event_type_get_flags(),
+ * #GST_EVENT_IS_UPSTREAM, #GST_EVENT_IS_DOWNSTREAM, and
+ * #GST_EVENT_IS_SERIALIZED. Note that in practice that an application or
+ * plugin doesn't need to bother itself with this information; the core handles
+ * all necessary locks and checks.
+ *
+ * This function takes owership of the provided event so you should
+ * gst_event_ref() it if you want to reuse the event after this call.
+ *
+ * Returns: TRUE if the event was handled.
+ */
+gboolean
+gst_pad_send_event (GstPad * pad, GstEvent * event)
+{
+ gboolean result;
+ GstPadProbeType type;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ if (GST_PAD_IS_SINK (pad)) {
+ if (G_UNLIKELY (!GST_EVENT_IS_DOWNSTREAM (event)))
+ goto wrong_direction;
+ type = GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM;
+ } else if (GST_PAD_IS_SRC (pad)) {
+ if (G_UNLIKELY (!GST_EVENT_IS_UPSTREAM (event)))
+ goto wrong_direction;
+ type = GST_PAD_PROBE_TYPE_EVENT_UPSTREAM;
+ } else
+ goto unknown_direction;
+
+ if (gst_pad_send_event_unchecked (pad, event, type) != GST_FLOW_OK)
+ result = FALSE;
+ else
+ result = TRUE;
+
+ return result;
+
+ /* ERROR handling */
+wrong_direction:
+ {
+ g_warning ("pad %s:%s sending %s event in wrong direction",
+ GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
+ gst_event_unref (event);
return FALSE;
}
-update_failed:
+unknown_direction:
{
- GST_OBJECT_UNLOCK (pad);
- if (need_unlock)
- GST_PAD_STREAM_UNLOCK (pad);
- GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad, "Update events failed");
+ g_warning ("pad %s:%s has invalid direction", GST_DEBUG_PAD_NAME (pad));
gst_event_unref (event);
return FALSE;
}
}
-
-
/**
* gst_pad_set_element_private:
* @pad: the #GstPad to set the private data of.
* gst_pad_get_sticky_event:
* @pad: the #GstPad to get the event from.
* @event_type: the #GstEventType that should be retrieved.
+ * @idx: the index of the event
*
* Returns a new reference of the sticky event of type @event_type
* from the event.
*
- * Returns: (transfer full): a #GstEvent of type @event_type. Unref after usage.
+ * Returns: (transfer full): a #GstEvent of type @event_type or NULL when no
+ * event of @event_type was on @pad. Unref after usage.
*/
GstEvent *
-gst_pad_get_sticky_event (GstPad * pad, GstEventType event_type)
+gst_pad_get_sticky_event (GstPad * pad, GstEventType event_type, guint idx)
{
GstEvent *event = NULL;
- guint idx;
+ PadEvent *ev;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail ((event_type & GST_EVENT_TYPE_STICKY) != 0, NULL);
- idx = GST_EVENT_STICKY_IDX_TYPE (event_type);
-
GST_OBJECT_LOCK (pad);
- if ((event = pad->priv->events[idx].event)) {
+ ev = find_event_by_type (pad, event_type, idx);
+ if (ev && (event = ev->event))
gst_event_ref (event);
- }
GST_OBJECT_UNLOCK (pad);
return event;
}
+typedef struct
+{
+ GstPadStickyEventsForeachFunction func;
+ gpointer user_data;
+} ForeachDispatch;
+
+static gboolean
+foreach_dispatch_function (GstPad * pad, PadEvent * ev, gpointer user_data)
+{
+ ForeachDispatch *data = user_data;
+ gboolean ret;
+
+ GST_OBJECT_UNLOCK (pad);
+
+ ret = data->func (pad, &ev->event, data->user_data);
+
+ GST_OBJECT_LOCK (pad);
+
+ return ret;
+}
+
/**
* gst_pad_sticky_events_foreach:
* @pad: the #GstPad that should be used for iteration.
- * @foreach_func: (scope call): the #GstPadStickyEventsForeachFunction that should be called for every event.
+ * @foreach_func: (scope call): the #GstPadStickyEventsForeachFunction that
+ * should be called for every event.
* @user_data: (closure): the optional user data.
*
- * Iterates all active sticky events on @pad and calls @foreach_func for every
- * event. If @foreach_func returns something else than GST_FLOW_OK the iteration
- * is immediately stopped.
- *
- * Returns: GST_FLOW_OK if iteration was successful
+ * Iterates all sticky events on @pad and calls @foreach_func for every
+ * event. If @foreach_func returns %FALSE the iteration is immediately stopped.
*/
-GstFlowReturn
+void
gst_pad_sticky_events_foreach (GstPad * pad,
GstPadStickyEventsForeachFunction foreach_func, gpointer user_data)
{
- GstFlowReturn ret = GST_FLOW_OK;
- guint i;
- GstEvent *event;
-
- g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
- g_return_val_if_fail (foreach_func != NULL, GST_FLOW_ERROR);
+ ForeachDispatch data;
- GST_OBJECT_LOCK (pad);
-
-restart:
- for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
- gboolean res;
- PadEvent *ev;
-
- ev = &pad->priv->events[i];
-
- /* skip without active event */
- if ((event = ev->event) == NULL)
- continue;
-
- gst_event_ref (event);
- GST_OBJECT_UNLOCK (pad);
-
- res = foreach_func (pad, event, user_data);
-
- GST_OBJECT_LOCK (pad);
- gst_event_unref (event);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (foreach_func != NULL);
- if (res != GST_FLOW_OK) {
- ret = res;
- break;
- }
+ data.func = foreach_func;
+ data.user_data = user_data;
- /* things could have changed while we release the lock, check if we still
- * are handling the same event, if we don't something changed and we have
- * to try again. FIXME. we need a cookie here. */
- if (event != ev->event) {
- GST_DEBUG_OBJECT (pad, "events changed, restarting");
- goto restart;
- }
- }
+ GST_OBJECT_LOCK (pad);
+ events_foreach (pad, foreach_dispatch_function, &data);
GST_OBJECT_UNLOCK (pad);
-
- return ret;
}
static void