diff --git a/gst/autoplug/gstsearchfuncs.c b/gst/autoplug/gstsearchfuncs.c index 080588f80a..936c0dcbf2 100644 --- a/gst/autoplug/gstsearchfuncs.c +++ b/gst/autoplug/gstsearchfuncs.c @@ -24,18 +24,19 @@ #include "gstsearchfuncs.h" /* function that really misses in GLib + * though the GLib version should take a function as argument... */ void g_list_free_list_and_elements (GList *list) { - GList *walk = list; - - while (walk) - { - g_free (walk->data); - walk = g_list_next (walk); - } - g_list_free (list); + GList *walk = list; + + while (walk) + { + g_free (walk->data); + walk = g_list_next (walk); + } + g_list_free (list); } /** @@ -50,20 +51,20 @@ g_list_free_list_and_elements (GList *list) GstPadTemplate * gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src) { - GList *templs; - - templs = fac->padtemplates; - - while (templs) - { - if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && gst_caps_check_compatibility(src, GST_PADTEMPLATE_CAPS (templs->data))) - { - return GST_PADTEMPLATE (templs->data); - } + GList *templs; + + templs = fac->padtemplates; + + while (templs) + { + if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && gst_caps_check_compatibility(src, GST_PADTEMPLATE_CAPS (templs->data))) + { + return GST_PADTEMPLATE (templs->data); + } templs = g_list_next (templs); - } - - return NULL; + } + + return NULL; } /** * gst_autoplug_can_connect_sink: @@ -77,20 +78,20 @@ gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src) GstPadTemplate * gst_autoplug_can_connect_sink (GstElementFactory *fac, GstCaps *sink) { - GList *templs; - - templs = fac->padtemplates; - - while (templs) - { - if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) && gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (templs->data), sink)) - { - return GST_PADTEMPLATE (templs->data); - } + GList *templs; + + templs = fac->padtemplates; + + while (templs) + { + if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) && gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (templs->data), sink)) + { + return GST_PADTEMPLATE (templs->data); + } templs = g_list_next (templs); - } - - return NULL; + } + + return NULL; } GstPadTemplate * gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest) @@ -113,9 +114,9 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest) gst_padtemplate_get_caps (desttemp))) { GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "factory \"%s\" can connect with factory \"%s\"\n", - GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest)); + GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest)); return desttemp; - } + } } desttemps = g_list_next (desttemps); @@ -123,8 +124,8 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest) srctemps = g_list_next (srctemps); } GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, - "factory \"%s\" cannot connect with factory \"%s\"\n", - GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest)); + "factory \"%s\" cannot connect with factory \"%s\"\n", + GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest)); return NULL; } @@ -132,18 +133,18 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest) gboolean gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir) { - GList *templs = fac->padtemplates; - - while (templs) - { - if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir) - { - return TRUE; - } - templs = g_list_next (templs); - } - - return FALSE; + GList *templs = fac->padtemplates; + + while (templs) + { + if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir) + { + return TRUE; + } + templs = g_list_next (templs); + } + + return FALSE; } /* Decisions are based on the padtemplates. @@ -152,42 +153,42 @@ gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir) GList * gst_autoplug_factories_sinks (GList *factories) { - GList *ret = NULL; - - while (factories) - { - if (gst_autoplug_factory_has_sink (factories->data)) - ret = g_list_prepend (ret, factories->data); - factories = g_list_next (factories); + GList *ret = NULL; + + while (factories) + { + if (gst_autoplug_factory_has_sink (factories->data)) + ret = g_list_prepend (ret, factories->data); + factories = g_list_next (factories); } - return ret; + return ret; } GList * gst_autoplug_factories_srcs (GList *factories) { - GList *ret = NULL; - - while (factories) - { - if (gst_autoplug_factory_has_src (factories->data)) - ret = g_list_prepend (ret, factories->data); - factories = g_list_next (factories); + GList *ret = NULL; + + while (factories) + { + if (gst_autoplug_factory_has_src (factories->data)) + ret = g_list_prepend (ret, factories->data); + factories = g_list_next (factories); } - return ret; + return ret; } -GList * +GList * gst_autoplug_factories_filters (GList *factories) { - GList *ret = NULL; - - while (factories) - { - /* if you want it faster do src/sink check at once, don't call two functions */ - if (gst_autoplug_factory_has_src (factories->data) && gst_autoplug_factory_has_sink (factories->data)) - ret = g_list_prepend (ret, factories->data); - factories = g_list_next (factories); + GList *ret = NULL; + + while (factories) + { + /* if you want it faster do src/sink check at once, don't call two functions */ + if (gst_autoplug_factory_has_src (factories->data) && gst_autoplug_factory_has_sink (factories->data)) + ret = g_list_prepend (ret, factories->data); + factories = g_list_next (factories); } - return ret; + return ret; } @@ -197,33 +198,33 @@ gst_autoplug_factories_filters (GList *factories) GList * gst_autoplug_factories_filters_with_sink_caps (GList *factories) { - GList *ret = NULL; - - while (factories) - { - GList *templs = ((GstElementFactory *) factories->data)->padtemplates; - gboolean have_src = FALSE; - gboolean have_sink = FALSE; - while (templs) - { - if (GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) - { - have_src = TRUE; - } - if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && (GST_PADTEMPLATE_CAPS (templs->data) != NULL)) - { - have_sink = TRUE; - } - if (have_src && have_sink) - { - ret = g_list_prepend (ret, factories->data); - break; - } - templs = g_list_next (templs); - } - factories = g_list_next (factories); - } - return ret; + GList *ret = NULL; + + while (factories) + { + GList *templs = ((GstElementFactory *) factories->data)->padtemplates; + gboolean have_src = FALSE; + gboolean have_sink = FALSE; + while (templs) + { + if (GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) + { + have_src = TRUE; + } + if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && (GST_PADTEMPLATE_CAPS (templs->data) != NULL)) + { + have_sink = TRUE; + } + if (have_src && have_sink) + { + ret = g_list_prepend (ret, factories->data); + break; + } + templs = g_list_next (templs); + } + factories = g_list_next (factories); + } + return ret; } @@ -233,29 +234,29 @@ gst_autoplug_factories_filters_with_sink_caps (GList *factories) GList * gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir, guint maxtemplates) { - GList *ret = NULL; - - while (factories) - { - guint count = 0; - GList *templs = ((GstElementFactory *) factories->data)->padtemplates; + GList *ret = NULL; + + while (factories) + { + guint count = 0; + GList *templs = ((GstElementFactory *) factories->data)->padtemplates; - while (templs) - { - if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir) - { - count++; - } - if (count > maxtemplates) - break; - templs = g_list_next (templs); - } - if (count <= maxtemplates) - ret = g_list_prepend (ret, factories->data); - - factories = g_list_next (factories); - } - return ret; + while (templs) + { + if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir) + { + count++; + } + if (count > maxtemplates) + break; + templs = g_list_next (templs); + } + if (count <= maxtemplates) + ret = g_list_prepend (ret, factories->data); + + factories = g_list_next (factories); + } + return ret; } /********************************************************************* * @@ -275,117 +276,109 @@ gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir, GList * gst_autoplug_sp (GstCaps *srccaps, GstCaps *sinkcaps, GList *factories) { - GList *factory_nodes = NULL; - guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */ - GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */ - - GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, "attempting to autoplug via shortest path"); - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps)); - /* g_print ("trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps)); */ - /* wrap all factories as GstAutoplugNode - * initialize the cost */ - while (factories) - { - GstAutoplugNode *node = g_new0 (GstAutoplugNode, 1); - node->prev = NULL; - node->fac = (GstElementFactory *) factories->data; - node->templ = gst_autoplug_can_connect_src (node->fac, srccaps); - node->cost = (node->templ ? gst_autoplug_get_cost (node->fac) : GST_AUTOPLUG_MAX_COST); - node->endpoint = gst_autoplug_can_connect_sink (node->fac, sinkcaps); - if ((node->endpoint != NULL) && (bestnode == NULL || (node->cost < bestnode->cost))) - { - bestnode = node; - } - factory_nodes = g_list_prepend (factory_nodes, node); - /* make curcost the minimum cost of any plugin */ - curcost = node->cost < curcost ? node->cost : curcost; - factories = g_list_next (factories); - } - - /* check if we even have possible endpoints */ - if (bestnode == NULL) - { - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no factory found that could connect to sink caps\n"); - g_list_free_list_and_elements (factory_nodes); - return NULL; - } - - /* iterate until we found the best path */ - while (curcost < GST_AUTOPLUG_MAX_COST) - { - GList *nodes = factory_nodes; - guint nextcost = GST_AUTOPLUG_MAX_COST; /* next cost to check */ - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "iterating at current cost %d, bestnode %s at %d\n", curcost, GST_OBJECT_NAME (bestnode->fac), bestnode->cost); - /* check if we already have a valid best connection to the sink */ - if (bestnode->cost <= curcost) - { - GList *ret; - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a way to connect via %s\n", GST_OBJECT_NAME ((GstObject *) bestnode->fac)); - /* enter all factories into the return list */ - ret = g_list_prepend (NULL, bestnode->fac); - bestnode = bestnode->prev; - while (bestnode != NULL) - { - ret = g_list_prepend (ret, bestnode->fac); - bestnode = bestnode->prev; - } - g_list_free_list_and_elements (factory_nodes); - return ret; - } - - /* iterate over all factories we have - * if they have the current cost, calculate if this - * factory supplies shorter paths to other elements - */ - while (nodes) - { - if (((GstAutoplugNode *) nodes->data)->cost == curcost) - { - /* now check all elements if we got a shorter path */ - GList *sinknodes = factory_nodes; - GstAutoplugNode *srcnode = (GstAutoplugNode *) nodes->data; - while (sinknodes) - { - GstAutoplugNode *sinknode = (GstAutoplugNode *) sinknodes->data; - GstPadTemplate *templ; - if ((sinknode->cost > srcnode->cost + gst_autoplug_get_cost (sinknode->fac)) && (templ = gst_autoplug_can_match(srcnode->fac, sinknode->fac))) - { - /* we got a shorter path - * now enter that path to that node */ - sinknode->prev = srcnode; - sinknode->templ = templ; - sinknode->cost = srcnode->cost + gst_autoplug_get_cost (sinknode->fac); - /* make sure to set which cost to view next */ - nextcost = (nextcost > sinknode->cost) ? sinknode->cost : nextcost; - /* did we get a new best node? */ - if (sinknode->endpoint && (sinknode->cost < bestnode->cost)) - { - bestnode = sinknode; - } - } - sinknodes = g_list_next (sinknodes); - } - /* FIXME: for speed remove the item we just iterated with from the factory_nodes - * but don't free it yet and don't forget to free it. - */ - } - nodes = g_list_next (nodes); - } - curcost = nextcost; - } - - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found no path from source caps to sink caps\n"); - g_list_free_list_and_elements (factory_nodes); - return NULL; + GList *factory_nodes = NULL; + guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */ + GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */ + + 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 */ + while (factories) + { + GstAutoplugNode *node = g_new0 (GstAutoplugNode, 1); + node->prev = NULL; + node->fac = (GstElementFactory *) factories->data; + node->templ = gst_autoplug_can_connect_src (node->fac, srccaps); + node->cost = (node->templ ? gst_autoplug_get_cost (node->fac) : GST_AUTOPLUG_MAX_COST); + node->endpoint = gst_autoplug_can_connect_sink (node->fac, sinkcaps); + if ((node->endpoint != NULL) && ((bestnode == NULL) || (node->cost < bestnode->cost))) + { + bestnode = node; + } + factory_nodes = g_list_prepend (factory_nodes, node); + /* make curcost the minimum cost of any plugin */ + curcost = node->cost < curcost ? node->cost : curcost; + factories = g_list_next (factories); + } + + /* check if we even have possible endpoints */ + if (bestnode == NULL) + { + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no factory found that could connect to sink caps\n"); + g_list_free_list_and_elements (factory_nodes); + return NULL; + } + + /* iterate until we found the best path */ + while (curcost < GST_AUTOPLUG_MAX_COST) + { + GList *nodes = factory_nodes; + guint nextcost = GST_AUTOPLUG_MAX_COST; /* next cost to check */ + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "iterating at current cost %d, bestnode %s at %d\n", curcost, GST_OBJECT_NAME (bestnode->fac), bestnode->cost); + /* check if we already have a valid best connection to the sink */ + if (bestnode->cost <= curcost) + { + GList *ret; + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a way to connect via %s\n", GST_OBJECT_NAME ((GstObject *) bestnode->fac)); + /* enter all factories into the return list */ + ret = g_list_prepend (NULL, bestnode->fac); + bestnode = bestnode->prev; + while (bestnode != NULL) + { + ret = g_list_prepend (ret, bestnode->fac); + bestnode = bestnode->prev; + } + g_list_free_list_and_elements (factory_nodes); + return ret; + } + + /* iterate over all factories we have + * if they have the current cost, calculate if this + * factory supplies shorter paths to other elements + */ + while (nodes) + { + if (((GstAutoplugNode *) nodes->data)->cost == curcost) + { + /* now check all elements if we got a shorter path */ + GList *sinknodes = factory_nodes; + GstAutoplugNode *srcnode = (GstAutoplugNode *) nodes->data; + while (sinknodes) + { + GstAutoplugNode *sinknode = (GstAutoplugNode *) sinknodes->data; + GstPadTemplate *templ; + if ((sinknode->cost > srcnode->cost + gst_autoplug_get_cost (sinknode->fac)) && (templ = gst_autoplug_can_match(srcnode->fac, sinknode->fac))) + { + /* we got a shorter path + * now enter that path to that node */ + sinknode->prev = srcnode; + sinknode->templ = templ; + sinknode->cost = srcnode->cost + gst_autoplug_get_cost (sinknode->fac); + /* make sure to set which cost to view next */ + nextcost = (nextcost > sinknode->cost) ? sinknode->cost : nextcost; + /* did we get a new best node? */ + if (sinknode->endpoint && (sinknode->cost < bestnode->cost)) + { + bestnode = sinknode; + } + } + sinknodes = g_list_next (sinknodes); + } + /* FIXME: for speed remove the item we just iterated with from the factory_nodes + * but don't free it yet and don't forget to free it. + */ + } + nodes = g_list_next (nodes); + } + curcost = nextcost; + } + + GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found no path from source caps to sink caps\n"); + g_list_free_list_and_elements (factory_nodes); + return NULL; } - - - - - - diff --git a/gst/autoplug/gstspider.c b/gst/autoplug/gstspider.c index a28d9d5837..3b4c811e1d 100644 --- a/gst/autoplug/gstspider.c +++ b/gst/autoplug/gstspider.c @@ -24,7 +24,9 @@ * TODO: * - handle automatic removal of unneeded elements * - make the spider handle and send events (esp. new media) + * - decide if we plug pads or elements, currently it's a mess * - allow disconnecting + * - implement proper saving/loading from xml * - implement a way to allow merging/splitting (aka tee) * - find ways to define which elements to use when plugging * - remove pads @@ -51,7 +53,7 @@ enum { enum { ARG_0, - ARG_PLUGTYPE, + ARG_FACTORIES, /* FILL ME TOO */ }; @@ -70,19 +72,19 @@ GST_PADTEMPLATE_FACTORY (spider_sink_factory, 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); /* autoplugging functions */ -static GstElement * gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir); -static GstPadConnectReturn gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdentity *sink); -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_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad); +static GstPadConnectReturn gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath); /* random functions */ static gchar * gst_spider_unused_elementname (GstBin *bin, const gchar *startwith); @@ -101,9 +103,10 @@ gst_spider_get_type(void) if (!spider_type) { static const GTypeInfo spider_info = { - sizeof(GstSpiderClass), NULL, + sizeof(GstSpiderClass), NULL, - (GClassInitFunc)gst_spider_class_init, + NULL, + (GClassInitFunc) gst_spider_class_init, NULL, NULL, sizeof(GstSpider), @@ -119,7 +122,7 @@ static void gst_spider_class_init (GstSpiderClass *klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; + GstElementClass *gstelement_class; gobject_class = (GObjectClass*) klass; gstelement_class = (GstElementClass*) klass; @@ -127,21 +130,33 @@ gst_spider_class_init (GstSpiderClass *klass) parent_class = g_type_class_ref(GST_TYPE_BIN); /* properties */ - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PLUGTYPE, - g_param_spec_int ("plugtype", "plug direction", "encoding, decoding or anything", - GST_SPIDER_ANY, GST_SPIDER_PLUGTYPES - 1, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FACTORIES, + g_param_spec_pointer ("factories", "allowed factories", "allowed factories for autoplugging", G_PARAM_READWRITE)); gobject_class->set_property = gst_spider_set_property; gobject_class->get_property = gst_spider_get_property; + gobject_class->dispose = gst_spider_dispose; gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_spider_request_new_pad); } static void gst_spider_init (GstSpider *spider) { - spider->plugtype = GST_SPIDER_ANY; + /* 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 ()); } +static void +gst_spider_dispose (GObject *object) +{ + GstSpider *spider; + + spider = GST_SPIDER (object); + g_list_free (spider->factories); + + ((GObjectClass *) parent_class)->dispose (object); +} static GstPad * gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name) { @@ -161,10 +176,12 @@ gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gc case GST_PAD_SRC: padname = gst_spider_unused_elementname ((GstBin *)spider, "src_"); identity = gst_spider_identity_new_src (padname); + returnpad = identity->src; break; case GST_PAD_SINK: padname = gst_spider_unused_elementname ((GstBin *)spider, "sink_"); identity = gst_spider_identity_new_sink (padname); + returnpad = identity->sink; break; case GST_PAD_UNKNOWN: default: @@ -172,9 +189,6 @@ gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gc return NULL; } - /* connect a ghost pad on the right side of the identity and set the requested template */ - returnpad = gst_spider_identity_request_new_pad (GST_ELEMENT (identity), templ, NULL); - /* FIXME: use the requested name for the pad */ gst_object_ref (GST_OBJECT (templ)); @@ -192,32 +206,24 @@ static void gst_spider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstSpider *spider; - + GList *list; + /* it's not null if we got it, but it might not be ours */ g_return_if_fail (GST_IS_SPIDER (object)); spider = GST_SPIDER (object); switch (prop_id) { - case ARG_PLUGTYPE: - switch (g_value_get_int (value)) + case ARG_FACTORIES: + list = (GList *) g_value_get_pointer (value); + while (list) { - case GST_SPIDER_ANY: - spider->plugtype = GST_SPIDER_ANY; - GST_DEBUG (0,"spider: setting plugtype to ANY\n"); - break; - case GST_SPIDER_ENCODE: - spider->plugtype = GST_SPIDER_ENCODE; - GST_DEBUG (0,"spider: setting plugtype to ENCODE\n"); - break; - case GST_SPIDER_DECODE: - spider->plugtype = GST_SPIDER_DECODE; - GST_DEBUG (0,"spider: setting plugtype to DECODE\n"); - break; - default: - GST_DEBUG (0,"spider: invalid value %d while setting plugtype\n", g_value_get_int (value)); - break; + g_return_if_fail (list->data != NULL); + g_return_if_fail (GST_IS_ELEMENTFACTORY (list->data)); + list = g_list_next (list); } + g_list_free (spider->factories); + spider->factories = (GList *) g_value_get_pointer (value); break; default: break; @@ -232,8 +238,8 @@ gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSp spider = GST_SPIDER(object); switch (prop_id) { - case ARG_PLUGTYPE: - g_value_set_int (value, spider->plugtype); + case ARG_FACTORIES: + g_value_set_pointer (value, spider->factories); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -259,26 +265,43 @@ gst_spider_unused_elementname (GstBin *bin, const gchar *startwith) typedef struct { GstSpider *spider; GstElement *sink; - GList *plugpath; gulong signal_id; } GstSpiderConnectSometimes; static void gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnectSometimes *data) { gboolean restart = FALSE; + GstPad *sinkpad; + GList *sinkpads = gst_element_get_pad_list (data->sink); + if (gst_element_get_state ((GstElement *) data->spider) == GST_STATE_PLAYING) { restart = TRUE; gst_element_set_state ((GstElement *) data->spider, GST_STATE_PAUSED); } - gst_spider_create_and_plug (data->spider, src, data->sink, data->plugpath); - g_signal_handler_disconnect (src, data->signal_id); + /* 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 (restart) { gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING); } - g_free (data); - + /* do we need this? */ gst_element_interrupt (src); } /* connects newsrc to newsink using the elementfactories in plugpath */ @@ -287,6 +310,7 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink { 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) { @@ -295,6 +319,7 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink 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)) @@ -314,7 +339,6 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (element)); data->spider = spider; data->sink = sink; - data->plugpath = plugpath; data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad", G_CALLBACK (gst_spider_connect_sometimes), data); @@ -322,12 +346,11 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink } 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 (element)); - g_list_free (plugpath); + 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_delete_link (plugpath, plugpath); + plugpath = g_list_next (plugpath); /* recursively connect the rest of the elements */ if (element != sink) { @@ -361,7 +384,7 @@ gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPad } /* plugs a pad into the autoplugger if it isn't plugged yet */ void -gst_spider_plug (GstSpiderIdentity *ident) +gst_spider_plug (GstSpiderIdentity *ident) { GstSpider *spider; GList *plugto; @@ -413,9 +436,9 @@ gst_spider_plug (GstSpiderIdentity *ident) /* plug in the right direction */ if (plugpad == ident->src) { - gst_spider_plug_peers (spider, peer, ident); + gst_spider_plug_peers (spider, peer->src, ident->sink); } else { - gst_spider_plug_peers (spider, ident, peer); + gst_spider_plug_peers (spider, ident->src, peer->sink); } } } @@ -429,42 +452,36 @@ gst_spider_plug (GstSpiderIdentity *ident) * if no connection was possible */ static GstPadConnectReturn -gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdentity *sink) +gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad) { - GstElement *element, *newsrc, *newsink; - GstPad *pad, *compat; + GstElement *element, *src, *sink, *newsrc, *newsink; GList *plugpath; - GList *neededfactories; GList *templist; gboolean result = TRUE; - GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); - - neededfactories = (GList *) gst_elementfactory_get_list (); - /* use only elements which have sources and sinks and where the sinks have caps */ - neededfactories = gst_autoplug_factories_filters_with_sink_caps (neededfactories); - - /* use only the elements with exactly 1 sink/src when decoding/encoding */ - if (spider->plugtype == GST_SPIDER_ENCODE) - { - templist = neededfactories; - neededfactories = gst_autoplug_factories_at_most_templates (neededfactories, GST_PAD_SRC, 1); - g_list_free (templist); - } - if (spider->plugtype == GST_SPIDER_DECODE) - { - templist = neededfactories; - neededfactories = gst_autoplug_factories_at_most_templates (neededfactories, GST_PAD_SINK, 1); - g_list_free (templist); - } + 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); + /* find a path from src to sink */ - plugpath = gst_autoplug_sp (gst_pad_get_caps ((GstPad *) GST_RPAD_PEER (src->sink)), gst_pad_get_caps ((GstPad *) GST_RPAD_PEER (sink->src)), neededfactories); + plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (sinkpad), spider->factories); + + + /* prints out the path that was found for plugging + 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)); - return FALSE; + return GST_PAD_CONNECT_REFUSED; } GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a connection that needs %d elements\n", g_list_length (plugpath)); @@ -472,16 +489,16 @@ gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdent * 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 = (GstElement *) src; - while (element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC)) + newsrc = src; + while ((element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC))) { newsrc = element; plugpath = g_list_delete_link (plugpath, plugpath); } /* now do the same at the end */ - newsink = (GstElement *) sink; + newsink = sink; templist = g_list_last (plugpath); - while (element = gst_spider_find_element_to_plug (newsink, (GstElementFactory *) plugpath->data, GST_PAD_SINK)) + while ((element = gst_spider_find_element_to_plug (newsink, (GstElementFactory *) plugpath->data, GST_PAD_SINK))) { GList *cur = templist; newsink = element; @@ -494,7 +511,7 @@ gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdent result = gst_spider_create_and_plug (spider, newsrc, newsink, plugpath); /* free no longer needed data */ - g_list_free (neededfactories); + g_list_free (plugpath); return result; } diff --git a/gst/autoplug/gstspider.h b/gst/autoplug/gstspider.h index 695f2b24c0..3632992903 100644 --- a/gst/autoplug/gstspider.h +++ b/gst/autoplug/gstspider.h @@ -26,13 +26,6 @@ #include #include "gstspideridentity.h" -typedef enum { - GST_SPIDER_ANY = 0, - GST_SPIDER_ENCODE = 1, - GST_SPIDER_DECODE = 2, - GST_SPIDER_PLUGTYPES -} GstSpiderPlugtype; - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -54,9 +47,9 @@ typedef struct _GstSpider GstSpider; typedef struct _GstSpiderClass GstSpiderClass; struct _GstSpider { - GstBin parent; + GstBin parent; - GstSpiderPlugtype plugtype; /* direction to plug */ + GList * factories; /* factories to use for plugging */ }; struct _GstSpiderClass { diff --git a/gst/autoplug/gstspideridentity.c b/gst/autoplug/gstspideridentity.c index 3408b8fb0a..6343850e12 100644 --- a/gst/autoplug/gstspideridentity.c +++ b/gst/autoplug/gstspideridentity.c @@ -39,14 +39,14 @@ GstElementDetails gst_spider_identity_details = { * delete me when meging with spider.c */ GST_PADTEMPLATE_FACTORY (spider_src_factory, - "src_%02d", + "src", GST_PAD_SRC, GST_PAD_REQUEST, NULL /* no caps */ ); GST_PADTEMPLATE_FACTORY (spider_sink_factory, - "sink_%02d", + "sink", GST_PAD_SINK, GST_PAD_REQUEST, NULL /* no caps */ @@ -140,18 +140,25 @@ gst_spider_identity_get_bufferpool (GstPad *pad) } static void -gst_spider_identity_init (GstSpiderIdentity *spider_identity) +gst_spider_identity_init (GstSpiderIdentity *ident) { - /* pads */ - spider_identity->sink = NULL; - spider_identity->src = NULL; + /* sink */ + ident->sink = gst_pad_new_from_template (GST_PADTEMPLATE_GET (spider_sink_factory), "sink"); + gst_element_add_pad (GST_ELEMENT (ident), ident->sink); + gst_pad_set_connect_function (ident->sink, GST_DEBUG_FUNCPTR (gst_spider_identity_connect)); + gst_pad_set_getcaps_function (ident->sink, GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps)); + /* src */ + ident->src = gst_pad_new_from_template (GST_PADTEMPLATE_GET (spider_src_factory), "src"); + gst_element_add_pad (GST_ELEMENT (ident), ident->src); + gst_pad_set_connect_function (ident->src, GST_DEBUG_FUNCPTR (gst_spider_identity_connect)); + gst_pad_set_getcaps_function (ident->src, GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps)); /* variables */ - spider_identity->plugged = FALSE; + ident->plugged = FALSE; /* caching */ - spider_identity->cache_start = NULL; - spider_identity->cache_end = NULL; + ident->cache_start = NULL; + ident->cache_end = NULL; } @@ -198,6 +205,9 @@ gst_spider_identity_new_sink (gchar *name) GST_ELEMENT_NAME (ret) = name; + /* set the right functions */ + gst_element_set_loop_function (GST_ELEMENT (ret), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop)); + return ret; } @@ -300,7 +310,7 @@ gst_spider_identity_change_state (GstElement *element) switch (GST_STATE_TRANSITION (element)) { case GST_STATE_PAUSED_TO_PLAYING: /* start typefinding or plugging */ - if ((ident->sink != NULL) && (ident->src == NULL)) + if ((GST_RPAD_PEER (ident->sink) != NULL) && (GST_RPAD_PEER (ident->src) == NULL)) { if (gst_pad_get_caps ((GstPad *) GST_PAD_PEER (ident->sink)) == NULL) { @@ -311,7 +321,7 @@ gst_spider_identity_change_state (GstElement *element) } } /* autoplug on src */ - if ((ident->src != NULL) && (ident->sink == NULL)) + if ((GST_RPAD_PEER (ident->src) != NULL) && (GST_RPAD_PEER (ident->sink) == NULL)) { gst_spider_plug (ident); } @@ -330,7 +340,7 @@ gst_spider_identity_start_typefinding (GstSpiderIdentity *ident) { GstElement* typefind; - GST_DEBUG (GST_CAT_AUTOPLUG, "element %s starts typefinding", GST_ELEMENT_NAME(ident)); + GST_DEBUG (GST_CAT_AUTOPLUG, "element %s starts typefinding\n", GST_ELEMENT_NAME(ident)); /* create and connect typefind object */ typefind = gst_elementfactory_make ("typefind", g_strdup_printf("%s%s", "typefind", GST_ELEMENT_NAME(ident))); @@ -362,7 +372,7 @@ callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdent { gboolean restart_spider = FALSE; - GST_INFO (GST_CAT_AUTOPLUG, "element %s has found caps", GST_ELEMENT_NAME(ident)); + GST_INFO (GST_CAT_AUTOPLUG, "element %s has found caps\n", GST_ELEMENT_NAME(ident)); /* checks */ /* we have to ref the typefind, because if me remove it the scheduler segfaults diff --git a/gst/autoplug/spidertest.c b/gst/autoplug/spidertest.c index 8b97444ad9..4ae09f61f0 100644 --- a/gst/autoplug/spidertest.c +++ b/gst/autoplug/spidertest.c @@ -1,6 +1,36 @@ #include #include +/* returns all factories which have a maximum of maxtemplates GstPadTemplates in direction dir + */ +GList * +gst_factories_at_most_templates(GList *factories, GstPadDirection dir, guint maxtemplates) +{ + GList *ret = NULL; + + while (factories) + { + guint count = 0; + GList *templs = ((GstElementFactory *) factories->data)->padtemplates; + + while (templs) + { + if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir) + { + count++; + } + if (count > maxtemplates) + break; + templs = g_list_next (templs); + } + if (count <= maxtemplates) + ret = g_list_prepend (ret, factories->data); + + factories = g_list_next (factories); + } + return ret; +} + /* 1:1 copy of gstpropsprivate.h, needed for INFO events */ #define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID) @@ -87,8 +117,9 @@ event_func (GstElement *element, GstEvent *event) int main(int argc,char *argv[]) { GstElement *bin, *filesrc, *decoder, *osssink, *videosink; + GList *facs; - if (argc != 2) { + if (argc < 2) { g_print("usage: %s \n", argv[0]); exit(-1); } @@ -111,7 +142,9 @@ int main(int argc,char *argv[]) } /* only use decoding plugins */ - g_object_set(G_OBJECT(decoder),"plugtype", 2, NULL); + g_object_get (decoder, "factories", &facs, NULL); + facs = gst_factories_at_most_templates(facs, GST_PAD_SINK, 1); + g_object_set (decoder, "factories", facs, NULL); /* create video and audio sink */ osssink = gst_elementfactory_make("osssink", "audio");