mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +00:00
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
This commit is contained in:
parent
e8b452e27c
commit
e149d96faa
4 changed files with 397 additions and 209 deletions
|
@ -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 */
|
||||
|
|
|
@ -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,100 +280,279 @@ 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)
|
||||
{
|
||||
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);
|
||||
|
||||
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))
|
||||
{
|
||||
gst_object_unref ((GstObject *) conn->path->data);
|
||||
conn->path = g_list_delete_link (conn->path, conn->path);
|
||||
}
|
||||
if (conn->path == NULL)
|
||||
{
|
||||
conn->current = (GstElement *) conn->sink;
|
||||
} else {
|
||||
conn->current = to;
|
||||
}
|
||||
}
|
||||
/* add an element to the connection */
|
||||
static void
|
||||
gst_spider_connection_add (GstSpiderConnection *conn, GstElement *element)
|
||||
{
|
||||
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;
|
||||
|
||||
g_assert (spider == (GstSpider *) GST_OBJECT_PARENT (sink));
|
||||
|
||||
while (list)
|
||||
{
|
||||
GstSpiderConnection *conn = (GstSpiderConnection *) list->data;
|
||||
if (conn->src == src && conn->sink == sink)
|
||||
return conn;
|
||||
list = g_list_next(list);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* 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 *padlist;
|
||||
GstPadDirection dir;
|
||||
GstSpiderConnection *conn;
|
||||
|
||||
/* checks */
|
||||
g_return_if_fail (ident != NULL);
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
|
||||
g_assert (spider != NULL);
|
||||
g_assert (GST_IS_SPIDER (spider));
|
||||
|
||||
/* return if we're already plugged */
|
||||
if (ident->plugged) return;
|
||||
|
||||
/* get the direction of our ident */
|
||||
if (GST_PAD_PEER (ident->sink))
|
||||
{
|
||||
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 {
|
||||
dir = GST_PAD_SINK;
|
||||
}
|
||||
} else {
|
||||
if (GST_PAD_PEER (ident->src))
|
||||
{
|
||||
dir = GST_PAD_SRC;
|
||||
} else {
|
||||
/* the ident isn't connected on either side */
|
||||
g_warning ("Trying to autoplug an unconnected element. Aborting...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (padlist->data);
|
||||
GstSpiderIdentity *peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad);
|
||||
/* we only want to connect to the other side */
|
||||
if (dir != GST_PAD_DIRECTION (otherpad))
|
||||
{
|
||||
/* we only connect to plugged in elements */
|
||||
if (peer->plugged == TRUE)
|
||||
{
|
||||
/* plug in the right direction */
|
||||
if (dir == GST_PAD_SINK)
|
||||
{
|
||||
conn = gst_spider_connection_get (ident, peer);
|
||||
} else {
|
||||
conn = gst_spider_connection_get (peer, ident);
|
||||
}
|
||||
if ((GstElement *) conn->sink == conn->current)
|
||||
{
|
||||
gst_spider_plug (conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
padlist = g_list_next (padlist);
|
||||
}
|
||||
|
||||
ident->plugged = TRUE;
|
||||
}
|
||||
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_create_and_plug (GstSpiderConnection *conn, GList *plugpath)
|
||||
{
|
||||
GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->sink);
|
||||
GList *endelements = NULL, *templist = NULL;
|
||||
GstElement *element;
|
||||
|
||||
/* g_print ("C&P: from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); */
|
||||
/* get the next element */
|
||||
if (plugpath == NULL)
|
||||
{
|
||||
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)); */
|
||||
}
|
||||
/* insert and connect new element */
|
||||
if (!gst_element_connect_elements (src, element))
|
||||
{
|
||||
/* 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);
|
||||
/* exit if plugging is already done */
|
||||
if ((GstElement *) conn->src == conn->current)
|
||||
return GST_PAD_CONNECT_DONE;
|
||||
|
||||
/* recursively connect the rest of the elements */
|
||||
if (element != sink) {
|
||||
return gst_spider_create_and_plug (spider, element, sink, plugpath);
|
||||
/* 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;
|
||||
|
@ -382,105 +580,52 @@ gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPad
|
|||
|
||||
return NULL;
|
||||
}
|
||||
/* plugs a pad into the autoplugger if it isn't plugged yet */
|
||||
void
|
||||
gst_spider_plug (GstSpiderIdentity *ident)
|
||||
{
|
||||
GstSpider *spider;
|
||||
GList *plugto;
|
||||
GstPad *plugpad;
|
||||
|
||||
/* checks */
|
||||
g_return_if_fail (ident != NULL);
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
|
||||
g_assert (spider != NULL);
|
||||
g_assert (GST_IS_SPIDER (spider));
|
||||
|
||||
/* return, if we're already plugged */
|
||||
if (ident->plugged) return;
|
||||
|
||||
if (ident->sink && GST_PAD_PEER (ident->sink))
|
||||
{
|
||||
if (ident->src && 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;
|
||||
}
|
||||
} else {
|
||||
if (ident->src && GST_PAD_PEER (ident->src))
|
||||
{
|
||||
plugpad = ident->src;
|
||||
} else {
|
||||
/* the ident isn't connected on either side */
|
||||
g_warning ("Trying to autoplug an unconnected element. Aborting...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* now iterate all possible pads and connect */
|
||||
plugto = gst_element_get_pad_list (GST_ELEMENT (spider));
|
||||
while (plugto)
|
||||
{
|
||||
GstPad *otherpad = (GstPad *) GST_GPAD_REALPAD (plugto->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))
|
||||
{
|
||||
/* we only connect to plugged in elements */
|
||||
if (peer->plugged == TRUE)
|
||||
{
|
||||
/* plug in the right direction */
|
||||
if (plugpad == ident->src)
|
||||
{
|
||||
gst_spider_plug_peers (spider, peer->src, ident->sink);
|
||||
} else {
|
||||
gst_spider_plug_peers (spider, ident->src, peer->sink);
|
||||
}
|
||||
}
|
||||
}
|
||||
plugto = g_list_next (plugto);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
/* try to establish the connection */
|
||||
static GstPadConnectReturn
|
||||
gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad)
|
||||
gst_spider_plug (GstSpiderConnection *conn)
|
||||
{
|
||||
GstElement *element, *src, *sink, *newsrc, *newsink;
|
||||
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;
|
||||
|
||||
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 */
|
||||
plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (sinkpad), spider->factories);
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue