* GstElements will use gst_pad_push() and gst_pad_pull_range() to push out
* or pull in a buffer.
*
- * To send a #GstEvent on a pad, use gst_pad_send_event().
- *
- * Last reviewed on 2005-11-23 (0.9.5)
+ * To send a #GstEvent on a pad, use gst_pad_send_event() and
+ * gst_pad_push_event().
*
+ * Last reviewed on 2006-07-06 (0.10.9)
*/
#include "gst_private.h"
#include "gstpad.h"
-#include "gstghostpad.h"
#include "gstpadtemplate.h"
#include "gstenumtypes.h"
#include "gstmarshal.h"
typedef struct
{
- gint ret;
- gchar *name;
+ const gint ret;
+ const gchar *name;
GQuark quark;
} GstFlowQuarks;
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_NOT_NEGOTIATED, "not-negotiated", 0},
{GST_FLOW_ERROR, "error", 0},
{GST_FLOW_NOT_SUPPORTED, "not-supported", 0},
+ {GST_FLOW_CUSTOM_ERROR, "custom-error", 0},
{0, NULL, 0}
};
*
* Gets a string representing the given flow return.
*
- * Returns: a string with the name of the flow return.
+ * Returns: a static string with the name of the flow return.
*/
G_CONST_RETURN gchar *
gst_flow_get_name (GstFlowReturn ret)
{
gint i;
+ ret = CLAMP (ret, GST_FLOW_CUSTOM_ERROR, GST_FLOW_CUSTOM_SUCCESS);
+
for (i = 0; flow_quarks[i].name; i++) {
if (ret == flow_quarks[i].ret)
return flow_quarks[i].name;
{
gint i;
+ ret = CLAMP (ret, GST_FLOW_CUSTOM_ERROR, GST_FLOW_CUSTOM_SUCCESS);
+
for (i = 0; flow_quarks[i].name; i++) {
if (ret == flow_quarks[i].ret)
return flow_quarks[i].quark;
gst_pad_class_init (GstPadClass * klass)
{
GObjectClass *gobject_class;
-
-
GstObjectClass *gstobject_class;
- gobject_class = (GObjectClass *) klass;
- gstobject_class = (GstObjectClass *) klass;
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstobject_class = GST_OBJECT_CLASS (klass);
- parent_class = g_type_class_ref (GST_TYPE_OBJECT);
+ parent_class = g_type_class_peek_parent (klass);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pad_dispose);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pad_finalize);
NULL, gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1,
GST_TYPE_MINI_OBJECT);
- g_object_class_install_property (G_OBJECT_CLASS (klass), PAD_PROP_CAPS,
+ g_object_class_install_property (gobject_class, PAD_PROP_CAPS,
g_param_spec_boxed ("caps", "Caps", "The capabilities of the pad",
- GST_TYPE_CAPS, G_PARAM_READABLE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PAD_PROP_DIRECTION,
+ GST_TYPE_CAPS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PAD_PROP_DIRECTION,
g_param_spec_enum ("direction", "Direction", "The direction of the pad",
GST_TYPE_PAD_DIRECTION, GST_PAD_UNKNOWN,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PAD_PROP_TEMPLATE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ /* FIXME, Make G_PARAM_CONSTRUCT_ONLY when we fix ghostpads. */
+ g_object_class_install_property (gobject_class, PAD_PROP_TEMPLATE,
g_param_spec_object ("template", "Template",
"The GstPadTemplate of this pad", GST_TYPE_PAD_TEMPLATE,
- G_PARAM_READWRITE));
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#ifndef GST_DISABLE_LOADSAVE
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_pad_save_thyself);
static void
gst_pad_init (GstPad * pad)
{
- pad->direction = GST_PAD_UNKNOWN;
- pad->peer = NULL;
+ GST_PAD_DIRECTION (pad) = GST_PAD_UNKNOWN;
+ GST_PAD_PEER (pad) = NULL;
- pad->chainfunc = NULL;
+ GST_PAD_CHAINFUNC (pad) = NULL;
- pad->caps = NULL;
+ GST_PAD_LINKFUNC (pad) = NULL;
- pad->linkfunc = NULL;
- pad->getcapsfunc = NULL;
+ GST_PAD_CAPS (pad) = NULL;
+ GST_PAD_GETCAPSFUNC (pad) = NULL;
- pad->activatefunc = GST_DEBUG_FUNCPTR (gst_pad_activate_default);
- pad->eventfunc = GST_DEBUG_FUNCPTR (gst_pad_event_default);
- pad->querytypefunc = GST_DEBUG_FUNCPTR (gst_pad_get_query_types_default);
- pad->queryfunc = GST_DEBUG_FUNCPTR (gst_pad_query_default);
- pad->intlinkfunc = GST_DEBUG_FUNCPTR (gst_pad_get_internal_links_default);
+ GST_PAD_ACTIVATEFUNC (pad) = GST_DEBUG_FUNCPTR (gst_pad_activate_default);
+ GST_PAD_EVENTFUNC (pad) = GST_DEBUG_FUNCPTR (gst_pad_event_default);
+ GST_PAD_QUERYTYPEFUNC (pad) =
+ GST_DEBUG_FUNCPTR (gst_pad_get_query_types_default);
+ GST_PAD_QUERYFUNC (pad) = GST_DEBUG_FUNCPTR (gst_pad_query_default);
+ GST_PAD_INTLINKFUNC (pad) =
+ GST_DEBUG_FUNCPTR (gst_pad_get_internal_links_default);
GST_PAD_ACCEPTCAPSFUNC (pad) = GST_DEBUG_FUNCPTR (gst_pad_acceptcaps_default);
pad->do_buffer_signals = 0;
pad->do_event_signals = 0;
- GST_PAD_UNSET_FLUSHING (pad);
+ GST_PAD_SET_FLUSHING (pad);
pad->preroll_lock = g_mutex_new ();
pad->preroll_cond = g_cond_new ();
gst_pad_dispose (GObject * object)
{
GstPad *pad = GST_PAD (object);
+ GstPad *peer;
- GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "dispose %s:%s",
- GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, pad, "dispose");
- /* we don't hold a ref to the peer so we can just set the
- * peer to NULL. */
- GST_PAD_PEER (pad) = NULL;
+ /* unlink the peer pad */
+ if ((peer = gst_pad_get_peer (pad))) {
+ /* window for MT unsafeness, someone else could unlink here
+ * and then we call unlink with wrong pads. The unlink
+ * function would catch this and safely return failed. */
+ if (GST_PAD_IS_SRC (pad))
+ gst_pad_unlink (pad, peer);
+ else
+ gst_pad_unlink (peer, pad);
+
+ gst_object_unref (peer);
+ }
/* clear the caps */
gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
switch (prop_id) {
case PAD_PROP_CAPS:
+ GST_OBJECT_LOCK (object);
g_value_set_boxed (value, GST_PAD_CAPS (object));
+ GST_OBJECT_UNLOCK (object);
break;
case PAD_PROP_DIRECTION:
g_value_set_enum (value, GST_PAD_DIRECTION (object));
break;
case GST_ACTIVATE_NONE:
GST_OBJECT_LOCK (pad);
- GST_DEBUG_OBJECT (pad, "setting ACTIVATE_MODE NONE, set flushing",
- new_mode);
+ GST_DEBUG_OBJECT (pad, "setting ACTIVATE_MODE NONE, set flushing");
GST_PAD_SET_FLUSHING (pad);
+ GST_PAD_ACTIVATE_MODE (pad) = new_mode;
/* unlock blocked pads so element can resume and stop */
- GST_PAD_BLOCK_SIGNAL (pad);
+ GST_PAD_BLOCK_BROADCAST (pad);
GST_OBJECT_UNLOCK (pad);
break;
}
case GST_ACTIVATE_NONE:
/* ensures that streaming stops */
GST_PAD_STREAM_LOCK (pad);
- /* while we're at it set activation mode */
- GST_OBJECT_LOCK (pad);
- GST_DEBUG_OBJECT (pad, "setting ACTIVATE_MODE %d", new_mode);
- GST_PAD_ACTIVATE_MODE (pad) = new_mode;
- GST_OBJECT_UNLOCK (pad);
+ GST_DEBUG_OBJECT (pad, "stopped streaming");
GST_PAD_STREAM_UNLOCK (pad);
break;
}
if (active) {
switch (old) {
case GST_ACTIVATE_PUSH:
+ GST_DEBUG_OBJECT (pad, "activating pad from push");
+ ret = TRUE;
+ break;
case GST_ACTIVATE_PULL:
+ GST_DEBUG_OBJECT (pad, "activating pad from pull");
ret = TRUE;
break;
case GST_ACTIVATE_NONE:
+ GST_DEBUG_OBJECT (pad, "activating pad from none");
ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad);
break;
}
} else {
switch (old) {
case GST_ACTIVATE_PUSH:
+ GST_DEBUG_OBJECT (pad, "deactivating pad from push");
ret = gst_pad_activate_push (pad, FALSE);
break;
case GST_ACTIVATE_PULL:
+ GST_DEBUG_OBJECT (pad, "deactivating pad from pull");
ret = gst_pad_activate_pull (pad, FALSE);
break;
case GST_ACTIVATE_NONE:
+ GST_DEBUG_OBJECT (pad, "deactivating pad from none");
ret = TRUE;
break;
}
}
- if (!active && !ret) {
+ if (!ret) {
GST_OBJECT_LOCK (pad);
- g_critical ("Failed to deactivate pad %s:%s, very bad",
- GST_DEBUG_PAD_NAME (pad));
+ if (!active) {
+ g_critical ("Failed to deactivate pad %s:%s, very bad",
+ GST_DEBUG_PAD_NAME (pad));
+ } else {
+ GST_WARNING_OBJECT (pad, "Failed to activate pad");
+ }
GST_OBJECT_UNLOCK (pad);
}
*
* 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.
+ * 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.
*
* If you don't know what this is, you probably don't want to call it.
*
old = GST_PAD_ACTIVATE_MODE (pad);
GST_OBJECT_UNLOCK (pad);
- if ((active && old == GST_ACTIVATE_PULL)
- || (!active && old == GST_ACTIVATE_NONE))
- goto was_ok;
-
if (active) {
- g_return_val_if_fail (old == GST_ACTIVATE_NONE, FALSE);
+ switch (old) {
+ case GST_ACTIVATE_PULL:
+ GST_DEBUG_OBJECT (pad, "activating pad from pull, was ok");
+ goto was_ok;
+ case GST_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_ACTIVATE_NONE:
+ GST_DEBUG_OBJECT (pad, "activating pad from none");
+ break;
+ }
} else {
- g_return_val_if_fail (old == GST_ACTIVATE_PULL, FALSE);
+ switch (old) {
+ case GST_ACTIVATE_NONE:
+ GST_DEBUG_OBJECT (pad, "deactivating pad from none, was ok");
+ goto was_ok;
+ case GST_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_ACTIVATE_PULL:
+ GST_DEBUG_OBJECT (pad, "deactivating pad from pull");
+ break;
+ }
}
if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
if ((peer = gst_pad_get_peer (pad))) {
- if (!gst_pad_activate_pull (peer, active))
+ GST_DEBUG_OBJECT (pad, "calling peer");
+ if (G_UNLIKELY (!gst_pad_activate_pull (peer, active)))
goto peer_failed;
gst_object_unref (peer);
+ } else {
+ goto not_linked;
}
} else {
- if (GST_PAD_GETRANGEFUNC (pad) == NULL)
- goto failure; /* Can't activate pull on a src without a
+ if (G_UNLIKELY (GST_PAD_GETRANGEFUNC (pad) == NULL))
+ goto failure; /* Can't activate pull on a src without a
getrange function */
}
pre_activate (pad, new);
if (GST_PAD_ACTIVATEPULLFUNC (pad)) {
- if (!GST_PAD_ACTIVATEPULLFUNC (pad) (pad, active))
+ if (G_UNLIKELY (!GST_PAD_ACTIVATEPULLFUNC (pad) (pad, active)))
goto failure;
} else {
/* can happen for sinks of passthrough elements */
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in pull mode",
active ? "activated" : "deactivated");
+
return TRUE;
was_ok:
active ? "activated" : "deactivated");
return TRUE;
}
+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;
+ }
peer_failed:
{
GST_OBJECT_LOCK (peer);
gst_object_unref (peer);
return FALSE;
}
+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");
- pre_activate (pad, GST_ACTIVATE_NONE);
- post_activate (pad, GST_ACTIVATE_NONE);
+ 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 or not the pad should be active.
+ * @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 successfull.
+ * Returns: %TRUE if the operation was successful.
*
* MT safe.
*/
old = GST_PAD_ACTIVATE_MODE (pad);
GST_OBJECT_UNLOCK (pad);
- if ((active && old == GST_ACTIVATE_PUSH)
- || (!active && old == GST_ACTIVATE_NONE))
- goto was_ok;
-
if (active) {
- g_return_val_if_fail (old == GST_ACTIVATE_NONE, FALSE);
+ switch (old) {
+ case GST_ACTIVATE_PUSH:
+ GST_DEBUG_OBJECT (pad, "activating pad from push, was ok");
+ goto was_ok;
+ case GST_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_ACTIVATE_NONE:
+ GST_DEBUG_OBJECT (pad, "activating pad from none");
+ break;
+ }
} else {
- g_return_val_if_fail (old == GST_ACTIVATE_PUSH, FALSE);
+ switch (old) {
+ case GST_ACTIVATE_NONE:
+ GST_DEBUG_OBJECT (pad, "deactivating pad from none, was ok");
+ goto was_ok;
+ case GST_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_ACTIVATE_PUSH:
+ GST_DEBUG_OBJECT (pad, "deactivating pad from push");
+ break;
+ }
}
new = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
pre_activate (pad, new);
if (GST_PAD_ACTIVATEPUSHFUNC (pad)) {
- if (!GST_PAD_ACTIVATEPUSHFUNC (pad) (pad, active)) {
+ if (G_UNLIKELY (!GST_PAD_ACTIVATEPUSHFUNC (pad) (pad, active))) {
goto failure;
}
} else {
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;
+ }
failure:
{
+ GST_OBJECT_LOCK (pad);
GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in push mode",
active ? "activate" : "deactivate");
- pre_activate (pad, GST_ACTIVATE_NONE);
- post_activate (pad, GST_ACTIVATE_NONE);
+ GST_PAD_SET_FLUSHING (pad);
+ GST_PAD_ACTIVATE_MODE (pad) = old;
+ GST_OBJECT_UNLOCK (pad);
return FALSE;
}
}
* You can pass NULL as the callback to make this call block. Be careful with
* this blocking call as it might not return for reasons stated above.
*
- * Returns: TRUE if the pad could be blocked. This function can fail
- * if wrong parameters were passed or the pad was already in the
- * requested state.
+ * Returns: TRUE if the pad could be blocked. This function can fail if the
+ * wrong parameters were passed or the pad was already in the requested state.
*
* MT safe.
*/
gst_pad_set_blocked_async (GstPad * pad, gboolean blocked,
GstPadBlockCallback callback, gpointer user_data)
{
- gboolean was_blocked, was_ghost = FALSE;
+ gboolean was_blocked = FALSE;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- if (GST_IS_GHOST_PAD (pad)) {
- pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
- if (!pad) {
- return FALSE;
- }
- was_ghost = TRUE;
- }
-
GST_OBJECT_LOCK (pad);
was_blocked = GST_PAD_IS_BLOCKED (pad);
goto had_right_state;
if (blocked) {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocking pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocking pad");
GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKED);
pad->block_callback = callback;
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "blocked");
}
} else {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocking pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocking pad");
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKED);
pad->block_callback = callback;
pad->block_data = user_data;
- if (callback) {
- GST_PAD_BLOCK_SIGNAL (pad);
- } else {
- GST_PAD_BLOCK_SIGNAL (pad);
+ GST_PAD_BLOCK_BROADCAST (pad);
+ if (!callback) {
+ /* no callback, wait for the unblock to happen */
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "waiting for unblock");
GST_PAD_BLOCK_WAIT (pad);
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocked");
}
GST_OBJECT_UNLOCK (pad);
- if (was_ghost) {
- gst_object_unref (pad);
- }
-
return TRUE;
had_right_state:
{
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pad %s:%s was in right state (%d)", GST_DEBUG_PAD_NAME (pad),
- was_blocked);
+ "pad was in right state (%d)", was_blocked);
GST_OBJECT_UNLOCK (pad);
- if (was_ghost) {
- gst_object_unref (pad);
- }
return FALSE;
}
}
* a shortcut for gst_pad_set_blocked_async() with a NULL
* callback.
*
- * Returns: TRUE if the pad could be blocked. This function can fail
- * wrong parameters were passed or the pad was already in the
- * requested state.
+ * Returns: TRUE if the pad could be blocked. This function can fail if the
+ * wrong parameters were passed or the pad was already in the requested state.
*
* MT safe.
*/
*
* Checks if the pad is blocked or not. This function returns the
* last requested state of the pad. It is not certain that the pad
- * is actually blocked at this point.
+ * is actually blocking at this point (see gst_pad_is_blocking()).
*
* Returns: TRUE if the pad is blocked.
*
}
/**
+ * gst_pad_is_blocking:
+ * @pad: the #GstPad to query
+ *
+ * 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.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.11
+ */
+gboolean
+gst_pad_is_blocking (GstPad * pad)
+{
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), 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);
+ GST_OBJECT_UNLOCK (pad);
+
+ return result;
+}
+
+/**
* gst_pad_set_activate_function:
- * @pad: a sink #GstPad.
+ * @pad: a #GstPad.
* @activate: the #GstPadActivateFunction to set.
*
- * Sets the given activate function for the pad. The activate function will
- * dispatch to activate_push or activate_pull to perform the actual activation.
- * Only makes sense to set on sink pads.
+ * 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.
*
* Call this function if your sink pad can start a pull-based task.
*/
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_ACTIVATEFUNC (pad) = activate;
- GST_CAT_DEBUG (GST_CAT_PADS, "activatefunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (activate));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "activatefunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (activate));
}
/**
* gst_pad_set_activatepull_function:
- * @pad: a sink #GstPad.
+ * @pad: a #GstPad.
* @activatepull: the #GstPadActivateModeFunction to set.
*
* Sets the given activate_pull function for the pad. An activate_pull function
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_ACTIVATEPULLFUNC (pad) = activatepull;
- GST_CAT_DEBUG (GST_CAT_PADS, "activatepullfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (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 sink #GstPad.
+ * @pad: a #GstPad.
* @activatepush: the #GstPadActivateModeFunction to set.
*
* Sets the given activate_push function for the pad. An activate_push function
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_ACTIVATEPUSHFUNC (pad) = activatepush;
- GST_CAT_DEBUG (GST_CAT_PADS, "activatepushfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (activatepush));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "activatepushfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (activatepush));
}
/**
* @chain: the #GstPadChainFunction to set.
*
* Sets the given chain function for the pad. The chain function is called to
- * process a #GstBuffer input buffer.
+ * process a #GstBuffer input buffer. see #GstPadChainFunction for more details.
*/
void
gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain)
g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
GST_PAD_CHAINFUNC (pad) = chain;
- GST_CAT_DEBUG (GST_CAT_PADS, "chainfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (chain));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "chainfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (chain));
}
/**
* @pad: a source #GstPad.
* @get: the #GstPadGetRangeFunction to set.
*
- * Sets the given getrange function for the pad. The getrange function is called to
- * produce a new #GstBuffer to start the processing pipeline. Getrange functions cannot
- * return %NULL.
+ * 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_GETRANGEFUNC (pad) = get;
- GST_CAT_DEBUG (GST_CAT_PADS, "getrangefunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (get));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "getrangefunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (get));
}
/**
* @pad: a source #GstPad.
* @check: the #GstPadCheckGetRangeFunction to set.
*
- * Sets the given checkgetrange function for the pad. Implement this function on
- * a pad if you dynamically support getrange based scheduling on the pad.
+ * Sets the given checkgetrange function for the pad. Implement this function
+ * on a pad if you dynamically support getrange based scheduling on the pad.
*/
void
gst_pad_set_checkgetrange_function (GstPad * pad,
GST_PAD_CHECKGETRANGEFUNC (pad) = check;
- GST_CAT_DEBUG (GST_CAT_PADS, "checkgetrangefunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (check));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "checkgetrangefunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (check));
}
/**
* gst_pad_set_event_function:
- * @pad: a source #GstPad.
+ * @pad: a #GstPad of either direction.
* @event: the #GstPadEventFunction to set.
*
* Sets the given event handler for the pad.
GST_PAD_EVENTFUNC (pad) = event;
- GST_CAT_DEBUG (GST_CAT_PADS, "eventfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (event));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "eventfunc for set to %s",
+ GST_DEBUG_FUNCPTR_NAME (event));
}
/**
GST_PAD_QUERYFUNC (pad) = query;
- GST_CAT_DEBUG (GST_CAT_PADS, "queryfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (query));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "queryfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (query));
}
/**
GST_PAD_QUERYTYPEFUNC (pad) = type_func;
- GST_CAT_DEBUG (GST_CAT_PADS, "querytypefunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (type_func));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "querytypefunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (type_func));
}
/**
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_INTLINKFUNC (pad) = intlink;
- GST_CAT_DEBUG (GST_CAT_PADS, "internal link for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (intlink));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "internal link set to %s",
+ GST_DEBUG_FUNCPTR_NAME (intlink));
}
/**
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_LINKFUNC (pad) = link;
- GST_CAT_DEBUG (GST_CAT_PADS, "linkfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (link));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "linkfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (link));
}
/**
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_UNLINKFUNC (pad) = unlink;
- GST_CAT_DEBUG (GST_CAT_PADS, "unlinkfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (unlink));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "unlinkfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (unlink));
}
/**
* @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.
+ * 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 (GST_CAT_PADS, "getcapsfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (getcaps));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "getcapsfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (getcaps));
}
/**
*
* Sets the given acceptcaps function for the pad. The acceptcaps function
* will be called to check if the pad can accept the given caps. Setting the
- * acceptcaps function to NULL restores the default behaviour of allowing
+ * acceptcaps function to NULL restores the default behaviour of allowing
* any caps that matches the caps from gst_pad_get_caps.
*/
void
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_ACCEPTCAPSFUNC (pad) = acceptcaps;
- GST_CAT_DEBUG (GST_CAT_PADS, "acceptcapsfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (acceptcaps));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "acceptcapsfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (acceptcaps));
}
/**
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_FIXATECAPSFUNC (pad) = fixatecaps;
- GST_CAT_DEBUG (GST_CAT_PADS, "fixatecapsfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (fixatecaps));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "fixatecapsfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (fixatecaps));
}
/**
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_SETCAPSFUNC (pad) = setcaps;
- GST_CAT_DEBUG (GST_CAT_PADS, "setcapsfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (setcaps));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "setcapsfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (setcaps));
}
/**
g_return_if_fail (GST_PAD_IS_SINK (pad));
GST_PAD_BUFFERALLOCFUNC (pad) = bufalloc;
- GST_CAT_DEBUG (GST_CAT_PADS, "bufferallocfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (bufalloc));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "bufferallocfunc set to %s",
+ GST_DEBUG_FUNCPTR_NAME (bufalloc));
}
/**
* @srcpad: the source #GstPad to unlink.
* @sinkpad: the sink #GstPad to unlink.
*
- * Unlinks the source pad from the sink pad. Will emit the "unlinked" signal on
- * both pads.
+ * 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
* the pads were not linked together.
* This check is required so that we don't try to link
* pads from elements in different bins without ghostpads.
*
- * The LOCK should be helt on both pads
+ * The LOCK should be held on both pads
*/
static gboolean
gst_pad_link_check_hierarchy (GstPad * src, GstPad * sink)
{
GstObject *psrc, *psink;
- gboolean res = TRUE;
psrc = GST_OBJECT_PARENT (src);
psink = GST_OBJECT_PARENT (sink);
/* if one of the pads has no parent, we allow the link */
- if (psrc && psink) {
- /* if the parents are the same, we have a loop */
- if (psrc == psink) {
- GST_CAT_DEBUG (GST_CAT_CAPS, "pads have same parent %" GST_PTR_FORMAT,
- psrc);
- res = FALSE;
- goto done;
- }
- /* if they both have a parent, we check the grandparents */
- psrc = gst_object_get_parent (psrc);
- psink = gst_object_get_parent (psink);
-
- if (psrc != psink) {
- /* if they have grandparents but they are not the same */
- GST_CAT_DEBUG (GST_CAT_CAPS,
- "pads have different grandparents %" GST_PTR_FORMAT " and %"
- GST_PTR_FORMAT, psrc, psink);
- res = FALSE;
- }
- if (psrc)
- gst_object_unref (psrc);
- if (psink)
- gst_object_unref (psink);
+ if (G_UNLIKELY (psrc == NULL || psink == NULL))
+ goto no_parent;
+
+ /* only care about parents that are elements */
+ if (G_UNLIKELY (!GST_IS_ELEMENT (psrc) || !GST_IS_ELEMENT (psink)))
+ goto no_element_parent;
+
+ /* if the parents are the same, we have a loop */
+ if (G_UNLIKELY (psrc == psink))
+ goto same_parents;
+
+ /* if they both have a parent, we check the grandparents. We can not lock
+ * the parent because we hold on the child (pad) and the locking order is
+ * parent >> child. */
+ psrc = GST_OBJECT_PARENT (psrc);
+ psink = GST_OBJECT_PARENT (psink);
+
+ /* if they have grandparents but they are not the same */
+ if (G_UNLIKELY (psrc != psink))
+ goto wrong_grandparents;
+
+ return TRUE;
+
+ /* ERRORS */
+no_parent:
+ {
+ GST_CAT_DEBUG (GST_CAT_CAPS,
+ "one of the pads has no parent %" GST_PTR_FORMAT " and %"
+ GST_PTR_FORMAT, psrc, psink);
+ return TRUE;
+ }
+no_element_parent:
+ {
+ GST_CAT_DEBUG (GST_CAT_CAPS,
+ "one of the pads has no element parent %" GST_PTR_FORMAT " and %"
+ GST_PTR_FORMAT, psrc, psink);
+ return TRUE;
+ }
+same_parents:
+ {
+ GST_CAT_DEBUG (GST_CAT_CAPS, "pads have same parent %" GST_PTR_FORMAT,
+ psrc);
+ return FALSE;
+ }
+wrong_grandparents:
+ {
+ GST_CAT_DEBUG (GST_CAT_CAPS,
+ "pads have different grandparents %" GST_PTR_FORMAT " and %"
+ GST_PTR_FORMAT, psrc, psink);
+ return FALSE;
}
-done:
- return res;
}
/* FIXME leftover from an attempt at refactoring... */
-/* call with the two pads unlocked */
+/* call with the two pads unlocked, when this function returns GST_PAD_LINK_OK,
+ * the two pads will be locked in the srcpad, sinkpad order. */
static GstPadLinkReturn
gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad)
{
}
src_was_linked:
{
- GST_CAT_INFO (GST_CAT_PADS, "src %s:%s was already linked",
- GST_DEBUG_PAD_NAME (srcpad));
+ GST_CAT_INFO (GST_CAT_PADS, "src %s:%s was already linked to %s:%s",
+ GST_DEBUG_PAD_NAME (srcpad),
+ GST_DEBUG_PAD_NAME (GST_PAD_PEER (srcpad)));
/* we do not emit a warning in this case because unlinking cannot
* be made MT safe.*/
GST_OBJECT_UNLOCK (srcpad);
}
sink_was_linked:
{
- GST_CAT_INFO (GST_CAT_PADS, "sink %s:%s was already linked",
- GST_DEBUG_PAD_NAME (sinkpad));
+ GST_CAT_INFO (GST_CAT_PADS, "sink %s:%s was already linked to %s:%s",
+ GST_DEBUG_PAD_NAME (sinkpad),
+ GST_DEBUG_PAD_NAME (GST_PAD_PEER (sinkpad)));
/* we do not emit a warning in this case because unlinking cannot
* be made MT safe.*/
GST_OBJECT_UNLOCK (sinkpad);
gst_pad_get_caps_unlocked (GstPad * pad)
{
GstCaps *result = NULL;
+ GstPadTemplate *templ;
- GST_CAT_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)",
- GST_DEBUG_PAD_NAME (pad), pad);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
if (GST_PAD_GETCAPSFUNC (pad)) {
- GST_CAT_DEBUG (GST_CAT_CAPS, "dispatching to pad getcaps function");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+ "dispatching to pad getcaps function");
GST_OBJECT_FLAG_SET (pad, GST_PAD_IN_GETCAPS);
GST_OBJECT_UNLOCK (pad);
g_critical ("pad %s:%s returned NULL caps from getcaps function",
GST_DEBUG_PAD_NAME (pad));
} else {
- GST_CAT_DEBUG (GST_CAT_CAPS,
- "pad getcaps %s:%s returned %" GST_PTR_FORMAT,
- GST_DEBUG_PAD_NAME (pad), result);
+ 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)) {
" which are not a real subset of its template caps %"
GST_PTR_FORMAT, result, templ_caps);
g_warning
- ("pad %s:%s returned caps that are not a real subset of its template caps",
- GST_DEBUG_PAD_NAME (pad));
+ ("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;
goto done;
}
}
- if (GST_PAD_PAD_TEMPLATE (pad)) {
- GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
-
+ if ((templ = GST_PAD_PAD_TEMPLATE (pad))) {
result = GST_PAD_TEMPLATE_CAPS (templ);
- GST_CAT_DEBUG (GST_CAT_CAPS,
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result,
result);
result = gst_caps_ref (result);
goto done;
}
- if (GST_PAD_CAPS (pad)) {
- result = GST_PAD_CAPS (pad);
-
- GST_CAT_DEBUG (GST_CAT_CAPS,
+ if ((result = GST_PAD_CAPS (pad))) {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using pad caps %p %" GST_PTR_FORMAT, result, result);
result = gst_caps_ref (result);
goto done;
}
- GST_CAT_DEBUG (GST_CAT_CAPS, "pad has no caps");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad has no caps");
result = gst_caps_new_empty ();
done:
*
* 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_CAPS for that instead.
+ * gst_pad_set_caps() - use GST_PAD_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.
GST_OBJECT_LOCK (pad);
- GST_CAT_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)",
- GST_DEBUG_PAD_NAME (pad), pad);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
result = gst_pad_get_caps_unlocked (pad);
+
+ /* be sure that we have a copy */
+ if (result)
+ result = gst_caps_make_writable (result);
+
GST_OBJECT_UNLOCK (pad);
return result;
*
* Gets the capabilities of the peer connected to this pad.
*
- * Returns: the #GstCaps of the peer pad. This function returns a new caps, so use
- * gst_caps_unref to get rid of it. this function returns NULL if there is no
- * peer pad.
+ * Returns: the #GstCaps of the peer pad. This function returns a new caps, so
+ * use gst_caps_unref to get rid of it. this function returns NULL if there is
+ * no peer pad.
*/
GstCaps *
gst_pad_peer_get_caps (GstPad * pad)
GST_OBJECT_LOCK (pad);
- GST_CAT_DEBUG (GST_CAT_CAPS, "get peer caps of %s:%s (%p)",
- GST_DEBUG_PAD_NAME (pad), pad);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get peer caps");
peerpad = GST_PAD_PEER (pad);
if (G_UNLIKELY (peerpad == NULL))
} else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
GValue temp = { 0 };
+ /* list could be empty */
+ if (gst_value_list_get_size (src) <= 0)
+ return FALSE;
+
gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
+
if (!fixate_value (dest, &temp))
gst_value_init_and_copy (dest, &temp);
g_value_unset (&temp);
}
}
-/* Default accept caps implementation just checks against
+/* Default accept caps implementation just checks against
* against the allowed caps for the pad */
static gboolean
gst_pad_acceptcaps_default (GstPad * pad, GstCaps * caps)
GstCaps *allowed;
gboolean result = FALSE;
+ GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
+
allowed = gst_pad_get_caps (pad);
- if (allowed) {
- intersect = gst_caps_intersect (allowed, caps);
+ if (!allowed)
+ goto nothing_allowed;
- result = !gst_caps_is_empty (intersect);
+ GST_DEBUG_OBJECT (pad, "allowed caps %" GST_PTR_FORMAT, allowed);
- gst_caps_unref (allowed);
- gst_caps_unref (intersect);
- }
+ intersect = gst_caps_intersect (allowed, caps);
+
+ GST_DEBUG_OBJECT (pad, "intersection %" GST_PTR_FORMAT, intersect);
+
+ result = !gst_caps_is_empty (intersect);
+ if (!result)
+ GST_DEBUG_OBJECT (pad, "intersection gave empty caps");
+
+ gst_caps_unref (allowed);
+ gst_caps_unref (intersect);
return result;
+
+ /* ERRORS */
+nothing_allowed:
+ {
+ GST_DEBUG_OBJECT (pad, "no caps allowed on the pad");
+ return FALSE;
+ }
}
/**
if (caps == NULL)
return TRUE;
+ /* lock for checking the existing caps */
GST_OBJECT_LOCK (pad);
acceptfunc = GST_PAD_ACCEPTCAPSFUNC (pad);
- if (GST_PAD_CAPS (pad) != NULL)
- existing = gst_caps_ref (GST_PAD_CAPS (pad));
-
- GST_CAT_DEBUG (GST_CAT_CAPS, "pad accept caps of %s:%s (%p)",
- GST_DEBUG_PAD_NAME (pad), pad);
- GST_OBJECT_UNLOCK (pad);
-
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "accept caps of %p", caps);
/* The current caps on a pad are trivially acceptable */
- if (existing) {
+ if (G_LIKELY ((existing = GST_PAD_CAPS (pad)))) {
if (caps == existing || gst_caps_is_equal (caps, existing))
goto is_same_caps;
- gst_caps_unref (existing);
}
+ GST_OBJECT_UNLOCK (pad);
if (G_LIKELY (acceptfunc)) {
/* we can call the function */
result = acceptfunc (pad, caps);
+ GST_DEBUG_OBJECT (pad, "acceptfunc returned %d", result);
} else {
/* Only null if the element explicitly unset it */
result = gst_pad_acceptcaps_default (pad, caps);
+ GST_DEBUG_OBJECT (pad, "default acceptcaps returned %d", result);
}
return result;
is_same_caps:
- gst_caps_unref (existing);
- return TRUE;
+ {
+ GST_DEBUG_OBJECT (pad, "pad had same caps");
+ GST_OBJECT_UNLOCK (pad);
+ return TRUE;
+ }
}
/**
* gst_pad_peer_accept_caps:
- * @pad: a #GstPad to check
+ * @pad: a #GstPad to check the peer of
* @caps: a #GstCaps to check on the pad
*
- * Check if the given pad accepts the caps.
+ * Check if the peer of @pad accepts @caps. If @pad has no peer, this function
+ * returns TRUE.
*
- * Returns: TRUE if the pad can accept the caps.
+ * 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)
GST_OBJECT_LOCK (pad);
- GST_CAT_DEBUG (GST_CAT_CAPS, "peer accept caps of %s:%s (%p)",
- GST_DEBUG_PAD_NAME (pad), pad);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "peer accept caps of (%p)", pad);
peerpad = GST_PAD_PEER (pad);
if (G_UNLIKELY (peerpad == NULL))
goto no_peer;
- result = gst_pad_accept_caps (peerpad, caps);
+ gst_object_ref (peerpad);
+ /* release lock before calling external methods but keep ref to pad */
GST_OBJECT_UNLOCK (pad);
+ result = gst_pad_accept_caps (peerpad, caps);
+
+ gst_object_unref (peerpad);
+
return result;
no_peer:
g_return_val_if_fail (caps == NULL || gst_caps_is_fixed (caps), FALSE);
GST_OBJECT_LOCK (pad);
- setcaps = GST_PAD_SETCAPSFUNC (pad);
-
existing = GST_PAD_CAPS (pad);
+ if (existing == caps)
+ goto was_ok;
+
if (gst_caps_is_equal (caps, existing))
goto setting_same_caps;
+ setcaps = GST_PAD_SETCAPSFUNC (pad);
+
/* call setcaps function to configure the pad only if the
* caps is not NULL */
if (setcaps != NULL && caps) {
GST_OBJECT_LOCK (pad);
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_SETCAPS);
} else {
- GST_CAT_DEBUG (GST_CAT_CAPS, "pad %s:%s was dispatching",
- GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad was dispatching");
}
}
gst_caps_replace (&GST_PAD_CAPS (pad), caps);
- GST_CAT_DEBUG (GST_CAT_CAPS, "%s:%s caps %" GST_PTR_FORMAT,
- GST_DEBUG_PAD_NAME (pad), caps);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "caps %" GST_PTR_FORMAT, caps);
GST_OBJECT_UNLOCK (pad);
g_object_notify (G_OBJECT (pad), "caps");
return TRUE;
+was_ok:
+ {
+ GST_OBJECT_UNLOCK (pad);
+ return TRUE;
+ }
setting_same_caps:
{
gst_caps_replace (&GST_PAD_CAPS (pad), caps);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"caps %" GST_PTR_FORMAT " same as existing, updating ptr only", caps);
GST_OBJECT_UNLOCK (pad);
-
return TRUE;
}
-/* errors */
+
+ /* ERRORS */
could_not_set:
{
GST_OBJECT_LOCK (pad);
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_SETCAPS);
- GST_CAT_DEBUG (GST_CAT_CAPS,
- "pad %s:%s, caps %" GST_PTR_FORMAT " could not be set",
- GST_DEBUG_PAD_NAME (pad), caps);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+ "caps %" GST_PTR_FORMAT " could not be set", caps);
GST_OBJECT_UNLOCK (pad);
return FALSE;
static gboolean
gst_pad_configure_sink (GstPad * pad, GstCaps * caps)
{
- GstPadSetCapsFunction setcaps;
gboolean res;
- setcaps = GST_PAD_SETCAPSFUNC (pad);
-
- /* See if pad accepts the caps - only needed if
- * no setcaps function */
- if (setcaps == NULL)
- if (!gst_pad_accept_caps (pad, caps))
- goto not_accepted;
+ /* See if pad accepts the caps */
+ if (!gst_pad_accept_caps (pad, caps))
+ goto not_accepted;
/* set caps on pad if call succeeds */
res = gst_pad_set_caps (pad, caps);
not_accepted:
{
- GST_CAT_DEBUG (GST_CAT_CAPS, "caps %" GST_PTR_FORMAT " not accepted", caps);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+ "caps %" GST_PTR_FORMAT " not accepted", caps);
return FALSE;
}
}
static gboolean
gst_pad_configure_src (GstPad * pad, GstCaps * caps, gboolean dosetcaps)
{
- GstPadSetCapsFunction setcaps;
gboolean res;
- setcaps = GST_PAD_SETCAPSFUNC (pad);
-
- /* See if pad accepts the caps - only needed if
- * no setcaps function */
- if (setcaps == NULL)
- if (!gst_pad_accept_caps (pad, caps))
- goto not_accepted;
+ /* See if pad accepts the caps */
+ if (!gst_pad_accept_caps (pad, caps))
+ goto not_accepted;
if (dosetcaps)
res = gst_pad_set_caps (pad, caps);
not_accepted:
{
- GST_CAT_DEBUG (GST_CAT_CAPS, "caps %" GST_PTR_FORMAT " not accepted", caps);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+ "caps %" GST_PTR_FORMAT " not accepted", caps);
return FALSE;
}
}
*
* Gets the capabilities for @pad's template.
*
- * Returns: the #GstCaps of this pad template. If you intend to keep a reference
- * on the caps, make a copy (see gst_caps_copy ()).
+ * Returns: the #GstCaps of this pad template. If you intend to keep a
+ * reference on the caps, make a copy (see gst_caps_copy ()).
*/
const GstCaps *
gst_pad_get_pad_template_caps (GstPad * pad)
return gst_static_caps_get (&anycaps);
}
-
/**
* gst_pad_get_peer:
* @pad: a #GstPad to get the peer of.
/**
* gst_pad_get_allowed_caps:
- * @srcpad: a #GstPad, it must a a source pad.
+ * @pad: a #GstPad.
*
* Gets the capabilities of the allowed media types that can flow through
- * @srcpad and its peer. The pad must be a source pad.
- * The caller must free the resulting caps.
+ * @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
+ * on the resulting caps.
*
- * Returns: the allowed #GstCaps of the pad link. Free the caps when
- * you no longer need it. This function returns NULL when the @srcpad has no
- * peer.
+ * Returns: the allowed #GstCaps of the pad link. Unref the caps when you no
+ * longer need it. This function returns NULL when @pad has no peer.
*
* MT safe.
*/
GstCaps *
-gst_pad_get_allowed_caps (GstPad * srcpad)
+gst_pad_get_allowed_caps (GstPad * pad)
{
GstCaps *mycaps;
GstCaps *caps;
GstCaps *peercaps;
GstPad *peer;
- g_return_val_if_fail (GST_IS_PAD (srcpad), NULL);
- g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
+ g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- GST_OBJECT_LOCK (srcpad);
+ GST_OBJECT_LOCK (pad);
- peer = GST_PAD_PEER (srcpad);
+ peer = GST_PAD_PEER (pad);
if (G_UNLIKELY (peer == NULL))
goto no_peer;
- GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%s:%s: getting allowed caps",
- GST_DEBUG_PAD_NAME (srcpad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "getting allowed caps");
gst_object_ref (peer);
- GST_OBJECT_UNLOCK (srcpad);
- mycaps = gst_pad_get_caps (srcpad);
+ GST_OBJECT_UNLOCK (pad);
+ mycaps = gst_pad_get_caps (pad);
peercaps = gst_pad_get_caps (peer);
gst_object_unref (peer);
gst_caps_unref (peercaps);
gst_caps_unref (mycaps);
- GST_CAT_DEBUG (GST_CAT_CAPS, "allowed caps %" GST_PTR_FORMAT, caps);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "allowed caps %" GST_PTR_FORMAT,
+ caps);
return caps;
no_peer:
{
- GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%s:%s: no peer",
- GST_DEBUG_PAD_NAME (srcpad));
- GST_OBJECT_UNLOCK (srcpad);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "no peer");
+ GST_OBJECT_UNLOCK (pad);
return NULL;
}
* always negotiated before sinkpads so it is possible that the negotiated caps
* on the srcpad do not match the negotiated caps of the peer.
*
- * Returns: the negotiated #GstCaps of the pad link. Free the caps when
+ * Returns: the negotiated #GstCaps of the pad link. Unref the caps when
* you no longer need it. This function returns NULL when the @pad has no
* peer or is not negotiated yet.
*
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto no_peer;
- GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%s:%s: getting negotiated caps",
- GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "getting negotiated caps");
caps = GST_PAD_CAPS (pad);
if (caps)
gst_caps_ref (caps);
GST_OBJECT_UNLOCK (pad);
- GST_CAT_DEBUG (GST_CAT_CAPS, "negotiated caps %" GST_PTR_FORMAT, caps);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "negotiated caps %" GST_PTR_FORMAT,
+ caps);
return caps;
no_peer:
{
- GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%s:%s: no peer",
- GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "no peer");
GST_OBJECT_UNLOCK (pad);
return NULL;
}
}
+/* calls the buffer_alloc function on the given pad */
static GstFlowReturn
-gst_pad_alloc_buffer_full (GstPad * pad, guint64 offset, gint size,
- GstCaps * caps, GstBuffer ** buf, gboolean setcaps)
+gst_pad_buffer_alloc_unchecked (GstPad * pad, guint64 offset, gint size,
+ GstCaps * caps, GstBuffer ** buf)
{
- GstPad *peer;
GstFlowReturn ret;
GstPadBufferAllocFunction bufferallocfunc;
- gboolean caps_changed;
-
- g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
- g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
- g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
GST_OBJECT_LOCK (pad);
- while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad)))
- if ((ret = handle_pad_block (pad)) != GST_FLOW_OK)
- goto flushed;
-
- if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
- goto no_peer;
-
- gst_object_ref (peer);
- GST_OBJECT_UNLOCK (pad);
-
- if (G_LIKELY ((bufferallocfunc = peer->bufferallocfunc) == NULL))
- goto fallback;
-
- GST_OBJECT_LOCK (peer);
- /* when the peer is flushing we cannot give a buffer */
- if (G_UNLIKELY (GST_PAD_IS_FLUSHING (peer)))
+ /* when the pad is flushing we cannot give a buffer */
+ if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
goto flushing;
+ bufferallocfunc = pad->bufferallocfunc;
+
if (offset == GST_BUFFER_OFFSET_NONE) {
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
- "calling bufferallocfunc &%s (@%p) of peer pad %s:%s for size %d offset NONE",
- GST_DEBUG_FUNCPTR_NAME (bufferallocfunc),
- &bufferallocfunc, GST_DEBUG_PAD_NAME (peer), size);
+ "calling bufferallocfunc &%s (@%p) for size %d offset NONE",
+ GST_DEBUG_FUNCPTR_NAME (bufferallocfunc), bufferallocfunc, size);
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
- "calling bufferallocfunc &%s (@%p) of peer pad %s:%s for size %d offset %"
+ "calling bufferallocfunc &%s (@%p) of for size %d offset %"
G_GUINT64_FORMAT, GST_DEBUG_FUNCPTR_NAME (bufferallocfunc),
- &bufferallocfunc, GST_DEBUG_PAD_NAME (peer), size, offset);
+ bufferallocfunc, size, offset);
}
- GST_OBJECT_UNLOCK (peer);
+ GST_OBJECT_UNLOCK (pad);
- ret = bufferallocfunc (peer, offset, size, caps, buf);
+ /* G_LIKELY for now since most elements don't implement a buffer alloc
+ * function and there is no default alloc proxy function as this is usually
+ * not possible. */
+ if (G_LIKELY (bufferallocfunc == NULL))
+ goto fallback;
+
+ ret = bufferallocfunc (pad, offset, size, caps, buf);
if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto peer_error;
+ goto error;
+
+ /* no error, but NULL buffer means fallback to the default */
if (G_UNLIKELY (*buf == NULL))
goto fallback;
/* If the buffer alloc function didn't set up the caps like it should,
* do it for it */
- if (caps && (GST_BUFFER_CAPS (*buf) == NULL)) {
- GST_WARNING ("Buffer allocation function for pad % " GST_PTR_FORMAT
- " did not set up caps. Setting", peer);
-
+ if (G_UNLIKELY (caps && (GST_BUFFER_CAPS (*buf) == NULL))) {
+ GST_WARNING_OBJECT (pad,
+ "Buffer allocation function did not set caps. Setting");
gst_buffer_set_caps (*buf, caps);
}
-
-do_caps:
- gst_object_unref (peer);
-
- /* FIXME, move capnego this into a base class? */
- caps = GST_BUFFER_CAPS (*buf);
- caps_changed = caps && caps != GST_PAD_CAPS (pad);
- /* we got a new datatype on the pad, see if it can handle it */
- if (G_UNLIKELY (caps_changed)) {
- GST_DEBUG_OBJECT (pad, "caps changed to %" GST_PTR_FORMAT, caps);
- if (G_UNLIKELY (!gst_pad_configure_src (pad, caps, setcaps)))
- goto not_negotiated;
- }
return ret;
-flushed:
+flushing:
{
- GST_CAT_DEBUG (GST_CAT_PADS, "%s:%s pad block stopped by flush",
- GST_DEBUG_PAD_NAME (pad));
+ /* pad was flushing */
GST_OBJECT_UNLOCK (pad);
- return ret;
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "pad was flushing");
+ return GST_FLOW_WRONG_STATE;
}
-no_peer:
+error:
{
- /* pad has no peer */
- GST_CAT_DEBUG (GST_CAT_PADS,
- "%s:%s called bufferallocfunc but had no peer",
- GST_DEBUG_PAD_NAME (pad));
- GST_OBJECT_UNLOCK (pad);
- return GST_FLOW_NOT_LINKED;
- }
-flushing:
- {
- /* peer was flushing */
- GST_OBJECT_UNLOCK (peer);
- gst_object_unref (peer);
- GST_CAT_DEBUG (GST_CAT_PADS,
- "%s:%s called bufferallocfunc but peer was flushing",
- GST_DEBUG_PAD_NAME (pad));
- return GST_FLOW_WRONG_STATE;
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+ "alloc function returned error (%d) %s", ret, gst_flow_get_name (ret));
+ return ret;
}
- /* fallback case, allocate a buffer of our own, add pad caps. */
fallback:
{
- GST_CAT_DEBUG (GST_CAT_PADS,
- "%s:%s fallback buffer alloc", GST_DEBUG_PAD_NAME (pad));
- *buf = gst_buffer_new_and_alloc (size);
- GST_BUFFER_OFFSET (*buf) = offset;
- gst_buffer_set_caps (*buf, caps);
+ /* fallback case, allocate a buffer of our own, add pad caps. */
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "fallback buffer alloc");
+
+ if ((*buf = gst_buffer_try_new_and_alloc (size))) {
+ GST_BUFFER_OFFSET (*buf) = offset;
+ gst_buffer_set_caps (*buf, caps);
+ return GST_FLOW_OK;
+ } else {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+ "out of memory allocating %d bytes", size);
+ return GST_FLOW_ERROR;
+ }
+ }
+}
+
+/* FIXME 0.11: size should be unsigned */
+static GstFlowReturn
+gst_pad_alloc_buffer_full (GstPad * pad, guint64 offset, gint size,
+ GstCaps * caps, GstBuffer ** buf, gboolean setcaps)
+{
+ GstPad *peer;
+ GstFlowReturn ret;
+ GstCaps *newcaps;
+ gboolean caps_changed;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
+ g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
+ g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+ g_return_val_if_fail (size >= 0, GST_FLOW_ERROR);
+
+ GST_DEBUG_OBJECT (pad, "offset %" G_GUINT64_FORMAT ", size %d", offset, size);
+
+ GST_OBJECT_LOCK (pad);
+ while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad)))
+ if ((ret = handle_pad_block (pad)) != GST_FLOW_OK)
+ goto flushed;
+
+ if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
+ goto no_peer;
+
+ gst_object_ref (peer);
+ GST_OBJECT_UNLOCK (pad);
+
+ ret = gst_pad_buffer_alloc_unchecked (peer, offset, size, caps, buf);
+ gst_object_unref (peer);
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto peer_error;
+
+ /* FIXME, move capnego this into a base class? */
+ newcaps = GST_BUFFER_CAPS (*buf);
+
+ /* Lock for checking caps, pretty pointless as the _pad_push() function might
+ * change it concurrently, one of the problems with automatic caps setting in
+ * pad_alloc_and_set_caps. Worst case, if does a check too much, but only
+ * when there is heavy renegotiation going on in both directions. */
+ GST_OBJECT_LOCK (pad);
+ caps_changed = newcaps && newcaps != GST_PAD_CAPS (pad);
+ GST_OBJECT_UNLOCK (pad);
+
+ /* we got a new datatype on the pad, see if it can handle it */
+ if (G_UNLIKELY (caps_changed)) {
+ GST_DEBUG_OBJECT (pad,
+ "caps changed from %" GST_PTR_FORMAT " to %p %" GST_PTR_FORMAT,
+ GST_PAD_CAPS (pad), newcaps, newcaps);
+ if (G_UNLIKELY (!gst_pad_configure_src (pad, newcaps, setcaps)))
+ goto not_negotiated;
+ }
- ret = GST_FLOW_OK;
+ /* sanity check (only if caps are the same) */
+ if (G_LIKELY (newcaps == caps) && G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size))
+ goto wrong_size_fallback;
- goto do_caps;
+ return ret;
+
+flushed:
+ {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "pad block stopped by flush");
+ GST_OBJECT_UNLOCK (pad);
+ return ret;
+ }
+no_peer:
+ {
+ /* pad has no peer */
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+ "called bufferallocfunc but had no peer");
+ GST_OBJECT_UNLOCK (pad);
+ return GST_FLOW_NOT_LINKED;
+ }
+peer_error:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "alloc function returned error %s", gst_flow_get_name (ret));
+ return ret;
}
not_negotiated:
{
"alloc function returned unacceptable buffer");
return GST_FLOW_NOT_NEGOTIATED;
}
-peer_error:
+wrong_size_fallback:
{
- gst_object_unref (peer);
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "alloc function returned error %s", gst_flow_get_name (ret));
- return ret;
+ GST_CAT_ERROR_OBJECT (GST_CAT_PADS, pad, "buffer returned by alloc "
+ "function is too small (%u < %d), doing fallback buffer alloc",
+ GST_BUFFER_SIZE (*buf), size);
+
+ gst_buffer_unref (*buf);
+
+ if ((*buf = gst_buffer_try_new_and_alloc (size))) {
+ GST_BUFFER_OFFSET (*buf) = offset;
+ gst_buffer_set_caps (*buf, caps);
+ return GST_FLOW_OK;
+ } else {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+ "out of memory allocating %d bytes", size);
+ return GST_FLOW_ERROR;
+ }
}
}
* Allocates a new, empty buffer optimized to push to pad @pad. This
* function only works if @pad is a source pad and has a peer.
*
+ * A new, empty #GstBuffer will be put in the @buf argument.
* You need to check the caps of the buffer after performing this
* function and renegotiate to the format if needed.
*
- * A new, empty #GstBuffer will be put in the @buf argument.
- *
* Returns: a result code indicating success of the operation. Any
- * result code other than GST_FLOW_OK is an error and @buf should
+ * result code other than #GST_FLOW_OK is an error and @buf should
* not be used.
* An error can occur if the pad is not connected or when the downstream
* peer elements cannot provide an acceptable buffer.
*
* MT safe.
*/
+
+/* FIXME 0.11: size should be unsigned */
GstFlowReturn
gst_pad_alloc_buffer (GstPad * pad, guint64 offset, gint size, GstCaps * caps,
GstBuffer ** buf)
* newly allocated buffer are different from the @pad caps.
*
* Returns: a result code indicating success of the operation. Any
- * result code other than GST_FLOW_OK is an error and @buf should
+ * result code other than #GST_FLOW_OK is an error and @buf should
* not be used.
* An error can occur if the pad is not connected or when the downstream
* peer elements cannot provide an acceptable buffer.
*
* MT safe.
*/
+
+/* FIXME 0.11: size should be unsigned */
GstFlowReturn
gst_pad_alloc_buffer_and_set_caps (GstPad * pad, guint64 offset, gint size,
GstCaps * caps, GstBuffer ** buf)
parent = GST_PAD_PARENT (pad);
if (!parent)
- return NULL;
+ goto no_parent;
parent_pads = parent->pads;
GstPad *parent_pad = GST_PAD_CAST (parent_pads->data);
if (parent_pad->direction != direction) {
+ GST_DEBUG_OBJECT (pad, "adding pad %s:%s",
+ GST_DEBUG_PAD_NAME (parent_pad));
res = g_list_prepend (res, parent_pad);
}
-
parent_pads = g_list_next (parent_pads);
}
-
return res;
+
+no_parent:
+ {
+ GST_DEBUG_OBJECT (pad, "no parent");
+ return NULL;
+ }
}
/**
GList *orig, *pads;
gboolean result;
- GST_INFO_OBJECT (pad, "Sending event %p to all internally linked pads",
- event);
-
- result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
+ GST_INFO_OBJECT (pad, "Sending event %p (%s) to all internally linked pads",
+ event, GST_EVENT_TYPE_NAME (event));
orig = pads = gst_pad_get_internal_links (pad);
+ if (!pads) {
+ /* If this is a sinkpad and we don't have pads to send the event to, we
+ * return TRUE. This is so that when using the default handler on a sink
+ * element, we don't fail to push it. */
+ result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
+ } else {
+ /* we have pads, the result will be TRUE if one of the pads handled the
+ * event in the code below. */
+ result = FALSE;
+ }
+
while (pads) {
GstPad *eventpad = GST_PAD_CAST (pads->data);
GST_LOG_OBJECT (pad, "Reffing and sending event %p (%s) to %s:%s",
event, GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (eventpad));
gst_event_ref (event);
- gst_pad_push_event (eventpad, event);
+ result |= gst_pad_push_event (eventpad, event);
} else {
/* we only send the event on one pad, multi-sinkpad elements
* should implement a handler */
GST_DEBUG_OBJECT (pad, "pausing task because of eos");
gst_pad_pause_task (pad);
}
+ /* fall thru */
default:
break;
}
* @dispatch: the #GstDispatcherFunction to call.
* @data: gpointer user data passed to the dispatcher function.
*
- * Invokes the given dispatcher function on all pads that are
- * internally linked to the given pad.
+ * Invokes the given dispatcher function on each respective peer of
+ * all pads that are internally linked to the given pad.
* The GstPadDispatcherFunction should return TRUE when no further pads
* need to be processed.
*
while (int_pads) {
GstPad *int_pad = GST_PAD_CAST (int_pads->data);
- GstPad *int_peer = GST_PAD_PEER (int_pad);
+ GstPad *int_peer = gst_pad_get_peer (int_pad);
if (int_peer) {
+ GST_DEBUG_OBJECT (int_pad, "dispatching to peer %s:%s",
+ GST_DEBUG_PAD_NAME (int_peer));
res = dispatch (int_peer, data);
+ gst_object_unref (int_peer);
if (res)
break;
+ } else {
+ GST_DEBUG_OBJECT (int_pad, "no peer");
}
int_pads = g_list_next (int_pads);
}
-
g_list_free (orig);
+ GST_DEBUG_OBJECT (pad, "done, result %d", res);
return res;
}
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
- GST_DEBUG ("sending query %p to pad %s:%s", query, GST_DEBUG_PAD_NAME (pad));
+ GST_DEBUG_OBJECT (pad, "sending query %p", query);
if ((func = GST_PAD_QUERYFUNC (pad)) == NULL)
goto no_func;
no_func:
{
- GST_DEBUG ("pad had no query function");
+ GST_DEBUG_OBJECT (pad, "had no query function");
+ return FALSE;
+ }
+}
+
+/**
+ * gst_pad_peer_query:
+ * @pad: a #GstPad to invoke the peer query on.
+ * @query: the #GstQuery to perform.
+ *
+ * Performs gst_pad_query() on the peer of @pad.
+ *
+ * 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
+ * if @pad has no peer.
+ *
+ * Since: 0.10.15
+ */
+gboolean
+gst_pad_peer_query (GstPad * pad, GstQuery * query)
+{
+ GstPad *peerpad;
+ gboolean result;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
+
+ GST_OBJECT_LOCK (pad);
+
+ GST_DEBUG_OBJECT (pad, "peer query");
+
+ peerpad = GST_PAD_PEER (pad);
+ if (G_UNLIKELY (peerpad == NULL))
+ goto no_peer;
+
+ gst_object_ref (peerpad);
+ GST_OBJECT_UNLOCK (pad);
+
+ result = gst_pad_query (peerpad, query);
+
+ gst_object_unref (peerpad);
+
+ return result;
+
+ /* ERRORS */
+no_peer:
+ {
+ GST_WARNING_OBJECT (pad, "pad has no peer");
+ GST_OBJECT_UNLOCK (pad);
return FALSE;
}
}
* @pad: a #GstPad to call the default query handler on.
* @query: the #GstQuery to handle.
*
- * Invokes the default query handler for the given pad.
- * The query is sent to all pads internally linked to @pad. Note that
- * if there are many possible sink pads that are internally linked to
+ * Invokes the default query handler for the given pad.
+ * The query is sent to all pads internally linked to @pad. Note that
+ * if there are many possible sink pads that are internally linked to
* @pad, only one will be sent the query.
* Multi-sinkpad elements should implement custom query handlers.
*
while (field) {
if (!strcmp ((char *) field->name, "name")) {
name = (gchar *) xmlNodeGetContent (field);
- pad = gst_element_get_pad (GST_ELEMENT (parent), name);
+ pad = gst_element_get_static_pad (GST_ELEMENT (parent), name);
+ if (!pad)
+ pad = gst_element_get_request_pad (GST_ELEMENT (parent), name);
g_free (name);
} else if (!strcmp ((char *) field->name, "peer")) {
peer = (gchar *) xmlNodeGetContent (field);
split = g_strsplit (peer, ".", 2);
if (split[0] == NULL || split[1] == NULL) {
- GST_CAT_DEBUG (GST_CAT_XML,
- "Could not parse peer '%s' for pad %s:%s, leaving unlinked",
- peer, GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_XML, pad,
+ "Could not parse peer '%s', leaving unlinked", peer);
g_free (peer);
return;
if (target == NULL)
goto cleanup;
- targetpad = gst_element_get_pad (target, split[1]);
+ targetpad = gst_element_get_static_pad (target, split[1]);
+ if (!pad)
+ targetpad = gst_element_get_request_pad (target, split[1]);
if (targetpad == NULL)
goto cleanup;
xmlNewChild (parent, NULL, (xmlChar *) "name",
(xmlChar *) GST_PAD_NAME (pad));
+
+ if (GST_PAD_IS_SRC (pad)) {
+ xmlNewChild (parent, NULL, (xmlChar *) "direction", (xmlChar *) "source");
+ } else if (GST_PAD_IS_SINK (pad)) {
+ xmlNewChild (parent, NULL, (xmlChar *) "direction", (xmlChar *) "sink");
+ } else {
+ xmlNewChild (parent, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
+ }
+
if (GST_PAD_PEER (pad) != NULL) {
gchar *content;
#endif /* GST_DISABLE_LOADSAVE */
/*
- * should be called with pad lock held
+ * should be called with pad OBJECT_LOCK and STREAM_LOCK held.
+ * GST_PAD_IS_BLOCKED (pad) == TRUE when this function is
+ * called.
+ *
+ * This function performs the pad blocking when an event, buffer push
+ * or buffer_alloc is performed on a _SRC_ pad. It blocks the
+ * streaming thread after informing the pad has been blocked.
+ *
+ * An application can with this method wait and block any streaming
+ * thread and perform operations such as seeking or linking.
+ *
+ * Two methods are available for notifying the application of the
+ * block:
+ * - the callback method, which happens in the STREAMING thread with
+ * the STREAM_LOCK held. With this method, the most useful way of
+ * dealing with the callback is to post a message to the main thread
+ * where the pad block can then be handled outside of the streaming
+ * thread. With the last method one can perform all operations such
+ * as doing a state change, linking, unblocking, seeking etc on the
+ * pad.
+ * - the GCond signal method, which makes any thread unblock when
+ * the pad block happens.
+ *
+ * During the actual blocking state, the GST_PAD_BLOCKING flag is set.
+ * The GST_PAD_BLOCKING flag is unset when the pad was unblocked.
*
* MT safe.
*/
gpointer user_data;
GstFlowReturn ret = GST_FLOW_OK;
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "signal block taken on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "signal block taken");
+
+ /* flushing, don't bother trying to block and return WRONG_STATE
+ * right away */
+ if (GST_PAD_IS_FLUSHING (pad))
+ goto flushingnonref;
- /* need to grab extra ref for the callbacks */
+ /* we grab an extra ref for the callbacks, this is probably not
+ * needed (callback code does not have a ref and cannot unref). I
+ * think this was done to make it possible to unref the element in
+ * the callback, which is in the end totally impossible as it
+ * requires grabbing the STREAM_LOCK and OBJECT_LOCK which are
+ * all taken when calling this function. */
gst_object_ref (pad);
+ /* we either have a callback installed to notify the block or
+ * some other thread is doing a GCond wait. */
callback = pad->block_callback;
if (callback) {
+ /* there is a callback installed, call it. We release the
+ * lock so that the callback can do something usefull with the
+ * pad */
user_data = pad->block_data;
GST_OBJECT_UNLOCK (pad);
callback (pad, TRUE, user_data);
GST_OBJECT_LOCK (pad);
+
+ /* we released the lock, recheck flushing */
+ if (GST_PAD_IS_FLUSHING (pad))
+ goto flushing;
} else {
- GST_PAD_BLOCK_SIGNAL (pad);
+ /* no callback, signal the thread that is doing a GCond wait
+ * if any. */
+ GST_PAD_BLOCK_BROADCAST (pad);
}
+ /* OBJECT_LOCK could have been released when we did the callback, which
+ * then could have made the pad unblock so we need to check the blocking
+ * condition again. */
while (GST_PAD_IS_BLOCKED (pad)) {
- if (GST_PAD_IS_FLUSHING (pad))
- goto flushing;
+ /* now we block the streaming thread. It can be unlocked when we
+ * deactivate the pad (which will also set the FLUSHING flag) or
+ * when the pad is unblocked. A flushing event will also unblock
+ * 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_PAD_BLOCK_WAIT (pad);
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING);
+
+ /* see if we got unblocked by a flush or not */
if (GST_PAD_IS_FLUSHING (pad))
goto flushing;
}
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "got unblocked");
+ /* when we get here, the pad is unblocked again and we perform
+ * the needed unblock code. */
callback = pad->block_callback;
if (callback) {
+ /* we need to call the callback */
user_data = pad->block_data;
GST_OBJECT_UNLOCK (pad);
callback (pad, FALSE, user_data);
GST_OBJECT_LOCK (pad);
} else {
- GST_PAD_BLOCK_SIGNAL (pad);
+ /* we need to signal the thread waiting on the GCond */
+ GST_PAD_BLOCK_BROADCAST (pad);
}
gst_object_unref (pad);
return ret;
+flushingnonref:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pad was flushing");
+ return GST_FLOW_WRONG_STATE;
+ }
flushing:
{
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pad became flushing");
gst_object_unref (pad);
return GST_FLOW_WRONG_STATE;
}
g_value_set_boolean (&ret, TRUE);
g_value_init (&args[0], GST_TYPE_PAD);
g_value_set_object (&args[0], pad);
- g_value_init (&args[1], GST_TYPE_MINI_OBJECT); // G_TYPE_POINTER);
+ g_value_init (&args[1], GST_TYPE_MINI_OBJECT);
gst_value_set_mini_object (&args[1], obj);
if (GST_IS_EVENT (obj))
return res;
}
-/**
- * gst_pad_chain:
- * @pad: a sink #GstPad.
- * @buffer: the #GstBuffer to send.
- *
- * Chain a buffer to @pad.
- *
- * Returns: a #GstFlowReturn from the pad.
- *
- * MT safe.
+/* this is the chain function that does not perform the additional argument
+ * checking for that little extra speed.
*/
-GstFlowReturn
-gst_pad_chain (GstPad * pad, GstBuffer * buffer)
+static inline GstFlowReturn
+gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer)
{
GstCaps *caps;
gboolean caps_changed;
GstFlowReturn ret;
gboolean emit_signal;
- g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
- g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK,
- GST_FLOW_ERROR);
- g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
- g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
-
GST_PAD_STREAM_LOCK (pad);
GST_OBJECT_LOCK (pad);
/* we got a new datatype on the pad, see if it can handle it */
if (G_UNLIKELY (caps_changed)) {
- GST_DEBUG_OBJECT (pad, "caps changed to %" GST_PTR_FORMAT, caps);
+ GST_DEBUG_OBJECT (pad, "caps changed to %p %" GST_PTR_FORMAT, caps, caps);
if (G_UNLIKELY (!gst_pad_configure_sink (pad, caps)))
goto not_negotiated;
}
goto no_function;
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "calling chainfunction &%s of pad %s:%s",
- GST_DEBUG_FUNCPTR_NAME (chainfunc), GST_DEBUG_PAD_NAME (pad));
+ "calling chainfunction &%s", GST_DEBUG_FUNCPTR_NAME (chainfunc));
ret = chainfunc (pad, buffer);
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "called chainfunction &%s of pad %s:%s, returned %s",
- GST_DEBUG_FUNCPTR_NAME (chainfunc), GST_DEBUG_PAD_NAME (pad),
- gst_flow_get_name (ret));
+ "called chainfunction &%s, returned %s",
+ GST_DEBUG_FUNCPTR_NAME (chainfunc), gst_flow_get_name (ret));
GST_PAD_STREAM_UNLOCK (pad);
("push on pad %s:%s but it has no chainfunction",
GST_DEBUG_PAD_NAME (pad)));
GST_PAD_STREAM_UNLOCK (pad);
- return GST_FLOW_ERROR;
+ return GST_FLOW_NOT_SUPPORTED;
}
}
/**
+ * gst_pad_chain:
+ * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not.
+ * @buffer: the #GstBuffer to send, return GST_FLOW_ERROR if not.
+ *
+ * Chain a buffer to @pad.
+ *
+ * The function returns #GST_FLOW_WRONG_STATE if the pad was flushing.
+ *
+ * If the caps on @buffer are different from the current caps on @pad, this
+ * function will call any setcaps function (see gst_pad_set_setcaps_function())
+ * installed on @pad. If the new caps are not acceptable for @pad, this
+ * function returns #GST_FLOW_NOT_NEGOTIATED.
+ *
+ * The function proceeds calling the chain function installed on @pad (see
+ * gst_pad_set_chain_function()) and the return value of that function is
+ * returned to the caller. #GST_FLOW_NOT_SUPPORTED is returned if @pad has no
+ * chain function.
+ *
+ * In all cases, success or failure, the caller loses its reference to @buffer
+ * after calling this function.
+ *
+ * Returns: a #GstFlowReturn from the pad.
+ *
+ * MT safe.
+ */
+GstFlowReturn
+gst_pad_chain (GstPad * pad, GstBuffer * buffer)
+{
+ g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
+ g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK,
+ GST_FLOW_ERROR);
+ g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
+
+ return gst_pad_chain_unchecked (pad, buffer);
+}
+
+/**
* gst_pad_push:
- * @pad: a source #GstPad.
- * @buffer: the #GstBuffer to push.
+ * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not.
+ * @buffer: the #GstBuffer to push returns GST_FLOW_ERROR if not.
*
* Pushes a buffer to the peer of @pad.
- * buffer probes will be triggered before the buffer gets pushed.
+ *
+ * This function will call an installed pad block before triggering any
+ * installed pad probes.
+ *
+ * If the caps on @buffer are different from the currently configured caps on
+ * @pad, this function will call any installed setcaps function on @pad (see
+ * gst_pad_set_setcaps_function()). In case of failure to renegotiate the new
+ * format, this function returns #GST_FLOW_NOT_NEGOTIATED.
+ *
+ * The function proceeds calling gst_pad_chain() on the peer pad and returns
+ * the value from that function. If @pad has no peer, #GST_FLOW_NOT_LINKED will
+ * be returned.
+ *
+ * In all cases, success or failure, the caller loses its reference to @buffer
+ * after calling this function.
*
* Returns: a #GstFlowReturn from the peer pad.
*
{
GstPad *peer;
GstFlowReturn ret;
+
GstCaps *caps;
gboolean caps_changed;
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC, GST_FLOW_ERROR);
- g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
GST_OBJECT_LOCK (pad);
/* FIXME: this check can go away; pad_set_blocked could be implemented with
- * probes completely */
+ * probes completely or probes with an extended pad block. */
while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad)))
if ((ret = handle_pad_block (pad)) != GST_FLOW_OK)
goto flushed;
if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
goto not_linked;
+
+ /* take ref to peer pad before releasing the lock */
gst_object_ref (peer);
- /* Before pushing the buffer to the peer pad, ensure that caps
+ /* Before pushing the buffer to the peer pad, ensure that caps
* are set on this pad */
caps = GST_BUFFER_CAPS (buffer);
caps_changed = caps && caps != GST_PAD_CAPS (pad);
/* we got a new datatype from the pad, it had better handle it */
if (G_UNLIKELY (caps_changed)) {
- GST_DEBUG_OBJECT (pad, "caps changed to %" GST_PTR_FORMAT, caps);
+ GST_DEBUG_OBJECT (pad,
+ "caps changed from %" GST_PTR_FORMAT " to %p %" GST_PTR_FORMAT,
+ GST_PAD_CAPS (pad), caps, caps);
if (G_UNLIKELY (!gst_pad_configure_src (pad, caps, TRUE)))
goto not_negotiated;
}
- ret = gst_pad_chain (peer, buffer);
+ ret = gst_pad_chain_unchecked (peer, buffer);
gst_object_unref (peer);
if (G_LIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL)) {
/* FIXME, kindoff ghetto */
ret = GST_PAD_GETRANGEFUNC (peer) != NULL;
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "no checkgetrangefunc, assuming %d", ret);
} else {
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"calling checkgetrangefunc %s of peer pad %s:%s",
/* ERROR recovery here */
wrong_direction:
{
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "checking pull range, but pad must be a sinkpad");
GST_OBJECT_UNLOCK (pad);
return FALSE;
}
/**
* gst_pad_get_range:
- * @pad: a src #GstPad.
+ * @pad: a src #GstPad, returns #GST_FLOW_ERROR if not.
* @offset: The start offset of the buffer
* @size: The length of the buffer
- * @buffer: a pointer to hold the #GstBuffer.
+ * @buffer: a pointer to hold the #GstBuffer, returns #GST_FLOW_ERROR if %NULL.
*
- * Calls the getrange function of @pad.
+ * When @pad is flushing this function returns #GST_FLOW_WRONG_STATE
+ * immediatly.
+ *
+ * Calls the getrange function of @pad, see #GstPadGetRangeFunction for a
+ * description of a getrange function. If @pad has no getrange function
+ * installed (see gst_pad_set_getrange_function()) this function returns
+ * #GST_FLOW_NOT_SUPPORTED.
+ *
+ * @buffer's caps must either be unset or the same as what is already
+ * configured on @pad. Renegotiation within a running pull-mode pipeline is not
+ * supported.
+ *
+ * This is a lowlevel function. Usualy gst_pad_pull_range() is used.
*
* Returns: a #GstFlowReturn from the pad.
*
goto no_function;
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "calling getrangefunc %s of peer pad %s:%s, offset %"
+ "calling getrangefunc %s, offset %"
G_GUINT64_FORMAT ", size %u",
- GST_DEBUG_FUNCPTR_NAME (getrangefunc), GST_DEBUG_PAD_NAME (pad),
- offset, size);
+ GST_DEBUG_FUNCPTR_NAME (getrangefunc), offset, size);
ret = getrangefunc (pad, offset, size, buffer);
GST_PAD_STREAM_UNLOCK (pad);
+ if (G_LIKELY (ret == GST_FLOW_OK)) {
+ GstCaps *caps;
+ gboolean caps_changed;
+
+ GST_OBJECT_LOCK (pad);
+ /* Before pushing the buffer to the peer pad, ensure that caps
+ * are set on this pad */
+ caps = GST_BUFFER_CAPS (*buffer);
+ caps_changed = caps && caps != GST_PAD_CAPS (pad);
+ GST_OBJECT_UNLOCK (pad);
+
+ /* we got a new datatype from the pad not supported in a running pull-mode
+ * pipeline */
+ if (G_UNLIKELY (caps_changed))
+ goto not_negotiated;
+ }
+
return ret;
/* ERRORS */
("pullrange on pad %s:%s but it has no getrangefunction",
GST_DEBUG_PAD_NAME (pad)));
GST_PAD_STREAM_UNLOCK (pad);
- return GST_FLOW_ERROR;
+ return GST_FLOW_NOT_SUPPORTED;
}
dropping:
{
- GST_DEBUG ("Dropping data after FALSE probe return");
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "Dropping data after FALSE probe return");
GST_PAD_STREAM_UNLOCK (pad);
gst_buffer_unref (*buffer);
*buffer = NULL;
return GST_FLOW_UNEXPECTED;
}
+not_negotiated:
+ {
+ /* ideally we want to use the commented-out code, but currently demuxers
+ * and typefind do not follow part-negotiation.txt. When switching into
+ * pull mode, typefind should probably return the found caps from
+ * getcaps(), and demuxers should do the setcaps(). */
+
+#if 0
+ gst_buffer_unref (*buffer);
+ *buffer = NULL;
+ GST_CAT_WARNING_OBJECT (GST_CAT_SCHEDULING, pad,
+ "getrange returned buffer of different caps");
+ return GST_FLOW_NOT_NEGOTIATED;
+#endif
+ GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "getrange returned buffer of different caps");
+ return ret;
+ }
}
/**
* gst_pad_pull_range:
- * @pad: a sink #GstPad.
+ * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not.
* @offset: The start offset of the buffer
* @size: The length of the buffer
- * @buffer: a pointer to hold the #GstBuffer.
+ * @buffer: a pointer to hold the #GstBuffer, returns GST_FLOW_ERROR if %NULL.
+ *
+ * Pulls a @buffer from the peer pad.
+ *
+ * This function will first trigger the pad block signal if it was
+ * installed.
*
- * Pulls a buffer from the peer pad. @pad must be a linked
- * sinkpad.
+ * When @pad is not linked #GST_FLOW_NOT_LINKED is returned else this
+ * function returns the result of gst_pad_get_range() on the peer pad.
+ * See gst_pad_get_range() for a list of return values and for the
+ * semantics of the arguments of this function.
+ *
+ * @buffer's caps must either be unset or the same as what is already
+ * configured on @pad. Renegotiation within a running pull-mode pipeline is not
+ * supported.
*
* Returns: a #GstFlowReturn from the peer pad.
+ * When this function returns #GST_FLOW_OK, @buffer will contain a valid
+ * #GstBuffer that should be freed with gst_buffer_unref() after usage.
+ * @buffer may not be used or freed when any other return value than
+ * #GST_FLOW_OK is returned.
*
* MT safe.
*/
if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (*buffer)))
goto dropping;
}
+
+ if (G_LIKELY (ret == GST_FLOW_OK)) {
+ GstCaps *caps;
+ gboolean caps_changed;
+
+ GST_OBJECT_LOCK (pad);
+ /* Before pushing the buffer to the peer pad, ensure that caps
+ * are set on this pad */
+ caps = GST_BUFFER_CAPS (*buffer);
+ caps_changed = caps && caps != GST_PAD_CAPS (pad);
+ GST_OBJECT_UNLOCK (pad);
+
+ /* we got a new datatype on the pad, see if it can handle it */
+ if (G_UNLIKELY (caps_changed))
+ goto not_negotiated;
+ }
+
return ret;
/* ERROR recovery here */
}
dropping:
{
- GST_DEBUG ("Dropping data after FALSE probe return");
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "Dropping data after FALSE probe return");
gst_buffer_unref (*buffer);
*buffer = NULL;
return GST_FLOW_UNEXPECTED;
}
+not_negotiated:
+ {
+ /* ideally we want to use the commented-out code, but currently demuxers
+ * and typefind do not follow part-negotiation.txt. When switching into
+ * pull mode, typefind should probably return the found caps from
+ * getcaps(), and demuxers should do the setcaps(). */
+
+#if 0
+ gst_buffer_unref (*buffer);
+ *buffer = NULL;
+ GST_CAT_WARNING_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pullrange returned buffer of different caps");
+ return GST_FLOW_NOT_NEGOTIATED;
+#endif
+ GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pullrange returned buffer of different caps");
+ return ret;
+ }
}
/**
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
+ GST_LOG_OBJECT (pad, "event: %s", GST_EVENT_TYPE_NAME (event));
+
GST_OBJECT_LOCK (pad);
+
+ /* 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 (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;
+ }
break;
case GST_EVENT_FLUSH_STOP:
GST_PAD_UNSET_FLUSHING (pad);
+
+ /* if we are blocked, flush away the FLUSH_STOP event */
+ if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
+ GST_LOG_OBJECT (pad, "Pad is blocked, not forwarding flush-stop");
+ goto flushed;
+ }
break;
default:
+ while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
+ /* block the event as long as the pad is blocked */
+ if (handle_pad_block (pad) != GST_FLOW_OK)
+ goto flushed;
+ }
break;
}
- if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
- if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) {
- GST_PAD_BLOCK_SIGNAL (pad);
- }
- }
-
if (G_UNLIKELY (GST_PAD_DO_EVENT_SIGNALS (pad) > 0)) {
GST_OBJECT_UNLOCK (pad);
if (peerpad == NULL)
goto not_linked;
- GST_LOG_OBJECT (peerpad, "sending event on peerpad");
+ GST_LOG_OBJECT (pad, "sending event %s to peerpad %" GST_PTR_FORMAT,
+ GST_EVENT_TYPE_NAME (event), peerpad);
gst_object_ref (peerpad);
GST_OBJECT_UNLOCK (pad);
result = gst_pad_send_event (peerpad, event);
+ /* Note: we gave away ownership of the event at this point */
+ GST_LOG_OBJECT (pad, "sent event to peerpad %" GST_PTR_FORMAT ", result %d",
+ peerpad, result);
gst_object_unref (peerpad);
- GST_LOG_OBJECT (peerpad, "sent event on peerpad");
return result;
}
not_linked:
{
+ GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked");
gst_event_unref (event);
GST_OBJECT_UNLOCK (pad);
return FALSE;
}
+flushed:
+ {
+ GST_DEBUG_OBJECT (pad,
+ "Not forwarding event since we're flushing and blocking");
+ gst_event_unref (event);
+ GST_OBJECT_UNLOCK (pad);
+ return TRUE;
+ }
}
/**
* 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.
+ * #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.
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
- GST_CAT_DEBUG (GST_CAT_EVENT,
- "have event type %d (FLUSH_START) on pad %s:%s",
- GST_EVENT_TYPE (event), GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad,
+ "have event type %d (FLUSH_START)", GST_EVENT_TYPE (event));
/* can't even accept a flush begin event when flushing */
if (GST_PAD_IS_FLUSHING (pad))
goto flushing;
GST_PAD_SET_FLUSHING (pad);
- GST_CAT_DEBUG (GST_CAT_EVENT, "set flush flag");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad, "set flush flag");
break;
case GST_EVENT_FLUSH_STOP:
GST_PAD_UNSET_FLUSHING (pad);
- GST_CAT_DEBUG (GST_CAT_EVENT, "cleared flush flag");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad, "cleared flush flag");
GST_OBJECT_UNLOCK (pad);
/* grab stream lock */
GST_PAD_STREAM_LOCK (pad);
GST_OBJECT_LOCK (pad);
break;
default:
- GST_CAT_DEBUG (GST_CAT_EVENT, "have event type %s on pad %s:%s",
- GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (pad));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, pad, "have event type %s",
+ GST_EVENT_TYPE_NAME (event));
/* make this a little faster, no point in grabbing the lock
* if the pad is allready flushing. */
goto flushing;
if (serialized) {
- /* lock order: STREAM_LOCK, LOCK */
+ /* lock order: STREAM_LOCK, LOCK, recheck flushing. */
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_LOCK (pad);
need_unlock = TRUE;
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
+ GST_DEBUG_OBJECT (pad, "sent event, result %d", result);
+
return result;
/* ERROR handling */
g_warning ("pad %s:%s has no event handler, file a bug.",
GST_DEBUG_PAD_NAME (pad));
GST_OBJECT_UNLOCK (pad);
+ if (need_unlock)
+ GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
return FALSE;
}
GST_OBJECT_UNLOCK (pad);
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
- GST_CAT_INFO (GST_CAT_EVENT, "Received event on flushing pad. Discarding");
+ GST_CAT_INFO_OBJECT (GST_CAT_EVENT, pad,
+ "Received event on flushing pad. Discarding");
gst_event_unref (event);
return FALSE;
}
dropping:
{
- GST_DEBUG ("Dropping event after FALSE probe return");
+ GST_DEBUG_OBJECT (pad, "Dropping event after FALSE probe return");
gst_event_unref (event);
return FALSE;
}
* @func: the task function to call
* @data: data passed to the task function
*
- * Starts a task that repeadedly calls @func with @data. This function
- * is nostly used in the pad activation function to start the
- * dataflow. This function will automatically acquire the STREAM_LOCK of
- * the pad before calling @func.
+ * Starts a task that repeatedly calls @func with @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.
+ * Returns: a %TRUE if the task could be started.
*/
gboolean
gst_pad_start_task (GstPad * pad, GstTaskFunction func, gpointer data)
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (func != NULL, FALSE);
+ GST_DEBUG_OBJECT (pad, "start task");
+
GST_OBJECT_LOCK (pad);
task = GST_PAD_TASK (pad);
if (task == NULL) {
task = gst_task_create (func, data);
gst_task_set_lock (task, GST_PAD_GET_STREAM_LOCK (pad));
GST_PAD_TASK (pad) = task;
+ GST_DEBUG_OBJECT (pad, "created task");
}
gst_task_start (task);
GST_OBJECT_UNLOCK (pad);
* gst_pad_pause_task:
* @pad: the #GstPad to pause the task of
*
- * Pause the task of @pad. This function will also make sure that the
- * function executed by the task will effectively stop.
+ * Pause the task of @pad. This function will also wait until the
+ * 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
* has no task.
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ GST_DEBUG_OBJECT (pad, "pause task");
+
GST_OBJECT_LOCK (pad);
task = GST_PAD_TASK (pad);
if (task == NULL)
gst_task_pause (task);
GST_OBJECT_UNLOCK (pad);
+ /* wait for task function to finish, this lock is recursive so it does nothing
+ * when the pause is called from the task itself */
GST_PAD_STREAM_LOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ GST_DEBUG_OBJECT (pad, "stop task");
+
GST_OBJECT_LOCK (pad);
task = GST_PAD_TASK (pad);
if (task == NULL)
GST_PAD_STREAM_LOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
- gst_task_join (task);
+ if (!gst_task_join (task))
+ goto join_failed;
gst_object_unref (task);
no_task:
{
+ GST_DEBUG_OBJECT (pad, "no task");
GST_OBJECT_UNLOCK (pad);
GST_PAD_STREAM_LOCK (pad);
GST_PAD_STREAM_UNLOCK (pad);
+ /* this is not an error */
return TRUE;
}
+join_failed:
+ {
+ /* this is bad, possibly the application tried to join the task from
+ * the task's thread. We install the task again so that it will be stopped
+ * again from the right thread next time hopefully. */
+ GST_OBJECT_LOCK (pad);
+ GST_DEBUG_OBJECT (pad, "join failed");
+ /* we can only install this task if there was no other task */
+ if (GST_PAD_TASK (pad) == NULL)
+ GST_PAD_TASK (pad) = task;
+ GST_OBJECT_UNLOCK (pad);
+
+ return FALSE;
+ }
}