mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +00:00
initial import of the spider autoplugger
Original commit message from CVS: initial import of the spider autoplugger
This commit is contained in:
parent
60b74d0591
commit
475a7acaa3
7 changed files with 1806 additions and 0 deletions
391
gst/autoplug/gstsearchfuncs.c
Normal file
391
gst/autoplug/gstsearchfuncs.c
Normal file
|
@ -0,0 +1,391 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#include "gstsearchfuncs.h"
|
||||
|
||||
/* function that really misses in GLib
|
||||
*/
|
||||
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_can_connect_src:
|
||||
* @fac: factory to connect to
|
||||
* @src: caps to check
|
||||
*
|
||||
* Checks if a factory's sink can connect to the given caps
|
||||
*
|
||||
* Return: TRUE, if a connection can be established.
|
||||
*/
|
||||
GstPadTemplate *
|
||||
gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src)
|
||||
{
|
||||
GList *templs;
|
||||
|
||||
templs = fac->padtemplates;
|
||||
|
||||
while (templs)
|
||||
{
|
||||
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && gst_caps_check_compatibility(src, GST_PADTEMPLATE_CAPS (templs->data)))
|
||||
{
|
||||
return GST_PADTEMPLATE (templs->data);
|
||||
}
|
||||
templs = g_list_next (templs);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* gst_autoplug_can_connect_sink:
|
||||
* @fac: factory to connect to
|
||||
* @src: caps to check
|
||||
*
|
||||
* Checks if a factory's src can connect to the given caps
|
||||
*
|
||||
* Return: TRUE, if a connection can be established.
|
||||
*/
|
||||
GstPadTemplate *
|
||||
gst_autoplug_can_connect_sink (GstElementFactory *fac, GstCaps *sink)
|
||||
{
|
||||
GList *templs;
|
||||
|
||||
templs = fac->padtemplates;
|
||||
|
||||
while (templs)
|
||||
{
|
||||
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) && gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (templs->data), sink))
|
||||
{
|
||||
return GST_PADTEMPLATE (templs->data);
|
||||
}
|
||||
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_caps_check_compatibility (gst_padtemplate_get_caps (srctemp),
|
||||
gst_padtemplate_get_caps (desttemp))) {
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||
"factory \"%s\" can connect with factory \"%s\"\n",
|
||||
GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
|
||||
return desttemp;
|
||||
}
|
||||
}
|
||||
|
||||
desttemps = g_list_next (desttemps);
|
||||
}
|
||||
srctemps = g_list_next (srctemps);
|
||||
}
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||
"factory \"%s\" cannot connect with factory \"%s\"\n",
|
||||
GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
|
||||
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_PADTEMPLATE_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;
|
||||
}
|
||||
|
||||
|
||||
/* returns all factories which have sinks with non-NULL caps and srcs with
|
||||
* any caps.
|
||||
*/
|
||||
GList *
|
||||
gst_autoplug_factories_filters_with_sink_caps (GList *factories)
|
||||
{
|
||||
GList *ret = NULL;
|
||||
|
||||
while (factories)
|
||||
{
|
||||
GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
|
||||
gboolean have_src = FALSE;
|
||||
gboolean have_sink = FALSE;
|
||||
while (templs)
|
||||
{
|
||||
if (GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC)
|
||||
{
|
||||
have_src = TRUE;
|
||||
}
|
||||
if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && (GST_PADTEMPLATE_CAPS (templs->data) != NULL))
|
||||
{
|
||||
have_sink = TRUE;
|
||||
}
|
||||
if (have_src && have_sink)
|
||||
{
|
||||
ret = g_list_prepend (ret, factories->data);
|
||||
break;
|
||||
}
|
||||
templs = g_list_next (templs);
|
||||
}
|
||||
factories = g_list_next (factories);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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_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;
|
||||
}
|
||||
/*********************************************************************
|
||||
*
|
||||
* SHORTEST PATH ALGORITHM
|
||||
*/
|
||||
/**
|
||||
* gst_autoplug_sp:
|
||||
* @srccaps: Caps to plug from
|
||||
* @sinkcaps: Caps to plug to
|
||||
* @factories: GList containing all allowed #GstElementFactory entries
|
||||
*
|
||||
* main function
|
||||
*
|
||||
* Returns: a GList of GstElementFactory items which have to be connected to get
|
||||
* the shortest path.
|
||||
*/
|
||||
GList *
|
||||
gst_autoplug_sp (GstCaps *srccaps, GstCaps *sinkcaps, GList *factories)
|
||||
{
|
||||
GList *factory_nodes = NULL;
|
||||
guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */
|
||||
GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */
|
||||
|
||||
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, "attempting to autoplug via shortest path");
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps));
|
||||
/* g_print ("trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps)); */
|
||||
/* wrap all factories as GstAutoplugNode
|
||||
* initialize the cost */
|
||||
while (factories)
|
||||
{
|
||||
GstAutoplugNode *node = g_new0 (GstAutoplugNode, 1);
|
||||
node->prev = NULL;
|
||||
node->fac = (GstElementFactory *) factories->data;
|
||||
node->templ = gst_autoplug_can_connect_src (node->fac, srccaps);
|
||||
node->cost = (node->templ ? gst_autoplug_get_cost (node->fac) : GST_AUTOPLUG_MAX_COST);
|
||||
node->endpoint = gst_autoplug_can_connect_sink (node->fac, sinkcaps);
|
||||
if ((node->endpoint != NULL) && (bestnode == NULL || (node->cost < bestnode->cost)))
|
||||
{
|
||||
bestnode = node;
|
||||
}
|
||||
factory_nodes = g_list_prepend (factory_nodes, node);
|
||||
/* make curcost the minimum cost of any plugin */
|
||||
curcost = node->cost < curcost ? node->cost : curcost;
|
||||
factories = g_list_next (factories);
|
||||
}
|
||||
|
||||
/* check if we even have possible endpoints */
|
||||
if (bestnode == NULL)
|
||||
{
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no factory found that could connect to sink caps\n");
|
||||
g_list_free_list_and_elements (factory_nodes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* iterate until we found the best path */
|
||||
while (curcost < GST_AUTOPLUG_MAX_COST)
|
||||
{
|
||||
GList *nodes = factory_nodes;
|
||||
guint nextcost = GST_AUTOPLUG_MAX_COST; /* next cost to check */
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "iterating at current cost %d, bestnode %s at %d\n", curcost, GST_OBJECT_NAME (bestnode->fac), bestnode->cost);
|
||||
/* check if we already have a valid best connection to the sink */
|
||||
if (bestnode->cost <= curcost)
|
||||
{
|
||||
GList *ret;
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a way to connect via %s\n", GST_OBJECT_NAME ((GstObject *) bestnode->fac));
|
||||
/* enter all factories into the return list */
|
||||
ret = g_list_prepend (NULL, bestnode->fac);
|
||||
bestnode = bestnode->prev;
|
||||
while (bestnode != NULL)
|
||||
{
|
||||
ret = g_list_prepend (ret, bestnode->fac);
|
||||
bestnode = bestnode->prev;
|
||||
}
|
||||
g_list_free_list_and_elements (factory_nodes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* iterate over all factories we have
|
||||
* if they have the current cost, calculate if this
|
||||
* factory supplies shorter paths to other elements
|
||||
*/
|
||||
while (nodes)
|
||||
{
|
||||
if (((GstAutoplugNode *) nodes->data)->cost == curcost)
|
||||
{
|
||||
/* now check all elements if we got a shorter path */
|
||||
GList *sinknodes = factory_nodes;
|
||||
GstAutoplugNode *srcnode = (GstAutoplugNode *) nodes->data;
|
||||
while (sinknodes)
|
||||
{
|
||||
GstAutoplugNode *sinknode = (GstAutoplugNode *) sinknodes->data;
|
||||
GstPadTemplate *templ;
|
||||
if ((sinknode->cost > srcnode->cost + gst_autoplug_get_cost (sinknode->fac)) && (templ = gst_autoplug_can_match(srcnode->fac, sinknode->fac)))
|
||||
{
|
||||
/* we got a shorter path
|
||||
* now enter that path to that node */
|
||||
sinknode->prev = srcnode;
|
||||
sinknode->templ = templ;
|
||||
sinknode->cost = srcnode->cost + gst_autoplug_get_cost (sinknode->fac);
|
||||
/* make sure to set which cost to view next */
|
||||
nextcost = (nextcost > sinknode->cost) ? sinknode->cost : nextcost;
|
||||
/* did we get a new best node? */
|
||||
if (sinknode->endpoint && (sinknode->cost < bestnode->cost))
|
||||
{
|
||||
bestnode = sinknode;
|
||||
}
|
||||
}
|
||||
sinknodes = g_list_next (sinknodes);
|
||||
}
|
||||
/* FIXME: for speed remove the item we just iterated with from the factory_nodes
|
||||
* but don't free it yet and don't forget to free it.
|
||||
*/
|
||||
}
|
||||
nodes = g_list_next (nodes);
|
||||
}
|
||||
curcost = nextcost;
|
||||
}
|
||||
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found no path from source caps to sink caps\n");
|
||||
g_list_free_list_and_elements (factory_nodes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
63
gst/autoplug/gstsearchfuncs.h
Normal file
63
gst/autoplug/gstsearchfuncs.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* 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 */
|
||||
GstPadTemplate * gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src);
|
||||
GstPadTemplate * gst_autoplug_can_connect_sink (GstElementFactory *fac, 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 (GstCaps *src_caps, GstCaps *sink_caps, GList *factories);
|
||||
|
||||
#endif /* __GST_SEARCHFUNCS_H__ */
|
536
gst/autoplug/gstspider.c
Normal file
536
gst/autoplug/gstspider.c
Normal file
|
@ -0,0 +1,536 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstspider.c: element to automatically connect 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)
|
||||
* - allow disconnecting
|
||||
* - 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
|
||||
* ...
|
||||
*/
|
||||
|
||||
#include "gstspider.h"
|
||||
#include "gstspideridentity.h"
|
||||
#include "gstsearchfuncs.h"
|
||||
|
||||
/* signals and args */
|
||||
enum {
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_PLUGTYPE,
|
||||
/* FILL ME TOO */
|
||||
};
|
||||
|
||||
/* generic templates */
|
||||
GST_PADTEMPLATE_FACTORY (spider_src_factory,
|
||||
"src_%02d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_REQUEST,
|
||||
NULL /* no caps */
|
||||
);
|
||||
|
||||
GST_PADTEMPLATE_FACTORY (spider_sink_factory,
|
||||
"sink_%02d",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
NULL /* no caps */
|
||||
);
|
||||
/* standard GObject stuff */
|
||||
static void gst_spider_class_init (GstSpiderClass *klass);
|
||||
static void gst_spider_init (GstSpider *spider);
|
||||
static void gst_spider_dispose (GObject *object);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* autoplugging functions */
|
||||
static GstElement * gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir);
|
||||
static GstPadConnectReturn gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdentity *sink);
|
||||
static GstPadConnectReturn gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath);
|
||||
|
||||
/* random functions */
|
||||
static gchar * gst_spider_unused_elementname (GstBin *bin, const gchar *startwith);
|
||||
|
||||
/* === 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_PLUGTYPE,
|
||||
g_param_spec_int ("plugtype", "plug direction", "encoding, decoding or anything",
|
||||
GST_SPIDER_ANY, GST_SPIDER_PLUGTYPES - 1, 0, G_PARAM_READWRITE));
|
||||
|
||||
gobject_class->set_property = gst_spider_set_property;
|
||||
gobject_class->get_property = gst_spider_get_property;
|
||||
|
||||
gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_spider_request_new_pad);
|
||||
}
|
||||
static void
|
||||
gst_spider_init (GstSpider *spider)
|
||||
{
|
||||
spider->plugtype = GST_SPIDER_ANY;
|
||||
}
|
||||
|
||||
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_PADTEMPLATE (templ), NULL);
|
||||
|
||||
spider = GST_SPIDER (element);
|
||||
|
||||
/* create an identity object, so we have a pad */
|
||||
switch ( GST_PADTEMPLATE_DIRECTION (templ))
|
||||
{
|
||||
case GST_PAD_SRC:
|
||||
padname = gst_spider_unused_elementname ((GstBin *)spider, "src_");
|
||||
identity = gst_spider_identity_new_src (padname);
|
||||
break;
|
||||
case GST_PAD_SINK:
|
||||
padname = gst_spider_unused_elementname ((GstBin *)spider, "sink_");
|
||||
identity = gst_spider_identity_new_sink (padname);
|
||||
break;
|
||||
case GST_PAD_UNKNOWN:
|
||||
default:
|
||||
g_warning("Spider: you must request a source or sink pad.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* connect a ghost pad on the right side of the identity and set the requested template */
|
||||
returnpad = gst_spider_identity_request_new_pad (GST_ELEMENT (identity), templ, NULL);
|
||||
|
||||
/* FIXME: use the requested name for the pad */
|
||||
|
||||
gst_object_ref (GST_OBJECT (templ));
|
||||
GST_PAD_PADTEMPLATE (returnpad) = templ;
|
||||
|
||||
gst_bin_add (GST_BIN (element), GST_ELEMENT (identity));
|
||||
|
||||
returnpad = gst_element_add_ghost_pad (element, returnpad, padname);
|
||||
GST_DEBUG (GST_CAT_ELEMENT_PADS, "successuflly created requested pad %s:%s\n", 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;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_SPIDER (object));
|
||||
|
||||
spider = GST_SPIDER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_PLUGTYPE:
|
||||
switch (g_value_get_int (value))
|
||||
{
|
||||
case GST_SPIDER_ANY:
|
||||
spider->plugtype = GST_SPIDER_ANY;
|
||||
GST_DEBUG (0,"spider: setting plugtype to ANY\n");
|
||||
break;
|
||||
case GST_SPIDER_ENCODE:
|
||||
spider->plugtype = GST_SPIDER_ENCODE;
|
||||
GST_DEBUG (0,"spider: setting plugtype to ENCODE\n");
|
||||
break;
|
||||
case GST_SPIDER_DECODE:
|
||||
spider->plugtype = GST_SPIDER_DECODE;
|
||||
GST_DEBUG (0,"spider: setting plugtype to DECODE\n");
|
||||
break;
|
||||
default:
|
||||
GST_DEBUG (0,"spider: invalid value %d while setting plugtype\n", g_value_get_int (value));
|
||||
break;
|
||||
}
|
||||
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_PLUGTYPE:
|
||||
g_value_set_int (value, spider->plugtype);
|
||||
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;
|
||||
}
|
||||
/* callback and struct for the data supplied to the callback that is used to connect dynamic pads */
|
||||
typedef struct {
|
||||
GstSpider *spider;
|
||||
GstElement *sink;
|
||||
GList *plugpath;
|
||||
gulong signal_id;
|
||||
} GstSpiderConnectSometimes;
|
||||
static void
|
||||
gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnectSometimes *data)
|
||||
{
|
||||
gboolean restart = FALSE;
|
||||
if (gst_element_get_state ((GstElement *) data->spider) == GST_STATE_PLAYING)
|
||||
{
|
||||
restart = TRUE;
|
||||
gst_element_set_state ((GstElement *) data->spider, GST_STATE_PAUSED);
|
||||
}
|
||||
gst_spider_create_and_plug (data->spider, src, data->sink, data->plugpath);
|
||||
g_signal_handler_disconnect (src, data->signal_id);
|
||||
if (restart)
|
||||
{
|
||||
gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING);
|
||||
}
|
||||
g_free (data);
|
||||
|
||||
gst_element_interrupt (src);
|
||||
}
|
||||
/* connects newsrc to newsink using the elementfactories in plugpath */
|
||||
static GstPadConnectReturn
|
||||
gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath)
|
||||
{
|
||||
GstElement *element;
|
||||
|
||||
/* get the next element */
|
||||
if (plugpath == NULL)
|
||||
{
|
||||
element = sink;
|
||||
} else {
|
||||
element = gst_elementfactory_create ((GstElementFactory *) plugpath->data,
|
||||
gst_spider_unused_elementname (GST_BIN (spider), GST_OBJECT_NAME (plugpath->data)));
|
||||
gst_bin_add (GST_BIN (spider), element);
|
||||
}
|
||||
/* insert and connect new element */
|
||||
if (!gst_element_connect_elements (src, element))
|
||||
{
|
||||
/* check if the src has SOMETIMES templates. If so, connect a callback */
|
||||
GList *templs = gst_element_get_padtemplate_list (src);
|
||||
|
||||
/* remove element that couldn't be connected, if it wasn't the endpoint */
|
||||
if (element != sink)
|
||||
gst_bin_remove (GST_BIN (spider), element);
|
||||
|
||||
while (templs) {
|
||||
GstPadTemplate *templ = (GstPadTemplate *) templs->data;
|
||||
if ((GST_PADTEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PADTEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
|
||||
{
|
||||
GstSpiderConnectSometimes *data = g_new (GstSpiderConnectSometimes, 1);
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (element));
|
||||
data->spider = spider;
|
||||
data->sink = sink;
|
||||
data->plugpath = plugpath;
|
||||
data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad",
|
||||
G_CALLBACK (gst_spider_connect_sometimes), data);
|
||||
|
||||
return GST_PAD_CONNECT_DELAYED;
|
||||
}
|
||||
templs = g_list_next (templs);
|
||||
}
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (element));
|
||||
g_list_free (plugpath);
|
||||
return GST_PAD_CONNECT_REFUSED;
|
||||
}
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "added element %s and attached it to element %s\n", GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (src));
|
||||
plugpath = g_list_delete_link (plugpath, plugpath);
|
||||
|
||||
/* recursively connect the rest of the elements */
|
||||
if (element != sink) {
|
||||
return gst_spider_create_and_plug (spider, element, sink, plugpath);
|
||||
}
|
||||
|
||||
return GST_PAD_CONNECT_DONE;
|
||||
}
|
||||
/* checks, if src is already connected 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);
|
||||
|
||||
while (padlist)
|
||||
{
|
||||
GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data);
|
||||
/* is the pad on the right side and is it connected? */
|
||||
if ((GST_PAD_DIRECTION (pad) == dir) && (pad = GST_PAD (GST_RPAD_PEER (pad))))
|
||||
{
|
||||
/* is the element the pad is connected to of the right type? */
|
||||
GstElement *element = GST_PAD_PARENT (pad);
|
||||
if (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))->elementfactory == fac) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
padlist = g_list_next (padlist);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/* plugs a pad into the autoplugger if it isn't plugged yet */
|
||||
void
|
||||
gst_spider_plug (GstSpiderIdentity *ident)
|
||||
{
|
||||
GstSpider *spider;
|
||||
GList *plugto;
|
||||
GstPad *plugpad;
|
||||
|
||||
/* checks */
|
||||
g_return_if_fail (ident != NULL);
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
|
||||
g_assert (spider != NULL);
|
||||
g_assert (GST_IS_SPIDER (spider));
|
||||
|
||||
/* return, if we're already plugged */
|
||||
if (ident->plugged) return;
|
||||
|
||||
if (ident->sink && GST_PAD_PEER (ident->sink))
|
||||
{
|
||||
if (ident->src && GST_PAD_PEER (ident->src))
|
||||
{
|
||||
/* Hey, the ident is connected on both sides */
|
||||
g_warning ("Trying to autoplug a connected element. Aborting...");
|
||||
return;
|
||||
} else {
|
||||
plugpad = ident->sink;
|
||||
}
|
||||
} else {
|
||||
if (ident->src && GST_PAD_PEER (ident->src))
|
||||
{
|
||||
plugpad = ident->src;
|
||||
} else {
|
||||
/* the ident isn't connected on either side */
|
||||
g_warning ("Trying to autoplug an unconnected element. Aborting...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* now iterate all possible pads and connect */
|
||||
plugto = gst_element_get_pad_list (GST_ELEMENT (spider));
|
||||
while (plugto)
|
||||
{
|
||||
GstPad *otherpad = (GstPad *) GST_GPAD_REALPAD (plugto->data);
|
||||
GstSpiderIdentity *peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad);
|
||||
/* we only want to connect to the other side */
|
||||
if (GST_PAD_DIRECTION (plugpad) != GST_PAD_DIRECTION (otherpad))
|
||||
{
|
||||
/* we only connect to plugged in elements */
|
||||
if (peer->plugged == TRUE)
|
||||
{
|
||||
/* plug in the right direction */
|
||||
if (plugpad == ident->src)
|
||||
{
|
||||
gst_spider_plug_peers (spider, peer, ident);
|
||||
} else {
|
||||
gst_spider_plug_peers (spider, ident, peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
plugto = g_list_next (plugto);
|
||||
}
|
||||
|
||||
ident->plugged = TRUE;
|
||||
}
|
||||
/* connect the src Identity element to the sink identity element
|
||||
* Returns: DONE, if item could be plugged, DELAYED, if a callback is needed or REFUSED,
|
||||
* if no connection was possible
|
||||
*/
|
||||
static GstPadConnectReturn
|
||||
gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdentity *sink)
|
||||
{
|
||||
GstElement *element, *newsrc, *newsink;
|
||||
GstPad *pad, *compat;
|
||||
GList *plugpath;
|
||||
GList *neededfactories;
|
||||
GList *templist;
|
||||
gboolean result = TRUE;
|
||||
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
|
||||
|
||||
neededfactories = (GList *) gst_elementfactory_get_list ();
|
||||
/* use only elements which have sources and sinks and where the sinks have caps */
|
||||
neededfactories = gst_autoplug_factories_filters_with_sink_caps (neededfactories);
|
||||
|
||||
/* use only the elements with exactly 1 sink/src when decoding/encoding */
|
||||
if (spider->plugtype == GST_SPIDER_ENCODE)
|
||||
{
|
||||
templist = neededfactories;
|
||||
neededfactories = gst_autoplug_factories_at_most_templates (neededfactories, GST_PAD_SRC, 1);
|
||||
g_list_free (templist);
|
||||
}
|
||||
if (spider->plugtype == GST_SPIDER_DECODE)
|
||||
{
|
||||
templist = neededfactories;
|
||||
neededfactories = gst_autoplug_factories_at_most_templates (neededfactories, GST_PAD_SINK, 1);
|
||||
g_list_free (templist);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* if there is no way to plug: return */
|
||||
if (plugpath == NULL) {
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to plug from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
|
||||
return FALSE;
|
||||
}
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a connection that needs %d elements\n", 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
|
||||
*/
|
||||
newsrc = (GstElement *) src;
|
||||
while (element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC))
|
||||
{
|
||||
newsrc = element;
|
||||
plugpath = g_list_delete_link (plugpath, plugpath);
|
||||
}
|
||||
/* now do the same at the end */
|
||||
newsink = (GstElement *) sink;
|
||||
templist = g_list_last (plugpath);
|
||||
while (element = gst_spider_find_element_to_plug (newsink, (GstElementFactory *) plugpath->data, GST_PAD_SINK))
|
||||
{
|
||||
GList *cur = templist;
|
||||
newsink = element;
|
||||
templist = g_list_previous (templist);
|
||||
g_list_delete_link (cur, cur);
|
||||
}
|
||||
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%d elements must be inserted to establish the connection\n", g_list_length (plugpath));
|
||||
/* create the elements and plug them */
|
||||
result = gst_spider_create_and_plug (spider, newsrc, newsink, plugpath);
|
||||
|
||||
/* free no longer needed data */
|
||||
g_list_free (neededfactories);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GstElementDetails gst_spider_details = {
|
||||
"Spider",
|
||||
"Filter/Autplug",
|
||||
"Automatically connect sinks and sources",
|
||||
VERSION,
|
||||
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
|
||||
"(C) 2002",
|
||||
};
|
||||
|
||||
static gboolean
|
||||
plugin_init (GModule *module, GstPlugin *plugin)
|
||||
{
|
||||
GstElementFactory *factory;
|
||||
|
||||
factory = gst_elementfactory_new("spider", GST_TYPE_SPIDER,
|
||||
&gst_spider_details);
|
||||
g_return_val_if_fail(factory != NULL, FALSE);
|
||||
|
||||
gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (spider_src_factory));
|
||||
gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (spider_sink_factory));
|
||||
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstPluginDesc plugin_desc = {
|
||||
GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"gstspider",
|
||||
plugin_init
|
||||
};
|
||||
|
||||
|
||||
|
77
gst/autoplug/gstspider.h
Normal file
77
gst/autoplug/gstspider.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* 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"
|
||||
|
||||
typedef enum {
|
||||
GST_SPIDER_ANY = 0,
|
||||
GST_SPIDER_ENCODE = 1,
|
||||
GST_SPIDER_DECODE = 2,
|
||||
GST_SPIDER_PLUGTYPES
|
||||
} GstSpiderPlugtype;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
extern GstElementDetails gst_spider_details;
|
||||
|
||||
#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;
|
||||
|
||||
GstSpiderPlugtype plugtype; /* direction to plug */
|
||||
};
|
||||
|
||||
struct _GstSpiderClass {
|
||||
GstBinClass parent_class;
|
||||
};
|
||||
|
||||
/* default initialization stuff */
|
||||
GType gst_spider_get_type (void);
|
||||
|
||||
/* private functions to be called by GstSpiderIdentity */
|
||||
void gst_spider_plug (GstSpiderIdentity *ident);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __GST_SPIDER_H__ */
|
502
gst/autoplug/gstspideridentity.c
Normal file
502
gst/autoplug/gstspideridentity.c
Normal file
|
@ -0,0 +1,502 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "gstspideridentity.h"
|
||||
|
||||
#include "gstspider.h"
|
||||
|
||||
GstElementDetails gst_spider_identity_details = {
|
||||
"SpiderIdentity",
|
||||
"Filter/Autoplug",
|
||||
"connection between spider and outside elements",
|
||||
VERSION,
|
||||
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
|
||||
"(C) 2002",
|
||||
};
|
||||
|
||||
|
||||
/* generic templates
|
||||
* delete me when meging with spider.c
|
||||
*/
|
||||
GST_PADTEMPLATE_FACTORY (spider_src_factory,
|
||||
"src_%02d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_REQUEST,
|
||||
NULL /* no caps */
|
||||
);
|
||||
|
||||
GST_PADTEMPLATE_FACTORY (spider_sink_factory,
|
||||
"sink_%02d",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
NULL /* no caps */
|
||||
);
|
||||
|
||||
/* 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 GstPadConnectReturn gst_spider_identity_connect (GstPad *pad, GstCaps *caps);
|
||||
static GstCaps* gst_spider_identity_getcaps (GstPad *pad, GstCaps *caps);
|
||||
/* loop functions */
|
||||
static void gst_spider_identity_dumb_loop (GstSpiderIdentity *ident);
|
||||
static void gst_spider_identity_src_loop (GstSpiderIdentity *ident);
|
||||
static void gst_spider_identity_sink_loop_typefinding (GstSpiderIdentity *ident);
|
||||
static void gst_spider_identity_sink_loop_emptycache (GstSpiderIdentity *ident);
|
||||
|
||||
/* set/get functions */
|
||||
gboolean gst_spider_identity_is_plugged (GstSpiderIdentity *identity);
|
||||
void gst_spider_identity_set_caps (GstSpiderIdentity *identity, GstCaps *caps);
|
||||
|
||||
/* callback */
|
||||
static void callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdentity *identity);
|
||||
|
||||
/* other functions */
|
||||
static void gst_spider_identity_start_typefinding (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);
|
||||
}
|
||||
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_padtemplate (gstelement_class, GST_PADTEMPLATE_GET (spider_src_factory));
|
||||
gst_element_class_add_padtemplate (gstelement_class, GST_PADTEMPLATE_GET (spider_sink_factory));
|
||||
|
||||
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 GstBufferPool*
|
||||
gst_spider_identity_get_bufferpool (GstPad *pad)
|
||||
{
|
||||
/* fix me */
|
||||
GstSpiderIdentity *spider_identity;
|
||||
|
||||
spider_identity = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
|
||||
|
||||
return gst_pad_get_bufferpool (spider_identity->src);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_identity_init (GstSpiderIdentity *spider_identity)
|
||||
{
|
||||
/* pads */
|
||||
spider_identity->sink = NULL;
|
||||
spider_identity->src = NULL;
|
||||
|
||||
/* variables */
|
||||
spider_identity->plugged = FALSE;
|
||||
|
||||
/* caching */
|
||||
spider_identity->cache_start = NULL;
|
||||
spider_identity->cache_end = NULL;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spider_identity_chain (GstPad *pad, GstBuffer *buf)
|
||||
{
|
||||
GstSpiderIdentity *ident;
|
||||
|
||||
/* g_print ("chaining on pad %s:%s with buffer %p\n", GST_DEBUG_PAD_NAME (pad), buf); */
|
||||
|
||||
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_pad_event_default (ident->sink, GST_EVENT (buf));
|
||||
}
|
||||
|
||||
if ((ident->src != NULL) && (GST_PAD_PEER (ident->src) != NULL)) {
|
||||
/* g_print("pushing buffer %p (refcount %d - buffersize %d) to pad %s:%s\n", buf, GST_BUFFER_REFCOUNT (buf), GST_BUFFER_SIZE (buf), GST_DEBUG_PAD_NAME (ident->src)); */
|
||||
gst_pad_push (ident->src, buf);
|
||||
} else if (GST_IS_BUFFER (buf)) {
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
}
|
||||
GstSpiderIdentity*
|
||||
gst_spider_identity_new_src (gchar *name)
|
||||
{
|
||||
GstSpiderIdentity *ret = (GstSpiderIdentity *) g_object_new (gst_spider_identity_get_type (), NULL);
|
||||
|
||||
GST_ELEMENT_NAME (ret) = name;
|
||||
/* set the right functions */
|
||||
gst_element_set_loop_function (GST_ELEMENT (ret), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_src_loop));
|
||||
|
||||
return ret;
|
||||
}
|
||||
GstSpiderIdentity*
|
||||
gst_spider_identity_new_sink (gchar *name)
|
||||
{
|
||||
GstSpiderIdentity *ret = (GstSpiderIdentity *) g_object_new (gst_spider_identity_get_type (), NULL);
|
||||
|
||||
GST_ELEMENT_NAME (ret) = name;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* shamelessly stolen from gstqueue.c to get proxy connections */
|
||||
static GstPadConnectReturn
|
||||
gst_spider_identity_connect (GstPad *pad, GstCaps *caps)
|
||||
{
|
||||
GstSpiderIdentity *spider_identity = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
|
||||
GstPad *otherpad;
|
||||
|
||||
if (pad == spider_identity->src)
|
||||
otherpad = spider_identity->sink;
|
||||
else
|
||||
otherpad = spider_identity->src;
|
||||
|
||||
if (otherpad != NULL)
|
||||
return gst_pad_proxy_connect (otherpad, caps);
|
||||
|
||||
return GST_PAD_CONNECT_OK;
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
gst_spider_identity_getcaps (GstPad *pad, GstCaps *caps)
|
||||
{
|
||||
GstSpiderIdentity *spider_identity = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
|
||||
GstPad *otherpad;
|
||||
|
||||
if (pad == spider_identity->src)
|
||||
otherpad = spider_identity->sink;
|
||||
else
|
||||
otherpad = spider_identity->src;
|
||||
|
||||
if (otherpad != NULL)
|
||||
return gst_pad_get_allowed_caps (otherpad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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_PADTEMPLATE (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_PADTEMPLATE_DIRECTION (templ))
|
||||
{
|
||||
case GST_PAD_SINK:
|
||||
if (ident->sink != NULL) break;
|
||||
/* sink */
|
||||
GST_DEBUG(0, "element %s requests new sink pad\n", GST_ELEMENT_NAME(ident));
|
||||
ident->sink = gst_pad_new ("sink", GST_PAD_SINK);
|
||||
gst_element_add_pad (GST_ELEMENT (ident), ident->sink);
|
||||
gst_pad_set_connect_function (ident->sink, GST_DEBUG_FUNCPTR (gst_spider_identity_connect));
|
||||
gst_pad_set_getcaps_function (ident->sink, GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps));
|
||||
return ident->sink;
|
||||
case GST_PAD_SRC:
|
||||
/* src */
|
||||
if (ident->src != NULL) break;
|
||||
GST_DEBUG(0, "element %s requests new src pad\n", GST_ELEMENT_NAME(ident));
|
||||
ident->src = gst_pad_new ("src", GST_PAD_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));
|
||||
return ident->src;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
GST_DEBUG(0, "element %s requested a new pad but none could be created\n", 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_PAD_CONNECT_REFUSED);
|
||||
g_return_val_if_fail (GST_IS_SPIDER_IDENTITY (ident), GST_PAD_CONNECT_REFUSED);
|
||||
|
||||
/* autoplugger check */
|
||||
spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
|
||||
g_return_val_if_fail (spider != NULL, GST_PAD_CONNECT_REFUSED);
|
||||
g_return_val_if_fail (GST_IS_SPIDER (spider), GST_PAD_CONNECT_REFUSED);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
/* start typefinding or plugging */
|
||||
if ((ident->sink != NULL) && (ident->src == NULL))
|
||||
{
|
||||
if (gst_pad_get_caps ((GstPad *) GST_PAD_PEER (ident->sink)) == NULL)
|
||||
{
|
||||
gst_spider_identity_start_typefinding (ident);
|
||||
break;
|
||||
} else {
|
||||
gst_spider_plug (ident);
|
||||
}
|
||||
}
|
||||
/* autoplug on src */
|
||||
if ((ident->src != NULL) && (ident->sink == NULL))
|
||||
{
|
||||
gst_spider_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_typefinding (GstSpiderIdentity *ident)
|
||||
{
|
||||
GstElement* typefind;
|
||||
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG, "element %s starts typefinding", GST_ELEMENT_NAME(ident));
|
||||
|
||||
/* create and connect typefind object */
|
||||
typefind = gst_elementfactory_make ("typefind", g_strdup_printf("%s%s", "typefind", GST_ELEMENT_NAME(ident)));
|
||||
g_signal_connect (G_OBJECT (typefind), "have_type",
|
||||
G_CALLBACK (callback_typefind_have_type), ident);
|
||||
gst_bin_add (GST_BIN (GST_ELEMENT_PARENT (ident)), typefind);
|
||||
gst_pad_connect (gst_element_get_compatible_pad ((GstElement *) ident, gst_element_get_pad (typefind, "sink")), gst_element_get_pad (typefind, "sink"));
|
||||
|
||||
gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_sink_loop_typefinding));
|
||||
}
|
||||
/* waiting for a good suggestion on where to set the caps from typefinding
|
||||
* Caps must be cleared when pad is disconnected
|
||||
*
|
||||
* Currently we are naive and set the caps on the source of the identity object
|
||||
* directly and hope to avoid any disturbance in the force.
|
||||
*/
|
||||
void
|
||||
gst_spider_identity_set_caps (GstSpiderIdentity *ident, GstCaps *caps)
|
||||
{
|
||||
if (ident->src)
|
||||
{
|
||||
gst_pad_try_set_caps (ident->src, caps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdentity *ident)
|
||||
{
|
||||
gboolean restart_spider = FALSE;
|
||||
|
||||
GST_INFO (GST_CAT_AUTOPLUG, "element %s has found caps", GST_ELEMENT_NAME(ident));
|
||||
/* checks */
|
||||
|
||||
/* we have to ref the typefind, because if me remove it the scheduler segfaults
|
||||
* FIXME: get rid of the typefinder
|
||||
*/
|
||||
gst_object_ref (GST_OBJECT (typefind));
|
||||
|
||||
g_assert (GST_IS_ELEMENT (typefind));
|
||||
g_assert (GST_IS_SPIDER_IDENTITY (ident));
|
||||
|
||||
/* pause the autoplugger */
|
||||
if (gst_element_get_state (GST_ELEMENT (GST_ELEMENT_PARENT(ident))) == GST_STATE_PLAYING)
|
||||
{
|
||||
gst_element_set_state (GST_ELEMENT (GST_ELEMENT_PARENT(ident)), GST_STATE_PAUSED);
|
||||
restart_spider = TRUE;
|
||||
}
|
||||
|
||||
/* remove typefind */
|
||||
gst_pad_disconnect (ident->src, (GstPad*) GST_RPAD_PEER (ident->src));
|
||||
gst_bin_remove (GST_BIN (GST_ELEMENT_PARENT (ident)), typefind);
|
||||
|
||||
/* set caps */
|
||||
gst_spider_identity_set_caps (ident, caps);
|
||||
|
||||
/* set new loop function, we gotta empty the cache */
|
||||
gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_sink_loop_emptycache));
|
||||
|
||||
/* autoplug this pad */
|
||||
gst_spider_plug (ident);
|
||||
|
||||
/* restart autoplugger */
|
||||
if (restart_spider)
|
||||
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_pad_pull (ident->sink);
|
||||
|
||||
gst_spider_identity_chain (ident->sink, buf);
|
||||
}
|
||||
/* do nothing until we're connected - 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;
|
||||
}
|
||||
|
||||
/* in any case, we don't want to do anything:
|
||||
* - if we're not plugged, we don't have buffers
|
||||
* - if we're plugged, we wanna be chained please
|
||||
*/
|
||||
gst_element_interrupt (GST_ELEMENT (ident));
|
||||
return;
|
||||
}
|
||||
/* This loop function is only needed when typefinding.
|
||||
* It works quite simple: get a new buffer, append it to the cache
|
||||
* and push it to the typefinder.
|
||||
*/
|
||||
static void
|
||||
gst_spider_identity_sink_loop_typefinding (GstSpiderIdentity *ident)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
/* checks - disable for speed */
|
||||
g_return_if_fail (ident != NULL);
|
||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||
g_assert (ident->sink != NULL);
|
||||
|
||||
/* get buffer */
|
||||
buf = gst_pad_pull (ident->sink);
|
||||
|
||||
/* if it's an event... */
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
/* handle DISCONT events, please */
|
||||
gst_pad_event_default (ident->sink, GST_EVENT (buf));
|
||||
}
|
||||
|
||||
/* add it to the end of the cache */
|
||||
gst_buffer_ref (buf);
|
||||
GST_DEBUG (0, "element %s adds buffer %p (size %d) to cache\n", GST_ELEMENT_NAME(ident), buf, GST_BUFFER_SIZE (buf));
|
||||
ident->cache_end = g_list_prepend (ident->cache_end, buf);
|
||||
if (ident->cache_start == NULL)
|
||||
ident->cache_start = ident->cache_end;
|
||||
|
||||
/* push the buffer */
|
||||
gst_spider_identity_chain (ident->sink, buf);
|
||||
}
|
||||
/* this function is needed after typefinding:
|
||||
* empty the cache and when the cache is empty - remove this function
|
||||
*/
|
||||
static void
|
||||
gst_spider_identity_sink_loop_emptycache (GstSpiderIdentity *ident)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
/* get the buffer and push it */
|
||||
buf = GST_BUFFER (ident->cache_start->data);
|
||||
gst_spider_identity_chain (ident->sink, buf);
|
||||
|
||||
ident->cache_start = g_list_previous (ident->cache_start);
|
||||
|
||||
/* now check if we have more buffers to push */
|
||||
if (ident->cache_start == NULL)
|
||||
{
|
||||
GST_DEBUG(0, "cache from %s is empty, changing loop function\n", GST_ELEMENT_NAME(ident));
|
||||
/* free cache */
|
||||
g_list_free (ident->cache_end);
|
||||
ident->cache_end = NULL;
|
||||
|
||||
/* remove loop function */
|
||||
gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
|
||||
gst_element_interrupt (GST_ELEMENT (ident));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
90
gst/autoplug/gstspideridentity.h
Normal file
90
gst/autoplug/gstspideridentity.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* 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 <config.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
GstElementDetails gst_spider_identity_details;
|
||||
|
||||
|
||||
#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;
|
||||
|
||||
/* caching */
|
||||
GList *cache_start;
|
||||
GList *cache_end;
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __GST_SPIDER_IDENTITY_H__ */
|
147
gst/autoplug/spidertest.c
Normal file
147
gst/autoplug/spidertest.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
#include <stdlib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
/* 1:1 copy of gstpropsprivate.h, needed for INFO events */
|
||||
|
||||
#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID)
|
||||
|
||||
typedef struct _GstPropsEntry GstPropsEntry;
|
||||
|
||||
struct _GstPropsEntry {
|
||||
GQuark propid;
|
||||
GstPropsId propstype;
|
||||
|
||||
union {
|
||||
/* flat values */
|
||||
gboolean bool_data;
|
||||
guint32 fourcc_data;
|
||||
gint int_data;
|
||||
gfloat float_data;
|
||||
|
||||
/* structured values */
|
||||
struct {
|
||||
GList *entries;
|
||||
} list_data;
|
||||
struct {
|
||||
gchar *string;
|
||||
} string_data;
|
||||
struct {
|
||||
gint min;
|
||||
gint max;
|
||||
} int_range_data;
|
||||
struct {
|
||||
gfloat min;
|
||||
gfloat max;
|
||||
} float_range_data;
|
||||
} data;
|
||||
};
|
||||
|
||||
/* end gstpropsprivate.h */
|
||||
|
||||
/* property output, stolen from gst-launch */
|
||||
static void
|
||||
print_props (gpointer data, gpointer user_data)
|
||||
{
|
||||
GstPropsEntry *entry = (GstPropsEntry *)data;
|
||||
GstElement *element = GST_ELEMENT (user_data);
|
||||
|
||||
g_print ("%s: %s: ", gst_element_get_name (element),
|
||||
g_quark_to_string (entry->propid));
|
||||
switch (entry->propstype) {
|
||||
case GST_PROPS_INT_ID:
|
||||
g_print ("%d\n", entry->data.int_data);
|
||||
break;
|
||||
case GST_PROPS_STRING_ID:
|
||||
g_print ("%s\n", entry->data.string_data.string);
|
||||
break;
|
||||
case GST_PROPS_FLOAT_ID:
|
||||
g_print ("%f\n", entry->data.float_data);
|
||||
break;
|
||||
default:
|
||||
g_print ("unknown\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
event_func (GstElement *element, GstEvent *event)
|
||||
{
|
||||
GstProps *props;
|
||||
|
||||
if (event == NULL)
|
||||
return;
|
||||
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_INFO) {
|
||||
props = GST_EVENT_INFO_PROPS (event);
|
||||
|
||||
g_list_foreach (props->properties, print_props, GST_EVENT_SRC (event));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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 (G_OBJECT (bin), "event", G_CALLBACK (event_func), NULL);
|
||||
|
||||
/* create a disk reader */
|
||||
filesrc = gst_elementfactory_make("filesrc", "disk_source");
|
||||
g_object_set(G_OBJECT(filesrc),"location", argv[1], NULL);
|
||||
|
||||
/* now it's time to get the decoder */
|
||||
decoder = gst_elementfactory_make("spider", "spider");
|
||||
if (!decoder) {
|
||||
g_print ("could not find plugin \"spider\"\n");
|
||||
exit (-2);
|
||||
}
|
||||
|
||||
/* only use decoding plugins */
|
||||
g_object_set(G_OBJECT(decoder),"plugtype", 2, NULL);
|
||||
|
||||
/* create video and audio sink */
|
||||
osssink = gst_elementfactory_make("osssink", "audio");
|
||||
videosink = gst_elementfactory_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);
|
||||
|
||||
/* connect objects */
|
||||
if (!(gst_element_connect_elements(filesrc, decoder) &&
|
||||
gst_element_connect_elements(decoder, osssink) &&
|
||||
gst_element_connect_elements(decoder, videosink)))
|
||||
{
|
||||
g_print ("the pipeline could not be connected\n");
|
||||
exit (-4);
|
||||
}
|
||||
|
||||
/* 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