*/
/**
* SECTION:gstpad
+ * @title: GstPad
* @short_description: Object contained by elements that allows links to
* other elements
* @see_also: #GstPadTemplate, #GstElement, #GstEvent, #GstQuery, #GstBuffer
#define GST_PAD_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_PAD, GstPadPrivate))
+#define _PAD_PROBE_TYPE_ALL_BOTH_AND_FLUSH (GST_PAD_PROBE_TYPE_ALL_BOTH | GST_PAD_PROBE_TYPE_EVENT_FLUSH)
+
/* 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. */
* call. Used to block any data flowing in the pad while the idle callback
* Doesn't finish its work */
gint idle_running;
+
+ /* conditional and variable used to ensure pads only get (de)activated
+ * by a single thread at a time. Protected by the object lock */
+ GCond activation_cond;
+ gboolean in_activation;
};
typedef struct
static GstFlowReturn gst_pad_push_event_unchecked (GstPad * pad,
GstEvent * event, GstPadProbeType type);
+static gboolean activate_mode_internal (GstPad * pad, GstObject * parent,
+ GstPadMode mode, gboolean active);
+
static guint gst_pad_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *pspec_caps = NULL;
pad->priv->events = g_array_sized_new (FALSE, TRUE, sizeof (PadEvent), 16);
pad->priv->events_cookie = 0;
pad->priv->last_cookie = -1;
+ g_cond_init (&pad->priv->activation_cond);
+
pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
}
{
gint64 offset;
- GST_DEBUG_OBJECT (pad, "apply pad offset %" GST_TIME_FORMAT,
- GST_TIME_ARGS (pad->offset));
+ GST_DEBUG_OBJECT (pad, "apply pad offset %" GST_STIME_FORMAT,
+ GST_STIME_ARGS (pad->offset));
if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
GstSegment segment;
GstPad *pad = GST_PAD_CAST (object);
GstPad *peer;
- GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, pad, "dispose");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, pad, "%p dispose", pad);
/* unlink the peer pad */
if ((peer = gst_pad_get_peer (pad))) {
g_rec_mutex_clear (&pad->stream_rec_lock);
g_cond_clear (&pad->block_cond);
+ g_cond_clear (&pad->priv->activation_cond);
g_array_free (pad->priv->events, TRUE);
G_OBJECT_CLASS (parent_class)->finalize (object);
static gboolean
gst_pad_activate_default (GstPad * pad, GstObject * parent)
{
- return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+
+ return activate_mode_internal (pad, parent, GST_PAD_MODE_PUSH, TRUE);
}
/**
return "unknown";
}
-static void
+/* Returns TRUE if pad wasn't already in the new_mode */
+static gboolean
pre_activate (GstPad * pad, GstPadMode new_mode)
{
switch (new_mode) {
case GST_PAD_MODE_NONE:
GST_OBJECT_LOCK (pad);
+ while (G_UNLIKELY (pad->priv->in_activation))
+ g_cond_wait (&pad->priv->activation_cond, GST_OBJECT_GET_LOCK (pad));
+ if (new_mode == GST_PAD_MODE (pad)) {
+ GST_WARNING_OBJECT (pad,
+ "Pad is already in the process of being deactivated");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
+ pad->priv->in_activation = TRUE;
GST_DEBUG_OBJECT (pad, "setting PAD_MODE NONE, set flushing");
GST_PAD_SET_FLUSHING (pad);
pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
case GST_PAD_MODE_PUSH:
case GST_PAD_MODE_PULL:
GST_OBJECT_LOCK (pad);
+ while (G_UNLIKELY (pad->priv->in_activation))
+ g_cond_wait (&pad->priv->activation_cond, GST_OBJECT_GET_LOCK (pad));
+ if (new_mode == GST_PAD_MODE (pad)) {
+ GST_WARNING_OBJECT (pad,
+ "Pad is already in the process of being activated");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
+ pad->priv->in_activation = TRUE;
GST_DEBUG_OBJECT (pad, "setting pad into %s mode, unset flushing",
gst_pad_mode_get_name (new_mode));
GST_PAD_UNSET_FLUSHING (pad);
}
break;
}
+ return TRUE;
}
static void
{
switch (new_mode) {
case GST_PAD_MODE_NONE:
+ GST_OBJECT_LOCK (pad);
+ pad->priv->in_activation = FALSE;
+ g_cond_broadcast (&pad->priv->activation_cond);
+ GST_OBJECT_UNLOCK (pad);
+
/* ensures that streaming stops */
GST_PAD_STREAM_LOCK (pad);
GST_DEBUG_OBJECT (pad, "stopped streaming");
break;
case GST_PAD_MODE_PUSH:
case GST_PAD_MODE_PULL:
+ GST_OBJECT_LOCK (pad);
+ pad->priv->in_activation = FALSE;
+ g_cond_broadcast (&pad->priv->activation_cond);
+ GST_OBJECT_UNLOCK (pad);
/* NOP */
break;
}
} else {
GST_DEBUG_OBJECT (pad, "deactivating pad from %s mode",
gst_pad_mode_get_name (old));
- ret = gst_pad_activate_mode (pad, old, FALSE);
+ ret = activate_mode_internal (pad, parent, old, FALSE);
if (ret)
pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
}
}
}
-/**
- * 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 @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.
- *
- * Returns: %TRUE if the operation was successful.
- *
- * MT safe.
- */
-gboolean
-gst_pad_activate_mode (GstPad * pad, GstPadMode mode, gboolean active)
+static gboolean
+activate_mode_internal (GstPad * pad, GstObject * parent, GstPadMode mode,
+ gboolean active)
{
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_MODE (pad);
dir = GST_PAD_DIRECTION (pad);
- ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
new = active ? mode : GST_PAD_MODE_NONE;
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)))
+ if (G_UNLIKELY (!activate_mode_internal (pad, parent, old, FALSE)))
goto deactivate_failed;
+ old = GST_PAD_MODE_NONE;
}
switch (mode) {
/* 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)) {
- if (G_UNLIKELY (!GST_PAD_ACTIVATEMODEFUNC (pad) (pad, parent, mode,
- active)))
- goto failure;
- } else {
- /* can happen for sinks of passthrough elements */
- }
+ /* pre_activate returns TRUE if we weren't already in the process of
+ * switching to the 'new' mode */
+ if (pre_activate (pad, new)) {
- post_activate (pad, new);
+ 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 %s mode",
active ? "activated" : "deactivated", gst_pad_mode_get_name (mode));
}
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 %s mode",
active ? "activate" : "deactivate", gst_pad_mode_get_name (mode));
GST_PAD_SET_FLUSHING (pad);
GST_PAD_MODE (pad) = old;
+ pad->priv->in_activation = FALSE;
+ g_cond_broadcast (&pad->priv->activation_cond);
GST_OBJECT_UNLOCK (pad);
goto exit;
}
}
/**
+ * 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 @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.
+ *
+ * Returns: %TRUE if the operation was successful.
+ *
+ * MT safe.
+ */
+gboolean
+gst_pad_activate_mode (GstPad * pad, GstPadMode mode, gboolean active)
+{
+ GstObject *parent;
+ gboolean res;
+ GstPadMode old, new;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+
+ GST_OBJECT_LOCK (pad);
+
+ old = GST_PAD_MODE (pad);
+ new = active ? mode : GST_PAD_MODE_NONE;
+ if (old == new)
+ goto was_ok;
+
+ ACQUIRE_PARENT (pad, parent, no_parent);
+
+ GST_OBJECT_UNLOCK (pad);
+
+ res = activate_mode_internal (pad, parent, mode, active);
+
+ RELEASE_PARENT (parent);
+
+ return res;
+
+was_ok:
+ {
+ GST_OBJECT_UNLOCK (pad);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in %s mode",
+ active ? "activated" : "deactivated", gst_pad_mode_get_name (mode));
+ return TRUE;
+ }
+no_parent:
+ {
+ GST_WARNING_OBJECT (pad, "no parent");
+ GST_OBJECT_UNLOCK (pad);
+ return FALSE;
+ }
+}
+
+/**
* gst_pad_is_active:
* @pad: the #GstPad to query
*
/* when no contraints are given for the types, assume all types are
* acceptable */
- if ((mask & GST_PAD_PROBE_TYPE_ALL_BOTH) == 0)
+ if ((mask & _PAD_PROBE_TYPE_ALL_BOTH_AND_FLUSH) == 0)
mask |= GST_PAD_PROBE_TYPE_ALL_BOTH;
if ((mask & GST_PAD_PROBE_TYPE_SCHEDULING) == 0)
mask |= GST_PAD_PROBE_TYPE_SCHEDULING;
GST_DEBUG_FUNCPTR_NAME (event));
}
+static gboolean
+event_wrap (GstPad * pad, GstObject * object, GstEvent * event)
+{
+ GstFlowReturn ret;
+
+ ret = GST_PAD_EVENTFULLFUNC (pad) (pad, object, event);
+ if (ret == GST_FLOW_OK)
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * gst_pad_set_event_full_function:
+ * @p: a #GstPad of either direction.
+ * @f: the #GstPadEventFullFunction to set.
+ *
+ * Calls gst_pad_set_event_full_function_full() with %NULL for the user_data and
+ * notify.
+ */
+/**
+ * gst_pad_set_event_full_function_full:
+ * @pad: a #GstPad of either direction.
+ * @event: the #GstPadEventFullFunction 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.
+ *
+ * Since: 1.8
+ */
+void
+gst_pad_set_event_full_function_full (GstPad * pad,
+ GstPadEventFullFunction event, gpointer user_data, GDestroyNotify notify)
+{
+ g_return_if_fail (GST_IS_PAD (pad));
+
+ if (pad->eventnotify)
+ pad->eventnotify (pad->eventdata);
+ GST_PAD_EVENTFULLFUNC (pad) = event;
+ GST_PAD_EVENTFUNC (pad) = event_wrap;
+ pad->eventdata = user_data;
+ pad->eventnotify = notify;
+
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "eventfullfunc for set to %s",
+ GST_DEBUG_FUNCPTR_NAME (event));
+}
+
/**
* gst_pad_set_query_function:
* @p: a #GstPad of either direction.
g_return_val_if_fail (GST_PAD_IS_SINK (sinkpad),
GST_PAD_LINK_WRONG_DIRECTION);
+ GST_TRACER_PAD_LINK_PRE (srcpad, sinkpad);
+
/* Notify the parent early. See gst_pad_unlink for details. */
if (G_LIKELY ((parent = GST_ELEMENT_CAST (gst_pad_get_parent (srcpad))))) {
if (G_LIKELY (GST_IS_ELEMENT (parent))) {
GST_CAT_INFO (GST_CAT_PADS, "linked %s:%s and %s:%s, successful",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
- gst_pad_send_event (srcpad, gst_event_new_reconfigure ());
+ if (!(flags & GST_PAD_LINK_CHECK_NO_RECONFIGURE))
+ gst_pad_send_event (srcpad, gst_event_new_reconfigure ());
done:
if (G_LIKELY (parent)) {
gst_object_unref (parent);
}
+ GST_TRACER_PAD_LINK_POST (srcpad, sinkpad, result);
return result;
/* ERRORS */
GstPadLinkReturn
gst_pad_link (GstPad * srcpad, GstPad * sinkpad)
{
- GstPadLinkReturn ret;
-
- GST_TRACER_PAD_LINK_PRE (srcpad, sinkpad);
- ret = gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_DEFAULT);
- GST_TRACER_PAD_LINK_POST (srcpad, sinkpad, ret);
-
- return ret;
+ return gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_DEFAULT);
}
static void
* Gets the capabilities currently configured on @pad with the last
* #GST_EVENT_CAPS event.
*
- * Returns: the current caps of the pad with incremented ref-count.
+ * Returns: (transfer full) (nullable): the current caps of the pad with
+ * incremented ref-count or %NULL when pad has no caps. Unref after usage.
*/
GstCaps *
gst_pad_get_current_caps (GstPad * pad)
* Gets the peer of @pad. This function refs the peer pad so
* you need to unref it after use.
*
- * Returns: (transfer full): the peer #GstPad. Unref after usage.
+ * Returns: (transfer full) (nullable): the peer #GstPad. Unref after usage.
*
* MT safe.
*/
/* Query peer caps */
query = gst_query_new_caps (mycaps);
- gst_pad_peer_query (pad, query);
+ if (!gst_pad_peer_query (pad, query)) {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "Caps query failed");
+ goto end;
+ }
+
gst_query_parse_caps_result (query, &caps);
+ if (caps == NULL) {
+ g_warn_if_fail (caps != NULL);
+ goto end;
+ }
gst_caps_ref (caps);
- gst_query_unref (query);
-
- gst_caps_unref (mycaps);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "allowed caps %" GST_PTR_FORMAT,
caps);
+end:
+ gst_query_unref (query);
+ gst_caps_unref (mycaps);
+
return caps;
no_peer:
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;
+ GstCaps *caps, *allowed = NULL;
gboolean result;
GST_DEBUG_OBJECT (pad, "query accept-caps %" GST_PTR_FORMAT, query);
* a PROXY CAPS */
if (GST_PAD_IS_PROXY_CAPS (pad)) {
result = gst_pad_proxy_query_accept_caps (pad, query);
- goto done;
+ if (result)
+ allowed = gst_pad_get_pad_template_caps (pad);
+ else
+ goto done;
}
- GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, pad,
- "fallback ACCEPT_CAPS query, consider implementing a specialized version");
-
gst_query_parse_accept_caps (query, &caps);
- if (GST_PAD_IS_ACCEPT_TEMPLATE (pad))
- allowed = gst_pad_get_pad_template_caps (pad);
- else
- allowed = gst_pad_query_caps (pad, caps);
+ if (!allowed) {
+ if (GST_PAD_IS_ACCEPT_TEMPLATE (pad)) {
+ allowed = gst_pad_get_pad_template_caps (pad);
+ } else {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, pad,
+ "fallback ACCEPT_CAPS query, consider implementing a specialized version");
+ allowed = gst_pad_query_caps (pad, caps);
+ }
+ }
if (allowed) {
if (GST_PAD_IS_ACCEPT_INTERSECT (pad)) {
/* Default latency implementation */
typedef struct
{
+ guint count;
gboolean live;
GstClockTime min, max;
} LatencyFoldData;
GST_LOG_OBJECT (pad, "got latency live:%s min:%" G_GINT64_FORMAT
" max:%" G_GINT64_FORMAT, live ? "true" : "false", min, max);
- if (live) {
+ /* FIXME : Why do we only take values into account if it's live ? */
+ if (live || fold_data->count == 0) {
if (min > fold_data->min)
fold_data->min = min;
else if (max < fold_data->max)
fold_data->max = max;
- fold_data->live = TRUE;
+ fold_data->live = live;
}
+ fold_data->count += 1;
} else if (peer) {
GST_DEBUG_OBJECT (pad, "latency query failed");
g_value_set_boolean (ret, FALSE);
g_value_init (&ret, G_TYPE_BOOLEAN);
retry:
+ fold_data.count = 0;
fold_data.live = FALSE;
fold_data.min = 0;
fold_data.max = GST_CLOCK_TIME_NONE;
type = info->type;
original_data = info->data;
- /* 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)
goto no_match;
+
+ if (G_UNLIKELY (data->handled)) {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "probe previously returned HANDLED, not calling again");
+ goto no_match;
+ } else if (G_UNLIKELY (data->dropped)) {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "probe previously returned DROPPED, not calling again");
+ goto no_match;
+ }
+
+ if (type & GST_PAD_PROBE_TYPE_PUSH) {
+ /* one of the data types for non-idle probes */
+ if ((type & GST_PAD_PROBE_TYPE_IDLE) == 0
+ && (flags & _PAD_PROBE_TYPE_ALL_BOTH_AND_FLUSH & type) == 0)
+ goto no_match;
+ } else if (type & GST_PAD_PROBE_TYPE_PULL) {
+ /* one of the data types for non-idle probes */
+ if ((type & GST_PAD_PROBE_TYPE_BLOCKING) == 0
+ && (flags & _PAD_PROBE_TYPE_ALL_BOTH_AND_FLUSH & type) == 0)
+ goto no_match;
+ } else {
+ /* Type must have PULL or PUSH probe types */
+ g_assert_not_reached ();
+ }
+
/* one of the blocking types must match */
if ((type & GST_PAD_PROBE_TYPE_BLOCKING) &&
(flags & GST_PAD_PROBE_TYPE_BLOCKING & type) == 0)
goto done;
pad->offset = offset;
- GST_DEBUG_OBJECT (pad, "changed offset to %" G_GINT64_FORMAT, offset);
+ GST_DEBUG_OBJECT (pad, "changed offset to %" GST_STIME_FORMAT,
+ GST_STIME_ARGS (offset));
/* resend all sticky events with updated offset on next buffer push */
events_foreach (pad, mark_event_not_received, NULL);
} else {
data->ret = gst_pad_push_event_unchecked (pad, gst_event_ref (event),
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+ if (data->ret == GST_FLOW_CUSTOM_SUCCESS_1)
+ data->ret = GST_FLOW_OK;
}
switch (data->ret) {
GST_DEBUG_OBJECT (pad, "sent query %p (%s), result %d", query,
GST_QUERY_TYPE_NAME (query), res);
- GST_TRACER_PAD_QUERY_POST (pad, res, query);
+ GST_TRACER_PAD_QUERY_POST (pad, query, res);
if (res != TRUE)
goto query_failed;
/* do post-blocking probes */
PROBE_HANDLE (pad, type, data, probe_stopped, probe_handled);
+ /* recheck sticky events because the probe might have cause a relink */
+ if (G_UNLIKELY ((ret = check_sticky (pad, NULL))) != GST_FLOW_OK)
+ goto events_error;
+
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto not_linked;
/* Unset the EOS flag when received STREAM_START event, so pad can
* store sticky event and then push it later */
if (type == GST_EVENT_STREAM_START) {
- GST_LOG_OBJECT (pad, "Removing pending EOS events");
+ GST_LOG_OBJECT (pad, "Removing pending EOS and StreamGroupDone events");
remove_event_by_type (pad, GST_EVENT_EOS);
+ remove_event_by_type (pad, GST_EVENT_STREAM_GROUP_DONE);
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS);
}
/**
* gst_pad_store_sticky_event:
* @pad: a #GstPad
- * @event: a #GstEvent
+ * @event: (transfer none): a #GstEvent
*
* Store the sticky @event on @pad
*
/* 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_STREAM_GROUP_DONE);
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;
}
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH |
GST_PAD_PROBE_TYPE_BLOCK, 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);
+ }
break;
}
}
GstEventType event_type;
gboolean serialized, need_unlock = FALSE, sticky;
GstPadEventFunction eventfunc;
+ GstPadEventFullFunction eventfullfunc = NULL;
GstObject *parent;
GST_OBJECT_LOCK (pad);
/* Remove 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_STREAM_GROUP_DONE);
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;
/* 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_STREAM_GROUP_DONE);
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_EOS);
break;
default:
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
- if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
+ eventfullfunc = GST_PAD_EVENTFULLFUNC (pad);
+ eventfunc = GST_PAD_EVENTFUNC (pad);
+ if (G_UNLIKELY (eventfunc == NULL && eventfullfunc == NULL))
goto no_function;
ACQUIRE_PARENT (pad, parent, no_parent);
if (sticky)
gst_event_ref (event);
- if (eventfunc (pad, parent, event)) {
+ if (eventfullfunc) {
+ ret = eventfullfunc (pad, parent, event);
+ } else if (eventfunc (pad, parent, event)) {
ret = GST_FLOW_OK;
} else {
/* something went wrong */
* Gets the private data of a pad.
* No locking is performed in this function.
*
- * Returns: (transfer none): a #gpointer to the private data.
+ * Returns: (transfer none) (nullable): a #gpointer to the private data.
*/
gpointer
gst_pad_get_element_private (GstPad * pad)
if (task == NULL)
goto no_task;
res = gst_task_set_state (task, GST_TASK_PAUSED);
+ /* unblock activation waits if any */
+ pad->priv->in_activation = FALSE;
+ g_cond_broadcast (&pad->priv->activation_cond);
GST_OBJECT_UNLOCK (pad);
/* wait for task function to finish, this lock is recursive so it does nothing
}
/**
+ * gst_pad_get_task_state:
+ * @pad: the #GstPad to get task state from
+ *
+ * Get @pad task state. If no task is currently
+ * set, #GST_TASK_STOPPED is returned.
+ *
+ * Returns: The current state of @pad's task.
+ *
+ * Since: 1.12
+ */
+GstTaskState
+gst_pad_get_task_state (GstPad * pad)
+{
+ GstTask *task;
+ GstTaskState res;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), GST_TASK_STOPPED);
+
+ GST_OBJECT_LOCK (pad);
+ task = GST_PAD_TASK (pad);
+ if (task == NULL)
+ goto no_task;
+ res = gst_task_get_state (task);
+ GST_OBJECT_UNLOCK (pad);
+
+ return res;
+
+no_task:
+ {
+ GST_DEBUG_OBJECT (pad, "pad has no task");
+ GST_OBJECT_UNLOCK (pad);
+ return GST_TASK_STOPPED;
+ }
+}
+
+/**
* gst_pad_stop_task:
* @pad: the #GstPad to stop the task of
*
goto no_task;
GST_PAD_TASK (pad) = NULL;
res = gst_task_set_state (task, GST_TASK_STOPPED);
+ /* unblock activation waits if any */
+ pad->priv->in_activation = FALSE;
+ g_cond_broadcast (&pad->priv->activation_cond);
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_LOCK (pad);
* gst_pad_probe_info_get_event:
* @info: a #GstPadProbeInfo
*
- * Returns: (transfer none): The #GstEvent from the probe
+ * Returns: (transfer none) (nullable): The #GstEvent from the probe
*/
GstEvent *
* gst_pad_probe_info_get_query:
* @info: a #GstPadProbeInfo
*
- * Returns: (transfer none): The #GstQuery from the probe
+ * Returns: (transfer none) (nullable): The #GstQuery from the probe
*/
GstQuery *
* gst_pad_probe_info_get_buffer:
* @info: a #GstPadProbeInfo
*
- * Returns: (transfer none): The #GstBuffer from the probe
+ * Returns: (transfer none) (nullable): The #GstBuffer from the probe
*/
GstBuffer *
* gst_pad_probe_info_get_buffer_list:
* @info: a #GstPadProbeInfo
*
- * Returns: (transfer none): The #GstBufferlist from the probe
+ * Returns: (transfer none) (nullable): The #GstBufferList from the probe
*/
GstBufferList *