mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 11:10:37 +00:00
A first (rude) attempt at autoplug.
Original commit message from CVS: A first (rude) attempt at autoplug. Autoplugging selects appropriate codecs to connect src to sink, adds them to the pipeline and connect pads. Autoplugging will run the typedetect plugin if the src pad has no MIME type. No autoplugging is done on the src and sink pads, it's hardcoded: connect 'src to sink'. No attempt at creating threads. No attempt at dynamically autoplugging not yet existing pads. Changes to (some) plugins to properly set their MIME types.
This commit is contained in:
parent
78a7023543
commit
fa4a4319f0
16 changed files with 498 additions and 37 deletions
|
@ -49,6 +49,11 @@ Building apps
|
|||
(fdsrc->mp3decoder->audiosink)
|
||||
(step by step explanation)
|
||||
More on factories
|
||||
problems with helloworld
|
||||
MIME types
|
||||
GStreamer types
|
||||
Basic types
|
||||
|
||||
|
||||
advanced concepts
|
||||
threads
|
||||
|
|
|
@ -133,9 +133,9 @@ gst_audiosink_class_init(GstAudioSinkClass *klass) {
|
|||
static void gst_audiosink_init(GstAudioSink *audiosink) {
|
||||
audiosink->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
|
||||
gst_element_add_pad(GST_ELEMENT(audiosink),audiosink->sinkpad);
|
||||
if (!gst_audiosink_type_audio)
|
||||
gst_audiosink_type_audio = gst_type_find_by_mime("audio/raw");
|
||||
|
||||
gst_pad_set_type_id(audiosink->sinkpad,gst_audiosink_type_audio);
|
||||
|
||||
gst_pad_set_chain_function(audiosink->sinkpad,gst_audiosink_chain);
|
||||
|
||||
audiosink->fd = -1;
|
||||
|
@ -342,3 +342,14 @@ static GstElementStateReturn gst_audiosink_change_state(GstElement *element) {
|
|||
return GST_ELEMENT_CLASS(parent_class)->change_state(element);
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
gboolean gst_audiosink_factory_init(GstElementFactory *factory) {
|
||||
|
||||
if (!gst_audiosink_type_audio)
|
||||
gst_audiosink_type_audio = gst_type_find_by_mime("audio/raw");
|
||||
|
||||
gst_type_add_sink(gst_audiosink_type_audio, factory);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ struct _GstAudioSinkClass {
|
|||
|
||||
GtkType gst_audiosink_get_type(void);
|
||||
|
||||
gboolean gst_audiosink_factory_init(GstElementFactory *factory);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -42,25 +42,26 @@ struct _elements_entry {
|
|||
gchar *name;
|
||||
GtkType (*type) (void);
|
||||
GstElementDetails *details;
|
||||
gboolean (*factoryinit) (GstElementFactory *factory);
|
||||
};
|
||||
|
||||
struct _elements_entry _elements[] = {
|
||||
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details },
|
||||
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details },
|
||||
{ "asyncdisksrc", gst_asyncdisksrc_get_type, &gst_asyncdisksrc_details },
|
||||
{ "audiosink", gst_audiosink_get_type, &gst_audiosink_details },
|
||||
{ "audiosrc", gst_audiosrc_get_type, &gst_audiosrc_details },
|
||||
{ "disksrc", gst_disksrc_get_type, &gst_disksrc_details },
|
||||
{ "identity", gst_identity_get_type, &gst_identity_details },
|
||||
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details },
|
||||
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details },
|
||||
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, NULL },
|
||||
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, NULL },
|
||||
{ "asyncdisksrc", gst_asyncdisksrc_get_type, &gst_asyncdisksrc_details, NULL },
|
||||
{ "audiosink", gst_audiosink_get_type, &gst_audiosink_details, gst_audiosink_factory_init },
|
||||
{ "audiosrc", gst_audiosrc_get_type, &gst_audiosrc_details, NULL },
|
||||
{ "disksrc", gst_disksrc_get_type, &gst_disksrc_details, NULL },
|
||||
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
|
||||
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
|
||||
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
|
||||
#if HAVE_LIBGHTTP
|
||||
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details },
|
||||
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL },
|
||||
#endif /* HAVE_LIBGHTTP */
|
||||
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details },
|
||||
{ "queue", gst_queue_get_type, &gst_queue_details },
|
||||
{ "sinesrc", gst_sinesrc_get_type, &gst_sinesrc_details },
|
||||
{ "typefind", gst_typefind_get_type, &gst_typefind_details },
|
||||
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
|
||||
{ "queue", gst_queue_get_type, &gst_queue_details, NULL },
|
||||
{ "sinesrc", gst_sinesrc_get_type, &gst_sinesrc_details, NULL },
|
||||
{ "typefind", gst_typefind_get_type, &gst_typefind_details, NULL },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
|
@ -82,7 +83,10 @@ GstPlugin *plugin_init(GModule *module) {
|
|||
_elements[i].details);
|
||||
if (factory != NULL) {
|
||||
gst_plugin_add_factory(plugin,factory);
|
||||
// DEBUG("added factory '%s'\n",_elements[i].name);
|
||||
if (_elements[i].factoryinit) {
|
||||
_elements[i].factoryinit(factory);
|
||||
}
|
||||
// g_print("added factory '%s'\n",_elements[i].name);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//#define DEBUG_ENABLED
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
GstElementDetails gst_bin_details = {
|
||||
"Generic bin",
|
||||
"Bin",
|
||||
|
@ -542,6 +544,7 @@ gst_element_get_name(element),gst_pad_get_name(pad));
|
|||
g_print("gstbin: don't need cothreads, looking for entry points\n");
|
||||
// clear previous plan state
|
||||
g_list_free(bin->entries);
|
||||
bin->entries = NULL;
|
||||
bin->numentries = 0;
|
||||
// we have to find which elements will drive an iteration
|
||||
elements = bin->children;
|
||||
|
@ -617,5 +620,4 @@ void gst_bin_iterate_func(GstBin *bin) {
|
|||
entries = g_list_next(entries);
|
||||
}
|
||||
}
|
||||
// g_print(",");
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ struct _GstBinClass {
|
|||
|
||||
GtkType gst_bin_get_type(void);
|
||||
GstElement *gst_bin_new(gchar *name);
|
||||
#define gst_bin_destroy(bin) gst_object_destroy(GST_OBJECT(bin))
|
||||
|
||||
/* add and remove elements from the bin */
|
||||
void gst_bin_add(GstBin *bin,GstElement *element);
|
||||
|
|
|
@ -306,6 +306,17 @@ gint gst_element_set_state(GstElement *element,GstElementState state) {
|
|||
return return_val;
|
||||
}
|
||||
|
||||
GstElementFactory *gst_element_get_factory(GstElement *element) {
|
||||
GstElementClass *oclass;
|
||||
|
||||
g_return_val_if_fail(element != NULL, NULL);
|
||||
g_return_val_if_fail(GST_IS_ELEMENT(element), NULL);
|
||||
|
||||
oclass = GST_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
|
||||
|
||||
return oclass->elementfactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_change_state:
|
||||
* @element: element to change state of
|
||||
|
|
|
@ -144,6 +144,9 @@ struct _GstElementFactory {
|
|||
GtkType type; /* unique GtkType of element */
|
||||
|
||||
GstElementDetails *details; /* pointer to details struct */
|
||||
|
||||
GList *src_types;
|
||||
GList *sink_types;
|
||||
};
|
||||
|
||||
|
||||
|
@ -172,6 +175,8 @@ gint gst_element_set_state(GstElement *element,GstElementState state);
|
|||
|
||||
void gst_element_error(GstElement *element,gchar *error);
|
||||
|
||||
GstElementFactory *gst_element_get_factory(GstElement *element);
|
||||
|
||||
#define gst_element_destroy(element) gst_object_destroy(GST_OBJECT(element))
|
||||
|
||||
/* XML write and read */
|
||||
|
@ -182,6 +187,9 @@ GstElementFactory *gst_elementfactory_new(gchar *name,GtkType type,
|
|||
GstElementDetails *details);
|
||||
void gst_elementfactory_register(GstElementFactory *elementfactory);
|
||||
|
||||
void gst_elementfactory_add_src(GstElementFactory *elementfactory, guint16 id);
|
||||
void gst_elementfactory_add_sink(GstElementFactory *elementfactory, guint16 id);
|
||||
|
||||
GstElementFactory *gst_elementfactory_find(gchar *name);
|
||||
GList *gst_elementfactory_get_list();
|
||||
|
||||
|
|
|
@ -91,6 +91,8 @@ GstElementFactory *gst_elementfactory_new(gchar *name,GtkType type,
|
|||
factory->name = g_strdup(name);
|
||||
factory->type = type;
|
||||
factory->details = details;
|
||||
factory->src_types = NULL;
|
||||
factory->sink_types = NULL;
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
@ -136,3 +138,16 @@ GstElement *gst_elementfactory_make(gchar *factoryname,gchar *name) {
|
|||
element = gst_elementfactory_create(factory,name);
|
||||
return element;
|
||||
}
|
||||
|
||||
void gst_elementfactory_add_src(GstElementFactory *elementfactory, guint16 id) {
|
||||
guint type = id;
|
||||
|
||||
elementfactory->src_types = g_list_prepend(elementfactory->src_types, GUINT_TO_POINTER(type));
|
||||
}
|
||||
|
||||
void gst_elementfactory_add_sink(GstElementFactory *elementfactory, guint16 id) {
|
||||
guint type = id;
|
||||
|
||||
elementfactory->sink_types = g_list_prepend(elementfactory->sink_types, GUINT_TO_POINTER(type));
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
|
||||
#include <gst/gstpipeline.h>
|
||||
#include <gst/gstsink.h>
|
||||
#include <gst/gstutils.h>
|
||||
#include <gst/gsttype.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
@ -50,6 +53,7 @@ static GstElementStateReturn gst_pipeline_change_state(GstElement *element);
|
|||
|
||||
static void gst_pipeline_prepare(GstPipeline *pipeline);
|
||||
|
||||
static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data);
|
||||
|
||||
static GstBin *parent_class = NULL;
|
||||
//static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 };
|
||||
|
@ -109,6 +113,164 @@ static void gst_pipeline_prepare(GstPipeline *pipeline) {
|
|||
g_print("GstPipeline: preparing pipeline \"%s\" for playing\n", gst_element_get_name(GST_ELEMENT(pipeline)));
|
||||
}
|
||||
|
||||
static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data) {
|
||||
g_print("GstPipeline: pipeline have type %p\n", (gboolean *)data);
|
||||
|
||||
*(gboolean *)data = TRUE;
|
||||
}
|
||||
|
||||
static guint16 gst_pipeline_typefind(GstPipeline *pipeline, GstElement *element) {
|
||||
gboolean found = FALSE;
|
||||
GstElement *typefind;
|
||||
guint16 type_id = 0;
|
||||
|
||||
g_print("GstPipeline: typefind for element \"%s\" %p\n", gst_element_get_name(element), &found);
|
||||
|
||||
typefind = gst_elementfactory_make("typefind","typefind");
|
||||
g_return_val_if_fail(typefind != NULL, FALSE);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(typefind),"have_type",
|
||||
GTK_SIGNAL_FUNC(gst_pipeline_have_type), &found);
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(element,"src"),
|
||||
gst_element_get_pad(typefind,"sink"));
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline), typefind);
|
||||
|
||||
gst_bin_create_plan(GST_BIN(pipeline));
|
||||
gst_element_set_state(GST_ELEMENT(element),GST_STATE_READY);
|
||||
gst_element_set_state(GST_ELEMENT(element),GST_STATE_PLAYING);
|
||||
|
||||
while (!found) {
|
||||
gst_src_push(GST_SRC(element));
|
||||
}
|
||||
|
||||
gst_element_set_state(GST_ELEMENT(element),GST_STATE_NULL);
|
||||
|
||||
if (found) {
|
||||
type_id = gst_util_get_int_arg(GTK_OBJECT(typefind),"type");
|
||||
}
|
||||
|
||||
gst_pad_set_type_id(gst_element_get_pad(element, "src"), type_id);
|
||||
|
||||
gst_pad_disconnect(gst_element_get_pad(element,"src"),
|
||||
gst_element_get_pad(typefind,"sink"));
|
||||
gst_bin_remove(GST_BIN(pipeline), typefind);
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
||||
gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
|
||||
GList *elements;
|
||||
GstElement *element, *srcelement, *sinkelement;
|
||||
GList *factories;
|
||||
GstElementFactory *factory;
|
||||
GList *src_types, *sink_types;
|
||||
guint16 src_type = 0, sink_type = 0;
|
||||
gboolean complete = FALSE;
|
||||
|
||||
g_return_val_if_fail(GST_IS_PIPELINE(pipeline), FALSE);
|
||||
|
||||
g_print("GstPipeline: autopluging pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
|
||||
|
||||
elements = gst_bin_get_list(GST_BIN(pipeline));
|
||||
|
||||
// fase 1, find all the sinks and sources...
|
||||
while (elements) {
|
||||
element = GST_ELEMENT(elements->data);
|
||||
|
||||
if (GST_IS_SINK(element)) {
|
||||
g_print("GstPipeline: found sink \"%s\"\n", gst_element_get_name(element));
|
||||
|
||||
if (sink_type) {
|
||||
g_print("GstPipeline: multiple sinks detected, can't autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
|
||||
return FALSE;
|
||||
}
|
||||
sinkelement = element;
|
||||
factory = gst_element_get_factory(element);
|
||||
|
||||
sink_types = factory->sink_types;
|
||||
if (sink_types == NULL) {
|
||||
g_print("GstPipeline: sink \"%s\" has no MIME type, can't autoplug \n", gst_element_get_name(element));
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
sink_type = GPOINTER_TO_UINT(sink_types->data);
|
||||
g_print("GstPipeline: sink \"%s\" has MIME type %d \n", gst_element_get_name(element), sink_type);
|
||||
}
|
||||
}
|
||||
else if (GST_IS_SRC(element)) {
|
||||
g_print("GstPipeline: found source \"%s\"\n", gst_element_get_name(element));
|
||||
|
||||
if (src_type) {
|
||||
g_print("GstPipeline: multiple sources detected, can't autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
srcelement = element;
|
||||
|
||||
factory = gst_element_get_factory(element);
|
||||
|
||||
src_types = factory->src_types;
|
||||
if (src_types == NULL) {
|
||||
g_print("GstPipeline: source \"%s\" has no MIME type, running typefind...\n", gst_element_get_name(element));
|
||||
|
||||
src_type = gst_pipeline_typefind(pipeline, element);
|
||||
|
||||
if (src_type) {
|
||||
g_print("GstPipeline: source \"%s\" type found %d\n", gst_element_get_name(element), src_type);
|
||||
}
|
||||
else {
|
||||
g_print("GstPipeline: source \"%s\" has no type\n", gst_element_get_name(element));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (src_types) {
|
||||
src_types = g_list_next(src_types);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
g_print("GstPipeline: found invalid element \"%s\", not source or sink\n", gst_element_get_name(element));
|
||||
}
|
||||
|
||||
elements = g_list_next(elements);
|
||||
}
|
||||
|
||||
factories = gst_type_get_sink_to_src(src_type, sink_type);
|
||||
|
||||
while (factories) {
|
||||
// fase 2: find elements to form a pad
|
||||
|
||||
factory = (GstElementFactory *)(factories->data);
|
||||
|
||||
g_print("GstPipeline: factory \"%s\"\n", factory->name);
|
||||
|
||||
element = gst_elementfactory_create(factory, factory->name);
|
||||
gst_bin_add(GST_BIN(pipeline), element);
|
||||
|
||||
// FIXME match paths to connect with MIME types instead
|
||||
// of names.
|
||||
gst_pad_connect(gst_element_get_pad(srcelement,"src"),
|
||||
gst_element_get_pad(element,"sink"));
|
||||
|
||||
srcelement = element;
|
||||
|
||||
factories = g_list_next(factories);
|
||||
|
||||
complete = TRUE;
|
||||
}
|
||||
|
||||
if (complete) {
|
||||
gst_pad_connect(gst_element_get_pad(srcelement,"src"),
|
||||
gst_element_get_pad(sinkelement,"sink"));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_print("GstPipeline: unable to autoplug pipeline \"%s\"\n", gst_element_get_name(GST_ELEMENT(pipeline)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstElementStateReturn gst_pipeline_change_state(GstElement *element) {
|
||||
GstPipeline *pipeline;
|
||||
|
|
|
@ -41,7 +41,7 @@ GstElementDetails gst_pipeline_details;
|
|||
#define GST_IS_PIPELINE(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_PIPELINE))
|
||||
#define GST_IS_PIPELINE_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_PIPELINE)))
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_PIPELINE))
|
||||
|
||||
typedef struct _GstPipeline GstPipeline;
|
||||
typedef struct _GstPipelineClass GstPipelineClass;
|
||||
|
@ -58,6 +58,8 @@ GtkType gst_pipeline_get_type(void);
|
|||
GstPipeline *gst_pipeline_new(guchar *name);
|
||||
#define gst_pipeline_destroy(pipeline) gst_object_destroy(GST_OBJECT(pipeline))
|
||||
|
||||
gboolean gst_pipeline_autoplug(GstPipeline *pipeline);
|
||||
|
||||
void gst_pipeline_iterate(GstPipeline *pipeline);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
213
gst/gsttype.c
213
gst/gsttype.c
|
@ -33,6 +33,27 @@
|
|||
GList *_gst_types;
|
||||
guint16 _gst_maxtype;
|
||||
|
||||
struct _gst_type_node
|
||||
{
|
||||
int iNode;
|
||||
int iDist;
|
||||
int iPrev;
|
||||
};
|
||||
typedef struct _gst_type_node gst_type_node;
|
||||
|
||||
/* we keep a (spase) matrix in the hashtable like:
|
||||
*
|
||||
* type_id list of factories hashed by src type_id
|
||||
*
|
||||
* 1 -> (1, factory1, factory2), (3, factory3)
|
||||
* 2 -> NULL
|
||||
* 3 -> (4, factory4)
|
||||
* 4 -> NULL
|
||||
*
|
||||
* That way, we can quickly find all factories that convert
|
||||
* 1 to 2.
|
||||
*
|
||||
**/
|
||||
|
||||
void _gst_type_initialize() {
|
||||
_gst_types = NULL;
|
||||
|
@ -58,6 +79,7 @@ guint16 gst_type_register(GstTypeFactory *factory) {
|
|||
type->typefindfunc = factory->typefindfunc;
|
||||
type->srcs = NULL;
|
||||
type->sinks = NULL;
|
||||
type->converters = g_hash_table_new(NULL, NULL);
|
||||
_gst_types = g_list_prepend(_gst_types,type);
|
||||
|
||||
id = type->id;
|
||||
|
@ -122,22 +144,102 @@ GstType *gst_type_find_by_id(guint16 id) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void gst_type_dump_converter(gpointer key, gpointer value, gpointer data) {
|
||||
GList *walk = (GList *)value;
|
||||
GstElementFactory *factory;
|
||||
|
||||
g_print("%u, (", GPOINTER_TO_UINT(key));
|
||||
|
||||
while (walk) {
|
||||
factory = (GstElementFactory *) walk->data;
|
||||
g_print("%s, ", factory->name);
|
||||
walk = g_list_next(walk);
|
||||
}
|
||||
g_print("NULL)), ");
|
||||
}
|
||||
|
||||
void gst_type_dump() {
|
||||
GList *walk = _gst_types;
|
||||
GstType *type;
|
||||
|
||||
g_print("gst_type_dump() : \n");
|
||||
|
||||
while (walk) {
|
||||
type = (GstType *)walk->data;
|
||||
|
||||
g_print("gst_type: %d (%s) -> (", type->id, type->mime);
|
||||
g_hash_table_foreach(type->converters, gst_type_dump_converter, NULL);
|
||||
g_print("NULL)\n");
|
||||
|
||||
walk = g_list_next(walk);
|
||||
}
|
||||
}
|
||||
|
||||
void gst_type_add_src(guint16 id,GstElementFactory *src) {
|
||||
GList *walk;
|
||||
GstType *type = gst_type_find_by_id(id);
|
||||
|
||||
g_return_if_fail(type != NULL);
|
||||
g_return_if_fail(src != NULL);
|
||||
|
||||
type->srcs = g_list_prepend(type->srcs,src);
|
||||
gst_elementfactory_add_src(src, id);
|
||||
|
||||
// find out if the element has to be indexed in the matrix
|
||||
walk = src->sink_types;
|
||||
|
||||
while (walk) {
|
||||
GstType *type2 = gst_type_find_by_id(GPOINTER_TO_UINT(walk->data));
|
||||
GList *converters = (GList *)g_hash_table_lookup(type2->converters, GUINT_TO_POINTER((guint)id));
|
||||
GList *orig = converters;
|
||||
|
||||
while (converters) {
|
||||
if (converters->data == src) {
|
||||
break;
|
||||
}
|
||||
converters = g_list_next(converters);
|
||||
}
|
||||
|
||||
if (!converters) {
|
||||
orig = g_list_prepend(orig, src);
|
||||
g_hash_table_insert(type2->converters, GUINT_TO_POINTER((guint)id), orig);
|
||||
}
|
||||
|
||||
walk = g_list_next(walk);
|
||||
}
|
||||
}
|
||||
|
||||
void gst_type_add_sink(guint16 id,GstElementFactory *sink) {
|
||||
GList *walk;
|
||||
GstType *type = gst_type_find_by_id(id);
|
||||
|
||||
g_return_if_fail(type != NULL);
|
||||
g_return_if_fail(sink != NULL);
|
||||
|
||||
type->sinks = g_list_prepend(type->sinks,sink);
|
||||
gst_elementfactory_add_sink(sink, id);
|
||||
|
||||
// find out if the element has to be indexed in the matrix
|
||||
walk = sink->src_types;
|
||||
|
||||
while (walk) {
|
||||
GList *converters = (GList *)g_hash_table_lookup(type->converters, walk->data);
|
||||
GList *orig = converters;
|
||||
|
||||
while (converters) {
|
||||
if (converters->data == sink) {
|
||||
break;
|
||||
}
|
||||
converters = g_list_next(converters);
|
||||
}
|
||||
|
||||
if (!converters) {
|
||||
orig = g_list_prepend(orig, sink);
|
||||
g_hash_table_insert(type->converters, walk->data, orig);
|
||||
}
|
||||
|
||||
walk = g_list_next(walk);
|
||||
}
|
||||
}
|
||||
|
||||
GList *gst_type_get_srcs(guint16 id) {
|
||||
|
@ -156,6 +258,117 @@ GList *gst_type_get_sinks(guint16 id) {
|
|||
return type->sinks;
|
||||
}
|
||||
|
||||
/*
|
||||
* An implementation of Dijkstra's shortest path
|
||||
* algorithm to find the best set of GstElementFactories
|
||||
* to connnect two GstTypes
|
||||
*
|
||||
**/
|
||||
|
||||
static GList *gst_type_enqueue(GList *queue, gint iNode, gint iDist, gint iPrev) {
|
||||
gst_type_node *node = g_malloc(sizeof(gst_type_node));
|
||||
|
||||
node->iNode = iNode;
|
||||
node->iDist = iDist;
|
||||
node->iPrev = iPrev;
|
||||
|
||||
queue = g_list_append(queue, node);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
static GList *gst_type_dequeue(GList *queue, gint *iNode, gint *iDist, gint *iPrev) {
|
||||
GList *head;
|
||||
gst_type_node *node;
|
||||
|
||||
head = g_list_first(queue);
|
||||
|
||||
if (head) {
|
||||
node = (gst_type_node *)head->data;
|
||||
*iNode = node->iNode;
|
||||
*iPrev = node->iPrev;
|
||||
*iDist = node->iDist;
|
||||
head = g_list_remove(queue, node);
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static GList *construct_path (gst_type_node *rgnNodes, gint chNode)
|
||||
{
|
||||
guint src = chNode;
|
||||
guint current = rgnNodes[chNode].iPrev;
|
||||
GList *factories = NULL;
|
||||
GstType *type;
|
||||
GList *converters;
|
||||
|
||||
while (current != 999)
|
||||
{
|
||||
type = gst_type_find_by_id(current);
|
||||
converters = (GList *)g_hash_table_lookup(type->converters, GUINT_TO_POINTER(src));
|
||||
|
||||
g_print("(%d %d)", src, current);
|
||||
factories = g_list_prepend(factories, converters->data);
|
||||
src = current;
|
||||
current = rgnNodes[current].iPrev;
|
||||
}
|
||||
g_print("\n");
|
||||
return factories;
|
||||
}
|
||||
|
||||
static guint gst_type_find_cost(gint src, gint dest) {
|
||||
GstType *type = gst_type_find_by_id(src);
|
||||
|
||||
GList *converters = (GList *)g_hash_table_lookup(type->converters, GUINT_TO_POINTER(dest));
|
||||
|
||||
if (converters) return 1;
|
||||
return 999;
|
||||
}
|
||||
|
||||
GList *gst_type_get_sink_to_src(guint16 sinkid, guint16 srcid) {
|
||||
gst_type_node *rgnNodes;
|
||||
GList *queue = NULL;
|
||||
gint iNode, iDist, iPrev, i, iCost;
|
||||
|
||||
if (sinkid == srcid) {
|
||||
//FIXME return an identity element
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
rgnNodes = g_malloc(sizeof(gst_type_node) * _gst_maxtype);
|
||||
|
||||
for (i=0; i< _gst_maxtype; i++) {
|
||||
rgnNodes[i].iNode = i;
|
||||
rgnNodes[i].iDist = 999;
|
||||
rgnNodes[i].iPrev = 999;
|
||||
}
|
||||
rgnNodes[sinkid].iDist = 0;
|
||||
rgnNodes[sinkid].iPrev = 999;
|
||||
|
||||
queue = gst_type_enqueue(queue, sinkid, 0, 999);
|
||||
|
||||
while (g_list_length(queue) > 0) {
|
||||
|
||||
queue = gst_type_dequeue(queue, &iNode, &iDist, &iPrev);
|
||||
|
||||
for (i=0; i< _gst_maxtype; i++) {
|
||||
iCost = gst_type_find_cost(iNode, i);
|
||||
if (iCost != 999) {
|
||||
if((999 == rgnNodes[i].iDist) ||
|
||||
(rgnNodes[i].iDist > (iCost + iDist))) {
|
||||
rgnNodes[i].iDist = iDist + iCost;
|
||||
rgnNodes[i].iPrev = iNode;
|
||||
|
||||
queue = gst_type_enqueue(queue, i, iDist + iCost, iNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return construct_path(rgnNodes, srcid);
|
||||
}
|
||||
|
||||
GList *gst_type_get_list() {
|
||||
return _gst_types;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
|
||||
/* type of function used to check a stream for equality with type */
|
||||
typedef gboolean (*GstTypeFindFunc) (GstBuffer *buf,gpointer *private);
|
||||
typedef gboolean (*GstTypeFindFunc) (GstBuffer *buf,gpointer *priv);
|
||||
|
||||
typedef struct _GstType GstType;
|
||||
typedef struct _GstTypeFactory GstTypeFactory;
|
||||
|
@ -42,6 +42,10 @@ struct _GstType {
|
|||
|
||||
GList *srcs; /* list of src objects for this type */
|
||||
GList *sinks; /* list of sink objects for type */
|
||||
|
||||
GHashTable *converters; /* a hashtable of factories that can convert
|
||||
from this type to destination type. The
|
||||
factories are indexed by destination type */
|
||||
};
|
||||
|
||||
struct _GstTypeFactory {
|
||||
|
@ -70,7 +74,11 @@ GList *gst_type_get_sinks(guint16 id);
|
|||
|
||||
/* get GstType by id */
|
||||
GstType *gst_type_find_by_id(guint16 id);
|
||||
|
||||
GList *gst_type_get_sink_to_src(guint16 sinkid, guint16 srcid);
|
||||
|
||||
/* get the list of registered types (returns list of GstType!) */
|
||||
GList *gst_type_get_list();
|
||||
|
||||
void gst_type_dump();
|
||||
#endif /* __GST_TYPE_H__ */
|
||||
|
|
|
@ -133,9 +133,9 @@ gst_audiosink_class_init(GstAudioSinkClass *klass) {
|
|||
static void gst_audiosink_init(GstAudioSink *audiosink) {
|
||||
audiosink->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
|
||||
gst_element_add_pad(GST_ELEMENT(audiosink),audiosink->sinkpad);
|
||||
if (!gst_audiosink_type_audio)
|
||||
gst_audiosink_type_audio = gst_type_find_by_mime("audio/raw");
|
||||
|
||||
gst_pad_set_type_id(audiosink->sinkpad,gst_audiosink_type_audio);
|
||||
|
||||
gst_pad_set_chain_function(audiosink->sinkpad,gst_audiosink_chain);
|
||||
|
||||
audiosink->fd = -1;
|
||||
|
@ -342,3 +342,14 @@ static GstElementStateReturn gst_audiosink_change_state(GstElement *element) {
|
|||
return GST_ELEMENT_CLASS(parent_class)->change_state(element);
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
gboolean gst_audiosink_factory_init(GstElementFactory *factory) {
|
||||
|
||||
if (!gst_audiosink_type_audio)
|
||||
gst_audiosink_type_audio = gst_type_find_by_mime("audio/raw");
|
||||
|
||||
gst_type_add_sink(gst_audiosink_type_audio, factory);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ struct _GstAudioSinkClass {
|
|||
|
||||
GtkType gst_audiosink_get_type(void);
|
||||
|
||||
gboolean gst_audiosink_factory_init(GstElementFactory *factory);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -42,25 +42,26 @@ struct _elements_entry {
|
|||
gchar *name;
|
||||
GtkType (*type) (void);
|
||||
GstElementDetails *details;
|
||||
gboolean (*factoryinit) (GstElementFactory *factory);
|
||||
};
|
||||
|
||||
struct _elements_entry _elements[] = {
|
||||
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details },
|
||||
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details },
|
||||
{ "asyncdisksrc", gst_asyncdisksrc_get_type, &gst_asyncdisksrc_details },
|
||||
{ "audiosink", gst_audiosink_get_type, &gst_audiosink_details },
|
||||
{ "audiosrc", gst_audiosrc_get_type, &gst_audiosrc_details },
|
||||
{ "disksrc", gst_disksrc_get_type, &gst_disksrc_details },
|
||||
{ "identity", gst_identity_get_type, &gst_identity_details },
|
||||
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details },
|
||||
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details },
|
||||
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, NULL },
|
||||
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, NULL },
|
||||
{ "asyncdisksrc", gst_asyncdisksrc_get_type, &gst_asyncdisksrc_details, NULL },
|
||||
{ "audiosink", gst_audiosink_get_type, &gst_audiosink_details, gst_audiosink_factory_init },
|
||||
{ "audiosrc", gst_audiosrc_get_type, &gst_audiosrc_details, NULL },
|
||||
{ "disksrc", gst_disksrc_get_type, &gst_disksrc_details, NULL },
|
||||
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
|
||||
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
|
||||
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
|
||||
#if HAVE_LIBGHTTP
|
||||
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details },
|
||||
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL },
|
||||
#endif /* HAVE_LIBGHTTP */
|
||||
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details },
|
||||
{ "queue", gst_queue_get_type, &gst_queue_details },
|
||||
{ "sinesrc", gst_sinesrc_get_type, &gst_sinesrc_details },
|
||||
{ "typefind", gst_typefind_get_type, &gst_typefind_details },
|
||||
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
|
||||
{ "queue", gst_queue_get_type, &gst_queue_details, NULL },
|
||||
{ "sinesrc", gst_sinesrc_get_type, &gst_sinesrc_details, NULL },
|
||||
{ "typefind", gst_typefind_get_type, &gst_typefind_details, NULL },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
|
@ -82,7 +83,10 @@ GstPlugin *plugin_init(GModule *module) {
|
|||
_elements[i].details);
|
||||
if (factory != NULL) {
|
||||
gst_plugin_add_factory(plugin,factory);
|
||||
// DEBUG("added factory '%s'\n",_elements[i].name);
|
||||
if (_elements[i].factoryinit) {
|
||||
_elements[i].factoryinit(factory);
|
||||
}
|
||||
// g_print("added factory '%s'\n",_elements[i].name);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue