mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-22 15:18:21 +00:00
gst/autoplug/: Die, spider, die.
Original commit message from CVS: * gst/autoplug/.cvsignore: * gst/autoplug/Makefile.am: * gst/autoplug/gstsearchfuncs.c: * gst/autoplug/gstsearchfuncs.h: * gst/autoplug/gstspider.c: * gst/autoplug/gstspider.h: * gst/autoplug/gstspideridentity.c: * gst/autoplug/gstspideridentity.h: * gst/autoplug/spidertest.c: Die, spider, die.
This commit is contained in:
parent
f494f49acd
commit
778981a34e
10 changed files with 13 additions and 2204 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2005-04-25 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
|
||||
* gst/autoplug/.cvsignore:
|
||||
* gst/autoplug/Makefile.am:
|
||||
* gst/autoplug/gstsearchfuncs.c:
|
||||
* gst/autoplug/gstsearchfuncs.h:
|
||||
* gst/autoplug/gstspider.c:
|
||||
* gst/autoplug/gstspider.h:
|
||||
* gst/autoplug/gstspideridentity.c:
|
||||
* gst/autoplug/gstspideridentity.h:
|
||||
* gst/autoplug/spidertest.c:
|
||||
Die, spider, die.
|
||||
|
||||
2005-04-25 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
|
||||
|
|
6
gst/autoplug/.gitignore
vendored
6
gst/autoplug/.gitignore
vendored
|
@ -1,6 +0,0 @@
|
|||
autoplugtest
|
||||
spidertest
|
||||
*.bb
|
||||
*.bbg
|
||||
*.da
|
||||
*.def
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
plugin_LTLIBRARIES = libgstspider.la
|
||||
|
||||
libgstspider_la_SOURCES = \
|
||||
gstspider.c gstspideridentity.c \
|
||||
gstsearchfuncs.c
|
||||
libgstspider_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstspider_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
libgstspider_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = gstspider.h gstspideridentity.h gstsearchfuncs.h
|
||||
|
||||
noinst_PROGRAMS = spidertest
|
||||
|
||||
spidertest_SOURCES = spidertest.c
|
||||
spidertest_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
spidertest_LDADD = $(GST_OBJ_LIBS)
|
||||
|
|
@ -1,440 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999-2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000-2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstsearchfuncs.c: functions needed when doing searches while
|
||||
* autoplugging
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstsearchfuncs.h"
|
||||
|
||||
/* FIXME: "evil hack" alarm, we need a better way to get a category in here */
|
||||
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_AUTOPLUG_ATTEMPT);
|
||||
#define GST_CAT_DEFAULT GST_CAT_AUTOPLUG_ATTEMPT
|
||||
|
||||
/* function that really misses in GLib
|
||||
* though the GLib version should take a function as argument...
|
||||
*/
|
||||
static 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_autoplug_caps_intersect:
|
||||
* @src: a source #GstCaps
|
||||
* @sink: the sink #GstCaps
|
||||
*
|
||||
* Checks if the given caps have a non-null intersection.
|
||||
*
|
||||
* Returns: TRUE, if both caps intersect.
|
||||
*/
|
||||
gboolean
|
||||
gst_autoplug_caps_intersect (const GstCaps * src, const GstCaps * sink)
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
/* get an intersection */
|
||||
caps = gst_caps_intersect (src, sink);
|
||||
|
||||
/* if the caps can't link, there is no intersection */
|
||||
if (gst_caps_is_empty (caps)) {
|
||||
gst_caps_unref (caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* hurrah, we can link, now remove the intersection */
|
||||
gst_caps_unref (caps);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_autoplug_can_connect_src:
|
||||
* @fac: factory to connect to
|
||||
* @src: caps to check
|
||||
*
|
||||
* Checks if a factory's sink can connect to the given caps
|
||||
*
|
||||
* Returns: #GstPadTemplate that can connect to the given caps
|
||||
*/
|
||||
GstPadTemplate *
|
||||
gst_autoplug_can_connect_src (GstElementFactory * fac, const GstCaps * src)
|
||||
{
|
||||
GList *templs;
|
||||
|
||||
templs = fac->padtemplates;
|
||||
|
||||
while (templs) {
|
||||
if ((GST_PAD_TEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) &&
|
||||
gst_autoplug_caps_intersect (src,
|
||||
GST_PAD_TEMPLATE_CAPS (templs->data))) {
|
||||
return GST_PAD_TEMPLATE (templs->data);
|
||||
}
|
||||
templs = g_list_next (templs);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_autoplug_can_connect_sink:
|
||||
* @fac: factory to connect to
|
||||
* @sink: caps to check
|
||||
*
|
||||
* Checks if a factory's src can connect to the given caps
|
||||
*
|
||||
* Returns: #GstPadTemplate that can connect to the given caps
|
||||
*/
|
||||
GstPadTemplate *
|
||||
gst_autoplug_can_connect_sink (GstElementFactory * fac, const GstCaps * sink)
|
||||
{
|
||||
GList *templs;
|
||||
|
||||
templs = fac->padtemplates;
|
||||
|
||||
while (templs) {
|
||||
GstCaps *caps = GST_PAD_TEMPLATE_CAPS (templs->data);
|
||||
|
||||
if ((GST_PAD_TEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) &&
|
||||
gst_autoplug_caps_intersect (caps, sink)) {
|
||||
return GST_PAD_TEMPLATE (templs->data);
|
||||
}
|
||||
templs = g_list_next (templs);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GstPadTemplate *
|
||||
gst_autoplug_can_match (GstElementFactory * src, GstElementFactory * dest)
|
||||
{
|
||||
GList *srctemps, *desttemps;
|
||||
|
||||
srctemps = src->padtemplates;
|
||||
|
||||
while (srctemps) {
|
||||
GstPadTemplate *srctemp = (GstPadTemplate *) srctemps->data;
|
||||
|
||||
desttemps = dest->padtemplates;
|
||||
|
||||
while (desttemps) {
|
||||
GstPadTemplate *desttemp = (GstPadTemplate *) desttemps->data;
|
||||
|
||||
if (srctemp->direction == GST_PAD_SRC &&
|
||||
desttemp->direction == GST_PAD_SINK) {
|
||||
if (gst_autoplug_caps_intersect (gst_pad_template_get_caps (srctemp),
|
||||
gst_pad_template_get_caps (desttemp))) {
|
||||
GST_DEBUG ("factory \"%s\" can connect with factory \"%s\"",
|
||||
GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
|
||||
return desttemp;
|
||||
}
|
||||
}
|
||||
|
||||
desttemps = g_list_next (desttemps);
|
||||
}
|
||||
srctemps = g_list_next (srctemps);
|
||||
}
|
||||
GST_DEBUG ("factory \"%s\" cannot connect with factory \"%s\"",
|
||||
GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* returns TRUE if the factory has padtemplates with the specified direction */
|
||||
gboolean
|
||||
gst_autoplug_factory_has_direction (GstElementFactory * fac,
|
||||
GstPadDirection dir)
|
||||
{
|
||||
GList *templs = fac->padtemplates;
|
||||
|
||||
while (templs) {
|
||||
if (GST_PAD_TEMPLATE_DIRECTION (templs->data) == dir) {
|
||||
return TRUE;
|
||||
}
|
||||
templs = g_list_next (templs);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Decisions are based on the padtemplates.
|
||||
* These functions return a new list so be sure to free it.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
gst_autoplug_rank_compare (const GstElementFactory * a,
|
||||
const GstElementFactory * b)
|
||||
{
|
||||
if (GST_PLUGIN_FEATURE (a)->rank > GST_PLUGIN_FEATURE (b)->rank)
|
||||
return -1;
|
||||
return (GST_PLUGIN_FEATURE (a)->rank < GST_PLUGIN_FEATURE (b)->rank) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* returns all factories which have sinks with non-NULL caps and srcs with
|
||||
* any caps. also only returns factories with a non-zero rank, and sorts by
|
||||
* rank descending.
|
||||
*/
|
||||
GList *
|
||||
gst_autoplug_factories_filters_with_sink_caps (GList * factories)
|
||||
{
|
||||
GList *ret = NULL;
|
||||
GstElementFactory *factory;
|
||||
GList *templs;
|
||||
|
||||
while (factories) {
|
||||
factory = (GstElementFactory *) factories->data;
|
||||
templs = factory->padtemplates;
|
||||
|
||||
if (GST_PLUGIN_FEATURE (factory)->rank > 0) {
|
||||
gboolean have_src = FALSE;
|
||||
gboolean have_sink = FALSE;
|
||||
|
||||
while (templs) {
|
||||
if (GST_PAD_TEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) {
|
||||
have_src = TRUE;
|
||||
}
|
||||
if ((GST_PAD_TEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK)
|
||||
&& (GST_PAD_TEMPLATE_CAPS (templs->data) != NULL)) {
|
||||
have_sink = TRUE;
|
||||
}
|
||||
if (have_src && have_sink) {
|
||||
ret = g_list_prepend (ret, factory);
|
||||
break;
|
||||
}
|
||||
templs = g_list_next (templs);
|
||||
}
|
||||
}
|
||||
factories = g_list_next (factories);
|
||||
}
|
||||
return g_list_sort (ret, (GCompareFunc) gst_autoplug_rank_compare);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* returns all factories which have a maximum of maxtemplates GstPadTemplates in direction dir
|
||||
*/
|
||||
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;
|
||||
|
||||
while (templs) {
|
||||
if (GST_PAD_TEMPLATE_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;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SHORTEST PATH ALGORITHM
|
||||
*/
|
||||
/**
|
||||
* gst_autoplug_sp:
|
||||
* @src_caps: a #GstCaps to plug from.
|
||||
* @sink_caps: the #GstCaps to plug to.
|
||||
* @factories: a #GList containing all allowed #GstElementFactory entries.
|
||||
*
|
||||
* Finds the shortest path of elements that together make up a possible
|
||||
* connection between the source and sink caps.
|
||||
*
|
||||
* Returns: a #GList of #GstElementFactory items which have to be connected
|
||||
* to get the shortest path.
|
||||
*/
|
||||
GList *
|
||||
gst_autoplug_sp (const GstCaps * srccaps, const 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 */
|
||||
|
||||
g_return_val_if_fail (srccaps != NULL, NULL);
|
||||
g_return_val_if_fail (sinkcaps != NULL, NULL);
|
||||
|
||||
GST_INFO ("attempting to autoplug via shortest path from %"
|
||||
GST_PTR_FORMAT " to %" GST_PTR_FORMAT, srccaps, 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;
|
||||
GST_DEBUG ("trying with %s", node->fac->details.longname);
|
||||
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->templ && node->endpoint)
|
||||
GST_DEBUG ("%s makes connection possible", node->fac->details.longname);
|
||||
else
|
||||
GST_DEBUG ("direct connection with %s not possible",
|
||||
node->fac->details.longname);
|
||||
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 ("no factory found that could connect to sink caps");
|
||||
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 ("iterating at current cost %d, bestnode %s at %d", 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 ("found a way to connect via %s",
|
||||
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 ("found no path from source caps to sink caps");
|
||||
g_list_free_list_and_elements (factory_nodes);
|
||||
return NULL;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999-2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000-2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstsearchfuncs.h: Header for gstsearchfuncs.c
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_SEARCHFUNCS_H__
|
||||
#define __GST_SEARCHFUNCS_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
/* placeholder for maximum cost when plugging */
|
||||
#define GST_AUTOPLUG_MAX_COST 999999
|
||||
|
||||
/* struct for a node, in the search tree */
|
||||
typedef struct _GstAutoplugNode GstAutoplugNode;
|
||||
|
||||
struct _GstAutoplugNode {
|
||||
GstAutoplugNode *prev; /* previous node */
|
||||
GstElementFactory *fac; /* factory of element to connect to */
|
||||
GstPadTemplate *templ; /* template which can connect */
|
||||
guint cost; /* total cost to get here */
|
||||
GstPadTemplate *endpoint; /* pad template that can connect to sink caps */
|
||||
};
|
||||
|
||||
/* helper functions */
|
||||
gboolean gst_autoplug_caps_intersect (const GstCaps *src, const GstCaps *sink);
|
||||
GstPadTemplate * gst_autoplug_can_connect_src (GstElementFactory *fac, const GstCaps *src);
|
||||
GstPadTemplate * gst_autoplug_can_connect_sink (GstElementFactory *fac, const GstCaps *sink);
|
||||
GstPadTemplate * gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest);
|
||||
gboolean gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir);
|
||||
#define gst_autoplug_factory_has_sink(fac) gst_autoplug_factory_has_direction((fac), GST_PAD_SINK)
|
||||
#define gst_autoplug_factory_has_src(fac) gst_autoplug_factory_has_direction((fac), GST_PAD_SRC)
|
||||
|
||||
/* cost functions */
|
||||
#define gst_autoplug_get_cost(fac) 1
|
||||
|
||||
/* factory selections */
|
||||
GList * gst_autoplug_factories_sinks (GList *factories);
|
||||
GList * gst_autoplug_factories_srcs (GList *factories);
|
||||
GList * gst_autoplug_factories_filters (GList *factories);
|
||||
GList * gst_autoplug_factories_filters_with_sink_caps(GList *factories);
|
||||
GList * gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir, guint maxtemplates);
|
||||
|
||||
/* shortest path algorithm */
|
||||
GList * gst_autoplug_sp (const GstCaps *src_caps, const GstCaps *sink_caps, GList *factories);
|
||||
|
||||
#endif /* __GST_SEARCHFUNCS_H__ */
|
|
@ -1,765 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstspider.c: element to automatically link sinks and sources
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 unlinking
|
||||
* - 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
|
||||
* - improve typefinding
|
||||
* - react to errors inside the pipeline
|
||||
* - implement more properties, change the current
|
||||
* - emit signals (most important: "NOT PLUGGABLE")
|
||||
* - implement something for reporting the state of the spider
|
||||
* to allow easier debugging.
|
||||
* (could be useful for bins in general)
|
||||
* - fix bugs
|
||||
* ...
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "../gst-i18n-lib.h"
|
||||
#include "gstspider.h"
|
||||
#include "gstspideridentity.h"
|
||||
#include "gstsearchfuncs.h"
|
||||
|
||||
static GstElementDetails gst_spider_details = GST_ELEMENT_DETAILS ("Spider",
|
||||
"Generic",
|
||||
"Automatically link sinks and sources",
|
||||
"Benjamin Otte <in7y118@public.uni-hamburg.de>");
|
||||
|
||||
GST_DEBUG_CATEGORY (gst_spider_debug);
|
||||
#define GST_CAT_DEFAULT gst_spider_debug
|
||||
|
||||
/* signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_FACTORIES,
|
||||
/* FILL ME TOO */
|
||||
};
|
||||
|
||||
/* generic templates */
|
||||
static GstStaticPadTemplate spider_sink_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
static GstStaticPadTemplate spider_src_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("src_%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* link functions */
|
||||
static GstSpiderConnection *gst_spider_link_new (GstSpiderIdentity * src);
|
||||
static void gst_spider_link_destroy (GstSpiderConnection * conn);
|
||||
static void gst_spider_link_reset (GstSpiderConnection * conn, GstElement * to);
|
||||
static void gst_spider_link_add (GstSpiderConnection * conn,
|
||||
GstElement * element);
|
||||
static GstSpiderConnection *gst_spider_link_find (GstSpiderIdentity * src);
|
||||
static GstSpiderConnection *gst_spider_link_get (GstSpiderIdentity * src);
|
||||
|
||||
/* autoplugging functions */
|
||||
static GstElement *gst_spider_find_element_to_plug (GstElement * src,
|
||||
GstElementFactory * fac, GstPadDirection dir);
|
||||
static GstPadLinkReturn gst_spider_plug (GstSpiderConnection * conn);
|
||||
static GstPadLinkReturn gst_spider_plug_from_srcpad (GstSpiderConnection * conn,
|
||||
GstPad * srcpad);
|
||||
/*static GstPadLinkReturn gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad); */
|
||||
static GstPadLinkReturn gst_spider_create_and_plug (GstSpiderConnection * conn,
|
||||
GList * plugpath);
|
||||
|
||||
/* random functions */
|
||||
static gchar *gst_spider_unused_elementname (GstBin * bin,
|
||||
const gchar * startwith);
|
||||
|
||||
/* debugging stuff
|
||||
static void print_spider_contents (GstSpider *spider);
|
||||
static void print_spider_link (GstSpiderConnection *conn); */
|
||||
|
||||
/* === variables === */
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
/* no signals yet
|
||||
static guint gst_spider_signals[LAST_SIGNAL] = { 0 };*/
|
||||
|
||||
/* GObject and GStreamer init functions */
|
||||
GType
|
||||
gst_spider_get_type (void)
|
||||
{
|
||||
static GType spider_type = 0;
|
||||
|
||||
if (!spider_type) {
|
||||
static const GTypeInfo spider_info = {
|
||||
sizeof (GstSpiderClass),
|
||||
NULL,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_spider_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstSpider),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_spider_init,
|
||||
};
|
||||
|
||||
spider_type =
|
||||
g_type_register_static (GST_TYPE_BIN, "GstSpider", &spider_info, 0);
|
||||
}
|
||||
return spider_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_class_init (GstSpiderClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_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_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;
|
||||
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&spider_sink_factory));
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&spider_src_factory));
|
||||
gst_element_class_set_details (gstelement_class, &gst_spider_details);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_spider_request_new_pad);
|
||||
}
|
||||
static void
|
||||
gst_spider_init (GstSpider * spider)
|
||||
{
|
||||
/* use only elements which have sources and sinks and where the sinks have caps */
|
||||
/* FIXME: How do we handle factories that are added after the spider was constructed? */
|
||||
GList *list = gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY);
|
||||
|
||||
spider->factories = gst_autoplug_factories_filters_with_sink_caps (list);
|
||||
g_list_free (list);
|
||||
|
||||
spider->links = NULL;
|
||||
|
||||
spider->sink_ident = gst_spider_identity_new_sink ("sink_ident");
|
||||
gst_bin_add (GST_BIN (spider), GST_ELEMENT (spider->sink_ident));
|
||||
gst_element_add_ghost_pad (GST_ELEMENT (spider), spider->sink_ident->sink,
|
||||
"sink");
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_dispose (GObject * object)
|
||||
{
|
||||
GstSpider *spider;
|
||||
GList *list;
|
||||
|
||||
spider = GST_SPIDER (object);
|
||||
g_list_free (spider->factories);
|
||||
spider->factories = NULL;
|
||||
|
||||
for (list = spider->links; list; list = list->next) {
|
||||
GstSpiderConnection *conn = list->data;
|
||||
|
||||
g_list_free (conn->path);
|
||||
g_free (conn);
|
||||
}
|
||||
g_list_free (spider->links);
|
||||
spider->links = NULL;
|
||||
|
||||
((GObjectClass *) parent_class)->dispose (object);
|
||||
}
|
||||
static GstPad *
|
||||
gst_spider_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * name)
|
||||
{
|
||||
GstPad *returnpad;
|
||||
gchar *padname;
|
||||
GstSpiderIdentity *identity;
|
||||
GstSpider *spider;
|
||||
|
||||
g_return_val_if_fail (templ != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
|
||||
g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC,
|
||||
NULL);
|
||||
|
||||
spider = GST_SPIDER (element);
|
||||
|
||||
/* create an identity object, so we have a pad */
|
||||
padname = gst_spider_unused_elementname ((GstBin *) spider, "src_");
|
||||
identity = gst_spider_identity_new_src (padname);
|
||||
returnpad = identity->src;
|
||||
|
||||
/* FIXME: use the requested name for the pad */
|
||||
|
||||
gst_object_replace ((GstObject **) & returnpad->padtemplate,
|
||||
(GstObject *) templ);
|
||||
|
||||
gst_bin_add (GST_BIN (element), GST_ELEMENT (identity));
|
||||
|
||||
returnpad = gst_element_add_ghost_pad (element, returnpad, padname);
|
||||
g_free (padname);
|
||||
gst_spider_link_new (identity);
|
||||
GST_DEBUG ("successfully created requested pad %s:%s",
|
||||
GST_DEBUG_PAD_NAME (returnpad));
|
||||
|
||||
return returnpad;
|
||||
}
|
||||
|
||||
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_FACTORIES:
|
||||
list = (GList *) g_value_get_pointer (value);
|
||||
for (; list; list = list->next) {
|
||||
g_return_if_fail (list->data != NULL);
|
||||
g_return_if_fail (GST_IS_ELEMENT_FACTORY (list->data));
|
||||
}
|
||||
g_list_free (spider->factories);
|
||||
spider->factories = (GList *) g_value_get_pointer (value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
gst_spider_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstSpider *spider;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
spider = GST_SPIDER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_FACTORIES:
|
||||
g_value_set_pointer (value, spider->factories);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* get a name for an element that isn't used yet */
|
||||
static gchar *
|
||||
gst_spider_unused_elementname (GstBin * bin, const gchar * startwith)
|
||||
{
|
||||
gchar *name = g_strdup_printf ("%s%d", startwith, 0);
|
||||
guint i;
|
||||
|
||||
for (i = 0; gst_bin_get_by_name (bin, name) != NULL;) {
|
||||
g_free (name);
|
||||
name = g_strdup_printf ("%s%d", startwith, ++i);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
static void
|
||||
gst_spider_link_sometimes (GstElement * src, GstPad * pad,
|
||||
GstSpiderConnection * conn)
|
||||
{
|
||||
gulong signal_id = conn->signal_id;
|
||||
|
||||
GST_INFO ("plugging from new sometimes pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
/* try to autoplug the elements */
|
||||
if (gst_spider_plug_from_srcpad (conn, pad) != GST_PAD_LINK_REFUSED) {
|
||||
GST_DEBUG ("%s:%s was autoplugged to %s:%s, removing callback",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (conn->src->sink));
|
||||
g_signal_handler_disconnect (src, signal_id);
|
||||
signal_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* create a new link from those two elements */
|
||||
static GstSpiderConnection *
|
||||
gst_spider_link_new (GstSpiderIdentity * src)
|
||||
{
|
||||
GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (src));
|
||||
|
||||
GstSpiderConnection *conn = g_new0 (GstSpiderConnection, 1);
|
||||
|
||||
conn->src = src;
|
||||
conn->path = NULL;
|
||||
conn->current = (GstElement *) spider->sink_ident;
|
||||
spider->links = g_list_prepend (spider->links, conn);
|
||||
|
||||
return conn;
|
||||
}
|
||||
static void
|
||||
gst_spider_link_destroy (GstSpiderConnection * conn)
|
||||
{
|
||||
GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (conn->src));
|
||||
|
||||
/* reset link to unplugged */
|
||||
gst_spider_link_reset (conn, (GstElement *) spider->sink_ident);
|
||||
g_free (conn);
|
||||
}
|
||||
static void
|
||||
gst_spider_link_reset (GstSpiderConnection * conn, GstElement * to)
|
||||
{
|
||||
GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (conn->src));
|
||||
|
||||
GST_DEBUG ("resetting link from %s to %s, currently at %s to %s",
|
||||
GST_ELEMENT_NAME (spider->sink_ident), GST_ELEMENT_NAME (conn->src),
|
||||
GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (to));
|
||||
while ((conn->path != NULL) && ((GstElement *) conn->path->data != to)) {
|
||||
gst_object_unref ((GstObject *) conn->path->data);
|
||||
conn->path = g_list_delete_link (conn->path, conn->path);
|
||||
}
|
||||
if (conn->path == NULL) {
|
||||
conn->current = (GstElement *) spider->sink_ident;
|
||||
} else {
|
||||
conn->current = to;
|
||||
}
|
||||
}
|
||||
|
||||
/* add an element to the link */
|
||||
static void
|
||||
gst_spider_link_add (GstSpiderConnection * conn, GstElement * element)
|
||||
{
|
||||
conn->path = g_list_prepend (conn->path, element);
|
||||
conn->current = element;
|
||||
}
|
||||
|
||||
/* find the link from those two elements */
|
||||
static GstSpiderConnection *
|
||||
gst_spider_link_find (GstSpiderIdentity * src)
|
||||
{
|
||||
GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (src);
|
||||
GList *list;
|
||||
|
||||
for (list = spider->links; list; list = list->next) {
|
||||
GstSpiderConnection *conn = (GstSpiderConnection *) list->data;
|
||||
|
||||
if (conn->src == src) {
|
||||
return conn;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get a new link from those two elements
|
||||
* search first; if none is found, create a new one */
|
||||
static GstSpiderConnection *
|
||||
gst_spider_link_get (GstSpiderIdentity * src)
|
||||
{
|
||||
GstSpiderConnection *ret;
|
||||
|
||||
if ((ret = gst_spider_link_find (src)) != NULL) {
|
||||
return ret;
|
||||
}
|
||||
return gst_spider_link_new (src);
|
||||
}
|
||||
|
||||
void
|
||||
gst_spider_identity_plug (GstSpiderIdentity * ident)
|
||||
{
|
||||
GstSpider *spider;
|
||||
const GList *padlist;
|
||||
GstPadDirection dir;
|
||||
GstSpiderConnection *conn;
|
||||
|
||||
/* checks */
|
||||
g_return_if_fail (ident != NULL);
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
|
||||
g_assert (spider != NULL);
|
||||
g_assert (GST_IS_SPIDER (spider));
|
||||
|
||||
/* return if we're already plugged */
|
||||
if (ident->plugged)
|
||||
return;
|
||||
|
||||
/* check if there is at least one element factory that can handle the
|
||||
identity's src caps */
|
||||
{
|
||||
GstCaps *src_caps = gst_pad_get_caps (ident->src);
|
||||
|
||||
if (!gst_caps_is_empty (src_caps) && !gst_caps_is_any (src_caps)) {
|
||||
GList *factories;
|
||||
GstPadTemplate *padtemp;
|
||||
gboolean found = FALSE;
|
||||
|
||||
factories = spider->factories;
|
||||
while (factories) {
|
||||
if ((padtemp =
|
||||
gst_autoplug_can_connect_src (factories->data, src_caps))) {
|
||||
GST_DEBUG ("can connect src to %s pad template: %" GST_PTR_FORMAT,
|
||||
GST_PLUGIN_FEATURE_NAME (factories->data),
|
||||
gst_pad_template_get_caps (padtemp));
|
||||
found = TRUE;
|
||||
}
|
||||
factories = factories->next;
|
||||
}
|
||||
if (!found) {
|
||||
const char *mime;
|
||||
|
||||
mime = gst_structure_get_name (gst_caps_get_structure (src_caps, 0));
|
||||
|
||||
GST_ELEMENT_ERROR (spider, STREAM, CODEC_NOT_FOUND,
|
||||
(_("There is no element present to handle the stream's mime type %s."), mime), (NULL));
|
||||
gst_caps_unref (src_caps);
|
||||
return;
|
||||
}
|
||||
}
|
||||
gst_caps_unref (src_caps);
|
||||
}
|
||||
|
||||
/* get the direction of our ident */
|
||||
if (GST_PAD_PEER (ident->sink)) {
|
||||
if (GST_PAD_PEER (ident->src)) {
|
||||
/* Hey, the ident is linked on both sides */
|
||||
g_warning ("Trying to autoplug a linked element. Aborting...");
|
||||
return;
|
||||
} else {
|
||||
dir = GST_PAD_SINK;
|
||||
}
|
||||
} else {
|
||||
if (GST_PAD_PEER (ident->src)) {
|
||||
dir = GST_PAD_SRC;
|
||||
} else {
|
||||
/* the ident isn't linked on either side */
|
||||
g_warning ("Trying to autoplug an unlinked element. Aborting...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* now iterate all possible pads and link when needed */
|
||||
padlist = GST_ELEMENT (spider)->pads;
|
||||
for (; padlist; padlist = padlist->next) {
|
||||
GstPad *otherpad;
|
||||
GstSpiderIdentity *peer;
|
||||
|
||||
g_assert (GST_IS_PAD (padlist->data));
|
||||
otherpad = (GstPad *) GST_GPAD_REALPAD (padlist->data);
|
||||
peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad);
|
||||
/* we only want to link to the other side */
|
||||
if (dir != GST_PAD_DIRECTION (otherpad)) {
|
||||
/* we only link to plugged in elements */
|
||||
if (peer->plugged == TRUE) {
|
||||
/* plug in the right direction */
|
||||
if (dir == GST_PAD_SINK) {
|
||||
conn = gst_spider_link_get (peer);
|
||||
} else {
|
||||
conn = gst_spider_link_get (ident);
|
||||
}
|
||||
if ((GstElement *) spider->sink_ident == conn->current) {
|
||||
gst_spider_plug (conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ident->plugged = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_spider_identity_unplug (GstSpiderIdentity * ident)
|
||||
{
|
||||
GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident);
|
||||
GList *list;
|
||||
|
||||
for (list = spider->links; list; list = list->next) {
|
||||
GstSpiderConnection *conn = list->data;
|
||||
|
||||
if (conn->src == ident) {
|
||||
g_list_delete_link (spider->links, list);
|
||||
gst_spider_link_destroy (conn);
|
||||
}
|
||||
}
|
||||
ident->plugged = FALSE;
|
||||
}
|
||||
|
||||
/* links src to sink using the elementfactories in plugpath
|
||||
* plugpath will be removed afterwards */
|
||||
static GstPadLinkReturn
|
||||
gst_spider_create_and_plug (GstSpiderConnection * conn, GList * plugpath)
|
||||
{
|
||||
GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
|
||||
GList *endelements = NULL, *templist = NULL;
|
||||
GstElement *element;
|
||||
|
||||
/* exit if plugging is already done */
|
||||
if ((GstElement *) conn->src == conn->current)
|
||||
return GST_PAD_LINK_DONE;
|
||||
|
||||
/* try to shorten the list at the end and not duplicate link code */
|
||||
if (plugpath != NULL) {
|
||||
templist = g_list_last (plugpath);
|
||||
element = (GstElement *) conn->src;
|
||||
while ((plugpath != NULL)
|
||||
&& (element =
|
||||
gst_spider_find_element_to_plug (element,
|
||||
(GstElementFactory *) plugpath->data, GST_PAD_SINK))) {
|
||||
GList *cur = templist;
|
||||
|
||||
endelements = g_list_prepend (endelements, element);
|
||||
templist = g_list_previous (templist);
|
||||
g_list_delete_link (cur, cur);
|
||||
}
|
||||
}
|
||||
|
||||
/* do the linking */
|
||||
while (conn->current != (GstElement *) (endelements ==
|
||||
NULL ? conn->src : endelements->data)) {
|
||||
/* get sink element to plug, src is conn->current */
|
||||
if (plugpath == NULL) {
|
||||
element =
|
||||
(GstElement *) (endelements == NULL ? conn->src : endelements->data);
|
||||
} else {
|
||||
element =
|
||||
gst_element_factory_create ((GstElementFactory *) plugpath->data,
|
||||
NULL);
|
||||
GST_DEBUG
|
||||
("Adding element %s of type %s and syncing state with autoplugger",
|
||||
GST_ELEMENT_NAME (element), GST_PLUGIN_FEATURE_NAME (plugpath->data));
|
||||
gst_bin_add (GST_BIN (spider), element);
|
||||
}
|
||||
/* insert and link new element */
|
||||
if (gst_element_link (conn->current, element)) {
|
||||
gst_element_sync_state_with_parent (element);
|
||||
} else {
|
||||
/* check if the src has SOMETIMES templates. If so, link a callback */
|
||||
GList *templs = gst_element_get_pad_template_list (conn->current);
|
||||
|
||||
/* remove element that couldn't be linked, if it wasn't the endpoint */
|
||||
if (element != (GstElement *) conn->src)
|
||||
gst_bin_remove (GST_BIN (spider), element);
|
||||
|
||||
for (; templs; templs = templs->next) {
|
||||
GstPadTemplate *templ = (GstPadTemplate *) templs->data;
|
||||
|
||||
if ((GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC)
|
||||
&& (GST_PAD_TEMPLATE_PRESENCE (templ) == GST_PAD_SOMETIMES)) {
|
||||
GST_DEBUG ("adding callback to link element %s to %s",
|
||||
GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
|
||||
conn->signal_id =
|
||||
g_signal_connect (G_OBJECT (conn->current), "new_pad",
|
||||
G_CALLBACK (gst_spider_link_sometimes), conn);
|
||||
g_list_free (plugpath);
|
||||
return GST_PAD_LINK_DELAYED;
|
||||
}
|
||||
}
|
||||
GST_DEBUG ("no chance to link element %s to %s",
|
||||
GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
|
||||
g_list_free (plugpath);
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
}
|
||||
GST_DEBUG ("coupling %s and %s",
|
||||
GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (conn->current));
|
||||
gst_spider_link_add (conn, element);
|
||||
if (plugpath != NULL)
|
||||
plugpath = g_list_delete_link (plugpath, plugpath);
|
||||
}
|
||||
|
||||
/* ref all elements at the end */
|
||||
while (endelements) {
|
||||
gst_spider_link_add (conn, endelements->data);
|
||||
endelements = g_list_delete_link (endelements, endelements);
|
||||
}
|
||||
|
||||
return GST_PAD_LINK_DONE;
|
||||
}
|
||||
|
||||
/* checks, if src is already linked to an element from factory fac on direction dir */
|
||||
static GstElement *
|
||||
gst_spider_find_element_to_plug (GstElement * src, GstElementFactory * fac,
|
||||
GstPadDirection dir)
|
||||
{
|
||||
GList *padlist = GST_ELEMENT_PADS (src);
|
||||
|
||||
for (; padlist; padlist = padlist->next) {
|
||||
GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data);
|
||||
|
||||
/* is the pad on the right side and is it linked? */
|
||||
if ((GST_PAD_DIRECTION (pad) == dir)
|
||||
&& (pad = (GstPad *) (GST_RPAD_PEER (pad)))) {
|
||||
/* is the element the pad is linked to of the right type? */
|
||||
GstElement *element = GST_PAD_PARENT (pad);
|
||||
|
||||
if (G_TYPE_FROM_INSTANCE (element) ==
|
||||
gst_element_factory_get_element_type (fac)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* try to establish the link */
|
||||
static GstPadLinkReturn
|
||||
gst_spider_plug (GstSpiderConnection * conn)
|
||||
{
|
||||
GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
|
||||
|
||||
if ((GstElement *) conn->src == conn->current)
|
||||
return GST_PAD_LINK_DONE;
|
||||
if ((GstElement *) spider->sink_ident == conn->current)
|
||||
return gst_spider_plug_from_srcpad (conn, spider->sink_ident->src);
|
||||
g_warning
|
||||
("FIXME: autoplugging only possible from GstSpiderIdentity conn->sink yet (yep, that's technical)\n");
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
}
|
||||
|
||||
/* try to establish the link using this pad */
|
||||
static GstPadLinkReturn
|
||||
gst_spider_plug_from_srcpad (GstSpiderConnection * conn, GstPad * srcpad)
|
||||
{
|
||||
GstElement *element;
|
||||
GList *plugpath;
|
||||
gboolean result = TRUE;
|
||||
GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
|
||||
GstElement *startelement = conn->current;
|
||||
GstCaps *caps1;
|
||||
GstCaps *caps2;
|
||||
|
||||
g_assert ((GstElement *) GST_OBJECT_PARENT (srcpad) == conn->current);
|
||||
GST_DEBUG ("trying to plug from %s:%s to %s",
|
||||
GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (conn->src));
|
||||
|
||||
/* see if they match already */
|
||||
if (gst_pad_link (srcpad, conn->src->sink)) {
|
||||
GST_DEBUG ("%s:%s and %s:%s can link directly",
|
||||
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (conn->src->sink));
|
||||
gst_pad_unlink (srcpad, conn->src->sink);
|
||||
gst_spider_create_and_plug (conn, NULL);
|
||||
return GST_PAD_LINK_OK;
|
||||
}
|
||||
|
||||
/* find a path from src to sink */
|
||||
caps1 = gst_pad_get_caps (srcpad);
|
||||
caps2 = gst_pad_get_caps (conn->src->sink);
|
||||
plugpath = gst_autoplug_sp (caps1, caps2, spider->factories);
|
||||
gst_caps_unref (caps1);
|
||||
gst_caps_unref (caps2);
|
||||
|
||||
/* prints out the path that was found for plugging */
|
||||
/* g_print ("found path from %s to %s:\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
|
||||
templist = plugpath;
|
||||
while (templist)
|
||||
{
|
||||
g_print("%s\n", GST_OBJECT_NAME (templist->data));
|
||||
templist = g_list_next (templist);
|
||||
} */
|
||||
|
||||
/* if there is no way to plug: return */
|
||||
if (plugpath == NULL) {
|
||||
GST_DEBUG ("no chance to plug from %s to %s",
|
||||
GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
}
|
||||
GST_DEBUG ("found a link that needs %d elements", g_list_length (plugpath));
|
||||
|
||||
/* now remove non-needed elements from the beginning of the path
|
||||
* 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
|
||||
*/
|
||||
element = conn->current;
|
||||
while ((plugpath != NULL)
|
||||
&& (element =
|
||||
gst_spider_find_element_to_plug (element,
|
||||
(GstElementFactory *) plugpath->data, GST_PAD_SRC))) {
|
||||
gst_spider_link_add (conn, element);
|
||||
plugpath = g_list_delete_link (plugpath, plugpath);
|
||||
}
|
||||
|
||||
GST_DEBUG ("%d elements must be inserted to establish the link",
|
||||
g_list_length (plugpath));
|
||||
/* create the elements and plug them */
|
||||
result = gst_spider_create_and_plug (conn, plugpath);
|
||||
|
||||
/* reset the "current" element */
|
||||
if (result == GST_PAD_LINK_REFUSED) {
|
||||
gst_spider_link_reset (conn, startelement);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (gst_spider_debug, "spider", 0,
|
||||
"spider autoplugging element");
|
||||
|
||||
if (!gst_element_register (plugin, "spider", GST_RANK_NONE, GST_TYPE_SPIDER))
|
||||
return FALSE;
|
||||
if (!gst_element_register (plugin, "spideridentity", GST_RANK_NONE,
|
||||
GST_TYPE_SPIDER_IDENTITY))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"gstspider",
|
||||
"a 1:n autoplugger",
|
||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
|
|
@ -1,93 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstspider.h: Header for GstSpider object
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_SPIDER_H__
|
||||
#define __GST_SPIDER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "gstspideridentity.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN(gst_spider_debug);
|
||||
|
||||
/*
|
||||
* Theory of operation:
|
||||
* When connecting a sink to a source, GstSpiderConnections are used to keep track
|
||||
* of the current status of the link. sink -> src is the path we intend to
|
||||
* plug. current is how far we've come. If current equals
|
||||
* - NULL, there is no possible path,
|
||||
* - src, the link is established.
|
||||
* - sink, it wasn't tried to establish a link.
|
||||
* - something else, we have come that far while plugging.
|
||||
* signal_id is used to remember the signal_id when we are waiting for a "new_pad"
|
||||
* callback during link.
|
||||
* When a path is established, the elements in the path (excluding sink and src)
|
||||
* are refcounted once for every path.
|
||||
* A GstSpider keeps a list of all GstSpiderConnections in it.
|
||||
*/
|
||||
typedef struct {
|
||||
GstSpiderIdentity *src;
|
||||
/* dunno if the path should stay here or if its too much load.
|
||||
* it's at least easier then always searching it */
|
||||
GList *path;
|
||||
GstElement *current;
|
||||
gulong signal_id;
|
||||
} GstSpiderConnection;
|
||||
|
||||
#define GST_TYPE_SPIDER \
|
||||
(gst_spider_get_type())
|
||||
#define GST_SPIDER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPIDER,GstSpider))
|
||||
#define GST_SPIDER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPIDER,GstSpiderClass))
|
||||
#define GST_IS_SPIDER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPIDER))
|
||||
#define GST_IS_SPIDER_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPIDER))
|
||||
|
||||
typedef struct _GstSpider GstSpider;
|
||||
typedef struct _GstSpiderClass GstSpiderClass;
|
||||
|
||||
struct _GstSpider {
|
||||
GstBin parent;
|
||||
|
||||
GstSpiderIdentity *sink_ident;
|
||||
GList * factories; /* factories to use for plugging */
|
||||
|
||||
GList * links; /* GStSpiderConnection list of all links */
|
||||
};
|
||||
|
||||
struct _GstSpiderClass {
|
||||
GstBinClass parent_class;
|
||||
};
|
||||
|
||||
/* default initialization stuff */
|
||||
GType gst_spider_get_type (void);
|
||||
|
||||
/* private link functions to be called by GstSpiderIdentity */
|
||||
void gst_spider_identity_plug (GstSpiderIdentity *ident);
|
||||
void gst_spider_identity_unplug (GstSpiderIdentity *ident);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_SPIDER_H__ */
|
|
@ -1,608 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstspideridentity.c: identity element for the spider autoplugger
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstspideridentity.h"
|
||||
#include "gstspider.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_spider_identity_debug);
|
||||
#define GST_CAT_DEFAULT gst_spider_identity_debug
|
||||
|
||||
static GstElementDetails gst_spider_identity_details =
|
||||
GST_ELEMENT_DETAILS ("SpiderIdentity",
|
||||
"Generic",
|
||||
"Link between spider and outside elements",
|
||||
"Benjamin Otte <in7y118@public.uni-hamburg.de>");
|
||||
|
||||
|
||||
/* generic templates
|
||||
* delete me when meging with spider.c
|
||||
*/
|
||||
static GstStaticPadTemplate spider_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static GstStaticPadTemplate spider_sink_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
/* SpiderIdentity signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
/* GObject stuff */
|
||||
static void gst_spider_identity_class_init (GstSpiderIdentityClass * klass);
|
||||
static void gst_spider_identity_init (GstSpiderIdentity * spider_identity);
|
||||
|
||||
/* functions set in pads, elements and stuff */
|
||||
static void gst_spider_identity_chain (GstPad * pad, GstBuffer * buf);
|
||||
static GstElementStateReturn gst_spider_identity_change_state (GstElement *
|
||||
element);
|
||||
static GstPadLinkReturn gst_spider_identity_link (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static GstCaps *gst_spider_identity_getcaps (GstPad * pad);
|
||||
|
||||
/* loop functions */
|
||||
static void gst_spider_identity_dumb_loop (GstSpiderIdentity * ident);
|
||||
static void gst_spider_identity_src_loop (GstSpiderIdentity * ident);
|
||||
static void gst_spider_identity_sink_loop_type_finding (GstSpiderIdentity *
|
||||
ident);
|
||||
|
||||
static gboolean gst_spider_identity_handle_src_event (GstPad * pad,
|
||||
GstEvent * event);
|
||||
|
||||
/* other functions */
|
||||
static void gst_spider_identity_start_type_finding (GstSpiderIdentity * ident);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
/* no signals
|
||||
static guint gst_spider_identity_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
GType
|
||||
gst_spider_identity_get_type (void)
|
||||
{
|
||||
static GType spider_identity_type = 0;
|
||||
|
||||
if (!spider_identity_type) {
|
||||
static const GTypeInfo spider_identity_info = {
|
||||
sizeof (GstSpiderIdentityClass), NULL,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_spider_identity_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstSpiderIdentity),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_spider_identity_init,
|
||||
};
|
||||
|
||||
spider_identity_type =
|
||||
g_type_register_static (GST_TYPE_ELEMENT, "GstSpiderIdentity",
|
||||
&spider_identity_info, 0);
|
||||
GST_DEBUG_CATEGORY_INIT (gst_spider_identity_debug, "spideridentity", 0,
|
||||
"spider autoplugging proxy element");
|
||||
}
|
||||
return spider_identity_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_identity_class_init (GstSpiderIdentityClass * klass)
|
||||
{
|
||||
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||
|
||||
/* add our two pad templates */
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&spider_src_factory));
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&spider_sink_factory));
|
||||
gst_element_class_set_details (gstelement_class,
|
||||
&gst_spider_identity_details);
|
||||
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_change_state);
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_request_new_pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_identity_init (GstSpiderIdentity * ident)
|
||||
{
|
||||
/* sink */
|
||||
ident->sink =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&spider_sink_factory), "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (ident), ident->sink);
|
||||
gst_pad_set_link_function (ident->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_link));
|
||||
gst_pad_set_getcaps_function (ident->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps));
|
||||
/* src */
|
||||
ident->src =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&spider_src_factory), "src");
|
||||
gst_element_add_pad (GST_ELEMENT (ident), ident->src);
|
||||
gst_pad_set_link_function (ident->src,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_link));
|
||||
gst_pad_set_getcaps_function (ident->src,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps));
|
||||
gst_pad_set_event_function (ident->src,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_handle_src_event));
|
||||
|
||||
/* variables */
|
||||
ident->plugged = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_identity_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstSpiderIdentity *ident;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
ident = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GST_DEBUG_OBJECT (ident, "spider identity received event %p", buf);
|
||||
/* start hack for current event stuff here */
|
||||
/* check for unlinked elements and send them the EOS event, too */
|
||||
if (GST_EVENT_TYPE (GST_EVENT (buf)) == GST_EVENT_EOS) {
|
||||
GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident);
|
||||
GList *list = spider->links;
|
||||
|
||||
while (list) {
|
||||
GstSpiderConnection *conn = (GstSpiderConnection *) list->data;
|
||||
|
||||
list = g_list_next (list);
|
||||
if (conn->current != (GstElement *) conn->src) {
|
||||
GstEvent *event;
|
||||
|
||||
event = gst_event_new (GST_EVENT_EOS);
|
||||
GST_DEBUG_OBJECT (ident,
|
||||
"sending EOS event %p to unconnected element %s from %s",
|
||||
event, GST_ELEMENT_NAME (conn->src), GST_ELEMENT_NAME (ident));
|
||||
gst_pad_push (conn->src->src, GST_DATA (event));
|
||||
gst_element_set_eos (GST_ELEMENT (conn->src));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* end hack for current event stuff here */
|
||||
GST_DEBUG_OBJECT (ident,
|
||||
"calling default handler for event %p on pad %s:%s",
|
||||
buf, GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
gst_pad_event_default (pad, GST_EVENT (buf));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ident->src != NULL) && (GST_PAD_PEER (ident->src) != NULL)) {
|
||||
GST_LOG_OBJECT (ident, "pushing buffer %p "
|
||||
"(refcount %d, size %u, offset %" G_GINT64_FORMAT ") ",
|
||||
buf, GST_BUFFER_REFCOUNT_VALUE (buf),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf));
|
||||
gst_pad_push (ident->src, GST_DATA (buf));
|
||||
} else if (GST_IS_BUFFER (buf)) {
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
}
|
||||
|
||||
GstSpiderIdentity *
|
||||
gst_spider_identity_new_src (gchar * name)
|
||||
{
|
||||
GstSpiderIdentity *ret =
|
||||
(GstSpiderIdentity *) gst_element_factory_make ("spideridentity", name);
|
||||
/* set the right functions */
|
||||
gst_element_set_loop_function (GST_ELEMENT (ret), (GstElementLoopFunction)
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_src_loop));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GstSpiderIdentity *
|
||||
gst_spider_identity_new_sink (gchar * name)
|
||||
{
|
||||
GstSpiderIdentity *ret =
|
||||
(GstSpiderIdentity *) gst_element_factory_make ("spideridentity", name);
|
||||
|
||||
/* set the right functions */
|
||||
gst_element_set_loop_function (GST_ELEMENT (ret), (GstElementLoopFunction)
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* shamelessly stolen from gstqueue.c to get proxy links */
|
||||
static GstPadLinkReturn
|
||||
gst_spider_identity_link (GstPad * pad, const GstCaps * caps)
|
||||
{
|
||||
GstSpiderIdentity *spider_identity =
|
||||
GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
|
||||
GstPad *otherpad;
|
||||
|
||||
if (pad == spider_identity->src) {
|
||||
otherpad = spider_identity->sink;
|
||||
if (GST_PAD_PEER (otherpad) == NULL)
|
||||
return GST_PAD_LINK_DELAYED;
|
||||
} else {
|
||||
otherpad = spider_identity->src;
|
||||
}
|
||||
|
||||
g_return_val_if_fail (otherpad != NULL, GST_PAD_LINK_REFUSED);
|
||||
|
||||
return gst_pad_try_set_caps (otherpad, caps);
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_spider_identity_getcaps (GstPad * pad)
|
||||
{
|
||||
GstSpiderIdentity *ident = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
|
||||
GstPad *otherpad;
|
||||
|
||||
if (pad == ident->src)
|
||||
otherpad = ident->sink;
|
||||
else
|
||||
otherpad = ident->src;
|
||||
|
||||
if (otherpad != NULL) {
|
||||
if (GST_PAD_PEER (otherpad)) {
|
||||
GstCaps *ret = gst_pad_get_allowed_caps (otherpad);
|
||||
|
||||
if (ident->caps) {
|
||||
GstCaps *ret2 = gst_caps_intersect (ident->caps, ret);
|
||||
|
||||
gst_caps_unref (ret);
|
||||
ret = ret2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (ident->caps)
|
||||
return gst_caps_copy (ident->caps);
|
||||
|
||||
return gst_caps_new_any ();
|
||||
}
|
||||
|
||||
GstPad *
|
||||
gst_spider_identity_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * name)
|
||||
{
|
||||
GstSpiderIdentity *ident;
|
||||
|
||||
/*checks */
|
||||
g_return_val_if_fail (templ != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
|
||||
ident = GST_SPIDER_IDENTITY (element);
|
||||
g_return_val_if_fail (ident != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_SPIDER_IDENTITY (ident), NULL);
|
||||
|
||||
switch (GST_PAD_TEMPLATE_DIRECTION (templ)) {
|
||||
case GST_PAD_SINK:
|
||||
if (ident->sink != NULL)
|
||||
break;
|
||||
/* sink */
|
||||
GST_DEBUG ("element %s requests new sink pad", GST_ELEMENT_NAME (ident));
|
||||
ident->sink =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&spider_sink_factory), "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (ident), ident->sink);
|
||||
gst_pad_set_link_function (ident->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_link));
|
||||
gst_pad_set_getcaps_function (ident->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps));
|
||||
return ident->sink;
|
||||
case GST_PAD_SRC:
|
||||
/* src */
|
||||
if (ident->src != NULL)
|
||||
break;
|
||||
GST_DEBUG ("element %s requests new src pad", GST_ELEMENT_NAME (ident));
|
||||
ident->src =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&spider_src_factory), "src");
|
||||
gst_element_add_pad (GST_ELEMENT (ident), ident->src);
|
||||
gst_pad_set_link_function (ident->src,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_link));
|
||||
gst_pad_set_getcaps_function (ident->src,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps));
|
||||
gst_pad_set_event_function (ident->src,
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_handle_src_event));
|
||||
return ident->src;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
GST_DEBUG ("element %s requested a new pad but none could be created",
|
||||
GST_ELEMENT_NAME (ident));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this function has to
|
||||
* - start the autoplugger
|
||||
* - start type finding
|
||||
* ...
|
||||
*/
|
||||
static GstElementStateReturn
|
||||
gst_spider_identity_change_state (GstElement * element)
|
||||
{
|
||||
GstSpiderIdentity *ident;
|
||||
GstSpider *spider;
|
||||
GstElementStateReturn ret = GST_STATE_SUCCESS;
|
||||
|
||||
/* element check */
|
||||
ident = GST_SPIDER_IDENTITY (element);
|
||||
g_return_val_if_fail (ident != NULL, GST_STATE_FAILURE);
|
||||
g_return_val_if_fail (GST_IS_SPIDER_IDENTITY (ident), GST_STATE_FAILURE);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
gst_caps_replace (&ident->caps, NULL);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
/* autoplugger check */
|
||||
spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
|
||||
g_return_val_if_fail (spider != NULL, GST_STATE_FAILURE);
|
||||
g_return_val_if_fail (GST_IS_SPIDER (spider), GST_STATE_FAILURE);
|
||||
|
||||
/* start typefinding or plugging */
|
||||
if ((GST_RPAD_PEER (ident->sink) != NULL)
|
||||
&& (GST_RPAD_PEER (ident->src) == NULL)) {
|
||||
GstCaps *caps =
|
||||
gst_pad_get_caps ((GstPad *) GST_PAD_PEER (ident->sink));
|
||||
if (gst_caps_is_any (caps) || gst_caps_is_empty (caps)) {
|
||||
gst_spider_identity_start_type_finding (ident);
|
||||
gst_caps_unref (caps);
|
||||
break;
|
||||
} else {
|
||||
gst_spider_identity_plug (ident);
|
||||
}
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
/* autoplug on src */
|
||||
if ((GST_RPAD_PEER (ident->src) != NULL)
|
||||
&& (GST_RPAD_PEER (ident->sink) == NULL)) {
|
||||
gst_spider_identity_plug (ident);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ret != GST_STATE_FAILURE)
|
||||
&& (GST_ELEMENT_CLASS (parent_class)->change_state))
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_identity_start_type_finding (GstSpiderIdentity * ident)
|
||||
{
|
||||
/* GstElement* typefind;
|
||||
gchar *name;*/
|
||||
gboolean restart = FALSE;
|
||||
|
||||
GST_DEBUG ("element %s starts typefinding", GST_ELEMENT_NAME (ident));
|
||||
if (GST_STATE (GST_ELEMENT_PARENT (ident)) == GST_STATE_PLAYING) {
|
||||
gst_element_set_state (GST_ELEMENT (GST_ELEMENT_PARENT (ident)),
|
||||
GST_STATE_PAUSED);
|
||||
restart = TRUE;
|
||||
}
|
||||
|
||||
gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction)
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_sink_loop_type_finding));
|
||||
|
||||
if (restart) {
|
||||
gst_element_set_state (GST_ELEMENT (GST_ELEMENT_PARENT (ident)),
|
||||
GST_STATE_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
/* since we can't set the loop function to NULL if there's a cothread for us,
|
||||
* we have to use a dumb one
|
||||
*/
|
||||
static void
|
||||
gst_spider_identity_dumb_loop (GstSpiderIdentity * ident)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
g_return_if_fail (ident != NULL);
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
g_assert (ident->sink != NULL);
|
||||
|
||||
buf = GST_BUFFER (gst_pad_pull (ident->sink));
|
||||
|
||||
gst_spider_identity_chain (ident->sink, buf);
|
||||
}
|
||||
|
||||
/* do nothing until we're linked - then disable yourself
|
||||
*/
|
||||
static void
|
||||
gst_spider_identity_src_loop (GstSpiderIdentity * ident)
|
||||
{
|
||||
/* checks - disable for speed */
|
||||
g_return_if_fail (ident != NULL);
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
|
||||
/* we don't want a loop function if we're plugged */
|
||||
if (ident->sink && GST_PAD_PEER (ident->sink)) {
|
||||
gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction)
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
|
||||
gst_spider_identity_dumb_loop (ident);
|
||||
return;
|
||||
}
|
||||
gst_element_interrupt (GST_ELEMENT (ident));
|
||||
}
|
||||
|
||||
/* This loop function is only needed when typefinding.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
guint best_probability;
|
||||
GstCaps *caps;
|
||||
}
|
||||
SpiderTypeFind;
|
||||
static guint8 *
|
||||
spider_find_peek (gpointer data, gint64 offset, guint size)
|
||||
{
|
||||
SpiderTypeFind *find = (SpiderTypeFind *) data;
|
||||
gint64 buffer_offset = GST_BUFFER_OFFSET_IS_VALID (find->buffer) ?
|
||||
GST_BUFFER_OFFSET (find->buffer) : 0;
|
||||
|
||||
if (offset >= buffer_offset
|
||||
&& offset + size <= buffer_offset + GST_BUFFER_SIZE (find->buffer)) {
|
||||
GST_LOG ("peek %" G_GINT64_FORMAT ", %u successful", offset, size);
|
||||
return GST_BUFFER_DATA (find->buffer) + offset - buffer_offset;
|
||||
} else {
|
||||
GST_LOG ("peek %" G_GINT64_FORMAT ", %u failed", offset, size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
static void
|
||||
spider_find_suggest (gpointer data, guint probability, const GstCaps * caps)
|
||||
{
|
||||
SpiderTypeFind *find = (SpiderTypeFind *) data;
|
||||
|
||||
GST_INFO ("suggest %u, %" GST_PTR_FORMAT, probability, caps);
|
||||
if (probability > find->best_probability) {
|
||||
gst_caps_replace (&find->caps, gst_caps_copy (caps));
|
||||
find->best_probability = probability;
|
||||
}
|
||||
}
|
||||
static void
|
||||
gst_spider_identity_sink_loop_type_finding (GstSpiderIdentity * ident)
|
||||
{
|
||||
GstData *data;
|
||||
GstTypeFind gst_find;
|
||||
SpiderTypeFind find;
|
||||
GList *walk, *type_list = NULL;
|
||||
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
|
||||
data = gst_pad_pull (ident->sink);
|
||||
if (!GST_IS_BUFFER (data)) {
|
||||
gst_spider_identity_chain (ident->sink, GST_BUFFER (data));
|
||||
return;
|
||||
}
|
||||
|
||||
find.buffer = GST_BUFFER (data);
|
||||
/* maybe there are already valid caps now? */
|
||||
find.caps = gst_pad_get_allowed_caps (ident->sink);
|
||||
if (!gst_caps_is_empty (find.caps) && !gst_caps_is_any (find.caps)) {
|
||||
goto plug;
|
||||
} else {
|
||||
gst_caps_unref (find.caps);
|
||||
find.caps = NULL;
|
||||
}
|
||||
|
||||
/* now do the actual typefinding with the supplied buffer */
|
||||
walk = type_list = gst_type_find_factory_get_list ();
|
||||
|
||||
find.best_probability = 0;
|
||||
find.caps = NULL;
|
||||
gst_find.data = &find;
|
||||
gst_find.get_length = NULL;
|
||||
gst_find.peek = spider_find_peek;
|
||||
gst_find.suggest = spider_find_suggest;
|
||||
while (walk) {
|
||||
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
|
||||
|
||||
GST_DEBUG ("trying typefind function %s",
|
||||
GST_PLUGIN_FEATURE_NAME (factory));
|
||||
gst_type_find_factory_call_function (factory, &gst_find);
|
||||
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
|
||||
goto plug;
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
if (find.best_probability > 0)
|
||||
goto plug;
|
||||
GST_ELEMENT_ERROR (ident, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
|
||||
find.buffer = GST_BUFFER (gst_event_new (GST_EVENT_EOS));
|
||||
|
||||
end:
|
||||
/* remove loop function */
|
||||
gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction)
|
||||
GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
|
||||
|
||||
/* push the buffer */
|
||||
gst_spider_identity_chain (ident->sink, find.buffer);
|
||||
|
||||
return;
|
||||
|
||||
plug:
|
||||
GST_INFO ("typefind function found caps");
|
||||
ident->caps = find.caps;
|
||||
if (GST_PAD_IS_LINKED (ident->src)) {
|
||||
GstPadLinkReturn ret;
|
||||
|
||||
ret = gst_pad_try_set_caps (ident->src, find.caps);
|
||||
if (GST_PAD_LINK_FAILED (ret)) {
|
||||
g_critical ("could not set caps on spideridentity src pad\n");
|
||||
}
|
||||
}
|
||||
GST_LOG_OBJECT (ident, "spider starting caps: %" GST_PTR_FORMAT, find.caps);
|
||||
if (type_list)
|
||||
g_list_free (type_list);
|
||||
|
||||
gst_spider_identity_plug (ident);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_spider_identity_handle_src_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstSpiderIdentity *ident;
|
||||
|
||||
GST_DEBUG ("spider_identity src_event");
|
||||
|
||||
ident = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_FLUSH:
|
||||
case GST_EVENT_SEEK:
|
||||
default:
|
||||
res = gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstspideridentity.h:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_SPIDER_IDENTITY_H__
|
||||
#define __GST_SPIDER_IDENTITY_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_SPIDER_IDENTITY \
|
||||
(gst_spider_identity_get_type())
|
||||
#define GST_SPIDER_IDENTITY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPIDER_IDENTITY,GstSpiderIdentity))
|
||||
#define GST_SPIDER_IDENTITY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPIDER_IDENTITY,GstSpiderIdentityClass))
|
||||
#define GST_IS_SPIDER_IDENTITY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPIDER_IDENTITY))
|
||||
#define GST_IS_SPIDER_IDENTITY_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPIDER_IDENTITY))
|
||||
|
||||
typedef struct _GstSpiderIdentity GstSpiderIdentity;
|
||||
typedef struct _GstSpiderIdentityClass GstSpiderIdentityClass;
|
||||
|
||||
struct _GstSpiderIdentity {
|
||||
GstElement element;
|
||||
|
||||
/* sink and source */
|
||||
GstPad *sink;
|
||||
GstPad *src;
|
||||
|
||||
/* plugged into autoplugger yet? */
|
||||
gboolean plugged;
|
||||
|
||||
/* Caps from typefinding */
|
||||
GstCaps *caps;
|
||||
};
|
||||
|
||||
struct _GstSpiderIdentityClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
GType gst_spider_identity_get_type (void);
|
||||
|
||||
GstSpiderIdentity* gst_spider_identity_new_sink (gchar *name);
|
||||
GstSpiderIdentity* gst_spider_identity_new_src (gchar *name);
|
||||
GstPad* gst_spider_identity_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_SPIDER_IDENTITY_H__ */
|
|
@ -1,138 +0,0 @@
|
|||
#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_PAD_TEMPLATE_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;
|
||||
}
|
||||
|
||||
static void
|
||||
property_change_callback (GObject * object, GstObject * orig,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GValue value = { 0, }; /* the important thing is that value.type = 0 */
|
||||
gchar *str = 0;
|
||||
|
||||
if (pspec->flags & G_PARAM_READABLE) {
|
||||
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
||||
g_object_get_property (G_OBJECT (orig), pspec->name, &value);
|
||||
if (G_IS_PARAM_SPEC_STRING (pspec))
|
||||
str = g_value_dup_string (&value);
|
||||
else if (G_IS_PARAM_SPEC_ENUM (pspec))
|
||||
str = g_strdup_printf ("%d", g_value_get_enum (&value));
|
||||
else if (G_IS_PARAM_SPEC_INT64 (pspec))
|
||||
str = g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (&value));
|
||||
else
|
||||
str = g_strdup_value_contents (&value);
|
||||
|
||||
g_print ("%s: %s = %s\n", GST_OBJECT_NAME (orig), pspec->name, str);
|
||||
g_free (str);
|
||||
g_value_unset (&value);
|
||||
} else {
|
||||
g_warning ("Parameter not readable. What's up with that?");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
error_callback (GObject * object, GstObject * orig, gchar * error)
|
||||
{
|
||||
g_print ("ERROR: %s: %s\n", GST_OBJECT_NAME (orig), error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test program for the autoplugger.
|
||||
* Uses new API extensions (2002-01-28), too.
|
||||
*
|
||||
* USAGE: spidertest <mediafile>
|
||||
* If mediafile can be recognized, xvideo and oss audio output are tried.
|
||||
*/
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GstElement *bin, *filesrc, *decoder, *osssink, *videosink;
|
||||
GList *facs;
|
||||
|
||||
if (argc < 2) {
|
||||
g_print ("usage: %s <file>\n", argv[0]);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
/* create a new bin to hold the elements */
|
||||
bin = gst_pipeline_new ("pipeline");
|
||||
g_signal_connect (bin, "deep_notify", G_CALLBACK (property_change_callback),
|
||||
NULL);
|
||||
g_signal_connect (bin, "error", G_CALLBACK (error_callback), NULL);
|
||||
|
||||
/* create a disk reader */
|
||||
filesrc = gst_element_factory_make ("filesrc", "disk_source");
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
||||
/* now it's time to get the decoder */
|
||||
decoder = gst_element_factory_make ("spider", "spider");
|
||||
if (!decoder) {
|
||||
g_print ("could not find plugin \"spider\"\n");
|
||||
exit (-2);
|
||||
}
|
||||
|
||||
/* only use decoding plugins */
|
||||
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_element_factory_make ("osssink", "audio");
|
||||
videosink = gst_element_factory_make ("xvideosink", "video");
|
||||
|
||||
if ((!osssink) || (!videosink)) {
|
||||
g_print ("could not create output plugins\n");
|
||||
exit (-3);
|
||||
}
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add (GST_BIN (bin), filesrc);
|
||||
gst_bin_add (GST_BIN (bin), decoder);
|
||||
gst_bin_add (GST_BIN (bin), osssink);
|
||||
gst_bin_add (GST_BIN (bin), videosink);
|
||||
|
||||
/* link objects */
|
||||
if (!(gst_element_link (filesrc, decoder) &&
|
||||
gst_element_link (decoder, osssink) &&
|
||||
gst_element_link (decoder, videosink))) {
|
||||
g_print ("the pipeline could not be linked\n");
|
||||
exit (-4);
|
||||
}
|
||||
|
||||
/* gst_bin_use_clock (GST_BIN (bin), gst_system_clock_obtain ());*/
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state (bin, GST_STATE_PLAYING);
|
||||
|
||||
while (gst_bin_iterate (GST_BIN (bin)));
|
||||
|
||||
exit (0);
|
||||
}
|
Loading…
Reference in a new issue