#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);
}
/**
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:
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)
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);
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;
}
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.
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;
}
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;
}
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;
}
/*********************************************************************
*
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;
}
-
-
-
-
-
-
* 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
enum {
ARG_0,
- ARG_PLUGTYPE,
+ ARG_FACTORIES,
/* FILL ME TOO */
};
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);
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),
gst_spider_class_init (GstSpiderClass *klass)
{
GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
+ GstElementClass *gstelement_class;
gobject_class = (GObjectClass*) klass;
gstelement_class = (GstElementClass*) 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)
{
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:
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));
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;
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);
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 */
{
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 = 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))
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);
}
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) {
}
/* 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;
/* 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);
}
}
}
* 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));
+ 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));
- 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);
+ /* 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 (srcpad), gst_pad_get_caps (sinkpad), spider->factories);
- /* 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);
- }
- /* 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);
+ /* 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));
* 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;
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;
}
#include <gst/gst.h>
#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 */
typedef struct _GstSpiderClass GstSpiderClass;
struct _GstSpider {
- GstBin parent;
+ GstBin parent;
- GstSpiderPlugtype plugtype; /* direction to plug */
+ GList * factories; /* factories to use for plugging */
};
struct _GstSpiderClass {
* 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 */
}
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;
}
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;
}
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)
{
}
}
/* 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);
}
{
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)));
{
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
#include <stdlib.h>
#include <gst/gst.h>
+/* 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)
int main(int argc,char *argv[])
{
GstElement *bin, *filesrc, *decoder, *osssink, *videosink;
+ GList *facs;
- if (argc != 2) {
+ if (argc < 2) {
g_print("usage: %s <file>\n", argv[0]);
exit(-1);
}
}
/* 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");