*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
/**
* SECTION:gstpad
* application requests.
*
* Pads without pad templates can be created with gst_pad_new(),
- * which takes a direction and a name as an argument. If the name is NULL,
+ * which takes a direction and a name as an argument. If the name is %NULL,
* then a guaranteed unique name will be assigned to it.
*
* A #GstElement creating a pad will typically use the various
*
* gst_pad_get_parent() will retrieve the #GstElement that owns the pad.
*
- * After two pads are retrieved from an element with gst_element_get_pad(),
+ * After two pads are retrieved from an element by gst_element_get_static_pad(),
* the pads can be linked with gst_pad_link(). (For quick links,
* you can also use gst_element_link(), which will make the obvious
* link for you if it's straightforward.). Pads can be unlinked again with
* Convenience functions exist to start, pause and stop the task on a pad with
* gst_pad_start_task(), gst_pad_pause_task() and gst_pad_stop_task()
* respectively.
- *
- * Last reviewed on 2012-03-29 (0.11.3)
*/
#include "gst_private.h"
/* we have a pending and an active event on the pad. On source pads only the
* active event is used. On sinkpads, events are copied to the pending entry and
- * moved to the active event when the eventfunc returned TRUE. */
+ * moved to the active event when the eventfunc returned %TRUE. */
typedef struct
{
gboolean received;
{
guint events_cookie;
GArray *events;
+ guint last_cookie;
gint using;
guint probe_list_cookie;
return 0;
}
+/**
+ * gst_pad_link_get_name:
+ * @ret: a #GstPadLinkReturn to get the name of.
+ *
+ * Gets a string representing the given pad-link return.
+ *
+ * Returns: a static string with the name of the pad-link return.
+ *
+ * Since: 1.4
+ */
+const gchar *
+gst_pad_link_get_name (GstPadLinkReturn ret)
+{
+ switch (ret) {
+ case GST_PAD_LINK_OK:
+ return "ok";
+ case GST_PAD_LINK_WRONG_HIERARCHY:
+ return "wrong hierarchy";
+ case GST_PAD_LINK_WAS_LINKED:
+ return "was linked";
+ case GST_PAD_LINK_WRONG_DIRECTION:
+ return "wrong direction";
+ case GST_PAD_LINK_NOFORMAT:
+ return "no common format";
+ case GST_PAD_LINK_NOSCHED:
+ return "incompatible scheduling";
+ case GST_PAD_LINK_REFUSED:
+ return "refused";
+ }
+ g_return_val_if_reached ("unknown");
+}
+
#define _do_init \
{ \
gint i; \
g_hook_list_init (&pad->probes, sizeof (GstProbe));
pad->priv->events = g_array_sized_new (FALSE, TRUE, sizeof (PadEvent), 16);
+ pad->priv->events_cookie = 0;
+ pad->priv->last_cookie = -1;
+ pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
}
/* called when setting the pad inactive. It removes all sticky events from
- * the pad */
+ * the pad. must be called with object lock */
static void
remove_events (GstPad * pad)
{
len = events->len;
for (i = 0; i < len; i++) {
PadEvent *ev = &g_array_index (events, PadEvent, i);
- gst_event_unref (ev->event);
+ GstEvent *event = ev->event;
+
+ ev->event = NULL;
+
+ if (event && GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
+ GST_OBJECT_UNLOCK (pad);
+
+ GST_DEBUG_OBJECT (pad, "notify caps");
+ g_object_notify_by_pspec ((GObject *) pad, pspec_caps);
+
+ GST_OBJECT_LOCK (pad);
+ }
+ gst_event_unref (event);
}
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
g_array_set_size (events, 0);
pad->priv->events_cookie++;
}
+/* should be called with object lock */
static PadEvent *
find_event_by_type (GstPad * pad, GstEventType type, guint idx)
{
return ev;
}
+/* should be called with OBJECT lock */
static PadEvent *
find_event (GstPad * pad, GstEvent * event)
{
return ev;
}
+/* should be called with OBJECT lock */
static void
remove_event_by_type (GstPad * pad, GstEventType type)
{
}
/* check all events on srcpad against those on sinkpad. All events that are not
- * on sinkpad are marked as received=FALSE and the PENDING_EVENTS is set on the
+ * on sinkpad are marked as received=%FALSE and the PENDING_EVENTS is set on the
* srcpad so that the events will be sent next time */
+/* should be called with srcpad and sinkpad LOCKS */
static void
schedule_events (GstPad * srcpad, GstPad * sinkpad)
{
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 */
+ gst_event_unref (ev->event);
g_array_remove_index (events, i);
len--;
cookie = ++pad->priv->events_cookie;
/* should be called with LOCK */
static GstEvent *
-apply_pad_offset (GstPad * pad, GstEvent * event)
+apply_pad_offset (GstPad * pad, GstEvent * event, gboolean upstream)
{
/* check if we need to adjust the segment */
if (pad->offset != 0) {
- GstSegment segment;
+ gint64 offset;
- /* copy segment values */
- gst_event_copy_segment (event, &segment);
- gst_event_unref (event);
+ GST_DEBUG_OBJECT (pad, "apply pad offset %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (pad->offset));
- /* adjust and make a new event with the offset applied */
- segment.base += pad->offset;
- event = gst_event_new_segment (&segment);
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+ GstSegment segment;
+
+ g_assert (!upstream);
+
+ /* copy segment values */
+ gst_event_copy_segment (event, &segment);
+ gst_event_unref (event);
+
+ gst_segment_offset_running_time (&segment, segment.format, pad->offset);
+ event = gst_event_new_segment (&segment);
+ }
+
+ event = gst_event_make_writable (event);
+ offset = gst_event_get_running_time_offset (event);
+ if (upstream)
+ offset -= pad->offset;
+ else
+ offset += pad->offset;
+ gst_event_set_running_time_offset (event, offset);
}
return event;
}
gst_pad_set_pad_template (pad, NULL);
+ GST_OBJECT_LOCK (pad);
remove_events (pad);
+ GST_OBJECT_UNLOCK (pad);
g_hook_list_clear (&pad->probes);
* @direction: the #GstPadDirection of the pad.
*
* Creates a new pad with the given name in the given direction.
- * If name is NULL, a guaranteed unique name (across all pads)
+ * If name is %NULL, a guaranteed unique name (across all pads)
* will be assigned.
* This function makes a copy of the name so you can safely free the name.
*
- * Returns: (transfer floating): 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.
*/
* @name: the name of the element
*
* Creates a new pad with the given name from the given template.
- * If name is NULL, a guaranteed unique name (across all pads)
+ * If name is %NULL, a guaranteed unique name (across all pads)
* 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.
*/
GstPad *
gst_pad_new_from_template (GstPadTemplate * templ, const gchar * name)
* @name: the name of the element
*
* Creates a new pad with the given name from the given static template.
- * If name is NULL, a guaranteed unique name (across all pads)
+ * If name is %NULL, a guaranteed unique name (across all pads)
* 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.
*/
GstPad *
gst_pad_new_from_static_template (GstStaticPadTemplate * templ,
return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
}
+/**
+ * gst_pad_mode_get_name:
+ * @mode: the pad mode
+ *
+ * Return the name of a pad mode, for use in debug messages mostly.
+ *
+ * Returns: short mnemonic for pad mode @mode
+ */
+const gchar *
+gst_pad_mode_get_name (GstPadMode mode)
+{
+ switch (mode) {
+ case GST_PAD_MODE_NONE:
+ return "none";
+ case GST_PAD_MODE_PUSH:
+ return "push";
+ case GST_PAD_MODE_PULL:
+ return "pull";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
static void
pre_activate (GstPad * pad, GstPadMode new_mode)
{
GST_OBJECT_LOCK (pad);
GST_DEBUG_OBJECT (pad, "setting PAD_MODE NONE, set flushing");
GST_PAD_SET_FLUSHING (pad);
+ pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
GST_PAD_MODE (pad) = new_mode;
/* unlock blocked pads so element can resume and stop */
GST_PAD_BLOCK_BROADCAST (pad);
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_DEBUG_OBJECT (pad, "setting pad into %s mode, unset flushing",
+ gst_pad_mode_get_name (new_mode));
GST_PAD_UNSET_FLUSHING (pad);
+ pad->ABI.abi.last_flowret = GST_FLOW_OK;
GST_PAD_MODE (pad) = new_mode;
if (GST_PAD_IS_SINK (pad)) {
GstPad *peer;
* push or pull mode, just return. Otherwise dispatches to the pad's activate
* function to perform the actual activation.
*
- * If not @active, checks the pad's current mode and calls
- * gst_pad_activate_push() or gst_pad_activate_pull(), as appropriate, with a
- * FALSE argument.
+ * If not @active, calls gst_pad_activate_mode() with the pad's current mode
+ * and a %FALSE argument.
*
- * Returns: #TRUE if the operation was successful.
+ * Returns: %TRUE if the operation was successful.
*
* MT safe.
*/
if (old == GST_PAD_MODE_NONE) {
GST_DEBUG_OBJECT (pad, "activating pad from none");
ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad, parent);
+ if (ret)
+ pad->ABI.abi.last_flowret = GST_FLOW_OK;
} else {
- GST_DEBUG_OBJECT (pad, "pad was active in mode %d", old);
+ GST_DEBUG_OBJECT (pad, "pad was active in %s mode",
+ gst_pad_mode_get_name (old));
ret = TRUE;
}
} else {
GST_DEBUG_OBJECT (pad, "pad was inactive");
ret = TRUE;
} else {
- GST_DEBUG_OBJECT (pad, "deactivating pad from mode %d", old);
+ GST_DEBUG_OBJECT (pad, "deactivating pad from %s mode",
+ gst_pad_mode_get_name (old));
ret = gst_pad_activate_mode (pad, old, FALSE);
+ if (ret)
+ pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
}
}
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 */
*
* If you don't know what this is, you probably don't want to call it.
*
- * Returns: TRUE if the operation was successful.
+ * Returns: %TRUE if the operation was successful.
*
* MT safe.
*/
if (old == new)
goto was_ok;
- if (active && old != mode) {
+ if (active && old != mode && old != GST_PAD_MODE_NONE) {
/* 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);
+ GST_DEBUG_OBJECT (pad, "deactivating pad from %s mode",
+ gst_pad_mode_get_name (old));
+
if (G_UNLIKELY (!gst_pad_activate_mode (pad, old, FALSE)))
goto deactivate_failed;
}
break;
}
+ /* Mark pad as needing reconfiguration */
+ if (active)
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
pre_activate (pad, new);
if (GST_PAD_ACTIVATEMODEFUNC (pad)) {
post_activate (pad, new);
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in mode %d",
- active ? "activated" : "deactivated", mode);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in %s mode",
+ active ? "activated" : "deactivated", gst_pad_mode_get_name (mode));
exit_success:
res = TRUE;
+
+ /* Clear sticky flags on deactivation */
+ if (!active) {
+ GST_OBJECT_LOCK (pad);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS);
+ GST_OBJECT_UNLOCK (pad);
+ }
+
exit:
RELEASE_PARENT (parent);
}
was_ok:
{
- GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in mode %d",
- active ? "activated" : "deactivated", mode);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in %s mode",
+ active ? "activated" : "deactivated", gst_pad_mode_get_name (mode));
goto exit_success;
}
deactivate_failed:
{
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
- "failed to %s in switch to mode %d from mode %d",
- (active ? "activate" : "deactivate"), mode, old);
+ "failed to %s in switch to %s mode from %s mode",
+ (active ? "activate" : "deactivate"), gst_pad_mode_get_name (mode),
+ gst_pad_mode_get_name (old));
goto exit;
}
peer_failed:
failure:
{
GST_OBJECT_LOCK (pad);
- GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in mode %d",
- active ? "activate" : "deactivate", mode);
+ GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in %s mode",
+ active ? "activate" : "deactivate", gst_pad_mode_get_name (mode));
GST_PAD_SET_FLUSHING (pad);
GST_PAD_MODE (pad) = old;
GST_OBJECT_UNLOCK (pad);
*
* Query if a pad is active
*
- * Returns: TRUE if the pad is active.
+ * Returns: %TRUE if the pad is active.
*
* MT safe.
*/
return result;
}
+static void
+cleanup_hook (GstPad * pad, GHook * hook)
+{
+ GstPadProbeType type;
+
+ if (!G_HOOK_IS_VALID (hook))
+ return;
+
+ type = (hook->flags) >> G_HOOK_FLAG_USER_SHIFT;
+
+ if (type & GST_PAD_PROBE_TYPE_BLOCKING) {
+ /* unblock when we remove the last blocking probe */
+ pad->num_blocked--;
+ GST_DEBUG_OBJECT (pad, "remove blocking probe, now %d left",
+ pad->num_blocked);
+
+ /* Might have new probes now that want to be called */
+ GST_PAD_BLOCK_BROADCAST (pad);
+
+ if (pad->num_blocked == 0) {
+ GST_DEBUG_OBJECT (pad, "last blocking probe removed, unblocking");
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_BLOCKED);
+ }
+ }
+ g_hook_destroy_link (&pad->probes, hook);
+ pad->num_probes--;
+}
+
/**
* gst_pad_add_probe:
* @pad: the #GstPad to add the probe to
* Be notified of different states of pads. The provided callback is called for
* every state that matches @mask.
*
- * Returns: an id or 0 on error. The id can be used to remove the probe with
- * gst_pad_remove_probe().
+ * Returns: an id or 0 if no probe is pending. The id can be used to remove the
+ * probe with gst_pad_remove_probe(). When using GST_PAD_PROBE_TYPE_IDLE it can
+ * happend that the probe can be run immediately and if the probe returns
+ * GST_PAD_PROBE_REMOVE this functions returns 0.
*
* MT safe.
*/
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);
+
+ /* Might have new probes now that want to be called */
+ GST_PAD_BLOCK_BROADCAST (pad);
}
/* call the callback if we need to be called for idle callbacks */
GST_OBJECT_UNLOCK (pad);
} else {
GstPadProbeInfo info = { GST_PAD_PROBE_TYPE_IDLE, res, };
+ GstPadProbeReturn ret;
+
+ /* Keep another ref, the callback could destroy the pad */
+ gst_object_ref (pad);
/* the pad is idle now, we can signal the idle callback now */
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"pad is idle, trigger idle callback");
GST_OBJECT_UNLOCK (pad);
- callback (pad, &info, user_data);
+ ret = callback (pad, &info, user_data);
+
+ GST_OBJECT_LOCK (pad);
+ switch (ret) {
+ case GST_PAD_PROBE_REMOVE:
+ /* remove the probe */
+ GST_DEBUG_OBJECT (pad, "asked to remove hook");
+ cleanup_hook (pad, hook);
+ res = 0;
+ break;
+ case GST_PAD_PROBE_DROP:
+ GST_DEBUG_OBJECT (pad, "asked to drop item");
+ break;
+ case GST_PAD_PROBE_PASS:
+ GST_DEBUG_OBJECT (pad, "asked to pass item");
+ break;
+ case GST_PAD_PROBE_OK:
+ GST_DEBUG_OBJECT (pad, "probe returned OK");
+ break;
+ default:
+ GST_DEBUG_OBJECT (pad, "probe returned %d", ret);
+ break;
+ }
+ GST_OBJECT_UNLOCK (pad);
+
+ gst_object_unref (pad);
}
} else {
GST_OBJECT_UNLOCK (pad);
return res;
}
-static void
-cleanup_hook (GstPad * pad, GHook * hook)
-{
- GstPadProbeType type;
-
- type = (hook->flags) >> G_HOOK_FLAG_USER_SHIFT;
-
- if (type & GST_PAD_PROBE_TYPE_BLOCKING) {
- /* unblock when we remove the last blocking probe */
- pad->num_blocked--;
- GST_DEBUG_OBJECT (pad, "remove blocking probe, now %d left",
- pad->num_blocked);
- if (pad->num_blocked == 0) {
- GST_DEBUG_OBJECT (pad, "last blocking probe removed, unblocking");
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_BLOCKED);
- GST_PAD_BLOCK_BROADCAST (pad);
- }
- }
- g_hook_destroy_link (&pad->probes, hook);
- pad->num_probes--;
-}
-
/**
* gst_pad_remove_probe:
* @pad: the #GstPad with the probe
* last requested state of the pad. It is not certain that the pad
* is actually blocking at this point (see gst_pad_is_blocking()).
*
- * Returns: TRUE if the pad is blocked.
+ * Returns: %TRUE if the pad is blocked.
*
* MT safe.
*/
* Checks if the pad is blocking or not. This is a guaranteed state
* of whether the pad is actually blocking on a #GstBuffer or a #GstEvent.
*
- * Returns: TRUE if the pad is blocking.
+ * Returns: %TRUE if the pad is blocking.
*
* MT safe.
- *
- * Since: 0.10.11
*/
gboolean
gst_pad_is_blocking (GstPad * pad)
}
/**
+ * gst_pad_needs_reconfigure:
+ * @pad: the #GstPad to check
+ *
+ * Check the #GST_PAD_FLAG_NEED_RECONFIGURE flag on @pad and return %TRUE
+ * if the flag was set.
+ *
+ * Returns: %TRUE is the GST_PAD_FLAG_NEED_RECONFIGURE flag is set on @pad.
+ */
+gboolean
+gst_pad_needs_reconfigure (GstPad * pad)
+{
+ gboolean reconfigure;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+
+ GST_OBJECT_LOCK (pad);
+ reconfigure = GST_PAD_NEEDS_RECONFIGURE (pad);
+ GST_DEBUG_OBJECT (pad, "peeking RECONFIGURE flag %d", reconfigure);
+ GST_OBJECT_UNLOCK (pad);
+
+ return reconfigure;
+}
+
+/**
* gst_pad_check_reconfigure:
* @pad: the #GstPad to check
*
GST_OBJECT_LOCK (pad);
reconfigure = GST_PAD_NEEDS_RECONFIGURE (pad);
- if (reconfigure)
+ if (reconfigure) {
GST_DEBUG_OBJECT (pad, "remove RECONFIGURE flag");
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_NEED_RECONFIGURE);
+ }
GST_OBJECT_UNLOCK (pad);
return reconfigure;
}
/**
+ * gst_pad_set_activate_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadActivateFunction to set.
+ *
+ * Calls gst_pad_set_activate_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_activate_function_full:
* @pad: a #GstPad.
* @activate: the #GstPadActivateFunction to set.
* @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
- * the actual activation. Only makes sense to set on sink pads.
+ * dispatch to gst_pad_activate_mode() to perform the actual activation.
+ * Only makes sense to set on sink pads.
*
* Call this function if your sink pad can start a pull-based task.
*/
}
/**
+ * gst_pad_set_activatemode_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadActivateModeFunction to set.
+ *
+ * Calls gst_pad_set_activatemode_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_activatemode_function_full:
* @pad: a #GstPad.
* @activatemode: the #GstPadActivateModeFunction to set.
}
/**
+ * gst_pad_set_chain_function:
+ * @p: a sink #GstPad.
+ * @f: the #GstPadChainFunction to set.
+ *
+ * Calls gst_pad_set_chain_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_chain_function_full:
* @pad: a sink #GstPad.
* @chain: the #GstPadChainFunction to set.
}
/**
+ * gst_pad_set_chain_list_function:
+ * @p: a sink #GstPad.
+ * @f: the #GstPadChainListFunction to set.
+ *
+ * Calls gst_pad_set_chain_list_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_chain_list_function_full:
* @pad: a sink #GstPad.
* @chainlist: the #GstPadChainListFunction to set.
* Sets the given chain list function for the pad. The chainlist function is
* called to process a #GstBufferList input buffer list. See
* #GstPadChainListFunction for more details.
- *
- * Since: 0.10.24
*/
void
gst_pad_set_chain_list_function_full (GstPad * pad,
}
/**
+ * gst_pad_set_getrange_function:
+ * @p: a source #GstPad.
+ * @f: the #GstPadGetRangeFunction to set.
+ *
+ * Calls gst_pad_set_getrange_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_getrange_function_full:
* @pad: a source #GstPad.
* @get: the #GstPadGetRangeFunction to set.
}
/**
+ * gst_pad_set_event_function:
+ * @p: a #GstPad of either direction.
+ * @f: the #GstPadEventFunction to set.
+ *
+ * Calls gst_pad_set_event_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_event_function_full:
* @pad: a #GstPad of either direction.
* @event: the #GstPadEventFunction to set.
}
/**
+ * gst_pad_set_query_function:
+ * @p: a #GstPad of either direction.
+ * @f: the #GstPadQueryFunction to set.
+ *
+ * Calls gst_pad_set_query_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
* gst_pad_set_query_function_full:
* @pad: a #GstPad of either direction.
* @query: the #GstPadQueryFunction to set.
}
/**
+ * gst_pad_set_iterate_internal_links_function:
+ * @p: a #GstPad of either direction.
+ * @f: the #GstPadIterIntLinkFunction to set.
+ *
+ * Calls gst_pad_set_iterate_internal_links_function_full() with %NULL
+ * for the user_data and notify.
+ */
+/**
* gst_pad_set_iterate_internal_links_function_full:
* @pad: a #GstPad of either direction.
* @iterintlink: the #GstPadIterIntLinkFunction to set.
* @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_full (GstPad * pad,
}
/**
+ * gst_pad_set_link_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadLinkFunction to set.
+ *
+ * Calls gst_pad_set_link_function_full() with %NULL
+ * for the user_data and notify.
+ */
+/**
* gst_pad_set_link_function_full:
* @pad: a #GstPad.
* @link: the #GstPadLinkFunction to set.
}
/**
+ * gst_pad_set_unlink_function:
+ * @p: a #GstPad.
+ * @f: the #GstPadUnlinkFunction to set.
+ *
+ * Calls gst_pad_set_unlink_function_full() with %NULL
+ * for the user_data and notify.
+ */
+/**
* gst_pad_set_unlink_function_full:
* @pad: a #GstPad.
* @unlink: the #GstPadUnlinkFunction to set.
* Unlinks the source pad from the sink pad. Will emit the #GstPad::unlinked
* signal on both pads.
*
- * Returns: TRUE if the pads were unlinked. This function returns FALSE if
+ * Returns: %TRUE if the pads were unlinked. This function returns %FALSE if
* the pads were not linked together.
*
* MT safe.
goto not_linked_together;
if (GST_PAD_UNLINKFUNC (srcpad)) {
- GST_PAD_UNLINKFUNC (srcpad) (srcpad);
+ GstObject *tmpparent;
+
+ ACQUIRE_PARENT (srcpad, tmpparent, no_src_parent);
+
+ GST_PAD_UNLINKFUNC (srcpad) (srcpad, tmpparent);
+ RELEASE_PARENT (tmpparent);
}
+no_src_parent:
if (GST_PAD_UNLINKFUNC (sinkpad)) {
- GST_PAD_UNLINKFUNC (sinkpad) (sinkpad);
+ GstObject *tmpparent;
+
+ ACQUIRE_PARENT (sinkpad, tmpparent, no_sink_parent);
+
+ GST_PAD_UNLINKFUNC (sinkpad) (sinkpad, tmpparent);
+ RELEASE_PARENT (tmpparent);
}
+no_sink_parent:
/* first clear peers */
GST_PAD_PEER (srcpad) = NULL;
*
* Checks if a @pad is linked to another pad or not.
*
- * Returns: TRUE if the pad is linked, FALSE otherwise.
+ * Returns: %TRUE if the pad is linked, %FALSE otherwise.
*
* MT safe.
*/
sinkcaps);
/* if we have caps on both pads we can check the intersection. If one
- * of the caps is NULL, we return TRUE. */
+ * of the caps is %NULL, we return %TRUE. */
if (G_UNLIKELY (srccaps == NULL || sinkcaps == NULL)) {
if (srccaps)
gst_caps_unref (srccaps);
done:
GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible",
- (compatible ? "" : "not"));
+ (compatible ? "" : "not "));
return compatible;
}
* Checks if the source pad and the sink pad are compatible so they can be
* linked.
*
- * Returns: TRUE if the pads can be linked.
+ * Returns: %TRUE if the pads can be linked.
*/
gboolean
gst_pad_can_link (GstPad * srcpad, GstPad * sinkpad)
*
* Returns: A result code indicating if the connection worked or
* what went wrong.
- *
- * Since: 0.10.30
*/
GstPadLinkReturn
gst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
GST_OBJECT_UNLOCK (srcpad);
if (srcfunc) {
+ GstObject *tmpparent;
+
+ ACQUIRE_PARENT (srcpad, tmpparent, no_parent);
/* this one will call the peer link function */
- result = srcfunc (srcpad, sinkpad);
+ result = srcfunc (srcpad, tmpparent, sinkpad);
+ RELEASE_PARENT (tmpparent);
} else if (sinkfunc) {
+ GstObject *tmpparent;
+
+ ACQUIRE_PARENT (sinkpad, tmpparent, no_parent);
/* if no source link function, we need to call the sink link
* function ourselves. */
- result = sinkfunc (sinkpad, srcpad);
+ result = sinkfunc (sinkpad, tmpparent, srcpad);
+ RELEASE_PARENT (tmpparent);
}
+ no_parent:
GST_OBJECT_LOCK (srcpad);
GST_OBJECT_LOCK (sinkpad);
}
link_failed:
{
- GST_CAT_INFO (GST_CAT_PADS, "link between %s:%s and %s:%s failed",
- GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
+ GST_CAT_INFO (GST_CAT_PADS, "link between %s:%s and %s:%s failed: %s",
+ GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad),
+ gst_pad_link_get_name (result));
GST_PAD_PEER (srcpad) = NULL;
GST_PAD_PEER (sinkpad) = NULL;
*
* Check if @pad has caps set on it with a #GST_EVENT_CAPS event.
*
- * Returns: TRUE when @pad has caps associated with it.
+ * Returns: %TRUE when @pad has caps associated with it.
*/
gboolean
gst_pad_has_current_caps (GstPad * pad)
}
/**
- * gst_pad_set_caps:
- * @pad: a #GstPad to set the capabilities of.
- * @caps: (transfer none): a #GstCaps to set.
- *
- * Sets the capabilities of this pad. The caps must be fixed. Any previous
- * caps on the pad will be unreffed. This function refs the caps so you should
- * unref if as soon as you don't need it anymore.
- * It is possible to set NULL caps, which will make the pad unnegotiated
- * again.
- *
- * Returns: TRUE if the caps could be set. FALSE if the caps were not fixed
- * or bad parameters were provided to this function.
- *
- * MT safe.
- */
-gboolean
-gst_pad_set_caps (GstPad * pad, GstCaps * caps)
-{
- GstEvent *event;
- gboolean res = TRUE;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (caps != NULL && gst_caps_is_fixed (caps), FALSE);
-
- event = gst_event_new_caps (caps);
-
- if (GST_PAD_IS_SRC (pad))
- res = gst_pad_push_event (pad, event);
- else
- res = gst_pad_send_event (pad, event);
-
- return res;
-}
-
-/**
* gst_pad_get_pad_template_caps:
* @pad: a #GstPad to get the template capabilities from.
*
* on the resulting caps.
*
* Returns: (transfer full): the allowed #GstCaps of the pad link. Unref the
- * caps when you no longer need it. This function returns NULL when @pad
+ * caps when you no longer need it. This function returns %NULL when @pad
* has no peer.
*
* MT safe.
{
GstCaps *mycaps;
GstCaps *caps;
- GstCaps *peercaps;
GstPad *peer;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
GST_OBJECT_UNLOCK (pad);
mycaps = gst_pad_query_caps (pad, NULL);
- peercaps = gst_pad_query_caps (peer, NULL);
+ caps = gst_pad_query_caps (peer, mycaps);
gst_object_unref (peer);
- caps = gst_caps_intersect (mycaps, peercaps);
- gst_caps_unref (peercaps);
gst_caps_unref (mycaps);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "allowed caps %" GST_PTR_FORMAT,
/**
* gst_pad_iterate_internal_links_default:
* @pad: the #GstPad to get the internal links of.
- * @parent: the parent of @pad or NULL
+ * @parent: (allow-none): the parent of @pad or %NULL
*
* Iterate the list of pads to which the given pad is linked to inside of
* the parent element.
*
* The caller must free this iterator after use with gst_iterator_free().
*
- * Returns: a #GstIterator of #GstPad, or NULL if @pad has no parent. Unref each
+ * Returns: a #GstIterator of #GstPad, or %NULL if @pad has no parent. Unref each
* returned pad with gst_object_unref().
- *
- * Since: 0.10.21
*/
GstIterator *
gst_pad_iterate_internal_links_default (GstPad * pad, GstObject * parent)
* Returns: (transfer full): a new #GstIterator of #GstPad or %NULL when the
* pad does not have an iterator function configured. Use
* gst_iterator_free() after usage.
- *
- * Since: 0.10.21
*/
GstIterator *
gst_pad_iterate_internal_links (GstPad * pad)
/**
* gst_pad_forward:
* @pad: a #GstPad
- * @forward: a #GstPadForwardFunction
+ * @forward: (scope call): a #GstPadForwardFunction
* @user_data: user data passed to @forward
*
* Calls @forward for all internally linked pads of @pad. This function deals with
* dynamically changing internal pads and will make sure that the @forward
* function is only called once for each pad.
*
- * When @forward returns TRUE, no further pads will be processed.
+ * When @forward returns %TRUE, no further pads will be processed.
*
- * Returns: TRUE if one of the dispatcher functions returned TRUE.
+ * Returns: %TRUE if one of the dispatcher functions returned %TRUE.
*/
gboolean
gst_pad_forward (GstPad * pad, GstPadForwardFunction forward,
/**
* gst_pad_event_default:
* @pad: a #GstPad to call the default event handler on.
- * @parent: the parent of @pad or NULL
+ * @parent: (allow-none): the parent of @pad or %NULL
* @event: (transfer full): the #GstEvent to handle.
*
* Invokes the default event handler for the given pad.
* 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.
+ * Returns: %TRUE if the event was sent successfully.
*/
gboolean
gst_pad_event_default (GstPad * pad, GstObject * parent, GstEvent * event)
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
- GST_LOG_OBJECT (pad, "default event handler");
+ GST_LOG_OBJECT (pad, "default event handler for event %" GST_PTR_FORMAT,
+ event);
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- {
- GST_DEBUG_OBJECT (pad, "pausing task because of eos");
- gst_pad_pause_task (pad);
- break;
- }
case GST_EVENT_CAPS:
forward = GST_PAD_IS_PROXY_CAPS (pad);
result = TRUE;
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_query_caps (pad, caps);
if (allowed) {
- GST_DEBUG_OBJECT (pad, "allowed caps %" GST_PTR_FORMAT, allowed);
- result = gst_caps_is_subset (caps, allowed);
+ if (GST_PAD_IS_ACCEPT_INTERSECT (pad)) {
+ GST_DEBUG_OBJECT (pad,
+ "allowed caps intersect %" GST_PTR_FORMAT ", caps %" GST_PTR_FORMAT,
+ allowed, caps);
+ result = gst_caps_can_intersect (caps, allowed);
+ } else {
+ GST_DEBUG_OBJECT (pad, "allowed caps subset %" GST_PTR_FORMAT ", caps %"
+ GST_PTR_FORMAT, allowed, caps);
+ result = gst_caps_is_subset (caps, allowed);
+ }
gst_caps_unref (allowed);
} else {
- GST_DEBUG_OBJECT (pad, "no caps allowed on the pad");
+ GST_DEBUG_OBJECT (pad, "no compatible caps allowed on the pad");
result = FALSE;
}
gst_query_set_accept_caps_result (query, result);
GstPadTemplate *templ;
gboolean fixed_caps;
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
-
- gst_query_parse_caps (query, &filter);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "query caps %" GST_PTR_FORMAT,
+ query);
/* 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;
+ goto done;
}
}
+ gst_query_parse_caps (query, &filter);
+
/* no proxy or it failed, do default handling */
fixed_caps = GST_PAD_IS_FIXED_CAPS (pad);
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, result, result);
result = gst_caps_ref (result);
}
-
gst_query_set_caps_result (query, result);
gst_caps_unref (result);
+done:
return TRUE;
}
query_forward_func (GstPad * pad, QueryData * data)
{
GST_LOG_OBJECT (pad, "query peer %p (%s) of %s:%s",
- data->query, GST_EVENT_TYPE_NAME (data->query), GST_DEBUG_PAD_NAME (pad));
+ data->query, GST_QUERY_TYPE_NAME (data->query), GST_DEBUG_PAD_NAME (pad));
data->result |= gst_pad_peer_query (pad, data->query);
/**
* gst_pad_query_default:
* @pad: a #GstPad to call the default query handler on.
- * @parent: the parent of @pad or NULL
+ * @parent: (allow-none): the parent of @pad or %NULL
* @query: (transfer none): the #GstQuery to handle.
*
* Invokes the default query handler for the given pad.
* @pad, only one will be sent the query.
* Multi-sinkpad elements should implement custom query handlers.
*
- * Returns: TRUE if the query was performed successfully.
+ * Returns: %TRUE if the query was performed successfully.
*/
gboolean
gst_pad_query_default (GstPad * pad, GstObject * parent, GstQuery * query)
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_SCHEDULING:
- forward = FALSE;
+ forward = GST_PAD_IS_PROXY_SCHEDULING (pad);
break;
case GST_QUERY_ALLOCATION:
forward = GST_PAD_IS_PROXY_ALLOCATION (pad);
flags = hook->flags >> G_HOOK_FLAG_USER_SHIFT;
type = info->type;
- /* one of the data types */
- if ((flags & GST_PAD_PROBE_TYPE_ALL_BOTH & type) == 0)
+ /* one of the data types for non-idle probes */
+ if ((type & GST_PAD_PROBE_TYPE_IDLE) == 0
+ && (flags & GST_PAD_PROBE_TYPE_ALL_BOTH & type) == 0)
goto no_match;
/* one of the scheduling types */
if ((flags & GST_PAD_PROBE_TYPE_SCHEDULING & type) == 0)
if ((type & GST_PAD_PROBE_TYPE_BLOCKING) &&
(flags & GST_PAD_PROBE_TYPE_BLOCKING & type) == 0)
goto no_match;
+ if ((type & GST_PAD_PROBE_TYPE_BLOCKING) == 0 &&
+ (flags & GST_PAD_PROBE_TYPE_BLOCKING))
+ 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)
GST_DEBUG_OBJECT (pad, "asked to pass item");
data->pass = TRUE;
break;
+ case GST_PAD_PROBE_OK:
+ GST_DEBUG_OBJECT (pad, "probe returned OK");
+ break;
default:
GST_DEBUG_OBJECT (pad, "probe returned %d", ret);
break;
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_BLOCKING);
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "We got unblocked");
+ /* if the list changed, call the new callbacks (they will not have their
+ * cookie set to data.cookie */
+ if (cookie != pad->priv->probe_list_cookie) {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "probe list changed, restarting");
+ goto again;
+ }
+
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
}
return result;
}
+static gboolean
+mark_event_not_received (GstPad * pad, PadEvent * ev, gpointer user_data)
+{
+ ev->received = FALSE;
+ return TRUE;
+}
+
/**
* gst_pad_set_offset:
* @pad: a #GstPad
void
gst_pad_set_offset (GstPad * pad, gint64 offset)
{
- PadEvent *ev;
-
g_return_if_fail (GST_IS_PAD (pad));
GST_OBJECT_LOCK (pad);
pad->offset = offset;
GST_DEBUG_OBJECT (pad, "changed offset to %" G_GINT64_FORMAT, offset);
- /* sinkpads will apply their offset the next time a segment
- * event is received. */
- if (GST_PAD_IS_SINK (pad))
- goto done;
-
- /* 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);
- }
+ /* resend all sticky events with updated offset on next buffer push */
+ events_foreach (pad, mark_event_not_received, NULL);
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
done:
GST_OBJECT_UNLOCK (pad);
* that pushing the EOS event failed
*/
gboolean was_eos;
+
+ /* If called for an event this is
+ * the event that would be pushed
+ * next. Don't forward sticky events
+ * that would come after that */
+ GstEvent *event;
} PushStickyData;
/* should be called with pad LOCK */
return TRUE;
}
- data->ret = gst_pad_push_event_unchecked (pad, gst_event_ref (event),
- GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+ /* If we're called because of an sticky event, only forward
+ * events that would come before this new event and the
+ * event itself */
+ if (data->event && GST_EVENT_IS_STICKY (data->event) &&
+ GST_EVENT_TYPE (data->event) <= GST_EVENT_SEGMENT &&
+ GST_EVENT_TYPE (data->event) < GST_EVENT_TYPE (event)) {
+ data->ret = GST_FLOW_CUSTOM_SUCCESS_1;
+ } else {
+ data->ret = gst_pad_push_event_unchecked (pad, gst_event_ref (event),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+ }
switch (data->ret) {
case GST_FLOW_OK:
GST_DEBUG_OBJECT (pad, "event %s marked received",
GST_EVENT_TYPE_NAME (event));
break;
+ case GST_FLOW_CUSTOM_SUCCESS:
+ /* we can't assume the event is received when it was dropped */
+ GST_DEBUG_OBJECT (pad, "event %s was dropped, mark pending",
+ GST_EVENT_TYPE_NAME (event));
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+ data->ret = GST_FLOW_OK;
+ break;
+ case GST_FLOW_CUSTOM_SUCCESS_1:
+ /* event was ignored and should be sent later */
+ GST_DEBUG_OBJECT (pad, "event %s was ignored, mark pending",
+ GST_EVENT_TYPE_NAME (event));
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+ data->ret = GST_FLOW_OK;
+ break;
case GST_FLOW_NOT_LINKED:
/* not linked is not a problem, we are sticky so the event will be
- * sent later */
- GST_DEBUG_OBJECT (pad, "pad was not linked");
- data->ret = GST_FLOW_OK;
- /* fallthrough */
+ * sent later but only for non-EOS events */
+ GST_DEBUG_OBJECT (pad, "pad was not linked, mark pending");
+ if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
+ data->ret = GST_FLOW_OK;
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+ break;
default:
- GST_DEBUG_OBJECT (pad, "mark pending events");
+ GST_DEBUG_OBJECT (pad, "result %s, mark pending events",
+ gst_flow_get_name (data->ret));
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
break;
}
/* check sticky events and push them when needed. should be called
* with pad LOCK */
static inline GstFlowReturn
-check_sticky (GstPad * pad)
+check_sticky (GstPad * pad, GstEvent * event)
{
- PushStickyData data = { GST_FLOW_OK, FALSE };
+ PushStickyData data = { GST_FLOW_OK, FALSE, event };
if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
* event failed.
*/
if (data.ret != GST_FLOW_OK && !data.was_eos) {
- GArray *events = pad->priv->events;
- gint i, len;
-
- len = events->len;
- for (i = 0; i < len; i++) {
- PadEvent *ev = &g_array_index (events, PadEvent, i);
-
- if (G_UNLIKELY (ev->event == NULL) || ev->received)
- continue;
-
- if (GST_EVENT_TYPE (ev->event) == GST_EVENT_EOS) {
- gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
- GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
-
- break;
- }
+ PadEvent *ev = find_event_by_type (pad, GST_EVENT_EOS, 0);
+
+ if (ev && !ev->received) {
+ data.ret = gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+ /* the event could have been dropped. Because this can only
+ * happen if the user asked for it, it's not an error */
+ if (data.ret == GST_FLOW_CUSTOM_SUCCESS)
+ data.ret = GST_FLOW_OK;
}
}
}
*
* Please also note that some queries might need a running pipeline to work.
*
- * Returns: TRUE if the query could be performed.
+ * Returns: %TRUE if the query could be performed.
*/
gboolean
gst_pad_query (GstPad * pad, GstQuery * query)
* The caller is responsible for both the allocation and deallocation of
* the query structure.
*
- * Returns: TRUE if the query could be performed. This function returns %FALSE
+ * Returns: %TRUE if the query could be performed. This function returns %FALSE
* if @pad has no peer.
- *
- * Since: 0.10.15
*/
gboolean
gst_pad_peer_query (GstPad * pad, GstQuery * query)
if (GST_PAD_IS_SRC (pad) && serialized) {
/* all serialized queries on the srcpad trigger push of
* sticky events */
- if (!check_sticky (pad) == GST_FLOW_OK)
+ if (check_sticky (pad, NULL) != GST_FLOW_OK)
goto sticky_failed;
}
}
no_peer:
{
- GST_WARNING_OBJECT (pad, "pad has no peer");
+ GST_INFO_OBJECT (pad, "pad has no peer");
GST_OBJECT_UNLOCK (pad);
return FALSE;
}
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
goto wrong_mode;
+#ifndef G_DISABLE_ASSERT
+ if (G_UNLIKELY (pad->priv->last_cookie != pad->priv->events_cookie)) {
+ if (!find_event_by_type (pad, GST_EVENT_STREAM_START, 0)) {
+ g_warning (G_STRLOC
+ ":%s:<%s:%s> Got data flow before stream-start event",
+ G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
+ }
+ if (!find_event_by_type (pad, GST_EVENT_SEGMENT, 0)) {
+ g_warning (G_STRLOC
+ ":%s:<%s:%s> Got data flow before segment event",
+ G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
+ }
+ pad->priv->last_cookie = pad->priv->events_cookie;
+ }
+#endif
+
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
PROBE_PUSH (pad, type, data, probe_stopped);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return GST_FLOW_FLUSHING;
}
+eos:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "chaining, but pad was EOS");
+ GST_OBJECT_UNLOCK (pad);
+ GST_PAD_STREAM_UNLOCK (pad);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+ return GST_FLOW_EOS;
+ }
wrong_mode:
{
g_critical ("chain on pad %s:%s but it was not in push mode",
ret = GST_FLOW_OK;
break;
default:
- GST_DEBUG_OBJECT (pad, "an error occured %s", gst_flow_get_name (ret));
+ GST_DEBUG_OBJECT (pad, "an error occurred %s", gst_flow_get_name (ret));
break;
}
return ret;
* 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
+ * preceding GST_EVENT_CAPS event), this function returns
* #GST_FLOW_NOT_NEGOTIATED.
*
* The function proceeds calling the chain function installed on @pad (see
* MT safe.
*
* Returns: a #GstFlowReturn from the pad.
- *
- * Since: 0.10.24
*/
GstFlowReturn
gst_pad_chain_list (GstPad * pad, GstBufferList * list)
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PUSH))
goto wrong_mode;
- if (G_UNLIKELY ((ret = check_sticky (pad))) != GST_FLOW_OK)
+#ifndef G_DISABLE_ASSERT
+ if (G_UNLIKELY (pad->priv->last_cookie != pad->priv->events_cookie)) {
+ if (!find_event_by_type (pad, GST_EVENT_STREAM_START, 0)) {
+ g_warning (G_STRLOC
+ ":%s:<%s:%s> Got data flow before stream-start event",
+ G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
+ }
+ if (!find_event_by_type (pad, GST_EVENT_SEGMENT, 0)) {
+ g_warning (G_STRLOC
+ ":%s:<%s:%s> Got data flow before segment event",
+ G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
+ }
+ pad->priv->last_cookie = pad->priv->events_cookie;
+ }
+#endif
+
+ if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
goto events_error;
/* do block probes */
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
+ /* recheck sticky events because the probe might have cause a relink */
+ if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
+ goto events_error;
+
/* do post-blocking probes */
PROBE_PUSH (pad, type, data, probe_stopped);
gst_object_unref (peer);
GST_OBJECT_LOCK (pad);
+ pad->ABI.abi.last_flowret = ret;
pad->priv->using--;
if (pad->priv->using == 0) {
/* pad is not active anymore, trigger idle callbacks */
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"pushing, but pad was flushing");
+ pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
GST_OBJECT_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return GST_FLOW_FLUSHING;
}
+eos:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but pad was EOS");
+ pad->ABI.abi.last_flowret = GST_FLOW_EOS;
+ GST_OBJECT_UNLOCK (pad);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+ return GST_FLOW_EOS;
+ }
wrong_mode:
{
g_critical ("pushing on pad %s:%s but it was not activated in push mode",
GST_DEBUG_PAD_NAME (pad));
+ pad->ABI.abi.last_flowret = GST_FLOW_ERROR;
GST_OBJECT_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return GST_FLOW_ERROR;
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"error pushing events, return %s", gst_flow_get_name (ret));
+ pad->ABI.abi.last_flowret = ret;
GST_OBJECT_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return ret;
probe_stopped:
{
GST_OBJECT_UNLOCK (pad);
+ pad->ABI.abi.last_flowret =
+ ret == GST_FLOW_CUSTOM_SUCCESS ? GST_FLOW_OK : ret;
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
switch (ret) {
ret = GST_FLOW_OK;
break;
default:
- GST_DEBUG_OBJECT (pad, "an error occured %s", gst_flow_get_name (ret));
+ GST_DEBUG_OBJECT (pad, "an error occurred %s", gst_flow_get_name (ret));
break;
}
return ret;
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"pushing, but it was not linked");
+ pad->ABI.abi.last_flowret = GST_FLOW_NOT_LINKED;
GST_OBJECT_UNLOCK (pad);
gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
return GST_FLOW_NOT_LINKED;
* Returns: a #GstFlowReturn from the peer pad.
*
* MT safe.
- *
- * Since: 0.10.24
*/
GstFlowReturn
gst_pad_push_list (GstPad * pad, GstBufferList * list)
if (G_UNLIKELY (GST_PAD_MODE (pad) != GST_PAD_MODE_PULL))
goto wrong_mode;
- if (G_UNLIKELY ((ret = check_sticky (pad))) != GST_FLOW_OK)
+ if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
goto events_error;
res_buf = *buffer;
PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
res_buf, offset, size, probe_stopped);
+ /* recheck sticky events because the probe might have cause a relink */
+ if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
+ goto events_error;
+
ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
RELEASE_PARENT (parent);
+ GST_OBJECT_LOCK (pad);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto get_range_failed;
/* can only fire the signal if we have a valid buffer */
- GST_OBJECT_LOCK (pad);
probed_data:
PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER,
res_buf, offset, size, probe_stopped_unref);
+ pad->ABI.abi.last_flowret = ret;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"getrange, but pad was flushing");
+ pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
return GST_FLOW_FLUSHING;
{
g_critical ("getrange on pad %s:%s but it was not activated in pull mode",
GST_DEBUG_PAD_NAME (pad));
+ pad->ABI.abi.last_flowret = GST_FLOW_ERROR;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
return GST_FLOW_ERROR;
events_error:
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "error pushing events");
+ pad->ABI.abi.last_flowret = ret;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
return ret;
no_parent:
{
GST_DEBUG_OBJECT (pad, "no parent");
+ pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
return GST_FLOW_FLUSHING;
ret = GST_FLOW_EOS;
}
}
+ pad->ABI.abi.last_flowret = ret;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
/* if we drop here, it signals EOS */
if (ret == GST_FLOW_CUSTOM_SUCCESS)
ret = GST_FLOW_EOS;
+ pad->ABI.abi.last_flowret = ret;
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
if (*buffer == NULL)
}
get_range_failed:
{
+ pad->ABI.abi.last_flowret = ret;
+ GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
GST_CAT_LEVEL_LOG (GST_CAT_SCHEDULING,
(ret >= GST_FLOW_EOS) ? GST_LEVEL_INFO : GST_LEVEL_WARNING,
* installed (see gst_pad_set_getrange_function()) this function returns
* #GST_FLOW_NOT_SUPPORTED.
*
- * If @buffer points to a variable holding NULL, a valid new #GstBuffer will be
+ * If @buffer points to a variable holding %NULL, a valid new #GstBuffer will be
* placed in @buffer when this function returns #GST_FLOW_OK. The new buffer
* must be freed with gst_buffer_unref() after usage.
*
* When this function returns any other result value than #GST_FLOW_OK, @buffer
* will be unchanged.
*
- * This is a lowlevel function. Usualy gst_pad_pull_range() is used.
+ * This is a lowlevel function. Usually gst_pad_pull_range() is used.
*
* Returns: a #GstFlowReturn from the pad.
*
* See gst_pad_get_range() for a list of return values and for the
* semantics of the arguments of this function.
*
- * If @buffer points to a variable holding NULL, a valid new #GstBuffer will be
+ * If @buffer points to a variable holding %NULL, a valid new #GstBuffer will be
* placed in @buffer when this function returns #GST_FLOW_OK. The new buffer
* must be freed with gst_buffer_unref() after usage. When this function
- * returns any other result value, @buffer will still point to NULL.
+ * returns any other result value, @buffer will still point to %NULL.
*
* When @buffer points to a variable that points to a valid #GstBuffer, the
* buffer will be filled with the result data when this function returns
GST_OBJECT_LOCK (pad);
pad->priv->using--;
+ pad->ABI.abi.last_flowret = ret;
if (pad->priv->using == 0) {
/* pad is not active anymore, trigger idle callbacks */
PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_IDLE,
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"pullrange, but pad was flushing");
+ pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
GST_OBJECT_UNLOCK (pad);
return GST_FLOW_FLUSHING;
}
{
g_critical ("pullrange on pad %s:%s but it was not activated in pull mode",
GST_DEBUG_PAD_NAME (pad));
+ pad->ABI.abi.last_flowret = GST_FLOW_ERROR;
GST_OBJECT_UNLOCK (pad);
return GST_FLOW_ERROR;
}
ret = GST_FLOW_EOS;
}
}
+ pad->ABI.abi.last_flowret = ret;
GST_OBJECT_UNLOCK (pad);
return ret;
}
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"pulling range, but it was not linked");
+ pad->ABI.abi.last_flowret = GST_FLOW_NOT_LINKED;
GST_OBJECT_UNLOCK (pad);
return GST_FLOW_NOT_LINKED;
}
pull_range_failed:
{
+ pad->ABI.abi.last_flowret = ret;
GST_OBJECT_UNLOCK (pad);
GST_CAT_LEVEL_LOG (GST_CAT_SCHEDULING,
(ret >= GST_FLOW_EOS) ? GST_LEVEL_INFO : GST_LEVEL_WARNING,
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"post probe returned %s", gst_flow_get_name (ret));
- GST_OBJECT_UNLOCK (pad);
+
/* if we drop here, it signals EOS */
if (ret == GST_FLOW_CUSTOM_SUCCESS)
ret = GST_FLOW_EOS;
+
+ pad->ABI.abi.last_flowret = ret;
+ GST_OBJECT_UNLOCK (pad);
+
if (*buffer == NULL)
gst_buffer_unref (res_buf);
return ret;
}
}
-static gboolean
-gst_pad_store_sticky_event (GstPad * pad, GstEvent * event, gboolean locked)
+/* must be called with pad object lock */
+static GstFlowReturn
+store_sticky_event (GstPad * pad, GstEvent * event)
{
guint i, len;
GstEventType type;
GArray *events;
gboolean res = FALSE;
const gchar *name = NULL;
+ gboolean insert = TRUE;
type = GST_EVENT_TYPE (event);
+
+ /* Store all sticky events except SEGMENT/EOS when we're flushing,
+ * otherwise they can be dropped and nothing would ever resend them.
+ * Only do that for activated pads though, everything else is a bug!
+ */
+ if (G_UNLIKELY (GST_PAD_MODE (pad) == GST_PAD_MODE_NONE
+ || (GST_PAD_IS_FLUSHING (pad) && (type == GST_EVENT_SEGMENT
+ || type == GST_EVENT_EOS))))
+ goto flushed;
+
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
if (type & GST_EVENT_TYPE_STICKY_MULTI)
name = gst_structure_get_name (gst_event_get_structure (event));
/* overwrite */
if ((res = gst_event_replace (&ev->event, event)))
ev->received = FALSE;
+
+ insert = FALSE;
+ break;
+ }
+
+ if (type < GST_EVENT_TYPE (ev->event) || (type != GST_EVENT_TYPE (ev->event)
+ && GST_EVENT_TYPE (ev->event) == GST_EVENT_EOS)) {
+ /* STREAM_START, CAPS and SEGMENT must be delivered in this order. By
+ * storing the sticky ordered we can check that this is respected. */
+ if (G_UNLIKELY (GST_EVENT_TYPE (ev->event) <= GST_EVENT_SEGMENT
+ || GST_EVENT_TYPE (ev->event) == GST_EVENT_EOS))
+ g_warning (G_STRLOC
+ ":%s:<%s:%s> Sticky event misordering, got '%s' before '%s'",
+ G_STRFUNC, GST_DEBUG_PAD_NAME (pad),
+ gst_event_type_get_name (GST_EVENT_TYPE (ev->event)),
+ gst_event_type_get_name (type));
break;
}
}
- if (i == len) {
+ if (insert) {
PadEvent ev;
ev.event = gst_event_ref (event);
ev.received = FALSE;
- g_array_append_val (events, ev);
+ g_array_insert_val (events, i, ev);
res = TRUE;
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
- if (locked)
- GST_OBJECT_UNLOCK (pad);
+ 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);
+ GST_OBJECT_LOCK (pad);
break;
default:
break;
}
}
- return res;
+ if (type == GST_EVENT_EOS) {
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_EOS);
+ pad->ABI.abi.last_flowret = GST_FLOW_EOS;
+ }
+
+ return GST_PAD_IS_FLUSHING (pad) ? GST_FLOW_FLUSHING : GST_FLOW_OK;
+
+ /* ERRORS */
+flushed:
+ {
+ GST_DEBUG_OBJECT (pad, "pad is flushing");
+ return GST_FLOW_FLUSHING;
+ }
+eos:
+ {
+ GST_DEBUG_OBJECT (pad, "pad is EOS");
+ return GST_FLOW_EOS;
+ }
+}
+
+/**
+ * gst_pad_store_sticky_event:
+ * @pad: a #GstPad
+ * @event: a #GstEvent
+ *
+ * Store the sticky @event on @pad
+ *
+ * Returns: #GST_FLOW_OK on success, #GST_FLOW_FLUSHING when the pad
+ * was flushing or #GST_FLOW_EOS when the pad was EOS.
+ *
+ * Since: 1.2
+ */
+GstFlowReturn
+gst_pad_store_sticky_event (GstPad * pad, GstEvent * event)
+{
+ GstFlowReturn ret;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
+
+ GST_OBJECT_LOCK (pad);
+ ret = store_sticky_event (pad, event);
+ GST_OBJECT_UNLOCK (pad);
+
+ return ret;
+}
+
+static gboolean
+sticky_changed (GstPad * pad, PadEvent * ev, gpointer user_data)
+{
+ PushStickyData *data = user_data;
+
+ /* Forward all sticky events before our current one that are pending */
+ if (ev->event != data->event
+ && GST_EVENT_TYPE (ev->event) < GST_EVENT_TYPE (data->event))
+ return push_sticky (pad, ev, data);
+
+ return TRUE;
}
/* should be called with pad LOCK */
GstPad *peerpad;
GstEventType event_type;
+ /* pass the adjusted event on. We need to do this even if
+ * there is no peer pad because of the probes. */
+ event = apply_pad_offset (pad, event, GST_PAD_IS_SINK (pad));
+
/* Two checks to be made:
* . (un)set the FLUSHING flag for flushing events,
* . handle pad blocking */
/* Remove sticky EOS events */
GST_LOG_OBJECT (pad, "Removing pending EOS events");
remove_event_by_type (pad, GST_EVENT_EOS);
+ remove_event_by_type (pad, GST_EVENT_SEGMENT);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS);
+ pad->ABI.abi.last_flowret = GST_FLOW_OK;
type |= GST_PAD_PROBE_TYPE_EVENT_FLUSH;
break;
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushed;
+ /* No need to check for EOS here as either the caller (gst_pad_push_event())
+ * checked already or this is called as part of pushing sticky events,
+ * in which case we still want to forward the EOS event downstream.
+ */
+
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEGMENT:
- /* 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_FLAG_NEED_RECONFIGURE);
/* send probes after modifying the events above */
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
+ /* recheck sticky events because the probe might have cause a relink */
+ if (GST_PAD_HAS_PENDING_EVENTS (pad) && GST_PAD_IS_SRC (pad)
+ && (GST_EVENT_IS_SERIALIZED (event)
+ || GST_EVENT_IS_STICKY (event))) {
+ PushStickyData data = { GST_FLOW_OK, FALSE, event };
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+
+ /* Push all sticky events before our current one
+ * that have changed */
+ events_foreach (pad, sticky_changed, &data);
+ }
+
/* now check the peer pad */
peerpad = GST_PAD_PEER (pad);
if (peerpad == NULL)
GST_OBJECT_UNLOCK (pad);
GST_LOG_OBJECT (pad, "sending event %p (%s) to peerpad %" GST_PTR_FORMAT,
- event, GST_EVENT_TYPE_NAME (event), peerpad);
+ event, gst_event_type_get_name (event_type), peerpad);
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 ", ret %s", event, peerpad,
- gst_flow_get_name (ret));
+ "sent event %p to (%s) peerpad %" GST_PTR_FORMAT ", ret %s", event,
+ gst_event_type_get_name (event_type), peerpad, gst_flow_get_name (ret));
gst_object_unref (peerpad);
switch (ret) {
case GST_FLOW_CUSTOM_SUCCESS:
GST_DEBUG_OBJECT (pad, "dropped event");
- ret = GST_FLOW_OK;
break;
default:
- GST_DEBUG_OBJECT (pad, "an error occured %s", gst_flow_get_name (ret));
+ GST_DEBUG_OBJECT (pad, "an error occurred %s", gst_flow_get_name (ret));
break;
}
return ret;
}
not_linked:
{
- GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked");
+ GST_DEBUG_OBJECT (pad, "Dropping event %s because pad is not linked",
+ gst_event_type_get_name (GST_EVENT_TYPE (event)));
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
gst_event_unref (event);
+
+ /* unlinked pads should not influence latency configuration */
+ if (event_type == GST_EVENT_LATENCY)
+ return GST_FLOW_OK;
+
return GST_FLOW_NOT_LINKED;
}
idle_probe_stopped:
* mainly used by elements to send events to their peer
* elements.
*
- * This function takes owership of the provided event so you should
+ * This function takes ownership 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.
+ * Returns: %TRUE if the event was handled.
*
* MT safe.
*/
gboolean
gst_pad_push_event (GstPad * pad, GstEvent * event)
{
- gboolean res = TRUE;
+ gboolean res = FALSE;
GstPadProbeType type;
gboolean sticky, serialized;
serialized = GST_EVENT_IS_SERIALIZED (event);
if (sticky) {
- /* can't store on flushing pads */
- if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
- goto flushed;
-
- /* srcpad sticky events are store immediately, the received flag is set
+ /* srcpad sticky events are stored 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));
+ switch (store_sticky_event (pad, event)) {
+ case GST_FLOW_FLUSHING:
+ goto flushed;
+ case GST_FLOW_EOS:
+ goto eos;
+ default:
+ break;
}
}
if (GST_PAD_IS_SRC (pad) && (serialized || sticky)) {
/* all serialized or sticky events on the srcpad trigger push of
* sticky events */
- res = (check_sticky (pad) == GST_FLOW_OK);
+ res = (check_sticky (pad, event) == GST_FLOW_OK);
}
+ if (!sticky) {
+ GstFlowReturn ret;
- /* If pushing sticky events did not fail and this is no sticky event
- * push it right away */
- if (res && !sticky) {
- res = (gst_pad_push_event_unchecked (pad, event, type) == GST_FLOW_OK);
+ /* other events are pushed right away */
+ ret = gst_pad_push_event_unchecked (pad, event, type);
+ /* dropped events by a probe are not an error */
+ res = (ret == GST_FLOW_OK || ret == GST_FLOW_CUSTOM_SUCCESS);
} else {
+ /* Errors in sticky event pushing are no problem and ignored here
+ * as they will cause more meaningful errors during data flow.
+ * For EOS events, that are not followed by data flow, we still
+ * return FALSE here though.
+ */
+ if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
+ res = TRUE;
gst_event_unref (event);
}
GST_OBJECT_UNLOCK (pad);
gst_event_unref (event);
return FALSE;
}
+eos:
+ {
+ GST_DEBUG_OBJECT (pad, "We're EOS");
+ GST_OBJECT_UNLOCK (pad);
+ gst_event_unref (event);
+ return FALSE;
+ }
}
/* Check if we can call the event function with the given event */
static GstFlowReturn
pre_eventfunc_check (GstPad * pad, GstEvent * event)
{
- GstCaps *caps, *templ;
+ GstCaps *caps;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
/* backwards compatibility mode for caps */
gst_event_parse_caps (event, &caps);
- /* See if pad accepts the caps */
- templ = gst_pad_get_pad_template_caps (pad);
- if (!gst_caps_is_subset (caps, templ))
+ if (!gst_pad_query_accept_caps (pad, caps))
goto not_accepted;
-
- gst_caps_unref (templ);
break;
}
default:
/* ERRORS */
not_accepted:
{
- gst_caps_unref (templ);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"caps %" GST_PTR_FORMAT " not accepted", caps);
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "no intersection with template %" GST_PTR_FORMAT, templ);
return GST_FLOW_NOT_NEGOTIATED;
}
}
GstObject *parent;
GST_OBJECT_LOCK (pad);
+
+ event = apply_pad_offset (pad, event, GST_PAD_IS_SRC (pad));
+
if (GST_PAD_IS_SINK (pad))
serialized = GST_EVENT_IS_SERIALIZED (event);
else
GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad, "cleared flush flag");
}
/* Remove pending EOS events */
- GST_LOG_OBJECT (pad, "Removing pending EOS events");
+ GST_LOG_OBJECT (pad, "Removing pending EOS and SEGMENT events");
remove_event_by_type (pad, GST_EVENT_EOS);
+ remove_event_by_type (pad, GST_EVENT_SEGMENT);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS);
+ pad->ABI.abi.last_flowret = GST_FLOW_OK;
GST_OBJECT_UNLOCK (pad);
/* grab stream lock */
goto flushing;
if (serialized) {
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
+
/* lock order: STREAM_LOCK, LOCK, recheck flushing. */
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_LOCK (pad);
GST_OBJECT_LOCK (pad);
if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
- }
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEGMENT:
- event = apply_pad_offset (pad, event);
- break;
- default:
- break;
+ if (G_UNLIKELY (GST_PAD_IS_EOS (pad)))
+ goto eos;
}
-
- /* 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;
}
+ /* 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);
+
if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
goto no_function;
if (sticky) {
if (ret == GST_FLOW_OK) {
+ GST_OBJECT_LOCK (pad);
/* after the event function accepted the event, we can store the sticky
* event on the pad */
- gst_pad_store_sticky_event (pad, event, FALSE);
+ switch (store_sticky_event (pad, event)) {
+ case GST_FLOW_FLUSHING:
+ goto flushing;
+ case GST_FLOW_EOS:
+ goto eos;
+ default:
+ break;
+ }
+ GST_OBJECT_UNLOCK (pad);
}
gst_event_unref (event);
}
gst_event_unref (event);
return GST_FLOW_FLUSHING;
}
+eos:
+ {
+ GST_OBJECT_UNLOCK (pad);
+ if (need_unlock)
+ GST_PAD_STREAM_UNLOCK (pad);
+ GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad,
+ "Received event on EOS pad. Discarding");
+ gst_event_unref (event);
+ return GST_FLOW_EOS;
+ }
probe_stopped:
{
GST_OBJECT_UNLOCK (pad);
ret = GST_FLOW_OK;
break;
default:
- GST_DEBUG_OBJECT (pad, "an error occured %s", gst_flow_get_name (ret));
+ GST_DEBUG_OBJECT (pad, "an error occurred %s", gst_flow_get_name (ret));
break;
}
return ret;
* 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
+ * This function takes ownership 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.
+ * Returns: %TRUE if the event was handled.
*/
gboolean
gst_pad_send_event (GstPad * pad, GstEvent * 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 or NULL when no
+ * Returns: (transfer full): a #GstEvent of type @event_type or %NULL when no
* event of @event_type was on @pad. Unref after usage.
*/
GstEvent *
foreach_dispatch_function (GstPad * pad, PadEvent * ev, gpointer user_data)
{
ForeachDispatch *data = user_data;
- gboolean ret;
+ gboolean ret = TRUE;
- GST_OBJECT_UNLOCK (pad);
+ if (ev->event) {
+ GST_OBJECT_UNLOCK (pad);
- ret = data->func (pad, &ev->event, data->user_data);
+ ret = data->func (pad, &ev->event, data->user_data);
- GST_OBJECT_LOCK (pad);
+ GST_OBJECT_LOCK (pad);
+ }
return ret;
}
thread, task);
}
-static GstTaskThreadCallbacks thr_callbacks = {
- pad_enter_thread,
- pad_leave_thread,
-};
-
/**
* gst_pad_start_task:
* @pad: the #GstPad to start the task of
* @func: the task function to call
- * @data: data passed to the task function
+ * @user_data: user data passed to the task function
+ * @notify: called when @user_data is no longer referenced
*
- * Starts a task that repeatedly calls @func with @data. This function
+ * Starts a task that repeatedly calls @func with @user_data. This function
* is mostly used in pad activation functions to start the dataflow.
* The #GST_PAD_STREAM_LOCK of @pad will automatically be acquired
* before @func is called.
* Returns: a %TRUE if the task could be started.
*/
gboolean
-gst_pad_start_task (GstPad * pad, GstTaskFunction func, gpointer data)
+gst_pad_start_task (GstPad * pad, GstTaskFunction func, gpointer user_data,
+ GDestroyNotify notify)
{
GstTask *task;
gboolean res;
GST_OBJECT_LOCK (pad);
task = GST_PAD_TASK (pad);
if (task == NULL) {
- task = gst_task_new (func, data);
+ task = gst_task_new (func, user_data, notify);
gst_task_set_lock (task, GST_PAD_GET_STREAM_LOCK (pad));
- gst_task_set_thread_callbacks (task, &thr_callbacks, pad, NULL);
+ gst_task_set_enter_callback (task, pad_enter_thread, pad, NULL);
+ gst_task_set_leave_callback (task, pad_leave_thread, pad, NULL);
GST_INFO_OBJECT (pad, "created task %p", task);
GST_PAD_TASK (pad) = task;
gst_object_ref (task);
* function executed by the task is finished if this function is not
* called from the task function.
*
- * Returns: a TRUE if the task could be paused or FALSE when the pad
+ * Returns: a %TRUE if the task could be paused or %FALSE when the pad
* has no task.
*/
gboolean
* Regardless of whether the pad has a task, the stream lock is acquired and
* released so as to ensure that streaming through this pad has finished.
*
- * Returns: a TRUE if the task could be stopped or FALSE on error.
+ * Returns: a %TRUE if the task could be stopped or %FALSE on error.
*/
gboolean
gst_pad_stop_task (GstPad * pad)
return FALSE;
}
}
+
+/**
+ * gst_pad_probe_info_get_event:
+ * @info: a #GstPadProbeInfo
+ *
+ * Returns: (transfer none): The #GstEvent from the probe
+ */
+
+GstEvent *
+gst_pad_probe_info_get_event (GstPadProbeInfo * info)
+{
+ g_return_val_if_fail (info->type & (GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
+ GST_PAD_PROBE_TYPE_EVENT_UPSTREAM), NULL);
+
+ return GST_PAD_PROBE_INFO_EVENT (info);
+}
+
+
+/**
+ * gst_pad_probe_info_get_query:
+ * @info: a #GstPadProbeInfo
+ *
+ * Returns: (transfer none): The #GstQuery from the probe
+ */
+
+GstQuery *
+gst_pad_probe_info_get_query (GstPadProbeInfo * info)
+{
+ g_return_val_if_fail (info->type & (GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM |
+ GST_PAD_PROBE_TYPE_QUERY_UPSTREAM), NULL);
+
+ return GST_PAD_PROBE_INFO_QUERY (info);
+}
+
+/**
+ * gst_pad_probe_info_get_buffer:
+ * @info: a #GstPadProbeInfo
+ *
+ * Returns: (transfer none): The #GstBuffer from the probe
+ */
+
+GstBuffer *
+gst_pad_probe_info_get_buffer (GstPadProbeInfo * info)
+{
+ g_return_val_if_fail (info->type & GST_PAD_PROBE_TYPE_BUFFER, NULL);
+
+ return GST_PAD_PROBE_INFO_BUFFER (info);
+}
+
+/**
+ * gst_pad_probe_info_get_bufferlist:
+ * @info: a #GstPadProbeInfo
+ *
+ * Returns: (transfer none): The #GstBufferlist from the probe
+ */
+
+GstBufferList *
+gst_pad_probe_info_get_buffer_list (GstPadProbeInfo * info)
+{
+ g_return_val_if_fail (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST, NULL);
+
+ return GST_PAD_PROBE_INFO_BUFFER_LIST (info);
+}
+
+/**
+ * gst_pad_get_last_flow_return:
+ * @pad: the #GstPad
+ *
+ * Gets the #GstFlowReturn return from the last data passed by this pad.
+ *
+ * Since: 1.4
+ */
+GstFlowReturn
+gst_pad_get_last_flow_return (GstPad * pad)
+{
+ GstFlowReturn ret;
+
+ GST_OBJECT_LOCK (pad);
+ ret = GST_PAD_LAST_FLOW_RETURN (pad);
+ GST_OBJECT_UNLOCK (pad);
+
+ return ret;
+}