Merged the AUTOPLUG2 branch

Original commit message from CVS:
Merged the AUTOPLUG2 branch
This commit is contained in:
Wim Taymans 2001-03-07 21:52:56 +00:00
parent 031e0a3acb
commit 55006f6367
57 changed files with 2837 additions and 1247 deletions

View file

@ -597,6 +597,7 @@ AM_CONDITIONAL(HAVE_LIBSHOUT, test "x$HAVE_LIBSHOUT" = "xyes")
AM_CONDITIONAL(HAVE_LIBESD, test "x$HAVE_LIBESD" = "xyes") AM_CONDITIONAL(HAVE_LIBESD, test "x$HAVE_LIBESD" = "xyes")
AM_CONDITIONAL(HAVE_LIBASOUND, test "x$HAVE_LIBASOUND" = "xyes") AM_CONDITIONAL(HAVE_LIBASOUND, test "x$HAVE_LIBASOUND" = "xyes")
AM_CONDITIONAL(HAVE_MPEG2DEC, test "x$HAVE_MPEG2DEC" = "xyes") AM_CONDITIONAL(HAVE_MPEG2DEC, test "x$HAVE_MPEG2DEC" = "xyes")
AM_CONDITIONAL(HAVE_LIBXMMS, test "x$HAVE_LIBXMMS" = "xyes")
@ -680,6 +681,7 @@ gst/Makefile
gst/types/Makefile gst/types/Makefile
gst/meta/Makefile gst/meta/Makefile
gst/elements/Makefile gst/elements/Makefile
gst/autoplug/Makefile
libs/Makefile libs/Makefile
libs/riff/Makefile libs/riff/Makefile
libs/colorspace/Makefile libs/colorspace/Makefile

View file

@ -15,60 +15,18 @@ to convert a certain GstCaps to another one.
</para> </para>
<!-- ##### MACRO GST_AUTOPLUG_MAX_COST ##### -->
<para>
The maximum cost of a certain connection.
</para>
<!-- ##### USER_FUNCTION GstAutoplugCostFunction ##### -->
<para>
Calculate the cost between two elements.
</para>
@src: the source element
@dest: the destination element
@data: optional user data
@Returns: the cost for a connection between the two elements
<!-- ##### USER_FUNCTION GstAutoplugListFunction ##### -->
<para>
Get a list of all elements. These elements will be used in autoplugging.
</para>
@data: user data
@Returns: a GList of elements
<!-- ##### FUNCTION gst_autoplug_caps ##### -->
<para>
</para>
@srccaps:
@sinkcaps:
@Returns:
<!-- ##### FUNCTION gst_autoplug_pads ##### -->
<para>
</para>
@srcpad:
@sinkpad:
@Returns:
<!-- ##### FUNCTION gst_autoplug_caps_list ##### --> <!-- ##### FUNCTION gst_autoplug_caps_list ##### -->
<para> <para>
</para> </para>
@autoplug:
@srcpad:
@sinkpad:
@Varargs:
@Returns:
<!-- # Unused Parameters # -->
@srccaps: @srccaps:
@sinkcaps: @sinkcaps:
@Returns:

View file

@ -133,6 +133,8 @@ a start/stop timecode pair.
@offset: the offset of the region to get @offset: the offset of the region to get
@len: the length of the region to get @len: the length of the region to get
@Returns: a #GstBuffer @Returns: a #GstBuffer
<!-- # Unused Parameters # -->
@size: the size of the region to get
<!-- ##### USER_FUNCTION GstPadQoSFunction ##### --> <!-- ##### USER_FUNCTION GstPadQoSFunction ##### -->

View file

@ -38,33 +38,6 @@ pipeline figure out what plugins to use.
@Returns: @Returns:
<!-- ##### FUNCTION gst_pipeline_add_sink ##### -->
<para>
</para>
@pipeline:
@sink:
<!-- ##### FUNCTION gst_pipeline_add_src ##### -->
<para>
</para>
@pipeline:
@src:
<!-- ##### FUNCTION gst_pipeline_autoplug ##### -->
<para>
</para>
@pipeline:
@Returns:
<!-- ##### MACRO gst_pipeline_destroy ##### --> <!-- ##### MACRO gst_pipeline_destroy ##### -->
<para> <para>
Destroys the pipeline. Destroys the pipeline.

View file

@ -27,6 +27,8 @@ GStreamer is extensible so <classname>GstElements</classname> can be loaded at r
@numtypes: @numtypes:
@elements: @elements:
@numelements: @numelements:
@autopluggers:
@numautopluggers:
@loaded: @loaded:
<!-- ##### STRUCT GstPluginElement ##### --> <!-- ##### STRUCT GstPluginElement ##### -->
@ -203,15 +205,6 @@ by the loader at statup.
@Returns: @Returns:
<!-- ##### FUNCTION gst_plugin_find_elementfactory ##### -->
<para>
</para>
@name:
@Returns:
<!-- ##### FUNCTION gst_plugin_load_elementfactory ##### --> <!-- ##### FUNCTION gst_plugin_load_elementfactory ##### -->
<para> <para>

View file

@ -780,10 +780,6 @@ Query whether this object has multiple input pads.
</para> </para>
<!-- ##### SECTION ./tmpl/gstasyncdisksrc.sgml:Short_Description ##### -->
Asynchronous disk reader. (asyncdisksrc)
<!-- ##### FUNCTION gst_src_signal_eos ##### --> <!-- ##### FUNCTION gst_src_signal_eos ##### -->
<para> <para>
@ -1383,11 +1379,15 @@ The start point of a filter graph
@klass: @klass:
<<<<<<< gstreamer-unused.sgml
<!-- ##### SECTION ./tmpl/gstasyncdisksrc.sgml:Title ##### --> <!-- ##### SECTION ./tmpl/gstasyncdisksrc.sgml:Title ##### -->
GstAsyncDiskSrc GstAsyncDiskSrc
<!-- ##### MACRO GST_TYPE_ASYNCDISKSRC ##### --> <!-- ##### MACRO GST_TYPE_ASYNCDISKSRC ##### -->
=======
<!-- ##### MACRO GST_TYPE_ASYNCDISKSRC ##### -->
>>>>>>> 1.23.2.3
<para> <para>
</para> </para>
@ -2009,6 +2009,7 @@ GstFilter
</para> </para>
<<<<<<< gstreamer-unused.sgml
<!-- ##### ENUM GstSrcFlags ##### --> <!-- ##### ENUM GstSrcFlags ##### -->
<para> <para>
Flags for the GstSrc element Flags for the GstSrc element
@ -2024,6 +2025,18 @@ Flags for the GstSrc element
<!-- ##### MACRO GST_HTTPSRC ##### --> <!-- ##### MACRO GST_HTTPSRC ##### -->
=======
<!-- ##### ENUM GstSrcFlags ##### -->
<para>
Flags for the GstSrc element
</para>
@GST_SRC_ASYNC: Indicates that this src is asynchronous
@GST_SRC_FLAG_LAST: subclasses can use this to number their flags
<!-- ##### MACRO GST_HTTPSRC ##### -->
>>>>>>> 1.23.2.3
<para> <para>
</para> </para>

149
docs/random/hierarchy Normal file
View file

@ -0,0 +1,149 @@
Face it, the plugins/ directory hierarchy is crap. We want to propose a
better layout for it now. Some things to consider:
- Elements have a klass member in the factory that is used to
denote the functional type of the element. For example, the
mp3 encoder has a klass of Filter/Encoder/Audio
- The plugins can be grouped together by the media type they
operate on or by the way they work (decoder/encoder)
In GStreamer all plugins are techically filters, the only way they
can be considered sources or sinks (input/output) elements is
by the absence of src/sink pads. At first sight the source/filter/
sink distinction is quite useless because most of the plugins
will go into the filters category anyway.
We don't want to make the hierarchy too deep, yet provide a
clean way to ask for a mp3 decoder element..
Anyway this is a rough proposal to fire off the discussions...
Wim
Source
Disk
disksrc
fdsrc
multifilesrc
Network
HTTPsrc
RTPsrc
CDDA
cdparanoia
XMMS
..
DVD
dvdsrc
Audio
ASLA
OSS
Capture
v4lsrc
firewire
Demuxer
AVI
MPEG1
MPEG2
QT
Muxer
AVI
MPEG1
QT
Aggregator
Tee
gsttee
Connection
queue
CORBA
Parser
MPEG1
MPEG2
AC3
Mixer
Audio
Merge
Video
Subtitles
Merge
Filters
Audio
ladspa
resample
Video
colorspace
Effect
Audio
stereo
volume
delay
chorus
Video
median
smooth
XMMS
Decoder
MPEG1
MPEG2
MP3
mpg123
xing
win32
AU
WAV
JPEG
AC3
ac3dec
RTJPEG
vorbis
Encoder
MPEG1
MPEG2
MP3
lame
mpegaudio
win32
JPEG
AU
WAV
RTJPEG
Vorbis
Visualisation
Video
histogram
Audio
smoothwave
spectrum
synaesthesia
vumeter
XMMS
Sink
Disk
filesink
multifilesink
Network
ICECASTsink
FTPsink
RTPsink
XMMS
ESD
Video
videosink
SDLsink
Audio
OSSsink
ALSAsink

View file

@ -42,22 +42,26 @@ any intermediate steps to accomplish this conversion.
The API for the user apps should be no more then this: The API for the user apps should be no more then this:
GstElement* gst_autoplug_construct (GstAutoplug *autoplug, GstElement* gst_autoplug_caps_list (GstAutoplug *autoplug,
GstCaps *incaps, GList *incaps,
GstCaps *outcaps, ...); GList *outcaps, ...);
autoplug is a reference to the autoplug implementation autoplug is a reference to the autoplug implementation
incaps is a GstCaps handle for the source pad, the last set incaps is a GList of GstCaps* for the source pad, the last set
of arguments is a va_list of destination caps. of arguments is a va_list of destination caps lists.
A handle to the autoplugger implementation can be obtained A handle to the autoplugger implementation can be obtained
with with
GList* gst_autoplug_get_list (void); GList* gst_autoplugfactory_get_list (void);
which will return a GList* of autopluggers. which will return a GList* of autopluggers.
GstAutoplug* gst_autoplug_get ("name"); GstAutoplug* gst_autoplugfactory_make ("name");
or
GstAutoplug* gst_autoplugfactory_create (GstAutoplugFactory *autoplug);
is used to get an autoplugger. is used to get an autoplugger.
@ -72,11 +76,12 @@ overriding various methods.
the autoplugger can be registered with: the autoplugger can be registered with:
gst_plugin_add_autoplugger (GstPlugin *plugin, gst_plugin_add_autoplugger (GstPlugin *plugin,
GstAutoplug *autoplug); GstAutoplugFactory *autoplug);
This will allow us to only load the autoplugger when needed. This will allow us to only load the autoplugger when needed.
4) implementation 4) implementation
----------------- -----------------
@ -108,11 +113,9 @@ properties:
- name, description, more text to identify the autoplugger. - name, description, more text to identify the autoplugger.
- a class method autoplug_construct that has to be implemented by - a class method autoplug_caps_list that has to be implemented by
the real autoplugger. the real autoplugger.
- possible PadTemplates that this autoplugger can handle well?
optionally, the core autoplugger code can provide convenience optionally, the core autoplugger code can provide convenience
functions to implement custom autopluggers. The shortest path functions to implement custom autopluggers. The shortest path
algorithm with pluggable weighting and list functions come to algorithm with pluggable weighting and list functions come to
@ -124,8 +127,9 @@ A possible use case would be to let gstmediaplay perform an
autoplug on the media stream and insert a custom sound/video autoplug on the media stream and insert a custom sound/video
effect in the pipeline when an appropriate element is created. effect in the pipeline when an appropriate element is created.
the "new_object" signal will be fired by the autoplugger whenever
a new object has been created. This signal can be caught by the
user app to perform an introspection on the newly created object.
comments?
Wim

View file

@ -31,8 +31,6 @@ int main(int argc,char *argv[])
exit(-1); exit(-1);
} }
/* create a new bin to hold the elements */ /* create a new bin to hold the elements */
pipeline = gst_pipeline_new("pipeline"); pipeline = gst_pipeline_new("pipeline");
g_assert(pipeline != NULL); g_assert(pipeline != NULL);
@ -59,6 +57,7 @@ int main(int argc,char *argv[])
gtk_widget_show_all(appwindow); gtk_widget_show_all(appwindow);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), videosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), videosink);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink);
@ -67,6 +66,7 @@ int main(int argc,char *argv[])
g_print("unable to handle stream\n"); g_print("unable to handle stream\n");
exit(-1); exit(-1);
} }
*/
xmlSaveFile("xmlTest.gst", gst_xml_write(GST_ELEMENT(pipeline))); xmlSaveFile("xmlTest.gst", gst_xml_write(GST_ELEMENT(pipeline)));

View file

@ -41,6 +41,7 @@ int main(int argc,char *argv[])
g_assert(audiosink != NULL); g_assert(audiosink != NULL);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink);
@ -48,6 +49,7 @@ int main(int argc,char *argv[])
g_print("unable to handle stream\n"); g_print("unable to handle stream\n");
exit(-1); exit(-1);
} }
*/
// hmmmm hack? FIXME // hmmmm hack? FIXME
GST_FLAG_UNSET (pipeline, GST_BIN_FLAG_MANAGER); GST_FLAG_UNSET (pipeline, GST_BIN_FLAG_MANAGER);

View file

@ -46,6 +46,7 @@ int main(int argc,char *argv[])
g_assert(audiosink != NULL); g_assert(audiosink != NULL);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), queue); gst_pipeline_add_sink(GST_PIPELINE(pipeline), queue);
@ -58,6 +59,7 @@ int main(int argc,char *argv[])
g_print("cannot autoplug pipeline\n"); g_print("cannot autoplug pipeline\n");
exit(-1); exit(-1);
} }
*/
gst_bin_add(GST_BIN(pipeline), thread); gst_bin_add(GST_BIN(pipeline), thread);

View file

@ -45,6 +45,7 @@ int main(int argc,char *argv[])
g_assert(audiosink != NULL); g_assert(audiosink != NULL);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink);
@ -52,6 +53,7 @@ int main(int argc,char *argv[])
g_print("unable to handle stream\n"); g_print("unable to handle stream\n");
exit(-1); exit(-1);
} }
*/
//gst_bin_remove(GST_BIN(pipeline), disksrc); //gst_bin_remove(GST_BIN(pipeline), disksrc);

View file

@ -1,5 +1,5 @@
# cheap trick to build . first... # cheap trick to build . first...
SUBDIRS = . types meta elements SUBDIRS = . types meta elements autoplug
lib_LTLIBRARIES = libgst.la lib_LTLIBRARIES = libgst.la

12
gst/autoplug/Makefile.am Normal file
View file

@ -0,0 +1,12 @@
filterdir = $(libdir)/gst
filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la
libgststaticautoplug_la_SOURCES = \
gststaticautoplug.c
libgststaticautoplugrender_la_SOURCES = \
gststaticautoplugrender.c
libgststaticautoplug_la_LDFLAGS = -version-info $(GSTREAMER_LIBVERSION)
libgststaticautoplugrender_la_LDFLAGS = -version-info $(GSTREAMER_LIBVERSION)

View file

@ -0,0 +1,619 @@
/* 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 "gststaticautoplug.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_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 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)
{
static GtkType static_autoplug_type = 0;
if (!static_autoplug_type) {
static const GtkTypeInfo static_autoplug_info = {
"GstStaticAutoplug",
sizeof(GstElement),
sizeof(GstElementClass),
(GtkClassInitFunc)gst_static_autoplug_class_init,
(GtkObjectInitFunc)gst_static_autoplug_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_class_init(GstStaticAutoplugClass *klass)
{
GstAutoplugClass *gstautoplug_class;
gstautoplug_class = (GstAutoplugClass*) klass;
parent_class = gtk_type_class(GST_TYPE_AUTOPLUG);
gstautoplug_class->autoplug_to_caps = gst_static_autoplug_to_caps;
}
static void gst_static_autoplug_init(GstStaticAutoplug *autoplug) {
}
GstPlugin*
plugin_init (GModule *module)
{
GstPlugin *plugin;
GstAutoplugFactory *factory;
plugin = gst_plugin_new("gststaticautoplug");
g_return_val_if_fail(plugin != NULL,NULL);
gst_plugin_set_longname (plugin, "A static autoplugger");
factory = gst_autoplugfactory_new ("static",
"A static autoplugger, it constructs the complete element before running it",
gst_static_autoplug_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);
}
}
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_caps (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, va_list args)
{
caps_struct caps;
GList *capslist;
GstElement *result = NULL, *srcelement = NULL;
GList **factories;
GList *chains = NULL;
GList *endcaps = NULL;
guint numsinks = 0, i;
gboolean have_common = FALSE;
capslist = sinkcaps;
/*
* 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 (capslist) {
GList *elements;
caps.sink = capslist;
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);
endcaps = g_list_append (endcaps, capslist);
numsinks++;
}
else {
}
capslist = va_arg (args, GList *);
}
/*
* 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);
while (factories[i]) {
// fase 4: add other elements...
GstElementFactory *factory;
GstElement *element;
factory = (GstElementFactory *)(factories[i]->data);
GST_DEBUG (0,"factory \"%s\"\n", factory->name);
element = gst_elementfactory_create(factory, factory->name);
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]);
}
/*
* we're at the last element in the chain,
* find a suitable pad to turn into a ghostpad
*/
{
GList *endcap = (GList *)(endcaps->data);
GList *pads = gst_element_get_pad_list (thesrcelement);
gboolean have_pad = FALSE;
endcaps = g_list_next (endcaps);
GST_DEBUG (0,"attempting to create a ghostpad for %s\n", GST_ELEMENT_NAME (thesrcelement));
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), endcap)) {
gst_element_add_ghost_pad (result, pad, g_strdup_printf("src_%02d", i));
have_pad = TRUE;
break;
}
}
if (!have_pad) {
dynamic_pad_struct *data = g_new0(dynamic_pad_struct, 1);
data->result = result;
data->endcap = endcap;
data->i = i;
GST_DEBUG (0,"delaying the creation of a ghostpad for %s\n", GST_ELEMENT_NAME (thesrcelement));
gtk_signal_connect (GTK_OBJECT (thesrcelement), "new_pad",
autoplug_dynamic_pad, data);
gtk_signal_connect (GTK_OBJECT (thesrcelement), "new_ghost_pad",
autoplug_dynamic_pad, data);
}
}
}
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);
}

View file

@ -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_H__
#define __GST_STATIC_AUTOPLUG_H__
#include <gst/gstautoplug.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GST_TYPE_STATIC_AUTOPLUG \
(gst_static_autoplug_get_type())
#define GST_STATIC_AUTOPLUG(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_STATIC_AUTOPLUG,GstStaticAutoplug))
#define GST_STATIC_AUTOPLUG_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_STATIC_AUTOPLUG,GstStaticAutoplugClass))
#define GST_IS_STATIC_AUTOPLUG(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_STATIC_AUTOPLUG))
#define GST_IS_STATIC_AUTOPLUG_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_STATIC_AUTOPLUG))
typedef struct _GstStaticAutoplug GstStaticAutoplug;
typedef struct _GstStaticAutoplugClass GstStaticAutoplugClass;
struct _GstStaticAutoplug {
GstAutoplug object;
};
struct _GstStaticAutoplugClass {
GstAutoplugClass parent_class;
};
GtkType gst_static_autoplug_get_type (void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_STATIC_AUTOPLUG_H__ */

View file

@ -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);
}

View file

@ -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__ */

View file

@ -223,7 +223,7 @@ gst_disksrc_get (GstPad *pad)
/* deal with EOF state */ /* deal with EOF state */
if (src->curoffset >= src->size) { if (src->curoffset >= src->size) {
gst_element_signal_eos (GST_ELEMENT (src)); gst_pad_set_eos (pad);
return NULL; return NULL;
} }
@ -284,7 +284,7 @@ gst_disksrc_get_region (GstPad *pad, GstRegionType type,guint64 offset,guint64 l
/* deal with EOF state */ /* deal with EOF state */
if (offset >= src->size) { if (offset >= src->size) {
gst_element_signal_eos (GST_ELEMENT (src)); gst_pad_set_eos (pad);
return NULL; return NULL;
} }

View file

@ -24,337 +24,268 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstautoplug.h" #include "gstautoplug.h"
#include "gstplugin.h"
GList* _gst_autoplugfactories;
enum {
NEW_OBJECT,
LAST_SIGNAL
};
enum {
ARG_0,
/* FILL ME */
};
static void gst_autoplug_class_init (GstAutoplugClass *klass); static void gst_autoplug_class_init (GstAutoplugClass *klass);
static void gst_autoplug_init (GstAutoplug *autoplug); static void gst_autoplug_init (GstAutoplug *autoplug);
static GList* gst_autoplug_func (gpointer src, gpointer sink,
GstAutoplugListFunction list_function,
GstAutoplugCostFunction cost_function,
gpointer data);
struct _gst_autoplug_node
{
gpointer iNode;
gpointer iPrev;
gint iDist;
};
typedef struct _gst_autoplug_node gst_autoplug_node;
static GstObjectClass *parent_class = NULL; static GstObjectClass *parent_class = NULL;
static guint gst_autoplug_signals[LAST_SIGNAL] = { 0 };
GtkType gst_autoplug_get_type(void) { GtkType gst_autoplug_get_type(void)
{
static GtkType autoplug_type = 0; static GtkType autoplug_type = 0;
if (!autoplug_type) { if (!autoplug_type) {
static const GtkTypeInfo autoplug_info = { static const GtkTypeInfo autoplug_info = {
"GstAutoplug", "GstAutoplug",
sizeof(GstElement), sizeof(GstAutoplug),
sizeof(GstElementClass), sizeof(GstAutoplugClass),
(GtkClassInitFunc)gst_autoplug_class_init, (GtkClassInitFunc)gst_autoplug_class_init,
(GtkObjectInitFunc)gst_autoplug_init, (GtkObjectInitFunc)gst_autoplug_init,
(GtkArgSetFunc)NULL, (GtkArgSetFunc)NULL,
(GtkArgGetFunc)NULL, (GtkArgGetFunc)NULL,
(GtkClassInitFunc)NULL, (GtkClassInitFunc)NULL,
}; };
autoplug_type = gtk_type_unique(GST_TYPE_AUTOPLUG,&autoplug_info); autoplug_type = gtk_type_unique (GST_TYPE_OBJECT, &autoplug_info);
} }
return autoplug_type; return autoplug_type;
} }
static void static void
gst_autoplug_class_init(GstAutoplugClass *klass) { 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(GST_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,
GTK_SIGNAL_OFFSET (GstAutoplugClass, new_object),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_OBJECT);
gtk_object_class_add_signals (gtkobject_class, gst_autoplug_signals, LAST_SIGNAL);
} }
static void gst_autoplug_init(GstAutoplug *autoplug) { static void gst_autoplug_init(GstAutoplug *autoplug)
}
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 GList* void
gst_autoplug_elementfactory_get_list (gpointer data) _gst_autoplug_initialize (void)
{ {
return gst_elementfactory_get_list (); _gst_autoplugfactories = NULL;
} }
typedef struct { void
GList *src; gst_autoplug_signal_new_object (GstAutoplug *autoplug, GstObject *object)
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; gtk_signal_emit (GTK_OBJECT (autoplug), gst_autoplug_signals[NEW_OBJECT], object);
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) GstElement*
return 1; gst_autoplug_to_caps (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, ...)
else {
return GST_AUTOPLUG_MAX_COST; GstAutoplugClass *oclass;
GstElement *element = NULL;
va_list args;
va_start (args, sinkcaps);
oclass = GST_AUTOPLUG_CLASS (GTK_OBJECT (autoplug)->klass);
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);
return element;
}
/**
* gst_autoplugfactory_new:
* @name: name of autoplugfactory to create
* @longdesc: long description of autoplugfactory to create
* @type: the gtk type of the GstAutoplug element of this factory
*
* Create a new autoplugfactory with the given parameters
*
* Returns: a new #GstAutoplugFactory.
*/
GstAutoplugFactory*
gst_autoplugfactory_new (const gchar *name, const gchar *longdesc, GtkType type)
{
GstAutoplugFactory *factory;
g_return_val_if_fail(name != NULL, NULL);
factory = g_new0(GstAutoplugFactory, 1);
factory->name = g_strdup(name);
factory->longdesc = g_strdup (longdesc);
factory->type = type;
_gst_autoplugfactories = g_list_prepend (_gst_autoplugfactories, factory);
return factory;
} }
/** /**
* gst_autoplug_caps: * gst_autoplugfactory_destroy:
* @srccaps: the source caps * @autoplug: factory to destroy
* @sinkcaps: the sink caps
* *
* Perform autoplugging between the two given caps. * Removes the autoplug from the global list.
*
* Returns: a list of elementfactories that can connect
* the two caps
*/ */
GList* void
gst_autoplug_caps (GstCaps *srccaps, GstCaps *sinkcaps) gst_autoplugfactory_destroy (GstAutoplugFactory *autoplug)
{ {
caps_struct caps; g_return_if_fail (autoplug != NULL);
caps.src = g_list_prepend (NULL,srccaps); _gst_autoplugfactories = g_list_remove (_gst_autoplugfactories, autoplug);
caps.sink = g_list_prepend (NULL,sinkcaps);
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"autoplugging two caps structures"); // we don't free the struct bacause someone might have a handle to it..
return gst_autoplug_func (caps.src, caps.sink,
gst_autoplug_elementfactory_get_list,
gst_autoplug_caps_find_cost,
&caps);
} }
/** /**
* gst_autoplug_caps_list: * gst_autoplug_find:
* @srccaps: the source caps list * @name: name of autoplugger to find
* @sinkcaps: the sink caps list
* *
* Perform autoplugging between the two given caps lists. * Search for an autoplugger of the given name.
* *
* Returns: a list of elementfactories that can connect * Returns: #GstAutoplug if found, NULL otherwise
* the two caps lists
*/ */
GList* GstAutoplugFactory*
gst_autoplug_caps_list (GList *srccaps, GList *sinkcaps) gst_autoplugfactory_find (const gchar *name)
{ {
caps_struct caps; GList *walk;
GstAutoplugFactory *factory;
caps.src = srccaps; g_return_val_if_fail(name != NULL, NULL);
caps.sink = sinkcaps;
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"autoplugging two caps list structures"); GST_DEBUG (0,"gstautoplug: find \"%s\"\n", name);
return gst_autoplug_func (caps.src, caps.sink, walk = _gst_autoplugfactories;
gst_autoplug_elementfactory_get_list, while (walk) {
gst_autoplug_caps_find_cost, factory = (GstAutoplugFactory *)(walk->data);
&caps); if (!strcmp (name, factory->name))
return factory;
walk = g_list_next (walk);
}
return NULL;
} }
/** /**
* gst_autoplug_pads: * gst_autoplugfactory_get_list:
* @srcpad: the source pad
* @sinkpad: the sink pad
* *
* Perform autoplugging between the two given pads. * Get the global list of elementfactories.
* *
* Returns: a list of elementfactories that can connect * Returns: GList of type #GstElementFactory
* the two pads
*/ */
GList* GList*
gst_autoplug_pads (GstPad *srcpad, GstPad *sinkpad) gst_autoplugfactory_get_list (void)
{ {
caps_struct caps; return _gst_autoplugfactories;
caps.src = gst_pad_get_caps_list(srcpad);
caps.sink = gst_pad_get_caps_list(sinkpad);
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"autoplugging two caps structures");
return gst_autoplug_func (caps.src, caps.sink,
gst_autoplug_elementfactory_get_list,
gst_autoplug_caps_find_cost,
&caps);
}
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* GstAutoplug*
construct_path (gst_autoplug_node *rgnNodes, gpointer factory) gst_autoplugfactory_create (GstAutoplugFactory *factory)
{ {
GstElementFactory *current; GstAutoplug *new = NULL;
GList *factories = NULL;
current = rgnNodes[find_factory(rgnNodes, factory)].iPrev; g_return_val_if_fail (factory != NULL, NULL);
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"factories found in autoplugging (reversed order)"); if (factory->type == 0){
factory = gst_plugin_load_autoplugfactory (factory->name);
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; g_return_val_if_fail (factory != NULL, NULL);
} g_return_val_if_fail (factory->type != 0, NULL);
return factories;
new = GST_AUTOPLUG (gtk_type_new (factory->type));
return new;
} }
static GList* GstAutoplug*
gst_autoplug_enqueue (GList *queue, gpointer iNode, gint iDist, gpointer iPrev) gst_autoplugfactory_make (const gchar *name)
{ {
gst_autoplug_node *node = g_malloc (sizeof (gst_autoplug_node)); GstAutoplugFactory *factory;
node->iNode = iNode; g_return_val_if_fail (name != NULL, NULL);
node->iDist = iDist;
node->iPrev = iPrev;
queue = g_list_append (queue, node); factory = gst_autoplugfactory_find (name);
return queue; if (factory == NULL)
return NULL;
return gst_autoplugfactory_create (factory);;
} }
static GList* xmlNodePtr
gst_autoplug_dequeue (GList *queue, gpointer *iNode, gint *iDist, gpointer *iPrev) gst_autoplugfactory_save_thyself (GstAutoplugFactory *factory, xmlNodePtr parent)
{ {
GList *head; g_return_val_if_fail(factory != NULL, NULL);
gst_autoplug_node *node;
head = g_list_first (queue); xmlNewChild(parent,NULL,"name",factory->name);
xmlNewChild(parent,NULL,"longdesc", factory->longdesc);
if (head) { return parent;
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* GstAutoplugFactory*
gst_autoplug_func (gpointer src, gpointer sink, gst_autoplugfactory_load_thyself (xmlNodePtr parent)
GstAutoplugListFunction list_function,
GstAutoplugCostFunction cost_function,
gpointer data)
{ {
gst_autoplug_node *rgnNodes; GstAutoplugFactory *factory = g_new0(GstAutoplugFactory, 1);
GList *queue = NULL; xmlNodePtr children = parent->xmlChildrenNode;
gpointer iNode, iPrev;
gint iDist, i, iCost;
GList *elements = g_list_copy (list_function(data)); while (children) {
GList *factories; if (!strcmp(children->name, "name")) {
guint num_factories; factory->name = xmlNodeGetContent(children);
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 { if (!strcmp(children->name, "longdesc")) {
rgnNodes[i].iDist = GST_AUTOPLUG_MAX_COST; factory->longdesc = xmlNodeGetContent(children);
}
children = children->next;
} }
factories = g_list_next (factories); _gst_autoplugfactories = g_list_prepend (_gst_autoplugfactories, factory);
}
rgnNodes[num_factories].iNode = NULL;
queue = gst_autoplug_enqueue (queue, src, 0, NULL); return factory;
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);
} }

View file

@ -31,7 +31,7 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
#define GST_TYPE_AUTOPLUG \ #define GST_TYPE_AUTOPLUG \
(gst_object_get_type()) (gst_autoplug_get_type())
#define GST_AUTOPLUG(obj) \ #define GST_AUTOPLUG(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_AUTOPLUG,GstAutoplug)) (GTK_CHECK_CAST((obj),GST_TYPE_AUTOPLUG,GstAutoplug))
#define GST_AUTOPLUG_CLASS(klass) \ #define GST_AUTOPLUG_CLASS(klass) \
@ -44,25 +44,61 @@ extern "C" {
typedef struct _GstAutoplug GstAutoplug; typedef struct _GstAutoplug GstAutoplug;
typedef struct _GstAutoplugClass GstAutoplugClass; typedef struct _GstAutoplugClass GstAutoplugClass;
#define GST_AUTOPLUG_MAX_COST 999999 typedef enum {
GST_AUTOPLUG_TO_CAPS = GST_OBJECT_FLAG_LAST,
GST_AUTOPLUG_TO_RENDERER,
GST_AUTOPLUG_FLAG_LAST = GST_OBJECT_FLAG_LAST + 8,
} GstAutoplugFlags;
typedef guint (*GstAutoplugCostFunction) (gpointer src, gpointer dest, gpointer data);
typedef GList* (*GstAutoplugListFunction) (gpointer data);
struct _GstAutoplug { struct _GstAutoplug {
GtkObject object; GstObject object;
}; };
struct _GstAutoplugClass { struct _GstAutoplugClass {
GtkObjectClass parent_class; GstObjectClass parent_class;
/* signal callbacks */
void (*new_object) (GstAutoplug *autoplug, GstObject *object);
/* perform the autoplugging */
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;
struct _GstAutoplugFactory {
gchar *name; /* name of autoplugger */
gchar *longdesc; /* long description of the autoplugger (well, don't overdo it..) */
GtkType type; /* unique GtkType of the autoplugger */
}; };
GtkType gst_autoplug_get_type (void); GtkType gst_autoplug_get_type (void);
GList* gst_autoplug_caps (GstCaps *srccaps, GstCaps *sinkcaps); void gst_autoplug_signal_new_object (GstAutoplug *autoplug, GstObject *object);
GList* gst_autoplug_caps_list (GList *srccaps, GList *sinkcaps);
GList* gst_autoplug_pads (GstPad *srcpad, GstPad *sinkpad);
GstElement* gst_autoplug_to_caps (GstAutoplug *autoplug, GList *srccaps, GList *sinkcaps, ...);
GstElement* gst_autoplug_to_renderers (GstAutoplug *autoplug, GList *srccaps,
GstElement *target, ...);
/*
* creating autopluggers
*
*/
GstAutoplugFactory* gst_autoplugfactory_new (const gchar *name, const gchar *longdesc, GtkType type);
void gst_autoplugfactory_destroy (GstAutoplugFactory *factory);
GstAutoplugFactory* gst_autoplugfactory_find (const gchar *name);
GList* gst_autoplugfactory_get_list (void);
GstAutoplug* gst_autoplugfactory_create (GstAutoplugFactory *factory);
GstAutoplug* gst_autoplugfactory_make (const gchar *name);
xmlNodePtr gst_autoplugfactory_save_thyself (GstAutoplugFactory *factory, xmlNodePtr parent);
GstAutoplugFactory* gst_autoplugfactory_load_thyself (xmlNodePtr parent);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -234,6 +234,7 @@ gst_bin_change_state (GstElement *element)
GstBin *bin; GstBin *bin;
GList *children; GList *children;
GstElement *child; GstElement *child;
GstElementStateReturn ret;
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (element)); GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (element));
@ -265,6 +266,8 @@ gst_bin_change_state (GstElement *element)
break; break;
} }
case GST_STATE_READY_TO_NULL:
GST_FLAG_UNSET (bin, GST_BIN_FLAG_MANAGER);
default: default:
break; break;
} }
@ -289,9 +292,9 @@ gst_bin_change_state (GstElement *element)
children = g_list_next (children); children = g_list_next (children);
} }
// g_print("<-- \"%s\"\n",gst_object_get_name(GST_OBJECT(bin))); // g_print("<-- \"%s\"\n",gst_object_get_name(GST_OBJECT(bin)));
ret = gst_bin_change_state_norecurse (bin);
return ret;
return gst_bin_change_state_norecurse (bin);
} }
@ -587,7 +590,7 @@ gst_bin_create_plan (GstBin *bin)
static void static void
gst_bin_received_eos (GstElement *element, GstBin *bin) gst_bin_received_eos (GstElement *element, GstBin *bin)
{ {
GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "child %s fired eos, pending %d\n", GST_ELEMENT_NAME (element), GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "child %s fired eos, pending %d", GST_ELEMENT_NAME (element),
bin->num_eos_providers); bin->num_eos_providers);
GST_LOCK (bin); GST_LOCK (bin);
@ -756,7 +759,9 @@ gst_bin_create_plan_func (GstBin *bin)
} }
// else it's not ours and we need to wait for EOS notifications // else it's not ours and we need to wait for EOS notifications
else { else {
gtk_signal_connect (GTK_OBJECT (element), "eos", gst_bin_received_eos, bin); GST_DEBUG (0,"setting up EOS signal from \"%s\" to \"%s\"\n", elementname,
gst_element_get_name (GST_ELEMENT(bin)->manager));
gtk_signal_connect (GTK_OBJECT (element), "eos", gst_bin_received_eos, GST_ELEMENT(bin)->manager);
bin->eos_providers = g_list_prepend (bin->eos_providers, element); bin->eos_providers = g_list_prepend (bin->eos_providers, element);
bin->num_eos_providers++; bin->num_eos_providers++;
} }
@ -869,7 +874,7 @@ gst_bin_iterate_func (GstBin *bin)
if (bin->num_eos_providers) { if (bin->num_eos_providers) {
GST_LOCK (bin); GST_LOCK (bin);
GST_DEBUG (0,"waiting for eos providers\n"); GST_DEBUG (0,"waiting for eos providers\n");
g_cond_wait (bin->eoscond, GST_OBJECT(bin)->lock); g_cond_wait (bin->eoscond, GST_GET_LOCK(bin));
GST_DEBUG (0,"num eos providers %d\n", bin->num_eos_providers); GST_DEBUG (0,"num eos providers %d\n", bin->num_eos_providers);
GST_UNLOCK (bin); GST_UNLOCK (bin);
} }

View file

@ -252,11 +252,11 @@ gst_caps_get_type_id (GstCaps *caps)
* Set the type id of the caps. * Set the type id of the caps.
*/ */
void void
gst_caps_set_type_id (GstCaps *caps, guint16 typeid) gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
{ {
g_return_if_fail (caps != NULL); g_return_if_fail (caps != NULL);
caps->id = typeid; caps->id = type_id;
} }
/** /**

View file

@ -66,7 +66,7 @@ const gchar* gst_caps_get_mime (GstCaps *caps);
void gst_caps_set_mime (GstCaps *caps, const gchar *mime); void gst_caps_set_mime (GstCaps *caps, const gchar *mime);
guint16 gst_caps_get_type_id (GstCaps *caps); guint16 gst_caps_get_type_id (GstCaps *caps);
void gst_caps_set_type_id (GstCaps *caps, guint16 /*typeid*/); void gst_caps_set_type_id (GstCaps *caps, guint16 type_id);
GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props); GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props);
GstProps* gst_caps_get_props (GstCaps *caps); GstProps* gst_caps_get_props (GstCaps *caps);

View file

@ -902,13 +902,15 @@ gst_element_save_thyself (GstObject *object,
type = gtk_type_parent (type); type = gtk_type_parent (type);
} }
pads = element->pads; pads = GST_ELEMENT_PADS (element);
while (pads) { while (pads) {
GstPad *pad = GST_PAD (pads->data); GstPad *pad = GST_PAD (pads->data);
xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
// figure out if it's a direct pad or a ghostpad // figure out if it's a direct pad or a ghostpad
if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
gst_object_save_thyself (GST_OBJECT (pad), padtag); gst_object_save_thyself (GST_OBJECT (pad), padtag);
}
pads = g_list_next (pads); pads = g_list_next (pads);
} }
@ -973,7 +975,6 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
} }
child = child->next; child = child->next;
} }
gst_util_set_object_arg (GTK_OBJECT (element), name, value); gst_util_set_object_arg (GTK_OBJECT (element), name, value);
} }
children = children->next; children = children->next;

View file

@ -122,6 +122,7 @@ typedef enum {
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj)) #define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj)) #define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
#define GST_ELEMENT_PADS(obj) ((obj)->pads)
typedef struct _GstElement GstElement; typedef struct _GstElement GstElement;
typedef struct _GstElementClass GstElementClass; typedef struct _GstElementClass GstElementClass;

View file

@ -110,10 +110,12 @@ GstElementFactory*
gst_elementfactory_new (const gchar *name, GtkType type, gst_elementfactory_new (const gchar *name, GtkType type,
GstElementDetails *details) GstElementDetails *details)
{ {
GstElementFactory *factory = g_new0(GstElementFactory, 1); GstElementFactory *factory;
g_return_val_if_fail(name != NULL, NULL); g_return_val_if_fail(name != NULL, NULL);
factory = g_new0(GstElementFactory, 1);
factory->name = g_strdup(name); factory->name = g_strdup(name);
factory->type = type; factory->type = type;
factory->details = details; factory->details = details;

View file

@ -370,13 +370,15 @@ gst_object_get_path_string (GstObject *object)
GSList *parentage = NULL; GSList *parentage = NULL;
GSList *parents; GSList *parents;
void *parent; void *parent;
gchar *prevpath, *path = ""; gchar *prevpath, *path;
const char *component; const char *component;
gchar *separator = ""; gchar *separator = "";
gboolean free_component; gboolean free_component;
parentage = g_slist_prepend (NULL, object); parentage = g_slist_prepend (NULL, object);
path = g_strdup ("");
// first walk the object hierarchy to build a list of the parents // first walk the object hierarchy to build a list of the parents
do { do {
if (GST_IS_OBJECT (object)) { if (GST_IS_OBJECT (object)) {
@ -397,9 +399,9 @@ gst_object_get_path_string (GstObject *object)
parents = parentage; parents = parentage;
while (parents) { while (parents) {
if (GST_IS_OBJECT (parents->data)) { if (GST_IS_OBJECT (parents->data)) {
GstObjectClass *oclass = GST_OBJECT_CLASS (GTK_OBJECT (parents->data)); GstObjectClass *oclass = GST_OBJECT_CLASS (GTK_OBJECT (parents->data)->klass);
component = GST_OBJECT_NAME (parents->data); component = gst_object_get_name (parents->data);
separator = oclass->path_string_separator; separator = oclass->path_string_separator;
free_component = FALSE; free_component = FALSE;
} else { } else {

View file

@ -35,7 +35,6 @@ static void gst_pad_init (GstPad *pad);
static xmlNodePtr gst_pad_save_thyself (GstObject *object, xmlNodePtr parent); static xmlNodePtr gst_pad_save_thyself (GstObject *object, xmlNodePtr parent);
static GstObject *pad_parent_class = NULL; static GstObject *pad_parent_class = NULL;
GtkType GtkType
@ -593,6 +592,25 @@ gst_pad_get_parent (GstPad *pad)
return GST_OBJECT_PARENT (pad); return GST_OBJECT_PARENT (pad);
} }
/**
* gst_pad_get_real_parent:
* @pad: the pad to get the parent from
*
* Get the real parent object of this pad. If the pad
* is a ghostpad, the actual owner of the real pad is
* returned, as opposed to the gst_pad_get_parent.
*
* Returns: the parent object
*/
GstObject*
gst_pad_get_real_parent (GstPad *pad)
{
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
return GST_PAD_PARENT (GST_PAD (GST_PAD_REALIZE (pad)));
}
/** /**
* gst_pad_add_ghost_pad: * gst_pad_add_ghost_pad:
* @pad: the pad to set the ghost parent * @pad: the pad to set the ghost parent
@ -948,7 +966,7 @@ gst_pad_pull (GstPad *pad)
{ {
GstRealPad *peer = GST_RPAD_PEER(pad); GstRealPad *peer = GST_RPAD_PEER(pad);
g_return_if_fail (peer != NULL); g_return_val_if_fail (peer != NULL, NULL);
GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad)); GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
@ -983,7 +1001,7 @@ gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len
{ {
GstRealPad *peer = GST_RPAD_PEER(pad); GstRealPad *peer = GST_RPAD_PEER(pad);
g_return_if_fail (peer != NULL); g_return_val_if_fail (peer != NULL, NULL);
GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len); GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len);
@ -1003,6 +1021,65 @@ gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len
* templates * templates
* *
*/ */
static void gst_padtemplate_class_init (GstPadTemplateClass *klass);
static void gst_padtemplate_init (GstPadTemplate *templ);
enum {
TEMPL_PAD_CREATED,
/* FILL ME */
TEMPL_LAST_SIGNAL
};
static GstObject *padtemplate_parent_class = NULL;
static guint gst_padtemplate_signals[TEMPL_LAST_SIGNAL] = { 0 };
GtkType
gst_padtemplate_get_type (void)
{
static GtkType padtemplate_type = 0;
if (!padtemplate_type) {
static const GtkTypeInfo padtemplate_info = {
"GstPadTemplate",
sizeof(GstPadTemplate),
sizeof(GstPadTemplateClass),
(GtkClassInitFunc)gst_padtemplate_class_init,
(GtkObjectInitFunc)gst_padtemplate_init,
(GtkArgSetFunc)NULL,
(GtkArgGetFunc)NULL,
(GtkClassInitFunc)NULL,
};
padtemplate_type = gtk_type_unique(GST_TYPE_OBJECT,&padtemplate_info);
}
return padtemplate_type;
}
static void
gst_padtemplate_class_init (GstPadTemplateClass *klass)
{
GtkObjectClass *gtkobject_class;
GstObjectClass *gstobject_class;
gtkobject_class = (GtkObjectClass*)klass;
gstobject_class = (GstObjectClass*)klass;
padtemplate_parent_class = gtk_type_class(GST_TYPE_OBJECT);
gst_padtemplate_signals[TEMPL_PAD_CREATED] =
gtk_signal_new ("pad_created", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstPadTemplateClass, pad_created),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_PAD);
gtk_object_class_add_signals (gtkobject_class, gst_padtemplate_signals, TEMPL_LAST_SIGNAL);
gstobject_class->path_string_separator = "*";
}
static void
gst_padtemplate_init (GstPadTemplate *templ)
{
}
/** /**
* gst_padtemplate_new: * gst_padtemplate_new:
@ -1022,7 +1099,7 @@ gst_padtemplate_new (GstPadFactory *factory)
g_return_val_if_fail (factory != NULL, NULL); g_return_val_if_fail (factory != NULL, NULL);
new = g_new0 (GstPadTemplate, 1); new = gtk_type_new (gst_padtemplate_get_type ());
tag = (*factory)[i++]; tag = (*factory)[i++];
g_return_val_if_fail (tag != NULL, new); g_return_val_if_fail (tag != NULL, new);
@ -1063,7 +1140,9 @@ gst_padtemplate_create (gchar *name_template,
{ {
GstPadTemplate *new; GstPadTemplate *new;
new = g_new0 (GstPadTemplate, 1); g_return_val_if_fail (name_template != NULL, NULL);
new = gtk_type_new (gst_padtemplate_get_type ());
new->name_template = name_template; new->name_template = name_template;
new->direction = direction; new->direction = direction;
@ -1134,21 +1213,24 @@ GstPadTemplate*
gst_padtemplate_load_thyself (xmlNodePtr parent) gst_padtemplate_load_thyself (xmlNodePtr parent)
{ {
xmlNodePtr field = parent->xmlChildrenNode; xmlNodePtr field = parent->xmlChildrenNode;
GstPadTemplate *factory = g_new0 (GstPadTemplate, 1); GstPadTemplate *factory;
gchar *name_template = NULL;
GstPadDirection direction = GST_PAD_UNKNOWN;
GstPadPresence presence = GST_PAD_ALWAYS;
GList *caps = NULL;
while (field) { while (field) {
if (!strcmp(field->name, "nametemplate")) { if (!strcmp(field->name, "nametemplate")) {
factory->name_template = xmlNodeGetContent(field); name_template = xmlNodeGetContent(field);
} }
if (!strcmp(field->name, "direction")) { if (!strcmp(field->name, "direction")) {
gchar *value = xmlNodeGetContent(field); gchar *value = xmlNodeGetContent(field);
factory->direction = GST_PAD_UNKNOWN;
if (!strcmp(value, "sink")) { if (!strcmp(value, "sink")) {
factory->direction = GST_PAD_SINK; direction = GST_PAD_SINK;
} }
else if (!strcmp(value, "src")) { else if (!strcmp(value, "src")) {
factory->direction = GST_PAD_SRC; direction = GST_PAD_SRC;
} }
g_free (value); g_free (value);
} }
@ -1156,21 +1238,24 @@ gst_padtemplate_load_thyself (xmlNodePtr parent)
gchar *value = xmlNodeGetContent(field); gchar *value = xmlNodeGetContent(field);
if (!strcmp(value, "always")) { if (!strcmp(value, "always")) {
factory->presence = GST_PAD_ALWAYS; presence = GST_PAD_ALWAYS;
} }
else if (!strcmp(value, "sometimes")) { else if (!strcmp(value, "sometimes")) {
factory->presence = GST_PAD_SOMETIMES; presence = GST_PAD_SOMETIMES;
} }
else if (!strcmp(value, "request")) { else if (!strcmp(value, "request")) {
factory->presence = GST_PAD_REQUEST; presence = GST_PAD_REQUEST;
} }
g_free (value); g_free (value);
} }
else if (!strcmp(field->name, "caps")) { else if (!strcmp(field->name, "caps")) {
factory->caps = g_list_append(factory->caps, gst_caps_load_thyself (field)); caps = g_list_append (caps, gst_caps_load_thyself (field));
} }
field = field->next; field = field->next;
} }
factory = gst_padtemplate_create (name_template, direction, presence, caps);
return factory; return factory;
} }
@ -1271,13 +1356,6 @@ gst_pad_get_element_private (GstPad *pad)
} }
/***** ghost pads *****/ /***** ghost pads *****/
static void gst_ghost_pad_class_init (GstGhostPadClass *klass); static void gst_ghost_pad_class_init (GstGhostPadClass *klass);

View file

@ -278,6 +278,7 @@ const gchar* gst_pad_get_name (GstPad *pad);
void gst_pad_set_parent (GstPad *pad, GstObject *parent); void gst_pad_set_parent (GstPad *pad, GstObject *parent);
GstObject* gst_pad_get_parent (GstPad *pad); GstObject* gst_pad_get_parent (GstPad *pad);
GstObject* gst_pad_get_real_parent (GstPad *pad);
void gst_pad_add_ghost_pad (GstPad *pad, GstPad *ghostpad); void gst_pad_add_ghost_pad (GstPad *pad, GstPad *ghostpad);
void gst_pad_remove_ghost_pad (GstPad *pad, GstPad *ghostpad); void gst_pad_remove_ghost_pad (GstPad *pad, GstPad *ghostpad);

View file

@ -24,10 +24,6 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstpipeline.h" #include "gstpipeline.h"
#include "gstthread.h"
#include "gstutils.h"
#include "gsttype.h"
#include "gstautoplug.h"
GstElementDetails gst_pipeline_details = { GstElementDetails gst_pipeline_details = {
@ -58,8 +54,6 @@ static GstElementStateReturn gst_pipeline_change_state (GstElement *element);
static void gst_pipeline_prepare (GstPipeline *pipeline); static void gst_pipeline_prepare (GstPipeline *pipeline);
static void gst_pipeline_have_type (GstElement *sink, GstElement *sink2, gpointer data);
static void gst_pipeline_pads_autoplug (GstElement *src, GstElement *sink);
static GstBinClass *parent_class = NULL; static GstBinClass *parent_class = NULL;
//static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 }; //static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 };
@ -101,9 +95,6 @@ gst_pipeline_init (GstPipeline *pipeline)
{ {
// we're a manager by default // we're a manager by default
GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER); GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER);
pipeline->src = NULL;
pipeline->sinks = NULL;
} }
@ -128,374 +119,6 @@ gst_pipeline_prepare (GstPipeline *pipeline)
GST_ELEMENT_NAME(GST_ELEMENT(pipeline))); GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
} }
static void
gst_pipeline_have_type (GstElement *sink, GstElement *sink2, gpointer data)
{
GST_DEBUG (0,"GstPipeline: pipeline have type %p\n", (gboolean *)data);
*(gboolean *)data = TRUE;
}
static GstCaps*
gst_pipeline_typefind (GstPipeline *pipeline, GstElement *element)
{
gboolean found = FALSE;
GstElement *typefind;
GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
GST_ELEMENT_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 (pipeline), GST_STATE_PLAYING);
// keep pushing buffers... the have_type signal handler will set the found flag
while (!found) {
gst_bin_iterate (GST_BIN (pipeline));
}
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
if (found) {
caps = gst_util_get_pointer_arg (GTK_OBJECT (typefind), "caps");
gst_pad_set_caps_list (gst_element_get_pad (element, "src"), g_list_prepend (NULL, caps));
}
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (GST_BIN (pipeline), typefind);
gst_object_unref (GST_OBJECT (typefind));
return caps;
}
static gboolean
gst_pipeline_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;
}
static void
gst_pipeline_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_pipeline_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_pipeline_pads_autoplug_func), sink);
}
}
/**
* gst_pipeline_add_src:
* @pipeline: the pipeline to add the src to
* @src: the src to add to the pipeline
*
* Adds a src element to the pipeline. This element
* will be used as a src for autoplugging. If you add more
* than one src element, the previously added element will
* be removed.
*/
void
gst_pipeline_add_src (GstPipeline *pipeline, GstElement *src)
{
g_return_if_fail (pipeline != NULL);
g_return_if_fail (GST_IS_PIPELINE (pipeline));
g_return_if_fail (src != NULL);
g_return_if_fail (GST_IS_ELEMENT (src));
if (pipeline->src) {
printf("gstpipeline: *WARNING* removing previously added element \"%s\"\n",
GST_ELEMENT_NAME(pipeline->src));
gst_bin_remove(GST_BIN(pipeline), pipeline->src);
}
pipeline->src = src;
gst_bin_add(GST_BIN(pipeline), src);
}
/**
* gst_pipeline_add_sink:
* @pipeline: the pipeline to add the sink to
* @sink: the sink to add to the pipeline
*
* Adds a sink element to the pipeline. This element
* will be used as a sink for autoplugging.
*/
void
gst_pipeline_add_sink (GstPipeline *pipeline, GstElement *sink)
{
g_return_if_fail (pipeline != NULL);
g_return_if_fail (GST_IS_PIPELINE (pipeline));
g_return_if_fail (sink != NULL);
g_return_if_fail (GST_IS_ELEMENT (sink));
pipeline->sinks = g_list_prepend (pipeline->sinks, sink);
//gst_bin_add(GST_BIN(pipeline), sink);
}
/**
* gst_pipeline_autoplug:
* @pipeline: the pipeline to autoplug
*
* Constructs a complete pipeline by automatically
* detecting the plugins needed.
*
* Returns: a gboolean indicating success or failure.
*/
gboolean
gst_pipeline_autoplug (GstPipeline *pipeline)
{
GList *elements;
GstElement *element, *srcelement = NULL, *sinkelement= NULL;
GList **factories;
GList **base_factories;
GstElementFactory *factory;
GstCaps *src_caps = 0;
guint i, numsinks;
gboolean use_thread = FALSE, have_common = FALSE;
GList *sinkstart;
g_return_val_if_fail(pipeline != NULL, FALSE);
g_return_val_if_fail(GST_IS_PIPELINE(pipeline), FALSE);
GST_DEBUG (0,"GstPipeline: autopluging pipeline \"%s\"\n",
GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
// fase 1, run typedetect on the source if needed...
if (!pipeline->src) {
GST_DEBUG (0,"GstPipeline: no source detected, can't autoplug pipeline \"%s\"\n",
GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
return FALSE;
}
GST_DEBUG (0,"GstPipeline: source \"%s\" has no MIME type, running typefind...\n",
GST_ELEMENT_NAME(pipeline->src));
src_caps = gst_pipeline_typefind(pipeline, pipeline->src);
if (src_caps) {
GST_DEBUG (0,"GstPipeline: source \"%s\" type found %d\n", GST_ELEMENT_NAME(pipeline->src),
src_caps->id);
}
else {
GST_DEBUG (0,"GstPipeline: source \"%s\" has no type\n", GST_ELEMENT_NAME(pipeline->src));
return FALSE;
}
srcelement = pipeline->src;
elements = pipeline->sinks;
sinkstart = g_list_copy (elements);
numsinks = g_list_length(elements);
factories = g_new0(GList *, numsinks);
base_factories = g_new0(GList *, numsinks);
i = 0;
// fase 2, loop over all the sinks..
while (elements) {
GstPad *pad;
element = GST_ELEMENT(elements->data);
pad = (GstPad *)gst_element_get_pad_list (element)->data;
base_factories[i] = factories[i] = gst_autoplug_caps_list (g_list_append(NULL,src_caps),
gst_pad_get_caps_list(pad));
// if we have a succesfull connection, proceed
if (factories[i] != NULL) {
i++;
}
else {
sinkstart = g_list_remove (sinkstart, element);
}
elements = g_list_next(elements);
}
while (factories[0]) {
// fase 3: add common elements
factory = (GstElementFactory *)(factories[0]->data);
// check to other paths for mathing elements (factories)
for (i=1; i<numsinks; i++) {
if (!factories[i] || (factory != (GstElementFactory *)(factories[i]->data))) {
goto differ;
}
factories[i] = g_list_next(factories[i]);
}
factory = (GstElementFactory *)(factories[0]->data);
GST_DEBUG (0,"common factory \"%s\"\n", factory->name);
element = gst_elementfactory_create(factory, factory->name);
gst_bin_add(GST_BIN(pipeline), element);
gst_pipeline_pads_autoplug(srcelement, element);
srcelement = element;
factories[0] = g_list_next(factories[0]);
have_common = TRUE;
}
differ:
// loop over all the sink elements
elements = sinkstart;
i = 0;
while (elements) {
GstElement *thesrcelement = srcelement;
GstElement *thebin = GST_ELEMENT(pipeline);
if (g_list_length(base_factories[i]) == 0) goto next;
sinkelement = (GstElement *)elements->data;
use_thread = have_common;
while (factories[i] || sinkelement) {
// fase 4: add other elements...
if (factories[i]) {
factory = (GstElementFactory *)(factories[i]->data);
GST_DEBUG (0,"factory \"%s\"\n", factory->name);
element = gst_elementfactory_create(factory, factory->name);
factories[i] = g_list_next(factories[i]);
}
// we have arived to the final sink element
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);
// 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_pipeline_pads_autoplug(thesrcelement, queue);
GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (element));
gst_bin_add(GST_BIN(thebin), element);
GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (thebin));
gst_bin_add(GST_BIN(pipeline), 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_pipeline_pads_autoplug(thesrcelement, element);
// this element is now the new source element
thesrcelement = element;
}
next:
elements = g_list_next(elements);
i++;
}
return TRUE;
GST_DEBUG (0,"GstPipeline: unable to autoplug pipeline \"%s\"\n",
GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
return FALSE;
}
static GstElementStateReturn static GstElementStateReturn
gst_pipeline_change_state (GstElement *element) gst_pipeline_change_state (GstElement *element)
{ {
@ -520,7 +143,6 @@ gst_pipeline_change_state (GstElement *element)
return GST_STATE_SUCCESS; return GST_STATE_SUCCESS;
} }
/** /**
* gst_pipeline_iterate: * gst_pipeline_iterate:
* @pipeline: #GstPipeline to iterate * @pipeline: #GstPipeline to iterate

View file

@ -50,9 +50,6 @@ typedef struct _GstPipelineClass GstPipelineClass;
struct _GstPipeline { struct _GstPipeline {
GstBin bin; GstBin bin;
GstElement *src; /* we only allow one src element */
GList *sinks; /* and multiple sinks */
}; };
struct _GstPipelineClass { struct _GstPipelineClass {
@ -63,11 +60,6 @@ GtkType gst_pipeline_get_type (void);
GstElement* gst_pipeline_new (guchar *name); GstElement* gst_pipeline_new (guchar *name);
#define gst_pipeline_destroy(pipeline) gst_object_destroy(GST_OBJECT(pipeline)) #define gst_pipeline_destroy(pipeline) gst_object_destroy(GST_OBJECT(pipeline))
void gst_pipeline_add_src (GstPipeline *pipeline, GstElement *src);
void gst_pipeline_add_sink (GstPipeline *pipeline, GstElement *sink);
gboolean gst_pipeline_autoplug (GstPipeline *pipeline);
void gst_pipeline_iterate (GstPipeline *pipeline); void gst_pipeline_iterate (GstPipeline *pipeline);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -82,6 +82,8 @@ _gst_plugin_initialize (void)
PLUGINS_SRCDIR "/gst/elements"); PLUGINS_SRCDIR "/gst/elements");
_gst_plugin_paths = g_list_prepend (_gst_plugin_paths, _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
PLUGINS_SRCDIR "/gst/types"); PLUGINS_SRCDIR "/gst/types");
_gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
PLUGINS_SRCDIR "/gst/autoplug");
#endif /* PLUGINS_USE_SRCDIR */ #endif /* PLUGINS_USE_SRCDIR */
doc = xmlParseFile (GST_CONFIG_DIR"/reg.xml"); doc = xmlParseFile (GST_CONFIG_DIR"/reg.xml");
@ -407,6 +409,8 @@ gst_plugin_new (const gchar *name)
plugin->numelements = 0; plugin->numelements = 0;
plugin->types = NULL; plugin->types = NULL;
plugin->numtypes = 0; plugin->numtypes = 0;
plugin->autopluggers = NULL;
plugin->numautopluggers = 0;
plugin->loaded = TRUE; plugin->loaded = TRUE;
return plugin; return plugin;
@ -541,15 +545,7 @@ gst_plugin_find (const gchar *name)
return NULL; return NULL;
} }
/** static GstElementFactory*
* gst_plugin_find_elementfactory:
* @name: name of elementfactory to find
*
* Find a registered elementfactory by name.
*
* Returns: @GstElementFactory if found, NULL if not
*/
GstElementFactory*
gst_plugin_find_elementfactory (const gchar *name) gst_plugin_find_elementfactory (const gchar *name)
{ {
GList *plugins, *factories; GList *plugins, *factories;
@ -621,6 +617,77 @@ gst_plugin_load_elementfactory (const gchar *name)
return factory; return factory;
} }
static GstAutoplugFactory*
gst_plugin_find_autoplugfactory (const gchar *name)
{
GList *plugins, *factories;
GstAutoplugFactory *factory;
g_return_val_if_fail(name != NULL, NULL);
plugins = _gst_plugins;
while (plugins) {
factories = ((GstPlugin *)(plugins->data))->autopluggers;
while (factories) {
factory = (GstAutoplugFactory*)(factories->data);
if (!strcmp(factory->name, name))
return (GstAutoplugFactory*)(factory);
factories = g_list_next(factories);
}
plugins = g_list_next(plugins);
}
return NULL;
}
/**
* gst_plugin_load_autoplugfactory:
* @name: name of autoplugfactory to load
*
* Load a registered autoplugfactory by name.
*
* Returns: @GstAutoplugFactory if loaded, NULL if not
*/
GstAutoplugFactory*
gst_plugin_load_autoplugfactory (const gchar *name)
{
GList *plugins, *factories;
GstAutoplugFactory *factory = NULL;
GstPlugin *plugin;
g_return_val_if_fail(name != NULL, NULL);
plugins = _gst_plugins;
while (plugins) {
plugin = (GstPlugin *)plugins->data;
factories = plugin->autopluggers;
while (factories) {
factory = (GstAutoplugFactory*)(factories->data);
if (!strcmp(factory->name,name)) {
if (!plugin->loaded) {
gchar *filename = g_strdup (plugin->filename);
gchar *pluginname = g_strdup (plugin->name);
GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded autoplugfactory %s from plugin %s",name,plugin->name);
gst_plugin_remove(plugin);
if (!gst_plugin_load_absolute(filename)) {
GST_DEBUG (0,"gstplugin: error loading autoplug factory %s from plugin %s\n", name, pluginname);
}
g_free (pluginname);
g_free (filename);
}
factory = gst_plugin_find_autoplugfactory(name);
return factory;
}
factories = g_list_next(factories);
}
plugins = g_list_next(plugins);
}
return factory;
}
/** /**
* gst_plugin_load_typefactory: * gst_plugin_load_typefactory:
* @mime: name of typefactory to load * @mime: name of typefactory to load
@ -708,6 +775,24 @@ gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory)
gst_type_register (factory); gst_type_register (factory);
} }
/**
* gst_plugin_add_type:
* @plugin: plugin to add type to
* @factory: the typefactory to add
*
* Add a typefactory to the list of those provided by the plugin.
*/
void
gst_plugin_add_autoplugger (GstPlugin *plugin, GstAutoplugFactory *factory)
{
g_return_if_fail (plugin != NULL);
g_return_if_fail (factory != NULL);
// g_print("adding factory to plugin\n");
plugin->autopluggers = g_list_prepend (plugin->autopluggers, factory);
plugin->numautopluggers++;
}
/** /**
* gst_plugin_get_list: * gst_plugin_get_list:
* *
@ -716,7 +801,7 @@ gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory)
* Returns; a GList of GstPlugin elements * Returns; a GList of GstPlugin elements
*/ */
GList* GList*
gst_plugin_get_list(void) gst_plugin_get_list (void)
{ {
return _gst_plugins; return _gst_plugins;
} }
@ -733,34 +818,45 @@ xmlNodePtr
gst_plugin_save_thyself (xmlNodePtr parent) gst_plugin_save_thyself (xmlNodePtr parent)
{ {
xmlNodePtr tree, subtree; xmlNodePtr tree, subtree;
GList *plugins = NULL, *elements = NULL, *types = NULL; GList *plugins = NULL, *elements = NULL, *types = NULL, *autopluggers = NULL;
plugins = gst_plugin_get_list(); plugins = gst_plugin_get_list ();
while (plugins) { while (plugins) {
GstPlugin *plugin = (GstPlugin *)plugins->data; GstPlugin *plugin = (GstPlugin *)plugins->data;
tree = xmlNewChild(parent,NULL,"plugin",NULL);
xmlNewChild(tree,NULL,"name",plugin->name); tree = xmlNewChild (parent, NULL, "plugin", NULL);
xmlNewChild(tree,NULL,"longname",plugin->longname); xmlNewChild (tree, NULL, "name", plugin->name);
xmlNewChild(tree,NULL,"filename",plugin->filename); xmlNewChild (tree, NULL, "longname", plugin->longname);
xmlNewChild (tree, NULL, "filename", plugin->filename);
types = plugin->types; types = plugin->types;
while (types) { while (types) {
GstTypeFactory *factory = (GstTypeFactory *)types->data; GstTypeFactory *factory = (GstTypeFactory *)types->data;
subtree = xmlNewChild(tree,NULL,"typefactory",NULL); subtree = xmlNewChild(tree, NULL, "typefactory", NULL);
gst_typefactory_save_thyself(factory, subtree); gst_typefactory_save_thyself (factory, subtree);
types = g_list_next(types); types = g_list_next (types);
} }
elements = plugin->elements; elements = plugin->elements;
while (elements) { while (elements) {
GstElementFactory *factory = (GstElementFactory *)elements->data; GstElementFactory *factory = (GstElementFactory *)elements->data;
subtree = xmlNewChild(tree,NULL,"elementfactory",NULL); subtree = xmlNewChild (tree, NULL, "elementfactory", NULL);
gst_elementfactory_save_thyself(factory, subtree); gst_elementfactory_save_thyself (factory, subtree);
elements = g_list_next(elements); elements = g_list_next (elements);
} }
plugins = g_list_next(plugins); autopluggers = plugin->autopluggers;
while (autopluggers) {
GstAutoplugFactory *factory = (GstAutoplugFactory *)autopluggers->data;
subtree = xmlNewChild (tree, NULL, "autoplugfactory", NULL);
gst_autoplugfactory_save_thyself (factory, subtree);
autopluggers = g_list_next (autopluggers);
}
plugins = g_list_next (plugins);
} }
return parent; return parent;
} }
@ -776,43 +872,50 @@ gst_plugin_load_thyself (xmlNodePtr parent)
{ {
xmlNodePtr kinderen; xmlNodePtr kinderen;
gint elementcount = 0; gint elementcount = 0;
gint autoplugcount = 0;
gint typecount = 0; gint typecount = 0;
gchar *pluginname; gchar *pluginname;
kinderen = parent->xmlChildrenNode; // Dutch invasion :-) kinderen = parent->xmlChildrenNode; // Dutch invasion :-)
while (kinderen) { while (kinderen) {
if (!strcmp(kinderen->name, "plugin")) { if (!strcmp (kinderen->name, "plugin")) {
xmlNodePtr field = kinderen->xmlChildrenNode; xmlNodePtr field = kinderen->xmlChildrenNode;
GstPlugin *plugin = g_new0 (GstPlugin, 1); GstPlugin *plugin = g_new0 (GstPlugin, 1);
plugin->elements = NULL; plugin->elements = NULL;
plugin->types = NULL; plugin->types = NULL;
plugin->loaded = FALSE; plugin->loaded = FALSE;
while (field) { while (field) {
if (!strcmp(field->name, "name")) { if (!strcmp (field->name, "name")) {
pluginname = xmlNodeGetContent(field); pluginname = xmlNodeGetContent (field);
if (gst_plugin_find(pluginname)) { if (gst_plugin_find (pluginname)) {
g_free(pluginname); g_free (pluginname);
g_free(plugin); g_free (plugin);
plugin = NULL; plugin = NULL;
break; break;
} else { } else {
plugin->name = pluginname; plugin->name = pluginname;
} }
} }
else if (!strcmp(field->name, "longname")) { else if (!strcmp (field->name, "longname")) {
plugin->longname = xmlNodeGetContent(field); plugin->longname = xmlNodeGetContent (field);
} }
else if (!strcmp(field->name, "filename")) { else if (!strcmp (field->name, "filename")) {
plugin->filename = xmlNodeGetContent(field); plugin->filename = xmlNodeGetContent (field);
} }
else if (!strcmp(field->name, "elementfactory")) { else if (!strcmp (field->name, "elementfactory")) {
GstElementFactory *factory = gst_elementfactory_load_thyself(field); GstElementFactory *factory = gst_elementfactory_load_thyself (field);
gst_plugin_add_factory (plugin, factory); gst_plugin_add_factory (plugin, factory);
elementcount++; elementcount++;
} }
else if (!strcmp(field->name, "typefactory")) { else if (!strcmp (field->name, "autoplugfactory")) {
GstTypeFactory *factory = gst_typefactory_load_thyself(field); GstAutoplugFactory *factory = gst_autoplugfactory_load_thyself (field);
gst_plugin_add_autoplugger (plugin, factory);
autoplugcount++;
}
else if (!strcmp (field->name, "typefactory")) {
GstTypeFactory *factory = gst_typefactory_load_thyself (field);
gst_plugin_add_type (plugin, factory); gst_plugin_add_type (plugin, factory);
elementcount++; elementcount++;
typecount++; typecount++;
@ -822,13 +925,14 @@ gst_plugin_load_thyself (xmlNodePtr parent)
} }
if (plugin) { if (plugin) {
_gst_plugins = g_list_prepend(_gst_plugins, plugin); _gst_plugins = g_list_prepend (_gst_plugins, plugin);
} }
} }
kinderen = kinderen->next; kinderen = kinderen->next;
} }
GST_INFO (GST_CAT_PLUGIN_LOADING,"added %d registered factories and %d types",elementcount,typecount); GST_INFO (GST_CAT_PLUGIN_LOADING, "added %d registered factories, %d autopluggers and %d types",
elementcount, autoplugcount, typecount);
} }
@ -863,3 +967,19 @@ gst_plugin_get_type_list (GstPlugin *plugin)
return plugin->types; return plugin->types;
} }
/**
* gst_plugin_get_autoplug_list:
* @plugin: the plugin to get the autoplugfactories from
*
* get a list of all the autoplugfactories that this plugin provides
*
* Returns: a GList of factories
*/
GList*
gst_plugin_get_autoplug_list (GstPlugin *plugin)
{
g_return_val_if_fail (plugin != NULL, NULL);
return plugin->autopluggers;
}

View file

@ -36,6 +36,7 @@
#include <gst/gsttype.h> #include <gst/gsttype.h>
#include <gst/gstelement.h> #include <gst/gstelement.h>
#include <gst/gstautoplug.h>
typedef struct _GstPlugin GstPlugin; typedef struct _GstPlugin GstPlugin;
@ -50,6 +51,8 @@ struct _GstPlugin {
gint numtypes; gint numtypes;
GList *elements; /* list of elements provided */ GList *elements; /* list of elements provided */
gint numelements; gint numelements;
GList *autopluggers; /* list of autopluggers provided */
gint numautopluggers;
gboolean loaded; /* if the plugin is in memory */ gboolean loaded; /* if the plugin is in memory */
}; };
@ -73,6 +76,7 @@ gboolean gst_plugin_is_loaded (GstPlugin *plugin);
GList* gst_plugin_get_type_list (GstPlugin *plugin); GList* gst_plugin_get_type_list (GstPlugin *plugin);
GList* gst_plugin_get_factory_list (GstPlugin *plugin); GList* gst_plugin_get_factory_list (GstPlugin *plugin);
GList* gst_plugin_get_autoplug_list (GstPlugin *plugin);
void gst_plugin_load_all (void); void gst_plugin_load_all (void);
gboolean gst_plugin_load (const gchar *name); gboolean gst_plugin_load (const gchar *name);
@ -81,14 +85,14 @@ gboolean gst_library_load (const gchar *name);
void gst_plugin_add_factory (GstPlugin *plugin, GstElementFactory *factory); void gst_plugin_add_factory (GstPlugin *plugin, GstElementFactory *factory);
void gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory); void gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory);
void gst_plugin_add_autoplugger (GstPlugin *plugin, GstAutoplugFactory *factory);
GstPlugin* gst_plugin_find (const gchar *name); GstPlugin* gst_plugin_find (const gchar *name);
GList* gst_plugin_get_list (void); GList* gst_plugin_get_list (void);
GstElementFactory* gst_plugin_find_elementfactory (const gchar *name);
GstElementFactory* gst_plugin_load_elementfactory (const gchar *name); GstElementFactory* gst_plugin_load_elementfactory (const gchar *name);
void gst_plugin_load_typefactory (const gchar *mime); void gst_plugin_load_typefactory (const gchar *mime);
GstAutoplugFactory* gst_plugin_load_autoplugfactory (const gchar *name);
xmlNodePtr gst_plugin_save_thyself (xmlNodePtr parent); xmlNodePtr gst_plugin_save_thyself (xmlNodePtr parent);
void gst_plugin_load_thyself (xmlNodePtr parent); void gst_plugin_load_thyself (xmlNodePtr parent);

View file

@ -601,6 +601,10 @@ gst_props_load_thyself_func (xmlNodePtr field)
sscanf (prop, "%08x", &entry->data.fourcc_data); sscanf (prop, "%08x", &entry->data.fourcc_data);
g_free (prop); g_free (prop);
} }
else {
g_free (entry);
entry = NULL;
}
return entry; return entry;
} }
@ -634,6 +638,7 @@ gst_props_load_thyself (xmlNodePtr parent)
while (subfield) { while (subfield) {
GstPropsEntry *subentry = gst_props_load_thyself_func (subfield); GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
if (subentry)
entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry); entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
subfield = subfield->next; subfield = subfield->next;

View file

@ -254,7 +254,7 @@ gst_thread_change_state (GstElement *element)
gst_thread_main_loop, thread); gst_thread_main_loop, thread);
// wait for it to 'spin up' // wait for it to 'spin up'
// gst_thread_wait_thread (thread); //gst_thread_wait_thread (thread);
} else { } else {
GST_INFO (GST_CAT_THREAD, "gstthread: NOT starting thread \"%s\"", GST_INFO (GST_CAT_THREAD, "gstthread: NOT starting thread \"%s\"",
GST_ELEMENT_NAME (GST_ELEMENT (element))); GST_ELEMENT_NAME (GST_ELEMENT (element)));

View file

@ -80,6 +80,7 @@ gst_type_register (GstTypeFactory *factory)
_gst_types = g_list_prepend (_gst_types, type); _gst_types = g_list_prepend (_gst_types, type);
id = type->id; id = type->id;
GST_DEBUG (0,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
} else { } else {
type = gst_type_find_by_id (id); type = gst_type_find_by_id (id);

View file

@ -64,7 +64,8 @@ static GstElementClass *parent_class = NULL;
static guint gst_typefind_signals[LAST_SIGNAL] = { 0 }; static guint gst_typefind_signals[LAST_SIGNAL] = { 0 };
GtkType GtkType
gst_typefind_get_type(void) { gst_typefind_get_type (void)
{
static GtkType typefind_type = 0; static GtkType typefind_type = 0;
if (!typefind_type) { if (!typefind_type) {
@ -78,7 +79,7 @@ gst_typefind_get_type(void) {
(GtkArgGetFunc)gst_typefind_get_arg, (GtkArgGetFunc)gst_typefind_get_arg,
(GtkClassInitFunc)NULL, (GtkClassInitFunc)NULL,
}; };
typefind_type = gtk_type_unique(GST_TYPE_ELEMENT,&typefind_info); typefind_type = gtk_type_unique (GST_TYPE_ELEMENT, &typefind_info);
} }
return typefind_type; return typefind_type;
} }

View file

@ -115,7 +115,6 @@ gst_play_class_init (GstPlayClass *klass)
static void static void
gst_play_init (GstPlay *play) gst_play_init (GstPlay *play)
{ {
GstPlayPrivate *priv = g_new0 (GstPlayPrivate, 1); GstPlayPrivate *priv = g_new0 (GstPlayPrivate, 1);
play->priv = priv; play->priv = priv;
@ -123,25 +122,20 @@ gst_play_init (GstPlay *play)
/* create a new bin to hold the elements */ /* create a new bin to hold the elements */
priv->thread = gst_thread_new ("main_thread"); priv->thread = gst_thread_new ("main_thread");
g_assert (priv->thread != NULL); g_assert (priv->thread != NULL);
priv->pipeline = gst_pipeline_new ("main_pipeline"); priv->bin = gst_bin_new ("main_bin");
g_assert (priv->pipeline != NULL); g_assert (priv->bin != NULL);
/* and an audio sink */ priv->audio_element = gst_elementfactory_make ("audiosink", "play_audio");
priv->audio_play = gst_elementfactory_make ("audiosink","play_audio"); g_return_if_fail (priv->audio_element != NULL);
g_return_if_fail (priv->audio_play != NULL); gtk_signal_connect (GTK_OBJECT (priv->audio_element), "handoff",
gtk_signal_connect (GTK_OBJECT (priv->audio_play), "handoff",
GTK_SIGNAL_FUNC (gst_play_audio_handoff), play); GTK_SIGNAL_FUNC (gst_play_audio_handoff), play);
/* and a video sink */ priv->video_element = gst_elementfactory_make ("videosink", "show");
priv->video_show = gst_elementfactory_make ("videosink","show"); g_return_if_fail (priv->video_element != NULL);
g_return_if_fail (priv->video_show != NULL); gtk_object_set (GTK_OBJECT (priv->video_element), "xv_enabled", FALSE, NULL);
gtk_object_set (GTK_OBJECT (priv->video_show),"xv_enabled",FALSE,NULL); gtk_signal_connect (GTK_OBJECT (priv->video_element), "frame_displayed",
gtk_signal_connect (GTK_OBJECT (priv->video_show), "frame_displayed",
GTK_SIGNAL_FUNC (gst_play_frame_displayed), play); GTK_SIGNAL_FUNC (gst_play_frame_displayed), play);
gst_pipeline_add_sink (GST_PIPELINE (priv->pipeline), priv->audio_play);
gst_pipeline_add_sink (GST_PIPELINE (priv->pipeline), priv->video_show);
play->state = GST_PLAY_STOPPED; play->state = GST_PLAY_STOPPED;
play->flags = 0; play->flags = 0;
@ -172,6 +166,14 @@ static void
gst_play_frame_displayed (GstElement *element, gst_play_frame_displayed (GstElement *element,
GstPlay *play) 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], gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_FRAME_DISPLAYED],
NULL); NULL);
} }
@ -185,14 +187,20 @@ gst_play_audio_handoff (GstElement *element,
} }
static void static void
gst_play_object_introspect (GstElement *element, gst_play_object_introspect (GstObject *object,
const gchar *property, const gchar *property,
GstElement **target) GstElement **target)
{ {
gchar *info; gchar *info;
GtkArgInfo *arg; GtkArgInfo *arg;
GstElement *element;
info = gtk_object_arg_get_info( GTK_OBJECT_TYPE(element), property, &arg); if (!GST_IS_ELEMENT (object))
return;
element = GST_ELEMENT (object);
info = gtk_object_arg_get_info (GTK_OBJECT_TYPE (element), property, &arg);
if (info) { if (info) {
g_free(info); g_free(info);
@ -208,8 +216,8 @@ gst_play_object_introspect (GstElement *element,
* this will change with glib 1.4 * this will change with glib 1.4
* */ * */
static void static void
gst_play_object_added (GstElement *pipeline, gst_play_object_added (GstAutoplug* autoplug,
GstElement *element, GstObject *object,
GstPlay *play) GstPlay *play)
{ {
GstPlayPrivate *priv; GstPlayPrivate *priv;
@ -218,31 +226,107 @@ gst_play_object_added (GstElement *pipeline,
priv = (GstPlayPrivate *)play->priv; priv = (GstPlayPrivate *)play->priv;
if (GST_FLAG_IS_SET (element, GST_ELEMENT_NO_SEEK)) { if (GST_FLAG_IS_SET (object, GST_ELEMENT_NO_SEEK)) {
priv->can_seek = FALSE; priv->can_seek = FALSE;
} }
if (GST_IS_BIN (element)) { if (GST_IS_BIN (object)) {
gtk_signal_connect (GTK_OBJECT (element), "object_added", gst_play_object_added, play); //gtk_signal_connect (GTK_OBJECT (object), "object_added", gst_play_object_added, play);
} }
else { else {
// first come first serve here... // first come first serve here...
if (!priv->offset_element) if (!priv->offset_element)
gst_play_object_introspect (element, "offset", &priv->offset_element); gst_play_object_introspect (object, "offset", &priv->offset_element);
if (!priv->bit_rate_element) if (!priv->bit_rate_element)
gst_play_object_introspect (element, "bit_rate", &priv->bit_rate_element); gst_play_object_introspect (object, "bit_rate", &priv->bit_rate_element);
if (!priv->media_time_element) if (!priv->media_time_element)
gst_play_object_introspect (element, "media_time", &priv->media_time_element); gst_play_object_introspect (object, "media_time", &priv->media_time_element);
if (!priv->current_time_element) if (!priv->current_time_element)
gst_play_object_introspect (element, "current_time", &priv->current_time_element); gst_play_object_introspect (object, "current_time", &priv->current_time_element);
} }
} }
static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
{
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
*(gboolean *)data = TRUE;
}
static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
gboolean found = FALSE;
GstElement *typefind;
GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
GST_ELEMENT_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_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag
gst_bin_iterate (bin);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
if (found) {
caps = gst_util_get_pointer_arg (GTK_OBJECT (typefind), "caps");
gst_pad_set_caps_list (gst_element_get_pad (element, "src"), g_list_prepend (NULL, caps));
}
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
gst_object_unref (GST_OBJECT (typefind));
return caps;
}
static gboolean
connect_pads (GstElement *new_element, GstElement *target, gboolean add)
{
GList *pads = gst_element_get_pad_list (new_element);
GstPad *targetpad = gst_element_get_pad (target, "sink");
while (pads) {
GstPad *pad = GST_PAD (pads->data);
if (gst_pad_check_compatibility (pad, targetpad)) {
if (add) {
gst_bin_add (GST_BIN (gst_element_get_parent (
GST_ELEMENT (gst_pad_get_real_parent (pad)))),
target);
}
gst_pad_connect (pad, targetpad);
return TRUE;
}
pads = g_list_next (pads);
}
return FALSE;
}
GstPlayReturn GstPlayReturn
gst_play_set_uri (GstPlay *play, gst_play_set_uri (GstPlay *play,
const guchar *uri) const guchar *uri)
{ {
GstPlayPrivate *priv; GstPlayPrivate *priv;
GstCaps *src_caps;
GstElement *new_element;
GstAutoplug *autoplug;
g_return_val_if_fail (play != NULL, GST_PLAY_ERROR); g_return_val_if_fail (play != NULL, GST_PLAY_ERROR);
g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR); g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR);
@ -250,39 +334,50 @@ gst_play_set_uri (GstPlay *play,
priv = (GstPlayPrivate *)play->priv; priv = (GstPlayPrivate *)play->priv;
if (priv->src) { if (priv->uri)
} g_free (priv->uri);
if (priv->uri) g_free (priv->uri);
priv->uri = g_strdup (uri); priv->uri = g_strdup (uri);
//priv->src = gst_elementfactory_make ("disksrc", "disk_src");
priv->src = gst_elementfactory_make ("disksrc", "disk_src"); priv->src = gst_elementfactory_make ("disksrc", "disk_src");
//priv->src = gst_elementfactory_make ("dvdsrc", "disk_src"); //priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
priv->offset_element = priv->src;
g_return_val_if_fail (priv->src != NULL, -1); g_return_val_if_fail (priv->src != NULL, -1);
gtk_object_set (GTK_OBJECT (priv->src),"location",uri,NULL); gtk_object_set (GTK_OBJECT (priv->src), "location", uri, NULL);
gtk_signal_connect (GTK_OBJECT (priv->src), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
gtk_signal_connect (GTK_OBJECT (priv->pipeline), "object_added", gst_play_object_added, play); gst_bin_add (GST_BIN (priv->bin), priv->src);
gst_pipeline_add_src (GST_PIPELINE (priv->pipeline),GST_ELEMENT (priv->src)); src_caps = gst_play_typefind (GST_BIN (priv->bin), priv->src);
if (!gst_pipeline_autoplug (GST_PIPELINE (priv->pipeline))) { if (!src_caps) {
return GST_PLAY_UNKNOWN_MEDIA; return GST_PLAY_UNKNOWN_MEDIA;
} }
if (GST_PAD_CONNECTED (gst_element_get_pad (priv->video_show, "sink"))) { autoplug = gst_autoplugfactory_make ("staticrender");
play->flags |= GST_PLAY_TYPE_VIDEO; g_assert (autoplug != NULL);
}
if (GST_PAD_CONNECTED (gst_element_get_pad (priv->audio_play, "sink"))) { gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
play->flags |= GST_PLAY_TYPE_AUDIO;
new_element = gst_autoplug_to_renderers (autoplug,
gst_pad_get_caps_list (gst_element_get_pad (priv->src, "src")),
priv->video_element,
priv->audio_element,
NULL);
if (!new_element) {
return GST_PLAY_CANNOT_PLAY;
} }
// hmmmm hack? FIXME gst_bin_remove (GST_BIN (priv->bin), priv->src);
GST_FLAG_UNSET (priv->pipeline, GST_BIN_FLAG_MANAGER); gst_bin_add (GST_BIN (priv->thread), priv->src);
gst_bin_add (GST_BIN (priv->thread), priv->pipeline); gst_bin_add (GST_BIN (priv->bin), new_element);
gst_element_connect (priv->src, "src", new_element, "sink");
gst_bin_add (GST_BIN (priv->thread), priv->bin);
gtk_signal_connect (GTK_OBJECT (priv->thread), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
return GST_PLAY_OK; return GST_PLAY_OK;
} }
@ -291,19 +386,21 @@ static void
gst_play_realize (GtkWidget *widget) gst_play_realize (GtkWidget *widget)
{ {
GstPlay *play; GstPlay *play;
GtkWidget *video_widget;
GstPlayPrivate *priv; GstPlayPrivate *priv;
g_return_if_fail (GST_IS_PLAY (widget)); g_return_if_fail (GST_IS_PLAY (widget));
g_print ("gst_play: realize\n");
play = GST_PLAY (widget); play = GST_PLAY (widget);
priv = (GstPlayPrivate *)play->priv; priv = (GstPlayPrivate *)play->priv;
video_widget = gst_util_get_widget_arg (GTK_OBJECT (priv->video_show),"widget"); priv->video_widget = gst_util_get_widget_arg (GTK_OBJECT (priv->video_element), "widget");
if (video_widget) { if (priv->video_widget) {
gtk_container_add (GTK_CONTAINER (widget), video_widget); gtk_container_add (GTK_CONTAINER (widget), priv->video_widget);
gtk_widget_show (video_widget); }
else {
g_print ("oops, no video widget found\n");
} }
if (GTK_WIDGET_CLASS (parent_class)->realize) { if (GTK_WIDGET_CLASS (parent_class)->realize) {
@ -397,7 +494,10 @@ gst_play_get_media_offset (GstPlay *play)
priv = (GstPlayPrivate *)play->priv; priv = (GstPlayPrivate *)play->priv;
if (priv->offset_element)
return gst_util_get_long_arg (GTK_OBJECT (priv->offset_element), "offset"); return gst_util_get_long_arg (GTK_OBJECT (priv->offset_element), "offset");
else
return 0;
} }
gulong gulong

View file

@ -31,6 +31,7 @@ typedef enum {
typedef enum { typedef enum {
GST_PLAY_OK, GST_PLAY_OK,
GST_PLAY_UNKNOWN_MEDIA, GST_PLAY_UNKNOWN_MEDIA,
GST_PLAY_CANNOT_PLAY,
GST_PLAY_ERROR, GST_PLAY_ERROR,
} GstPlayReturn; } GstPlayReturn;

View file

@ -12,9 +12,9 @@ typedef struct _GstPlayPrivate GstPlayPrivate;
struct _GstPlayPrivate { struct _GstPlayPrivate {
GstElement *thread; GstElement *thread;
GstElement *pipeline; GstElement *bin;
GstElement *audio_play; GstElement *video_element, *audio_element;
GstElement *video_show; GtkWidget *video_widget;
GstElement *src; GstElement *src;
guchar *uri; guchar *uri;

View file

@ -223,7 +223,7 @@ gst_disksrc_get (GstPad *pad)
/* deal with EOF state */ /* deal with EOF state */
if (src->curoffset >= src->size) { if (src->curoffset >= src->size) {
gst_element_signal_eos (GST_ELEMENT (src)); gst_pad_set_eos (pad);
return NULL; return NULL;
} }
@ -284,7 +284,7 @@ gst_disksrc_get_region (GstPad *pad, GstRegionType type,guint64 offset,guint64 l
/* deal with EOF state */ /* deal with EOF state */
if (offset >= src->size) { if (offset >= src->size) {
gst_element_signal_eos (GST_ELEMENT (src)); gst_pad_set_eos (pad);
return NULL; return NULL;
} }

View file

@ -62,7 +62,6 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
// set up thread state and kick things off // set up thread state and kick things off
gtk_object_set(GTK_OBJECT(audio_thread),"create_thread",TRUE,NULL); gtk_object_set(GTK_OBJECT(audio_thread),"create_thread",TRUE,NULL);
g_print("setting to READY state\n"); g_print("setting to READY state\n");
gst_element_set_state(GST_ELEMENT(audio_thread),GST_STATE_READY);
} else if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) { } else if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
//} else if (0) { //} else if (0) {
@ -116,7 +115,6 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
// set up thread state and kick things off // set up thread state and kick things off
gtk_object_set(GTK_OBJECT(video_thread),"create_thread",TRUE,NULL); gtk_object_set(GTK_OBJECT(video_thread),"create_thread",TRUE,NULL);
g_print("setting to READY state\n"); g_print("setting to READY state\n");
gst_element_set_state(GST_ELEMENT(video_thread),GST_STATE_READY);
} }
g_print("\n"); g_print("\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING); gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);

4
tests/.gitignore vendored
View file

@ -6,7 +6,7 @@ Makefile.in
.deps .deps
.libs .libs
*.xml *.xml
*.gst
init init
loadall loadall
simplefake simplefake
@ -24,3 +24,5 @@ markup
load load
padfactory padfactory
tee tee
autoplug2
autoplug3

View file

@ -1,7 +1,7 @@
SUBDIRS = sched eos SUBDIRS = sched eos
noinst_PROGRAMS = init loadall simplefake states caps queue registry \ noinst_PROGRAMS = init loadall simplefake states caps queue registry \
paranoia rip mp3encode autoplug props case4 markup load tee paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3
# we have nothing but apps here, we can do this safely # we have nothing but apps here, we can do this safely
LIBS += $(GST_LIBS) LIBS += $(GST_LIBS)

View file

@ -1,63 +1,45 @@
#include <gst/gst.h> #include <gst/gst.h>
static GList*
autoplug_caps (gchar *mime1, gchar *mime2)
{
GstCaps *caps1, *caps2;
caps1 = gst_caps_new ("tescaps1", mime1);
caps2 = gst_caps_new ("tescaps2", mime2);
return gst_autoplug_caps (caps1, caps2);
}
static void static void
dump_factories (GList *factories) new_object_added (GstAutoplug *autoplug, GstObject *object)
{ {
g_print ("dumping factories\n"); g_print ("added new object \"%s\"\n", gst_object_get_name (object));
while (factories) {
GstElementFactory *factory = (GstElementFactory *)factories->data;
g_print ("factory: \"%s\"\n", factory->name);
factories = g_list_next (factories);
}
} }
int main(int argc,char *argv[]) int
main (int argc, char *argv[])
{ {
GList *factories; GstElement *element;
GstElement *videosink, *audiosink;
GstAutoplug *autoplugger;
GList *testcaps;
gst_init(&argc,&argv); gst_init(&argc,&argv);
factories = autoplug_caps ("audio/mp3", "audio/raw"); audiosink = gst_elementfactory_make ("audiosink", "audiosink");
dump_factories (factories); g_assert (audiosink != NULL);
videosink = gst_elementfactory_make ("videosink", "videosink");
g_assert (videosink != NULL);
factories = autoplug_caps ("video/mpeg", "audio/raw"); testcaps = g_list_append (NULL,
dump_factories (factories); gst_caps_new_with_props ("test_caps",
factories = gst_autoplug_caps (
gst_caps_new_with_props(
"testcaps3",
"video/mpeg", "video/mpeg",
gst_props_new ( gst_props_new (
"mpegversion", GST_PROPS_INT (1), "mpegversion", GST_PROPS_INT (1),
"systemstream", GST_PROPS_BOOLEAN (TRUE), "systemstream", GST_PROPS_BOOLEAN (TRUE),
NULL)), NULL)));
gst_caps_new("testcaps4","audio/raw"));
dump_factories (factories);
factories = gst_autoplug_caps ( autoplugger = gst_autoplugfactory_make ("static");
gst_caps_new_with_props(
"testcaps5", gtk_signal_connect (GTK_OBJECT (autoplugger), "new_object", new_object_added, NULL);
"video/mpeg",
gst_props_new ( element = gst_autoplug_to_caps (autoplugger, testcaps,
"mpegversion", GST_PROPS_INT (1), gst_pad_get_caps_list (gst_element_get_pad (audiosink, "sink")),
"systemstream", GST_PROPS_BOOLEAN (FALSE), gst_pad_get_caps_list (gst_element_get_pad (videosink, "sink")),
NULL)), NULL);
gst_caps_new("testcaps6", "video/raw")); g_assert (element != NULL);
dump_factories (factories);
xmlDocDump (stdout, gst_xml_write (element));
exit (0); exit (0);
} }

78
tests/autoplug2.c Normal file
View file

@ -0,0 +1,78 @@
#include <gst/gst.h>
static GstElement*
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_to_caps (autoplug, caps1, caps2, NULL);
}
int
main (int argc, char *argv[])
{
GstElement *element;
GstAutoplug *autoplug;
gst_init(&argc,&argv);
autoplug = gst_autoplugfactory_make ("static");
element = autoplug_caps (autoplug, "audio/mp3", "audio/raw");
xmlSaveFile ("autoplug2_1.gst", gst_xml_write (element));
element = autoplug_caps (autoplug, "video/mpeg", "audio/raw");
xmlSaveFile ("autoplug2_2.gst", gst_xml_write (element));
element = gst_autoplug_to_caps (autoplug,
g_list_append (NULL, gst_caps_new_with_props(
"testcaps3",
"video/mpeg",
gst_props_new (
"mpegversion", GST_PROPS_INT (1),
"systemstream", GST_PROPS_BOOLEAN (TRUE),
NULL))),
g_list_append (NULL, gst_caps_new("testcaps4","audio/raw")),
NULL);
xmlSaveFile ("autoplug2_3.gst", gst_xml_write (element));
element = gst_autoplug_to_caps (autoplug,
g_list_append (NULL, gst_caps_new_with_props(
"testcaps5",
"video/mpeg",
gst_props_new (
"mpegversion", GST_PROPS_INT (1),
"systemstream", GST_PROPS_BOOLEAN (FALSE),
NULL))),
g_list_append (NULL, gst_caps_new("testcaps6", "video/raw")),
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);
}

102
tests/autoplug3.c Normal file
View file

@ -0,0 +1,102 @@
#include <gst/gst.h>
int
main (int argc, char *argv[])
{
GstElement *element;
GstElement *sink1, *sink2;
GstAutoplug *autoplug;
GstAutoplug *autoplug2;
gst_init(&argc,&argv);
sink1 = gst_elementfactory_make ("videosink", "videosink");
sink2 = gst_elementfactory_make ("audiosink", "audiosink");
autoplug = gst_autoplugfactory_make ("staticrender");
autoplug2 = gst_autoplugfactory_make ("static");
element = gst_autoplug_to_renderers (autoplug,
g_list_append (NULL, gst_caps_new ("mp3caps", "audio/mp3")), sink2, NULL);
xmlSaveFile ("autoplug3_1.gst", gst_xml_write (element));
element = gst_autoplug_to_renderers (autoplug,
g_list_append (NULL, gst_caps_new ("mpeg1caps", "video/mpeg")), sink1, NULL);
if (element) {
xmlSaveFile ("autoplug3_2.gst", gst_xml_write (element));
}
element = gst_autoplug_to_caps (autoplug2,
g_list_append (NULL, gst_caps_new_with_props(
"testcaps3",
"video/mpeg",
gst_props_new (
"mpegversion", GST_PROPS_INT (1),
"systemstream", GST_PROPS_BOOLEAN (TRUE),
NULL))),
g_list_append (NULL, gst_caps_new("testcaps4","audio/raw")),
NULL);
if (element) {
xmlSaveFile ("autoplug3_3.gst", gst_xml_write (element));
}
element = gst_autoplug_to_caps (autoplug2,
g_list_append (NULL, gst_caps_new_with_props(
"testcaps5",
"video/mpeg",
gst_props_new (
"mpegversion", GST_PROPS_INT (1),
"systemstream", GST_PROPS_BOOLEAN (FALSE),
NULL))),
g_list_append (NULL, gst_caps_new("testcaps6", "video/raw")),
NULL);
if (element) {
xmlSaveFile ("autoplug3_4.gst", gst_xml_write (element));
}
element = gst_autoplug_to_caps (autoplug2,
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);
if (element) {
xmlSaveFile ("autoplug3_5.gst", gst_xml_write (element));
}
element = gst_autoplug_to_caps (autoplug2,
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);
if (element) {
xmlSaveFile ("autoplug3_6.gst", gst_xml_write (element));
}
sink1 = gst_elementfactory_make ("videosink", "videosink");
sink2 = gst_elementfactory_make ("audiosink", "audiosink");
element = gst_autoplug_to_renderers (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))),
sink1,
sink2,
NULL);
if (element) {
xmlSaveFile ("autoplug3_7.gst", gst_xml_write (element));
}
exit (0);
}

View file

@ -31,8 +31,6 @@ int main(int argc,char *argv[])
exit(-1); exit(-1);
} }
/* create a new bin to hold the elements */ /* create a new bin to hold the elements */
pipeline = gst_pipeline_new("pipeline"); pipeline = gst_pipeline_new("pipeline");
g_assert(pipeline != NULL); g_assert(pipeline != NULL);
@ -59,6 +57,7 @@ int main(int argc,char *argv[])
gtk_widget_show_all(appwindow); gtk_widget_show_all(appwindow);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), videosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), videosink);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink);
@ -67,6 +66,7 @@ int main(int argc,char *argv[])
g_print("unable to handle stream\n"); g_print("unable to handle stream\n");
exit(-1); exit(-1);
} }
*/
xmlSaveFile("xmlTest.gst", gst_xml_write(GST_ELEMENT(pipeline))); xmlSaveFile("xmlTest.gst", gst_xml_write(GST_ELEMENT(pipeline)));

View file

@ -41,6 +41,7 @@ int main(int argc,char *argv[])
g_assert(audiosink != NULL); g_assert(audiosink != NULL);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink);
@ -48,6 +49,7 @@ int main(int argc,char *argv[])
g_print("unable to handle stream\n"); g_print("unable to handle stream\n");
exit(-1); exit(-1);
} }
*/
// hmmmm hack? FIXME // hmmmm hack? FIXME
GST_FLAG_UNSET (pipeline, GST_BIN_FLAG_MANAGER); GST_FLAG_UNSET (pipeline, GST_BIN_FLAG_MANAGER);

View file

@ -46,6 +46,7 @@ int main(int argc,char *argv[])
g_assert(audiosink != NULL); g_assert(audiosink != NULL);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), queue); gst_pipeline_add_sink(GST_PIPELINE(pipeline), queue);
@ -58,6 +59,7 @@ int main(int argc,char *argv[])
g_print("cannot autoplug pipeline\n"); g_print("cannot autoplug pipeline\n");
exit(-1); exit(-1);
} }
*/
gst_bin_add(GST_BIN(pipeline), thread); gst_bin_add(GST_BIN(pipeline), thread);

View file

@ -45,6 +45,7 @@ int main(int argc,char *argv[])
g_assert(audiosink != NULL); g_assert(audiosink != NULL);
/* add objects to the main pipeline */ /* add objects to the main pipeline */
/*
gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc); gst_pipeline_add_src(GST_PIPELINE(pipeline), disksrc);
gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink); gst_pipeline_add_sink(GST_PIPELINE(pipeline), audiosink);
@ -52,6 +53,7 @@ int main(int argc,char *argv[])
g_print("unable to handle stream\n"); g_print("unable to handle stream\n");
exit(-1); exit(-1);
} }
*/
//gst_bin_remove(GST_BIN(pipeline), disksrc); //gst_bin_remove(GST_BIN(pipeline), disksrc);

View file

@ -42,7 +42,7 @@ void print_prop(GstPropsEntry *prop,gboolean showname,gchar *pfx) {
g_free(longprefix); g_free(longprefix);
break; break;
default: default:
printf("\n"); printf("unknown props %d\n", prop->propstype);
} }
} }
@ -59,30 +59,9 @@ void print_props(GstProps *properties,gchar *pfx) {
} }
} }
/* gint
struct _GstPropsEntry { print_element_info (GstElementFactory *factory)
GQuark propid; {
GstPropsId propstype;
union {
// flat values
gboolean bool_data;
guint32 fourcc_data;
gint int_data;
// structured values
struct {
GList *entries;
} list_data;
struct {
gint min;
gint max;
} int_range_data;
} data;
};
*/
gint print_element_info(GstElementFactory *factory) {
GstElement *element; GstElement *element;
GstObjectClass *gstobject_class; GstObjectClass *gstobject_class;
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
@ -322,11 +301,9 @@ void print_element_list() {
} }
} }
void
void print_plugin_info(GstPlugin *plugin) { print_plugin_info (GstPlugin *plugin)
GList *factories; {
GstElementFactory *factory;
printf("Plugin Details:\n"); printf("Plugin Details:\n");
printf(" Name:\t\t%s\n",plugin->name); printf(" Name:\t\t%s\n",plugin->name);
printf(" Long Name:\t%s\n",plugin->longname); printf(" Long Name:\t%s\n",plugin->longname);
@ -334,6 +311,9 @@ void print_plugin_info(GstPlugin *plugin) {
printf("\n"); printf("\n");
if (plugin->numelements) { if (plugin->numelements) {
GList *factories;
GstElementFactory *factory;
printf("Element Factories:\n"); printf("Element Factories:\n");
factories = gst_plugin_get_factory_list(plugin); factories = gst_plugin_get_factory_list(plugin);
@ -344,6 +324,36 @@ void print_plugin_info(GstPlugin *plugin) {
printf(" %s: %s\n",factory->name,factory->details->longname); printf(" %s: %s\n",factory->name,factory->details->longname);
} }
} }
if (plugin->numautopluggers) {
GList *factories;
GstAutoplugFactory *factory;
printf("Autpluggers:\n");
factories = gst_plugin_get_autoplug_list(plugin);
while (factories) {
factory = (GstAutoplugFactory*)(factories->data);
factories = g_list_next(factories);
printf(" %s: %s\n", factory->name, factory->longdesc);
}
}
if (plugin->numtypes) {
GList *factories;
GstTypeFactory *factory;
printf("Types:\n");
factories = gst_plugin_get_type_list(plugin);
while (factories) {
factory = (GstTypeFactory*)(factories->data);
factories = g_list_next(factories);
printf(" %s: %s\n", factory->mime, factory->exts);
if (factory->typefindfunc)
printf(" Has typefind function: %s\n",GST_DEBUG_FUNCPTR_NAME(factory->typefindfunc));
}
}
printf("\n"); printf("\n");
} }