mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 02:01:12 +00:00
Merged the AUTOPLUG2 branch
Original commit message from CVS: Merged the AUTOPLUG2 branch
This commit is contained in:
parent
031e0a3acb
commit
55006f6367
57 changed files with 2837 additions and 1247 deletions
|
@ -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
|
||||||
|
|
|
@ -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:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 ##### -->
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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
149
docs/random/hierarchy
Normal 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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
|
@ -155,14 +155,14 @@ struct _GstEditorElement {
|
||||||
struct _GstEditorElementClass {
|
struct _GstEditorElementClass {
|
||||||
GnomeCanvasGroupClass parent_class;
|
GnomeCanvasGroupClass parent_class;
|
||||||
|
|
||||||
void (*name_changed) (GstEditorElement *element);
|
void (*name_changed) (GstEditorElement *element);
|
||||||
void (*position_changed) (GstEditorElement *element);
|
void (*position_changed) (GstEditorElement *element);
|
||||||
void (*size_changed) (GstEditorElement *element);
|
void (*size_changed) (GstEditorElement *element);
|
||||||
void (*realize) (GstEditorElement *element);
|
void (*realize) (GstEditorElement *element);
|
||||||
gint (*event) (GnomeCanvasItem *item,GdkEvent *event,
|
gint (*event) (GnomeCanvasItem *item,GdkEvent *event,
|
||||||
GstEditorElement *element);
|
GstEditorElement *element);
|
||||||
gint (*button_event) (GnomeCanvasItem *item,GdkEvent *event,
|
gint (*button_event) (GnomeCanvasItem *item,GdkEvent *event,
|
||||||
GstEditorElement *element);
|
GstEditorElement *element);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,11 +213,11 @@ struct _GstEditorBinClass {
|
||||||
GtkType gst_editor_bin_get_type();
|
GtkType gst_editor_bin_get_type();
|
||||||
|
|
||||||
GstEditorBin* gst_editor_bin_new (GstBin *bin, const gchar *first_arg_name,...);
|
GstEditorBin* gst_editor_bin_new (GstBin *bin, const gchar *first_arg_name,...);
|
||||||
void gst_editor_bin_add (GstEditorBin *bin, GstEditorElement *element);
|
void gst_editor_bin_add (GstEditorBin *bin, GstEditorElement *element);
|
||||||
|
|
||||||
void gst_editor_bin_connection_drag (GstEditorBin *bin,
|
void gst_editor_bin_connection_drag (GstEditorBin *bin,
|
||||||
gdouble wx,gdouble wy);
|
gdouble wx,gdouble wy);
|
||||||
void gst_editor_bin_start_banding (GstEditorBin *bin,GstEditorPad *pad);
|
void gst_editor_bin_start_banding (GstEditorBin *bin,GstEditorPad *pad);
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_EDITOR_CANVAS \
|
#define GST_TYPE_EDITOR_CANVAS \
|
||||||
|
@ -246,8 +246,8 @@ struct _GstEditorCanvasClass {
|
||||||
GstEditorCanvas* gst_editor_canvas_new (void);
|
GstEditorCanvas* gst_editor_canvas_new (void);
|
||||||
GstEditorCanvas* gst_editor_canvas_new_with_bin (GstEditorBin *bin);
|
GstEditorCanvas* gst_editor_canvas_new_with_bin (GstEditorBin *bin);
|
||||||
|
|
||||||
void gst_editor_canvas_set_bin (GstEditorCanvas *canvas,
|
void gst_editor_canvas_set_bin (GstEditorCanvas *canvas,
|
||||||
GstEditorBin *element);
|
GstEditorBin *element);
|
||||||
GstEditorElement* gst_editor_canvas_get_bin (GstEditorCanvas *canvas);
|
GstEditorElement* gst_editor_canvas_get_bin (GstEditorCanvas *canvas);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
12
gst/autoplug/Makefile.am
Normal 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)
|
619
gst/autoplug/gststaticautoplug.c
Normal file
619
gst/autoplug/gststaticautoplug.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
64
gst/autoplug/gststaticautoplug.h
Normal file
64
gst/autoplug/gststaticautoplug.h
Normal 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__ */
|
||||||
|
|
650
gst/autoplug/gststaticautoplugrender.c
Normal file
650
gst/autoplug/gststaticautoplugrender.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
64
gst/autoplug/gststaticautoplugrender.h
Normal file
64
gst/autoplug/gststaticautoplugrender.h
Normal 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__ */
|
||||||
|
|
|
@ -56,16 +56,16 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void gst_disksrc_class_init (GstDiskSrcClass *klass);
|
static void gst_disksrc_class_init (GstDiskSrcClass *klass);
|
||||||
static void gst_disksrc_init (GstDiskSrc *disksrc);
|
static void gst_disksrc_init (GstDiskSrc *disksrc);
|
||||||
|
|
||||||
static void gst_disksrc_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
static void gst_disksrc_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||||
static void gst_disksrc_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
static void gst_disksrc_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||||
|
|
||||||
static GstBuffer * gst_disksrc_get (GstPad *pad);
|
static GstBuffer * gst_disksrc_get (GstPad *pad);
|
||||||
static GstBuffer * gst_disksrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);
|
static GstBuffer * gst_disksrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);
|
||||||
|
|
||||||
static GstElementStateReturn gst_disksrc_change_state (GstElement *element);
|
static GstElementStateReturn gst_disksrc_change_state (GstElement *element);
|
||||||
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ static struct _elements_entry _elements[] = {
|
||||||
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
||||||
|
|
||||||
#if HAVE_LIBGHTTP
|
#if HAVE_LIBGHTTP
|
||||||
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL },
|
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL },
|
||||||
#endif /* HAVE_LIBGHTTP */
|
#endif /* HAVE_LIBGHTTP */
|
||||||
|
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
|
|
|
@ -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) {
|
GstAutoplug*
|
||||||
if (rgnNodes[i].iNode == factory) return i;
|
gst_autoplugfactory_create (GstAutoplugFactory *factory)
|
||||||
i++;
|
{
|
||||||
|
GstAutoplug *new = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (factory != NULL, NULL);
|
||||||
|
|
||||||
|
if (factory->type == 0){
|
||||||
|
factory = gst_plugin_load_autoplugfactory (factory->name);
|
||||||
}
|
}
|
||||||
return 0;
|
g_return_val_if_fail (factory != NULL, NULL);
|
||||||
|
g_return_val_if_fail (factory->type != 0, NULL);
|
||||||
|
|
||||||
|
new = GST_AUTOPLUG (gtk_type_new (factory->type));
|
||||||
|
|
||||||
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GList*
|
GstAutoplug*
|
||||||
construct_path (gst_autoplug_node *rgnNodes, gpointer factory)
|
gst_autoplugfactory_make (const gchar *name)
|
||||||
{
|
{
|
||||||
GstElementFactory *current;
|
GstAutoplugFactory *factory;
|
||||||
GList *factories = NULL;
|
|
||||||
|
|
||||||
current = rgnNodes[find_factory(rgnNodes, factory)].iPrev;
|
g_return_val_if_fail (name != NULL, NULL);
|
||||||
|
|
||||||
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"factories found in autoplugging (reversed order)");
|
factory = gst_autoplugfactory_find (name);
|
||||||
|
|
||||||
while (current != NULL)
|
if (factory == NULL)
|
||||||
{
|
return NULL;
|
||||||
gpointer next = NULL;
|
|
||||||
|
|
||||||
next = rgnNodes[find_factory(rgnNodes, current)].iPrev;
|
return gst_autoplugfactory_create (factory);;
|
||||||
if (next) {
|
}
|
||||||
factories = g_list_prepend (factories, current);
|
|
||||||
GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT,"factory: \"%s\"", current->name);
|
xmlNodePtr
|
||||||
|
gst_autoplugfactory_save_thyself (GstAutoplugFactory *factory, xmlNodePtr parent)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(factory != NULL, NULL);
|
||||||
|
|
||||||
|
xmlNewChild(parent,NULL,"name",factory->name);
|
||||||
|
xmlNewChild(parent,NULL,"longdesc", factory->longdesc);
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstAutoplugFactory*
|
||||||
|
gst_autoplugfactory_load_thyself (xmlNodePtr parent)
|
||||||
|
{
|
||||||
|
GstAutoplugFactory *factory = g_new0(GstAutoplugFactory, 1);
|
||||||
|
xmlNodePtr children = parent->xmlChildrenNode;
|
||||||
|
|
||||||
|
while (children) {
|
||||||
|
if (!strcmp(children->name, "name")) {
|
||||||
|
factory->name = xmlNodeGetContent(children);
|
||||||
}
|
}
|
||||||
current = next;
|
if (!strcmp(children->name, "longdesc")) {
|
||||||
}
|
factory->longdesc = xmlNodeGetContent(children);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
children = children->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return construct_path (rgnNodes, sink);
|
_gst_autoplugfactories = g_list_prepend (_gst_autoplugfactories, factory);
|
||||||
|
|
||||||
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
GtkType gst_autoplug_get_type (void);
|
typedef struct _GstAutoplugFactory GstAutoplugFactory;
|
||||||
|
|
||||||
GList* gst_autoplug_caps (GstCaps *srccaps, GstCaps *sinkcaps);
|
struct _GstAutoplugFactory {
|
||||||
GList* gst_autoplug_caps_list (GList *srccaps, GList *sinkcaps);
|
gchar *name; /* name of autoplugger */
|
||||||
GList* gst_autoplug_pads (GstPad *srcpad, GstPad *sinkpad);
|
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);
|
||||||
|
|
||||||
|
void gst_autoplug_signal_new_object (GstAutoplug *autoplug, GstObject *object);
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
15
gst/gstbin.c
15
gst/gstbin.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -52,7 +52,7 @@ struct _GstCaps {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* initialize the subsystem */
|
/* initialize the subsystem */
|
||||||
void _gst_caps_initialize (void);
|
void _gst_caps_initialize (void);
|
||||||
|
|
||||||
GstCaps* gst_caps_new (const gchar *name, const gchar *mime);
|
GstCaps* gst_caps_new (const gchar *name, const gchar *mime);
|
||||||
GstCaps* gst_caps_new_with_props (const gchar *name, const gchar *mime, GstProps *props);
|
GstCaps* gst_caps_new_with_props (const gchar *name, const gchar *mime, GstProps *props);
|
||||||
|
@ -60,21 +60,21 @@ GstCaps* gst_caps_register (GstCapsFactory *factory);
|
||||||
GstCaps* gst_caps_register_count (GstCapsFactory *factory, guint *counter);
|
GstCaps* gst_caps_register_count (GstCapsFactory *factory, guint *counter);
|
||||||
|
|
||||||
const gchar* gst_caps_get_name (GstCaps *caps);
|
const gchar* gst_caps_get_name (GstCaps *caps);
|
||||||
void gst_caps_set_name (GstCaps *caps, const gchar *name);
|
void gst_caps_set_name (GstCaps *caps, const gchar *name);
|
||||||
|
|
||||||
const gchar* gst_caps_get_mime (GstCaps *caps);
|
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);
|
||||||
|
|
||||||
gboolean gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps);
|
gboolean gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps);
|
||||||
gboolean gst_caps_list_check_compatibility (GList *fromcaps, GList *tocaps);
|
gboolean gst_caps_list_check_compatibility (GList *fromcaps, GList *tocaps);
|
||||||
|
|
||||||
xmlNodePtr gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent);
|
xmlNodePtr gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent);
|
||||||
GstCaps* gst_caps_load_thyself (xmlNodePtr parent);
|
GstCaps* gst_caps_load_thyself (xmlNodePtr parent);
|
||||||
|
|
||||||
#endif /* __GST_CAPS_H__ */
|
#endif /* __GST_CAPS_H__ */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
120
gst/gstpad.c
120
gst/gstpad.c
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 = {
|
||||||
|
@ -51,15 +47,13 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void gst_pipeline_class_init (GstPipelineClass *klass);
|
static void gst_pipeline_class_init (GstPipelineClass *klass);
|
||||||
static void gst_pipeline_init (GstPipeline *pipeline);
|
static void gst_pipeline_init (GstPipeline *pipeline);
|
||||||
|
|
||||||
static GstElementStateReturn gst_pipeline_change_state (GstElement *element);
|
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
|
||||||
|
|
|
@ -50,25 +50,17 @@ 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 {
|
||||||
GstBinClass parent_class;
|
GstBinClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
GtkType gst_pipeline_get_type (void);
|
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_iterate (GstPipeline *pipeline);
|
||||||
void gst_pipeline_add_sink (GstPipeline *pipeline, GstElement *sink);
|
|
||||||
|
|
||||||
gboolean gst_pipeline_autoplug (GstPipeline *pipeline);
|
|
||||||
|
|
||||||
void gst_pipeline_iterate (GstPipeline *pipeline);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
198
gst/gstplugin.c
198
gst/gstplugin.c
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -36,10 +36,11 @@
|
||||||
|
|
||||||
#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;
|
||||||
typedef struct _GstPluginElement GstPluginElement;
|
typedef struct _GstPluginElement GstPluginElement;
|
||||||
|
|
||||||
struct _GstPlugin {
|
struct _GstPlugin {
|
||||||
gchar *name; /* name of the plugin */
|
gchar *name; /* name of the plugin */
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
@ -57,40 +60,41 @@ struct _GstPlugin {
|
||||||
|
|
||||||
typedef GstPlugin* (*GstPluginInitFunc) (GModule *module);
|
typedef GstPlugin* (*GstPluginInitFunc) (GModule *module);
|
||||||
|
|
||||||
void _gst_plugin_initialize (void);
|
void _gst_plugin_initialize (void);
|
||||||
|
|
||||||
GstPlugin* gst_plugin_new (const gchar *name);
|
GstPlugin* gst_plugin_new (const gchar *name);
|
||||||
|
|
||||||
void gst_plugin_add_path (const gchar *path);
|
void gst_plugin_add_path (const gchar *path);
|
||||||
|
|
||||||
const gchar* gst_plugin_get_name (GstPlugin *plugin);
|
const gchar* gst_plugin_get_name (GstPlugin *plugin);
|
||||||
void gst_plugin_set_name (GstPlugin *plugin, const gchar *name);
|
void gst_plugin_set_name (GstPlugin *plugin, const gchar *name);
|
||||||
const gchar* gst_plugin_get_longname (GstPlugin *plugin);
|
const gchar* gst_plugin_get_longname (GstPlugin *plugin);
|
||||||
void gst_plugin_set_longname (GstPlugin *plugin, const gchar *longname);
|
void gst_plugin_set_longname (GstPlugin *plugin, const gchar *longname);
|
||||||
|
|
||||||
const gchar* gst_plugin_get_filename (GstPlugin *plugin);
|
const gchar* gst_plugin_get_filename (GstPlugin *plugin);
|
||||||
gboolean gst_plugin_is_loaded (GstPlugin *plugin);
|
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);
|
||||||
gboolean gst_plugin_load_absolute (const gchar *name);
|
gboolean gst_plugin_load_absolute (const gchar *name);
|
||||||
gboolean gst_library_load (const gchar *name);
|
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);
|
||||||
|
|
||||||
#endif /* __GST_PLUGIN_H__ */
|
#endif /* __GST_PLUGIN_H__ */
|
||||||
|
|
|
@ -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,7 +638,8 @@ 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);
|
||||||
|
|
||||||
entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
|
if (subentry)
|
||||||
|
entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
|
||||||
|
|
||||||
subfield = subfield->next;
|
subfield = subfield->next;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -43,7 +43,7 @@ struct _GstTypeFindInfo {
|
||||||
GstPlugin *plugin; /* the plugin with this typefind function */
|
GstPlugin *plugin; /* the plugin with this typefind function */
|
||||||
};
|
};
|
||||||
|
|
||||||
static GstCaps* gst_type_typefind_dummy (GstBuffer *buffer, gpointer priv);
|
static GstCaps* gst_type_typefind_dummy (GstBuffer *buffer, gpointer priv);
|
||||||
|
|
||||||
void
|
void
|
||||||
_gst_type_initialize (void)
|
_gst_type_initialize (void)
|
||||||
|
@ -74,12 +74,13 @@ gst_type_register (GstTypeFactory *factory)
|
||||||
if (!id) {
|
if (!id) {
|
||||||
type = g_new0 (GstType, 1);
|
type = g_new0 (GstType, 1);
|
||||||
|
|
||||||
type->id = _gst_maxtype++;
|
type->id = _gst_maxtype++;
|
||||||
type->mime = factory->mime;
|
type->mime = factory->mime;
|
||||||
type->exts = factory->exts;
|
type->exts = factory->exts;
|
||||||
_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);
|
||||||
|
|
|
@ -52,14 +52,14 @@ struct _GstTypeFactory {
|
||||||
|
|
||||||
|
|
||||||
/* initialize the subsystem */
|
/* initialize the subsystem */
|
||||||
void _gst_type_initialize (void);
|
void _gst_type_initialize (void);
|
||||||
|
|
||||||
/* create a new type, or find/merge an existing one */
|
/* create a new type, or find/merge an existing one */
|
||||||
guint16 gst_type_register (GstTypeFactory *factory);
|
guint16 gst_type_register (GstTypeFactory *factory);
|
||||||
|
|
||||||
/* look up a type by mime or extension */
|
/* look up a type by mime or extension */
|
||||||
guint16 gst_type_find_by_mime (const gchar *mime);
|
guint16 gst_type_find_by_mime (const gchar *mime);
|
||||||
guint16 gst_type_find_by_ext (const gchar *ext);
|
guint16 gst_type_find_by_ext (const gchar *ext);
|
||||||
|
|
||||||
/* get GstType by id */
|
/* get GstType by id */
|
||||||
GstType* gst_type_find_by_id (guint16 id);
|
GstType* gst_type_find_by_id (guint16 id);
|
||||||
|
@ -67,7 +67,7 @@ GstType* gst_type_find_by_id (guint16 id);
|
||||||
/* get the list of registered types (returns list of GstType!) */
|
/* get the list of registered types (returns list of GstType!) */
|
||||||
GList* gst_type_get_list (void);
|
GList* gst_type_get_list (void);
|
||||||
|
|
||||||
xmlNodePtr gst_typefactory_save_thyself (GstTypeFactory *factory, xmlNodePtr parent);
|
xmlNodePtr gst_typefactory_save_thyself (GstTypeFactory *factory, xmlNodePtr parent);
|
||||||
GstTypeFactory* gst_typefactory_load_thyself (xmlNodePtr parent);
|
GstTypeFactory* gst_typefactory_load_thyself (xmlNodePtr parent);
|
||||||
|
|
||||||
#endif /* __GST_TYPE_H__ */
|
#endif /* __GST_TYPE_H__ */
|
||||||
|
|
|
@ -52,19 +52,20 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void gst_typefind_class_init (GstTypeFindClass *klass);
|
static void gst_typefind_class_init (GstTypeFindClass *klass);
|
||||||
static void gst_typefind_init (GstTypeFind *typefind);
|
static void gst_typefind_init (GstTypeFind *typefind);
|
||||||
|
|
||||||
static void gst_typefind_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
static void gst_typefind_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||||
static void gst_typefind_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
static void gst_typefind_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||||
|
|
||||||
static void gst_typefind_chain (GstPad *pad, GstBuffer *buf);
|
static void gst_typefind_chain (GstPad *pad, GstBuffer *buf);
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
return gst_util_get_long_arg (GTK_OBJECT (priv->offset_element), "offset");
|
if (priv->offset_element)
|
||||||
|
return gst_util_get_long_arg (GTK_OBJECT (priv->offset_element), "offset");
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gulong
|
gulong
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -56,16 +56,16 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void gst_disksrc_class_init (GstDiskSrcClass *klass);
|
static void gst_disksrc_class_init (GstDiskSrcClass *klass);
|
||||||
static void gst_disksrc_init (GstDiskSrc *disksrc);
|
static void gst_disksrc_init (GstDiskSrc *disksrc);
|
||||||
|
|
||||||
static void gst_disksrc_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
static void gst_disksrc_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||||
static void gst_disksrc_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
static void gst_disksrc_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||||
|
|
||||||
static GstBuffer * gst_disksrc_get (GstPad *pad);
|
static GstBuffer * gst_disksrc_get (GstPad *pad);
|
||||||
static GstBuffer * gst_disksrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);
|
static GstBuffer * gst_disksrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);
|
||||||
|
|
||||||
static GstElementStateReturn gst_disksrc_change_state (GstElement *element);
|
static GstElementStateReturn gst_disksrc_change_state (GstElement *element);
|
||||||
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ static struct _elements_entry _elements[] = {
|
||||||
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
||||||
|
|
||||||
#if HAVE_LIBGHTTP
|
#if HAVE_LIBGHTTP
|
||||||
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL },
|
{ "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL },
|
||||||
#endif /* HAVE_LIBGHTTP */
|
#endif /* HAVE_LIBGHTTP */
|
||||||
|
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
|
|
|
@ -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
4
tests/.gitignore
vendored
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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",
|
||||||
|
"video/mpeg",
|
||||||
|
gst_props_new (
|
||||||
|
"mpegversion", GST_PROPS_INT (1),
|
||||||
|
"systemstream", GST_PROPS_BOOLEAN (TRUE),
|
||||||
|
NULL)));
|
||||||
|
|
||||||
factories = gst_autoplug_caps (
|
autoplugger = gst_autoplugfactory_make ("static");
|
||||||
gst_caps_new_with_props(
|
|
||||||
"testcaps3",
|
|
||||||
"video/mpeg",
|
|
||||||
gst_props_new (
|
|
||||||
"mpegversion", GST_PROPS_INT (1),
|
|
||||||
"systemstream", GST_PROPS_BOOLEAN (TRUE),
|
|
||||||
NULL)),
|
|
||||||
gst_caps_new("testcaps4","audio/raw"));
|
|
||||||
dump_factories (factories);
|
|
||||||
|
|
||||||
factories = gst_autoplug_caps (
|
gtk_signal_connect (GTK_OBJECT (autoplugger), "new_object", new_object_added, NULL);
|
||||||
gst_caps_new_with_props(
|
|
||||||
"testcaps5",
|
element = gst_autoplug_to_caps (autoplugger, testcaps,
|
||||||
"video/mpeg",
|
gst_pad_get_caps_list (gst_element_get_pad (audiosink, "sink")),
|
||||||
gst_props_new (
|
gst_pad_get_caps_list (gst_element_get_pad (videosink, "sink")),
|
||||||
"mpegversion", GST_PROPS_INT (1),
|
NULL);
|
||||||
"systemstream", GST_PROPS_BOOLEAN (FALSE),
|
g_assert (element != NULL);
|
||||||
NULL)),
|
|
||||||
gst_caps_new("testcaps6", "video/raw"));
|
xmlDocDump (stdout, gst_xml_write (element));
|
||||||
dump_factories (factories);
|
|
||||||
|
|
||||||
exit (0);
|
exit (0);
|
||||||
}
|
}
|
||||||
|
|
78
tests/autoplug2.c
Normal file
78
tests/autoplug2.c
Normal 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
102
tests/autoplug3.c
Normal 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);
|
||||||
|
}
|
|
@ -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)));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue