From 70cfc6cb4db1ce5b0a9e1f4c7939cb9eb198358d Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Sun, 7 Apr 2002 23:32:16 +0000 Subject: [PATCH] new parser that uses flex and bison Original commit message from CVS: * new parser that uses flex and bison - doesn't do dynamic pipelines yet... * added GErrors to the gst_parse_launch[v] api * added --gst-mask-help command line option * fixed -o option for gst-launch * GstElement api change: - gst_element_get_pad - gst_element_get_request_pad, gst_element_get_static_pad - gst_element_get_compatible_pad - gst_element_get_compatible_static_pad, gst_element_get_compatible_request_pad - gst_element_[dis]connect -> gst_element_[dis]connect_pads - gst_element_[dis]connect_elements -> gst_element_[dis]connect * manual update * example, tool, and doc updates for the api changes - no more plugin docs in the core docs, plugins require a more extensive doc system --- docs/gst/gstreamer-sections.txt | 250 +----- docs/gst/gstreamer.types.in | 21 - docs/gst/tmpl/gstaggregator.sgml | 20 - docs/gst/tmpl/gstbin.sgml | 1 - docs/gst/tmpl/gstdisksink.sgml | 17 - docs/gst/tmpl/gstelement.sgml | 143 +-- docs/gst/tmpl/gstfakesink.sgml | 33 - docs/gst/tmpl/gstfakesrc.sgml | 83 -- docs/gst/tmpl/gstfdsink.sgml | 5 - docs/gst/tmpl/gstfdsrc.sgml | 15 - docs/gst/tmpl/gstfilesrc.sgml | 35 - docs/gst/tmpl/gstidentity.sgml | 48 - docs/gst/tmpl/gstparse.sgml | 9 +- docs/gst/tmpl/gstpipefilter.sgml | 5 - docs/gst/tmpl/gstqueue.sgml | 21 - docs/gst/tmpl/gstreamer-unused.sgml | 867 +++++++++++++++++++ docs/gst/tmpl/gststatistics.sgml | 52 -- docs/gst/tmpl/gsttee.sgml | 15 - docs/gst/tmpl/gsttypefind.sgml | 13 - docs/manual/advanced-autoplugging.xml | 100 +-- docs/manual/advanced-threads.xml | 55 +- docs/manual/appendix-checklist.xml | 15 +- docs/manual/appendix-debugging.xml | 15 +- docs/manual/appendix-programs.xml | 111 ++- docs/manual/autoplugging.xml | 52 +- docs/manual/basics-bins.xml | 109 ++- docs/manual/basics-data.xml | 2 +- docs/manual/basics-elements.xml | 91 +- docs/manual/basics-helloworld.xml | 50 +- docs/manual/basics-pads.xml | 73 +- docs/manual/basics-plugins.xml | 5 + docs/manual/bins.xml | 109 ++- docs/manual/buffers.xml | 2 +- docs/manual/components.xml | 5 + docs/manual/connections.xml | 34 +- docs/manual/cothreads.xml | 38 +- docs/manual/debugging.xml | 15 +- docs/manual/dynamic.xml | 100 +-- docs/manual/elements.xml | 91 +- docs/manual/factories.xml | 100 +-- docs/manual/goals.xml | 46 +- docs/manual/gstreamer-manual.xml | 36 +- docs/manual/helloworld.xml | 50 +- docs/manual/helloworld2.xml | 8 +- docs/manual/highlevel-components.xml | 5 + docs/manual/init.xml | 24 + docs/manual/intro-motivation.xml | 2 +- docs/manual/intro-preface.xml | 4 +- docs/manual/intro.xml | 4 +- docs/manual/motivation.xml | 2 +- docs/manual/pads.xml | 73 +- docs/manual/plugins.xml | 5 + docs/manual/programs.xml | 111 ++- docs/manual/states.xml | 2 +- docs/manual/threads.xml | 55 +- docs/manual/utility.xml | 90 -- examples/autoplug/autoplug.c | 29 +- examples/helloworld/helloworld.c | 4 +- examples/helloworld2/helloworld2.c | 16 +- examples/launch/mp3parselaunch.c | 9 +- examples/mixer/mixer.c | 12 +- examples/xml/createxml.c | 2 +- examples/xml/runxml.c | 2 +- gst/Makefile.am | 5 +- gst/autoplug/autoplugtest.c | 25 +- gst/autoplug/gstspider.c | 2 +- gst/autoplug/spidertest.c | 6 +- gst/gst.c | 57 +- gst/gstelement.c | 293 ++++--- gst/gstelement.h | 35 +- gst/gstparse.c | 813 +++++++---------- gst/gstparse.h | 32 +- gst/parse/Makefile.am | 11 +- gst/parse/grammar.y | 148 ++-- gst/parse/parse.l | 97 ++- gst/parse/types.h | 37 +- tests/muxing/case1.c | 19 +- tests/old/examples/autoplug/autoplug.c | 29 +- tests/old/examples/helloworld/helloworld.c | 4 +- tests/old/examples/helloworld2/helloworld2.c | 16 +- tests/old/examples/launch/mp3parselaunch.c | 9 +- tests/old/examples/mixer/mixer.c | 12 +- tests/old/examples/xml/createxml.c | 2 +- tests/old/examples/xml/runxml.c | 2 +- tests/sched/dynamic-pipeline.c | 6 +- tools/gst-launch.c | 40 +- 86 files changed, 2621 insertions(+), 2495 deletions(-) delete mode 100644 docs/manual/utility.xml diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 6617353579..f81b57e7b9 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -93,15 +93,6 @@ GST_DEBUG_ENABLED GST_DEBUG_ENABLE_CATEGORIES -
-gstextratypes -GstExtraTypes -GST_TYPE_FILENAME - -gst_extra_get_filename_type -GST_DISABLE_LOADSAVE_REGISTRY -
-
gstscheduler GstScheduler @@ -202,7 +193,7 @@ gst_bin_details
gstparse GstParse -GstParseErrors +GstParseError gst_parse_launch gst_parse_launchv
@@ -360,22 +351,25 @@ gst_element_get_managing_bin gst_element_add_pad gst_element_remove_pad gst_element_get_pad +gst_element_get_static_pad +gst_element_get_request_pad gst_element_get_pad_list gst_element_get_padtemplate_list gst_element_get_padtemplate_by_name gst_element_add_ghost_pad gst_element_remove_ghost_pad -gst_element_request_compatible_pad -gst_element_request_pad_by_name gst_element_get_compatible_pad +gst_element_get_compatible_static_pad +gst_element_get_compatible_request_pad gst_element_get_compatible_pad_filtered gst_element_connect +gst_element_connect_many gst_element_connect_filtered -gst_element_connect_elements -gst_element_connect_elements_filtered -gst_element_connect_elements_many +gst_element_connect_pads +gst_element_connect_pads_filtered gst_element_disconnect -gst_element_disconnect_elements +gst_element_disconnect_many +gst_element_disconnect_pads gst_element_set_state gst_element_get_state gst_element_wait_state_change @@ -499,22 +493,6 @@ GST_IS_CLOCK GST_IS_CLOCK_CLASS
-
-gstsystemclock -GstSystemClock -GstSystemClock -gst_system_clock_obtain - -gst_system_clock_get_type -GstSystemClockClass -GST_TYPE_SYSTEM_CLOCK -GST_SYSTEM_CLOCK -GST_SYSTEM_CLOCK_CLASS -GST_IS_SYSTEM_CLOCK -GST_IS_SYSTEM_CLOCK_CLASS -
- -
gstlog @@ -1096,211 +1074,3 @@ gst_static_autoplug_render_get_type GST_STATIC_AUTOPLUG_RENDER_CLASS GST_IS_STATIC_AUTOPLUG_RENDER_CLASS
- -
-gstaggregator -GstAggregator -GstAggregatorSchedType - -gst_aggregator_details -GstAggregator -gst_aggregator_factory_init -GST_AGGREGATOR -GST_IS_AGGREGATOR -GST_TYPE_AGGREGATOR -gst_aggregator_get_type -GST_AGGREGATOR_CLASS -GST_IS_AGGREGATOR_CLASS -
- -
-gstfilesrc -GstFileSrc - -GstFileSrcFlags -GstFileSrc -GstFileSrcClass -gst_filesrc_get_type -GST_TYPE_FILESRC -GST_FILESRC -GST_FILESRC_CLASS -GST_IS_FILESRC -GST_IS_FILESRC_CLASS -
- -
-gstfakesink -GstFakeSink - -GstFakeSink -GstFakeSinkClass -gst_fakesink_get_type -GST_TYPE_FAKESINK -GST_FAKESINK -GST_FAKESINK_CLASS -GST_IS_FAKESINK -GST_IS_FAKESINK_CLASS -gst_fakesink_factory_init -
- -
-gstfakesrc -GstFakeSrc - -GstFakeSrc -GstFakeSrcOutputType -gst_fakesrc_get_type -GstFakeSrcClass -GST_TYPE_FAKESRC -GST_FAKESRC -GST_FAKESRC_CLASS -GST_IS_FAKESRC -GST_IS_FAKESRC_CLASS -GstFakeSrcDataType -GstFakeSrcFillType -GstFakeSrcSizeType -gst_fakesrc_factory_init -
- -
-gstfdsink -GstFdSink - -GstFdSink -GstFdSinkClass -gst_fdsink_get_type -GST_TYPE_FDSINK -GST_FDSINK -GST_FDSINK_CLASS -GST_IS_FDSINK -GST_IS_FDSINK_CLASS -
- -
-gstfdsrc -GstFdSrc - -GstFdSrc -GstFdSrcClass -gst_fdsrc_get_type -GST_TYPE_FDSRC -GST_FDSRC -GST_FDSRC_CLASS -GST_IS_FDSRC -GST_IS_FDSRC_CLASS -
- -
-gstidentity -GstIdentity - -GstIdentity -GstIdentityClass -gst_identity_get_type -GST_TYPE_IDENTITY -GST_IDENTITY -GST_IDENTITY_CLASS -GST_IS_IDENTITY -GST_IS_IDENTITY_CLASS -
- -
-gstqueue -GstQueue - -GstQueue -GstQueueClass -gst_queue_get_type -GST_TYPE_QUEUE -GST_QUEUE -GST_QUEUE_CLASS -GST_IS_QUEUE -GST_IS_QUEUE_CLASS -
- -
-gstpipefilter -GstPipefilter - -GST_TYPE_PIPEFILTER -GST_PIPEFILTER -GST_PIPEFILTER_CLASS -GST_IS_PIPEFILTER -GST_IS_PIPEFILTER_CLASS -GstPipeFilterFlags -GstPipefilter -GstPipefilterClass -gst_pipefilter_get_type -
- -
-gststatistics -GstStatistics - -GstStatistics -GstStatisticsClass -stats -GST_STATISTICS -GST_IS_STATISTICS -GST_TYPE_STATISTICS -gst_statistics_get_type -GST_STATISTICS_CLASS -GST_IS_STATISTICS_CLASS -
- - -
-gsttypefind -GstTypeFind - -GstTypeFind -GstTypeFindClass -gst_typefind_get_type -GST_TYPE_TYPEFIND -GST_TYPEFIND -GST_TYPEFIND_CLASS -GST_IS_TYPEFIND -GST_IS_TYPEFIND_CLASS -
- -
-gstdisksink -GstDiskSink - -GstDiskSink -GstDiskSinkFlags -GST_DISKSINK -GST_IS_DISKSINK -GST_TYPE_DISKSINK -gst_disksink_get_type -GST_DISKSINK_CLASS -GST_IS_DISKSINK_CLASS -
- -
-gstmultidisksrc -GstMultiDiskSrc -GstMultiDiskSrcFlags - -GstMultiDiskSrc -GST_MULTIDISKSRC -GST_IS_MULTIDISKSRC -GST_TYPE_MULTIDISKSRC -gst_multidisksrc_get_type -GST_MULTIDISKSRC_CLASS -GST_IS_MULTIDISKSRC_CLASS -
- -
-gstmd5sink -GstMD5Sink - -GST_MD5SINK -GST_IS_MD5SINK -GST_TYPE_MD5SINK -gst_md5sink_get_type -GST_MD5SINK_CLASS -GST_IS_MD5SINK_CLASS -gst_md5sink_factory_init -
- diff --git a/docs/gst/gstreamer.types.in b/docs/gst/gstreamer.types.in index 52709f2b85..5890f3327a 100644 --- a/docs/gst/gstreamer.types.in +++ b/docs/gst/gstreamer.types.in @@ -10,7 +10,6 @@ gst_pad_get_type gst_padtemplate_get_type gst_ghost_pad_get_type gst_thread_get_type -gst_tee_get_type gst_plugin_feature_get_type gst_autoplug_get_type gst_autoplugfactory_get_type @@ -18,25 +17,5 @@ gst_typefactory_get_type gst_elementfactory_get_type gst_schedulerfactory_get_type gst_scheduler_get_type -gst_system_clock_get_type gst_timecache_get_type gst_xml_get_type - -gst_aggregator_get_type -gst_fakesrc_get_type -gst_fakesink_get_type - -gst_filesrc_get_type -gst_fdsrc_get_type - -gst_fdsink_get_type -gst_disksink_get_type - -gst_pipefilter_get_type -gst_identity_get_type -gst_queue_get_type - -gst_statistics_get_type -gst_md5sink_get_type -gst_typefind_get_type - diff --git a/docs/gst/tmpl/gstaggregator.sgml b/docs/gst/tmpl/gstaggregator.sgml index afcfb6f16c..46ca5a9276 100644 --- a/docs/gst/tmpl/gstaggregator.sgml +++ b/docs/gst/tmpl/gstaggregator.sgml @@ -25,23 +25,3 @@ methods to request buffers from its pads. @AGGREGATOR_LOOP_SELECT: @AGGREGATOR_CHAIN: - - - - - - - - - - - - - - - - - - - - diff --git a/docs/gst/tmpl/gstbin.sgml b/docs/gst/tmpl/gstbin.sgml index f4ba3dc10c..6ac0bbffe8 100644 --- a/docs/gst/tmpl/gstbin.sgml +++ b/docs/gst/tmpl/gstbin.sgml @@ -54,7 +54,6 @@ Flags for a bin. @GST_BIN_SELF_SCHEDULABLE: @GST_BIN_FLAG_PREFER_COTHREADS: @GST_BIN_FLAG_FIXED_CLOCK: -@GST_BIN_SELF_ITERATING: @GST_BIN_FLAG_LAST: diff --git a/docs/gst/tmpl/gstdisksink.sgml b/docs/gst/tmpl/gstdisksink.sgml index efa98148b1..419b53577b 100644 --- a/docs/gst/tmpl/gstdisksink.sgml +++ b/docs/gst/tmpl/gstdisksink.sgml @@ -14,20 +14,3 @@ The disksink write to a file. The filename can be given as an argument. #GstFdSink - - -Is emited after the buffer has been written to the disk. - - -@gstdisksink: the object which received the signal. - - - -The filename to write to. - - - - - - - diff --git a/docs/gst/tmpl/gstelement.sgml b/docs/gst/tmpl/gstelement.sgml index 9d9f381c1f..c24dd75a70 100644 --- a/docs/gst/tmpl/gstelement.sgml +++ b/docs/gst/tmpl/gstelement.sgml @@ -376,6 +376,26 @@ instead. @Returns: GList of pads + + + + + +@element: +@name: +@Returns: + + + + + + + +@element: +@name: +@Returns: + + @@ -424,7 +444,17 @@ instead. @pad: - + + + + + +@element: +@pad: +@Returns: + + + @@ -434,23 +464,13 @@ instead. @Returns: - + @element: -@name: -@Returns: - - - - - - - -@element: -@pad: +@templ: @Returns: @@ -471,47 +491,14 @@ instead. @src: +@dest: +@Returns: + @srcpadname: -@dest: @destpadname: -@Returns: - - - - - -@src: -@srcpadname: -@dest: -@destpadname: -@filtercaps: -@Returns: - - - - - - - -@src: -@dest: -@Returns: - - - - - - - -@src: -@dest: -@filtercaps: -@Returns: - - - + @@ -522,7 +509,21 @@ instead. @Returns: - + + + + + +@src: +@dest: +@filtercaps: +@Returns: + +@srcpadname: +@destpadname: + + + @@ -531,15 +532,53 @@ instead. @srcpadname: @dest: @destpadname: +@Returns: - + + + + + +@src: +@srcpadname: +@dest: +@destpadname: +@filtercaps: +@Returns: + + + @src: @dest: + +@srcpadname: +@destpadname: + + + + + + + +@element_1: +@element_2: +@Varargs: + + + + + + + +@src: +@srcpadname: +@dest: +@destpadname: diff --git a/docs/gst/tmpl/gstfakesink.sgml b/docs/gst/tmpl/gstfakesink.sgml index a8b33e89be..361a67d1a7 100644 --- a/docs/gst/tmpl/gstfakesink.sgml +++ b/docs/gst/tmpl/gstfakesink.sgml @@ -16,36 +16,3 @@ with the buffer. (fakesink) - - -This signal is emmitted when a buffer is handled. - - -@gstfakesink: the object which received the signal. -@arg1: The buffer that is received. - - - -The number of sink pads. - - - - -Indicates the plugin should not emit messages. - - - - -Dump the contents of the buffer - - - - -Sync on the clock - - - - -The last message this plugin emmited. - - diff --git a/docs/gst/tmpl/gstfakesrc.sgml b/docs/gst/tmpl/gstfakesrc.sgml index 58611a1aa1..dfc2d57101 100644 --- a/docs/gst/tmpl/gstfakesrc.sgml +++ b/docs/gst/tmpl/gstfakesrc.sgml @@ -14,86 +14,3 @@ The GstFakeSrc generates empty buffers. (fakesrc) - - - - - -@gstfakesrc: the object which received the signal. -@arg1: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/gst/tmpl/gstfdsink.sgml b/docs/gst/tmpl/gstfdsink.sgml index a9f7327643..ec3e297b20 100644 --- a/docs/gst/tmpl/gstfdsink.sgml +++ b/docs/gst/tmpl/gstfdsink.sgml @@ -14,8 +14,3 @@ Write data to a file descriptor. - - -The filedescriptor to write to. - - diff --git a/docs/gst/tmpl/gstfdsrc.sgml b/docs/gst/tmpl/gstfdsrc.sgml index 882a451986..dd2c183b71 100644 --- a/docs/gst/tmpl/gstfdsrc.sgml +++ b/docs/gst/tmpl/gstfdsrc.sgml @@ -14,18 +14,3 @@ Read buffers from a file descriptor. - - -The filedescriptor to read from. Pass the argument as a char* (???) - - - - -The number of bytes per read. - - - - -Get the current offset in the file. - - diff --git a/docs/gst/tmpl/gstfilesrc.sgml b/docs/gst/tmpl/gstfilesrc.sgml index e86a3463f7..67715c209d 100644 --- a/docs/gst/tmpl/gstfilesrc.sgml +++ b/docs/gst/tmpl/gstfilesrc.sgml @@ -15,38 +15,3 @@ and subbuffers. - - -The offset in the file that is currently being read. - - - - -The filename - - - - -The filesize. - - - - -The file descriptor. - - - - -The size of the buffers to pass to the peer element. - - - - -The size of the mmapped area. - - - - -Indicates the mmapped area should be touched to bring it into memory. - - diff --git a/docs/gst/tmpl/gstidentity.sgml b/docs/gst/tmpl/gstidentity.sgml index a4ef012ece..e5a1a65bde 100644 --- a/docs/gst/tmpl/gstidentity.sgml +++ b/docs/gst/tmpl/gstidentity.sgml @@ -14,51 +14,3 @@ Pass data without modification. - - - - - -@gstidentity: the object which received the signal. -@arg1: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/gst/tmpl/gstparse.sgml b/docs/gst/tmpl/gstparse.sgml index b97b55c8ea..5346cc252c 100644 --- a/docs/gst/tmpl/gstparse.sgml +++ b/docs/gst/tmpl/gstparse.sgml @@ -44,15 +44,14 @@ can be made with . - + @GST_PARSE_ERROR_SYNTAX: -@GST_PARSE_ERROR_CREATING_ELEMENT: -@GST_PARSE_ERROR_NOSUCH_ELEMENT: -@GST_PARSE_ERROR_INTERNAL: +@GST_PARSE_ERROR_NO_SUCH_ELEMENT: +@GST_PARSE_ERROR_NO_SUCH_PROPERTY: @GST_PARSE_ERROR_CONNECT: @@ -61,6 +60,7 @@ can be made with . @pipeline_description: +@error: @Returns: @cmdline: @@ -73,6 +73,7 @@ can be made with . @argv: +@error: @Returns: diff --git a/docs/gst/tmpl/gstpipefilter.sgml b/docs/gst/tmpl/gstpipefilter.sgml index 55f1469e74..968c3132aa 100644 --- a/docs/gst/tmpl/gstpipefilter.sgml +++ b/docs/gst/tmpl/gstpipefilter.sgml @@ -15,8 +15,3 @@ buffers from its output. - - -Sets the command to be executed. - - diff --git a/docs/gst/tmpl/gstqueue.sgml b/docs/gst/tmpl/gstqueue.sgml index a8e74dd245..af326b0b02 100644 --- a/docs/gst/tmpl/gstqueue.sgml +++ b/docs/gst/tmpl/gstqueue.sgml @@ -25,24 +25,3 @@ The queue blocks by default. - - - - - - - -Get the number of buffers in the queue. - - - - -Specify the maximum number of buffers in the queue before the queue -blocks. - - - - - - - diff --git a/docs/gst/tmpl/gstreamer-unused.sgml b/docs/gst/tmpl/gstreamer-unused.sgml index 74cbfd14ae..0d7a09b732 100644 --- a/docs/gst/tmpl/gstreamer-unused.sgml +++ b/docs/gst/tmpl/gstreamer-unused.sgml @@ -58,6 +58,27 @@ audioraw GObject + + +The aggregator is mainly used for testing purposes. It has several +methods to request buffers from its pads. + + + + + + + + + + +Combine buffers. + + + +GstAggregator + + Reads data from a file. You can seek to a specific location by setting @@ -157,6 +178,26 @@ Generic connection between elements. GstConnection + + +The disksink write to a file. The filename can be given as an argument. + + + + + +#GstFdSink + + + + +Write to a file + + + +GstDiskSink + + Asynchonously read buffers from a file. @@ -198,6 +239,129 @@ GstDiskSrc GstEsdSink + + + + + + + + + + + + + + + + + +GstExtraTypes + + + + +Take a buffer and gst_buffer_unref() it. This element does nothing +with the buffer. (fakesink) + + + + + + + + + + + +Sources a buffer without doing anything with it. (fakesink) + + + +GstFakeSink + + + + +The GstFakeSrc generates empty buffers. (fakesrc) + + + + + + + + + + +Generate empty buffers. (fakesrc) + + + +GstFakeSrc + + + + +Write data to a file descriptor. + + + + + + + + + + +Write data to a file descriptor. (fdsink) + + + +GstFdSink + + + + +Read buffers from a file descriptor. + + + + + + + + + + +Read buffers from a file descriptor. (fdsrc) + + + +GstFdSrc + + + + +FileSrc is used to read buffers from a file. It efficiently uses mmap +and subbuffers. + + + + + + + + + + +Read data from a file + + + +GstFileSrc + + Filters take data in and spit data out. They are the main Element in a filter graph. @@ -261,6 +425,46 @@ Reads data from a URL. (httpsrc) GstHttpSrc + + +Pass data without modification. + + + + + + + + + + +Pass data without modification. (identity) + + + +GstIdentity + + + + + + + + + + + + + + + + + + + +GstMD5Sink + + The point of the metadata is to provide some context for each buffer. In @@ -374,6 +578,78 @@ Provide context for buffers GstMeta + + + + + + + + + + + + + + + + + +GstMultiDiskSrc + + + + +A GstPipefilter pipes data to an external program and creates +buffers from its output. + + + + + + + + + + +A wrapper around every stdin/stdout capable program + + + +GstPipefilter + + + + +Simple data queue. Data is queued till max_level buffers any subsequent buffers +sent to this filter will block until free space becomes available in the buffer. +The queue is typically used in conjunction with a thread. + + +You can query how many buffers are queued with the level argument. + + +The default queue length is set to 10. + + +The queue blocks by default. + + + + + + + + + + +Simple asynchronous data queue. + + + +GstQueue + + Create a sine wave of a given frequency and volume. @@ -438,6 +714,68 @@ The start point of a filter graph GstSrc + + +The plugin doesn't alter the data but provides statistics about +the data stream, such as buffers/bytes/events etc. + + + + + + + + + + +Provide statistics about data that passes this plugin + + + +GstStatistics + + + + + + + + + + + + + + + + + + + +GstSystemClock + + + + +This element can be added to the pipeline and will notify the listener of +the detected mime type of the stream. It is used in autoplugging. + + + + + + + + + + +Detect the mime type of a media stream + + + +GstTypeFind + + @@ -1889,6 +2227,12 @@ This macro unsets the given state on the element. + + +A type that can be used to indicate a filename. + + + @@ -2378,6 +2722,40 @@ This macro unsets the given state on the element. @v: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@AGGREGATOR_LOOP: +@AGGREGATOR_LOOP_PEEK: +@AGGREGATOR_LOOP_SELECT: +@AGGREGATOR_CHAIN: + @@ -2586,12 +2964,31 @@ the pool. + + +Is emited after the buffer has been written to the disk. + + +@gstdisksink: the object which received the signal. + + + +The filename to write to. + + + + + + + + + @@ -2716,12 +3113,50 @@ GstElementDetails struct for the element. + + +This signal is emmitted when a buffer is handled. + + +@gstfakesink: the object which received the signal. +@arg1: The buffer that is received. + + + +Dump the contents of the buffer + + + + + +The last message this plugin emmited. + + + + + +The number of sink pads. + + + + + +Indicates the plugin should not emit messages. + + + + + +Sync on the clock + + + @@ -2734,12 +3169,110 @@ GstElementDetails struct for the element. + + + + + +@gstfakesrc: the object which received the signal. +@arg1: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2752,6 +3285,12 @@ GstElementDetails struct for the element. + + +The filedescriptor to write to. + + + @@ -2764,12 +3303,72 @@ GstElementDetails struct for the element. + + +The number of bytes per read. + + + + + +The filedescriptor to read from. Pass the argument as a char* (???) + + + + + +Get the current offset in the file. + + + + + +The size of the buffers to pass to the peer element. + + + + + +The file descriptor. + + + + + +The filesize. + + + + + +The filename + + + + + +The size of the mmapped area. + + + + + +The offset in the file that is currently being read. + + + + + +Indicates the mmapped area should be touched to bring it into memory. + + + @@ -2813,12 +3412,68 @@ Specify the location of the file. The location must be a fully qualified URL. + + + + + +@gstidentity: the object which received the signal. +@arg1: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2842,6 +3497,14 @@ Flags indicating properties about the meta data. @GST_META_FREEABLE: the meta data can be freed + + + + + +@GST_MULTIDISKSRC_OPEN: +@GST_MULTIDISKSRC_FLAG_LAST: + @@ -2936,6 +3599,23 @@ The function that will be called when a QoS message is sent. @pad: the pad that sent the QoS message @qos_message: the message + + + + + +@GST_PARSE_ERROR_SYNTAX: +@GST_PARSE_ERROR_CREATING_ELEMENT: +@GST_PARSE_ERROR_NOSUCH_ELEMENT: +@GST_PARSE_ERROR_INTERNAL: +@GST_PARSE_ERROR_CONNECT: + + + +Sets the command to be executed. + + + @@ -2990,6 +3670,31 @@ Specify wether the queue blocks or not. + + + + + + + + +Get the number of buffers in the queue. + + + + + +Specify the maximum number of buffers in the queue before the queue +blocks. + + + + + + + + + @@ -3117,12 +3822,98 @@ Flags for the GstSrc element @GST_SRC_ASYNC: Indicates that this src is asynchronous @GST_SRC_FLAG_LAST: subclasses can use this to number their flags + + + + + +@gststatistics: the object which received the signal. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@clock: + + + + + + + + + + + + + + + + + + + @@ -3163,6 +3954,20 @@ TRUE if the thread should be created. @data: @message: + + +The signal to indicate the mime type was detected. + + +@gsttypefind: the object which received the signal. +@arg1: The mime type that was detected + + + + + + + Query the element for the current mime type @@ -4460,6 +5265,43 @@ must be defined to activate the tracing functionality. @state: @Returns: + + + + + +@src: +@dest: +@Returns: + + + + + + +@src: +@dest: +@filtercaps: +@Returns: + + + + + + +@element_1: +@element_2: +@Varargs: +@Returns: + + + + + + +@src: +@dest: + @@ -4510,6 +5352,15 @@ must be defined to activate the tracing functionality. @Returns: + + + + + +@element: +@templ: +@Returns: + @@ -4520,6 +5371,15 @@ must be defined to activate the tracing functionality. @Returns: @temp: + + + + + +@element: +@name: +@Returns: + @@ -5509,6 +6369,13 @@ Call the EOS function of the pad @src: + + + + + +@Returns: + diff --git a/docs/gst/tmpl/gststatistics.sgml b/docs/gst/tmpl/gststatistics.sgml index 0966d3e7f5..100aed6afd 100644 --- a/docs/gst/tmpl/gststatistics.sgml +++ b/docs/gst/tmpl/gststatistics.sgml @@ -15,55 +15,3 @@ the data stream, such as buffers/bytes/events etc. - - - - - -@gststatistics: the object which received the signal. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/gst/tmpl/gsttee.sgml b/docs/gst/tmpl/gsttee.sgml index 868ee2ba91..ad5d8acd70 100644 --- a/docs/gst/tmpl/gsttee.sgml +++ b/docs/gst/tmpl/gsttee.sgml @@ -14,18 +14,3 @@ A tee can be used to split out the filter graph. - - - - - - - - - - - - - - - diff --git a/docs/gst/tmpl/gsttypefind.sgml b/docs/gst/tmpl/gsttypefind.sgml index ace6c21877..4fb5972710 100644 --- a/docs/gst/tmpl/gsttypefind.sgml +++ b/docs/gst/tmpl/gsttypefind.sgml @@ -15,16 +15,3 @@ the detected mime type of the stream. It is used in autoplugging. - - -The signal to indicate the mime type was detected. - - -@gsttypefind: the object which received the signal. -@arg1: The mime type that was detected - - - - - - diff --git a/docs/manual/advanced-autoplugging.xml b/docs/manual/advanced-autoplugging.xml index c5b89e1101..eb7d5c70d3 100644 --- a/docs/manual/advanced-autoplugging.xml +++ b/docs/manual/advanced-autoplugging.xml @@ -21,28 +21,27 @@ ... /* now it's time to get the parser */ - parse = gst_elementfactory_make ("mp3parse", "parse"); - decoder = gst_elementfactory_make ("mpg123", "decoder"); + decoder = gst_elementfactory_make ("mad", "decoder"); ... While this mechanism is quite effective it also has some big problems: The elements are created based on their name. Indeed, we create an - element mpg123 by explicitly stating the mpg123 elements name. - Our little program therefore always uses the mpg123 decoder element + element mad by explicitly stating the mad element's name. + Our little program therefore always uses the mad decoder element to decode the MP3 audio stream, even if there are 3 other MP3 decoders in the system. We will see how we can use a more general way to create an MP3 decoder element. - We have to introduce the concept of MIME types and capabilities + We have to introduce the concept of MIME types and capabilities added to the source and sink pads. - more on MIME Types + More on MIME Types GStreamer uses MIME types to indentify the different types of data that can be handled by the elements. They are the high level @@ -124,9 +123,9 @@ a function that can be used to determine if a given buffer is of the given MIME type. - - There is also an association between a MIME type and a file - extension. + + There is also an association between a MIME type and a file extension, but the use of typefind + functions (similar to file(1)) is preferred.. The type information is maintained in a list of @@ -202,86 +201,9 @@ struct _GstType { This function will return 0 if the extension was not known. - - - id to <classname>GstElementFactory</classname> conversion - - When we have obtained a given type id using one of the above methods, - we can obtain a list of all the elements that operate on this MIME - type or extension. - - - Obtain a list of all the elements that use this id as source with: - - - GList *list; - - list = gst_type_gst_srcs (id); - - - - Obtain a list of all the elements that use this id as sink with: - - - GList *list; - - list = gst_type_gst_sinks (id); - - - When you have a list of elements, you can simply take the first - element of the list to obtain an appropriate element. - - - - As you can see, there might be a multitude of elements that - are able to operate on audio/raw types. some might include: - - - - an MP3 audio encoder. - - - - - an audio sink. - - - - - an audio resampler. - - - - - a spectrum filter. - - - - Depending on the application, you might want to use a different - element. This is why GStreamer leaves that decision up to the - application programmer. - - - - - - - id to id path detection - - You can obtain a GList of elements that - will transform the source id into the destination id. - - - GList *list; - - list = gst_type_gst_sink_to_src (sourceid, sinkid); - - - This piece of code will give you the elements needed to construct - a path from sourceid to sinkid. This function is mainly used in - autoplugging the pipeline. - - + + For more information, see . + diff --git a/docs/manual/advanced-threads.xml b/docs/manual/advanced-threads.xml index 77680e2cdd..f9b00b96b3 100644 --- a/docs/manual/advanced-threads.xml +++ b/docs/manual/advanced-threads.xml @@ -1,7 +1,7 @@ Threads - GStreamer has support for multithreading throught the use of + GStreamer has support for multithreading through the use of the GstThread object. This object is in fact a special GstBin that will become a thread when started. @@ -13,39 +13,58 @@ GstElement *my_thread; - // create the thread object + /* create the thread object */ my_thread = gst_thread_new ("my_thread"); - g_return_if_fail (audio_thread != NULL); + /* you could have used gst_elementfactory_make ("thread", "my_thread"); */ + g_return_if_fail (my_thread != NULL); - // add some plugins + /* add some plugins */ gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (funky_src)); gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect)); - // connect the elements here... + /* connect the elements here... */ ... - // start playing + /* start playing */ gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING); - - The above program will create a thread with two elements in it. As soon - as it is set to the PLAYING state, the thread will start to iterate. + + The above program will create a thread with two elements in it. As soon as it is set to the + PLAYING state, the thread will start to iterate itself. You never need to manually iterate a + thread. - - - A thread should normally contain a source element. Most often, the thread - is fed with data from a queue. - - - + + Constraints placed on the pipeline by the GstThread + + Within the pipeline, everything is the same as in any other bin. The difference lies at the + thread boundary, at the connection between the thread and the outside world (containing bin). + Since GStreamer is fundamentally buffer-oriented rather than byte-oriented, the natural + solution to this problem is an element that can "buffer" the buffers between the threads, in a + thread-safe fashion. This element is the queue, described more fully in . It doesn't matter if the queue is placed in the containing bin or in + the thread itself, but it needs to be present on one side of the other to enable inter-thread + communication. + + + + When would you want to use a thread? + + If you are writing a GUI application, making the top-level bin a thread will make your GUI + more responsive. If it were a pipeline instead, it would have to be iterated by your + application's event loop, which increases the latency between events (say, keyboard presses) + and responses from the GUI. In addition, any slight hang in the GUI would delay iteration of + the pipeline, which (for example) could cause pops in the output of the sound card, if it is + an audio pipeline. + + - A thread will be visualised as below + A thread can be visualised as below
- a thread + A thread diff --git a/docs/manual/appendix-checklist.xml b/docs/manual/appendix-checklist.xml index 46980e091f..fd7a891f3b 100644 --- a/docs/manual/appendix-checklist.xml +++ b/docs/manual/appendix-checklist.xml @@ -32,6 +32,12 @@ Sets the mask for the info *and* the debug output. + + + + Print out the meaning of gst-mask-* values. + + @@ -47,16 +53,15 @@ Print the a short desciption of the - options and an overview of the current debugging/info masks - set. + options - The follwing table gives an overview of the mask values and - their meaning. (enabled) means that the corresponding flag - has been set. + The following table gives an overview of the mask values and their meaning. (enabled) means + that the corresponding flag is set by default. This table is available to any GStreamer + application by the --gst-mask-help option. Mask (to be OR'ed) info/debug FLAGS diff --git a/docs/manual/appendix-debugging.xml b/docs/manual/appendix-debugging.xml index 46980e091f..fd7a891f3b 100644 --- a/docs/manual/appendix-debugging.xml +++ b/docs/manual/appendix-debugging.xml @@ -32,6 +32,12 @@ Sets the mask for the info *and* the debug output. + + + + Print out the meaning of gst-mask-* values. + + @@ -47,16 +53,15 @@ Print the a short desciption of the - options and an overview of the current debugging/info masks - set. + options - The follwing table gives an overview of the mask values and - their meaning. (enabled) means that the corresponding flag - has been set. + The following table gives an overview of the mask values and their meaning. (enabled) means + that the corresponding flag is set by default. This table is available to any GStreamer + application by the --gst-mask-help option. Mask (to be OR'ed) info/debug FLAGS diff --git a/docs/manual/appendix-programs.xml b/docs/manual/appendix-programs.xml index 28a1c17911..7f57334bba 100644 --- a/docs/manual/appendix-programs.xml +++ b/docs/manual/appendix-programs.xml @@ -4,38 +4,35 @@ - <command>gstreamer-register</command> + <command>gst-register</command> - gstreamer-register is used to rebuild the database of plugins. + gst-register is used to rebuild the database of plugins. It is used after a new plugin has been added to the system. The plugin database - can be found in /etc/gstreamer/reg.xml. + can be found, by default, in /etc/gstreamer/reg.xml. - <command>gstreamer-launch</command> + <command>gst-launch</command> This is a tool that will construct pipelines based on a command-line - syntax. + syntax. FIXME: need a more extensive grammar reference A simple commandline looks like: -gstreamer-launch filesrc location=hello.mp3 ! mp3parse ! mpg123 ! audiosink +gst-launch filesrc location=hello.mp3 ! mad ! osssink A more complex pipeline looks like: -gstreamer-launch filesrc redpill.vob audio_00! (ac3parse ! ac3dec ! audiosink) \ -video_00! (mpeg2dec ! videosink) +gst-launch filesrc location=redpill.vob ! mpegdemux name=demux \ + demux.audio_00! { ac3parse ! a52dec ! osssink } \ + demux.video_00! { mpeg2dec ! xvideosink } - - - Note that the parser isn't capable of more complex pipelines yet, including - the VOB player above. The minor tweaks will be made post 0.2.1. You can also use the the parser in you own code. GStreamer @@ -51,17 +48,21 @@ main (int argc, char *argv[]) { GstElement *pipeline; GstElement *filesrc; + GError *error = NULL; gst_init (&argc, &argv); if (argc != 2) { - g_print ("usage: %s <filename>\n", argv[0]); + g_print ("usage: %s <filename>\n", argv[0]); return -1; } - pipeline = gst_pipeline_new ("my_pipeline"); - - gst_parse_launch ("filesrc[my_filesrc] ! mp3parse ! mpg123 ! osssink", GST_BIN (pipeline)); + pipeline = gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error); + if (!pipeline) { + g_print ("Parse error: %s\n", error->message); + exit (1); + } + filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); @@ -81,20 +82,20 @@ main (int argc, char *argv[]) - <command>gstreamer-inspect</command> + <command>gst-inspect</command> This is a tool to query a plugin or an element about its properties. - To query the information about the element mpg123, you would specify: + To query the information about the element mad, you would specify: -gstreamer-inspect mpg123 +gst-inspect mad - Below is the output of a query for the audiosink element: + Below is the output of a query for the osssink element: @@ -102,56 +103,72 @@ Factory Details: Long name: Audio Sink (OSS) Class: Sink/Audio Description: Output to a sound card via OSS - Version: 0.1.0 - Author(s): Erik Walthinsen <omega@cse.ogi.edu> + Version: 0.3.3.1 + Author(s): Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim.taymans@chello.be> Copyright: (C) 1999 +GObject + +----GstObject + +----GstElement + +----GstOssSink + Pad Templates: SINK template: 'sink' - Exists: Always + Availability: Always Capabilities: - 'audiosink_sink': + 'osssink_sink': MIME type: 'audio/raw': - format: Integer: 16 + format: String: int + endianness: Integer: 1234 + width: List: + Integer: 8 + Integer: 16 depth: List: Integer: 8 Integer: 16 - rate: Integer range: 8000 - 48000 channels: Integer range: 1 - 2 + law: Integer: 0 + signed: List: + Boolean: FALSE + Boolean: TRUE + rate: Integer range: 1000 - 48000 + Element Flags: GST_ELEMENT_THREADSUGGESTED - no flags set Element Implementation: No loopfunc(), must be chain-based or not configured yet - Has change_state() function + Has change_state() function: gst_osssink_change_state + Has custom save_thyself() function: gst_element_save_thyself + Has custom restore_thyself() function: gst_element_restore_thyself + +Clocking Interaction: + element requires a clock + element provides a clock: GstOssClock Pads: SINK: 'sink' Implementation: - Has chainfunc(): 0x4001cde8 - Has default eosfunc() gst_pad_eos_func() + Has chainfunc(): 0x40056fc0 Pad Template: 'sink' - Capabilities: - 'audiosink_sink': - MIME type: 'audio/raw': - format: Integer: 16 - depth: List: - Integer: 8 - Integer: 16 - rate: Integer range: 8000 - 48000 - channels: Integer range: 1 - 2 Element Arguments: - GstAudioSink::mute: Boolean - GstAudioSink::format: Enum (default 16) - (8): 8 Bits - (16): 16 Bits - GstAudioSink::channels: Enum (default 2) + name : String (Default "element") + device : String (Default "/dev/dsp") + mute : Boolean (Default false) + format : Integer (Default 16) + channels : Enum "GstAudiosinkChannels" (default 1) + (0): Silence (1): Mono (2): Stereo - GstAudioSink::frequency: Integer + frequency : Integer (Default 11025) + fragment : Integer (Default 6) + buffer-size : Integer (Default 4096) + +Element Signals: + "handoff" : void user_function (GstOssSink* object, + gpointer user_data); @@ -159,11 +176,11 @@ Element Arguments: -gstreamer-inspect gstelements +gst-inspect gstelements - <command>gstmediaplay</command> + <command>gst-play</command> A sample media player. diff --git a/docs/manual/autoplugging.xml b/docs/manual/autoplugging.xml index 01f9852cc8..24b03f2176 100644 --- a/docs/manual/autoplugging.xml +++ b/docs/manual/autoplugging.xml @@ -2,8 +2,8 @@ Autoplugging GStreamer provides an API to automatically - construct complex pipelinebased on source and destination capabilities. - This feature is very usefull if you want to convert type X to type Y but + construct complex pipelines based on source and destination capabilities. + This feature is very useful if you want to convert type X to type Y but don't care about the plugins needed to accomplish this task. The autoplugger will consult the plugin repository, select and connect the elements needed for the conversion. @@ -106,7 +106,7 @@ Add the autoplugcache element to a bin and connect the sink pad to the src - pad of an element with unkown caps. + pad of an element with unknown caps. @@ -141,8 +141,52 @@ - In the next chapter we will create a new version of our helloworld exaple using the + In the next chapter we will create a new version of our helloworld example using the autoplugger, the autoplugcache and the typefind element. + + Another approach to autoplugging + + The autoplug API is interesting, but often impractical. It is static; it cannot deal with + dynamic pipelines (insert ref here). What one often wants is just an element to stick into a + pipeline that will DWIM (ref). Enter the spider. + + + The spider element + + The spider element is a generalized autoplugging element. At this point (April 2002), it's + the best we've got; it can be inserted anywhere within a pipeline to perform caps + conversion, if possible. Consider the following gst-launch line: + + $ gst-launch filesrc location=my.mp3 ! spider ! osssink + + The spider will detect the type of the stream, autoplug it to the osssink's caps, and play + the pipeline. It's neat. + + + + Spider features + + + + + Automatically typefinds the incoming stream. + + + + + Has request pads on the src side. This means that it can autoplug one source stream + into many sink streams. For example, a MPEG1 system stream can have audio as well as + video; that pipeline would be represented in gst-launch syntax as + + $ gst-launch filesrc location=my.mpeg1 ! spider ! { queue ! osssink } spider.src_%d! + { queue ! xvideosink } + + + + + + + diff --git a/docs/manual/basics-bins.xml b/docs/manual/basics-bins.xml index a60e071908..47f05c466b 100644 --- a/docs/manual/basics-bins.xml +++ b/docs/manual/basics-bins.xml @@ -7,7 +7,7 @@ Bins allow you to combine connected elements into one logical element. You do not deal with the individual elements anymore but with just one element, the bin. - We will see that this is extremely powerfull when you are going to construct + We will see that this is extremely powerful when you are going to construct complex pipelines since it allows you to break up the pipeline in smaller chunks. @@ -37,9 +37,10 @@ - A thread (GstThread). All the elements in the thread bin will - run in a separate thread. You will have to use this bin if you carfully have to - synchronize audio and video for example. You will learn more about threads in.. + A thread (GstThread). The plan for the + GstThread will be run in a separate thread. You will have to use + this bin if you have to carefully synchronize audio and video, for example. You will learn + more about threads in . @@ -48,26 +49,22 @@ Creating a bin - You create a bin with a specified name 'mybin' with: + Bins register themselves in the GStreamer registry, so they can be created in the normal way: - GstElement *bin; + GstElement *bin, *thread, *pipeline; - gst_bin_new ("mybin"); - ... + /* create a new bin called 'mybin'. this bin will be only for organizational purposes; a normal + GstBin doesn't affect plan generation */ + bin = gst_elementfactory_make ("bin", "mybin"); + + /* create a new thread, and give it a unique name */ + thread = gst_elementfactory_make ("thread", NULL); + + /* the core bins (GstBin, GstThread, GstPipeline) also have convenience APIs, + gst_<bintype>_new (). these are equivalent to the gst_elementfactory_make () syntax. */ + pipeline = gst_pipeline_new ("pipeline_name"); - - A thread can be created with: - - - GstElement *thread; - - gst_thread_new ("mythread"); - ... - - - Pipelines are created with gst_pipeline_new ("name"); - @@ -86,8 +83,9 @@ ... - Bins and threads can be added to other bins too. This allows you to create nested - bins. + Bins and threads can be added to other bins too. This allows you to create nested bins. Note + that it doesn't make very much sense to add a GstPipeline to anything, + as it's a toplevel bin that needs to be explicitly iterated. To get an element from the bin you can use: @@ -100,7 +98,7 @@ You can see that the name of the element becomes very handy for retrieving the - element from an bin by using the elements name. gst_bin_get_by_name () will + element from an bin by using the element's name. gst_bin_get_by_name () will recursively search nested bins. @@ -114,7 +112,7 @@ while (elements) { GstElement *element = GST_ELEMENT (elements->data); - g_print ("element in bin: %s\n", gst_element_get_name (element)); + g_print ("element in bin: %s\n", GST_OBJECT_NAME (GST_OBJECT (element))); elements = g_list_next (elements); } @@ -129,6 +127,18 @@ gst_bin_remove (GST_BIN (bin), element); ... + + To add many elements to a bin at the same time, try the gst_bin_add_many () API. Remember to + pass NULL as the last argument. + + + GstElement *filesrc, *decoder, *audiosink; + GstBin *bin; + + /* instantiate the elements and the bins... */ + + gst_bin_add_many (bin, filesrc, decoder, audiosink, NULL); + @@ -137,43 +147,56 @@ The application programmer can create custom bins packed with elements to perform a specific task. This allow you to write an MPEG audio decoder with just the follwing lines of code: + + - - - // create the mp3player element + /* create the mp3player element */ GstElement *mp3player = gst_elementfactory_make ("mp3player", "mp3player"); - // set the source mp3 audio file + /* set the source mp3 audio file */ g_object_set (G_OBJECT (mp3player), "location", "helloworld.mp3", NULL); - // start playback + /* start playback */ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING); ... - // pause playback + /* pause playback */ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED); ... - // stop + /* stop */ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL); - + + + Note that the above code assumes that the mp3player bin derives itself from a + GstThread, which begins to play as soon as its state is set to PLAYING. + Other bin types may need explicit iteration. For more information, see . Custom bins can be created with a plugin or an XML description. You will find more - information about creating custom bin in the Filter-Writers-Guide. + information about creating custom bin in the Plugin Writers Guide (FIXME ref). - Ghostpads + Ghost pads - You can see from figure ... how a bin has no pads of its own. This is where Ghostpads - come into play. + You can see from figure how a bin has no pads of its own. + This is where "ghost pads" come into play. +
+ Visualisation of a <classname>GstBin</classname> element without ghost pads + + + + + +
- A ghostpad is a pad from some element in the bin that has been promoted to the bin. + A ghost pad is a pad from some element in the bin that has been promoted to the bin. This way, the bin also has a pad. The bin becomes just another element with a pad and you can then use the bin just like any other element. This is a very important feature for creating custom bins.
- Visualisation of a <classname>GstBin</classname> element with a ghostpad + Visualisation of a <classname>GstBin</classname> element with a ghost pad @@ -181,18 +204,18 @@
- Above is a representation of a ghostpad. the sinkpad of element one is now also a pad + Above is a representation of a ghost pad. The sink pad of element one is now also a pad of the bin. - Ghostpads can actually be added to all GstElements and not just - GstBins. Use the following code example to add a ghostpad to a bin: + Ghost pads can actually be added to all GstElements and not just + GstBins. Use the following code example to add a ghost pad to a bin: GstElement *bin; GstElement *element; - element = gst_elementfactory_create ("mpg123", "decoder"); + element = gst_elementfactory_create ("mad", "decoder"); bin = gst_bin_new ("mybin"); gst_bin_add (GST_BIN (bin), element); @@ -210,7 +233,7 @@ filesrc = gst_elementfactory_create ("filesrc", "disk_reader"); - gst_element_connect (filesrc, "src", bin, "sink"); + gst_element_connect_pads (filesrc, "src", bin, "sink"); ...
diff --git a/docs/manual/basics-data.xml b/docs/manual/basics-data.xml index 78c1bca983..043a8fa2b8 100644 --- a/docs/manual/basics-data.xml +++ b/docs/manual/basics-data.xml @@ -51,7 +51,7 @@ A more complex case is when the filter modifies the data in place. It does so and simply passes on the buffer to the next element. This is just - as easy to deal with. An element that works in place has to be carefull when + as easy to deal with. An element that works in place has to be careful when the buffer is used in more than one element; a copy on write has to made in this situation. diff --git a/docs/manual/basics-elements.xml b/docs/manual/basics-elements.xml index 5d76c1fa57..3b361dee8e 100644 --- a/docs/manual/basics-elements.xml +++ b/docs/manual/basics-elements.xml @@ -12,21 +12,16 @@ different components you are going to use are derived from this GstElement. This means that a lot of functions you are going to use operate on this object. - - You will see that those elements have pads. These are the elements - connections with the 'outside' world. Depending on the number and direction of - the pads, we can see three types of elements: source, filter and sink element. - - - These three types are all the same GstElement object, they just differ in how - the pads are. + Elements, from the perspective of GStreamer, are viewed as "black boxes" with a number of + different aspects. One of these aspects is the presence of "pads", or connection points. This + terminology arises from soldering; pads are where wires can be attached. - GStreamer source elements + Source elements - This element will generate data that will be used by the pipeline. It is - typically a file or an audio source. + Source elements generate data for use by a pipeline, for example reading from disk or from a + sound card. Below you see how we will visualize the element. @@ -48,19 +43,17 @@ - GStreamer filter elements + Filters and codecs - Filter elements both have an input and an output pad. They operate on data - they receive in the sink pad and send the result to the src pad. - + Filter elements both have input and output pads. They operate on data they receive in their + sink pads and produce data on their src pads. For example, MPEG decoders and volume filters + would fall into this category. + - Examples of a filter element might include: an MPEG decoder, volume filter,... - - - Filters may also contain any number of input pads and output pads. For example, - a video mixer might have to input pads (the images of the two different video - streams) and one output pad. - + Elements are not constrained as to the number of pads they migh have; for example, a video + mixer might have two input pads (the images of the two different video streams) and one + output pad. +
Visualisation of a filter element @@ -71,7 +64,7 @@
The above figure shows the visualisation of a filter element. This element has - one sink pad (input) and one src (output) pad. Sink pads are drawn on the left + one sink (input) pad and one src (output) pad. Sink pads are drawn on the left of the element.
@@ -84,21 +77,21 @@
- The above figure shows the visualisation of a filter element with more than one - output pad. An example of such a filter is the AVI splitter. This element will - parse the input data and extracts the audio and video data. Most of these filters - dynamically send out a signal when a new pad is created so that the application - programmer can connect an arbitrary element to the newly created pad. - + The above figure shows the visualisation of a filter element with more than one output pad. + An example of such a filter is the AVI splitter (demuxer). This element will parse the input + data and extracts the audio and video data. Most of these filters dynamically send out a + signal when a new pad is created so that the application programmer can connect an arbitrary + element to the newly created pad. + - GStreamer sink elements - - This element accepts data but will not generate any new data. A sink element - is typically a file on disk, a soundcard, a display,... It is presented as - below: - + Sink elements + + Sink elements are terminal points in a media pipeline. They accept data but do not produce + anything. Disk writing, soundcard playback, and video output woul all be implemented by sink + elements. +
Visualisation of a sink element @@ -117,12 +110,12 @@ The following code example is used to get a factory that can be used to create the - mpg123 element, an mp3 decoder. + 'mad' element, an mp3 decoder. GstElementFactory *factory; - factory = gst_elementfactory_find ("mpg123"); + factory = gst_elementfactory_find ("mad"); Once you have the handle to the elementfactory, you can create a real element with @@ -133,23 +126,23 @@ element = gst_elementfactory_create (factory, "decoder"); - - gst_elementfactory_create () will use the elementfactory to create an element with the - given name. The name of the element is something you can use later on to lookup the - element in a bin, for example. - - - A simple shortcut exists for creating an element from a factory. The following example - creates an element, named "decoder" from the elementfactory named "mpg123". This - convenient function is most widly used to create an element. - + + gst_elementfactory_create () will use the elementfactory to create an element with the given + name. The name of the element is something you can use later on to lookup the element in a + bin, for example. You can pass NULL as the name argument to get a unique, default name. + + + A simple shortcut exists for creating an element from a factory. The following example creates + an element, named "decoder" from the elementfactory named "mad". This convenient function is + most widely used to create an element. + GstElement *element; - element = gst_elementfactory_make ("mpg123", "decoder"); + element = gst_elementfactory_make ("mad", "decoder"); - An element can be destroyed with: + An element can be destroyed with: FIXME talk about refcounting GstElement *element; diff --git a/docs/manual/basics-helloworld.xml b/docs/manual/basics-helloworld.xml index 8fe65276c6..6072152e14 100644 --- a/docs/manual/basics-helloworld.xml +++ b/docs/manual/basics-helloworld.xml @@ -8,13 +8,12 @@ Hello world - - We will create a simple first application. In fact it will be a complete - MP3 player, using standard GStreamer components. The player will read from - a file that is given as the first argument of the program. + + We will create a simple first application, a complete MP3 player, using standard + GStreamer components. The player will read from a file that is + given as the first argument of the program. - #include <gst/gst.h> @@ -45,15 +44,10 @@ main (int argc, char *argv[]) audiosink = gst_elementfactory_make ("osssink", "play_audio"); /* add objects to the main pipeline */ - gst_bin_add (GST_BIN (pipeline), filesrc); - gst_bin_add (GST_BIN (pipeline), decoder); - gst_bin_add (GST_BIN (pipeline), audiosink); + gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL); /* connect src to sink */ - gst_pad_connect (gst_element_get_pad (filesrc, "src"), - gst_element_get_pad (decoder, "sink")); - gst_pad_connect (gst_element_get_pad (decoder, "src"), - gst_element_get_pad (audiosink, "sink")); + gst_element_connect_many (filesrc, decoder, audiosink, NULL); /* start playing */ gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -64,10 +58,8 @@ main (int argc, char *argv[]) gst_element_set_state (pipeline, GST_STATE_NULL); /* we don't need a reference to these objects anymore */ - gst_object_unref (GST_OBJECT (audiosink)); - gst_object_unref (GST_OBJECT (decoder)); - gst_object_unref (GST_OBJECT (filesrc)); gst_object_unref (GST_OBJECT (pipeline)); + /* unreffing the pipeline unrefs the contained elements as well */ exit (0); } @@ -98,8 +90,8 @@ main (int argc, char *argv[]) - We are going to create 3 elements and one pipeline. Since all objects are - in fact elements, we can define them as: + We are going to create 3 elements and one pipeline. Since all elements share the same base + type, GstElement, we can define them as: ... @@ -142,7 +134,7 @@ main (int argc, char *argv[]) is installed on the system where this application is executed. - /* now it's time to get the parser */ + /* now it's time to get the decoder */ decoder = gst_elementfactory_make ("mad", "decoder"); @@ -167,9 +159,7 @@ main (int argc, char *argv[]) /* add objects to the main pipeline */ - gst_bin_add (GST_BIN (pipeline), filesrc); - gst_bin_add (GST_BIN (pipeline), decoder); - gst_bin_add (GST_BIN (pipeline), audiosink); + gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL); @@ -177,10 +167,7 @@ main (int argc, char *argv[]) /* connect src to sink */ - gst_pad_connect (gst_element_get_pad (filesrc, "src"), - gst_element_get_pad (decoder, "sink")); - gst_pad_connect (gst_element_get_pad (decoder, "src"), - gst_element_get_pad (audiosink, "sink")); + gst_element_connect_many (filesrc, decoder, audiosink, NULL); @@ -229,16 +216,13 @@ main (int argc, char *argv[]) /* stop the pipeline */ gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (audiosink)); - gst_object_unref (GST_OBJECT (decoder)); - gst_object_unref (GST_OBJECT (filesrc)); gst_object_unref (GST_OBJECT (pipeline)); exit (0); - don't forget to set the state of the pipeline to NULL. This will free + Don't forget to set the state of the pipeline to NULL. This will free all of the resources held by the elements. @@ -246,7 +230,7 @@ main (int argc, char *argv[]) - compiling helloworld.c + Compiling helloworld.c To compile the helloworld example, use: @@ -268,10 +252,10 @@ main (int argc, char *argv[]) - conclusion + Conclusion This concludes our first example. As you see, setting up a pipeline - is very lowlevel but powerfull. You will later in this manual how + is very lowlevel but powerful. You will later in this manual how you can create a custom MP3 element with a more high level API. @@ -284,7 +268,7 @@ main (int argc, char *argv[]) We could use a disksink to write the raw samples to a file, for example. It should also be clear that inserting filters, like a stereo effect, into the pipeline is not that hard to do. The most important thing is - that you can reuse allready existing elements. + that you can reuse already existing elements. diff --git a/docs/manual/basics-pads.xml b/docs/manual/basics-pads.xml index 36bd02184c..953367a6d1 100644 --- a/docs/manual/basics-pads.xml +++ b/docs/manual/basics-pads.xml @@ -1,7 +1,7 @@ GstPad - As we have seen in the previous chapter (GstElement), the pads are the elements + As we have seen in the previous chapter (GstElement), the pads are the element's connections with the outside world. @@ -44,7 +44,7 @@ Useful pad functions You can get the name of a pad with gst_pad_get_name () and set its name with - get_pad_set_name(); + get_pad_set_name(). gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink @@ -53,8 +53,8 @@ You can get the parent of the pad, this is the element that this pad belongs to, - with get_pad_set_parent(GstPad *pad). This function will return a pointer to a - GstObject. + with get_pad_get_parent(GstPad *pad). This function will return a pointer to a + GstElement. @@ -63,10 +63,10 @@ Some elements might not have their pads when they are created. This can, for example, happen with an MPEG2 system demuxer. The demuxer will create its pads at runtime when it detects the different elementary streams in the MPEG2 - system stream. + system stream. - Running gstreamer-inspect mpeg2parse will show that + Running gst-inspect mpegdemux will show that the element has only one pad: a sink pad called 'sink'. The other pads are "dormant" as you can see in the padtemplates from the 'Exists: Sometimes' property. Depending on the type of MPEG2 file you play, the pads are created. We @@ -104,7 +104,7 @@ main(int argc, char *argv[]) // create pipeline and do something usefull ... - mpeg2parser = gst_elementfactory_make ("mpeg2parse", "mpeg2parse"); + mpeg2parser = gst_elementfactory_make ("mpegdemux", "mpegdemux"); g_signal_connect (G_OBJECT (mpeg2parser), "new_pad", pad_connect_func, pipeline); ... @@ -141,19 +141,19 @@ main(int argc, char *argv[]) ... element = gst_elementfactory_make ("tee", "element"); - pad = gst_element_request_pad_by_name (element, "src%d"); + pad = gst_element_get_request_pad (element, "src%d"); g_print ("new pad %s\n", gst_pad_get_name (pad)); ... - The gst_element_request_pad_by_name method can be used to get a pad + The gst_element_get_request_pad method can be used to get a pad from the element based on the name_template of the padtemplate. It is also possible to request a pad that is compatible with another padtemplate. This is very usefull if you want to connect an element to a muxer element and you need to request a pad that is compatible. The - gst_element_request_compatible_pad is used to request a compatible pad, as + gst_element_get_compatible_pad is used to request a compatible pad, as is shown in the next example. @@ -162,11 +162,11 @@ main(int argc, char *argv[]) GstPad *pad; ... element = gst_elementfactory_make ("tee", "element"); - mp3parse = gst_elementfactory_make ("mp3parse", "mp3parse"); + mad = gst_elementfactory_make ("mad", "mad"); - templ = gst_element_get_padtemplate_by_name (mp3parse, "sink"); + templ = gst_element_get_padtemplate_by_name (mad, "sink"); - pad = gst_element_request_compatible_pad (element, templ); + pad = gst_element_get_compatible_pad (element, templ); g_print ("new pad %s\n", gst_pad_get_name (pad)); ... @@ -181,7 +181,7 @@ main(int argc, char *argv[]) We will briefly describe what capabilities are, enough for you to get a basic understanding of the concepts. You will find more information on how to create capabilities in the - filter-writer-guide. + Plugin Writer's Guide. @@ -207,8 +207,8 @@ struct _GstCaps { }; - Below is a dump of the capabilities of the element mpg123, as shown by - gstreamer-inspect. + Below is a dump of the capabilities of the element mad, as shown by + gst-inspect. You can see two pads: sink and src. Both pads have capability information attached to them. @@ -221,26 +221,25 @@ struct _GstCaps { Pads: - SINK: 'sink' - .... - Capabilities: - 'mpg123_sink': - MIME type: 'audio/mp3': - layer: Integer range: 1 - 3 - bitrate: Integer range: 8 - 320 - framed: Boolean: TRUE - - SRC: 'src' - .... + SINK template: 'sink' + Availability: Always Capabilities: - 'mpg123_src': - MIME type: 'audio/raw': - format: Integer: 16 - depth: Integer: 16 - rate: Integer range: 11025 - 48000 - channels: List: - Integer: 1 - Integer: 2 + 'mad_sink': + MIME type: 'audio/mp3': + + SRC template: 'src' + Availability: Always + Capabilities: + 'mad_src': + MIME type: 'audio/raw': + format: String: int + endianness: Integer: 1234 + width: Integer: 16 + depth: Integer: 16 + channels: Integer range: 1 - 2 + law: Integer: 0 + signed: Boolean: TRUE + rate: Integer range: 11025 - 48000 @@ -260,7 +259,7 @@ Pads: An integer range value. The property denotes a range of possible values. In the case - of the mpg123 element: the src pad has a property rate that can go from 11025 to 48000. + of the mad element: the src pad has a property rate that can go from 11025 to 48000. @@ -349,7 +348,7 @@ Pads: As we said, a capability has a name, a mime-type and some properties. The signature of the - function to create a new GstCaps * structure is like: + function to create a new GstCaps structure is like: GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props); diff --git a/docs/manual/basics-plugins.xml b/docs/manual/basics-plugins.xml index a89d9cb908..a8fa76abba 100644 --- a/docs/manual/basics-plugins.xml +++ b/docs/manual/basics-plugins.xml @@ -20,6 +20,11 @@ one or more autopluggers + + + exported symbols for use in other plugins + + The plugins have one simple method: plugin_init () where all the elementfactories are diff --git a/docs/manual/bins.xml b/docs/manual/bins.xml index a60e071908..47f05c466b 100644 --- a/docs/manual/bins.xml +++ b/docs/manual/bins.xml @@ -7,7 +7,7 @@ Bins allow you to combine connected elements into one logical element. You do not deal with the individual elements anymore but with just one element, the bin. - We will see that this is extremely powerfull when you are going to construct + We will see that this is extremely powerful when you are going to construct complex pipelines since it allows you to break up the pipeline in smaller chunks. @@ -37,9 +37,10 @@ - A thread (GstThread). All the elements in the thread bin will - run in a separate thread. You will have to use this bin if you carfully have to - synchronize audio and video for example. You will learn more about threads in.. + A thread (GstThread). The plan for the + GstThread will be run in a separate thread. You will have to use + this bin if you have to carefully synchronize audio and video, for example. You will learn + more about threads in . @@ -48,26 +49,22 @@ Creating a bin - You create a bin with a specified name 'mybin' with: + Bins register themselves in the GStreamer registry, so they can be created in the normal way: - GstElement *bin; + GstElement *bin, *thread, *pipeline; - gst_bin_new ("mybin"); - ... + /* create a new bin called 'mybin'. this bin will be only for organizational purposes; a normal + GstBin doesn't affect plan generation */ + bin = gst_elementfactory_make ("bin", "mybin"); + + /* create a new thread, and give it a unique name */ + thread = gst_elementfactory_make ("thread", NULL); + + /* the core bins (GstBin, GstThread, GstPipeline) also have convenience APIs, + gst_<bintype>_new (). these are equivalent to the gst_elementfactory_make () syntax. */ + pipeline = gst_pipeline_new ("pipeline_name"); - - A thread can be created with: - - - GstElement *thread; - - gst_thread_new ("mythread"); - ... - - - Pipelines are created with gst_pipeline_new ("name"); - @@ -86,8 +83,9 @@ ... - Bins and threads can be added to other bins too. This allows you to create nested - bins. + Bins and threads can be added to other bins too. This allows you to create nested bins. Note + that it doesn't make very much sense to add a GstPipeline to anything, + as it's a toplevel bin that needs to be explicitly iterated. To get an element from the bin you can use: @@ -100,7 +98,7 @@ You can see that the name of the element becomes very handy for retrieving the - element from an bin by using the elements name. gst_bin_get_by_name () will + element from an bin by using the element's name. gst_bin_get_by_name () will recursively search nested bins. @@ -114,7 +112,7 @@ while (elements) { GstElement *element = GST_ELEMENT (elements->data); - g_print ("element in bin: %s\n", gst_element_get_name (element)); + g_print ("element in bin: %s\n", GST_OBJECT_NAME (GST_OBJECT (element))); elements = g_list_next (elements); } @@ -129,6 +127,18 @@ gst_bin_remove (GST_BIN (bin), element); ... + + To add many elements to a bin at the same time, try the gst_bin_add_many () API. Remember to + pass NULL as the last argument. + + + GstElement *filesrc, *decoder, *audiosink; + GstBin *bin; + + /* instantiate the elements and the bins... */ + + gst_bin_add_many (bin, filesrc, decoder, audiosink, NULL); + @@ -137,43 +147,56 @@ The application programmer can create custom bins packed with elements to perform a specific task. This allow you to write an MPEG audio decoder with just the follwing lines of code: + + - - - // create the mp3player element + /* create the mp3player element */ GstElement *mp3player = gst_elementfactory_make ("mp3player", "mp3player"); - // set the source mp3 audio file + /* set the source mp3 audio file */ g_object_set (G_OBJECT (mp3player), "location", "helloworld.mp3", NULL); - // start playback + /* start playback */ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING); ... - // pause playback + /* pause playback */ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED); ... - // stop + /* stop */ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL); - + + + Note that the above code assumes that the mp3player bin derives itself from a + GstThread, which begins to play as soon as its state is set to PLAYING. + Other bin types may need explicit iteration. For more information, see . Custom bins can be created with a plugin or an XML description. You will find more - information about creating custom bin in the Filter-Writers-Guide. + information about creating custom bin in the Plugin Writers Guide (FIXME ref). - Ghostpads + Ghost pads - You can see from figure ... how a bin has no pads of its own. This is where Ghostpads - come into play. + You can see from figure how a bin has no pads of its own. + This is where "ghost pads" come into play. +
+ Visualisation of a <classname>GstBin</classname> element without ghost pads + + + + + +
- A ghostpad is a pad from some element in the bin that has been promoted to the bin. + A ghost pad is a pad from some element in the bin that has been promoted to the bin. This way, the bin also has a pad. The bin becomes just another element with a pad and you can then use the bin just like any other element. This is a very important feature for creating custom bins.
- Visualisation of a <classname>GstBin</classname> element with a ghostpad + Visualisation of a <classname>GstBin</classname> element with a ghost pad @@ -181,18 +204,18 @@
- Above is a representation of a ghostpad. the sinkpad of element one is now also a pad + Above is a representation of a ghost pad. The sink pad of element one is now also a pad of the bin. - Ghostpads can actually be added to all GstElements and not just - GstBins. Use the following code example to add a ghostpad to a bin: + Ghost pads can actually be added to all GstElements and not just + GstBins. Use the following code example to add a ghost pad to a bin: GstElement *bin; GstElement *element; - element = gst_elementfactory_create ("mpg123", "decoder"); + element = gst_elementfactory_create ("mad", "decoder"); bin = gst_bin_new ("mybin"); gst_bin_add (GST_BIN (bin), element); @@ -210,7 +233,7 @@ filesrc = gst_elementfactory_create ("filesrc", "disk_reader"); - gst_element_connect (filesrc, "src", bin, "sink"); + gst_element_connect_pads (filesrc, "src", bin, "sink"); ...
diff --git a/docs/manual/buffers.xml b/docs/manual/buffers.xml index 78c1bca983..043a8fa2b8 100644 --- a/docs/manual/buffers.xml +++ b/docs/manual/buffers.xml @@ -51,7 +51,7 @@ A more complex case is when the filter modifies the data in place. It does so and simply passes on the buffer to the next element. This is just - as easy to deal with. An element that works in place has to be carefull when + as easy to deal with. An element that works in place has to be careful when the buffer is used in more than one element; a copy on write has to made in this situation. diff --git a/docs/manual/components.xml b/docs/manual/components.xml index a4272342f8..0c5923f782 100644 --- a/docs/manual/components.xml +++ b/docs/manual/components.xml @@ -1,5 +1,10 @@ Components + + + FIXME: This chapter is way out of date. + + GStreamer includes components that people can include in their programs. diff --git a/docs/manual/connections.xml b/docs/manual/connections.xml index 381315f5ab..2504ca7940 100644 --- a/docs/manual/connections.xml +++ b/docs/manual/connections.xml @@ -45,16 +45,42 @@ - A convenient shortcut for the above code is done with the gst_element_connect () + A convenient shortcut for the above code is done with the gst_element_connect_pads () function: // connect them - gst_element_connect (element1, "src", element2, "sink"); + gst_element_connect_pads (element1, "src", element2, "sink"); .... // and disconnect them - gst_element_disconnect (element1, "src", element2, "sink"); + gst_element_disconnect_pads (element1, "src", element2, "sink"); + + + + An even more convenient shortcut for single-source, single-sink elements is the + gst_element_connect () function: + + + + // connect them + gst_element_connect (element1, element2); + .... + // and disconnect them + gst_element_disconnect (element1, element2); + + + + If you have more than one element to connection, the gst_element_connect_many () function takes + a NULL-terminated list of elements: + + + + // connect them + gst_element_connect_many (element1, element2, element3, element4, NULL); + .... + // and disconnect them + gst_element_disconnect_many (element1, element2, element3, element4, NULL); @@ -70,7 +96,7 @@ Making filtered connections You can also force a specific media type on the connection by using gst_pad_connect_filtered () - and gst_element_connect_filtered (). + and gst_element_connect_filtered (). FIXME link to caps documentation. diff --git a/docs/manual/cothreads.xml b/docs/manual/cothreads.xml index 7fc9c67964..f50f53ad79 100644 --- a/docs/manual/cothreads.xml +++ b/docs/manual/cothreads.xml @@ -1,9 +1,9 @@ Cothreads - - Cothreads are user-space threads that greatly reduce context - switching overhead introduced by regular kernel threads. - Cothreads are also used to handle the more complex elements. + + Cothreads are user-space threads that greatly reduce context switching overhead introduced by + regular kernel threads. Cothreads are also used to handle the more complex elements. They differ + from other user-space threading libraries in that they are scheduled explictly by GStreamer. A cothread is created by a GstBin whenever an element is found @@ -72,7 +72,7 @@ chain_function (GstPad *pad, GstBuffer *buffer) Loop-based elements - As opposed to chain-based elements, Loop-based elements enter an + As opposed to chain-based elements, loop-based elements enter an infinite loop that looks like this: @@ -97,24 +97,24 @@ chain_function (GstPad *pad, GstBuffer *buffer) - When the request for a buffer cannot immedialty satisfied, the control - will be given to the source element of the loop-based element until it - performs a push on its source pad. At that time the control is handed back - to the loop-based element, etc... The the execution trace can get fairly - complex using cothreads when there are multiple input/output pads for the - loop-based element. + When the request for a buffer cannot immediatly satisfied, the control will be given to the + source element of the loop-based element until it performs a push on its source pad. At that + time the control is handed back to the loop-based element, etc... The the execution trace can + get fairly complex using cothreads when there are multiple input/output pads for the + loop-based element. Cothread switches are performed within the call to gst_pad_pull and + gst_pad_push; from the perspective of the loop-based element, it just "appears" that + gst_pad_push (or _pull) might take a long time to return. - Loop based elements are mainly used for the more complex elements that need a - specific amount of data before they can start to produce output. An example - of such an element is the mpeg video decoder. the element will pull a buffer, - performs some decoding on it and optionally requests more buffers to decode, when - a complete video frame has been decoded, a buffer is send out. + Loop based elements are mainly used for the more complex elements that need a specific amount + of data before they can start to produce output. An example of such an element is the mpeg + video decoder. the element will pull a buffer, performs some decoding on it and optionally + requests more buffers to decode, when a complete video frame has been decoded, a buffer is + send out. For example, any plugin using the bytestream library will need to be loop-based. - There is no problem in putting cothreaded elements into a - GstThread to create even more complex pipelines with - both user and kernel space threads. + There is no problem in putting cothreaded elements into a GstThread to + create even more complex pipelines with both user and kernel space threads. diff --git a/docs/manual/debugging.xml b/docs/manual/debugging.xml index 46980e091f..fd7a891f3b 100644 --- a/docs/manual/debugging.xml +++ b/docs/manual/debugging.xml @@ -32,6 +32,12 @@ Sets the mask for the info *and* the debug output. + + + + Print out the meaning of gst-mask-* values. + + @@ -47,16 +53,15 @@ Print the a short desciption of the - options and an overview of the current debugging/info masks - set. + options - The follwing table gives an overview of the mask values and - their meaning. (enabled) means that the corresponding flag - has been set. + The following table gives an overview of the mask values and their meaning. (enabled) means + that the corresponding flag is set by default. This table is available to any GStreamer + application by the --gst-mask-help option. Mask (to be OR'ed) info/debug FLAGS diff --git a/docs/manual/dynamic.xml b/docs/manual/dynamic.xml index 56fe4e3309..b5b190606e 100644 --- a/docs/manual/dynamic.xml +++ b/docs/manual/dynamic.xml @@ -36,10 +36,10 @@ idle_func (gpointer data) int main(int argc, char *argv[]) { - GstElement *pipeline, *src, *parse; + GstElement *pipeline, *src, *demux; + struct poptOption *gst_table; gst_init (&argc, &argv); - gnome_init ("MPEG1 Video player","0.0.1", argc, argv); pipeline = gst_pipeline_new ("pipeline"); g_return_val_if_fail (pipeline != NULL, -1); @@ -48,20 +48,18 @@ main(int argc, char *argv[]) g_return_val_if_fail (src != NULL, -1); g_object_set (G_OBJECT (src), "location", argv[1], NULL); - parse = gst_elementfactory_make ("mpeg1parse", "parse"); - g_return_val_if_fail (parse != NULL, -1); + demux = gst_elementfactory_make ("mpegdemux", "demux"); + g_return_val_if_fail (demux != NULL, -1); - gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (src)); - gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (parse)); + gst_bin_add_many (GST_BIN (pipeline), src, demux, NULL); - g_signal_connect (G_OBJECT (parse), "new_pad", + g_signal_connect (G_OBJECT (demux), "new_pad", G_CALLBACK (new_pad_created), pipeline); g_signal_connect (G_OBJECT (src), "eos", G_CALLBACK (eof), NULL); - gst_pad_connect (gst_element_get_pad (src, "src"), - gst_element_get_pad (parse, "sink")); + gst_element_connect (src, parse); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); @@ -75,20 +73,19 @@ main(int argc, char *argv[]) } - - We create two elements: a filesrc (the element that will read the - file from disk) and an mpeg1parser. We also add an EOS (End Of Stream) - signal to the filesrc so that we will be notified when the file has ended. - There's nothing special about this piece of code except for the signal - 'new_pad' that we connected to the mpeg1parser using: + + We create two elements: a file source and an MPEG demuxer.. We also add an EOS (End Of Stream) + signal to the filesrc so that we will be notified when the file has ended. There's nothing + special about this piece of code except for the signal 'new_pad' that we connected to the + mpegdemux using: - g_signal_connect (G_OBJECT (parse), "new_pad", + g_signal_connect (G_OBJECT (demux), "new_pad", G_CALLBACK (new_pad_created), pipeline); When an elementary stream has been detected in the system stream, - mpeg1parse will create a new pad that will provide the data of the + mpegdemux will create a new pad that will provide the data of the elementary stream. A function 'new_pad_created' will be called when the pad is created: @@ -96,12 +93,10 @@ main(int argc, char *argv[]) void new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline) { - GstElement *parse_audio, *parse_video, *decode, *decode_video, *play, *videoscale, *show; + GstElement *decode_audio, *parse_video, *decode_video, *play, *videoscale, *show; GstElement *audio_queue, *video_queue; GstElement *audio_thread, *video_thread; - GtkWidget *appwindow; - g_print ("***** a new pad %s was created\n", gst_pad_get_name (pad)); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED); @@ -110,38 +105,28 @@ new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline) if (strncmp (gst_pad_get_name (pad), "audio_", 6) == 0) { // construct internal pipeline elements - parse_audio = gst_elementfactory_make ("mp3parse", "parse_audio"); - g_return_if_fail (parse_audio != NULL); - decode = gst_elementfactory_make ("mpg123", "decode_audio"); + decode = gst_elementfactory_make ("mad", "decode_audio"); g_return_if_fail (decode != NULL); - play = gst_elementfactory_make ("audiosink", "play_audio"); + play = gst_elementfactory_make ("osssink", "play_audio"); g_return_if_fail (play != NULL); // create the thread and pack stuff into it audio_thread = gst_thread_new ("audio_thread"); g_return_if_fail (audio_thread != NULL); - gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (parse_audio)); - gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (decode)); - gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (play)); + gst_bin_add_many (GST_BIN (audio_thread), decode_audio, play, NULL); // set up pad connections gst_element_add_ghost_pad (GST_ELEMENT (audio_thread), - gst_element_get_pad (parse_audio, "sink")); - gst_pad_connect (gst_element_get_pad (parse_audio,"src"), - gst_element_get_pad (decode,"sink")); - gst_pad_connect (gst_element_get_pad (decode,"src"), - gst_element_get_pad (play,"sink")); + gst_element_get_pad (decode_audio, "sink")); + gst_element_connect (decode, play); // construct queue and connect everything in the main pipelie audio_queue = gst_elementfactory_make ("queue", "audio_queue"); - gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_queue)); - gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_thread)); + gst_bin_add_many (GST_BIN (pipeline), audio_queue, audio_thread, NULL); - gst_pad_connect (pad, - gst_element_get_pad (audio_queue, "sink")); - gst_pad_connect (gst_element_get_pad (audio_queue, "src"), - gst_element_get_pad (audio_thread, "sink")); + gst_pad_connect (pad, gst_element_get_pad (audio_queue, "sink")); + gst_element_connect (audio_queue, audio_thread); // set up thread state and kick things off g_print ("setting to READY state\n"); @@ -151,47 +136,31 @@ new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline) else if (strncmp (gst_pad_get_name (pad), "video_", 6) == 0) { // construct internal pipeline elements - parse_video = gst_elementfactory_make ("mp1videoparse", "parse_video"); - g_return_if_fail (parse_video != NULL); - decode_video = gst_elementfactory_make ("mpeg_play", "decode_video"); + decode_video = gst_elementfactory_make ("mpeg2dec", "decode_video"); g_return_if_fail (decode_video != NULL); - show = gst_elementfactory_make ("videosink", "show"); + show = gst_elementfactory_make ("xvideosink", "show"); g_return_if_fail (show != NULL); - appwindow = gnome_app_new ("MPEG1 player", "MPEG1 player"); - gnome_app_set_contents (GNOME_APP (appwindow), - gst_util_get_widget_arg (GTK_OBJECT (show), "widget")); - gtk_widget_show_all (appwindow); - // create the thread and pack stuff into it video_thread = gst_thread_new ("video_thread"); g_return_if_fail (video_thread != NULL); - gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (parse_video)); - gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (decode_video)); - gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (show)); + gst_bin_add_many (GST_BIN (video_thread), decode_video, show, NULL); // set up pad connections gst_element_add_ghost_pad (GST_ELEMENT (video_thread), gst_element_get_pad (parse_video, "sink")); - gst_pad_connect (gst_element_get_pad (parse_video, "src"), - gst_element_get_pad (decode_video, "sink")); - gst_pad_connect (gst_element_get_pad (decode_video, "src"), - gst_element_get_pad (show, "sink")); + gst_element_connect (decode_video, show); // construct queue and connect everything in the main pipeline video_queue = gst_elementfactory_make ("queue", "video_queue"); - gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_queue)); - gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_thread)); + gst_bin_add_many (GST_BIN (pipeline), video_queue, video_thread); - gst_pad_connect (pad, - gst_element_get_pad (video_queue, "sink")); - gst_pad_connect (gst_element_get_pad (video_queue, "src"), - gst_element_get_pad (video_thread, "sink")); + gst_pad_connect (pad, gst_element_get_pad (video_queue, "sink")); + gst_element_connect (video_queue, video_thread); // set up thread state and kick things off - g_object_set (G_OBJECT (video_thread), "create_thread", TRUE, NULL); g_print ("setting to READY state\n"); gst_element_set_state (GST_ELEMENT (video_thread), GST_STATE_READY); } @@ -199,10 +168,9 @@ new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline) gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); } - - In the above example, we created new elements based on the name of - the newly created pad. We added them to a new thread There are other possibilities to check the - type of the pad, for example, by using the MIME type and the properties - of the pad. + + In the above example, we created new elements based on the name of the newly created pad. We + then added them to a new thread. There are other possibilities to check the type of the pad, for + example by using the MIME type and the properties of the pad. diff --git a/docs/manual/elements.xml b/docs/manual/elements.xml index 5d76c1fa57..3b361dee8e 100644 --- a/docs/manual/elements.xml +++ b/docs/manual/elements.xml @@ -12,21 +12,16 @@ different components you are going to use are derived from this GstElement. This means that a lot of functions you are going to use operate on this object. - - You will see that those elements have pads. These are the elements - connections with the 'outside' world. Depending on the number and direction of - the pads, we can see three types of elements: source, filter and sink element. - - - These three types are all the same GstElement object, they just differ in how - the pads are. + Elements, from the perspective of GStreamer, are viewed as "black boxes" with a number of + different aspects. One of these aspects is the presence of "pads", or connection points. This + terminology arises from soldering; pads are where wires can be attached. - GStreamer source elements + Source elements - This element will generate data that will be used by the pipeline. It is - typically a file or an audio source. + Source elements generate data for use by a pipeline, for example reading from disk or from a + sound card. Below you see how we will visualize the element. @@ -48,19 +43,17 @@ - GStreamer filter elements + Filters and codecs - Filter elements both have an input and an output pad. They operate on data - they receive in the sink pad and send the result to the src pad. - + Filter elements both have input and output pads. They operate on data they receive in their + sink pads and produce data on their src pads. For example, MPEG decoders and volume filters + would fall into this category. + - Examples of a filter element might include: an MPEG decoder, volume filter,... - - - Filters may also contain any number of input pads and output pads. For example, - a video mixer might have to input pads (the images of the two different video - streams) and one output pad. - + Elements are not constrained as to the number of pads they migh have; for example, a video + mixer might have two input pads (the images of the two different video streams) and one + output pad. +
Visualisation of a filter element @@ -71,7 +64,7 @@
The above figure shows the visualisation of a filter element. This element has - one sink pad (input) and one src (output) pad. Sink pads are drawn on the left + one sink (input) pad and one src (output) pad. Sink pads are drawn on the left of the element.
@@ -84,21 +77,21 @@
- The above figure shows the visualisation of a filter element with more than one - output pad. An example of such a filter is the AVI splitter. This element will - parse the input data and extracts the audio and video data. Most of these filters - dynamically send out a signal when a new pad is created so that the application - programmer can connect an arbitrary element to the newly created pad. - + The above figure shows the visualisation of a filter element with more than one output pad. + An example of such a filter is the AVI splitter (demuxer). This element will parse the input + data and extracts the audio and video data. Most of these filters dynamically send out a + signal when a new pad is created so that the application programmer can connect an arbitrary + element to the newly created pad. +
- GStreamer sink elements - - This element accepts data but will not generate any new data. A sink element - is typically a file on disk, a soundcard, a display,... It is presented as - below: - + Sink elements + + Sink elements are terminal points in a media pipeline. They accept data but do not produce + anything. Disk writing, soundcard playback, and video output woul all be implemented by sink + elements. +
Visualisation of a sink element @@ -117,12 +110,12 @@ The following code example is used to get a factory that can be used to create the - mpg123 element, an mp3 decoder. + 'mad' element, an mp3 decoder. GstElementFactory *factory; - factory = gst_elementfactory_find ("mpg123"); + factory = gst_elementfactory_find ("mad"); Once you have the handle to the elementfactory, you can create a real element with @@ -133,23 +126,23 @@ element = gst_elementfactory_create (factory, "decoder"); - - gst_elementfactory_create () will use the elementfactory to create an element with the - given name. The name of the element is something you can use later on to lookup the - element in a bin, for example. - - - A simple shortcut exists for creating an element from a factory. The following example - creates an element, named "decoder" from the elementfactory named "mpg123". This - convenient function is most widly used to create an element. - + + gst_elementfactory_create () will use the elementfactory to create an element with the given + name. The name of the element is something you can use later on to lookup the element in a + bin, for example. You can pass NULL as the name argument to get a unique, default name. + + + A simple shortcut exists for creating an element from a factory. The following example creates + an element, named "decoder" from the elementfactory named "mad". This convenient function is + most widely used to create an element. + GstElement *element; - element = gst_elementfactory_make ("mpg123", "decoder"); + element = gst_elementfactory_make ("mad", "decoder"); - An element can be destroyed with: + An element can be destroyed with: FIXME talk about refcounting GstElement *element; diff --git a/docs/manual/factories.xml b/docs/manual/factories.xml index c5b89e1101..eb7d5c70d3 100644 --- a/docs/manual/factories.xml +++ b/docs/manual/factories.xml @@ -21,28 +21,27 @@ ... /* now it's time to get the parser */ - parse = gst_elementfactory_make ("mp3parse", "parse"); - decoder = gst_elementfactory_make ("mpg123", "decoder"); + decoder = gst_elementfactory_make ("mad", "decoder"); ... While this mechanism is quite effective it also has some big problems: The elements are created based on their name. Indeed, we create an - element mpg123 by explicitly stating the mpg123 elements name. - Our little program therefore always uses the mpg123 decoder element + element mad by explicitly stating the mad element's name. + Our little program therefore always uses the mad decoder element to decode the MP3 audio stream, even if there are 3 other MP3 decoders in the system. We will see how we can use a more general way to create an MP3 decoder element. - We have to introduce the concept of MIME types and capabilities + We have to introduce the concept of MIME types and capabilities added to the source and sink pads. - more on MIME Types + More on MIME Types GStreamer uses MIME types to indentify the different types of data that can be handled by the elements. They are the high level @@ -124,9 +123,9 @@ a function that can be used to determine if a given buffer is of the given MIME type. - - There is also an association between a MIME type and a file - extension. + + There is also an association between a MIME type and a file extension, but the use of typefind + functions (similar to file(1)) is preferred.. The type information is maintained in a list of @@ -202,86 +201,9 @@ struct _GstType { This function will return 0 if the extension was not known. - - - id to <classname>GstElementFactory</classname> conversion - - When we have obtained a given type id using one of the above methods, - we can obtain a list of all the elements that operate on this MIME - type or extension. - - - Obtain a list of all the elements that use this id as source with: - - - GList *list; - - list = gst_type_gst_srcs (id); - - - - Obtain a list of all the elements that use this id as sink with: - - - GList *list; - - list = gst_type_gst_sinks (id); - - - When you have a list of elements, you can simply take the first - element of the list to obtain an appropriate element. - - - - As you can see, there might be a multitude of elements that - are able to operate on audio/raw types. some might include: - - - - an MP3 audio encoder. - - - - - an audio sink. - - - - - an audio resampler. - - - - - a spectrum filter. - - - - Depending on the application, you might want to use a different - element. This is why GStreamer leaves that decision up to the - application programmer. - - - - - - - id to id path detection - - You can obtain a GList of elements that - will transform the source id into the destination id. - - - GList *list; - - list = gst_type_gst_sink_to_src (sourceid, sinkid); - - - This piece of code will give you the elements needed to construct - a path from sourceid to sinkid. This function is mainly used in - autoplugging the pipeline. - - + + For more information, see . + diff --git a/docs/manual/goals.xml b/docs/manual/goals.xml index f8c5225dff..f699face74 100644 --- a/docs/manual/goals.xml +++ b/docs/manual/goals.xml @@ -38,11 +38,11 @@ Object oriented - Adhere as much as possible to the glib2.0 object model. A programmer familiar - with glib2 and GTK+ will be confortable with GStreamer. - + Adhere to the GLib 2.0 object model. A programmer familiar with GLib 2.0 or older versions + of Gtk+ will be comfortable with GStreamer. + - GStreamer uses the mechanism of signals and object arguments. + GStreamer uses the mechanism of signals and object properties. All objects can be queried at runtime for their various properties and @@ -53,7 +53,7 @@ Extensible - All GStreamer Objects can be extended using the glib2 inheritance methods. + All GStreamer Objects can be extended using the GObject inheritance methods. All plugins are loaded dynamically and can be extended and upgraded @@ -63,15 +63,14 @@ Allow binary only plugins - - plugins are shared libraries that are loaded at runtime. since all the - properties of the plugin can be set using the GObject properties, there - is no need to have any header files installed for the plugins. - + + Plugins are shared libraries that are loaded at runtime. Since all the properties of the + plugin can be set using the GObject properties, there is no need (and in fact no way) to + have any header files installed for the plugins. + Special care has been taking into making the plugin completely self - contained. This is in the operations, specification of the capabilities - of the plugin and properties. + contained. All relevant aspects of plugins can be queried at run-time. @@ -83,44 +82,43 @@ - Using glib g_mem_chunk where possible to minimize dynamic memory + Using GLib g_mem_chunk where possible to minimize dynamic memory allocation. - Connections between plugins are extremely light-weight. Data can travel + Extremely light-weight connections between plugins. Data can travel the pipeline with minimal overhead. - Provide a mechanism to directly work on the target memory. A - plugin can for example directly write to the X servers shared mem. - Buffers can also point to arbitrary memory like kernel memory. + Providing a mechanism to directly work on the target memory. A plugin can for example + directly write to the X server's shared memory space. Buffers can also point to + arbitrary memory, such as a sound card's internal hardware buffer. - Refcounting and copy on write to minimize the amount of memcpy. - Subbufers to efficiently split the data in a buffer. + Refcounting and copy on write minimize usage of memcpy(3). + Sub-buffers efficiently split buffers into manageable pieces. - Pipelines can be constructed using cothreads to minimize the - threading overhead. Cothreads are a simple user-space method for - switching between subtasks. + The use of cothreads to minimize the threading overhead. Cothreads are a simple and fast + user-space method for switching between subtasks. - HW acceleration is possible by writing a specialized plugin. + Allowing HW acceleration by the use of specialized plugins. - Uses a plugin registry with the specifications of the plugins so + Using a plugin registry with the specifications of the plugins so that the plugin loading can be delayed until the plugin is actually used. diff --git a/docs/manual/gstreamer-manual.xml b/docs/manual/gstreamer-manual.xml index f4dd80fda2..4a88755284 100644 --- a/docs/manual/gstreamer-manual.xml +++ b/docs/manual/gstreamer-manual.xml @@ -61,6 +61,15 @@ + + Andy + Wingo + + + wingo@pobox.com + + + @@ -81,15 +90,14 @@ Overview - - The first chapter of the book gives you an overview of GStreamer - design goals. Chapter 2 rapidly covers the basics of GStreamer - programming. In chapter 3 we will move on to the examples. - Since GStreamer adheres to the GTK+/glib2 programming model, the reader is - assumed to understand the basics of GTK+ and the glib2.0 object model. - For a gentle introduction to GTK+, you may wish to read the GTK+ - Tutorial or Eric Harlow's book Developing Linux - Applications with GTK+ and GDK. + + gives you an overview of GStreamer + design goals. rapidly covers the basics of + GStreamer programming. In we will move + on to the examples. Since GStreamer uses GLib 2.0, the reader is + assumed to understand the basics of the GObject object model. For a gentle introduction to + this system, you may wish to read the GTK+ Tutorial or Eric Harlow's + book Developing Linux Applications with GTK+ and GDK. @@ -186,8 +194,6 @@ &HELLOWORLD2; &DPARAMS; - - &UTILITY; @@ -196,10 +202,10 @@ - GStreamer has the posibility to externalize the pipelines - you create using an XML format. You can load a previously - created pipeline by loading the XML file. - + GStreamer has the possibility to serialize the pipelines you + create using an XML format. You can load a previously created pipeline by loading the XML + file. + &XML; diff --git a/docs/manual/helloworld.xml b/docs/manual/helloworld.xml index 8fe65276c6..6072152e14 100644 --- a/docs/manual/helloworld.xml +++ b/docs/manual/helloworld.xml @@ -8,13 +8,12 @@ Hello world - - We will create a simple first application. In fact it will be a complete - MP3 player, using standard GStreamer components. The player will read from - a file that is given as the first argument of the program. + + We will create a simple first application, a complete MP3 player, using standard + GStreamer components. The player will read from a file that is + given as the first argument of the program. - #include <gst/gst.h> @@ -45,15 +44,10 @@ main (int argc, char *argv[]) audiosink = gst_elementfactory_make ("osssink", "play_audio"); /* add objects to the main pipeline */ - gst_bin_add (GST_BIN (pipeline), filesrc); - gst_bin_add (GST_BIN (pipeline), decoder); - gst_bin_add (GST_BIN (pipeline), audiosink); + gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL); /* connect src to sink */ - gst_pad_connect (gst_element_get_pad (filesrc, "src"), - gst_element_get_pad (decoder, "sink")); - gst_pad_connect (gst_element_get_pad (decoder, "src"), - gst_element_get_pad (audiosink, "sink")); + gst_element_connect_many (filesrc, decoder, audiosink, NULL); /* start playing */ gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -64,10 +58,8 @@ main (int argc, char *argv[]) gst_element_set_state (pipeline, GST_STATE_NULL); /* we don't need a reference to these objects anymore */ - gst_object_unref (GST_OBJECT (audiosink)); - gst_object_unref (GST_OBJECT (decoder)); - gst_object_unref (GST_OBJECT (filesrc)); gst_object_unref (GST_OBJECT (pipeline)); + /* unreffing the pipeline unrefs the contained elements as well */ exit (0); } @@ -98,8 +90,8 @@ main (int argc, char *argv[]) - We are going to create 3 elements and one pipeline. Since all objects are - in fact elements, we can define them as: + We are going to create 3 elements and one pipeline. Since all elements share the same base + type, GstElement, we can define them as: ... @@ -142,7 +134,7 @@ main (int argc, char *argv[]) is installed on the system where this application is executed. - /* now it's time to get the parser */ + /* now it's time to get the decoder */ decoder = gst_elementfactory_make ("mad", "decoder"); @@ -167,9 +159,7 @@ main (int argc, char *argv[]) /* add objects to the main pipeline */ - gst_bin_add (GST_BIN (pipeline), filesrc); - gst_bin_add (GST_BIN (pipeline), decoder); - gst_bin_add (GST_BIN (pipeline), audiosink); + gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL); @@ -177,10 +167,7 @@ main (int argc, char *argv[]) /* connect src to sink */ - gst_pad_connect (gst_element_get_pad (filesrc, "src"), - gst_element_get_pad (decoder, "sink")); - gst_pad_connect (gst_element_get_pad (decoder, "src"), - gst_element_get_pad (audiosink, "sink")); + gst_element_connect_many (filesrc, decoder, audiosink, NULL); @@ -229,16 +216,13 @@ main (int argc, char *argv[]) /* stop the pipeline */ gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (audiosink)); - gst_object_unref (GST_OBJECT (decoder)); - gst_object_unref (GST_OBJECT (filesrc)); gst_object_unref (GST_OBJECT (pipeline)); exit (0); - don't forget to set the state of the pipeline to NULL. This will free + Don't forget to set the state of the pipeline to NULL. This will free all of the resources held by the elements. @@ -246,7 +230,7 @@ main (int argc, char *argv[]) - compiling helloworld.c + Compiling helloworld.c To compile the helloworld example, use: @@ -268,10 +252,10 @@ main (int argc, char *argv[]) - conclusion + Conclusion This concludes our first example. As you see, setting up a pipeline - is very lowlevel but powerfull. You will later in this manual how + is very lowlevel but powerful. You will later in this manual how you can create a custom MP3 element with a more high level API. @@ -284,7 +268,7 @@ main (int argc, char *argv[]) We could use a disksink to write the raw samples to a file, for example. It should also be clear that inserting filters, like a stereo effect, into the pipeline is not that hard to do. The most important thing is - that you can reuse allready existing elements. + that you can reuse already existing elements. diff --git a/docs/manual/helloworld2.xml b/docs/manual/helloworld2.xml index ba3b6dc81a..0234aaef62 100644 --- a/docs/manual/helloworld2.xml +++ b/docs/manual/helloworld2.xml @@ -1,8 +1,8 @@ Your second application - - In a previous chapter we created a first version of the helloworld - application. We then explained a better way of creating the elements + + FIXME: delete this section, talk more about the spider. In a previous chapter we created a first + version of the helloworld application. We then explained a better way of creating the elements using factories identified by MIME types and the autoplugger. @@ -35,7 +35,7 @@ main (int argc, char *argv[]) gst_init (&argc, &argv); if (argc != 2) { - g_print ("usage: %s <filename>\n", argv[0]); + g_print ("usage: %s <filename>\n", argv[0]); exit (-1); } diff --git a/docs/manual/highlevel-components.xml b/docs/manual/highlevel-components.xml index a4272342f8..0c5923f782 100644 --- a/docs/manual/highlevel-components.xml +++ b/docs/manual/highlevel-components.xml @@ -1,5 +1,10 @@ Components + + + FIXME: This chapter is way out of date. + + GStreamer includes components that people can include in their programs. diff --git a/docs/manual/init.xml b/docs/manual/init.xml index 985dcc2149..bae542d747 100644 --- a/docs/manual/init.xml +++ b/docs/manual/init.xml @@ -34,5 +34,29 @@ main (int argc, char *argv[]) Use the GST_VERSION_MAJOR, GST_VERSION_MINOR and GST_VERSION_MICRO macros to get the GStreamer version you are building against. + + The popt interface + + more info here + + +int +main(int argc, char *argv[]) +{ + gboolean silent = FALSE; + gchar *savefile = NULL; + struct poptOption options[] = { + {"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0, + "do not output status information", NULL}, + {"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0, + "save xml representation of pipeline to FILE and exit", "FILE"}, + POPT_TABLEEND + }; + + gst_init_with_popt_table (&argc, &argv, options); + + ... + + diff --git a/docs/manual/intro-motivation.xml b/docs/manual/intro-motivation.xml index 1ba996f8d5..69ea414d90 100644 --- a/docs/manual/intro-motivation.xml +++ b/docs/manual/intro-motivation.xml @@ -80,7 +80,7 @@ No provisions have been made for emerging technologies such as - the GNOME object embedding using BONOBO. + the GNOME object embedding using Bonobo. While the GStreamer core does not use network transparent technologies diff --git a/docs/manual/intro-preface.xml b/docs/manual/intro-preface.xml index 208c25ee91..5c45bfc31d 100644 --- a/docs/manual/intro-preface.xml +++ b/docs/manual/intro-preface.xml @@ -23,11 +23,11 @@ GStreamer, however, is much more than just another media player. Its main advantages are that the pluggable components also make it possible - to write a full flegded video or audio editing application. + to write a full fledged video or audio editing application. - The framework is based on plug-ins that will provide the various codec + The framework is based on plugins that will provide the various codec and other functionality. The plugins can be connected and arranged in a pipeline. This pipeline defines the flow of the data. Pipelines can also be edited with a GUI editor and saved as XML so that pipeline diff --git a/docs/manual/intro.xml b/docs/manual/intro.xml index 208c25ee91..5c45bfc31d 100644 --- a/docs/manual/intro.xml +++ b/docs/manual/intro.xml @@ -23,11 +23,11 @@ GStreamer, however, is much more than just another media player. Its main advantages are that the pluggable components also make it possible - to write a full flegded video or audio editing application. + to write a full fledged video or audio editing application. - The framework is based on plug-ins that will provide the various codec + The framework is based on plugins that will provide the various codec and other functionality. The plugins can be connected and arranged in a pipeline. This pipeline defines the flow of the data. Pipelines can also be edited with a GUI editor and saved as XML so that pipeline diff --git a/docs/manual/motivation.xml b/docs/manual/motivation.xml index 1ba996f8d5..69ea414d90 100644 --- a/docs/manual/motivation.xml +++ b/docs/manual/motivation.xml @@ -80,7 +80,7 @@ No provisions have been made for emerging technologies such as - the GNOME object embedding using BONOBO. + the GNOME object embedding using Bonobo. While the GStreamer core does not use network transparent technologies diff --git a/docs/manual/pads.xml b/docs/manual/pads.xml index 36bd02184c..953367a6d1 100644 --- a/docs/manual/pads.xml +++ b/docs/manual/pads.xml @@ -1,7 +1,7 @@ GstPad - As we have seen in the previous chapter (GstElement), the pads are the elements + As we have seen in the previous chapter (GstElement), the pads are the element's connections with the outside world. @@ -44,7 +44,7 @@ Useful pad functions You can get the name of a pad with gst_pad_get_name () and set its name with - get_pad_set_name(); + get_pad_set_name(). gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink @@ -53,8 +53,8 @@ You can get the parent of the pad, this is the element that this pad belongs to, - with get_pad_set_parent(GstPad *pad). This function will return a pointer to a - GstObject. + with get_pad_get_parent(GstPad *pad). This function will return a pointer to a + GstElement. @@ -63,10 +63,10 @@ Some elements might not have their pads when they are created. This can, for example, happen with an MPEG2 system demuxer. The demuxer will create its pads at runtime when it detects the different elementary streams in the MPEG2 - system stream. + system stream. - Running gstreamer-inspect mpeg2parse will show that + Running gst-inspect mpegdemux will show that the element has only one pad: a sink pad called 'sink'. The other pads are "dormant" as you can see in the padtemplates from the 'Exists: Sometimes' property. Depending on the type of MPEG2 file you play, the pads are created. We @@ -104,7 +104,7 @@ main(int argc, char *argv[]) // create pipeline and do something usefull ... - mpeg2parser = gst_elementfactory_make ("mpeg2parse", "mpeg2parse"); + mpeg2parser = gst_elementfactory_make ("mpegdemux", "mpegdemux"); g_signal_connect (G_OBJECT (mpeg2parser), "new_pad", pad_connect_func, pipeline); ... @@ -141,19 +141,19 @@ main(int argc, char *argv[]) ... element = gst_elementfactory_make ("tee", "element"); - pad = gst_element_request_pad_by_name (element, "src%d"); + pad = gst_element_get_request_pad (element, "src%d"); g_print ("new pad %s\n", gst_pad_get_name (pad)); ... - The gst_element_request_pad_by_name method can be used to get a pad + The gst_element_get_request_pad method can be used to get a pad from the element based on the name_template of the padtemplate. It is also possible to request a pad that is compatible with another padtemplate. This is very usefull if you want to connect an element to a muxer element and you need to request a pad that is compatible. The - gst_element_request_compatible_pad is used to request a compatible pad, as + gst_element_get_compatible_pad is used to request a compatible pad, as is shown in the next example. @@ -162,11 +162,11 @@ main(int argc, char *argv[]) GstPad *pad; ... element = gst_elementfactory_make ("tee", "element"); - mp3parse = gst_elementfactory_make ("mp3parse", "mp3parse"); + mad = gst_elementfactory_make ("mad", "mad"); - templ = gst_element_get_padtemplate_by_name (mp3parse, "sink"); + templ = gst_element_get_padtemplate_by_name (mad, "sink"); - pad = gst_element_request_compatible_pad (element, templ); + pad = gst_element_get_compatible_pad (element, templ); g_print ("new pad %s\n", gst_pad_get_name (pad)); ... @@ -181,7 +181,7 @@ main(int argc, char *argv[]) We will briefly describe what capabilities are, enough for you to get a basic understanding of the concepts. You will find more information on how to create capabilities in the - filter-writer-guide. + Plugin Writer's Guide. @@ -207,8 +207,8 @@ struct _GstCaps { }; - Below is a dump of the capabilities of the element mpg123, as shown by - gstreamer-inspect. + Below is a dump of the capabilities of the element mad, as shown by + gst-inspect. You can see two pads: sink and src. Both pads have capability information attached to them. @@ -221,26 +221,25 @@ struct _GstCaps { Pads: - SINK: 'sink' - .... - Capabilities: - 'mpg123_sink': - MIME type: 'audio/mp3': - layer: Integer range: 1 - 3 - bitrate: Integer range: 8 - 320 - framed: Boolean: TRUE - - SRC: 'src' - .... + SINK template: 'sink' + Availability: Always Capabilities: - 'mpg123_src': - MIME type: 'audio/raw': - format: Integer: 16 - depth: Integer: 16 - rate: Integer range: 11025 - 48000 - channels: List: - Integer: 1 - Integer: 2 + 'mad_sink': + MIME type: 'audio/mp3': + + SRC template: 'src' + Availability: Always + Capabilities: + 'mad_src': + MIME type: 'audio/raw': + format: String: int + endianness: Integer: 1234 + width: Integer: 16 + depth: Integer: 16 + channels: Integer range: 1 - 2 + law: Integer: 0 + signed: Boolean: TRUE + rate: Integer range: 11025 - 48000 @@ -260,7 +259,7 @@ Pads: An integer range value. The property denotes a range of possible values. In the case - of the mpg123 element: the src pad has a property rate that can go from 11025 to 48000. + of the mad element: the src pad has a property rate that can go from 11025 to 48000. @@ -349,7 +348,7 @@ Pads: As we said, a capability has a name, a mime-type and some properties. The signature of the - function to create a new GstCaps * structure is like: + function to create a new GstCaps structure is like: GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props); diff --git a/docs/manual/plugins.xml b/docs/manual/plugins.xml index a89d9cb908..a8fa76abba 100644 --- a/docs/manual/plugins.xml +++ b/docs/manual/plugins.xml @@ -20,6 +20,11 @@ one or more autopluggers + + + exported symbols for use in other plugins + + The plugins have one simple method: plugin_init () where all the elementfactories are diff --git a/docs/manual/programs.xml b/docs/manual/programs.xml index 28a1c17911..7f57334bba 100644 --- a/docs/manual/programs.xml +++ b/docs/manual/programs.xml @@ -4,38 +4,35 @@ - <command>gstreamer-register</command> + <command>gst-register</command> - gstreamer-register is used to rebuild the database of plugins. + gst-register is used to rebuild the database of plugins. It is used after a new plugin has been added to the system. The plugin database - can be found in /etc/gstreamer/reg.xml. + can be found, by default, in /etc/gstreamer/reg.xml. - <command>gstreamer-launch</command> + <command>gst-launch</command> This is a tool that will construct pipelines based on a command-line - syntax. + syntax. FIXME: need a more extensive grammar reference A simple commandline looks like: -gstreamer-launch filesrc location=hello.mp3 ! mp3parse ! mpg123 ! audiosink +gst-launch filesrc location=hello.mp3 ! mad ! osssink A more complex pipeline looks like: -gstreamer-launch filesrc redpill.vob audio_00! (ac3parse ! ac3dec ! audiosink) \ -video_00! (mpeg2dec ! videosink) +gst-launch filesrc location=redpill.vob ! mpegdemux name=demux \ + demux.audio_00! { ac3parse ! a52dec ! osssink } \ + demux.video_00! { mpeg2dec ! xvideosink } - - - Note that the parser isn't capable of more complex pipelines yet, including - the VOB player above. The minor tweaks will be made post 0.2.1. You can also use the the parser in you own code. GStreamer @@ -51,17 +48,21 @@ main (int argc, char *argv[]) { GstElement *pipeline; GstElement *filesrc; + GError *error = NULL; gst_init (&argc, &argv); if (argc != 2) { - g_print ("usage: %s <filename>\n", argv[0]); + g_print ("usage: %s <filename>\n", argv[0]); return -1; } - pipeline = gst_pipeline_new ("my_pipeline"); - - gst_parse_launch ("filesrc[my_filesrc] ! mp3parse ! mpg123 ! osssink", GST_BIN (pipeline)); + pipeline = gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error); + if (!pipeline) { + g_print ("Parse error: %s\n", error->message); + exit (1); + } + filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); @@ -81,20 +82,20 @@ main (int argc, char *argv[]) - <command>gstreamer-inspect</command> + <command>gst-inspect</command> This is a tool to query a plugin or an element about its properties. - To query the information about the element mpg123, you would specify: + To query the information about the element mad, you would specify: -gstreamer-inspect mpg123 +gst-inspect mad - Below is the output of a query for the audiosink element: + Below is the output of a query for the osssink element: @@ -102,56 +103,72 @@ Factory Details: Long name: Audio Sink (OSS) Class: Sink/Audio Description: Output to a sound card via OSS - Version: 0.1.0 - Author(s): Erik Walthinsen <omega@cse.ogi.edu> + Version: 0.3.3.1 + Author(s): Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim.taymans@chello.be> Copyright: (C) 1999 +GObject + +----GstObject + +----GstElement + +----GstOssSink + Pad Templates: SINK template: 'sink' - Exists: Always + Availability: Always Capabilities: - 'audiosink_sink': + 'osssink_sink': MIME type: 'audio/raw': - format: Integer: 16 + format: String: int + endianness: Integer: 1234 + width: List: + Integer: 8 + Integer: 16 depth: List: Integer: 8 Integer: 16 - rate: Integer range: 8000 - 48000 channels: Integer range: 1 - 2 + law: Integer: 0 + signed: List: + Boolean: FALSE + Boolean: TRUE + rate: Integer range: 1000 - 48000 + Element Flags: GST_ELEMENT_THREADSUGGESTED - no flags set Element Implementation: No loopfunc(), must be chain-based or not configured yet - Has change_state() function + Has change_state() function: gst_osssink_change_state + Has custom save_thyself() function: gst_element_save_thyself + Has custom restore_thyself() function: gst_element_restore_thyself + +Clocking Interaction: + element requires a clock + element provides a clock: GstOssClock Pads: SINK: 'sink' Implementation: - Has chainfunc(): 0x4001cde8 - Has default eosfunc() gst_pad_eos_func() + Has chainfunc(): 0x40056fc0 Pad Template: 'sink' - Capabilities: - 'audiosink_sink': - MIME type: 'audio/raw': - format: Integer: 16 - depth: List: - Integer: 8 - Integer: 16 - rate: Integer range: 8000 - 48000 - channels: Integer range: 1 - 2 Element Arguments: - GstAudioSink::mute: Boolean - GstAudioSink::format: Enum (default 16) - (8): 8 Bits - (16): 16 Bits - GstAudioSink::channels: Enum (default 2) + name : String (Default "element") + device : String (Default "/dev/dsp") + mute : Boolean (Default false) + format : Integer (Default 16) + channels : Enum "GstAudiosinkChannels" (default 1) + (0): Silence (1): Mono (2): Stereo - GstAudioSink::frequency: Integer + frequency : Integer (Default 11025) + fragment : Integer (Default 6) + buffer-size : Integer (Default 4096) + +Element Signals: + "handoff" : void user_function (GstOssSink* object, + gpointer user_data); @@ -159,11 +176,11 @@ Element Arguments: -gstreamer-inspect gstelements +gst-inspect gstelements - <command>gstmediaplay</command> + <command>gst-play</command> A sample media player. diff --git a/docs/manual/states.xml b/docs/manual/states.xml index 28064055dc..d603190730 100644 --- a/docs/manual/states.xml +++ b/docs/manual/states.xml @@ -146,7 +146,7 @@ The pipeline has to be in the PAUSED or NULL state if you want to insert or modify an element - in the pipeline. We will cover dynamic pipeline behaviour in ... + in the pipeline. We will cover dynamic pipeline behaviour in . diff --git a/docs/manual/threads.xml b/docs/manual/threads.xml index 77680e2cdd..f9b00b96b3 100644 --- a/docs/manual/threads.xml +++ b/docs/manual/threads.xml @@ -1,7 +1,7 @@ Threads - GStreamer has support for multithreading throught the use of + GStreamer has support for multithreading through the use of the GstThread object. This object is in fact a special GstBin that will become a thread when started. @@ -13,39 +13,58 @@ GstElement *my_thread; - // create the thread object + /* create the thread object */ my_thread = gst_thread_new ("my_thread"); - g_return_if_fail (audio_thread != NULL); + /* you could have used gst_elementfactory_make ("thread", "my_thread"); */ + g_return_if_fail (my_thread != NULL); - // add some plugins + /* add some plugins */ gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (funky_src)); gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect)); - // connect the elements here... + /* connect the elements here... */ ... - // start playing + /* start playing */ gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING); - - The above program will create a thread with two elements in it. As soon - as it is set to the PLAYING state, the thread will start to iterate. + + The above program will create a thread with two elements in it. As soon as it is set to the + PLAYING state, the thread will start to iterate itself. You never need to manually iterate a + thread. - - - A thread should normally contain a source element. Most often, the thread - is fed with data from a queue. - - - + + Constraints placed on the pipeline by the GstThread + + Within the pipeline, everything is the same as in any other bin. The difference lies at the + thread boundary, at the connection between the thread and the outside world (containing bin). + Since GStreamer is fundamentally buffer-oriented rather than byte-oriented, the natural + solution to this problem is an element that can "buffer" the buffers between the threads, in a + thread-safe fashion. This element is the queue, described more fully in . It doesn't matter if the queue is placed in the containing bin or in + the thread itself, but it needs to be present on one side of the other to enable inter-thread + communication. + + + + When would you want to use a thread? + + If you are writing a GUI application, making the top-level bin a thread will make your GUI + more responsive. If it were a pipeline instead, it would have to be iterated by your + application's event loop, which increases the latency between events (say, keyboard presses) + and responses from the GUI. In addition, any slight hang in the GUI would delay iteration of + the pipeline, which (for example) could cause pops in the output of the sound card, if it is + an audio pipeline. + + - A thread will be visualised as below + A thread can be visualised as below
- a thread + A thread diff --git a/docs/manual/utility.xml b/docs/manual/utility.xml deleted file mode 100644 index 2bc6504af4..0000000000 --- a/docs/manual/utility.xml +++ /dev/null @@ -1,90 +0,0 @@ - - Utility functions - - while you can use the regular g_object_getv () function to - query the value of an object property, GStreamer - provides some easy wrappers for this common operation. - - - Instead of writing the following glib code to query the GTK_STRING value - of an object: - - - GtkArg arg; - guchar *value; - - arg.name = argname; - g_object_getv (G_OBJECT (object), 1, &arg); - value = GTK_VALUE_STRING (arg); - - - You can also use: - - - value = gst_util_get_string_arg (object, argname); - - - These convenience functions exist for the following types: - - - - gint: with gst_util_get_int_arg (); - - - - - gboolean: with gst_util_get_bool_arg (); - - - - - glong: with gst_util_get_long_arg (); - - - - - gfloat: with gst_util_get_float_arg (); - - - - - gdouble: with gst_util_get_double_arg (); - - - - - guchar*: with gst_util_get_string_arg (); - - - - - gpointer: with gst_util_get_pointer_arg (); - - - - - - One usually sets object properties using g_object_set (). The problem with this - method is that you need to know the type of the property. A convenience function, - gst_utils_set_object_arg () is therefore provided so that you can always set - the property with a string value. for example: - - - gst_util_set_object_arg (someobject, "int_property", "1000"); - - - Will do The Right Thing(tm), converting the string to the type of the property when - needed. - - - - There is also another utility function that can be used to dump a block - of memory on the console. This function is very usefull for plugin - developers. The function will dump size bytes of the memory pointed - to by mem. - - - void gst_util_dump_mem (guchar *mem, guint size); - - - diff --git a/examples/autoplug/autoplug.c b/examples/autoplug/autoplug.c index 0848636555..1f7ae4f36b 100644 --- a/examples/autoplug/autoplug.c +++ b/examples/autoplug/autoplug.c @@ -19,22 +19,22 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); /* disconnect the typefind from the pipeline and remove it */ - gst_element_disconnect (cache, "src", typefind, "sink"); + gst_element_disconnect_pads (cache, "src", typefind, "sink"); gst_bin_remove (GST_BIN (autobin), typefind); /* and an audio sink */ - osssink = gst_elementfactory_make("osssink", "play_audio"); - g_assert(osssink != NULL); + osssink = gst_elementfactory_make ("osssink", "play_audio"); + g_assert (osssink != NULL); videosink = gst_bin_new ("videosink"); /* and an video sink */ - videoelement = gst_elementfactory_make("xvideosink", "play_video"); - g_assert(videosink != NULL); + videoelement = gst_elementfactory_make ("xvideosink", "play_video"); + g_assert (videosink != NULL); - colorspace = gst_elementfactory_make("colorspace", "colorspace"); - g_assert(colorspace != NULL); + colorspace = gst_elementfactory_make ("colorspace", "colorspace"); + g_assert (colorspace != NULL); - gst_element_connect (colorspace, "src", videoelement, "sink"); + gst_element_connect_pads (colorspace, "src", videoelement, "sink"); gst_bin_add (GST_BIN (videosink), colorspace); gst_bin_add (GST_BIN (videosink), videoelement); @@ -61,7 +61,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) g_object_set (G_OBJECT (cache), "reset", TRUE, NULL); - gst_element_connect (cache, "src", new_element, "sink"); + gst_element_connect_pads (cache, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -87,10 +87,9 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline) cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); - gst_element_disconnect (filesrc, "src", cache, "sink"); - gst_element_disconnect (cache, "src", new_element, "sink"); + gst_element_disconnect_many (filesrc, cache, new_element, NULL); gst_bin_remove (GST_BIN (autobin), cache); - gst_element_connect (filesrc, "src", new_element, "sink"); + gst_element_connect_pads (filesrc, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -132,14 +131,14 @@ int main(int argc,char *argv[]) gst_bin_add (GST_BIN (autobin), cache); gst_bin_add (GST_BIN (autobin), typefind); - gst_element_connect (cache, "src", typefind, "sink"); + gst_element_connect_pads (cache, "src", typefind, "sink"); gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink"); gst_bin_add (GST_BIN( pipeline), autobin); - gst_element_connect (filesrc, "src", autobin, "sink"); + gst_element_connect_pads (filesrc, "src", autobin, "sink"); /* start playing */ - gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING); + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); diff --git a/examples/helloworld/helloworld.c b/examples/helloworld/helloworld.c index d82d7157d5..67105949da 100644 --- a/examples/helloworld/helloworld.c +++ b/examples/helloworld/helloworld.c @@ -22,7 +22,7 @@ int main (int argc, char *argv[]) g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); /* now it's time to get the decoder */ - decoder = gst_elementfactory_make ("mad", "parse"); + decoder = gst_elementfactory_make ("mad", "decode"); if (!decoder) { g_print ("could not find plugin \"mad\""); return -1; @@ -35,7 +35,7 @@ int main (int argc, char *argv[]) gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL); /* connect the elements */ - gst_element_connect_elements_many (filesrc, decoder, osssink, NULL); + gst_element_connect_many (filesrc, decoder, osssink, NULL); /* start playing */ gst_element_set_state (bin, GST_STATE_PLAYING); diff --git a/examples/helloworld2/helloworld2.c b/examples/helloworld2/helloworld2.c index e36b74cb5d..4fa7e72826 100644 --- a/examples/helloworld2/helloworld2.c +++ b/examples/helloworld2/helloworld2.c @@ -18,8 +18,8 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); - /* disconnect the typefind from the pipeline and remove it */ - gst_element_disconnect (cache, "src", typefind, "sink"); + /* disconnect_pads the typefind from the pipeline and remove it */ + gst_element_disconnect_pads (cache, "src", typefind, "sink"); gst_bin_remove (GST_BIN (autobin), typefind); /* and an audio sink */ @@ -45,7 +45,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) g_object_set (G_OBJECT (cache), "reset", TRUE, NULL); - gst_element_connect (cache, "src", new_element, "sink"); + gst_element_connect_pads (cache, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); } @@ -67,10 +67,10 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline) cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); - gst_element_disconnect (filesrc, "src", cache, "sink"); - gst_element_disconnect (cache, "src", new_element, "sink"); + gst_element_disconnect_pads (filesrc, "src", cache, "sink"); + gst_element_disconnect_pads (cache, "src", new_element, "sink"); gst_bin_remove (GST_BIN (autobin), cache); - gst_element_connect (filesrc, "src", new_element, "sink"); + gst_element_connect_pads (filesrc, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -114,11 +114,11 @@ main (int argc, char *argv[]) gst_bin_add (GST_BIN (autobin), cache); gst_bin_add (GST_BIN (autobin), typefind); - gst_element_connect (cache, "src", typefind, "sink"); + gst_element_connect_pads (cache, "src", typefind, "sink"); gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink"); gst_bin_add (GST_BIN( pipeline), autobin); - gst_element_connect (filesrc, "src", autobin, "sink"); + gst_element_connect_pads (filesrc, "src", autobin, "sink"); /* start playing */ gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING); diff --git a/examples/launch/mp3parselaunch.c b/examples/launch/mp3parselaunch.c index 345cff3d45..5489b2652d 100644 --- a/examples/launch/mp3parselaunch.c +++ b/examples/launch/mp3parselaunch.c @@ -5,6 +5,7 @@ main (int argc, char *argv[]) { GstElement *pipeline; GstElement *filesrc; + GError *error = NULL; gst_init (&argc, &argv); @@ -13,8 +14,12 @@ main (int argc, char *argv[]) return -1; } - pipeline = (GstElement*) gst_parse_launch ("filesrc [ my_filesrc ] ! mad ! osssink"); - + pipeline = (GstElement*) gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error); + if (!pipeline) { + fprintf (stderr, "Parse error: %s", error->message); + exit (1); + } + filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); diff --git a/examples/mixer/mixer.c b/examples/mixer/mixer.c index 5e30152c2f..8bd3bde527 100644 --- a/examples/mixer/mixer.c +++ b/examples/mixer/mixer.c @@ -40,7 +40,7 @@ void eos(GstElement *element) /* playing = FALSE; */ } -static GstCaps* +G_GNUC_UNUSED static GstCaps* gst_play_typefind (GstBin *bin, GstElement *element) { GstElement *typefind; @@ -140,7 +140,7 @@ int main(int argc,char *argv[]) /* request pads and connect to adder */ GST_INFO (0, "requesting pad\n"); - pad = gst_element_request_pad_by_name (adder, "sink%d"); + pad = gst_element_get_request_pad (adder, "sink%d"); printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad)); sprintf (buffer, "channel%d", i); gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad); @@ -237,8 +237,8 @@ create_input_channel (int id, char* location) char buffer[20]; /* hold the names */ - GstAutoplug *autoplug; - GstCaps *srccaps; +/* GstAutoplug *autoplug; + GstCaps *srccaps; */ GstElement *new_element; GstElement *decoder; @@ -364,8 +364,8 @@ create_input_channel (int id, char* location) gst_bin_add (GST_BIN(channel->pipe), channel->volenv); gst_bin_add (GST_BIN (channel->pipe), new_element); - gst_element_connect (channel->filesrc, "src", new_element, "sink"); - gst_element_connect (new_element, "src_00", channel->volenv, "sink"); + gst_element_connect_pads (channel->filesrc, "src", new_element, "sink"); + gst_element_connect_pads (new_element, "src_00", channel->volenv, "sink"); /* add a ghost pad */ sprintf (buffer, "channel%d", id); diff --git a/examples/xml/createxml.c b/examples/xml/createxml.c index 00b09c56b1..d4501c9a69 100644 --- a/examples/xml/createxml.c +++ b/examples/xml/createxml.c @@ -19,7 +19,7 @@ object_saved (GstObject *object, xmlNodePtr parent, gpointer data) int main(int argc,char *argv[]) { - GstElement *filesrc, *osssink, *queue, *queue2, *parse, *decode; + GstElement *filesrc, *osssink, *queue, *queue2, *decode; GstElement *pipeline; GstElement *thread, *thread2; diff --git a/examples/xml/runxml.c b/examples/xml/runxml.c index 5b91e44ce4..e754d5f09e 100644 --- a/examples/xml/runxml.c +++ b/examples/xml/runxml.c @@ -4,7 +4,7 @@ gboolean playing; -static void +G_GNUC_UNUSED static void xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data) { xmlNodePtr children = self->xmlChildrenNode; diff --git a/gst/Makefile.am b/gst/Makefile.am index ddc82cf4f7..31c7a88f91 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -44,8 +44,7 @@ endif EXTRA_libgstreamer_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gsttypefind.c gstparse.c gstautoplug.c gsttrace.c -# cheap trick to build . first... -SUBDIRS = . $(GST_AUTOPLUG_DIRS) elements schedulers types +SUBDIRS = parse . $(GST_AUTOPLUG_DIRS) elements schedulers types DIST_SUBDIRS = autoplug elements parse types schedulers libcothreads_la_SOURCES = cothreads.c @@ -156,7 +155,7 @@ libgstreamer_la_CFLAGS = -D_GNU_SOURCE -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" # the compiler shoots cothreads.c in the head at -O6 libcothreads_la_CFLAGS = $(libgstreamer_la_CFLAGS) -O2 -libgstreamer_la_LIBADD = $(LIBGST_LIBS) +libgstreamer_la_LIBADD = $(LIBGST_LIBS) parse/libgstparse.la libgstreamer_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@ EXTRA_DIST = ROADMAP diff --git a/gst/autoplug/autoplugtest.c b/gst/autoplug/autoplugtest.c index f3eda9869e..d7951551d9 100644 --- a/gst/autoplug/autoplugtest.c +++ b/gst/autoplug/autoplugtest.c @@ -8,13 +8,13 @@ void cache_empty(GstElement *element, gpointer private) { gst_element_set_state (pipeline, GST_STATE_PAUSED); - gst_element_disconnect(src,"src",cache,"sink"); + gst_element_disconnect_pads (src,"src",cache,"sink"); gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); - gst_element_disconnect(cache,"src",decoder,"sink"); + gst_element_disconnect_pads (cache,"src",decoder,"sink"); gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); gst_bin_remove (GST_BIN(autobin), cache); gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); - gst_element_connect(src,"src",decoder,"sink"); + gst_element_connect_pads (src,"src",decoder,"sink"); gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -29,7 +29,7 @@ void have_type(GstElement *element, GstCaps *caps, GstCaps **private_caps) { gst_element_set_state (pipeline, GST_STATE_PAUSED); /* disconnect the typefind from the pipeline and remove it */ - gst_element_disconnect(cache,"src",typefind,"sink"); + gst_element_disconnect(cache,typefind); gst_bin_remove(GST_BIN(autobin),typefind); gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); @@ -39,22 +39,22 @@ void have_type(GstElement *element, GstCaps *caps, GstCaps **private_caps) { sink = gst_elementfactory_make ("osssink","sink"); gst_bin_add(GST_BIN(autobin),decoder); gst_bin_add(GST_BIN(autobin),sink); - gst_element_connect(decoder,"src",sink,"sink"); + gst_element_connect_pads(decoder,"src",sink,"sink"); g_object_set (G_OBJECT(cache), "reset", TRUE, NULL); - gst_element_connect(cache,"src",decoder,"sink"); + gst_element_connect_pads(cache,"src",decoder,"sink"); } else if (strstr(gst_caps_get_mime(caps),"x-ogg")) { decoder = gst_elementfactory_make ("vorbisdec","decoder"); sink = gst_elementfactory_make ("osssink","sink"); gst_bin_add(GST_BIN(autobin),decoder); gst_bin_add(GST_BIN(autobin),sink); - gst_element_connect(decoder,"src",sink,"sink"); + gst_element_connect_pads(decoder,"src",sink,"sink"); g_object_set (G_OBJECT(cache), "reset", TRUE, NULL); - gst_element_connect(cache,"src",decoder,"sink"); + gst_element_connect_pads(cache,"src",decoder,"sink"); } gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -78,14 +78,15 @@ int main (int argc,char *argv[]) { g_signal_connect (G_OBJECT(typefind),"have_type",(GCallback)have_type,&caps); gst_bin_add (GST_BIN(autobin),cache); gst_bin_add (GST_BIN(autobin),typefind); - gst_element_connect(cache,"src",typefind,"sink"); + gst_element_connect_pads (cache,"src",typefind,"sink"); gst_element_add_ghost_pad(autobin,gst_element_get_pad(cache,"sink"),"sink"); gst_bin_add (GST_BIN(pipeline), autobin); - gst_element_connect (src,"src",autobin,"sink"); + gst_element_connect_pads (src,"src",autobin,"sink"); gst_element_set_state(pipeline,GST_STATE_PLAYING); - while (1) - gst_bin_iterate(GST_BIN(pipeline)); + while (gst_bin_iterate(GST_BIN(pipeline))); + + return 0; } diff --git a/gst/autoplug/gstspider.c b/gst/autoplug/gstspider.c index 954a93f88e..fa0ce59e7b 100644 --- a/gst/autoplug/gstspider.c +++ b/gst/autoplug/gstspider.c @@ -533,7 +533,7 @@ gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath) gst_bin_add (GST_BIN (spider), element); } /* insert and connect new element */ - if (!gst_element_connect_elements (conn->current, element)) + if (!gst_element_connect (conn->current, element)) { /* check if the src has SOMETIMES templates. If so, connect a callback */ GList *templs = gst_element_get_padtemplate_list (conn->current); diff --git a/gst/autoplug/spidertest.c b/gst/autoplug/spidertest.c index b46d55629f..130671697e 100644 --- a/gst/autoplug/spidertest.c +++ b/gst/autoplug/spidertest.c @@ -119,9 +119,9 @@ int main(int argc,char *argv[]) gst_bin_add(GST_BIN(bin), videosink); /* connect objects */ - if (!(gst_element_connect_elements(filesrc, decoder) && - gst_element_connect_elements(decoder, osssink) && - gst_element_connect_elements(decoder, videosink))) + if (!(gst_element_connect(filesrc, decoder) && + gst_element_connect(decoder, osssink) && + gst_element_connect(decoder, videosink))) { g_print ("the pipeline could not be connected\n"); exit (-4); diff --git a/gst/gst.c b/gst/gst.c index 1dd3fe0a84..7576ca9e21 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -66,6 +66,7 @@ enum { ARG_INFO_MASK=1, ARG_DEBUG_MASK, ARG_MASK, + ARG_MASK_HELP, ARG_PLUGIN_SPEW, ARG_PLUGIN_PATH, ARG_PLUGIN_LOAD, @@ -82,6 +83,7 @@ static const struct poptOption options[] = { {"gst-info-mask", NUL, POPT_ARG_INT|POPT_ARGFLAG_STRIP, NULL, ARG_INFO_MASK, "info bitmask", "MASK"}, {"gst-debug-mask", NUL, POPT_ARG_INT|POPT_ARGFLAG_STRIP, NULL, ARG_DEBUG_MASK, "debugging bitmask", "MASK"}, {"gst-mask", NUL, POPT_ARG_INT|POPT_ARGFLAG_STRIP, NULL, ARG_MASK, "bitmask for both info and debugging", "MASK"}, + {"gst-mask-help", NUL, POPT_ARG_NONE|POPT_ARGFLAG_STRIP, NULL, ARG_MASK_HELP, "how to set the level of diagnostic output (-mask values)", NULL}, {"gst-plugin-spew", NUL, POPT_ARG_NONE|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_SPEW, "enable verbose plugin loading diagnostics", NULL}, {"gst-plugin-path", NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_PATH, "'" G_SEARCHPATH_SEPARATOR_S "'--separated path list for loading plugins", "PATHS"}, {"gst-plugin-load", NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_LOAD, "comma-separated list of plugins to preload in addition to the list stored in env variable GST_PLUGIN_PATH", "PLUGINS"}, @@ -265,7 +267,6 @@ static void init_post (void) { GLogLevelFlags llf; - gboolean showhelp = FALSE; const gchar *plugin_path; #ifndef GST_DISABLE_TRACE GstTrace *gst_trace; @@ -326,44 +327,33 @@ init_post (void) if (_gst_progname == NULL) { _gst_progname = g_strdup("gstprog"); } +} - /* FIXME: this is never true... */ - if (showhelp) { - guint i; - - g_print ("usage %s [OPTION...]\n", _gst_progname); - - g_print ("\nGStreamer options\n"); - g_print (" --gst-info-mask=FLAGS GST info flags to set (current %08x)\n", gst_info_get_categories()); - g_print (" --gst-debug-mask=FLAGS GST debugging flags to set\n"); - g_print (" --gst-mask=FLAGS GST info *and* debug flags to set\n"); - g_print (" --gst-plugin-spew Enable printout of errors while loading GST plugins\n"); - g_print (" --gst-plugin-path=PATH Add directories separated with '%s' to the plugin search path\n", - G_SEARCHPATH_SEPARATOR_S); - g_print (" --gst-plugin-load=PLUGINS Load plugins separated with '%s'\n", - GST_PLUGIN_SEPARATOR); - g_print (" --gst-scheduler=NAME Use a nonstandard scheduler\n"); - - g_print ("\n Mask (to be OR'ed) info/debug FLAGS \n"); - g_print ("--------------------------------------------------------\n"); - - for (i = 0; istate_cond = g_cond_new (); } - static void gst_element_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { @@ -184,7 +183,6 @@ gst_element_set_property (GObject *object, guint prop_id, const GValue *value, G (oclass->set_property) (object, prop_id, value, pspec); } - static void gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -194,6 +192,19 @@ gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamS (oclass->get_property) (object, prop_id, value, pspec); } +static GstPad* +gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name) +{ + GstPad *newpad = NULL; + GstElementClass *oclass; + + oclass = CLASS (element); + if (oclass->request_new_pad) + newpad = (oclass->request_new_pad)(element, templ, name); + + return newpad; +} + /** * gst_element_set_name: @@ -483,33 +494,126 @@ gst_element_remove_ghost_pad (GstElement *element, GstPad *pad) GstPad* gst_element_get_pad (GstElement *element, const gchar *name) { - GList *walk; + GstPad *pad; g_return_val_if_fail (element != NULL, NULL); g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); g_return_val_if_fail (name != NULL, NULL); - /* if there aren't any pads, well, we're not likely to find one */ - if (!element->numpads) - return NULL; + if ((pad = gst_element_get_static_pad (element, name))) + return pad; + + pad = gst_element_get_request_pad (element, name); + + return pad; +} + +/** + * gst_element_get_static_pad: + * @element: element to find pad of + * @name: name of pad to retrieve + * + * Retrieve a pad from the element by name. This version only retrieves + * already-existing (i.e. 'static') pads. + * + * Returns: requested pad if found, otherwise NULL. + */ +GstPad * +gst_element_get_static_pad (GstElement *element, const gchar *name) +{ + GList *walk; + + g_return_val_if_fail (element != NULL, NULL); + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + g_return_val_if_fail (name != NULL, NULL); - /* look through the list, matching by name */ walk = element->pads; while (walk) { GstPad *pad; pad = GST_PAD(walk->data); - if (!strcmp (GST_PAD_NAME(pad), name)) { - GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad)); + if (strcmp (GST_PAD_NAME(pad), name) == 0) { + GST_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad)); return pad; } walk = g_list_next (walk); } - GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element)); + GST_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element)); return NULL; } +/** + * gst_element_get_request_pad: + * @element: element to find pad of + * @name: name of pad to retrieve + * + * Retrieve a pad from the element by name. This version only retrieves + * request pads. + * + * Returns: requested pad if found, otherwise NULL. + */ +GstPad* +gst_element_get_request_pad (GstElement *element, const gchar *name) +{ + GstPadTemplate *templ = NULL; + GstPad *pad; + const gchar *req_name = NULL; + gboolean templ_found = FALSE; + GList *list; + gint n; + const gchar *data; + gchar *str, *endptr = NULL; + + g_return_val_if_fail (element != NULL, NULL); + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + g_return_val_if_fail (name != NULL, NULL); + + if (strstr (name, "%")) { + templ = gst_element_get_padtemplate_by_name (element, name); + req_name = NULL; + if (templ) + templ_found = TRUE; + } else { + list = gst_element_get_padtemplate_list(element); + while (!templ_found && list) { + templ = (GstPadTemplate*) list->data; + if (templ->presence == GST_PAD_REQUEST) { + /* we know that %s and %d are the only possibilities because of sanity + checks in gst_padtemplate_new */ + GST_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template); + if ((str = strchr (templ->name_template, '%')) && + strncmp (templ->name_template, name, str - templ->name_template) == 0 && + strlen (name) > str - templ->name_template) { + data = name + (str - templ->name_template); + if (*(str+1) == 'd') { + /* it's an int */ + n = (gint) strtol (data, &endptr, 10); + if (endptr && *endptr == '\0') { + templ_found = TRUE; + req_name = name; + break; + } + } else { + /* it's a string */ + templ_found = TRUE; + req_name = name; + break; + } + } + } + list = list->next; + } + } + + if (!templ_found) + return NULL; + + pad = gst_element_request_pad (element, templ, req_name); + + return pad; +} + /** * gst_element_get_pad_list: * @element: element to get pads of @@ -658,19 +762,6 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate * return newtempl; } -static GstPad* -gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name) -{ - GstPad *newpad = NULL; - GstElementClass *oclass; - - oclass = CLASS (element); - if (oclass->request_new_pad) - newpad = (oclass->request_new_pad)(element, templ, name); - - return newpad; -} - /** * gst_element_request_compatible_pad: * @element: element to request a new pad from @@ -700,78 +791,6 @@ gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ) return pad; } -/** - * gst_element_request_pad_by_name: - * @element: element to request a new pad from - * @name: the name of the padtemplate to use. - * - * Request a new pad from the element. The name argument will - * be used to decide what padtemplate to use. This function - * is typically used for elements with a padtemplate with presence - * GST_PAD_REQUEST. - * - * Returns: the new pad that was created. - */ -GstPad* -gst_element_request_pad_by_name (GstElement *element, const gchar *name) -{ - GstPadTemplate *templ = NULL; - GstPad *pad; - const gchar *req_name = NULL; - gboolean templ_found = FALSE; - GList *list; - gint n; - const gchar *data; - gchar *str, *endptr; - - g_return_val_if_fail (element != NULL, NULL); - g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); - g_return_val_if_fail (name != NULL, NULL); - - - if (strstr (name, "%")) { - templ = gst_element_get_padtemplate_by_name (element, name); - req_name = NULL; - if (templ) - templ_found = TRUE; - } else { - list = gst_element_get_padtemplate_list(element); - while (!templ_found && list) { - templ = (GstPadTemplate*) list->data; - if (templ->presence == GST_PAD_REQUEST) { - /* we know that %s and %d are the only possibilities because of sanity - checks in gst_padtemplate_new */ - if ((str = strchr (templ->name_template, '%')) && - strncmp (templ->name_template, name, str - templ->name_template) == 0 && - strlen (name) > str - templ->name_template) { - data = name + (str - templ->name_template); - if (*(str+1) == 'd') { - /* it's an int */ - n = (gint) strtol (data, &endptr, 10); - if (endptr == NULL) { - templ_found = TRUE; - req_name = name; - break; - } - } else { - /* it's a string */ - templ_found = TRUE; - req_name = name; - break; - } - } - } - list = list->next; - } - } - - if (!templ_found) - return NULL; - - pad = gst_element_request_pad (element, templ, req_name); - - return pad; -} /** * gst_element_get_compatible_pad_filtered: @@ -860,7 +879,7 @@ gst_element_get_compatible_pad (GstElement *element, GstPad *pad) } /** - * gst_element_connect_elements_filtered: + * gst_element_connect_filtered: * @src: the element containing source pad * @dest: the element containing destination pad * @filtercaps: the caps to use as filter @@ -875,7 +894,7 @@ gst_element_get_compatible_pad (GstElement *element, GstPad *pad) * Returns: TRUE if the elements could be connected. */ gboolean -gst_element_connect_elements_filtered (GstElement *src, GstElement *dest, +gst_element_connect_filtered (GstElement *src, GstElement *dest, GstCaps *filtercaps) { GList *srcpads, *destpads, *srctempls, *desttempls, *l; @@ -936,8 +955,8 @@ gst_element_connect_elements_filtered (GstElement *src, GstElement *dest, if (desttempl->presence == GST_PAD_REQUEST && desttempl->direction != srctempl->direction) { if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctempl), gst_padtemplate_get_caps (desttempl))) { - srcpad = gst_element_request_pad_by_name (src, srctempl->name_template); - destpad = gst_element_request_pad_by_name (dest, desttempl->name_template); + srcpad = gst_element_get_request_pad (src, srctempl->name_template); + destpad = gst_element_get_request_pad (dest, desttempl->name_template); if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) { GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad)); @@ -957,19 +976,17 @@ gst_element_connect_elements_filtered (GstElement *src, GstElement *dest, } /** - * gst_element_connect_elements_many: + * gst_element_connect_many: * @element_1: the first element in the connection chain * @element_2: the second element in the connection chain * @...: NULL-terminated list of elements to connect in order * - * Chain together a series of elements. Uses #gst_element_connect_elements. + * Chain together a series of elements. Uses #gst_element_connect. * * Returns: TRUE on success, FALSE otherwise. */ -/* API FIXME: this should be called gst_element_connect_many, and connect_elements - * should just be connect */ gboolean -gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, ...) +gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...) { va_list args; @@ -979,7 +996,7 @@ gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, va_start (args, element_2); while (element_2) { - if (!gst_element_connect_elements (element_1, element_2)) + if (!gst_element_connect (element_1, element_2)) return FALSE; element_1 = element_2; @@ -992,7 +1009,7 @@ gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, } /** - * gst_element_connect_elements: + * gst_element_connect: * @src: element containing source pad * @dest: element containing destination pad * @@ -1006,13 +1023,13 @@ gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, * Returns: TRUE if the elements could be connected. */ gboolean -gst_element_connect_elements (GstElement *src, GstElement *dest) +gst_element_connect (GstElement *src, GstElement *dest) { - return gst_element_connect_elements_filtered (src, dest, NULL); + return gst_element_connect_filtered (src, dest, NULL); } /** - * gst_element_connect_filtered: + * gst_element_connect_pads_filtered: * @src: element containing source pad * @srcpadname: name of pad in source element * @dest: element containing destination pad @@ -1027,17 +1044,17 @@ gst_element_connect_elements (GstElement *src, GstElement *dest) * Returns: TRUE if the pads could be connected. */ gboolean -gst_element_connect_filtered (GstElement *src, const gchar *srcpadname, - GstElement *dest, const gchar *destpadname, - GstCaps *filtercaps) +gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname, + GstElement *dest, const gchar *destpadname, + GstCaps *filtercaps) { GstPad *srcpad,*destpad; g_return_val_if_fail (src != NULL, FALSE); - g_return_val_if_fail (GST_IS_ELEMENT(src), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE); g_return_val_if_fail (srcpadname != NULL, FALSE); g_return_val_if_fail (dest != NULL, FALSE); - g_return_val_if_fail (GST_IS_ELEMENT(dest), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE); g_return_val_if_fail (destpadname != NULL, FALSE); /* obtain the pads requested */ @@ -1057,7 +1074,7 @@ gst_element_connect_filtered (GstElement *src, const gchar *srcpadname, } /** - * gst_element_connect: + * gst_element_connect_pads: * @src: element containing source pad * @srcpadname: name of pad in source element * @dest: element containing destination pad @@ -1071,14 +1088,14 @@ gst_element_connect_filtered (GstElement *src, const gchar *srcpadname, * Returns: TRUE if the pads could be connected. */ gboolean -gst_element_connect (GstElement *src, const gchar *srcpadname, - GstElement *dest, const gchar *destpadname) +gst_element_connect_pads (GstElement *src, const gchar *srcpadname, + GstElement *dest, const gchar *destpadname) { - return gst_element_connect_filtered (src, srcpadname, dest, destpadname, NULL); + return gst_element_connect_pads_filtered (src, srcpadname, dest, destpadname, NULL); } /** - * gst_element_disconnect: + * gst_element_disconnect_pads: * @src: element containing source pad * @srcpadname: name of pad in source element * @dest: element containing destination pad @@ -1087,8 +1104,8 @@ gst_element_connect (GstElement *src, const gchar *srcpadname, * Disconnect the two named pads of the source and destination elements. */ void -gst_element_disconnect (GstElement *src, const gchar *srcpadname, - GstElement *dest, const gchar *destpadname) +gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname, + GstElement *dest, const gchar *destpadname) { GstPad *srcpad,*destpad; @@ -1116,14 +1133,42 @@ gst_element_disconnect (GstElement *src, const gchar *srcpadname, } /** - * gst_element_disconnect_elements: + * gst_element_disconnect_many: + * @element_1: the first element in the connection chain + * @element_2: the second element in the connection chain + * @...: NULL-terminated list of elements to disconnect in order + * + * Disconnect a series of elements. Uses #gst_element_disconnect. + */ +void +gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...) +{ + va_list args; + + g_return_if_fail (element_1 != NULL && element_2 != NULL); + g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2)); + + va_start (args, element_2); + + while (element_2) { + gst_element_disconnect (element_1, element_2); + + element_1 = element_2; + element_2 = va_arg (args, GstElement*); + } + + va_end (args); +} + +/** + * gst_element_disconnect: * @src: source element * @dest: sink element * * Disconnect all pads connecting the two elements in the direction src -> dest. */ void -gst_element_disconnect_elements (GstElement *src, GstElement *dest) +gst_element_disconnect (GstElement *src, GstElement *dest) { GList *srcpads; GstPad *pad; @@ -1157,6 +1202,7 @@ gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg gst_object_unref (GST_OBJECT (element)); } } + /** * gst_element_error: * @element: Element with the error @@ -1226,6 +1272,7 @@ gst_element_wait_state_change (GstElement *element) g_cond_wait (element->state_cond, element->state_mutex); g_mutex_unlock (element->state_mutex); } + /** * gst_element_set_state: * @element: element to change state of diff --git a/gst/gstelement.h b/gst/gstelement.h index affb35105e..a99a143138 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -197,32 +197,37 @@ GstScheduler* gst_element_get_sched (GstElement *element); void gst_element_add_pad (GstElement *element, GstPad *pad); void gst_element_remove_pad (GstElement *element, GstPad *pad); -GstPad* gst_element_get_pad (GstElement *element, const gchar *name); -GList* gst_element_get_pad_list (GstElement *element); -GList* gst_element_get_padtemplate_list (GstElement *element); -GstPadTemplate* gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name); GstPad * gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name); void gst_element_remove_ghost_pad (GstElement *element, GstPad *pad); -GstPad* gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ); -GstPad* gst_element_request_pad_by_name (GstElement *element, const gchar *name); +GstPad* gst_element_get_pad (GstElement *element, const gchar *name); +GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name); +GstPad* gst_element_get_request_pad (GstElement *element, const gchar *name); + +GList* gst_element_get_pad_list (GstElement *element); +GList* gst_element_get_padtemplate_list (GstElement *element); +GstPadTemplate* gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name); + +GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad); GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad, GstCaps *filtercaps); -GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad); +GstPad* gst_element_get_compatible_request_pad (GstElement *element, GstPadTemplate *templ); +GstPad* gst_element_get_compatible_static_pad (GstElement *element, GstPadTemplate *templ); -/* these functions should probably have another name, but gst_element_connect is already used */ -gboolean gst_element_connect_elements (GstElement *src, GstElement *dest); -gboolean gst_element_connect_elements_filtered (GstElement *src, GstElement *dest, +gboolean gst_element_connect (GstElement *src, GstElement *dest); +gboolean gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...); +gboolean gst_element_connect_filtered (GstElement *src, GstElement *dest, GstCaps *filtercaps); -gboolean gst_element_connect (GstElement *src, const gchar *srcpadname, +void gst_element_disconnect (GstElement *src, GstElement *dest); +void gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...); + +gboolean gst_element_connect_pads (GstElement *src, const gchar *srcpadname, GstElement *dest, const gchar *destpadname); -gboolean gst_element_connect_filtered (GstElement *src, const gchar *srcpadname, +gboolean gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname, GstElement *dest, const gchar *destpadname, GstCaps *filtercaps); -void gst_element_disconnect (GstElement *src, const gchar *srcpadname, +void gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname, GstElement *dest, const gchar *destpadname); -void gst_element_disconnect_elements (GstElement *src, GstElement *dest); -gboolean gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, ...); void gst_element_set_eos (GstElement *element); diff --git a/gst/gstparse.c b/gst/gstparse.c index 4fcb25a592..a21535de3e 100644 --- a/gst/gstparse.c +++ b/gst/gstparse.c @@ -25,25 +25,11 @@ #define DEBUG_NOPREFIX(format,args...) #define VERBOSE(format,args...) -#define GST_PARSE_LISTPAD(list) ((GstPad*)(list->data)) - #include #include "gst_private.h" #include "gstparse.h" -#include "gstpipeline.h" -#include "gstthread.h" -#include "gstutils.h" - -typedef struct _gst_parse_priv gst_parse_priv; -struct _gst_parse_priv -{ - guint bincount; - guint threadcount; - gint binlevel; - gboolean verbose; - gboolean debug; -}; +#include "parse/types.h" typedef struct _gst_parse_delayed_pad gst_parse_delayed_pad; struct _gst_parse_delayed_pad @@ -60,7 +46,17 @@ typedef struct } dyn_connect; -static void + +GQuark +gst_parse_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("gst_parse_error"); + return quark; +} + +G_GNUC_UNUSED static void dynamic_connect (GstElement * element, GstPad * newpad, gpointer data) { dyn_connect *connect = (dyn_connect *) data; @@ -74,411 +70,277 @@ dynamic_connect (GstElement * element, GstPad * newpad, gpointer data) } } -static gint -gst_parse_launchv_recurse (const gchar **argv, GstBin * parent, gst_parse_priv * priv) +static gboolean +make_elements (graph_t *g, GError **error) { - gint i = -1, j = 0; - const gchar *arg; - GstElement *element = NULL, *previous = NULL, *prevelement = NULL; - gchar closingchar = '\0'; - gint len; - const gchar *cptr; - gchar *ptr; - gchar *sinkpadname = NULL, *srcpadname = NULL, *tempname; - GstPad *temppad; - GSList *sinkpads = NULL, *srcpads = NULL; - gint numsrcpads = 0, numsinkpads = 0; - GList *pads; - gint elementcount = 0; - gint retval = 0; - gboolean backref = FALSE; - - if (!priv) { - priv = g_new0 (gst_parse_priv, 1); + GList *l = NULL; + gchar *bin_type; + element_t *e; + + if (!(g->bins || g->elements)) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_SYNTAX, + "Empty bin"); + return FALSE; } - priv->binlevel++; - - if (GST_IS_PIPELINE (parent)) { - closingchar = '\0'; - DEBUG ("in pipeline "); - } else if (GST_IS_THREAD (parent)) { - closingchar = '}'; - DEBUG ("in thread "); - } else { - closingchar = ')'; - DEBUG ("in bin "); + if (g->current_bin_type) + bin_type = g->current_bin_type; + else + bin_type = "pipeline"; + + if (!(g->bin = gst_elementfactory_make (bin_type, NULL))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_NO_SUCH_ELEMENT, + "No such bin type %s", bin_type); + return FALSE; } - DEBUG_NOPREFIX ("%s\n", GST_ELEMENT_NAME (GST_ELEMENT (parent))); - - while ((arg = argv[++i])) { - len = strlen (arg); - element = NULL; - DEBUG ("** ARGUMENT is '%s'\n", arg); - - if (len == 0) { - DEBUG ("random arg, FIXME\n"); - - continue; - } else if (arg[0] == closingchar) { - DEBUG ("exiting container %s\n", GST_ELEMENT_NAME (GST_ELEMENT (parent))); - - retval = i + 1; - break; - } else if ((cptr = strchr (arg, '!'))) { - DEBUG ("attempting to connect pads together....\n"); - - /* if it starts with the ! */ - if (arg[0] == '!') { - srcpadname = NULL; - /* if there's a sinkpad... */ - if (len > 1) - sinkpadname = g_strdup (&arg[1]); - else - sinkpadname = NULL; - } else { - srcpadname = g_strndup (arg, (cptr - arg)); - /* if there's a sinkpad */ - if (len > (cptr - arg) + 1) - sinkpadname = g_strdup(&cptr[1]); - else - sinkpadname = NULL; - } - - if (srcpadname && (ptr = strchr (srcpadname, '.'))) { - gchar *element_name = srcpadname; - GstElement *new; - - *ptr = '\0'; /* it was a '.' before */ - - GST_DEBUG (0, "have pad for element %s", element_name); - new = gst_bin_get_by_name_recurse_up (parent, element_name); - if (!new) { - GST_DEBUG (0, "element %s does not exist! trying to continue", element_name); - } else { - previous = new; - srcpadname = ptr + 1; - backref = TRUE; - } - } - - GST_DEBUG (0, "have srcpad %s, sinkpad %s", srcpadname, sinkpadname); - - g_slist_free (srcpads); - srcpads = NULL; - numsrcpads = 0; - tempname = NULL; - - /* find src pads */ - if (srcpadname != NULL) { - while (1) { - /* split name at commas */ - if ((ptr = strchr (srcpadname, ','))) { - tempname = srcpadname; - srcpadname = &ptr[1]; - *ptr = '\0'; - } else { - tempname = srcpadname; - } - - /* look for pad with that name */ - if ((temppad = gst_element_get_pad (previous, tempname))) { - srcpads = g_slist_append (srcpads, temppad); - numsrcpads++; - } - - /* try to create a pad using that padtemplate name */ - else if ((temppad = gst_element_request_pad_by_name (previous, tempname))) { - srcpads = g_slist_append (srcpads, temppad); - numsrcpads++; - } - if (!temppad) { - GST_DEBUG (0, "NO SUCH pad %s in element %s", tempname, GST_ELEMENT_NAME (previous)); - } else { - GST_DEBUG (0, "have src pad %s:%s", GST_DEBUG_PAD_NAME (temppad)); - } - - /* if there is no more commas in srcpadname then we're done */ - if (tempname == srcpadname) - break; - g_free (tempname); - } - } else { - /* check through the list to find the first src pad */ - GST_DEBUG (0, "CHECKING element %s for pad named %s", GST_ELEMENT_NAME (previous), - srcpadname); - pads = gst_element_get_pad_list (previous); - while (pads) { - temppad = GST_PARSE_LISTPAD (pads); - GST_DEBUG (0, "have pad %s:%s", GST_DEBUG_PAD_NAME (temppad)); - if (GST_IS_GHOST_PAD (temppad)) - GST_DEBUG (0, "it's a ghost pad"); - if (gst_pad_get_direction (temppad) == GST_PAD_SRC) { - srcpads = g_slist_append (srcpads, temppad); - numsrcpads++; - break; - } - pads = g_list_next (pads); - } - if (!srcpads) - GST_DEBUG (0, "error, can't find a src pad!!!"); - else - GST_DEBUG (0, "have src pad %s:%s", GST_DEBUG_PAD_NAME (GST_PARSE_LISTPAD (srcpads))); - } - } else if (strchr (arg, '=')) { - gchar *propname; - gchar *propval; - gchar *pos; - - DEBUG ("have a property\n"); - - /* we have a property */ - propname = g_strdup (arg); - pos = strchr (propname, '='); - *pos = '\0'; - propval = pos + 1; - - /* use g_object_set in the future when gst_util_{set|get} go away */ - GST_DEBUG (0, "attempting to set property '%s' to '%s' on element '%s'", - propname, propval, GST_ELEMENT_NAME (previous)); - gst_util_set_object_arg (G_OBJECT (previous), propname, propval); - g_free (propname); - } else if (arg[0] == '[') { - DEBUG ("have element name\n"); - - if (arg[1] != '\0') { - fprintf (stderr, "error, unexpected junk after [\n"); - return GST_PARSE_ERROR_SYNTAX; - } - - if ((arg = argv[++i])) { - if (!previous) { - g_critical("parser error, please report"); - return GST_PARSE_ERROR_INTERNAL; - } - gst_element_set_name (previous, arg); - } else { - fprintf (stderr, "error, expected element name, found end of arguments\n"); - return GST_PARSE_ERROR_SYNTAX; - } - - if ((arg = argv[++i])) { - if (strcmp (arg, "]") != 0) { - fprintf (stderr, "error, expected ], found '%s'\n", arg); - return GST_PARSE_ERROR_SYNTAX; - } - } else { - fprintf (stderr, "error, expected ], found end of arguments\n"); - return GST_PARSE_ERROR_SYNTAX; - } - } else { - /* we have an element, a bin, or a thread. we treat these together because - * once we rech them we have to resolve any dangling connections from - * previous array arguments. */ - - if (strchr ("({", arg[0])) { - DEBUG ("have bin or thread\n"); - - if (arg[0] == '(') { - /* create a bin and add it to the current parent */ - priv->bincount++; - element = gst_elementfactory_make ("bin", NULL); - if (!element) { - fprintf (stderr, "Couldn't create a bin!\n"); - return GST_PARSE_ERROR_CREATING_ELEMENT; - } - GST_DEBUG (0, "CREATED bin %s", GST_ELEMENT_NAME (element)); - } else if (arg[0] == '{') { - /* create a thread and add it to the current parent */ - priv->threadcount++; - element = gst_elementfactory_make ("thread", NULL); - if (!element) { - fprintf (stderr, "Couldn't create a thread!\n"); - return GST_PARSE_ERROR_CREATING_ELEMENT; - } - GST_DEBUG (0, "CREATED thread %s", GST_ELEMENT_NAME (element)); - } else { - fprintf (stderr, "Illegal argument: %s\n", arg); - return GST_PARSE_ERROR_CREATING_ELEMENT; - } - - gst_bin_add (GST_BIN (parent), element); - - j = gst_parse_launchv_recurse (argv + i + 1, GST_BIN (element), priv); - /* check for parse error */ - if (j < 0) - return j; - - /* we will get autoincremented at the while */ - i += j; - - } else { - /* we have an element */ - DEBUG ("attempting to create element '%s'\n", arg); - - element = gst_elementfactory_make (arg, NULL); - if (!element) { -#ifndef GST_DISABLE_REGISTRY - fprintf (stderr, - "Couldn't create a '%s', no such element or need to run gst-register?\n", arg); -#else - fprintf (stderr, "Couldn't create a '%s', no such element or need to load plugin?\n", - arg); -#endif - return GST_PARSE_ERROR_NOSUCH_ELEMENT; - } - - GST_DEBUG (0, "CREATED element %s", GST_ELEMENT_NAME (element)); - gst_bin_add (GST_BIN (parent), element); - } - - elementcount++; - - g_slist_free (sinkpads); - sinkpads = NULL; - numsinkpads = 0; - tempname = NULL; - - /* find sink pads */ - if (sinkpadname != NULL) { - while (1) { - /* split name at commas */ - if ((ptr = strchr (sinkpadname, ','))) { - tempname = g_strndup (sinkpadname, (ptr - sinkpadname)); - sinkpadname = &ptr[1]; - } else { - tempname = sinkpadname; - } - - /* look for pad with that name */ - if ((temppad = gst_element_get_pad (element, tempname))) { - sinkpads = g_slist_append (sinkpads, temppad); - numsinkpads++; - } - - /* try to create a pad using that padtemplate name */ - else if ((temppad = gst_element_request_pad_by_name (element, tempname))) { - sinkpads = g_slist_append (sinkpads, temppad); - numsinkpads++; - } - if (!temppad) { - GST_DEBUG (0, "NO SUCH pad %s in element %s", tempname, GST_ELEMENT_NAME (element)); - } else { - GST_DEBUG (0, "have sink pad %s:%s", GST_DEBUG_PAD_NAME (temppad)); - } - - /* if there is no more commas in sinkpadname then we're done */ - if (tempname == sinkpadname) - break; - g_free (tempname); - } - } else { - /* check through the list to find the first sink pad */ - pads = gst_element_get_pad_list (element); - while (pads) { - temppad = GST_PAD (pads->data); - pads = g_list_next (pads); - if (gst_pad_get_direction (temppad) == GST_PAD_SINK) { - sinkpads = g_slist_append (sinkpads, temppad); - numsinkpads++; - break; - } - } - } - - if (!sinkpads) - GST_DEBUG (0, "can't find a sink pad for element"); - else - GST_DEBUG (0, "have sink pad %s:%s", GST_DEBUG_PAD_NAME (GST_PARSE_LISTPAD (sinkpads))); - - if (!srcpads && sinkpads && previous && srcpadname) { - dyn_connect *connect = g_malloc (sizeof (dyn_connect)); - - connect->srcpadname = srcpadname; - connect->target = GST_PARSE_LISTPAD (sinkpads); - connect->pipeline = GST_ELEMENT (parent); - - GST_DEBUG (0, "SETTING UP dynamic connection %s:%s and %s:%s", - gst_element_get_name (previous), - srcpadname, GST_DEBUG_PAD_NAME (GST_PARSE_LISTPAD (sinkpads))); - - g_signal_connect (G_OBJECT (previous), "new_pad", G_CALLBACK (dynamic_connect), connect); - } else { - for (j = 0; (j < numsrcpads) && (j < numsinkpads); j++) { - GST_DEBUG (0, "CONNECTING %s:%s and %s:%s", - GST_DEBUG_PAD_NAME (GST_PARSE_LISTPAD (g_slist_nth (srcpads, j))), - GST_DEBUG_PAD_NAME (GST_PARSE_LISTPAD (g_slist_nth (sinkpads, j)))); - if (!gst_pad_connect (GST_PARSE_LISTPAD (g_slist_nth (srcpads, j)), - GST_PARSE_LISTPAD (g_slist_nth (sinkpads, j)))) { - g_warning ("could not connect %s:%s to %s:%s", - GST_DEBUG_PAD_NAME (GST_PARSE_LISTPAD (g_slist_nth (srcpads, j))), - GST_DEBUG_PAD_NAME (GST_PARSE_LISTPAD (g_slist_nth (sinkpads, j)))); - return GST_PARSE_ERROR_CONNECT; - } - } - } - - g_slist_free (srcpads); - srcpads = NULL; - - g_slist_free (sinkpads); - sinkpads = NULL; - - /* if we're the first element, ghost all the sinkpads */ - if (elementcount == 1 && !backref) { - DEBUG ("first element, ghosting all of %s's sink pads to parent %s\n", - GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (GST_ELEMENT (parent))); - pads = gst_element_get_pad_list (element); - while (pads) { - temppad = GST_PAD (pads->data); - pads = g_list_next (pads); - if (!temppad) - DEBUG ("much oddness, pad doesn't seem to exist\n"); - else if (gst_pad_get_direction (temppad) == GST_PAD_SINK) { - gst_element_add_ghost_pad (GST_ELEMENT (parent), temppad, - g_strdup_printf ("%s-ghost", GST_PAD_NAME (temppad))); - GST_DEBUG (0, "GHOSTED %s:%s to %s as %s-ghost", - GST_DEBUG_PAD_NAME (temppad), GST_ELEMENT_NAME (GST_ELEMENT (parent)), - GST_PAD_NAME (temppad)); - } - } - } - - previous = element; - if (!GST_IS_BIN (element)) - prevelement = element; + + l = g->elements; + while (l) { + e = (element_t*)l->data; + if (!(e->element = gst_elementfactory_make (e->type, NULL))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_NO_SUCH_ELEMENT, + "No such element %s", e->type); + return FALSE; } + gst_bin_add (GST_BIN (g->bin), e->element); + l = g_list_next (l); } - /* ghost all the src pads of the bin */ - if (prevelement != NULL) { - DEBUG ("last element, ghosting all of %s's src pads to parent %s\n", - GST_ELEMENT_NAME (prevelement), GST_ELEMENT_NAME (GST_ELEMENT (parent))); - pads = gst_element_get_pad_list (prevelement); - while (pads) { - temppad = GST_PAD (pads->data); - pads = g_list_next (pads); - if (!temppad) - DEBUG ("much oddness, pad doesn't seem to exist\n"); - else if (gst_pad_get_direction (temppad) == GST_PAD_SRC) { - gst_element_add_ghost_pad (GST_ELEMENT (parent), temppad, - g_strdup_printf ("%s-ghost", GST_PAD_NAME (temppad))); - GST_DEBUG (0, "GHOSTED %s:%s to %s as %s-ghost", - GST_DEBUG_PAD_NAME (temppad), GST_ELEMENT_NAME (parent), GST_PAD_NAME (temppad)); - } - } + l = g->bins; + while (l) { + if (!make_elements ((graph_t*)l->data, error)) + return FALSE; + gst_bin_add (GST_BIN (g->bin), ((graph_t*)l->data)->bin); + l = g_list_next (l); } - - priv->binlevel--; - - if (retval) - return retval; - - DEBUG (closingchar != '\0' ? "returning IN THE WRONG PLACE\n" : "ending pipeline\n"); - - return i + 1; + + return TRUE; } +static gboolean +set_properties (graph_t *g, GError **error) +{ + GList *l, *l2; + element_t *e; + property_t *p; + GParamSpec *pspec; + + l = g->elements; + while (l) { + e = (element_t*)l->data; + l2 = e->property_values; + while (l2) { + p = (property_t*)l2->data; + if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (e->element), p->name))) { + g_object_set_property (G_OBJECT (e->element), p->name, p->value); + } else { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_NO_SUCH_PROPERTY, + "No such property '%s' in element '%s'", + p->name, GST_OBJECT_NAME (GST_OBJECT (e->element))); + return FALSE; + } + l2 = g_list_next (l2); + } + l = g_list_next (l); + } + + l = g->bins; + while (l) { + if (!set_properties ((graph_t*)l->data, error)) + return FALSE; + l = g_list_next (l); + } + + return TRUE; +} + +static GstElement* +find_element_by_index_recurse (graph_t *g, gint i) +{ + GList *l; + element_t *e; + GstElement *element; + + l = g->elements; + while (l) { + e = (element_t*)l->data; + if (e->index == i) { + return e->element; + } + l = g_list_next (l); + } + + l = g->bins; + while (l) { + if ((element = find_element_by_index_recurse ((graph_t*)l->data, i))) + return element; + l = g_list_next (l); + } + + return NULL; +} + +static GstElement* +find_element_by_index (graph_t *g, gint i) +{ + while (g->parent) + g = g->parent; + + return find_element_by_index_recurse (g, i); +} + +static gboolean +make_connections (graph_t *g, GError **error) +{ + GList *l, *a, *b; + connection_t *c; + GstElement *src, *sink; + GstPad *p1, *p2; + + l = g->connections; + while (l) { + c = (connection_t*)l->data; + if (c->src_name) { + if (!(src = gst_bin_get_by_name (GST_BIN (g->bin), c->src_name))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_NO_SUCH_ELEMENT, + "No such element '%s'", + c->src_name); + return FALSE; + } + } else { + src = find_element_by_index (g, c->src_index); + g_assert (src); + } + if (c->sink_name) { + if (!(sink = gst_bin_get_by_name (GST_BIN (g->bin), c->sink_name))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_NO_SUCH_ELEMENT, + "No such element '%s'", + c->sink_name); + return FALSE; + } + } else { + sink = find_element_by_index (g, c->sink_index); + g_assert (sink); + } + + a = c->src_pads; + b = c->sink_pads; + if (a && b) { + /* balanced multipad connection */ + while (a && b) { + if (!gst_element_connect_pads (src, (gchar*)a->data, sink, (gchar*)b->data)) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not connect %s:%s to %s:%s", + GST_OBJECT_NAME (src), (gchar*)a->data, + GST_OBJECT_NAME (sink), (gchar*)b->data); + return FALSE; + } + a = g_list_next (a); + b = g_list_next (b); + } + } else if (a) { + if (!(p1 = gst_element_get_pad (src, (gchar*)a->data))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not get a pad %s from element %s", + (gchar*)a->data, GST_OBJECT_NAME (src)); + return FALSE; + } + if (!(p2 = gst_element_get_compatible_pad (sink, p1))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not find a compatible pad in element %s to for %s:%s", + GST_OBJECT_NAME (sink), GST_OBJECT_NAME (src), (gchar*)a->data); + return FALSE; + } + if (!gst_pad_connect (p1, p2)) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not connect %s:%s to %s:%s", + GST_OBJECT_NAME (src), GST_OBJECT_NAME (p1), + GST_OBJECT_NAME (sink), GST_OBJECT_NAME (p1)); + return FALSE; + } + } else if (b) { + if (!(p2 = gst_element_get_pad (sink, (gchar*)b->data))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not get a pad %s from element %s", + (gchar*)b->data, GST_OBJECT_NAME (sink)); + return FALSE; + } + if (!(p1 = gst_element_get_compatible_pad (src, p2))) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not find a compatible pad in element %s to for %s:%s", + GST_OBJECT_NAME (src), GST_OBJECT_NAME (sink), (gchar*)b->data); + return FALSE; + } + if (!gst_pad_connect (p1, p2)) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not connect %s:%s to %s:%s", + GST_OBJECT_NAME (src), GST_OBJECT_NAME (p1), + GST_OBJECT_NAME (sink), GST_OBJECT_NAME (p1)); + return FALSE; + } + } else { + if (!gst_element_connect (src, sink)) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_CONNECT, + "Could not connect %s to %s", + GST_OBJECT_NAME (src), GST_OBJECT_NAME (sink)); + return FALSE; + } + } + l = g_list_next (l); + } + + l = g->bins; + while (l) { + if (!make_connections ((graph_t*)l->data, error)) + return FALSE; + l = g_list_next (l); + } + + return TRUE; +} + +static GstBin* +pipeline_from_graph (graph_t *g, GError **error) +{ + if (!make_elements (g, error)) + return NULL; + + if (!set_properties (g, error)) + return NULL; + + if (!make_connections (g, error)) + return NULL; + + return (GstBin*)g->bin; +} /** * gst_parse_launchv: @@ -488,25 +350,18 @@ gst_parse_launchv_recurse (const gchar **argv, GstBin * parent, gst_parse_priv * * * Returns: a new pipeline on success, NULL on failure */ -GstPipeline * -gst_parse_launchv (const gchar **argv) +GstBin * +gst_parse_launchv (const gchar **argv, GError **error) { - GstPipeline *pipeline; - gint ret; + GstBin *pipeline; + gchar *pipeline_description; - /* defer error detection to the _recurse function */ + /* i think this cast works out ok... */ + pipeline_description = g_strjoinv (" ", (gchar**)argv); + + pipeline = gst_parse_launch (pipeline_description, error); - pipeline = (GstPipeline*) gst_pipeline_new ("launch"); - - ret = gst_parse_launchv_recurse (argv, GST_BIN (pipeline), NULL); - - if (ret <= 0) { - /* print an error */ - gst_object_unref (GST_OBJECT (pipeline)); - return NULL; - } else { - return pipeline; - } + return pipeline; } /** @@ -517,98 +372,24 @@ gst_parse_launchv (const gchar **argv) * * Returns: a new GstPipeline (cast to a Bin) on success, NULL on failure */ -GstPipeline * -gst_parse_launch (const gchar * pipeline_description) +GstBin * +gst_parse_launch (const gchar * pipeline_description, GError **error) { - gchar **argvn; - gint newargc; - gint i; - const gchar *cp, *start, *end; - gchar *temp; - GSList *string_list = NULL, *slist; - GstPipeline *pipeline; + graph_t *graph; + static GStaticMutex flex_lock = G_STATIC_MUTEX_INIT; - end = pipeline_description + strlen (pipeline_description); - newargc = 0; + g_return_val_if_fail (pipeline_description != NULL, NULL); - temp = ""; + GST_INFO (GST_CAT_PIPELINE, "parsing pipeline description %s", + pipeline_description); - /* Extract the arguments to a gslist in reverse order */ - for (cp = pipeline_description; cp < end;) { - i = strcspn (cp, "([{}]) \"\\"); + /* the need for the mutex will go away with flex 2.5.6 */ + g_static_mutex_lock (&flex_lock); + graph = _gst_parse_launch (pipeline_description, error); + g_static_mutex_unlock (&flex_lock); - if (i > 0) { - temp = g_strconcat (temp, g_strndup (cp, i), NULL); - - /* see if we have an escape char */ - if (cp[i] != '\\') { - /* normal argument - copy and add to the list */ - string_list = g_slist_prepend (string_list, temp); - newargc++; - temp = ""; - } else { - temp = g_strconcat (temp, g_strndup (&cp[++i], 1), NULL); - } - cp += i; - } - - /* skip spaces */ - while (cp < end && *cp == ' ') { - cp++; - } - - /* handle quoted arguments */ - if (*cp == '"') { - start = ++cp; - - /* find matching quote */ - while (cp < end && *cp != '"') - cp++; - - /* make sure we got it */ - if (cp == end) { - g_warning ("gst_parse_launch: Unbalanced quote in command line"); - /* FIXME: The list leaks here */ - return 0; - } - - /* copy the string sans quotes */ - string_list = g_slist_prepend (string_list, g_strndup (start, cp - start)); - newargc++; - cp += 2; /* skip the quote aswell */ - } - - /* brackets exist in a separate argument slot */ - if (*cp && strchr ("([{}])", *cp)) { - string_list = g_slist_prepend (string_list, g_strndup (cp, 1)); - newargc++; - cp++; - } - } - - /* now allocate the new argv array, with room for NULL termination */ - argvn = g_new0 (char *, newargc + 1); - - GST_DEBUG (0, "got %d args", newargc); - - /* reverse the list and put the strings in the new array */ - i = newargc; - - for (slist = string_list; slist; slist = slist->next) - argvn[--i] = slist->data; - - g_slist_free (string_list); - - /* print them out */ - while (argvn[i++]) { - GST_DEBUG (0, "arg %d is: %s", i-1, argvn[i-1]); - } - - /* do it! */ - pipeline = gst_parse_launchv ((const char**) argvn); - - GST_DEBUG(0, "Finished - freeing temporary argument array"); - g_strfreev(argvn); - - return pipeline; + if (!graph) + return NULL; + + return pipeline_from_graph (graph, error); } diff --git a/gst/gstparse.h b/gst/gstparse.h index f32eec1f9a..807f001137 100644 --- a/gst/gstparse.h +++ b/gst/gstparse.h @@ -25,22 +25,24 @@ #include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS #ifndef GST_DISABLE_PARSE -typedef enum { - GST_PARSE_ERROR_SYNTAX = -1, - GST_PARSE_ERROR_CREATING_ELEMENT = -2, - GST_PARSE_ERROR_NOSUCH_ELEMENT = -3, - GST_PARSE_ERROR_INTERNAL = -4, - GST_PARSE_ERROR_CONNECT = -5, -} GstParseErrors; - -GstPipeline* gst_parse_launch (const gchar *pipeline_description); -GstPipeline* gst_parse_launchv (const gchar **argv); +GQuark gst_parse_error_quark (void); +#define GST_PARSE_ERROR gst_parse_error_quark () + +typedef enum +{ + GST_PARSE_ERROR_SYNTAX, + GST_PARSE_ERROR_NO_SUCH_ELEMENT, + GST_PARSE_ERROR_NO_SUCH_PROPERTY, + GST_PARSE_ERROR_CONNECT +} GstParseError; + + +GstBin* gst_parse_launch (const gchar *pipeline_description, GError **error); +GstBin* gst_parse_launchv (const gchar **argv, GError **error); #else /* GST_DISABLE_PARSE */ @@ -48,8 +50,6 @@ GstPipeline* gst_parse_launchv (const gchar **argv); #endif /* GST_DISABLE_PARSE */ -#ifdef __cplusplus -} -#endif /* __cplusplus */ +G_END_DECLS #endif /* __GST_PARSE_H__ */ diff --git a/gst/parse/Makefile.am b/gst/parse/Makefile.am index 0f19ed6c60..37af023d25 100644 --- a/gst/parse/Makefile.am +++ b/gst/parse/Makefile.am @@ -1,14 +1,11 @@ -#noinst_LTLIBRARIES = libgstparse.la +noinst_LTLIBRARIES = libgstparse.la -#libgstparse_la_SOURCES = parse.c grammar.c +libgstparse_la_SOURCES = lex.yy.c grammar.tab.c BISON = bison -d -v -noinst_PROGRAMS = grammar - -grammar_SOURCES = lex.yy.c grammar.tab.c -grammar_CFLAGS = $(GLIB_CFLAGS) -grammar_LDADD = $(GLIB_LIBS) +libgstparse_la_CFLAGS = $(LIBGST_CFLAGS) +libgstparse_la_LIBADD = $(LIBGST_LIBS) noinst_HEADERS = grammar.tab.h diff --git a/gst/parse/grammar.y b/gst/parse/grammar.y index 08eba24284..9ebabf7e78 100644 --- a/gst/parse/grammar.y +++ b/gst/parse/grammar.y @@ -1,73 +1,68 @@ %{ #include #include +#include "../gstparse.h" #include "types.h" + #define YYDEBUG 1 #define YYERROR_VERBOSE 1 +#define YYPARSE_PARAM pgraph + +static int yylex (void *lvalp); +static int yyerror (const char *s); %} %union { - double d; - gboolean b; - gint i; gchar *s; + GValue *v; graph_t *g; connection_t *c; property_t *p; element_t *e; - hash_t *h; } -%token IDENTIFIER STRING -%token FLOAT -%token INTEGER -%token BOOLEAN +%token IDENTIFIER +%token CONNECTION BCONNECTION +%token VALUE %type id -%type qid %type graph bin %type element %type

property_value value -%type connection lconnection rconnection qconnection iconnection +%type connection rconnection %left '{' '}' '(' ')' %left '!' '=' -%left '+' +%left ',' %left '.' +%pure_parser + %start graph %% id: IDENTIFIER ; -qid: id { $$ = g_new0 (hash_t, 1); $$->id2 = $1 } - | id '.' id { $$ = g_new0 (hash_t, 1); $$->id1 = $1; $$->id2 = $3; } - ; - -value: STRING { $$ = g_new0 (property_t, 1); - $$->value_type = G_TYPE_STRING; $$->value.s = $1; } - | FLOAT { $$ = g_new0 (property_t, 1); - $$->value_type = G_TYPE_DOUBLE; $$->value.d = $1; } - | INTEGER { $$ = g_new0 (property_t, 1); - $$->value_type = G_TYPE_INT; $$->value.i = $1; } - | BOOLEAN { $$ = g_new0 (property_t, 1); - $$->value_type = G_TYPE_BOOLEAN; $$->value.b = $1; } +value: VALUE { $$ = g_new0 (property_t, 1); $$->value = $1; } ; property_value: id '=' value { $$ = $3; $$->name = $1; } ; -element: id { $$ = g_new0 (element_t, 1); $$->name = $1; } +element: id { static int i = 0; $$ = g_new0 (element_t, 1); + $$->type = $1; $$->index = ++i; } ; -graph: /* empty */ { $$ = g_new0 (graph_t, 1); } - | graph element { GList *l = $$->connections_pending; - $$ = $1; +graph: /* empty */ { $$ = g_new0 (graph_t, 1); *((graph_t**) pgraph) = $$; } + | graph element { GList *l; + $$ = $1; l = $$->connections_pending; $$->elements = g_list_append ($$->elements, $2); $$->current = $2; + if (!$$->first) + $$->first = $$->current; while (l) { - ((connection_t*) l->data)->sink = $$->current->name; + ((connection_t*) l->data)->sink_index = $$->current->index; l = g_list_next (l); } if ($$->connections_pending) { @@ -75,11 +70,27 @@ graph: /* empty */ { $$ = g_new0 (graph_t, 1); } $$->connections_pending = NULL; } } - | graph bin { $$ = $1; $$->bins = g_list_append ($$->bins, $2); } - | graph connection { $$ = $1; $$->connections = g_list_append ($$->connections, $2); - if (!$2->src) - $2->src = $$->current->name; - if (!$2->sink) + | graph bin { GList *l; $$ = $1; l = $$->connections_pending; + *((graph_t**) pgraph) = $$; + $$->bins = g_list_append ($$->bins, $2); + $2->parent = $$; + $$->current = $2->first; + if (!$$->first) + $$->first = $$->current; + while (l) { + ((connection_t*) l->data)->sink_index = $$->current->index; + l = g_list_next (l); + } + if ($$->connections_pending) { + g_list_free ($$->connections_pending); + $$->connections_pending = NULL; + } + $$->current = $2->current; + } + | graph connection { $$ = $1; + $$->connections = g_list_append ($$->connections, $2); + $2->src_index = $$->current->index; + if (!$2->sink_name) $$->connections_pending = g_list_append ($$->connections_pending, $2); } | graph property_value { $$ = $1; @@ -88,40 +99,19 @@ graph: /* empty */ { $$ = g_new0 (graph_t, 1); } } ; -bin: '{' graph '}' { $$ = $2; $$->current_bin_type = "gstthread"; } +bin: '{' graph '}' { $$ = $2; $$->current_bin_type = "thread"; } | id '.' '(' graph ')' { $$ = $4; $$->current_bin_type = $1; } ; -connection: lconnection +connection: CONNECTION | rconnection - | qconnection - | iconnection ; -lconnection: qid '+' '!' { $$ = g_new0 (connection_t, 1); - $$->src = $1->id1; - $$->src_pads = g_list_append ($$->src_pads, $1->id2); - } - ; - -rconnection: '!' '+' qid { $$ = g_new0 (connection_t, 1); - $$->sink = $3->id1; - $$->sink_pads = g_list_append ($$->src_pads, $3->id2); - } - ; - -qconnection: qid '+' '!' '+' qid { $$ = g_new0 (connection_t, 1); - $$->src = $1->id1; - $$->src_pads = g_list_append ($$->src_pads, $1->id2); - $$->sink = $5->id1; - $$->sink_pads = g_list_append ($$->sink_pads, $5->id2); - } - ; - -iconnection: '!' { $$ = g_new0 (connection_t, 1); } - | id '+' iconnection '+' id +rconnection: '!' { $$ = g_new0 (connection_t, 1); } + | BCONNECTION { $$ = $1; } + | id ',' rconnection ',' id { $$ = $3; - $$->src_pads = g_list_append ($$->src_pads, $1); + $$->src_pads = g_list_prepend ($$->src_pads, $1); $$->sink_pads = g_list_append ($$->sink_pads, $5); } ; @@ -129,25 +119,47 @@ iconnection: '!' { $$ = g_new0 (connection_t, 1); } %% extern FILE *yyin; +int _gst_parse_yylex (YYSTYPE *lvalp); -int +static int yylex (void *lvalp) { + return _gst_parse_yylex ((YYSTYPE*) lvalp); +} + +static int yyerror (const char *s) { printf ("error: %s\n", s); return -1; } -int main (int argc, char **argv) +int yy_scan_string (char*); + +graph_t * _gst_parse_launch (const gchar *str, GError **error) { - ++argv, --argc; /* skip over program name */ - if ( argc > 0 ) - yyin = fopen (argv[0], "r"); - else - yyin = stdin; + graph_t *g = NULL; + gchar *dstr; + + g_return_val_if_fail (str != NULL, NULL); + + dstr = g_strdup (str); + yy_scan_string (dstr); #ifdef DEBUG yydebug = 1; #endif - return yyparse(); + if (yyparse (&g) != 0) { + g_set_error (error, + GST_PARSE_ERROR, + GST_PARSE_ERROR_SYNTAX, + "Invalid syntax"); + g_free (dstr); + return NULL; + } + + g_assert (g != NULL); + + g_free (dstr); + + return g; } diff --git a/gst/parse/parse.l b/gst/parse/parse.l index cb32ac1eeb..2467558080 100644 --- a/gst/parse/parse.l +++ b/gst/parse/parse.l @@ -12,13 +12,19 @@ #endif #define CHAR(x) PRINT ("char: %c\n", *yytext); return *yytext; + +#define YY_DECL int _gst_parse_yylex (YYSTYPE *lvalp) +#define YY_NO_UNPUT %} _integer [[:digit:]]+ -_float [[:digit:]]+"."*[[:digit:]]* -_number {_integer}|{_float} +_double [[:digit:]]+"."*[[:digit:]]* +_number {_integer}|{_double} _boolean "true"|"false"|"TRUE"|"FALSE" -_identifier [[:alpha:]][[:alnum:]\-_]* +_identifier [[:alpha:]][[:alnum:]\-_%]* +_lconnection ({_identifier}\.)?{_identifier}! +_rconnection !({_identifier}\.)?{_identifier} +_bconnection ({_identifier}\.)?{_identifier}!({_identifier}\.)?{_identifier} _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"") %x value @@ -28,21 +34,30 @@ _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"") { {_integer} { PRINT ("An integer: %s (%d)\n", yytext, - atoi (yytext)); + atoi (yytext)); + lvalp->v = g_new0 (GValue, 1); + g_value_init (lvalp->v, G_TYPE_INT); + g_value_set_int (lvalp->v, atoi (yytext)); BEGIN (INITIAL); - return INTEGER; + return VALUE; } - {_float} { - PRINT ("A float: %s (%g)\n", yytext, atof (yytext)); + {_double} { + PRINT ("A double: %s (%g)\n", yytext, atof (yytext)); + lvalp->v = g_new0 (GValue, 1); + g_value_init (lvalp->v, G_TYPE_DOUBLE); + g_value_set_double (lvalp->v, atof (yytext)); BEGIN (INITIAL); - return FLOAT; + return VALUE; } {_boolean} { PRINT ("A boolean: %s (%d)\n", yytext, tolower (*yytext) == 't' ? 1 : 0); + lvalp->v = g_new0 (GValue, 1); + g_value_init (lvalp->v, G_TYPE_BOOLEAN); + g_value_set_boolean (lvalp->v, tolower (*yytext) == 't' ? TRUE : FALSE); BEGIN (INITIAL); - return BOOLEAN; + return VALUE; } {_string} { @@ -50,20 +65,80 @@ _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"") yytext++; *(yytext + strlen (yytext) - 1) = '\0'; } - PRINT ("A string: %s\n", yytext); + PRINT ("A string: \"%s\"\n", yytext); + lvalp->v = g_new0 (GValue, 1); + g_value_init (lvalp->v, G_TYPE_STRING); + g_value_set_string (lvalp->v, yytext); BEGIN (INITIAL); - return STRING; + return VALUE; } [[:space:]]+ { /* PRINT ("space: [%s]\n", yytext); */ } . { PRINT ("unknown: %s\n", yytext); + return *yytext; } } +{_lconnection} { + gchar *d1, *q; + lvalp->c = g_new0 (connection_t, 1); + PRINT ("An connection: %s\n", yytext); + q = strchr (yytext, '!'); + d1 = strchr (yytext, '.'); + if (d1) { + lvalp->c->src_name = g_strndup (yytext, d1 - yytext); + lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (d1 + 1, q - d1 - 1)); + } else { + lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (yytext, q - yytext)); + } + + return CONNECTION; +} + +{_rconnection} { + gchar *d2; + lvalp->c = g_new0 (connection_t, 1); + PRINT ("An rconnection: %s\n", yytext); + d2 = strchr (yytext, '.'); + if (d2) { + lvalp->c->sink_name = g_strndup (yytext + 1, d2 - yytext - 1); + lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (d2 + 1)); + } else { + lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (yytext + 1)); + } + + return CONNECTION; +} + +{_bconnection} { + gchar *d1, *d2, *q; + lvalp->c = g_new0 (connection_t, 1); + PRINT ("A bconnection: %s\n", yytext); + q = strchr (yytext, '!'); + d1 = strchr (yytext, '.'); + d2 = strchr (q, '.'); + if (d1 && d1 < q) { + lvalp->c->src_name = g_strndup (yytext, d1 - yytext); + lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (d1 + 1, q - d1 - 1)); + } else { + lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (yytext, q - yytext)); + } + + if (d2) { + lvalp->c->sink_name = g_strndup (q + 1, d2 - q - 1); + lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (d2 + 1)); + } else { + lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (q + 1)); + } + + return BCONNECTION; +} + {_identifier} { PRINT ("An identifier: %s\n", yytext); + lvalp->s = g_strdup (yytext); return IDENTIFIER; } diff --git a/gst/parse/types.h b/gst/parse/types.h index a227ca7cdd..fa1c4051df 100644 --- a/gst/parse/types.h +++ b/gst/parse/types.h @@ -1,38 +1,43 @@ #include +#include "../gstelement.h" typedef struct { - gchar *name; + gchar *type; + gint index; GList *property_values; + GstElement *element; } element_t; typedef struct { gchar *name; - GType value_type; - union { - gdouble d; - gboolean b; - gint i; - gchar *s; - } value; + GValue *value; } property_t; typedef struct { - char *src; - char *sink; + /* if the names are present, upon connection we'll search out the pads of the + proper name and use those. otherwise, we'll search for elements of src_index + and sink_index. */ + char *src_name; + char *sink_name; + int src_index; + int sink_index; GList *src_pads; GList *sink_pads; } connection_t; -typedef struct { +typedef struct _graph_t graph_t; + +struct _graph_t { + element_t *first; element_t *current; + graph_t *parent; gchar *current_bin_type; GList *elements; GList *connections; GList *connections_pending; GList *bins; -} graph_t; + GstElement *bin; +}; + +graph_t * _gst_parse_launch (const gchar *str, GError **error); -typedef struct { - gchar *id1; - gchar *id2; -} hash_t; diff --git a/tests/muxing/case1.c b/tests/muxing/case1.c index 03e223d77b..2040651ab6 100644 --- a/tests/muxing/case1.c +++ b/tests/muxing/case1.c @@ -44,23 +44,18 @@ main(int argc,char *argv[]) sink = gst_elementfactory_make ("fakesink", "sink"); g_return_val_if_fail (sink != NULL, 4); - gst_bin_add (pipeline, GST_ELEMENT (src)); - gst_bin_add (pipeline, GST_ELEMENT (tee)); - gst_bin_add (pipeline, GST_ELEMENT (identity1)); - gst_bin_add (pipeline, GST_ELEMENT (identity2)); - gst_bin_add (pipeline, GST_ELEMENT (aggregator)); - gst_bin_add (pipeline, GST_ELEMENT (sink)); + gst_bin_add_many (pipeline, src, tee, identity1, identity2, aggregator, sink, NULL); - gst_element_connect (src, "src", tee, "sink"); - gst_pad_connect (gst_element_request_pad_by_name (tee, "src%d"), + gst_element_connect_pads (src, "src", tee, "sink"); + gst_pad_connect (gst_element_get_request_pad (tee, "src%d"), gst_element_get_pad (identity1, "sink")); - gst_pad_connect (gst_element_request_pad_by_name (tee, "src%d"), + gst_pad_connect (gst_element_get_request_pad (tee, "src%d"), gst_element_get_pad (identity2, "sink")); gst_pad_connect (gst_element_get_pad (identity1, "src"), - gst_element_request_pad_by_name (aggregator, "sink%d")); + gst_element_get_request_pad (aggregator, "sink%d")); gst_pad_connect (gst_element_get_pad (identity2, "src"), - gst_element_request_pad_by_name (aggregator, "sink%d")); - gst_element_connect (aggregator, "src", sink, "sink"); + gst_element_get_request_pad (aggregator, "sink%d")); + gst_element_connect_pads (aggregator, "src", sink, "sink"); g_signal_connect (G_OBJECT (src), "eos", G_CALLBACK (eos_signal), NULL); diff --git a/tests/old/examples/autoplug/autoplug.c b/tests/old/examples/autoplug/autoplug.c index 0848636555..1f7ae4f36b 100644 --- a/tests/old/examples/autoplug/autoplug.c +++ b/tests/old/examples/autoplug/autoplug.c @@ -19,22 +19,22 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); /* disconnect the typefind from the pipeline and remove it */ - gst_element_disconnect (cache, "src", typefind, "sink"); + gst_element_disconnect_pads (cache, "src", typefind, "sink"); gst_bin_remove (GST_BIN (autobin), typefind); /* and an audio sink */ - osssink = gst_elementfactory_make("osssink", "play_audio"); - g_assert(osssink != NULL); + osssink = gst_elementfactory_make ("osssink", "play_audio"); + g_assert (osssink != NULL); videosink = gst_bin_new ("videosink"); /* and an video sink */ - videoelement = gst_elementfactory_make("xvideosink", "play_video"); - g_assert(videosink != NULL); + videoelement = gst_elementfactory_make ("xvideosink", "play_video"); + g_assert (videosink != NULL); - colorspace = gst_elementfactory_make("colorspace", "colorspace"); - g_assert(colorspace != NULL); + colorspace = gst_elementfactory_make ("colorspace", "colorspace"); + g_assert (colorspace != NULL); - gst_element_connect (colorspace, "src", videoelement, "sink"); + gst_element_connect_pads (colorspace, "src", videoelement, "sink"); gst_bin_add (GST_BIN (videosink), colorspace); gst_bin_add (GST_BIN (videosink), videoelement); @@ -61,7 +61,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) g_object_set (G_OBJECT (cache), "reset", TRUE, NULL); - gst_element_connect (cache, "src", new_element, "sink"); + gst_element_connect_pads (cache, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -87,10 +87,9 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline) cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); - gst_element_disconnect (filesrc, "src", cache, "sink"); - gst_element_disconnect (cache, "src", new_element, "sink"); + gst_element_disconnect_many (filesrc, cache, new_element, NULL); gst_bin_remove (GST_BIN (autobin), cache); - gst_element_connect (filesrc, "src", new_element, "sink"); + gst_element_connect_pads (filesrc, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -132,14 +131,14 @@ int main(int argc,char *argv[]) gst_bin_add (GST_BIN (autobin), cache); gst_bin_add (GST_BIN (autobin), typefind); - gst_element_connect (cache, "src", typefind, "sink"); + gst_element_connect_pads (cache, "src", typefind, "sink"); gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink"); gst_bin_add (GST_BIN( pipeline), autobin); - gst_element_connect (filesrc, "src", autobin, "sink"); + gst_element_connect_pads (filesrc, "src", autobin, "sink"); /* start playing */ - gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING); + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); diff --git a/tests/old/examples/helloworld/helloworld.c b/tests/old/examples/helloworld/helloworld.c index d82d7157d5..67105949da 100644 --- a/tests/old/examples/helloworld/helloworld.c +++ b/tests/old/examples/helloworld/helloworld.c @@ -22,7 +22,7 @@ int main (int argc, char *argv[]) g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); /* now it's time to get the decoder */ - decoder = gst_elementfactory_make ("mad", "parse"); + decoder = gst_elementfactory_make ("mad", "decode"); if (!decoder) { g_print ("could not find plugin \"mad\""); return -1; @@ -35,7 +35,7 @@ int main (int argc, char *argv[]) gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL); /* connect the elements */ - gst_element_connect_elements_many (filesrc, decoder, osssink, NULL); + gst_element_connect_many (filesrc, decoder, osssink, NULL); /* start playing */ gst_element_set_state (bin, GST_STATE_PLAYING); diff --git a/tests/old/examples/helloworld2/helloworld2.c b/tests/old/examples/helloworld2/helloworld2.c index e36b74cb5d..4fa7e72826 100644 --- a/tests/old/examples/helloworld2/helloworld2.c +++ b/tests/old/examples/helloworld2/helloworld2.c @@ -18,8 +18,8 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); - /* disconnect the typefind from the pipeline and remove it */ - gst_element_disconnect (cache, "src", typefind, "sink"); + /* disconnect_pads the typefind from the pipeline and remove it */ + gst_element_disconnect_pads (cache, "src", typefind, "sink"); gst_bin_remove (GST_BIN (autobin), typefind); /* and an audio sink */ @@ -45,7 +45,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) g_object_set (G_OBJECT (cache), "reset", TRUE, NULL); - gst_element_connect (cache, "src", new_element, "sink"); + gst_element_connect_pads (cache, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); } @@ -67,10 +67,10 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline) cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); - gst_element_disconnect (filesrc, "src", cache, "sink"); - gst_element_disconnect (cache, "src", new_element, "sink"); + gst_element_disconnect_pads (filesrc, "src", cache, "sink"); + gst_element_disconnect_pads (cache, "src", new_element, "sink"); gst_bin_remove (GST_BIN (autobin), cache); - gst_element_connect (filesrc, "src", new_element, "sink"); + gst_element_connect_pads (filesrc, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -114,11 +114,11 @@ main (int argc, char *argv[]) gst_bin_add (GST_BIN (autobin), cache); gst_bin_add (GST_BIN (autobin), typefind); - gst_element_connect (cache, "src", typefind, "sink"); + gst_element_connect_pads (cache, "src", typefind, "sink"); gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink"); gst_bin_add (GST_BIN( pipeline), autobin); - gst_element_connect (filesrc, "src", autobin, "sink"); + gst_element_connect_pads (filesrc, "src", autobin, "sink"); /* start playing */ gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING); diff --git a/tests/old/examples/launch/mp3parselaunch.c b/tests/old/examples/launch/mp3parselaunch.c index 345cff3d45..5489b2652d 100644 --- a/tests/old/examples/launch/mp3parselaunch.c +++ b/tests/old/examples/launch/mp3parselaunch.c @@ -5,6 +5,7 @@ main (int argc, char *argv[]) { GstElement *pipeline; GstElement *filesrc; + GError *error = NULL; gst_init (&argc, &argv); @@ -13,8 +14,12 @@ main (int argc, char *argv[]) return -1; } - pipeline = (GstElement*) gst_parse_launch ("filesrc [ my_filesrc ] ! mad ! osssink"); - + pipeline = (GstElement*) gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error); + if (!pipeline) { + fprintf (stderr, "Parse error: %s", error->message); + exit (1); + } + filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); diff --git a/tests/old/examples/mixer/mixer.c b/tests/old/examples/mixer/mixer.c index 5e30152c2f..8bd3bde527 100644 --- a/tests/old/examples/mixer/mixer.c +++ b/tests/old/examples/mixer/mixer.c @@ -40,7 +40,7 @@ void eos(GstElement *element) /* playing = FALSE; */ } -static GstCaps* +G_GNUC_UNUSED static GstCaps* gst_play_typefind (GstBin *bin, GstElement *element) { GstElement *typefind; @@ -140,7 +140,7 @@ int main(int argc,char *argv[]) /* request pads and connect to adder */ GST_INFO (0, "requesting pad\n"); - pad = gst_element_request_pad_by_name (adder, "sink%d"); + pad = gst_element_get_request_pad (adder, "sink%d"); printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad)); sprintf (buffer, "channel%d", i); gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad); @@ -237,8 +237,8 @@ create_input_channel (int id, char* location) char buffer[20]; /* hold the names */ - GstAutoplug *autoplug; - GstCaps *srccaps; +/* GstAutoplug *autoplug; + GstCaps *srccaps; */ GstElement *new_element; GstElement *decoder; @@ -364,8 +364,8 @@ create_input_channel (int id, char* location) gst_bin_add (GST_BIN(channel->pipe), channel->volenv); gst_bin_add (GST_BIN (channel->pipe), new_element); - gst_element_connect (channel->filesrc, "src", new_element, "sink"); - gst_element_connect (new_element, "src_00", channel->volenv, "sink"); + gst_element_connect_pads (channel->filesrc, "src", new_element, "sink"); + gst_element_connect_pads (new_element, "src_00", channel->volenv, "sink"); /* add a ghost pad */ sprintf (buffer, "channel%d", id); diff --git a/tests/old/examples/xml/createxml.c b/tests/old/examples/xml/createxml.c index 00b09c56b1..d4501c9a69 100644 --- a/tests/old/examples/xml/createxml.c +++ b/tests/old/examples/xml/createxml.c @@ -19,7 +19,7 @@ object_saved (GstObject *object, xmlNodePtr parent, gpointer data) int main(int argc,char *argv[]) { - GstElement *filesrc, *osssink, *queue, *queue2, *parse, *decode; + GstElement *filesrc, *osssink, *queue, *queue2, *decode; GstElement *pipeline; GstElement *thread, *thread2; diff --git a/tests/old/examples/xml/runxml.c b/tests/old/examples/xml/runxml.c index 5b91e44ce4..e754d5f09e 100644 --- a/tests/old/examples/xml/runxml.c +++ b/tests/old/examples/xml/runxml.c @@ -4,7 +4,7 @@ gboolean playing; -static void +G_GNUC_UNUSED static void xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data) { xmlNodePtr children = self->xmlChildrenNode; diff --git a/tests/sched/dynamic-pipeline.c b/tests/sched/dynamic-pipeline.c index 5b25770d1c..baddae41b4 100644 --- a/tests/sched/dynamic-pipeline.c +++ b/tests/sched/dynamic-pipeline.c @@ -25,7 +25,7 @@ int main (int argc, char *argv[]) /* make the first pipeline */ gst_bin_add (GST_BIN(pipe1), fakesrc); gst_bin_add (GST_BIN(pipe1), fakesink1); - gst_element_connect(fakesrc, "src", fakesink1, "sink"); + gst_element_connect_pads (fakesrc, "src", fakesink1, "sink"); /* initialize cothreads */ gst_element_set_state(pipe1, GST_STATE_PLAYING); @@ -33,7 +33,7 @@ int main (int argc, char *argv[]) gst_element_set_state(pipe1, GST_STATE_READY); /* destroy the fakesink, but keep fakesrc (its state is GST_STATE_READY) */ - gst_element_disconnect(fakesrc, "src", fakesink1, "sink"); + gst_element_disconnect_pads (fakesrc, "src", fakesink1, "sink"); gst_object_ref(GST_OBJECT(fakesrc)); gst_bin_remove(GST_BIN(pipe1), fakesrc); gst_bin_remove(GST_BIN(pipe1), fakesink1); @@ -44,7 +44,7 @@ int main (int argc, char *argv[]) /* don't change the new pipeline's state, it should change on the bin_add */ gst_bin_add (GST_BIN(pipe2), fakesrc); - gst_element_connect(fakesrc, "src", fakesink2, "sink"); + gst_element_connect_pads (fakesrc, "src", fakesink2, "sink"); /* show the pipeline state */ gst_xml_write_file (GST_ELEMENT (pipe2), stdout); diff --git a/tools/gst-launch.c b/tools/gst-launch.c index 3890b01dfe..2e20805cdf 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -2,9 +2,6 @@ #include #include -static int launch_argc; -static char **launch_argv; - static guint64 iterations = 0; static guint64 sum = 0; static guint64 min = G_MAXINT; @@ -134,44 +131,37 @@ main(int argc, char *argv[]) { /* options */ gboolean silent = FALSE; + gchar *savefile = NULL; struct poptOption options[] = { - {"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0, "do not output status information", NULL}, + {"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0, + "do not output status information", NULL}, + {"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0, + "save xml representation of pipeline to FILE and exit", "FILE"}, POPT_TABLEEND }; GstElement *pipeline; gchar **argvn; - gboolean save_pipeline = FALSE; - gboolean run_pipeline = TRUE; - gchar *savefile = ""; + GError *error = NULL; free (malloc (8)); /* -lefence */ gst_init_with_popt_table (&argc, &argv, options); - if (argc >= 3 && !strcmp(argv[1], "-o")) { - save_pipeline = TRUE; - run_pipeline = FALSE; - savefile = argv[2]; - argv[2] = argv[0]; - argv+=2; - argc-=2; - } - - launch_argc = argc; - launch_argv = argv; - /* make a null-terminated version of argv */ - argvn = g_new0 (char *,argc); + argvn = g_new0 (char*, argc); memcpy (argvn, argv+1, sizeof (char*) * (argc-1)); if (strstr (argv[0], "gst-xmllaunch")) { - pipeline = xmllaunch_parse_cmdline ((const gchar **) argvn); + pipeline = xmllaunch_parse_cmdline ((const gchar**)argvn); } else { - pipeline = (GstElement*) gst_parse_launchv ((const gchar **) argvn); + pipeline = (GstElement*) gst_parse_launchv ((const gchar**)argvn, &error); } if (!pipeline) { - fprintf(stderr, "ERROR: pipeline could not be constructed\n"); + if (error) + fprintf(stderr, "ERROR: pipeline could not be constructed: %s\n", error->message); + else + fprintf(stderr, "ERROR: pipeline could not be constructed\n"); exit(1); } @@ -180,12 +170,12 @@ main(int argc, char *argv[]) g_signal_connect (pipeline, "error", G_CALLBACK (error_callback), NULL); #ifndef GST_DISABLE_LOADSAVE - if (save_pipeline) { + if (savefile) { gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w")); } #endif - if (run_pipeline) { + if (!savefile) { gst_buffer_print_stats(); fprintf(stderr,"RUNNING pipeline\n"); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {