From: Benjamin Otte Date: Mon, 11 Feb 2002 08:18:09 +0000 (+0000) Subject: major rewrite of the spider. X-Git-Tag: RELEASE-0_3_3-GUADECBYFOOT~106 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e149d96faa5e4f90e37d82e95f4172ede838d1fe;p=platform%2Fupstream%2Fgstreamer.git major rewrite of the spider. Original commit message from CVS: major rewrite of the spider. Now uses GstSpiderConnection to track current connections and remember the way they're plugged. Advantages of this approach: - function prototypes are now much cleaner. - Allow event propagation (EOS) to elements that are not connected but plugged. - Allow deconstruction of plugged pipes. (not implemented) Disadvantage: - I screwed up naming (always get src and sink the wrong way). It's very inconsistent in the gstspider.[ch] files - a little more time and memory are needed to manage the structs --- diff --git a/gst/autoplug/gstsearchfuncs.c b/gst/autoplug/gstsearchfuncs.c index 42d496d..97ef02a 100644 --- a/gst/autoplug/gstsearchfuncs.c +++ b/gst/autoplug/gstsearchfuncs.c @@ -309,6 +309,9 @@ gst_autoplug_sp (GstCaps *srccaps, GstCaps *sinkcaps, GList *factories) guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */ GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */ + g_return_val_if_fail (srccaps != NULL, NULL); + g_return_val_if_fail (sinkcaps != NULL, NULL); + GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, "attempting to autoplug via shortest path from %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps)); /* wrap all factories as GstAutoplugNode * initialize the cost */ diff --git a/gst/autoplug/gstspider.c b/gst/autoplug/gstspider.c index 9e74877..91f7822 100644 --- a/gst/autoplug/gstspider.c +++ b/gst/autoplug/gstspider.c @@ -71,26 +71,43 @@ GST_PADTEMPLATE_FACTORY (spider_sink_factory, GST_PAD_REQUEST, NULL /* no caps */ ); + + + /* standard GObject stuff */ -static void gst_spider_class_init (GstSpiderClass *klass); -static void gst_spider_init (GstSpider *spider); -static void gst_spider_dispose (GObject *object); +static void gst_spider_class_init (GstSpiderClass *klass); +static void gst_spider_init (GstSpider *spider); +static void gst_spider_dispose (GObject *object); /* element class functions */ -static GstPad* gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name); -static void gst_spider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static GstPad* gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name); +static void gst_spider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +/* connection functions */ +static GstSpiderConnection * gst_spider_connection_new (GstSpiderIdentity *sink, GstSpiderIdentity *src); +static void gst_spider_connection_destroy (GstSpiderConnection *conn); +static void gst_spider_connection_reset (GstSpiderConnection *conn, GstElement *to); +static void gst_spider_connection_add (GstSpiderConnection *conn, GstElement *element); +static GstSpiderConnection * gst_spider_connection_find (GstSpiderIdentity *sink, GstSpiderIdentity *src); +static GstSpiderConnection * gst_spider_connection_get (GstSpiderIdentity *sink, GstSpiderIdentity *src); /* autoplugging functions */ -static GstElement * gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir); -static GstPadConnectReturn gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad); -static GstPadConnectReturn gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath); +static GstElement * gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir); +static GstPadConnectReturn gst_spider_plug (GstSpiderConnection *conn); +static GstPadConnectReturn gst_spider_plug_from_srcpad (GstSpiderConnection *conn, GstPad *srcpad); +//static GstPadConnectReturn gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad); +static GstPadConnectReturn gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath); /* random functions */ -static gchar * gst_spider_unused_elementname (GstBin *bin, const gchar *startwith); +static gchar * gst_spider_unused_elementname (GstBin *bin, const gchar *startwith); + +/* debugging stuff +static void print_spider_contents (GstSpider *spider); +static void print_spider_connection (GstSpiderConnection *conn); */ /* === variables === */ -static GstElementClass *parent_class = NULL; +static GstElementClass * parent_class = NULL; /* no signals yet static guint gst_spider_signals[LAST_SIGNAL] = { 0 };*/ @@ -145,6 +162,8 @@ gst_spider_init (GstSpider *spider) /* use only elements which have sources and sinks and where the sinks have caps */ /* FIXME: How do we handle factories that are added after the spider was constructed? */ spider->factories = gst_autoplug_factories_filters_with_sink_caps ((GList *) gst_elementfactory_get_list ()); + + spider->connections = NULL; } static void @@ -261,134 +280,121 @@ gst_spider_unused_elementname (GstBin *bin, const gchar *startwith) return name; } -/* callback and struct for the data supplied to the callback that is used to connect dynamic pads */ -typedef struct { - GstSpider *spider; - GstElement *sink; - gulong signal_id; -} GstSpiderConnectSometimes; static void -gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnectSometimes *data) +gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnection *conn) { gboolean restart = FALSE; - GstPad *sinkpad; - GList *sinkpads = gst_element_get_pad_list (data->sink); + gulong signal_id = conn->signal_id; + GstPad *sinkpad = conn->src->sink; + GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (conn->sink)); - if (gst_element_get_state ((GstElement *) data->spider) == GST_STATE_PLAYING) + /* check if restarting is necessary */ + if (gst_element_get_state ((GstElement *) spider) == GST_STATE_PLAYING) { restart = TRUE; - gst_element_set_state ((GstElement *) data->spider, GST_STATE_PAUSED); + gst_element_set_state ((GstElement *) spider, GST_STATE_PAUSED); } + /* try to autoplug the elements */ - while (sinkpads) - { - sinkpad = (GstPad *) sinkpads->data; - if ((GST_RPAD_DIRECTION (sinkpad) == GST_PAD_SINK) && gst_spider_plug_peers (data->spider, pad, sinkpad) != GST_PAD_CONNECT_REFUSED) { - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%s:%s was autoplugged to %s:%s, removing callback\n", GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (sinkpad)); - g_signal_handler_disconnect (src, data->signal_id); - /* do the restarting here, because we want to free the data */ - if (restart) - { - gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING); - } - restart = FALSE; - g_free (data); - break; - } - sinkpads = g_list_next (sinkpads); + if (gst_spider_plug_from_srcpad (conn, pad) != GST_PAD_CONNECT_REFUSED) { + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%s:%s was autoplugged to %s:%s, removing callback\n", GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (sinkpad)); + g_signal_handler_disconnect (src, signal_id); + signal_id = 0; } + + /* restart if needed */ if (restart) { - gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING); + gst_element_set_state ((GstElement *) spider, GST_STATE_PLAYING); } - /* do we need this? */ - gst_element_interrupt (src); } -/* connects newsrc to newsink using the elementfactories in plugpath */ -static GstPadConnectReturn -gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath) +/* create a new connection from those two elements */ +static GstSpiderConnection * +gst_spider_connection_new (GstSpiderIdentity *sink, GstSpiderIdentity *src) { - GstElement *element; + GstSpider *spider; + + GstSpiderConnection *conn = g_new0 (GstSpiderConnection, 1); + conn->src = src; + conn->sink = sink; + conn->current = (GstElement *) sink; + conn->path = NULL; + spider = GST_SPIDER (GST_OBJECT_PARENT (src)); + spider->connections = g_list_prepend (spider->connections, conn); - /* g_print ("C&P: from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); */ - /* get the next element */ - if (plugpath == NULL) + return conn; +} +static void +gst_spider_connection_destroy (GstSpiderConnection *conn) +{ + /* reset connection to unplugged */ + gst_spider_connection_reset (conn, (GstElement *) conn->sink); + g_free (conn); +} +static void +gst_spider_connection_reset (GstSpiderConnection *conn, GstElement *to) +{ + GST_DEBUG (GST_CAT_AUTOPLUG, "resetting connection from %s to %s, currently at %s to %s\n", GST_ELEMENT_NAME (conn->sink), + GST_ELEMENT_NAME (conn->src), GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (to)); + while ((conn->path != NULL) && ((GstElement *) conn->path->data != to)) { - element = sink; - } else { - element = gst_elementfactory_create ((GstElementFactory *) plugpath->data, - gst_spider_unused_elementname (GST_BIN (spider), GST_OBJECT_NAME (plugpath->data))); - gst_bin_add (GST_BIN (spider), element); - /* g_print ("C&P: trying element %s\n", GST_ELEMENT_NAME (element)); */ + gst_object_unref ((GstObject *) conn->path->data); + conn->path = g_list_delete_link (conn->path, conn->path); } - /* insert and connect new element */ - if (!gst_element_connect_elements (src, element)) + if (conn->path == NULL) { - /* check if the src has SOMETIMES templates. If so, connect a callback */ - GList *templs = gst_element_get_padtemplate_list (src); - - /* remove element that couldn't be connected, if it wasn't the endpoint */ - if (element != sink) - gst_bin_remove (GST_BIN (spider), element); - - while (templs) { - GstPadTemplate *templ = (GstPadTemplate *) templs->data; - if ((GST_PADTEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PADTEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES)) - { - GstSpiderConnectSometimes *data = g_new (GstSpiderConnectSometimes, 1); - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); - data->spider = spider; - data->sink = sink; - data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad", - G_CALLBACK (gst_spider_connect_sometimes), data); - - return GST_PAD_CONNECT_DELAYED; - } - templs = g_list_next (templs); - } - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); - return GST_PAD_CONNECT_REFUSED; - } - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "added element %s and attached it to element %s\n", GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (src)); - plugpath = g_list_next (plugpath); - - /* recursively connect the rest of the elements */ - if (element != sink) { - return gst_spider_create_and_plug (spider, element, sink, plugpath); + conn->current = (GstElement *) conn->sink; + } else { + conn->current = to; } - - return GST_PAD_CONNECT_DONE; } -/* checks, if src is already connected to an element from factory fac on direction dir */ -static GstElement * -gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir) +/* add an element to the connection */ +static void +gst_spider_connection_add (GstSpiderConnection *conn, GstElement *element) { - GList *padlist = GST_ELEMENT_PADS (src); + gst_object_ref ((GstObject *) element); + gst_object_sink ((GstObject *) element); + conn->path = g_list_prepend (conn->path, element); + conn->current = element; +} +/* find the connection from those two elements */ +static GstSpiderConnection * +gst_spider_connection_find (GstSpiderIdentity *sink, GstSpiderIdentity *src) +{ + GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (src); + GList *list = spider->connections; - while (padlist) + g_assert (spider == (GstSpider *) GST_OBJECT_PARENT (sink)); + + while (list) { - GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data); - /* is the pad on the right side and is it connected? */ - if ((GST_PAD_DIRECTION (pad) == dir) && (pad = GST_PAD (GST_RPAD_PEER (pad)))) - { - /* is the element the pad is connected to of the right type? */ - GstElement *element = GST_PAD_PARENT (pad); - if (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))->elementfactory == fac) { - return element; - } - } - padlist = g_list_next (padlist); + GstSpiderConnection *conn = (GstSpiderConnection *) list->data; + if (conn->src == src && conn->sink == sink) + return conn; + list = g_list_next(list); } - return NULL; } -/* plugs a pad into the autoplugger if it isn't plugged yet */ -void -gst_spider_plug (GstSpiderIdentity *ident) +/* get a new connection from those two elements + * search first; if none is found, create a new one */ +static GstSpiderConnection * +gst_spider_connection_get (GstSpiderIdentity *sink, GstSpiderIdentity *src) +{ + GstSpiderConnection *ret; + + if ((ret = gst_spider_connection_find (sink, src)) != NULL) + { + return ret; + } + return gst_spider_connection_new (sink, src); +} +void +gst_spider_identity_plug (GstSpiderIdentity *ident) { GstSpider *spider; - GList *plugto; - GstPad *plugpad; + GList *padlist; + GstPadDirection dir; + GstSpiderConnection *conn; /* checks */ g_return_if_fail (ident != NULL); @@ -397,23 +403,24 @@ gst_spider_plug (GstSpiderIdentity *ident) g_assert (spider != NULL); g_assert (GST_IS_SPIDER (spider)); - /* return, if we're already plugged */ + /* return if we're already plugged */ if (ident->plugged) return; - - if (ident->sink && GST_PAD_PEER (ident->sink)) + + /* get the direction of our ident */ + if (GST_PAD_PEER (ident->sink)) { - if (ident->src && GST_PAD_PEER (ident->src)) + if (GST_PAD_PEER (ident->src)) { /* Hey, the ident is connected on both sides */ g_warning ("Trying to autoplug a connected element. Aborting..."); return; } else { - plugpad = ident->sink; + dir = GST_PAD_SINK; } } else { - if (ident->src && GST_PAD_PEER (ident->src)) + if (GST_PAD_PEER (ident->src)) { - plugpad = ident->src; + dir = GST_PAD_SRC; } else { /* the ident isn't connected on either side */ g_warning ("Trying to autoplug an unconnected element. Aborting..."); @@ -421,66 +428,204 @@ gst_spider_plug (GstSpiderIdentity *ident) } } - /* now iterate all possible pads and connect */ - plugto = gst_element_get_pad_list (GST_ELEMENT (spider)); - while (plugto) + /* now iterate all possible pads and connect when needed */ + padlist = gst_element_get_pad_list (GST_ELEMENT (spider)); + while (padlist) { - GstPad *otherpad = (GstPad *) GST_GPAD_REALPAD (plugto->data); + GstPad *otherpad = (GstPad *) GST_GPAD_REALPAD (padlist->data); GstSpiderIdentity *peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad); /* we only want to connect to the other side */ - if (GST_PAD_DIRECTION (plugpad) != GST_PAD_DIRECTION (otherpad)) + if (dir != GST_PAD_DIRECTION (otherpad)) { /* we only connect to plugged in elements */ if (peer->plugged == TRUE) { /* plug in the right direction */ - if (plugpad == ident->src) + if (dir == GST_PAD_SINK) { - gst_spider_plug_peers (spider, peer->src, ident->sink); + conn = gst_spider_connection_get (ident, peer); } else { - gst_spider_plug_peers (spider, ident->src, peer->sink); + conn = gst_spider_connection_get (peer, ident); } + if ((GstElement *) conn->sink == conn->current) + { + gst_spider_plug (conn); + } } } - plugto = g_list_next (plugto); + padlist = g_list_next (padlist); } - ident->plugged = TRUE; + ident->plugged = TRUE; } -/* connect the src Identity element to the sink identity element - * Returns: DONE, if item could be plugged, DELAYED, if a callback is needed or REFUSED, - * if no connection was possible - */ +void +gst_spider_identity_unplug (GstSpiderIdentity *ident) +{ + GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident); + GList *list = spider->connections; + + while (list) + { + GstSpiderConnection *conn = list->data; + GList *cur = list; + list = g_list_next (list); + if ((conn->src == ident) || (conn->sink == ident)) + { + g_list_delete_link (spider->connections, cur); + gst_spider_connection_destroy (conn); + } + } + ident->plugged = FALSE; +} +/* connects src to sink using the elementfactories in plugpath + * plugpath will be removed afterwards */ static GstPadConnectReturn -gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad) +gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath) { - GstElement *element, *src, *sink, *newsrc, *newsink; + GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->sink); + GList *endelements = NULL, *templist = NULL; + GstElement *element; + + /* exit if plugging is already done */ + if ((GstElement *) conn->src == conn->current) + return GST_PAD_CONNECT_DONE; + + /* try to shorten the list at the end and not duplicate connection code */ + if (plugpath != NULL) + { + templist = g_list_last (plugpath); + element = (GstElement *) conn->src; + while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SINK))) + { + GList *cur = templist; + endelements = g_list_prepend (endelements, element); + templist = g_list_previous (templist); + g_list_delete_link (cur, cur); + } + } + + /* do the connecting */ + while (conn->current != (GstElement *) (endelements == NULL ? conn->src : endelements->data)) + { + /* get sink element to plug, src is conn->current */ + if (plugpath == NULL) + { + element = (GstElement *) (endelements == NULL ? conn->src : endelements->data); + } else { + element = gst_elementfactory_create ((GstElementFactory *) plugpath->data, + gst_spider_unused_elementname (GST_BIN (spider), GST_OBJECT_NAME (plugpath->data))); + gst_bin_add (GST_BIN (spider), element); + } + /* insert and connect new element */ + if (!gst_element_connect_elements (conn->current, element)) + { + /* check if the src has SOMETIMES templates. If so, connect a callback */ + GList *templs = gst_element_get_padtemplate_list (conn->current); + + /* remove element that couldn't be connected, if it wasn't the endpoint */ + if (element != (GstElement *) conn->src) + gst_bin_remove (GST_BIN (spider), element); + + while (templs) { + GstPadTemplate *templ = (GstPadTemplate *) templs->data; + if ((GST_PADTEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PADTEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES)) + { + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src)); + conn->signal_id = g_signal_connect (G_OBJECT (conn->current), "new_pad", + G_CALLBACK (gst_spider_connect_sometimes), conn); + g_list_free (plugpath); + return GST_PAD_CONNECT_DELAYED; + } + templs = g_list_next (templs); + } + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to connect element %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src)); + g_list_free (plugpath); + return GST_PAD_CONNECT_REFUSED; + } + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "added element %s and attached it to element %s\n", GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (conn->current)); + gst_spider_connection_add (conn, element); + if (plugpath != NULL) + plugpath = g_list_delete_link (plugpath, plugpath); + } + + /* ref all elements at the end */ + while (endelements) + { + gst_spider_connection_add (conn, endelements->data); + endelements = g_list_delete_link (endelements, endelements); + } + + return GST_PAD_CONNECT_DONE; +} +/* checks, if src is already connected to an element from factory fac on direction dir */ +static GstElement * +gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir) +{ + GList *padlist = GST_ELEMENT_PADS (src); + + while (padlist) + { + GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data); + /* is the pad on the right side and is it connected? */ + if ((GST_PAD_DIRECTION (pad) == dir) && (pad = GST_PAD (GST_RPAD_PEER (pad)))) + { + /* is the element the pad is connected to of the right type? */ + GstElement *element = GST_PAD_PARENT (pad); + if (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))->elementfactory == fac) { + return element; + } + } + padlist = g_list_next (padlist); + } + + return NULL; +} +/* try to establish the connection */ +static GstPadConnectReturn +gst_spider_plug (GstSpiderConnection *conn) +{ + if ((GstElement *) conn->src == conn->current) + return GST_PAD_CONNECT_DONE; + if ((GstElement *) conn->sink == conn->current) + return gst_spider_plug_from_srcpad (conn, conn->sink->src); + g_warning ("FIXME: autoplugging only possible from GstSpiderIdentity conn->sink yet (yep, that's technical)\n"); + return GST_PAD_CONNECT_REFUSED; +} +/* try to establish the connection using this pad */ +static GstPadConnectReturn +gst_spider_plug_from_srcpad (GstSpiderConnection *conn, GstPad *srcpad) +{ + GstElement *element; GList *plugpath; GList *templist; gboolean result = TRUE; - - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s:%s to %s:%s\n", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); - - /* get src and sink element */ - src = (GstElement *) GST_PAD_PARENT (srcpad); - sink = (GstElement *) GST_PAD_PARENT (sinkpad); + GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src); + GstElement *startelement = conn->current; - /* find a path from src to sink */ - plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (sinkpad), spider->factories); + g_assert ((GstElement *) GST_OBJECT_PARENT (srcpad) == conn->current); + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s:%s to %s\n", GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (conn->src)); + /* find a path from src to sink */ + /* FIXME: make that if go away and work anyway */ + if (srcpad == conn->sink->src) + { + plugpath = gst_autoplug_sp (gst_pad_get_caps ((GstPad *) GST_RPAD_PEER (conn->sink->sink)), gst_pad_get_caps (conn->src->sink), spider->factories); + } else { + plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (conn->src->sink), spider->factories); + } - /* prints out the path that was found for plugging + /* prints out the path that was found for plugging */ + /* g_print ("found path from %s to %s:\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src)); templist = plugpath; while (templist) { g_print("%s\n", GST_OBJECT_NAME (templist->data)); templist = g_list_next (templist); - } */ + }*/ - /* if there is no way to plug: return */ if (plugpath == NULL) { - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to plug from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to plug from %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src)); return GST_PAD_CONNECT_REFUSED; } GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a connection that needs %d elements\n", g_list_length (plugpath)); @@ -489,29 +634,22 @@ gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad) * alter src to point to the new element where we need to start * plugging and alter the plugpath to represent the elements, that must be plugged */ - newsrc = src; - while ((element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC))) + element = conn->current; + while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SRC))) { - newsrc = element; + gst_spider_connection_add (conn, element); plugpath = g_list_delete_link (plugpath, plugpath); } - /* now do the same at the end */ - newsink = sink; - templist = g_list_last (plugpath); - while ((element = gst_spider_find_element_to_plug (newsink, (GstElementFactory *) plugpath->data, GST_PAD_SINK))) - { - GList *cur = templist; - newsink = element; - templist = g_list_previous (templist); - g_list_delete_link (cur, cur); - } GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%d elements must be inserted to establish the connection\n", g_list_length (plugpath)); /* create the elements and plug them */ - result = gst_spider_create_and_plug (spider, newsrc, newsink, plugpath); - - /* free no longer needed data */ - g_list_free (plugpath); + result = gst_spider_create_and_plug (conn, plugpath); + + /* reset the "current" element */ + if (result == GST_PAD_CONNECT_REFUSED) + { + gst_spider_connection_reset (conn, startelement); + } return result; } diff --git a/gst/autoplug/gstspider.h b/gst/autoplug/gstspider.h index 3632992..a59996b 100644 --- a/gst/autoplug/gstspider.h +++ b/gst/autoplug/gstspider.h @@ -32,6 +32,31 @@ extern "C" { extern GstElementDetails gst_spider_details; +/** + * Theory of operation: + * When connecting a sink to a source, GstSpiderConnections are used to keep track + * of the current status of the connection. sink -> src is the path we intend to + * plug. current is how far we've come. If current equals + * - NULL, there is no possible path, + * - src, the connection is established. + * - sink, it wasn't tried to establish a connection. + * - something else, we have come that far while plugging. + * signal_id is used to remember the signal_id when we are waiting for a "new_pad" + * callback during connection. + * When a path is established, the elements in the path (excluding sink and src) + * are refcounted once for every path. + * A GstSpider keeps a list of all GstSpiderConnections in it. + */ +typedef struct { + GstSpiderIdentity *sink; + GstSpiderIdentity *src; + /* dunno if the path should stay here or if its too much load. + * it's at least easier then always searching it */ + GList *path; + GstElement *current; + gulong signal_id; +} GstSpiderConnection; + #define GST_TYPE_SPIDER \ (gst_spider_get_type()) #define GST_SPIDER(obj) \ @@ -49,7 +74,9 @@ typedef struct _GstSpiderClass GstSpiderClass; struct _GstSpider { GstBin parent; - GList * factories; /* factories to use for plugging */ + GList * factories; /* factories to use for plugging */ + + GList * connections; /* GStSpiderConnection list of all connections */ }; struct _GstSpiderClass { @@ -59,8 +86,9 @@ struct _GstSpiderClass { /* default initialization stuff */ GType gst_spider_get_type (void); -/* private functions to be called by GstSpiderIdentity */ -void gst_spider_plug (GstSpiderIdentity *ident); +/* private connection functions to be called by GstSpiderIdentity */ +void gst_spider_identity_plug (GstSpiderIdentity *ident); +void gst_spider_identity_unplug (GstSpiderIdentity *ident); #ifdef __cplusplus diff --git a/gst/autoplug/gstspideridentity.c b/gst/autoplug/gstspideridentity.c index 8d5ce64..f9311f5 100644 --- a/gst/autoplug/gstspideridentity.c +++ b/gst/autoplug/gstspideridentity.c @@ -64,31 +64,30 @@ enum { }; /* GObject stuff */ -static void gst_spider_identity_class_init (GstSpiderIdentityClass *klass); -static void gst_spider_identity_init (GstSpiderIdentity *spider_identity); +static void gst_spider_identity_class_init (GstSpiderIdentityClass *klass); +static void gst_spider_identity_init (GstSpiderIdentity *spider_identity); /* functions set in pads, elements and stuff */ -static void gst_spider_identity_chain (GstPad *pad, GstBuffer *buf); -static GstElementStateReturn gst_spider_identity_change_state (GstElement *element); -static GstPadConnectReturn gst_spider_identity_connect (GstPad *pad, GstCaps *caps); -static GstCaps* gst_spider_identity_getcaps (GstPad *pad, GstCaps *caps); +static void gst_spider_identity_chain (GstPad *pad, GstBuffer *buf); +static GstElementStateReturn gst_spider_identity_change_state (GstElement *element); +static GstPadConnectReturn gst_spider_identity_connect (GstPad *pad, GstCaps *caps); +static GstCaps * gst_spider_identity_getcaps (GstPad *pad, GstCaps *caps); /* loop functions */ -static void gst_spider_identity_dumb_loop (GstSpiderIdentity *ident); -static void gst_spider_identity_src_loop (GstSpiderIdentity *ident); -static void gst_spider_identity_sink_loop_typefinding (GstSpiderIdentity *ident); -static void gst_spider_identity_sink_loop_emptycache (GstSpiderIdentity *ident); +static void gst_spider_identity_dumb_loop (GstSpiderIdentity *ident); +static void gst_spider_identity_src_loop (GstSpiderIdentity *ident); +static void gst_spider_identity_sink_loop_typefinding (GstSpiderIdentity *ident); +static void gst_spider_identity_sink_loop_emptycache (GstSpiderIdentity *ident); /* set/get functions */ -gboolean gst_spider_identity_is_plugged (GstSpiderIdentity *identity); -void gst_spider_identity_set_caps (GstSpiderIdentity *identity, GstCaps *caps); +static void gst_spider_identity_set_caps (GstSpiderIdentity *identity, GstCaps *caps); /* callback */ -static void callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdentity *identity); +static void callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdentity *identity); /* other functions */ -static void gst_spider_identity_start_typefinding (GstSpiderIdentity *ident); +static void gst_spider_identity_start_typefinding (GstSpiderIdentity *ident); -static GstElementClass *parent_class = NULL; +static GstElementClass * parent_class = NULL; /* no signals static guint gst_spider_identity_signals[LAST_SIGNAL] = { 0 }; */ @@ -166,6 +165,7 @@ static void gst_spider_identity_chain (GstPad *pad, GstBuffer *buf) { GstSpiderIdentity *ident; + GstPad *peerpad; /* g_print ("chaining on pad %s:%s with buffer %p\n", GST_DEBUG_PAD_NAME (pad), buf); */ @@ -176,6 +176,25 @@ gst_spider_identity_chain (GstPad *pad, GstBuffer *buf) ident = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad)); if (GST_IS_EVENT (buf)) { + /* start hack for current event stuff here */ + /* check for unconnected elements and send them the EOS event, too */ + if (GST_EVENT_TYPE (GST_EVENT (buf)) == GST_EVENT_EOS) + { + GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident); + GList *list = spider->connections; + while (list) + { + GstSpiderConnection *conn = (GstSpiderConnection *) list->data; + list = g_list_next (list); + if (conn->sink == ident && (GstElement *) conn->src != conn->current) + { + gst_element_set_eos (conn->src); + gst_pad_push (conn->src->src, gst_event_new (GST_EVENT_EOS)); + } + } + } + /* end hack for current event stuff here */ + gst_pad_event_default (ident->sink, GST_EVENT (buf)); return; } @@ -317,13 +336,13 @@ gst_spider_identity_change_state (GstElement *element) gst_spider_identity_start_typefinding (ident); break; } else { - gst_spider_plug (ident); + gst_spider_identity_plug (ident); } } /* autoplug on src */ if ((GST_RPAD_PEER (ident->src) != NULL) && (GST_RPAD_PEER (ident->sink) == NULL)) { - gst_spider_plug (ident); + gst_spider_identity_plug (ident); } default: break; @@ -396,7 +415,7 @@ callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdent gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_sink_loop_emptycache)); /* autoplug this pad */ - gst_spider_plug (ident); + gst_spider_identity_plug (ident); /* restart autoplugger */ if (restart_spider)