mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
- use autoplugging instead of predefined way on sometimes pads
Original commit message from CVS: - use autoplugging instead of predefined way on sometimes pads - exchange plugtype with factories in the spider - revamp the spider, now messier than before... - bugfixing - style corrections
This commit is contained in:
parent
a9e40dee74
commit
b97f4f91c8
5 changed files with 385 additions and 339 deletions
|
@ -24,18 +24,19 @@
|
||||||
#include "gstsearchfuncs.h"
|
#include "gstsearchfuncs.h"
|
||||||
|
|
||||||
/* function that really misses in GLib
|
/* function that really misses in GLib
|
||||||
|
* though the GLib version should take a function as argument...
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
g_list_free_list_and_elements (GList *list)
|
g_list_free_list_and_elements (GList *list)
|
||||||
{
|
{
|
||||||
GList *walk = list;
|
GList *walk = list;
|
||||||
|
|
||||||
while (walk)
|
while (walk)
|
||||||
{
|
{
|
||||||
g_free (walk->data);
|
g_free (walk->data);
|
||||||
walk = g_list_next (walk);
|
walk = g_list_next (walk);
|
||||||
}
|
}
|
||||||
g_list_free (list);
|
g_list_free (list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,20 +51,20 @@ g_list_free_list_and_elements (GList *list)
|
||||||
GstPadTemplate *
|
GstPadTemplate *
|
||||||
gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src)
|
gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src)
|
||||||
{
|
{
|
||||||
GList *templs;
|
GList *templs;
|
||||||
|
|
||||||
templs = fac->padtemplates;
|
templs = fac->padtemplates;
|
||||||
|
|
||||||
while (templs)
|
while (templs)
|
||||||
{
|
{
|
||||||
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && gst_caps_check_compatibility(src, GST_PADTEMPLATE_CAPS (templs->data)))
|
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && gst_caps_check_compatibility(src, GST_PADTEMPLATE_CAPS (templs->data)))
|
||||||
{
|
{
|
||||||
return GST_PADTEMPLATE (templs->data);
|
return GST_PADTEMPLATE (templs->data);
|
||||||
}
|
}
|
||||||
templs = g_list_next (templs);
|
templs = g_list_next (templs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* gst_autoplug_can_connect_sink:
|
* gst_autoplug_can_connect_sink:
|
||||||
|
@ -77,20 +78,20 @@ gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src)
|
||||||
GstPadTemplate *
|
GstPadTemplate *
|
||||||
gst_autoplug_can_connect_sink (GstElementFactory *fac, GstCaps *sink)
|
gst_autoplug_can_connect_sink (GstElementFactory *fac, GstCaps *sink)
|
||||||
{
|
{
|
||||||
GList *templs;
|
GList *templs;
|
||||||
|
|
||||||
templs = fac->padtemplates;
|
templs = fac->padtemplates;
|
||||||
|
|
||||||
while (templs)
|
while (templs)
|
||||||
{
|
{
|
||||||
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) && gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (templs->data), sink))
|
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) && gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (templs->data), sink))
|
||||||
{
|
{
|
||||||
return GST_PADTEMPLATE (templs->data);
|
return GST_PADTEMPLATE (templs->data);
|
||||||
}
|
}
|
||||||
templs = g_list_next (templs);
|
templs = g_list_next (templs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
GstPadTemplate *
|
GstPadTemplate *
|
||||||
gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
|
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_padtemplate_get_caps (desttemp))) {
|
||||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||||
"factory \"%s\" can connect with factory \"%s\"\n",
|
"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;
|
return desttemp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
desttemps = g_list_next (desttemps);
|
desttemps = g_list_next (desttemps);
|
||||||
|
@ -123,8 +124,8 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
|
||||||
srctemps = g_list_next (srctemps);
|
srctemps = g_list_next (srctemps);
|
||||||
}
|
}
|
||||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||||
"factory \"%s\" cannot connect with factory \"%s\"\n",
|
"factory \"%s\" cannot connect with factory \"%s\"\n",
|
||||||
GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
|
GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,18 +133,18 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
|
||||||
gboolean
|
gboolean
|
||||||
gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir)
|
gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir)
|
||||||
{
|
{
|
||||||
GList *templs = fac->padtemplates;
|
GList *templs = fac->padtemplates;
|
||||||
|
|
||||||
while (templs)
|
while (templs)
|
||||||
{
|
{
|
||||||
if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
|
if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
|
||||||
{
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
templs = g_list_next (templs);
|
templs = g_list_next (templs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decisions are based on the padtemplates.
|
/* Decisions are based on the padtemplates.
|
||||||
|
@ -152,42 +153,42 @@ gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir)
|
||||||
GList *
|
GList *
|
||||||
gst_autoplug_factories_sinks (GList *factories)
|
gst_autoplug_factories_sinks (GList *factories)
|
||||||
{
|
{
|
||||||
GList *ret = NULL;
|
GList *ret = NULL;
|
||||||
|
|
||||||
while (factories)
|
while (factories)
|
||||||
{
|
{
|
||||||
if (gst_autoplug_factory_has_sink (factories->data))
|
if (gst_autoplug_factory_has_sink (factories->data))
|
||||||
ret = g_list_prepend (ret, factories->data);
|
ret = g_list_prepend (ret, factories->data);
|
||||||
factories = g_list_next (factories);
|
factories = g_list_next (factories);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
GList *
|
GList *
|
||||||
gst_autoplug_factories_srcs (GList *factories)
|
gst_autoplug_factories_srcs (GList *factories)
|
||||||
{
|
{
|
||||||
GList *ret = NULL;
|
GList *ret = NULL;
|
||||||
|
|
||||||
while (factories)
|
while (factories)
|
||||||
{
|
{
|
||||||
if (gst_autoplug_factory_has_src (factories->data))
|
if (gst_autoplug_factory_has_src (factories->data))
|
||||||
ret = g_list_prepend (ret, factories->data);
|
ret = g_list_prepend (ret, factories->data);
|
||||||
factories = g_list_next (factories);
|
factories = g_list_next (factories);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
GList *
|
GList *
|
||||||
gst_autoplug_factories_filters (GList *factories)
|
gst_autoplug_factories_filters (GList *factories)
|
||||||
{
|
{
|
||||||
GList *ret = NULL;
|
GList *ret = NULL;
|
||||||
|
|
||||||
while (factories)
|
while (factories)
|
||||||
{
|
{
|
||||||
/* if you want it faster do src/sink check at once, don't call two functions */
|
/* 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))
|
if (gst_autoplug_factory_has_src (factories->data) && gst_autoplug_factory_has_sink (factories->data))
|
||||||
ret = g_list_prepend (ret, factories->data);
|
ret = g_list_prepend (ret, factories->data);
|
||||||
factories = g_list_next (factories);
|
factories = g_list_next (factories);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,33 +198,33 @@ gst_autoplug_factories_filters (GList *factories)
|
||||||
GList *
|
GList *
|
||||||
gst_autoplug_factories_filters_with_sink_caps (GList *factories)
|
gst_autoplug_factories_filters_with_sink_caps (GList *factories)
|
||||||
{
|
{
|
||||||
GList *ret = NULL;
|
GList *ret = NULL;
|
||||||
|
|
||||||
while (factories)
|
while (factories)
|
||||||
{
|
{
|
||||||
GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
|
GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
|
||||||
gboolean have_src = FALSE;
|
gboolean have_src = FALSE;
|
||||||
gboolean have_sink = FALSE;
|
gboolean have_sink = FALSE;
|
||||||
while (templs)
|
while (templs)
|
||||||
{
|
{
|
||||||
if (GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC)
|
if (GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC)
|
||||||
{
|
{
|
||||||
have_src = TRUE;
|
have_src = TRUE;
|
||||||
}
|
}
|
||||||
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && (GST_PADTEMPLATE_CAPS (templs->data) != NULL))
|
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && (GST_PADTEMPLATE_CAPS (templs->data) != NULL))
|
||||||
{
|
{
|
||||||
have_sink = TRUE;
|
have_sink = TRUE;
|
||||||
}
|
}
|
||||||
if (have_src && have_sink)
|
if (have_src && have_sink)
|
||||||
{
|
{
|
||||||
ret = g_list_prepend (ret, factories->data);
|
ret = g_list_prepend (ret, factories->data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
templs = g_list_next (templs);
|
templs = g_list_next (templs);
|
||||||
}
|
}
|
||||||
factories = g_list_next (factories);
|
factories = g_list_next (factories);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,29 +234,29 @@ gst_autoplug_factories_filters_with_sink_caps (GList *factories)
|
||||||
GList *
|
GList *
|
||||||
gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir, guint maxtemplates)
|
gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir, guint maxtemplates)
|
||||||
{
|
{
|
||||||
GList *ret = NULL;
|
GList *ret = NULL;
|
||||||
|
|
||||||
while (factories)
|
while (factories)
|
||||||
{
|
{
|
||||||
guint count = 0;
|
guint count = 0;
|
||||||
GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
|
GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
|
||||||
|
|
||||||
while (templs)
|
while (templs)
|
||||||
{
|
{
|
||||||
if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
|
if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (count > maxtemplates)
|
if (count > maxtemplates)
|
||||||
break;
|
break;
|
||||||
templs = g_list_next (templs);
|
templs = g_list_next (templs);
|
||||||
}
|
}
|
||||||
if (count <= maxtemplates)
|
if (count <= maxtemplates)
|
||||||
ret = g_list_prepend (ret, factories->data);
|
ret = g_list_prepend (ret, factories->data);
|
||||||
|
|
||||||
factories = g_list_next (factories);
|
factories = g_list_next (factories);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
*
|
*
|
||||||
|
@ -275,117 +276,109 @@ gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir,
|
||||||
GList *
|
GList *
|
||||||
gst_autoplug_sp (GstCaps *srccaps, GstCaps *sinkcaps, GList *factories)
|
gst_autoplug_sp (GstCaps *srccaps, GstCaps *sinkcaps, GList *factories)
|
||||||
{
|
{
|
||||||
GList *factory_nodes = NULL;
|
GList *factory_nodes = NULL;
|
||||||
guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */
|
guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */
|
||||||
GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */
|
GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */
|
||||||
|
|
||||||
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, "attempting to autoplug via shortest path");
|
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));
|
||||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps));
|
/* wrap all factories as GstAutoplugNode
|
||||||
/* g_print ("trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps)); */
|
* initialize the cost */
|
||||||
/* wrap all factories as GstAutoplugNode
|
while (factories)
|
||||||
* initialize the cost */
|
{
|
||||||
while (factories)
|
GstAutoplugNode *node = g_new0 (GstAutoplugNode, 1);
|
||||||
{
|
node->prev = NULL;
|
||||||
GstAutoplugNode *node = g_new0 (GstAutoplugNode, 1);
|
node->fac = (GstElementFactory *) factories->data;
|
||||||
node->prev = NULL;
|
node->templ = gst_autoplug_can_connect_src (node->fac, srccaps);
|
||||||
node->fac = (GstElementFactory *) factories->data;
|
node->cost = (node->templ ? gst_autoplug_get_cost (node->fac) : GST_AUTOPLUG_MAX_COST);
|
||||||
node->templ = gst_autoplug_can_connect_src (node->fac, srccaps);
|
node->endpoint = gst_autoplug_can_connect_sink (node->fac, sinkcaps);
|
||||||
node->cost = (node->templ ? gst_autoplug_get_cost (node->fac) : GST_AUTOPLUG_MAX_COST);
|
if ((node->endpoint != NULL) && ((bestnode == NULL) || (node->cost < bestnode->cost)))
|
||||||
node->endpoint = gst_autoplug_can_connect_sink (node->fac, sinkcaps);
|
{
|
||||||
if ((node->endpoint != NULL) && (bestnode == NULL || (node->cost < bestnode->cost)))
|
bestnode = node;
|
||||||
{
|
}
|
||||||
bestnode = node;
|
factory_nodes = g_list_prepend (factory_nodes, node);
|
||||||
}
|
/* make curcost the minimum cost of any plugin */
|
||||||
factory_nodes = g_list_prepend (factory_nodes, node);
|
curcost = node->cost < curcost ? node->cost : curcost;
|
||||||
/* make curcost the minimum cost of any plugin */
|
factories = g_list_next (factories);
|
||||||
curcost = node->cost < curcost ? node->cost : curcost;
|
}
|
||||||
factories = g_list_next (factories);
|
|
||||||
}
|
/* check if we even have possible endpoints */
|
||||||
|
if (bestnode == NULL)
|
||||||
/* 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);
|
||||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no factory found that could connect to sink caps\n");
|
return NULL;
|
||||||
g_list_free_list_and_elements (factory_nodes);
|
}
|
||||||
return NULL;
|
|
||||||
}
|
/* iterate until we found the best path */
|
||||||
|
while (curcost < GST_AUTOPLUG_MAX_COST)
|
||||||
/* 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 */
|
||||||
GList *nodes = factory_nodes;
|
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "iterating at current cost %d, bestnode %s at %d\n", curcost, GST_OBJECT_NAME (bestnode->fac), bestnode->cost);
|
||||||
guint nextcost = GST_AUTOPLUG_MAX_COST; /* next cost to check */
|
/* check if we already have a valid best connection to the sink */
|
||||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "iterating at current cost %d, bestnode %s at %d\n", curcost, GST_OBJECT_NAME (bestnode->fac), bestnode->cost);
|
if (bestnode->cost <= curcost)
|
||||||
/* 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));
|
||||||
GList *ret;
|
/* enter all factories into the return list */
|
||||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a way to connect via %s\n", GST_OBJECT_NAME ((GstObject *) bestnode->fac));
|
ret = g_list_prepend (NULL, bestnode->fac);
|
||||||
/* enter all factories into the return list */
|
bestnode = bestnode->prev;
|
||||||
ret = g_list_prepend (NULL, bestnode->fac);
|
while (bestnode != NULL)
|
||||||
bestnode = bestnode->prev;
|
{
|
||||||
while (bestnode != NULL)
|
ret = g_list_prepend (ret, bestnode->fac);
|
||||||
{
|
bestnode = bestnode->prev;
|
||||||
ret = g_list_prepend (ret, bestnode->fac);
|
}
|
||||||
bestnode = bestnode->prev;
|
g_list_free_list_and_elements (factory_nodes);
|
||||||
}
|
return ret;
|
||||||
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
|
||||||
/* iterate over all factories we have
|
* factory supplies shorter paths to other elements
|
||||||
* if they have the current cost, calculate if this
|
*/
|
||||||
* factory supplies shorter paths to other elements
|
while (nodes)
|
||||||
*/
|
{
|
||||||
while (nodes)
|
if (((GstAutoplugNode *) nodes->data)->cost == curcost)
|
||||||
{
|
{
|
||||||
if (((GstAutoplugNode *) nodes->data)->cost == curcost)
|
/* now check all elements if we got a shorter path */
|
||||||
{
|
GList *sinknodes = factory_nodes;
|
||||||
/* now check all elements if we got a shorter path */
|
GstAutoplugNode *srcnode = (GstAutoplugNode *) nodes->data;
|
||||||
GList *sinknodes = factory_nodes;
|
while (sinknodes)
|
||||||
GstAutoplugNode *srcnode = (GstAutoplugNode *) nodes->data;
|
{
|
||||||
while (sinknodes)
|
GstAutoplugNode *sinknode = (GstAutoplugNode *) sinknodes->data;
|
||||||
{
|
GstPadTemplate *templ;
|
||||||
GstAutoplugNode *sinknode = (GstAutoplugNode *) sinknodes->data;
|
if ((sinknode->cost > srcnode->cost + gst_autoplug_get_cost (sinknode->fac)) && (templ = gst_autoplug_can_match(srcnode->fac, sinknode->fac)))
|
||||||
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 */
|
||||||
/* we got a shorter path
|
sinknode->prev = srcnode;
|
||||||
* now enter that path to that node */
|
sinknode->templ = templ;
|
||||||
sinknode->prev = srcnode;
|
sinknode->cost = srcnode->cost + gst_autoplug_get_cost (sinknode->fac);
|
||||||
sinknode->templ = templ;
|
/* make sure to set which cost to view next */
|
||||||
sinknode->cost = srcnode->cost + gst_autoplug_get_cost (sinknode->fac);
|
nextcost = (nextcost > sinknode->cost) ? sinknode->cost : nextcost;
|
||||||
/* make sure to set which cost to view next */
|
/* did we get a new best node? */
|
||||||
nextcost = (nextcost > sinknode->cost) ? sinknode->cost : nextcost;
|
if (sinknode->endpoint && (sinknode->cost < bestnode->cost))
|
||||||
/* did we get a new best node? */
|
{
|
||||||
if (sinknode->endpoint && (sinknode->cost < bestnode->cost))
|
bestnode = sinknode;
|
||||||
{
|
}
|
||||||
bestnode = sinknode;
|
}
|
||||||
}
|
sinknodes = g_list_next (sinknodes);
|
||||||
}
|
}
|
||||||
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.
|
||||||
/* 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);
|
||||||
}
|
}
|
||||||
nodes = g_list_next (nodes);
|
curcost = nextcost;
|
||||||
}
|
}
|
||||||
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);
|
||||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found no path from source caps to sink caps\n");
|
return NULL;
|
||||||
g_list_free_list_and_elements (factory_nodes);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
* TODO:
|
* TODO:
|
||||||
* - handle automatic removal of unneeded elements
|
* - handle automatic removal of unneeded elements
|
||||||
* - make the spider handle and send events (esp. new media)
|
* - make the spider handle and send events (esp. new media)
|
||||||
|
* - decide if we plug pads or elements, currently it's a mess
|
||||||
* - allow disconnecting
|
* - allow disconnecting
|
||||||
|
* - implement proper saving/loading from xml
|
||||||
* - implement a way to allow merging/splitting (aka tee)
|
* - implement a way to allow merging/splitting (aka tee)
|
||||||
* - find ways to define which elements to use when plugging
|
* - find ways to define which elements to use when plugging
|
||||||
* - remove pads
|
* - remove pads
|
||||||
|
@ -51,7 +53,7 @@ enum {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ARG_0,
|
ARG_0,
|
||||||
ARG_PLUGTYPE,
|
ARG_FACTORIES,
|
||||||
/* FILL ME TOO */
|
/* FILL ME TOO */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,19 +72,19 @@ GST_PADTEMPLATE_FACTORY (spider_sink_factory,
|
||||||
NULL /* no caps */
|
NULL /* no caps */
|
||||||
);
|
);
|
||||||
/* standard GObject stuff */
|
/* standard GObject stuff */
|
||||||
static void gst_spider_class_init (GstSpiderClass *klass);
|
static void gst_spider_class_init (GstSpiderClass *klass);
|
||||||
static void gst_spider_init (GstSpider *spider);
|
static void gst_spider_init (GstSpider *spider);
|
||||||
static void gst_spider_dispose (GObject *object);
|
static void gst_spider_dispose (GObject *object);
|
||||||
|
|
||||||
/* element class functions */
|
/* element class functions */
|
||||||
static GstPad* gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name);
|
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_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 void gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
|
||||||
|
|
||||||
/* autoplugging functions */
|
/* autoplugging functions */
|
||||||
static GstElement * gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir);
|
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_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad);
|
||||||
static GstPadConnectReturn gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath);
|
static GstPadConnectReturn gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath);
|
||||||
|
|
||||||
/* random functions */
|
/* random functions */
|
||||||
static gchar * gst_spider_unused_elementname (GstBin *bin, const gchar *startwith);
|
static gchar * gst_spider_unused_elementname (GstBin *bin, const gchar *startwith);
|
||||||
|
@ -101,9 +103,10 @@ gst_spider_get_type(void)
|
||||||
|
|
||||||
if (!spider_type) {
|
if (!spider_type) {
|
||||||
static const GTypeInfo spider_info = {
|
static const GTypeInfo spider_info = {
|
||||||
sizeof(GstSpiderClass), NULL,
|
sizeof(GstSpiderClass),
|
||||||
NULL,
|
NULL,
|
||||||
(GClassInitFunc)gst_spider_class_init,
|
NULL,
|
||||||
|
(GClassInitFunc) gst_spider_class_init,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
sizeof(GstSpider),
|
sizeof(GstSpider),
|
||||||
|
@ -119,7 +122,7 @@ static void
|
||||||
gst_spider_class_init (GstSpiderClass *klass)
|
gst_spider_class_init (GstSpiderClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass*) klass;
|
gobject_class = (GObjectClass*) klass;
|
||||||
gstelement_class = (GstElementClass*) klass;
|
gstelement_class = (GstElementClass*) klass;
|
||||||
|
@ -127,21 +130,33 @@ gst_spider_class_init (GstSpiderClass *klass)
|
||||||
parent_class = g_type_class_ref(GST_TYPE_BIN);
|
parent_class = g_type_class_ref(GST_TYPE_BIN);
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PLUGTYPE,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FACTORIES,
|
||||||
g_param_spec_int ("plugtype", "plug direction", "encoding, decoding or anything",
|
g_param_spec_pointer ("factories", "allowed factories", "allowed factories for autoplugging", G_PARAM_READWRITE));
|
||||||
GST_SPIDER_ANY, GST_SPIDER_PLUGTYPES - 1, 0, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gobject_class->set_property = gst_spider_set_property;
|
gobject_class->set_property = gst_spider_set_property;
|
||||||
gobject_class->get_property = gst_spider_get_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);
|
gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_spider_request_new_pad);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
gst_spider_init (GstSpider *spider)
|
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 *
|
static GstPad *
|
||||||
gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name)
|
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:
|
case GST_PAD_SRC:
|
||||||
padname = gst_spider_unused_elementname ((GstBin *)spider, "src_");
|
padname = gst_spider_unused_elementname ((GstBin *)spider, "src_");
|
||||||
identity = gst_spider_identity_new_src (padname);
|
identity = gst_spider_identity_new_src (padname);
|
||||||
|
returnpad = identity->src;
|
||||||
break;
|
break;
|
||||||
case GST_PAD_SINK:
|
case GST_PAD_SINK:
|
||||||
padname = gst_spider_unused_elementname ((GstBin *)spider, "sink_");
|
padname = gst_spider_unused_elementname ((GstBin *)spider, "sink_");
|
||||||
identity = gst_spider_identity_new_sink (padname);
|
identity = gst_spider_identity_new_sink (padname);
|
||||||
|
returnpad = identity->sink;
|
||||||
break;
|
break;
|
||||||
case GST_PAD_UNKNOWN:
|
case GST_PAD_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
|
@ -172,9 +189,6 @@ gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gc
|
||||||
return NULL;
|
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 */
|
/* FIXME: use the requested name for the pad */
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (templ));
|
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)
|
gst_spider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
GstSpider *spider;
|
GstSpider *spider;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
/* it's not null if we got it, but it might not be ours */
|
/* it's not null if we got it, but it might not be ours */
|
||||||
g_return_if_fail (GST_IS_SPIDER (object));
|
g_return_if_fail (GST_IS_SPIDER (object));
|
||||||
|
|
||||||
spider = GST_SPIDER (object);
|
spider = GST_SPIDER (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_PLUGTYPE:
|
case ARG_FACTORIES:
|
||||||
switch (g_value_get_int (value))
|
list = (GList *) g_value_get_pointer (value);
|
||||||
|
while (list)
|
||||||
{
|
{
|
||||||
case GST_SPIDER_ANY:
|
g_return_if_fail (list->data != NULL);
|
||||||
spider->plugtype = GST_SPIDER_ANY;
|
g_return_if_fail (GST_IS_ELEMENTFACTORY (list->data));
|
||||||
GST_DEBUG (0,"spider: setting plugtype to ANY\n");
|
list = g_list_next (list);
|
||||||
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_list_free (spider->factories);
|
||||||
|
spider->factories = (GList *) g_value_get_pointer (value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -232,8 +238,8 @@ gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
|
||||||
spider = GST_SPIDER(object);
|
spider = GST_SPIDER(object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_PLUGTYPE:
|
case ARG_FACTORIES:
|
||||||
g_value_set_int (value, spider->plugtype);
|
g_value_set_pointer (value, spider->factories);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
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 {
|
typedef struct {
|
||||||
GstSpider *spider;
|
GstSpider *spider;
|
||||||
GstElement *sink;
|
GstElement *sink;
|
||||||
GList *plugpath;
|
|
||||||
gulong signal_id;
|
gulong signal_id;
|
||||||
} GstSpiderConnectSometimes;
|
} GstSpiderConnectSometimes;
|
||||||
static void
|
static void
|
||||||
gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnectSometimes *data)
|
gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnectSometimes *data)
|
||||||
{
|
{
|
||||||
gboolean restart = FALSE;
|
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)
|
if (gst_element_get_state ((GstElement *) data->spider) == GST_STATE_PLAYING)
|
||||||
{
|
{
|
||||||
restart = TRUE;
|
restart = TRUE;
|
||||||
gst_element_set_state ((GstElement *) data->spider, GST_STATE_PAUSED);
|
gst_element_set_state ((GstElement *) data->spider, GST_STATE_PAUSED);
|
||||||
}
|
}
|
||||||
gst_spider_create_and_plug (data->spider, src, data->sink, data->plugpath);
|
/* try to autoplug the elements */
|
||||||
g_signal_handler_disconnect (src, data->signal_id);
|
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)
|
if (restart)
|
||||||
{
|
{
|
||||||
gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING);
|
gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING);
|
||||||
}
|
}
|
||||||
g_free (data);
|
/* do we need this? */
|
||||||
|
|
||||||
gst_element_interrupt (src);
|
gst_element_interrupt (src);
|
||||||
}
|
}
|
||||||
/* connects newsrc to newsink using the elementfactories in plugpath */
|
/* 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;
|
GstElement *element;
|
||||||
|
|
||||||
|
/* g_print ("C&P: from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); */
|
||||||
/* get the next element */
|
/* get the next element */
|
||||||
if (plugpath == NULL)
|
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,
|
element = gst_elementfactory_create ((GstElementFactory *) plugpath->data,
|
||||||
gst_spider_unused_elementname (GST_BIN (spider), GST_OBJECT_NAME (plugpath->data)));
|
gst_spider_unused_elementname (GST_BIN (spider), GST_OBJECT_NAME (plugpath->data)));
|
||||||
gst_bin_add (GST_BIN (spider), element);
|
gst_bin_add (GST_BIN (spider), element);
|
||||||
|
/* g_print ("C&P: trying element %s\n", GST_ELEMENT_NAME (element)); */
|
||||||
}
|
}
|
||||||
/* insert and connect new element */
|
/* insert and connect new element */
|
||||||
if (!gst_element_connect_elements (src, 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));
|
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->spider = spider;
|
||||||
data->sink = sink;
|
data->sink = sink;
|
||||||
data->plugpath = plugpath;
|
|
||||||
data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad",
|
data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad",
|
||||||
G_CALLBACK (gst_spider_connect_sometimes), data);
|
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);
|
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));
|
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
|
||||||
g_list_free (plugpath);
|
|
||||||
return GST_PAD_CONNECT_REFUSED;
|
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));
|
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 */
|
/* recursively connect the rest of the elements */
|
||||||
if (element != sink) {
|
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 */
|
/* plugs a pad into the autoplugger if it isn't plugged yet */
|
||||||
void
|
void
|
||||||
gst_spider_plug (GstSpiderIdentity *ident)
|
gst_spider_plug (GstSpiderIdentity *ident)
|
||||||
{
|
{
|
||||||
GstSpider *spider;
|
GstSpider *spider;
|
||||||
GList *plugto;
|
GList *plugto;
|
||||||
|
@ -413,9 +436,9 @@ gst_spider_plug (GstSpiderIdentity *ident)
|
||||||
/* plug in the right direction */
|
/* plug in the right direction */
|
||||||
if (plugpad == ident->src)
|
if (plugpad == ident->src)
|
||||||
{
|
{
|
||||||
gst_spider_plug_peers (spider, peer, ident);
|
gst_spider_plug_peers (spider, peer->src, ident->sink);
|
||||||
} else {
|
} 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
|
* if no connection was possible
|
||||||
*/
|
*/
|
||||||
static GstPadConnectReturn
|
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;
|
GstElement *element, *src, *sink, *newsrc, *newsink;
|
||||||
GstPad *pad, *compat;
|
|
||||||
GList *plugpath;
|
GList *plugpath;
|
||||||
GList *neededfactories;
|
|
||||||
GList *templist;
|
GList *templist;
|
||||||
gboolean result = TRUE;
|
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);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* get src and sink element */
|
||||||
|
src = (GstElement *) GST_PAD_PARENT (srcpad);
|
||||||
|
sink = (GstElement *) GST_PAD_PARENT (sinkpad);
|
||||||
|
|
||||||
/* find a path from src to sink */
|
/* 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 there is no way to plug: return */
|
||||||
if (plugpath == NULL) {
|
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 (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));
|
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
|
* 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
|
* plugging and alter the plugpath to represent the elements, that must be plugged
|
||||||
*/
|
*/
|
||||||
newsrc = (GstElement *) src;
|
newsrc = src;
|
||||||
while (element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC))
|
while ((element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC)))
|
||||||
{
|
{
|
||||||
newsrc = element;
|
newsrc = element;
|
||||||
plugpath = g_list_delete_link (plugpath, plugpath);
|
plugpath = g_list_delete_link (plugpath, plugpath);
|
||||||
}
|
}
|
||||||
/* now do the same at the end */
|
/* now do the same at the end */
|
||||||
newsink = (GstElement *) sink;
|
newsink = sink;
|
||||||
templist = g_list_last (plugpath);
|
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;
|
GList *cur = templist;
|
||||||
newsink = element;
|
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);
|
result = gst_spider_create_and_plug (spider, newsrc, newsink, plugpath);
|
||||||
|
|
||||||
/* free no longer needed data */
|
/* free no longer needed data */
|
||||||
g_list_free (neededfactories);
|
g_list_free (plugpath);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,6 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "gstspideridentity.h"
|
#include "gstspideridentity.h"
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GST_SPIDER_ANY = 0,
|
|
||||||
GST_SPIDER_ENCODE = 1,
|
|
||||||
GST_SPIDER_DECODE = 2,
|
|
||||||
GST_SPIDER_PLUGTYPES
|
|
||||||
} GstSpiderPlugtype;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
@ -54,9 +47,9 @@ typedef struct _GstSpider GstSpider;
|
||||||
typedef struct _GstSpiderClass GstSpiderClass;
|
typedef struct _GstSpiderClass GstSpiderClass;
|
||||||
|
|
||||||
struct _GstSpider {
|
struct _GstSpider {
|
||||||
GstBin parent;
|
GstBin parent;
|
||||||
|
|
||||||
GstSpiderPlugtype plugtype; /* direction to plug */
|
GList * factories; /* factories to use for plugging */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstSpiderClass {
|
struct _GstSpiderClass {
|
||||||
|
|
|
@ -39,14 +39,14 @@ GstElementDetails gst_spider_identity_details = {
|
||||||
* delete me when meging with spider.c
|
* delete me when meging with spider.c
|
||||||
*/
|
*/
|
||||||
GST_PADTEMPLATE_FACTORY (spider_src_factory,
|
GST_PADTEMPLATE_FACTORY (spider_src_factory,
|
||||||
"src_%02d",
|
"src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_REQUEST,
|
GST_PAD_REQUEST,
|
||||||
NULL /* no caps */
|
NULL /* no caps */
|
||||||
);
|
);
|
||||||
|
|
||||||
GST_PADTEMPLATE_FACTORY (spider_sink_factory,
|
GST_PADTEMPLATE_FACTORY (spider_sink_factory,
|
||||||
"sink_%02d",
|
"sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_REQUEST,
|
GST_PAD_REQUEST,
|
||||||
NULL /* no caps */
|
NULL /* no caps */
|
||||||
|
@ -140,18 +140,25 @@ gst_spider_identity_get_bufferpool (GstPad *pad)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_spider_identity_init (GstSpiderIdentity *spider_identity)
|
gst_spider_identity_init (GstSpiderIdentity *ident)
|
||||||
{
|
{
|
||||||
/* pads */
|
/* sink */
|
||||||
spider_identity->sink = NULL;
|
ident->sink = gst_pad_new_from_template (GST_PADTEMPLATE_GET (spider_sink_factory), "sink");
|
||||||
spider_identity->src = NULL;
|
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 */
|
/* variables */
|
||||||
spider_identity->plugged = FALSE;
|
ident->plugged = FALSE;
|
||||||
|
|
||||||
/* caching */
|
/* caching */
|
||||||
spider_identity->cache_start = NULL;
|
ident->cache_start = NULL;
|
||||||
spider_identity->cache_end = NULL;
|
ident->cache_end = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +205,9 @@ gst_spider_identity_new_sink (gchar *name)
|
||||||
|
|
||||||
GST_ELEMENT_NAME (ret) = 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +310,7 @@ gst_spider_identity_change_state (GstElement *element)
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
/* start typefinding or plugging */
|
/* 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)
|
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 */
|
/* 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);
|
gst_spider_plug (ident);
|
||||||
}
|
}
|
||||||
|
@ -330,7 +340,7 @@ gst_spider_identity_start_typefinding (GstSpiderIdentity *ident)
|
||||||
{
|
{
|
||||||
GstElement* typefind;
|
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 */
|
/* create and connect typefind object */
|
||||||
typefind = gst_elementfactory_make ("typefind", g_strdup_printf("%s%s", "typefind", GST_ELEMENT_NAME(ident)));
|
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;
|
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 */
|
/* checks */
|
||||||
|
|
||||||
/* we have to ref the typefind, because if me remove it the scheduler segfaults
|
/* we have to ref the typefind, because if me remove it the scheduler segfaults
|
||||||
|
|
|
@ -1,6 +1,36 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <gst/gst.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 */
|
/* 1:1 copy of gstpropsprivate.h, needed for INFO events */
|
||||||
|
|
||||||
#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID)
|
#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[])
|
int main(int argc,char *argv[])
|
||||||
{
|
{
|
||||||
GstElement *bin, *filesrc, *decoder, *osssink, *videosink;
|
GstElement *bin, *filesrc, *decoder, *osssink, *videosink;
|
||||||
|
GList *facs;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc < 2) {
|
||||||
g_print("usage: %s <file>\n", argv[0]);
|
g_print("usage: %s <file>\n", argv[0]);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +142,9 @@ int main(int argc,char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only use decoding plugins */
|
/* 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 */
|
/* create video and audio sink */
|
||||||
osssink = gst_elementfactory_make("osssink", "audio");
|
osssink = gst_elementfactory_make("osssink", "audio");
|
||||||
|
|
Loading…
Reference in a new issue