From a03e803bb6561cc889203f44a49d89c2717cb2fc Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 8 Apr 2003 21:14:23 +0000 Subject: [PATCH] huge modifications, hope i didn't break something: Original commit message from CVS: huge modifications, hope i didn't break something: - added functions for setting/getting locked state of elements. gst_element_lock_state syncs the pads state with the state of its parent. - made all gst_element_link_* functions call gst_element_link_pads_filtered - gst_element_link_pads_filtered now accepts NULL as a pad name. - make sure the link functions are only called when the elements are paused That's it. --- gst/gstelement.c | 270 ++++++++++++++++++++++++++++++++++++++----------------- gst/gstelement.h | 4 + 2 files changed, 192 insertions(+), 82 deletions(-) diff --git a/gst/gstelement.c b/gst/gstelement.c index 98b7d10..bac07fb 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -1402,78 +1402,141 @@ gst_element_get_compatible_pad (GstElement *element, GstPad *pad) } /** - * gst_element_link_filtered: + * gst_element_link_pads_filtered: * @src: a #GstElement containing the source pad. + * @srcpadname: the name of the #GstPad in source element or NULL for any element. * @dest: the #GstElement containing the destination pad. + * @destpadname: the name of the #GstPad in destination element or NULL for any element. * @filtercaps: the #GstCaps to use as a filter. * - * Links the source to the destination element using the filtercaps. - * The link must be from source to destination, the other - * direction will not be tried. - * The functions looks for existing pads that aren't linked yet. - * It will use request pads if possible. But both pads will not be requested. - * If multiple links are possible, only one is established. + * Links the two named pads of the source and destination elements. + * Side effect is that if one of the pads has no parent, it becomes a + * child of the parent of the other element. If they have different + * parents, the link fails. * - * Returns: TRUE if the elements could be linked. + * Returns: TRUE if the pads could be linked. */ gboolean -gst_element_link_filtered (GstElement *src, GstElement *dest, - GstCaps *filtercaps) +gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname, + GstElement *dest, const gchar *destpadname, + GstCaps *filtercaps) { const GList *srcpads, *destpads, *srctempls, *desttempls, *l; GstPad *srcpad, *destpad; GstPadTemplate *srctempl, *desttempl; /* checks */ - g_return_val_if_fail (src != NULL, FALSE); g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE); - g_return_val_if_fail (dest != NULL, FALSE); g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE); + g_return_val_if_fail (GST_STATE (src) != GST_STATE_PLAYING, FALSE); + g_return_val_if_fail (GST_STATE (dest) != GST_STATE_PLAYING, FALSE); + + GST_INFO (GST_CAT_ELEMENT_PADS, "trying to link element %s:%s to element %s:%s", + GST_ELEMENT_NAME (src), srcpadname ? srcpadname : "(any)", + GST_ELEMENT_NAME (dest), destpadname ? destpadname : "(any)"); + + /* now get the pads we're trying to link and a list of all remaining pads */ + if (srcpadname) { + srcpad = gst_element_get_pad (src, srcpadname); + if (!srcpad) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (src), srcpadname); + return FALSE; + } else { + if (!(GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC)) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad", GST_DEBUG_PAD_NAME (srcpad)); + return FALSE; + } + if (GST_PAD_PEER (srcpad) != NULL) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (srcpad)); + return FALSE; + } + } + srcpads = NULL; + } else { + srcpads = gst_element_get_pad_list (src); + srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL; + } + if (destpadname) { + destpad = gst_element_get_pad (dest, destpadname); + if (!destpad) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (dest), destpadname); + return FALSE; + } else { + if (!(GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK)) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad", GST_DEBUG_PAD_NAME (destpad)); + return FALSE; + } + if (GST_PAD_PEER (destpad) != NULL) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (destpad)); + return FALSE; + } + } + destpads = NULL; + } else { + destpads = gst_element_get_pad_list (dest); + destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL; + } - GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying to link element %s to element %s", - GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest)); - - srcpads = gst_element_get_pad_list (src); - destpads = gst_element_get_pad_list (dest); - - if (srcpads || destpads) { - GST_DEBUG (GST_CAT_ELEMENT_PADS, "looping through src and dest pads"); - /* loop through the existing pads in the source, trying to find a + if (srcpadname && destpadname) { + /* two explicitly specified pads */ + return gst_pad_link_filtered (srcpad, destpad, filtercaps); + } + if (srcpad) { + /* loop through the allowed pads in the source, trying to find a * compatible destination pad */ - while (srcpads) { - srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data); + GST_DEBUG (GST_CAT_ELEMENT_PADS, "looping through allowed src and dest pads"); + do { GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s", GST_DEBUG_PAD_NAME (srcpad)); if ((GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC) && (GST_PAD_PEER (srcpad) == NULL)) { - destpad = gst_element_get_compatible_pad_filtered (dest, srcpad, + GstPad *temp = gst_element_get_compatible_pad_filtered (dest, srcpad, filtercaps); - if (destpad && gst_pad_link_filtered (srcpad, destpad, filtercaps)) { + if (temp && gst_pad_link_filtered (srcpad, temp, filtercaps)) { GST_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", - GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad)); + GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp)); return TRUE; } } - srcpads = g_list_next (srcpads); - } - + /* find a better way for this mess */ + if (srcpads) { + srcpads = g_list_next (srcpads); + if (srcpads) + srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data); + } + } while (srcpads); + } + if (srcpadname) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s", + GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest)); + return FALSE; + } + if (destpad) { /* loop through the existing pads in the destination */ - while (destpads) { - destpad = (GstPad *) GST_PAD_REALIZE (destpads->data); + do { GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s", GST_DEBUG_PAD_NAME (destpad)); if ((GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK) && (GST_PAD_PEER (destpad) == NULL)) { - srcpad = gst_element_get_compatible_pad_filtered (src, destpad, + GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad, filtercaps); - if (srcpad && gst_pad_link_filtered (srcpad, destpad, filtercaps)) { + if (temp && gst_pad_link_filtered (temp, destpad, filtercaps)) { GST_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", - GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad)); + GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad)); return TRUE; } } - destpads = g_list_next (destpads); - } + if (destpads) { + destpads = g_list_next (destpads); + if (destpads) + destpad = (GstPad *) GST_PAD_REALIZE (destpads->data); + } + } while (destpads); + } + if (destpadname) { + GST_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s", + GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad)); + return FALSE; } GST_DEBUG (GST_CAT_ELEMENT_PADS, @@ -1515,6 +1578,27 @@ gst_element_link_filtered (GstElement *src, GstElement *dest, GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest)); return FALSE; } +/** + * gst_element_link_filtered: + * @src: a #GstElement containing the source pad. + * @dest: the #GstElement containing the destination pad. + * @filtercaps: the #GstCaps to use as a filter. + * + * Links the source to the destination element using the filtercaps. + * The link must be from source to destination, the other + * direction will not be tried. + * The functions looks for existing pads that aren't linked yet. + * It will use request pads if possible. But both pads will not be requested. + * If multiple links are possible, only one is established. + * + * Returns: TRUE if the elements could be linked. + */ +gboolean +gst_element_link_filtered (GstElement *src, GstElement *dest, + GstCaps *filtercaps) +{ + return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps); +} /** * gst_element_link_many: @@ -1567,52 +1651,7 @@ gst_element_link_many (GstElement *element_1, GstElement *element_2, ...) gboolean gst_element_link (GstElement *src, GstElement *dest) { - return gst_element_link_filtered (src, dest, NULL); -} - -/** - * gst_element_link_pads_filtered: - * @src: a #GstElement containing the source pad. - * @srcpadname: the name of the #GstPad in source element. - * @dest: the #GstElement containing the destination pad. - * @destpadname: the name of the #GstPad in destination element. - * @filtercaps: the #GstCaps to use as a filter. - * - * Links the two named pads of the source and destination elements. - * Side effect is that if one of the pads has no parent, it becomes a - * child of the parent of the other element. If they have different - * parents, the link fails. - * - * Returns: TRUE if the pads could be linked. - */ -gboolean -gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname, - GstElement *dest, const gchar *destpadname, - GstCaps *filtercaps) -{ - GstPad *srcpad,*destpad; - - g_return_val_if_fail (src != NULL, FALSE); - g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE); - g_return_val_if_fail (srcpadname != NULL, FALSE); - g_return_val_if_fail (dest != NULL, FALSE); - g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE); - g_return_val_if_fail (destpadname != NULL, FALSE); - - /* obtain the pads requested */ - srcpad = gst_element_get_pad (src, srcpadname); - if (srcpad == NULL) { - GST_ERROR (src, "source element has no pad \"%s\"", srcpadname); - return FALSE; - } - destpad = gst_element_get_pad (dest, destpadname); - if (srcpad == NULL) { - GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname); - return FALSE; - } - - /* we're satisified they can be linked, let's do it */ - return gst_pad_link_filtered (srcpad, destpad, filtercaps); + return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL); } /** @@ -2050,6 +2089,73 @@ gst_element_error (GstElement *element, const gchar *error, ...) } /** + * gst_element_is_state_locked: + * @element: a #GstElement. + * + * Checks if the state of an element is locked. + * If the state of an element is locked, state changes of the parent don't + * affect the element. + * This way you can leave currently unused elements inside bins. Just lock their + * state before changing the state from #GST_STATE_NULL. + * + * Returns: TRUE, if the element's state is locked. + */ +gboolean +gst_element_is_state_locked (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + return GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE) ? TRUE : FALSE; +} +/** + * gst_element_lock_state: + * @element: a #GstElement. + * + * Locks the state of an element, so state changes of the parent don't affect + * this element anymore. + * + * Returns: TRUE, if the element's state could be locked. + */ +gboolean +gst_element_lock_state (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + GST_INFO (GST_CAT_STATES, "locking state of element %s\n", GST_ELEMENT_NAME (element)); + GST_FLAG_SET (element, GST_ELEMENT_LOCKED_STATE); + return TRUE; +} +/** + * gst_element_unlock_state: + * @element: a #GstElement. + * + * Unlocks the state of an element and synchronises the state with the parent. + * If this function succeeds, the state of this element is identical to the + * state of it's bin. + * When this function fails, the state of the element is undefined. + * + * Returns: TRUE, if the element's state could be unlocked. + */ +gboolean +gst_element_unlock_state (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + GST_INFO (GST_CAT_STATES, "unlocking state of element %s\n", GST_ELEMENT_NAME (element)); + GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE); + if (GST_ELEMENT_PARENT(element)) { + GST_DEBUG (GST_CAT_STATES, "setting state of unlocked element %s to %s\n", GST_ELEMENT_NAME (element), gst_element_state_get_name (GST_STATE (GST_ELEMENT_PARENT(element)))); + GstElementState old_state = GST_STATE (element); + if (gst_element_set_state (element, GST_STATE (GST_ELEMENT_PARENT(element))) == GST_STATE_FAILURE) { + GST_DEBUG (GST_CAT_STATES, "state change of unlocked element %s to %s stopped at %s, resetting\n", GST_ELEMENT_NAME (element), + gst_element_state_get_name (GST_STATE (GST_ELEMENT_PARENT(element))), gst_element_state_get_name (GST_STATE (element))); + gst_element_set_state (element, old_state); + return FALSE; + } + } + return TRUE; +} +/** * gst_element_get_state: * @element: a #GstElement to get the state of. * diff --git a/gst/gstelement.h b/gst/gstelement.h index 26e0a1e..f750957 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -325,6 +325,10 @@ void gst_element_set_eos (GstElement *element); void gst_element_error (GstElement *element, const gchar *error, ...); +gboolean gst_element_is_state_locked (GstElement *element); +gboolean gst_element_lock_state (GstElement *element); +gboolean gst_element_unlock_state (GstElement *element); + GstElementState gst_element_get_state (GstElement *element); GstElementStateReturn gst_element_set_state (GstElement *element, GstElementState state); -- 2.7.4