diff options
author | Wim Taymans <wim.taymans@gmail.com> | 2001-03-03 19:08:07 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@gmail.com> | 2001-03-03 19:08:07 +0000 |
commit | 3987dbee2255b301c3200e1323be14d16a42f819 (patch) | |
tree | fa94eadb0667efaf4c8522da8f895395628a5b91 | |
parent | 90ac5da6d6fe07dc902502cfed96a779b1717e23 (diff) |
Added an API for element construction and renderer autopluggers.
Original commit message from CVS:
Added an API for element construction and renderer autopluggers.
Added another autoplugger to render things.
Updated the player to use the new autoplugger.
-rw-r--r-- | gst/autoplug/Makefile.am | 8 | ||||
-rw-r--r-- | gst/autoplug/gststaticautoplug.c | 80 | ||||
-rw-r--r-- | gst/autoplug/gststaticautoplugrender.c | 650 | ||||
-rw-r--r-- | gst/autoplug/gststaticautoplugrender.h | 64 | ||||
-rw-r--r-- | gst/gstautoplug.c | 32 | ||||
-rw-r--r-- | gst/gstautoplug.h | 19 | ||||
-rw-r--r-- | gstplay/gstplay.c | 85 | ||||
-rw-r--r-- | gstplay/gstplayprivate.h | 2 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/autoplug.c | 2 | ||||
-rw-r--r-- | tests/autoplug2.c | 38 |
11 files changed, 823 insertions, 159 deletions
diff --git a/gst/autoplug/Makefile.am b/gst/autoplug/Makefile.am index a6a7c8bce6..0ddb2a8a74 100644 --- a/gst/autoplug/Makefile.am +++ b/gst/autoplug/Makefile.am @@ -1,8 +1,12 @@ filterdir = $(libdir)/gst -filter_LTLIBRARIES = libgststaticautoplug.la +filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la libgststaticautoplug_la_SOURCES = \ - gststaticautoplug.c + gststaticautoplug.c + +libgststaticautoplugrender_la_SOURCES = \ + gststaticautoplugrender.c libgststaticautoplug_la_LDFLAGS = -version-info $(GSTREAMER_LIBVERSION) +libgststaticautoplugrender_la_LDFLAGS = -version-info $(GSTREAMER_LIBVERSION) diff --git a/gst/autoplug/gststaticautoplug.c b/gst/autoplug/gststaticautoplug.c index 3eab16d77c..a39ac579fe 100644 --- a/gst/autoplug/gststaticautoplug.c +++ b/gst/autoplug/gststaticautoplug.c @@ -30,17 +30,19 @@ typedef guint (*GstAutoplugCostFunction) (gpointer src, gpointer dest, gpointe typedef GList* (*GstAutoplugListFunction) (gpointer data); -static void gst_static_autoplug_class_init (GstStaticAutoplugClass *klass); -static void gst_static_autoplug_init (GstStaticAutoplug *autoplug); +static void gst_static_autoplug_class_init (GstStaticAutoplugClass *klass); +static void gst_static_autoplug_init (GstStaticAutoplug *autoplug); -static GList* gst_autoplug_func (gpointer src, gpointer sink, - GstAutoplugListFunction list_function, - GstAutoplugCostFunction cost_function, - gpointer data); +static GList* gst_autoplug_func (gpointer src, gpointer sink, + GstAutoplugListFunction list_function, + GstAutoplugCostFunction cost_function, + gpointer data); -static GstElement* gst_static_autoplug_caps_list (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, va_list args); +static GstElement* gst_static_autoplug_to_caps (GstAutoplug *autoplug, + GList *srccaps, GList *sinkcaps, va_list args); + static GstAutoplugClass *parent_class = NULL; GtkType gst_static_autoplug_get_type(void) @@ -72,7 +74,7 @@ gst_static_autoplug_class_init(GstStaticAutoplugClass *klass) parent_class = gtk_type_class(GST_TYPE_AUTOPLUG); - gstautoplug_class->autoplug_caps_list = gst_static_autoplug_caps_list; + gstautoplug_class->autoplug_to_caps = gst_static_autoplug_to_caps; } static void gst_static_autoplug_init(GstStaticAutoplug *autoplug) { @@ -265,7 +267,7 @@ gst_autoplug_caps_find_cost (gpointer src, gpointer dest, gpointer data) } static GstElement* -gst_static_autoplug_caps_list (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, va_list args) +gst_static_autoplug_to_caps (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, va_list args) { caps_struct caps; GList *capslist; @@ -401,9 +403,6 @@ differ: for (i = 0; i < numsinks; i++) { GstElement *thesrcelement = srcelement; GstElement *thebin = GST_ELEMENT(result); - gboolean use_thread; - - use_thread = have_common; while (factories[i]) { // fase 4: add other elements... @@ -415,59 +414,10 @@ differ: GST_DEBUG (0,"factory \"%s\"\n", factory->name); element = gst_elementfactory_create(factory, factory->name); - // this element suggests the use of a thread, so we set one up... - if (GST_ELEMENT_IS_THREAD_SUGGESTED(element) || use_thread) { - GstElement *queue; - GList *sinkpads; - GstPad *srcpad, *sinkpad; - - use_thread = FALSE; - - GST_DEBUG (0,"sugest new thread for \"%s\" %08x\n", GST_ELEMENT_NAME (element), GST_FLAGS(element)); - - // create a new queue and add to the previous bin - queue = gst_elementfactory_make("queue", g_strconcat("queue_", GST_ELEMENT_NAME(element), NULL)); - GST_DEBUG (0,"adding element \"%s\"\n", GST_ELEMENT_NAME (element)); - gst_bin_add(GST_BIN(thebin), queue); - gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue)); - - // this will be the new bin for all following elements - thebin = gst_elementfactory_make("thread", g_strconcat("thread_", GST_ELEMENT_NAME(element), NULL)); - - srcpad = gst_element_get_pad(queue, "src"); - - sinkpads = gst_element_get_pad_list(element); - while (sinkpads) { - sinkpad = (GstPad *)sinkpads->data; - - // FIXME connect matching pads, not just the first one... - if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK && - !GST_PAD_CONNECTED(sinkpad)) { - GList *caps = gst_pad_get_caps_list (sinkpad); - - // the queue has the type of the elements it connects - gst_pad_set_caps_list (srcpad, caps); - gst_pad_set_caps_list (gst_element_get_pad(queue, "sink"), caps); - break; - } - sinkpads = g_list_next(sinkpads); - } - gst_autoplug_pads_autoplug(thesrcelement, queue); - - GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element)); - gst_bin_add(GST_BIN(thebin), element); - gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (element)); - GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (thebin)); - gst_bin_add(GST_BIN(result), thebin); - gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (thebin)); - thesrcelement = queue; - } - // no thread needed, easy case - else { - GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element)); - gst_bin_add(GST_BIN(thebin), element); - gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (element)); - } + GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element)); + gst_bin_add(GST_BIN(thebin), element); + gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (element)); + gst_autoplug_pads_autoplug(thesrcelement, element); // this element is now the new source element diff --git a/gst/autoplug/gststaticautoplugrender.c b/gst/autoplug/gststaticautoplugrender.c new file mode 100644 index 0000000000..5533d69178 --- /dev/null +++ b/gst/autoplug/gststaticautoplugrender.c @@ -0,0 +1,650 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000 Wim Taymans <wtay@chello.be> + * + * gststaticautoplug.c: A static Autoplugger of pipelines + * + * 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 "gststaticautoplugrender.h" + +#include <gst/gst.h> + +#define GST_AUTOPLUG_MAX_COST 999999 + +typedef guint (*GstAutoplugCostFunction) (gpointer src, gpointer dest, gpointer data); +typedef GList* (*GstAutoplugListFunction) (gpointer data); + + +static void gst_static_autoplug_render_class_init (GstStaticAutoplugRenderClass *klass); +static void gst_static_autoplug_render_init (GstStaticAutoplugRender *autoplug); + +static GList* gst_autoplug_func (gpointer src, gpointer sink, + GstAutoplugListFunction list_function, + GstAutoplugCostFunction cost_function, + gpointer data); + + + +static GstElement* gst_static_autoplug_to_render (GstAutoplug *autoplug, + GList *srccaps, GstElement *target, va_list args); + +static GstAutoplugClass *parent_class = NULL; + +GtkType gst_static_autoplug_render_get_type(void) +{ + static GtkType static_autoplug_type = 0; + + if (!static_autoplug_type) { + static const GtkTypeInfo static_autoplug_info = { + "GstStaticAutoplugRender", + sizeof(GstElement), + sizeof(GstElementClass), + (GtkClassInitFunc)gst_static_autoplug_render_class_init, + (GtkObjectInitFunc)gst_static_autoplug_render_init, + (GtkArgSetFunc)NULL, + (GtkArgGetFunc)NULL, + (GtkClassInitFunc)NULL, + }; + static_autoplug_type = gtk_type_unique (GST_TYPE_AUTOPLUG, &static_autoplug_info); + } + return static_autoplug_type; +} + +static void +gst_static_autoplug_render_class_init(GstStaticAutoplugRenderClass *klass) +{ + GstAutoplugClass *gstautoplug_class; + + gstautoplug_class = (GstAutoplugClass*) klass; + + parent_class = gtk_type_class(GST_TYPE_AUTOPLUG); + + gstautoplug_class->autoplug_to_renderers = gst_static_autoplug_to_render; +} + +static void gst_static_autoplug_render_init(GstStaticAutoplugRender *autoplug) { +} + +GstPlugin* +plugin_init (GModule *module) +{ + GstPlugin *plugin; + GstAutoplugFactory *factory; + + plugin = gst_plugin_new("gststaticautoplugrender"); + g_return_val_if_fail(plugin != NULL,NULL); + + gst_plugin_set_longname (plugin, "A static autoplugger"); + + factory = gst_autoplugfactory_new ("staticrender", + "A static autoplugger, it constructs the complete element before running it", + gst_static_autoplug_render_get_type ()); + + if (factory != NULL) { + gst_plugin_add_autoplugger (plugin, factory); + } + return plugin; +} + +static gboolean +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_list_check_compatibility (srctemp->caps, desttemp->caps)) { + GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, + "factory \"%s\" can connect with factory \"%s\"", src->name, dest->name); + return TRUE; + } + } + + desttemps = g_list_next (desttemps); + } + srctemps = g_list_next (srctemps); + } + GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, + "factory \"%s\" cannot connect with factory \"%s\"", src->name, dest->name); + return FALSE; +} + +static gboolean +gst_autoplug_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink) +{ + GList *sinkpads; + gboolean connected = FALSE; + + GST_DEBUG (0,"gstpipeline: autoplug pad connect function for \"%s\" to \"%s\"\n", + GST_ELEMENT_NAME(src), GST_ELEMENT_NAME(sink)); + + sinkpads = gst_element_get_pad_list(sink); + while (sinkpads) { + GstPad *sinkpad = (GstPad *)sinkpads->data; + + // if we have a match, connect the pads + if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK && + !GST_PAD_CONNECTED(sinkpad)) + { + if (gst_caps_list_check_compatibility (gst_pad_get_caps_list(pad), gst_pad_get_caps_list(sinkpad))) { + gst_pad_connect(pad, sinkpad); + GST_DEBUG (0,"gstpipeline: autoconnect pad \"%s\" in element %s <-> ", GST_PAD_NAME (pad), + GST_ELEMENT_NAME(src)); + GST_DEBUG (0,"pad \"%s\" in element %s\n", GST_PAD_NAME (sinkpad), + GST_ELEMENT_NAME(sink)); + connected = TRUE; + break; + } + else { + GST_DEBUG (0,"pads incompatible %s, %s\n", GST_PAD_NAME (pad), GST_PAD_NAME (sinkpad)); + } + } + sinkpads = g_list_next(sinkpads); + } + + if (!connected) { + GST_DEBUG (0,"gstpipeline: no path to sinks for type\n"); + } + return connected; +} + +typedef struct { + GstElement *result; + GList *endcap; + gint i; +} dynamic_pad_struct; + +static void +autoplug_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) +{ + dynamic_pad_struct *info = (dynamic_pad_struct *)data; + GList *pads = gst_element_get_pad_list (element); + + GST_DEBUG (0,"attempting to dynamically create a ghostpad for %s=%s\n", GST_ELEMENT_NAME (element), + GST_PAD_NAME (pad)); + + while (pads) { + GstPad *pad = GST_PAD (pads->data); + pads = g_list_next (pads); + + if (gst_caps_list_check_compatibility (gst_pad_get_caps_list (pad), info->endcap)) { + gst_element_add_ghost_pad (info->result, pad, g_strdup_printf("src_%02d", info->i)); + GST_DEBUG (0,"gstpipeline: new dynamic pad %s\n", GST_PAD_NAME (pad)); + break; + } + } +} + +static void +gst_autoplug_pads_autoplug (GstElement *src, GstElement *sink) +{ + GList *srcpads; + gboolean connected = FALSE; + + srcpads = gst_element_get_pad_list(src); + + while (srcpads && !connected) { + GstPad *srcpad = (GstPad *)srcpads->data; + + if (gst_pad_get_direction(srcpad) == GST_PAD_SRC) + connected = gst_autoplug_pads_autoplug_func (src, srcpad, sink); + + srcpads = g_list_next(srcpads); + } + + if (!connected) { + GST_DEBUG (0,"gstpipeline: delaying pad connections for \"%s\" to \"%s\"\n", + GST_ELEMENT_NAME(src), GST_ELEMENT_NAME(sink)); + gtk_signal_connect(GTK_OBJECT(src),"new_pad", + GTK_SIGNAL_FUNC(gst_autoplug_pads_autoplug_func), sink); + gtk_signal_connect(GTK_OBJECT(src),"new_ghost_pad", + GTK_SIGNAL_FUNC(gst_autoplug_pads_autoplug_func), sink); + } +} + +static GList* +gst_autoplug_elementfactory_get_list (gpointer data) +{ + return gst_elementfactory_get_list (); +} + +typedef struct { + GList *src; + GList *sink; +} caps_struct; + +#define IS_CAPS(cap) (((cap) == caps->src) || (cap) == caps->sink) + +static guint +gst_autoplug_caps_find_cost (gpointer src, gpointer dest, gpointer data) +{ + caps_struct *caps = (caps_struct *)data; + gboolean res; + + if (IS_CAPS (src) && IS_CAPS (dest)) { + res = gst_caps_list_check_compatibility ((GList *)src, (GList *)dest); + //GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"caps %d to caps %d %d", ((GstCaps *)src)->id, ((GstCaps *)dest)->id, res); + } + else if (IS_CAPS (src)) { + res = gst_elementfactory_can_sink_caps_list ((GstElementFactory *)dest, (GList *)src); + //GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"factory %s to src caps %d %d", ((GstElementFactory *)dest)->name, ((GstCaps *)src)->id, res); + } + else if (IS_CAPS (dest)) { + res = gst_elementfactory_can_src_caps_list ((GstElementFactory *)src, (GList *)dest); + //GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"factory %s to sink caps %d %d", ((GstElementFactory *)src)->name, ((GstCaps *)dest)->id, res); + } + else { + res = gst_autoplug_can_match ((GstElementFactory *)src, (GstElementFactory *)dest); + } + + if (res) + return 1; + else + return GST_AUTOPLUG_MAX_COST; +} + +static GstElement* +gst_static_autoplug_to_render (GstAutoplug *autoplug, GList *srccaps, GstElement *target, va_list args) +{ + caps_struct caps; + GstElement *targetelement; + GstElement *result = NULL, *srcelement = NULL; + GList **factories; + GList *chains = NULL; + GList *endelements = NULL; + guint numsinks = 0, i; + gboolean have_common = FALSE; + + targetelement = target; + + /* + * We first create a list of elements that are needed + * to convert the srcpad caps to the different sinkpad caps. + * and add the list of elementfactories to a list (chains). + */ + caps.src = srccaps; + + while (targetelement) { + GList *elements; + GstPad *pad; + + pad = GST_PAD (gst_element_get_pad_list (targetelement)->data); + + caps.sink = gst_pad_get_caps_list (pad); + + GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"autoplugging two caps structures"); + + elements = gst_autoplug_func (caps.src, caps.sink, + gst_autoplug_elementfactory_get_list, + gst_autoplug_caps_find_cost, + &caps); + + if (elements) { + chains = g_list_append (chains, elements); + endelements = g_list_append (endelements, targetelement); + numsinks++; + } + else { + } + + targetelement = va_arg (args, GstElement *); + } + + /* + * If no list could be found the pipeline cannot be autoplugged and + * we return a NULL element + */ + if (numsinks == 0) + return NULL; + + /* + * We now have a list of lists. We will turn this into an array + * of lists, this will make it much more easy to manipulate it + * in the next steps. + */ + factories = g_new0 (GList *, numsinks); + + for (i = 0; chains; i++) { + GList *elements = (GList *) chains->data; + + factories[i] = elements; + + chains = g_list_next (chains); + } + //FIXME, free the list + + result = gst_bin_new ("autoplug_bin"); + + /* + * We now hav a list of lists that is probably like: + * + * ! + * A -> B -> C + * ! + * A -> D -> E + * + * we now try to find the common elements (A) and add them to + * the bin. We remove them from both lists too. + */ + while (factories[0]) { + GstElementFactory *factory; + GstElement *element; + + // fase 3: add common elements + factory = (GstElementFactory *) (factories[0]->data); + + // check to other paths for matching elements (factories) + for (i=1; i<numsinks; i++) { + if (factory != (GstElementFactory *) (factories[i]->data)) { + goto differ; + } + } + + GST_DEBUG (0,"common factory \"%s\"\n", factory->name); + + element = gst_elementfactory_create (factory, factory->name); + gst_bin_add (GST_BIN(result), element); + + if (srcelement != NULL) { + gst_autoplug_pads_autoplug (srcelement, element); + } + // this is the first element, find a good ghostpad + else { + GList *pads; + + pads = gst_element_get_pad_list (element); + + while (pads) { + GstPad *pad = GST_PAD (pads->data); + + if (gst_caps_list_check_compatibility (srccaps, gst_pad_get_caps_list (pad))) { + gst_element_add_ghost_pad (result, pad, "sink"); + break; + } + + pads = g_list_next (pads); + } + } + gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (element)); + + srcelement = element; + + // advance the pointer in all lists + for (i=0; i<numsinks; i++) { + factories[i] = g_list_next (factories[i]); + } + + have_common = TRUE; + } + +differ: + + // loop over all the sink elements + for (i = 0; i < numsinks; i++) { + GstElement *thesrcelement = srcelement; + GstElement *thebin = GST_ELEMENT(result); + GstElement *sinkelement; + gboolean use_thread; + + sinkelement = GST_ELEMENT (endelements->data); + endelements = g_list_next (endelements); + + use_thread = have_common; + + while (factories[i] || sinkelement) { + // fase 4: add other elements... + GstElementFactory *factory; + GstElement *element; + + if (factories[i]) { + factory = (GstElementFactory *)(factories[i]->data); + + GST_DEBUG (0,"factory \"%s\"\n", factory->name); + element = gst_elementfactory_create(factory, factory->name); + } + else { + element = sinkelement; + sinkelement = NULL; + } + + // this element suggests the use of a thread, so we set one up... + if (GST_ELEMENT_IS_THREAD_SUGGESTED(element) || use_thread) { + GstElement *queue; + GList *sinkpads; + GstPad *srcpad, *sinkpad; + + use_thread = FALSE; + + GST_DEBUG (0,"sugest new thread for \"%s\" %08x\n", GST_ELEMENT_NAME (element), GST_FLAGS(element)); + + // create a new queue and add to the previous bin + queue = gst_elementfactory_make("queue", g_strconcat("queue_", GST_ELEMENT_NAME(element), NULL)); + GST_DEBUG (0,"adding element \"%s\"\n", GST_ELEMENT_NAME (element)); + gst_bin_add(GST_BIN(thebin), queue); + gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue)); + + // this will be the new bin for all following elements + thebin = gst_elementfactory_make("thread", g_strconcat("thread_", GST_ELEMENT_NAME(element), NULL)); + + srcpad = gst_element_get_pad(queue, "src"); + + sinkpads = gst_element_get_pad_list(element); + while (sinkpads) { + sinkpad = (GstPad *)sinkpads->data; + + // FIXME connect matching pads, not just the first one... + if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK && + !GST_PAD_CONNECTED(sinkpad)) { + GList *caps = gst_pad_get_caps_list (sinkpad); + + // the queue has the type of the elements it connects + gst_pad_set_caps_list (srcpad, caps); + gst_pad_set_caps_list (gst_element_get_pad(queue, "sink"), caps); + break; + } + sinkpads = g_list_next(sinkpads); + } + gst_autoplug_pads_autoplug(thesrcelement, queue); + + GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element)); + gst_bin_add(GST_BIN(thebin), element); + gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (element)); + GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (thebin)); + gst_bin_add(GST_BIN(result), thebin); + gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (thebin)); + thesrcelement = queue; + } + // no thread needed, easy case + else { + GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element)); + gst_bin_add(GST_BIN(thebin), element); + gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (element)); + } + gst_autoplug_pads_autoplug(thesrcelement, element); + + // this element is now the new source element + thesrcelement = element; + + factories[i] = g_list_next(factories[i]); + } + } + + return result; +} + +/* + * shortest path algorithm + * + */ +struct _gst_autoplug_node +{ + gpointer iNode; + gpointer iPrev; + gint iDist; +}; + +typedef struct _gst_autoplug_node gst_autoplug_node; + +static gint +find_factory (gst_autoplug_node *rgnNodes, gpointer factory) +{ + gint i=0; + + while (rgnNodes[i].iNode) { + if (rgnNodes[i].iNode == factory) return i; + i++; + } + return 0; +} + +static GList* +construct_path (gst_autoplug_node *rgnNodes, gpointer factory) +{ + GstElementFactory *current; + GList *factories = NULL; + + current = rgnNodes[find_factory(rgnNodes, factory)].iPrev; + + GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"factories found in autoplugging (reversed order)"); + + while (current != NULL) + { + gpointer next = NULL; + + next = rgnNodes[find_factory(rgnNodes, current)].iPrev; + if (next) { + factories = g_list_prepend (factories, current); + GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"factory: \"%s\"", current->name); + } + current = next; + } + return factories; +} + +static GList* +gst_autoplug_enqueue (GList *queue, gpointer iNode, gint iDist, gpointer iPrev) +{ + gst_autoplug_node *node = g_malloc (sizeof (gst_autoplug_node)); + + node->iNode = iNode; + node->iDist = iDist; + node->iPrev = iPrev; + + queue = g_list_append (queue, node); + + return queue; +} + +static GList* +gst_autoplug_dequeue (GList *queue, gpointer *iNode, gint *iDist, gpointer *iPrev) +{ + GList *head; + gst_autoplug_node *node; + + head = g_list_first (queue); + + if (head) { + node = (gst_autoplug_node *)head->data; + *iNode = node->iNode; + *iPrev = node->iPrev; + *iDist = node->iDist; + head = g_list_remove (queue, node); + } + + return head; +} + +static GList* +gst_autoplug_func (gpointer src, gpointer sink, + GstAutoplugListFunction list_function, + GstAutoplugCostFunction cost_function, + gpointer data) +{ + gst_autoplug_node *rgnNodes; + GList *queue = NULL; + gpointer iNode, iPrev; + gint iDist, i, iCost; + + GList *elements = g_list_copy (list_function(data)); + GList *factories; + guint num_factories; + + elements = g_list_append (elements, sink); + elements = g_list_append (elements, src); + + factories = elements; + + num_factories = g_list_length (factories); + + rgnNodes = g_new0 (gst_autoplug_node, num_factories+1); + + for (i=0; i< num_factories; i++) { + gpointer fact = factories->data; + + rgnNodes[i].iNode = fact; + rgnNodes[i].iPrev = NULL; + + if (fact == src) { + rgnNodes[i].iDist = 0; + } + else { + rgnNodes[i].iDist = GST_AUTOPLUG_MAX_COST; + } + + factories = g_list_next (factories); + } + rgnNodes[num_factories].iNode = NULL; + + queue = gst_autoplug_enqueue (queue, src, 0, NULL); + + while (g_list_length (queue) > 0) { + GList *factories2 = elements; + + queue = gst_autoplug_dequeue (queue, &iNode, &iDist, &iPrev); + + for (i=0; i< num_factories; i++) { + gpointer current = factories2->data; + + iCost = cost_function (iNode, current, data); + if (iCost != GST_AUTOPLUG_MAX_COST) { + if ((GST_AUTOPLUG_MAX_COST == rgnNodes[i].iDist) || + (rgnNodes[i].iDist > (iCost + iDist))) { + rgnNodes[i].iDist = iDist + iCost; + rgnNodes[i].iPrev = iNode; + + queue = gst_autoplug_enqueue (queue, current, iDist + iCost, iNode); + } + } + + factories2 = g_list_next (factories2); + } + } + + return construct_path (rgnNodes, sink); +} + diff --git a/gst/autoplug/gststaticautoplugrender.h b/gst/autoplug/gststaticautoplugrender.h new file mode 100644 index 0000000000..351d4cdcaf --- /dev/null +++ b/gst/autoplug/gststaticautoplugrender.h @@ -0,0 +1,64 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000 Wim Taymans <wtay@chello.be> + * + * gstautoplug.h: Header for autoplugging functionality + * + * 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_STATIC_AUTOPLUG_RENDER_H__ +#define __GST_STATIC_AUTOPLUG_RENDER_H__ + +#include <gst/gstautoplug.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_STATIC_AUTOPLUG_RENDER \ + (gst_static_autoplug_render_get_type()) +#define GST_STATIC_AUTOPLUG_RENDER(obj) \ + (GTK_CHECK_CAST((obj),GST_TYPE_STATIC_AUTOPLUG_RENDER,GstStaticAutoplugRender)) +#define GST_STATIC_AUTOPLUG_RENDER_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST((klass),GST_TYPE_STATIC_AUTOPLUG_RENDER,GstStaticAutoplugRenderClass)) +#define GST_IS_STATIC_AUTOPLUG_RENDER(obj) \ + (GTK_CHECK_TYPE((obj),GST_TYPE_STATIC_AUTOPLUG_RENDER)) +#define GST_IS_STATIC_AUTOPLUG_RENDER_CLASS(obj) \ + (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_STATIC_AUTOPLUG_RENDER)) + +typedef struct _GstStaticAutoplugRender GstStaticAutoplugRender; +typedef struct _GstStaticAutoplugRenderClass GstStaticAutoplugRenderClass; + +struct _GstStaticAutoplugRender { + GstAutoplug object; +}; + +struct _GstStaticAutoplugRenderClass { + GstAutoplugClass parent_class; +}; + + +GtkType gst_static_autoplug_render_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STATIC_AUTOPLUG_H__ */ + diff --git a/gst/gstautoplug.c b/gst/gstautoplug.c index 16eafbf27c..3f74b25bb1 100644 --- a/gst/gstautoplug.c +++ b/gst/gstautoplug.c @@ -59,7 +59,7 @@ GtkType gst_autoplug_get_type(void) (GtkArgGetFunc)NULL, (GtkClassInitFunc)NULL, }; - autoplug_type = gtk_type_unique (GTK_TYPE_OBJECT, &autoplug_info); + autoplug_type = gtk_type_unique (GST_TYPE_OBJECT, &autoplug_info); } return autoplug_type; } @@ -68,10 +68,12 @@ static void gst_autoplug_class_init(GstAutoplugClass *klass) { GtkObjectClass *gtkobject_class; + GstObjectClass *gstobject_class; gtkobject_class = (GtkObjectClass*) klass; + gstobject_class = (GstObjectClass*) klass; - parent_class = gtk_type_class(GTK_TYPE_OBJECT); + parent_class = gtk_type_class(GST_TYPE_OBJECT); gst_autoplug_signals[NEW_OBJECT] = gtk_signal_new ("new_object", GTK_RUN_LAST, gtkobject_class->type, @@ -100,17 +102,35 @@ gst_autoplug_signal_new_object (GstAutoplug *autoplug, GstObject *object) GstElement* -gst_autoplug_caps_list (GstAutoplug *autoplug, GList *srcpad, GList *sinkpad, ...) +gst_autoplug_to_caps (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, ...) { GstAutoplugClass *oclass; GstElement *element = NULL; va_list args; - va_start (args, sinkpad); + va_start (args, sinkcaps); oclass = GST_AUTOPLUG_CLASS (GTK_OBJECT (autoplug)->klass); - if (oclass->autoplug_caps_list) - element = (oclass->autoplug_caps_list) (autoplug, srcpad, sinkpad, args); + if (oclass->autoplug_to_caps) + element = (oclass->autoplug_to_caps) (autoplug, srccaps, sinkcaps, args); + + va_end (args); + + return element; +} + +GstElement* +gst_autoplug_to_renderers (GstAutoplug *autoplug, GList *srccaps, GstElement *target, ...) +{ + GstAutoplugClass *oclass; + GstElement *element = NULL; + va_list args; + + va_start (args, target); + + oclass = GST_AUTOPLUG_CLASS (GTK_OBJECT (autoplug)->klass); + if (oclass->autoplug_to_renderers) + element = (oclass->autoplug_to_renderers) (autoplug, srccaps, target, args); va_end (args); diff --git a/gst/gstautoplug.h b/gst/gstautoplug.h index 484471ffc6..14d96d55d3 100644 --- a/gst/gstautoplug.h +++ b/gst/gstautoplug.h @@ -44,18 +44,27 @@ extern "C" { typedef struct _GstAutoplug GstAutoplug; typedef struct _GstAutoplugClass GstAutoplugClass; +typedef enum { + GST_AUTOPLUG_TO_CAPS = GST_OBJECT_FLAG_LAST, + GST_AUTOPLUG_TO_RENDERER, + + GST_AUTOPLUG_FLAG_LAST = GST_OBJECT_FLAG_LAST + 8, +} GstAutoplugFlags; + + struct _GstAutoplug { - GtkObject object; + GstObject object; }; struct _GstAutoplugClass { - GtkObjectClass parent_class; + GstObjectClass parent_class; /* signal callbacks */ void (*new_object) (GstAutoplug *autoplug, GstObject *object); /* perform the autoplugging */ - GstElement* (*autoplug_caps_list) (GstAutoplug *autoplug, GList *srcpad, GList *sinkpad, va_list args); + GstElement* (*autoplug_to_caps) (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, va_list args); + GstElement* (*autoplug_to_renderers) (GstAutoplug *autoplug, GList *srccaps, GstElement *target, va_list args); }; typedef struct _GstAutoplugFactory GstAutoplugFactory; @@ -70,7 +79,9 @@ GtkType gst_autoplug_get_type (void); void gst_autoplug_signal_new_object (GstAutoplug *autoplug, GstObject *object); -GstElement* gst_autoplug_caps_list (GstAutoplug *autoplug, GList *srcpad, GList *sinkpad, ...); +GstElement* gst_autoplug_to_caps (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, ...); +GstElement* gst_autoplug_to_renderers (GstAutoplug *autoplug, GList *srccaps, + GstElement *target, ...); /* diff --git a/gstplay/gstplay.c b/gstplay/gstplay.c index 3ce0457c79..f0b7459dce 100644 --- a/gstplay/gstplay.c +++ b/gstplay/gstplay.c @@ -125,44 +125,17 @@ gst_play_init (GstPlay *play) priv->bin = gst_bin_new ("main_bin"); g_assert (priv->bin != NULL); - /* and an audio sink */ - priv->audio_play = gst_thread_new ("audio_render_thread"); - g_return_if_fail (priv->audio_play != NULL); - priv->audio_element = gst_elementfactory_make ("audiosink", "play_audio"); g_return_if_fail (priv->audio_element != NULL); gtk_signal_connect (GTK_OBJECT (priv->audio_element), "handoff", GTK_SIGNAL_FUNC (gst_play_audio_handoff), play); - priv->audio_queue = gst_elementfactory_make ("queue", "audio_queue"); - - gst_bin_add (GST_BIN (priv->audio_play), priv->audio_element), - - gst_element_connect (priv->audio_queue, "src", priv->audio_element, "sink"); - // FIXME, we need caps negiciation - gst_pad_set_caps_list (gst_element_get_pad (priv->audio_queue, "sink"), - gst_pad_get_caps_list ( - gst_element_get_pad (priv->audio_element, "sink"))); - - /* and a video sink */ - priv->video_show = gst_thread_new ("video_render_thread"); - g_return_if_fail (priv->video_show != NULL); - priv->video_element = gst_elementfactory_make ("videosink", "show"); g_return_if_fail (priv->video_element != NULL); gtk_object_set (GTK_OBJECT (priv->video_element), "xv_enabled", FALSE, NULL); gtk_signal_connect (GTK_OBJECT (priv->video_element), "frame_displayed", GTK_SIGNAL_FUNC (gst_play_frame_displayed), play); - priv->video_queue = gst_elementfactory_make ("queue", "video_queue"); - - gst_bin_add (GST_BIN (priv->video_show), priv->video_element), - - gst_element_connect (priv->video_queue, "src", priv->video_element, "sink"); - gst_pad_set_caps_list (gst_element_get_pad (priv->video_queue, "sink"), - gst_pad_get_caps_list ( - gst_element_get_pad (priv->video_element, "sink"))); - play->state = GST_PLAY_STOPPED; play->flags = 0; @@ -193,6 +166,14 @@ static void gst_play_frame_displayed (GstElement *element, GstPlay *play) { + GstPlayPrivate *priv; + + priv = (GstPlayPrivate *)play->priv; + + gdk_threads_enter (); + gtk_widget_show (GTK_WIDGET (priv->video_widget)); + gdk_threads_leave (); + gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_FRAME_DISPLAYED], NULL); } @@ -338,27 +319,6 @@ connect_pads (GstElement *new_element, GstElement *target, gboolean add) return FALSE; } -static void -dynamic_connect_pads (GstElement *new_element, GstPad *pad, gpointer data) -{ - GstPlay *play = (GstPlay *)data; - GstPlayPrivate *priv; - - priv = (GstPlayPrivate *)play->priv; - - gdk_threads_enter(); - if (!(play->flags & GST_PLAY_TYPE_AUDIO) && - (connect_pads (new_element, priv->audio_queue, FALSE))) { - play->flags |= GST_PLAY_TYPE_AUDIO; - } - if (!(play->flags & GST_PLAY_TYPE_VIDEO) && - (connect_pads (new_element, priv->video_queue, FALSE))) { - play->flags |= GST_PLAY_TYPE_VIDEO; - gtk_widget_show (priv->video_widget); - } - gdk_threads_leave(); -} - GstPlayReturn gst_play_set_uri (GstPlay *play, const guchar *uri) @@ -394,14 +354,15 @@ gst_play_set_uri (GstPlay *play, return GST_PLAY_UNKNOWN_MEDIA; } - autoplug = gst_autoplugfactory_make ("static"); + autoplug = gst_autoplugfactory_make ("staticrender"); + g_assert (autoplug != NULL); gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play); - new_element = gst_autoplug_caps_list (autoplug, + new_element = gst_autoplug_to_renderers (autoplug, gst_pad_get_caps_list (gst_element_get_pad (priv->src, "src")), - gst_pad_get_caps_list (gst_element_get_pad (priv->video_queue, "sink")), - gst_pad_get_caps_list (gst_element_get_pad (priv->audio_queue, "sink")), + priv->video_element, + priv->audio_element, NULL); if (!new_element) { @@ -415,26 +376,6 @@ gst_play_set_uri (GstPlay *play, gst_element_connect (priv->src, "src", new_element, "sink"); - if (connect_pads (new_element, priv->video_queue, TRUE)) { - gst_bin_add (GST_BIN (priv->bin), priv->video_show), - play->flags |= GST_PLAY_TYPE_VIDEO; - gtk_widget_show (priv->video_widget); - } - else { - gst_bin_add (GST_BIN (priv->bin), priv->video_show), - gtk_signal_connect (GTK_OBJECT (new_element), "new_pad", dynamic_connect_pads, play); - gtk_signal_connect (GTK_OBJECT (new_element), "new_ghost_pad", dynamic_connect_pads, play); - } - if (connect_pads (new_element, priv->audio_queue, TRUE)) { - gst_bin_add (GST_BIN (priv->bin), priv->audio_play), - play->flags |= GST_PLAY_TYPE_AUDIO; - } - else { - gst_bin_add (GST_BIN (priv->bin), priv->audio_play), - gtk_signal_connect (GTK_OBJECT (new_element), "new_pad", dynamic_connect_pads, play); - gtk_signal_connect (GTK_OBJECT (new_element), "new_ghost_pad", dynamic_connect_pads, play); - } - gst_bin_add (GST_BIN (priv->thread), priv->bin); gtk_signal_connect (GTK_OBJECT (priv->thread), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play); diff --git a/gstplay/gstplayprivate.h b/gstplay/gstplayprivate.h index f0abf4bc06..31e4e17f10 100644 --- a/gstplay/gstplayprivate.h +++ b/gstplay/gstplayprivate.h @@ -13,9 +13,7 @@ typedef struct _GstPlayPrivate GstPlayPrivate; struct _GstPlayPrivate { GstElement *thread; GstElement *bin; - GstElement *audio_play, *video_show; GstElement *video_element, *audio_element; - GstElement *video_queue, *audio_queue; GtkWidget *video_widget; GstElement *src; diff --git a/tests/Makefile.am b/tests/Makefile.am index d40db412c7..1d82923671 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = sched eos noinst_PROGRAMS = init loadall simplefake states caps queue registry \ -paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 +paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3 # we have nothing but apps here, we can do this safely LIBS += $(GST_LIBS) diff --git a/tests/autoplug.c b/tests/autoplug.c index 198824c487..87913c6f4f 100644 --- a/tests/autoplug.c +++ b/tests/autoplug.c @@ -33,7 +33,7 @@ main (int argc, char *argv[]) gtk_signal_connect (GTK_OBJECT (autoplugger), "new_object", new_object_added, NULL); - element = gst_autoplug_caps_list (autoplugger, testcaps, + element = gst_autoplug_to_caps (autoplugger, testcaps, gst_pad_get_caps_list (gst_element_get_pad (audiosink, "sink")), gst_pad_get_caps_list (gst_element_get_pad (videosink, "sink")), NULL); diff --git a/tests/autoplug2.c b/tests/autoplug2.c index 8a90882b28..64f0a9f58d 100644 --- a/tests/autoplug2.c +++ b/tests/autoplug2.c @@ -1,30 +1,33 @@ #include <gst/gst.h> static GstElement* -autoplug_caps (gchar *mime1, gchar *mime2) +autoplug_caps (GstAutoplug *autoplug, gchar *mime1, gchar *mime2) { GList *caps1, *caps2; caps1 = g_list_append (NULL, gst_caps_new ("tescaps1", mime1)); caps2 = g_list_append (NULL, gst_caps_new ("tescaps2", mime2)); - return gst_autoplug_caps_list (caps1, caps2, NULL); + return gst_autoplug_to_caps (autoplug, caps1, caps2, NULL); } int main (int argc, char *argv[]) { GstElement *element; + GstAutoplug *autoplug; gst_init(&argc,&argv); - element = autoplug_caps ("audio/mp3", "audio/raw"); + autoplug = gst_autoplugfactory_make ("static"); + + element = autoplug_caps (autoplug, "audio/mp3", "audio/raw"); xmlSaveFile ("autoplug2_1.gst", gst_xml_write (element)); - element = autoplug_caps ("video/mpeg", "audio/raw"); + element = autoplug_caps (autoplug, "video/mpeg", "audio/raw"); xmlSaveFile ("autoplug2_2.gst", gst_xml_write (element)); - element = gst_autoplug_caps_list ( + element = gst_autoplug_to_caps (autoplug, g_list_append (NULL, gst_caps_new_with_props( "testcaps3", "video/mpeg", @@ -36,7 +39,7 @@ main (int argc, char *argv[]) NULL); xmlSaveFile ("autoplug2_3.gst", gst_xml_write (element)); - element = gst_autoplug_caps_list ( + element = gst_autoplug_to_caps (autoplug, g_list_append (NULL, gst_caps_new_with_props( "testcaps5", "video/mpeg", @@ -48,5 +51,28 @@ main (int argc, char *argv[]) NULL); xmlSaveFile ("autoplug2_4.gst", gst_xml_write (element)); + element = gst_autoplug_to_caps (autoplug, + g_list_append (NULL, gst_caps_new( + "testcaps7", + "video/avi")), + g_list_append (NULL, gst_caps_new("testcaps8", "video/raw")), + g_list_append (NULL, gst_caps_new("testcaps9", "audio/raw")), + NULL); + xmlSaveFile ("autoplug2_5.gst", gst_xml_write (element)); + + element = gst_autoplug_to_caps (autoplug, + g_list_append (NULL, gst_caps_new_with_props( + "testcaps10", + "video/mpeg", + gst_props_new ( + "mpegversion", GST_PROPS_INT (1), + "systemstream", GST_PROPS_BOOLEAN (TRUE), + NULL))), + g_list_append (NULL, gst_caps_new("testcaps10", "video/raw")), + g_list_append (NULL, gst_caps_new("testcaps11", "audio/raw")), + NULL); + xmlSaveFile ("autoplug2_6.gst", gst_xml_write (element)); + + exit (0); exit (0); } |