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
This commit is contained in:
Andy Wingo 2002-04-07 23:32:16 +00:00
parent 3cbe1bacd0
commit 70cfc6cb4d
86 changed files with 2621 additions and 2495 deletions

View file

@ -93,15 +93,6 @@ GST_DEBUG_ENABLED
GST_DEBUG_ENABLE_CATEGORIES GST_DEBUG_ENABLE_CATEGORIES
</SECTION> </SECTION>
<SECTION>
<FILE>gstextratypes</FILE>
<TITLE>GstExtraTypes</TITLE>
GST_TYPE_FILENAME
<SUBSECTION Standard>
gst_extra_get_filename_type
GST_DISABLE_LOADSAVE_REGISTRY
</SECTION>
<SECTION> <SECTION>
<FILE>gstscheduler</FILE> <FILE>gstscheduler</FILE>
<TITLE>GstScheduler</TITLE> <TITLE>GstScheduler</TITLE>
@ -202,7 +193,7 @@ gst_bin_details
<SECTION> <SECTION>
<FILE>gstparse</FILE> <FILE>gstparse</FILE>
<TITLE>GstParse</TITLE> <TITLE>GstParse</TITLE>
GstParseErrors GstParseError
gst_parse_launch gst_parse_launch
gst_parse_launchv gst_parse_launchv
</SECTION> </SECTION>
@ -360,22 +351,25 @@ gst_element_get_managing_bin
gst_element_add_pad gst_element_add_pad
gst_element_remove_pad gst_element_remove_pad
gst_element_get_pad gst_element_get_pad
gst_element_get_static_pad
gst_element_get_request_pad
gst_element_get_pad_list gst_element_get_pad_list
gst_element_get_padtemplate_list gst_element_get_padtemplate_list
gst_element_get_padtemplate_by_name gst_element_get_padtemplate_by_name
gst_element_add_ghost_pad gst_element_add_ghost_pad
gst_element_remove_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_pad
gst_element_get_compatible_static_pad
gst_element_get_compatible_request_pad
gst_element_get_compatible_pad_filtered gst_element_get_compatible_pad_filtered
gst_element_connect gst_element_connect
gst_element_connect_many
gst_element_connect_filtered gst_element_connect_filtered
gst_element_connect_elements gst_element_connect_pads
gst_element_connect_elements_filtered gst_element_connect_pads_filtered
gst_element_connect_elements_many
gst_element_disconnect gst_element_disconnect
gst_element_disconnect_elements gst_element_disconnect_many
gst_element_disconnect_pads
gst_element_set_state gst_element_set_state
gst_element_get_state gst_element_get_state
gst_element_wait_state_change gst_element_wait_state_change
@ -499,22 +493,6 @@ GST_IS_CLOCK
GST_IS_CLOCK_CLASS GST_IS_CLOCK_CLASS
</SECTION> </SECTION>
<SECTION>
<FILE>gstsystemclock</FILE>
<TITLE>GstSystemClock</TITLE>
GstSystemClock
gst_system_clock_obtain
<SUBSECTION Standard>
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
</SECTION>
<SECTION> <SECTION>
<FILE>gstlog</FILE> <FILE>gstlog</FILE>
<SUBSECTION Standard> <SUBSECTION Standard>
@ -1096,211 +1074,3 @@ gst_static_autoplug_render_get_type
GST_STATIC_AUTOPLUG_RENDER_CLASS GST_STATIC_AUTOPLUG_RENDER_CLASS
GST_IS_STATIC_AUTOPLUG_RENDER_CLASS GST_IS_STATIC_AUTOPLUG_RENDER_CLASS
</SECTION> </SECTION>
<SECTION>
<FILE>gstaggregator</FILE>
<TITLE>GstAggregator</TITLE>
GstAggregatorSchedType
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>gstfilesrc</FILE>
<TITLE>GstFileSrc</TITLE>
<SUBSECTION Standard>
GstFileSrcFlags
GstFileSrc
GstFileSrcClass
gst_filesrc_get_type
GST_TYPE_FILESRC
GST_FILESRC
GST_FILESRC_CLASS
GST_IS_FILESRC
GST_IS_FILESRC_CLASS
</SECTION>
<SECTION>
<FILE>gstfakesink</FILE>
<TITLE>GstFakeSink</TITLE>
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>gstfakesrc</FILE>
<TITLE>GstFakeSrc</TITLE>
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>gstfdsink</FILE>
<TITLE>GstFdSink</TITLE>
<SUBSECTION Standard>
GstFdSink
GstFdSinkClass
gst_fdsink_get_type
GST_TYPE_FDSINK
GST_FDSINK
GST_FDSINK_CLASS
GST_IS_FDSINK
GST_IS_FDSINK_CLASS
</SECTION>
<SECTION>
<FILE>gstfdsrc</FILE>
<TITLE>GstFdSrc</TITLE>
<SUBSECTION Standard>
GstFdSrc
GstFdSrcClass
gst_fdsrc_get_type
GST_TYPE_FDSRC
GST_FDSRC
GST_FDSRC_CLASS
GST_IS_FDSRC
GST_IS_FDSRC_CLASS
</SECTION>
<SECTION>
<FILE>gstidentity</FILE>
<TITLE>GstIdentity</TITLE>
<SUBSECTION Standard>
GstIdentity
GstIdentityClass
gst_identity_get_type
GST_TYPE_IDENTITY
GST_IDENTITY
GST_IDENTITY_CLASS
GST_IS_IDENTITY
GST_IS_IDENTITY_CLASS
</SECTION>
<SECTION>
<FILE>gstqueue</FILE>
<TITLE>GstQueue</TITLE>
<SUBSECTION Standard>
GstQueue
GstQueueClass
gst_queue_get_type
GST_TYPE_QUEUE
GST_QUEUE
GST_QUEUE_CLASS
GST_IS_QUEUE
GST_IS_QUEUE_CLASS
</SECTION>
<SECTION>
<FILE>gstpipefilter</FILE>
<TITLE>GstPipefilter</TITLE>
<SUBSECTION Standard>
GST_TYPE_PIPEFILTER
GST_PIPEFILTER
GST_PIPEFILTER_CLASS
GST_IS_PIPEFILTER
GST_IS_PIPEFILTER_CLASS
GstPipeFilterFlags
GstPipefilter
GstPipefilterClass
gst_pipefilter_get_type
</SECTION>
<SECTION>
<FILE>gststatistics</FILE>
<TITLE>GstStatistics</TITLE>
<SUBSECTION Standard>
GstStatistics
GstStatisticsClass
stats
GST_STATISTICS
GST_IS_STATISTICS
GST_TYPE_STATISTICS
gst_statistics_get_type
GST_STATISTICS_CLASS
GST_IS_STATISTICS_CLASS
</SECTION>
<SECTION>
<FILE>gsttypefind</FILE>
<TITLE>GstTypeFind</TITLE>
<SUBSECTION Standard>
GstTypeFind
GstTypeFindClass
gst_typefind_get_type
GST_TYPE_TYPEFIND
GST_TYPEFIND
GST_TYPEFIND_CLASS
GST_IS_TYPEFIND
GST_IS_TYPEFIND_CLASS
</SECTION>
<SECTION>
<FILE>gstdisksink</FILE>
<TITLE>GstDiskSink</TITLE>
<SUBSECTION Standard>
GstDiskSink
GstDiskSinkFlags
GST_DISKSINK
GST_IS_DISKSINK
GST_TYPE_DISKSINK
gst_disksink_get_type
GST_DISKSINK_CLASS
GST_IS_DISKSINK_CLASS
</SECTION>
<SECTION>
<FILE>gstmultidisksrc</FILE>
<TITLE>GstMultiDiskSrc</TITLE>
GstMultiDiskSrcFlags
<SUBSECTION Standard>
GstMultiDiskSrc
GST_MULTIDISKSRC
GST_IS_MULTIDISKSRC
GST_TYPE_MULTIDISKSRC
gst_multidisksrc_get_type
GST_MULTIDISKSRC_CLASS
GST_IS_MULTIDISKSRC_CLASS
</SECTION>
<SECTION>
<FILE>gstmd5sink</FILE>
<TITLE>GstMD5Sink</TITLE>
<SUBSECTION Standard>
GST_MD5SINK
GST_IS_MD5SINK
GST_TYPE_MD5SINK
gst_md5sink_get_type
GST_MD5SINK_CLASS
GST_IS_MD5SINK_CLASS
gst_md5sink_factory_init
</SECTION>

View file

@ -10,7 +10,6 @@ gst_pad_get_type
gst_padtemplate_get_type gst_padtemplate_get_type
gst_ghost_pad_get_type gst_ghost_pad_get_type
gst_thread_get_type gst_thread_get_type
gst_tee_get_type
gst_plugin_feature_get_type gst_plugin_feature_get_type
gst_autoplug_get_type gst_autoplug_get_type
gst_autoplugfactory_get_type gst_autoplugfactory_get_type
@ -18,25 +17,5 @@ gst_typefactory_get_type
gst_elementfactory_get_type gst_elementfactory_get_type
gst_schedulerfactory_get_type gst_schedulerfactory_get_type
gst_scheduler_get_type gst_scheduler_get_type
gst_system_clock_get_type
gst_timecache_get_type gst_timecache_get_type
gst_xml_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

View file

@ -25,23 +25,3 @@ methods to request buffers from its pads.
@AGGREGATOR_LOOP_SELECT: @AGGREGATOR_LOOP_SELECT:
@AGGREGATOR_CHAIN: @AGGREGATOR_CHAIN:
<!-- ##### ARG GstAggregator:num-pads ##### -->
<para>
</para>
<!-- ##### ARG GstAggregator:silent ##### -->
<para>
</para>
<!-- ##### ARG GstAggregator:sched ##### -->
<para>
</para>
<!-- ##### ARG GstAggregator:last-message ##### -->
<para>
</para>

View file

@ -54,7 +54,6 @@ Flags for a bin.
@GST_BIN_SELF_SCHEDULABLE: @GST_BIN_SELF_SCHEDULABLE:
@GST_BIN_FLAG_PREFER_COTHREADS: @GST_BIN_FLAG_PREFER_COTHREADS:
@GST_BIN_FLAG_FIXED_CLOCK: @GST_BIN_FLAG_FIXED_CLOCK:
@GST_BIN_SELF_ITERATING:
@GST_BIN_FLAG_LAST: @GST_BIN_FLAG_LAST:
<!-- ##### STRUCT GstBin ##### --> <!-- ##### STRUCT GstBin ##### -->

View file

@ -14,20 +14,3 @@ The disksink write to a file. The filename can be given as an argument.
#GstFdSink #GstFdSink
</para> </para>
<!-- ##### SIGNAL GstDiskSink::handoff ##### -->
<para>
Is emited after the buffer has been written to the disk.
</para>
@gstdisksink: the object which received the signal.
<!-- ##### ARG GstDiskSink:location ##### -->
<para>
The filename to write to.
</para>
<!-- ##### ARG GstDiskSink:maxfilesize ##### -->
<para>
</para>

View file

@ -376,6 +376,26 @@ instead.
@Returns: GList of pads @Returns: GList of pads
<!-- ##### FUNCTION gst_element_get_static_pad ##### -->
<para>
</para>
@element:
@name:
@Returns:
<!-- ##### FUNCTION gst_element_get_request_pad ##### -->
<para>
</para>
@element:
@name:
@Returns:
<!-- ##### FUNCTION gst_element_get_pad_list ##### --> <!-- ##### FUNCTION gst_element_get_pad_list ##### -->
<para> <para>
@ -424,7 +444,17 @@ instead.
@pad: @pad:
<!-- ##### FUNCTION gst_element_request_compatible_pad ##### --> <!-- ##### FUNCTION gst_element_get_compatible_pad ##### -->
<para>
</para>
@element:
@pad:
@Returns:
<!-- ##### FUNCTION gst_element_get_compatible_static_pad ##### -->
<para> <para>
</para> </para>
@ -434,23 +464,13 @@ instead.
@Returns: @Returns:
<!-- ##### FUNCTION gst_element_request_pad_by_name ##### --> <!-- ##### FUNCTION gst_element_get_compatible_request_pad ##### -->
<para> <para>
</para> </para>
@element: @element:
@name: @templ:
@Returns:
<!-- ##### FUNCTION gst_element_get_compatible_pad ##### -->
<para>
</para>
@element:
@pad:
@Returns: @Returns:
@ -471,47 +491,14 @@ instead.
</para> </para>
@src: @src:
@dest:
@Returns:
<!-- # Unused Parameters # -->
@srcpadname: @srcpadname:
@dest:
@destpadname: @destpadname:
@Returns:
<!-- ##### FUNCTION gst_element_connect_filtered ##### --> <!-- ##### FUNCTION gst_element_connect_many ##### -->
<para>
</para>
@src:
@srcpadname:
@dest:
@destpadname:
@filtercaps:
@Returns:
<!-- ##### FUNCTION gst_element_connect_elements ##### -->
<para>
</para>
@src:
@dest:
@Returns:
<!-- ##### FUNCTION gst_element_connect_elements_filtered ##### -->
<para>
</para>
@src:
@dest:
@filtercaps:
@Returns:
<!-- ##### FUNCTION gst_element_connect_elements_many ##### -->
<para> <para>
</para> </para>
@ -522,7 +509,21 @@ instead.
@Returns: @Returns:
<!-- ##### FUNCTION gst_element_disconnect ##### --> <!-- ##### FUNCTION gst_element_connect_filtered ##### -->
<para>
</para>
@src:
@dest:
@filtercaps:
@Returns:
<!-- # Unused Parameters # -->
@srcpadname:
@destpadname:
<!-- ##### FUNCTION gst_element_connect_pads ##### -->
<para> <para>
</para> </para>
@ -531,15 +532,53 @@ instead.
@srcpadname: @srcpadname:
@dest: @dest:
@destpadname: @destpadname:
@Returns:
<!-- ##### FUNCTION gst_element_disconnect_elements ##### --> <!-- ##### FUNCTION gst_element_connect_pads_filtered ##### -->
<para>
</para>
@src:
@srcpadname:
@dest:
@destpadname:
@filtercaps:
@Returns:
<!-- ##### FUNCTION gst_element_disconnect ##### -->
<para> <para>
</para> </para>
@src: @src:
@dest: @dest:
<!-- # Unused Parameters # -->
@srcpadname:
@destpadname:
<!-- ##### FUNCTION gst_element_disconnect_many ##### -->
<para>
</para>
@element_1:
@element_2:
@Varargs:
<!-- ##### FUNCTION gst_element_disconnect_pads ##### -->
<para>
</para>
@src:
@srcpadname:
@dest:
@destpadname:
<!-- ##### FUNCTION gst_element_set_state ##### --> <!-- ##### FUNCTION gst_element_set_state ##### -->

View file

@ -16,36 +16,3 @@ with the buffer. (fakesink)
</para> </para>
<!-- ##### SIGNAL GstFakeSink::handoff ##### -->
<para>
This signal is emmitted when a buffer is handled.
</para>
@gstfakesink: the object which received the signal.
@arg1: The buffer that is received.
<!-- ##### ARG GstFakeSink:num-sinks ##### -->
<para>
The number of sink pads.
</para>
<!-- ##### ARG GstFakeSink:silent ##### -->
<para>
Indicates the plugin should not emit messages.
</para>
<!-- ##### ARG GstFakeSink:dump ##### -->
<para>
Dump the contents of the buffer
</para>
<!-- ##### ARG GstFakeSink:sync ##### -->
<para>
Sync on the clock
</para>
<!-- ##### ARG GstFakeSink:last-message ##### -->
<para>
The last message this plugin emmited.
</para>

View file

@ -14,86 +14,3 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
</para> </para>
<!-- ##### SIGNAL GstFakeSrc::handoff ##### -->
<para>
</para>
@gstfakesrc: the object which received the signal.
@arg1:
<!-- ##### ARG GstFakeSrc:num-sources ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:loop-based ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:output ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:data ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:sizetype ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:sizemin ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:sizemax ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:filltype ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:pattern ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:num-buffers ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:eos ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:silent ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:dump ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:parentsize ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:last-message ##### -->
<para>
</para>

View file

@ -14,8 +14,3 @@ Write data to a file descriptor.
</para> </para>
<!-- ##### ARG GstFdSink:fd ##### -->
<para>
The filedescriptor to write to.
</para>

View file

@ -14,18 +14,3 @@ Read buffers from a file descriptor.
</para> </para>
<!-- ##### ARG GstFdSrc:location ##### -->
<para>
The filedescriptor to read from. Pass the argument as a char* (???)
</para>
<!-- ##### ARG GstFdSrc:bytesperread ##### -->
<para>
The number of bytes per read.
</para>
<!-- ##### ARG GstFdSrc:offset ##### -->
<para>
Get the current offset in the file.
</para>

View file

@ -15,38 +15,3 @@ and subbuffers.
</para> </para>
<!-- ##### ARG GstFileSrc:offset ##### -->
<para>
The offset in the file that is currently being read.
</para>
<!-- ##### ARG GstFileSrc:location ##### -->
<para>
The filename
</para>
<!-- ##### ARG GstFileSrc:filesize ##### -->
<para>
The filesize.
</para>
<!-- ##### ARG GstFileSrc:fd ##### -->
<para>
The file descriptor.
</para>
<!-- ##### ARG GstFileSrc:blocksize ##### -->
<para>
The size of the buffers to pass to the peer element.
</para>
<!-- ##### ARG GstFileSrc:mmapsize ##### -->
<para>
The size of the mmapped area.
</para>
<!-- ##### ARG GstFileSrc:touch ##### -->
<para>
Indicates the mmapped area should be touched to bring it into memory.
</para>

View file

@ -14,51 +14,3 @@ Pass data without modification.
</para> </para>
<!-- ##### SIGNAL GstIdentity::handoff ##### -->
<para>
</para>
@gstidentity: the object which received the signal.
@arg1:
<!-- ##### ARG GstIdentity:loop-based ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:sleep-time ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:duplicate ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:error-after ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:drop-probability ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:silent ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:last-message ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:dump ##### -->
<para>
</para>

View file

@ -44,15 +44,14 @@ can be made with <option>{}</option>.
</para> </para>
<!-- ##### ENUM GstParseErrors ##### --> <!-- ##### ENUM GstParseError ##### -->
<para> <para>
</para> </para>
@GST_PARSE_ERROR_SYNTAX: @GST_PARSE_ERROR_SYNTAX:
@GST_PARSE_ERROR_CREATING_ELEMENT: @GST_PARSE_ERROR_NO_SUCH_ELEMENT:
@GST_PARSE_ERROR_NOSUCH_ELEMENT: @GST_PARSE_ERROR_NO_SUCH_PROPERTY:
@GST_PARSE_ERROR_INTERNAL:
@GST_PARSE_ERROR_CONNECT: @GST_PARSE_ERROR_CONNECT:
<!-- ##### FUNCTION gst_parse_launch ##### --> <!-- ##### FUNCTION gst_parse_launch ##### -->
@ -61,6 +60,7 @@ can be made with <option>{}</option>.
</para> </para>
@pipeline_description: @pipeline_description:
@error:
@Returns: @Returns:
<!-- # Unused Parameters # --> <!-- # Unused Parameters # -->
@cmdline: @cmdline:
@ -73,6 +73,7 @@ can be made with <option>{}</option>.
</para> </para>
@argv: @argv:
@error:
@Returns: @Returns:

View file

@ -15,8 +15,3 @@ buffers from its output.
</para> </para>
<!-- ##### ARG GstPipefilter:command ##### -->
<para>
Sets the command to be executed.
</para>

View file

@ -25,24 +25,3 @@ The queue blocks by default.
</para> </para>
<!-- ##### ARG GstQueue:leaky ##### -->
<para>
</para>
<!-- ##### ARG GstQueue:level ##### -->
<para>
Get the number of buffers in the queue.
</para>
<!-- ##### ARG GstQueue:max-level ##### -->
<para>
Specify the maximum number of buffers in the queue before the queue
blocks.
</para>
<!-- ##### ARG GstQueue:may-deadlock ##### -->
<para>
</para>

File diff suppressed because it is too large Load diff

View file

@ -15,55 +15,3 @@ the data stream, such as buffers/bytes/events etc.
</para> </para>
<!-- ##### SIGNAL GstStatistics::update ##### -->
<para>
</para>
@gststatistics: the object which received the signal.
<!-- ##### ARG GstStatistics:buffers ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:bytes ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:events ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:buffer-update-freq ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:bytes-update-freq ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:event-update-freq ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:update-on-eos ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:update ##### -->
<para>
</para>
<!-- ##### ARG GstStatistics:silent ##### -->
<para>
</para>

View file

@ -14,18 +14,3 @@ A tee can be used to split out the filter graph.
</para> </para>
<!-- ##### ARG GstTee:silent ##### -->
<para>
</para>
<!-- ##### ARG GstTee:num-pads ##### -->
<para>
</para>
<!-- ##### ARG GstTee:last-message ##### -->
<para>
</para>

View file

@ -15,16 +15,3 @@ the detected mime type of the stream. It is used in autoplugging.
</para> </para>
<!-- ##### SIGNAL GstTypeFind::have-type ##### -->
<para>
The signal to indicate the mime type was detected.
</para>
@gsttypefind: the object which received the signal.
@arg1: The mime type that was detected
<!-- ##### ARG GstTypeFind:caps ##### -->
<para>
</para>

View file

@ -21,28 +21,27 @@
<programlisting> <programlisting>
... ...
/* now it's time to get the parser */ /* now it's time to get the parser */
parse = gst_elementfactory_make ("mp3parse", "parse"); decoder = gst_elementfactory_make ("mad", "decoder");
decoder = gst_elementfactory_make ("mpg123", "decoder");
... ...
</programlisting> </programlisting>
<para> <para>
While this mechanism is quite effective it also has some big problems: While this mechanism is quite effective it also has some big problems:
The elements are created based on their name. Indeed, we create an The elements are created based on their name. Indeed, we create an
element mpg123 by explicitly stating the mpg123 elements name. element mad by explicitly stating the mad element's name.
Our little program therefore always uses the mpg123 decoder element Our little program therefore always uses the mad decoder element
to decode the MP3 audio stream, even if there are 3 other MP3 decoders 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 in the system. We will see how we can use a more general way to create
an MP3 decoder element. an MP3 decoder element.
</para> </para>
<para> <para>
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. added to the source and sink pads.
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title>more on MIME Types</title> <title>More on MIME Types</title>
<para> <para>
GStreamer uses MIME types to indentify the different types of data GStreamer uses MIME types to indentify the different types of data
that can be handled by the elements. They are the high level that can be handled by the elements. They are the high level
@ -125,8 +124,8 @@
the given MIME type. the given MIME type.
</para> </para>
<para> <para>
There is also an association between a MIME type and a file There is also an association between a MIME type and a file extension, but the use of typefind
extension. functions (similar to file(1)) is preferred..
</para> </para>
<para> <para>
The type information is maintained in a list of 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. This function will return 0 if the extension was not known.
</para> </para>
</sect2> </sect2>
<para>
<sect2> For more information, see <xref linkend="cha-autoplug"/>.
<title>id to <classname>GstElementFactory</classname> conversion</title> </para>
<para>
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.
</para>
<para>
Obtain a list of all the elements that use this id as source with:
</para>
<programlisting>
GList *list;
list = gst_type_gst_srcs (id);
</programlisting>
<para>
Obtain a list of all the elements that use this id as sink with:
</para>
<programlisting>
GList *list;
list = gst_type_gst_sinks (id);
</programlisting>
<para>
When you have a list of elements, you can simply take the first
element of the list to obtain an appropriate element.
</para>
<note>
<para>
As you can see, there might be a multitude of elements that
are able to operate on audio/raw types. some might include:
<itemizedlist>
<listitem>
<para>
an MP3 audio encoder.
</para>
</listitem>
<listitem>
<para>
an audio sink.
</para>
</listitem>
<listitem>
<para>
an audio resampler.
</para>
</listitem>
<listitem>
<para>
a spectrum filter.
</para>
</listitem>
</itemizedlist>
Depending on the application, you might want to use a different
element. This is why GStreamer leaves that decision up to the
application programmer.
</para>
</note>
</sect2>
<sect2>
<title>id to id path detection</title>
<para>
You can obtain a <classname>GList</classname> of elements that
will transform the source id into the destination id.
</para>
<programlisting>
GList *list;
list = gst_type_gst_sink_to_src (sourceid, sinkid);
</programlisting>
<para>
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.
</para>
</sect2>
</sect1> </sect1>
<sect1> <sect1>

View file

@ -1,7 +1,7 @@
<chapter id="cha-threads"> <chapter id="cha-threads">
<title>Threads</title> <title>Threads</title>
<para> <para>
GStreamer has support for multithreading throught the use of GStreamer has support for multithreading through the use of
the <classname>GstThread</classname> object. This object is in fact the <classname>GstThread</classname> object. This object is in fact
a special <classname>GstBin</classname> that will become a thread when started. a special <classname>GstBin</classname> that will become a thread when started.
</para> </para>
@ -13,39 +13,58 @@
<programlisting> <programlisting>
GstElement *my_thread; GstElement *my_thread;
// create the thread object /* create the thread object */
my_thread = gst_thread_new ("my_thread"); 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 (funky_src));
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect)); 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); gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING);
</programlisting> </programlisting>
<para> <para>
The above program will create a thread with two elements in it. As soon The above program will create a thread with two elements in it. As soon as it is set to the
as it is set to the PLAYING state, the thread will start to iterate. PLAYING state, the thread will start to iterate itself. You never need to manually iterate a
thread.
</para> </para>
<note> <sect2>
<title>Constraints placed on the pipeline by the GstThread</title>
<para> <para>
A thread should normally contain a source element. Most often, the thread Within the pipeline, everything is the same as in any other bin. The difference lies at the
is fed with data from a queue. 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 <xref
linkend="cha-queues"/>. 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.
</para> </para>
</note> </sect2>
<sect2>
<title>When would you want to use a thread?</title>
<para>
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.
</para>
</sect2>
<para> <para>
A thread will be visualised as below A thread can be visualised as below
</para> </para>
<figure float="1" id="sec-threads-img"> <figure float="1" id="sec-threads-img">
<title>a thread</title> <title>A thread</title>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/thread.&magic;" format="&magic;" /> <imagedata fileref="images/thread.&magic;" format="&magic;" />

View file

@ -32,6 +32,12 @@
Sets the mask for the info *and* the debug output. Sets the mask for the info *and* the debug output.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<option>--gst-mask-help</option>
Print out the meaning of gst-mask-* values.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<option>--gst-plugin-spew</option> <option>--gst-plugin-spew</option>
@ -47,16 +53,15 @@
<listitem> <listitem>
<para> <para>
<option>--help</option> Print the a short desciption of the <option>--help</option> Print the a short desciption of the
options and an overview of the current debugging/info masks options
set.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </para>
<para> <para>
The follwing table gives an overview of the mask values and The following table gives an overview of the mask values and their meaning. (enabled) means
their meaning. (enabled) means that the corresponding flag that the corresponding flag is set by default. This table is available to any GStreamer
has been set. application by the --gst-mask-help option.
</para> </para>
<programlisting> <programlisting>
Mask (to be OR'ed) info/debug FLAGS Mask (to be OR'ed) info/debug FLAGS

View file

@ -32,6 +32,12 @@
Sets the mask for the info *and* the debug output. Sets the mask for the info *and* the debug output.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<option>--gst-mask-help</option>
Print out the meaning of gst-mask-* values.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<option>--gst-plugin-spew</option> <option>--gst-plugin-spew</option>
@ -47,16 +53,15 @@
<listitem> <listitem>
<para> <para>
<option>--help</option> Print the a short desciption of the <option>--help</option> Print the a short desciption of the
options and an overview of the current debugging/info masks options
set.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </para>
<para> <para>
The follwing table gives an overview of the mask values and The following table gives an overview of the mask values and their meaning. (enabled) means
their meaning. (enabled) means that the corresponding flag that the corresponding flag is set by default. This table is available to any GStreamer
has been set. application by the --gst-mask-help option.
</para> </para>
<programlisting> <programlisting>
Mask (to be OR'ed) info/debug FLAGS Mask (to be OR'ed) info/debug FLAGS

View file

@ -4,38 +4,35 @@
</para> </para>
<sect1> <sect1>
<title><command>gstreamer-register</command></title> <title><command>gst-register</command></title>
<para> <para>
<command>gstreamer-register</command> is used to rebuild the database of plugins. <command>gst-register</command> is used to rebuild the database of plugins.
It is used after a new plugin has been added to the system. The plugin database It is used after a new plugin has been added to the system. The plugin database
can be found in <filename>/etc/gstreamer/reg.xml</filename>. can be found, by default, in <filename>/etc/gstreamer/reg.xml</filename>.
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title><command>gstreamer-launch</command></title> <title><command>gst-launch</command></title>
<para> <para>
This is a tool that will construct pipelines based on a command-line This is a tool that will construct pipelines based on a command-line
syntax. syntax. FIXME: need a more extensive grammar reference
</para> </para>
<para> <para>
A simple commandline looks like: A simple commandline looks like:
<screen> <screen>
gstreamer-launch filesrc location=hello.mp3 ! mp3parse ! mpg123 ! audiosink gst-launch filesrc location=hello.mp3 ! mad ! osssink
</screen> </screen>
A more complex pipeline looks like: A more complex pipeline looks like:
<screen> <screen>
gstreamer-launch filesrc redpill.vob audio_00! (ac3parse ! ac3dec ! audiosink) \ gst-launch filesrc location=redpill.vob ! mpegdemux name=demux \
video_00! (mpeg2dec ! videosink) demux.audio_00! { ac3parse ! a52dec ! osssink } \
demux.video_00! { mpeg2dec ! xvideosink }
</screen> </screen>
</para>
<para>
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.
</para> </para>
<para> <para>
You can also use the the parser in you own code. <application>GStreamer</application> You can also use the the parser in you own code. <application>GStreamer</application>
@ -51,16 +48,20 @@ main (int argc, char *argv[])
{ {
GstElement *pipeline; GstElement *pipeline;
GstElement *filesrc; GstElement *filesrc;
GError *error = NULL;
gst_init (&amp;argc, &amp;argv); gst_init (&amp;argc, &amp;argv);
if (argc != 2) { if (argc != 2) {
g_print ("usage: %s &lt;filename&gt;\n", argv[0]); g_print ("usage: &percnt;s &lt;filename&gt;\n", argv[0]);
return -1; 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", &amp;error);
if (!pipeline) {
g_print ("Parse error: &percnt;s\n", error->message);
exit (1);
}
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc"); filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
@ -81,20 +82,20 @@ main (int argc, char *argv[])
</sect1> </sect1>
<sect1> <sect1>
<title><command>gstreamer-inspect</command></title> <title><command>gst-inspect</command></title>
<para> <para>
This is a tool to query a plugin or an element about its properties. This is a tool to query a plugin or an element about its properties.
</para> </para>
<para> <para>
To query the information about the element mpg123, you would specify: To query the information about the element mad, you would specify:
</para> </para>
<screen> <screen>
gstreamer-inspect mpg123 gst-inspect mad
</screen> </screen>
<para> <para>
Below is the output of a query for the audiosink element: Below is the output of a query for the osssink element:
</para> </para>
<screen> <screen>
@ -102,56 +103,72 @@ Factory Details:
Long name: Audio Sink (OSS) Long name: Audio Sink (OSS)
Class: Sink/Audio Class: Sink/Audio
Description: Output to a sound card via OSS Description: Output to a sound card via OSS
Version: 0.1.0 Version: 0.3.3.1
Author(s): Erik Walthinsen &lt;omega@cse.ogi.edu&gt; Author(s): Erik Walthinsen &lt;omega@cse.ogi.edu&gt;, Wim Taymans &lt;wim.taymans@chello.be&gt;
Copyright: (C) 1999 Copyright: (C) 1999
GObject
+----GstObject
+----GstElement
+----GstOssSink
Pad Templates: Pad Templates:
SINK template: 'sink' SINK template: 'sink'
Exists: Always Availability: Always
Capabilities: Capabilities:
'audiosink_sink': 'osssink_sink':
MIME type: 'audio/raw': MIME type: 'audio/raw':
format: Integer: 16 format: String: int
endianness: Integer: 1234
width: List:
Integer: 8
Integer: 16
depth: List: depth: List:
Integer: 8 Integer: 8
Integer: 16 Integer: 16
rate: Integer range: 8000 - 48000
channels: Integer range: 1 - 2 channels: Integer range: 1 - 2
law: Integer: 0
signed: List:
Boolean: FALSE
Boolean: TRUE
rate: Integer range: 1000 - 48000
Element Flags: Element Flags:
GST_ELEMENT_THREADSUGGESTED GST_ELEMENT_THREADSUGGESTED
no flags set
Element Implementation: Element Implementation:
No loopfunc(), must be chain-based or not configured yet 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: Pads:
SINK: 'sink' SINK: 'sink'
Implementation: Implementation:
Has chainfunc(): 0x4001cde8 Has chainfunc(): 0x40056fc0
Has default eosfunc() gst_pad_eos_func()
Pad Template: 'sink' 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: Element Arguments:
GstAudioSink::mute: Boolean name : String (Default "element")
GstAudioSink::format: Enum (default 16) device : String (Default "/dev/dsp")
(8): 8 Bits mute : Boolean (Default false)
(16): 16 Bits format : Integer (Default 16)
GstAudioSink::channels: Enum (default 2) channels : Enum "GstAudiosinkChannels" (default 1)
(0): Silence
(1): Mono (1): Mono
(2): Stereo (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);
</screen> </screen>
<para> <para>
@ -159,11 +176,11 @@ Element Arguments:
</para> </para>
<screen> <screen>
gstreamer-inspect gstelements gst-inspect gstelements
</screen> </screen>
</sect1> </sect1>
<sect1> <sect1>
<title><command>gstmediaplay</command></title> <title><command>gst-play</command></title>
<para> <para>
A sample media player. A sample media player.
</para> </para>

View file

@ -2,8 +2,8 @@
<title>Autoplugging</title> <title>Autoplugging</title>
<para> <para>
<application>GStreamer</application> provides an API to automatically <application>GStreamer</application> provides an API to automatically
construct complex pipelinebased on source and destination capabilities. construct complex pipelines based on source and destination capabilities.
This feature is very usefull if you want to convert type X to type Y but 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 don't care about the plugins needed to accomplish this task. The
autoplugger will consult the plugin repository, select and connect the autoplugger will consult the plugin repository, select and connect the
elements needed for the conversion. elements needed for the conversion.
@ -106,7 +106,7 @@
<listitem> <listitem>
<para> <para>
Add the autoplugcache element to a bin and connect the sink pad to the src 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.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -141,8 +141,52 @@
</orderedlist> </orderedlist>
</para> </para>
<para> <para>
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. autoplugger, the autoplugcache and the typefind element.
</para> </para>
</sect1> </sect1>
<sect1>
<title>Another approach to autoplugging</title>
<para>
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.
</para>
<sect2>
<title>The spider element</title>
<para>
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:
<programlisting>
$ gst-launch filesrc location=my.mp3 ! spider ! osssink
</programlisting>
The spider will detect the type of the stream, autoplug it to the osssink's caps, and play
the pipeline. It's neat.
</para>
</sect2>
<sect2>
<title>Spider features</title>
<para>
<orderedlist>
<listitem>
<para>
Automatically typefinds the incoming stream.
</para>
</listitem>
<listitem>
<para>
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
<programlisting>
$ gst-launch filesrc location=my.mpeg1 ! spider ! { queue ! osssink } spider.src_%d!
{ queue ! xvideosink }
</programlisting>
</para>
</listitem>
</orderedlist>
</para>
</sect2>
</sect1>
</chapter> </chapter>

View file

@ -7,7 +7,7 @@
<para> <para>
Bins allow you to combine connected elements into one logical element. You do 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. 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. complex pipelines since it allows you to break up the pipeline in smaller chunks.
</para> </para>
<para> <para>
@ -37,9 +37,10 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
A thread (<classname>GstThread</classname>). All the elements in the thread bin will A thread (<classname>GstThread</classname>). The plan for the
run in a separate thread. You will have to use this bin if you carfully have to <classname>GstThread</classname> will be run in a separate thread. You will have to use
synchronize audio and video for example. You will learn more about threads in.. <!-- FIXME --> this bin if you have to carefully synchronize audio and video, for example. You will learn
more about threads in <xref linkend="cha-threads"/>.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@ -48,26 +49,22 @@
<sect1 id="sec-bin-create"> <sect1 id="sec-bin-create">
<title>Creating a bin</title> <title>Creating a bin</title>
<para> <para>
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:
</para> </para>
<programlisting> <programlisting>
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 */
</programlisting> bin = gst_elementfactory_make ("bin", "mybin");
<para>
A thread can be created with:
</para>
<programlisting>
GstElement *thread;
gst_thread_new ("mythread"); /* 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_&lt;bintype&gt;_new (). these are equivalent to the gst_elementfactory_make () syntax. */
pipeline = gst_pipeline_new ("pipeline_name");
</programlisting> </programlisting>
<para>
Pipelines are created with gst_pipeline_new ("name");
</para>
</sect1> </sect1>
<sect1 id="sec-bin-adding"> <sect1 id="sec-bin-adding">
@ -86,8 +83,9 @@
... ...
</programlisting> </programlisting>
<para> <para>
Bins and threads can be added to other bins too. This allows you to create nested Bins and threads can be added to other bins too. This allows you to create nested bins. Note
bins. that it doesn't make very much sense to add a <classname>GstPipeline</classname> to anything,
as it's a toplevel bin that needs to be explicitly iterated.
</para> </para>
<para> <para>
To get an element from the bin you can use: To get an element from the bin you can use:
@ -100,7 +98,7 @@
</programlisting> </programlisting>
<para> <para>
You can see that the name of the element becomes very handy for retrieving the 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. recursively search nested bins.
</para> </para>
<para> <para>
@ -114,7 +112,7 @@
while (elements) { while (elements) {
GstElement *element = GST_ELEMENT (elements-&gt;data); GstElement *element = GST_ELEMENT (elements-&gt;data);
g_print ("element in bin: &percnt;s\n", gst_element_get_name (element)); g_print ("element in bin: &percnt;s\n", GST_OBJECT_NAME (GST_OBJECT (element)));
elements = g_list_next (elements); elements = g_list_next (elements);
} }
@ -129,6 +127,18 @@
gst_bin_remove (GST_BIN (bin), element); gst_bin_remove (GST_BIN (bin), element);
... ...
</programlisting> </programlisting>
<para>
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.
</para>
<programlisting>
GstElement *filesrc, *decoder, *audiosink;
GstBin *bin;
/* instantiate the elements and the bins... */
gst_bin_add_many (bin, filesrc, decoder, audiosink, NULL);
</programlisting>
</sect1> </sect1>
<sect1 id="sec-bin-custom"> <sect1 id="sec-bin-custom">
@ -137,43 +147,56 @@
The application programmer can create custom bins packed with elements to perform a 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 specific task. This allow you to write an MPEG audio decoder with just the follwing lines
of code: of code:
</para>
<programlisting>
<programlisting> /* create the mp3player element */
// create the mp3player element
GstElement *mp3player = gst_elementfactory_make ("mp3player", "mp3player"); 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); g_object_set (G_OBJECT (mp3player), "location", "helloworld.mp3", NULL);
// start playback /* start playback */
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING); gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING);
... ...
// pause playback /* pause playback */
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED); gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED);
... ...
// stop /* stop */
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL); gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL);
</programlisting> </programlisting>
<para>
Note that the above code assumes that the mp3player bin derives itself from a
<classname>GstThread</classname>, which begins to play as soon as its state is set to PLAYING.
Other bin types may need explicit iteration. For more information, see <xref
linkend="cha-threads"/>.
Custom bins can be created with a plugin or an XML description. You will find more 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).
</para> </para>
</sect1> </sect1>
<sect1 id="sec-bin-ghostpads"> <sect1 id="sec-bin-ghostpads">
<title>Ghostpads</title> <title>Ghost pads</title>
<para> <para>
You can see from figure ... how a bin has no pads of its own. This is where Ghostpads You can see from figure <xref linkend="sec-bin-noghost-img"/> how a bin has no pads of its own.
come into play. This is where "ghost pads" come into play.
</para> </para>
<figure float="1" id="sec-bin-noghost-img">
<title>Visualisation of a <classname>GstBin</classname> element without ghost pads</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/bin-element-noghost.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
<para> <para>
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 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 you can then use the bin just like any other element. This is a very important feature
for creating custom bins. for creating custom bins.
</para> </para>
<figure float="1" id="sec-bin-ghost-img"> <figure float="1" id="sec-bin-ghost-img">
<title>Visualisation of a <classname>GstBin</classname> element with a ghostpad</title> <title>Visualisation of a <classname>GstBin</classname> element with a ghost pad</title>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/bin-element-ghost.&magic;" format="&magic;" /> <imagedata fileref="images/bin-element-ghost.&magic;" format="&magic;" />
@ -181,18 +204,18 @@
</mediaobject> </mediaobject>
</figure> </figure>
<para> <para>
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. of the bin.
</para> </para>
<para> <para>
Ghostpads can actually be added to all <classname>GstElement</classname>s and not just Ghost pads can actually be added to all <classname>GstElement</classname>s and not just
<classname>GstBin</classname>s. Use the following code example to add a ghostpad to a bin: <classname>GstBin</classname>s. Use the following code example to add a ghost pad to a bin:
</para> </para>
<programlisting> <programlisting>
GstElement *bin; GstElement *bin;
GstElement *element; GstElement *element;
element = gst_elementfactory_create ("mpg123", "decoder"); element = gst_elementfactory_create ("mad", "decoder");
bin = gst_bin_new ("mybin"); bin = gst_bin_new ("mybin");
gst_bin_add (GST_BIN (bin), element); gst_bin_add (GST_BIN (bin), element);
@ -210,7 +233,7 @@
filesrc = gst_elementfactory_create ("filesrc", "disk_reader"); filesrc = gst_elementfactory_create ("filesrc", "disk_reader");
gst_element_connect (filesrc, "src", bin, "sink"); gst_element_connect_pads (filesrc, "src", bin, "sink");
... ...
</programlisting> </programlisting>
</sect1> </sect1>

View file

@ -51,7 +51,7 @@
<para> <para>
A more complex case is when the filter modifies the data in place. It 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 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 the buffer is used in more than one element; a copy on write has to made in this
situation. situation.
</para> </para>

View file

@ -12,21 +12,16 @@
different components you are going to use are derived from this GstElement. 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. This means that a lot of functions you are going to use operate on this object.
</para> </para>
<para> <para> Elements, from the perspective of GStreamer, are viewed as "black boxes" with a number of
You will see that those elements have pads. These are the elements different aspects. One of these aspects is the presence of "pads", or connection points. This
connections with the 'outside' world. Depending on the number and direction of terminology arises from soldering; pads are where wires can be attached.
the pads, we can see three types of elements: source, filter and sink element.
</para>
<para>
These three types are all the same GstElement object, they just differ in how
the pads are.
</para> </para>
<sect2 id="sec-elements-src"> <sect2 id="sec-elements-src">
<title>GStreamer source elements</title> <title>Source elements</title>
<para> <para>
This element will generate data that will be used by the pipeline. It is Source elements generate data for use by a pipeline, for example reading from disk or from a
typically a file or an audio source. sound card.
</para> </para>
<para> <para>
Below you see how we will visualize the element. Below you see how we will visualize the element.
@ -48,18 +43,16 @@
</sect2> </sect2>
<sect2 id="sec-elements-filter"> <sect2 id="sec-elements-filter">
<title>GStreamer filter elements</title> <title>Filters and codecs</title>
<para> <para>
Filter elements both have an input and an output pad. They operate on data Filter elements both have input and output pads. They operate on data they receive in their
they receive in the sink pad and send the result to the src pad. sink pads and produce data on their src pads. For example, MPEG decoders and volume filters
would fall into this category.
</para> </para>
<para> <para>
Examples of a filter element might include: an MPEG decoder, volume filter,... Elements are not constrained as to the number of pads they migh have; for example, a video
</para> mixer might have two input pads (the images of the two different video streams) and one
<para> output pad.
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.
</para> </para>
<figure float="1" id="sec-element-filterimg"> <figure float="1" id="sec-element-filterimg">
<title>Visualisation of a filter element</title> <title>Visualisation of a filter element</title>
@ -71,7 +64,7 @@
</figure> </figure>
<para> <para>
The above figure shows the visualisation of a filter element. This element has 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. of the element.
</para> </para>
<figure float="1" id="sec-element-multifilterimg"> <figure float="1" id="sec-element-multifilterimg">
@ -84,20 +77,20 @@
</mediaobject> </mediaobject>
</figure> </figure>
<para> <para>
The above figure shows the visualisation of a filter element with more than one The above figure shows the visualisation of a filter element with more than one output pad.
output pad. An example of such a filter is the AVI splitter. This element will An example of such a filter is the AVI splitter (demuxer). This element will parse the input
parse the input data and extracts the audio and video data. Most of these filters data and extracts the audio and video data. Most of these filters dynamically send out a
dynamically send out a signal when a new pad is created so that the application signal when a new pad is created so that the application programmer can connect an arbitrary
programmer can connect an arbitrary element to the newly created pad. element to the newly created pad.
</para> </para>
</sect2> </sect2>
<sect2 id="sec-elements-sink"> <sect2 id="sec-elements-sink">
<title>GStreamer sink elements</title> <title>Sink elements</title>
<para> <para>
This element accepts data but will not generate any new data. A sink element Sink elements are terminal points in a media pipeline. They accept data but do not produce
is typically a file on disk, a soundcard, a display,... It is presented as anything. Disk writing, soundcard playback, and video output woul all be implemented by sink
below: elements.
</para> </para>
<figure float="1" id="sec-element-sinkimg"> <figure float="1" id="sec-element-sinkimg">
<title>Visualisation of a sink element</title> <title>Visualisation of a sink element</title>
@ -117,12 +110,12 @@
</para> </para>
<para> <para>
The following code example is used to get a factory that can be used to create the 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.
</para> </para>
<programlisting> <programlisting>
GstElementFactory *factory; GstElementFactory *factory;
factory = gst_elementfactory_find ("mpg123"); factory = gst_elementfactory_find ("mad");
</programlisting> </programlisting>
<para> <para>
Once you have the handle to the elementfactory, you can create a real element with Once you have the handle to the elementfactory, you can create a real element with
@ -134,22 +127,22 @@
element = gst_elementfactory_create (factory, "decoder"); element = gst_elementfactory_create (factory, "decoder");
</programlisting> </programlisting>
<para> <para>
gst_elementfactory_create () will use the elementfactory to create an element with the gst_elementfactory_create () will use the elementfactory to create an element with the given
given name. The name of the element is something you can use later on to lookup the name. The name of the element is something you can use later on to lookup the element in a
element in a bin, for example. bin, for example. You can pass NULL as the name argument to get a unique, default name.
</para> </para>
<para> <para>
A simple shortcut exists for creating an element from a factory. The following example A simple shortcut exists for creating an element from a factory. The following example creates
creates an element, named "decoder" from the elementfactory named "mpg123". This an element, named "decoder" from the elementfactory named "mad". This convenient function is
convenient function is most widly used to create an element. most widely used to create an element.
</para> </para>
<programlisting> <programlisting>
GstElement *element; GstElement *element;
element = gst_elementfactory_make ("mpg123", "decoder"); element = gst_elementfactory_make ("mad", "decoder");
</programlisting> </programlisting>
<para> <para>
An element can be destroyed with: An element can be destroyed with: FIXME talk about refcounting
</para> </para>
<programlisting> <programlisting>
GstElement *element; GstElement *element;

View file

@ -9,12 +9,11 @@
<sect1> <sect1>
<title>Hello world</title> <title>Hello world</title>
<para> <para>
We will create a simple first application. In fact it will be a complete We will create a simple first application, a complete MP3 player, using standard
MP3 player, using standard <application>GStreamer</application> components. The player will read from <application>GStreamer</application> components. The player will read from a file that is
a file that is given as the first argument of the program. given as the first argument of the program.
</para> </para>
<programlisting> <programlisting>
#include &lt;gst/gst.h&gt; #include &lt;gst/gst.h&gt;
@ -45,15 +44,10 @@ main (int argc, char *argv[])
audiosink = gst_elementfactory_make ("osssink", "play_audio"); audiosink = gst_elementfactory_make ("osssink", "play_audio");
/* add objects to the main pipeline */ /* add objects to the main pipeline */
gst_bin_add (GST_BIN (pipeline), filesrc); gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
gst_bin_add (GST_BIN (pipeline), decoder);
gst_bin_add (GST_BIN (pipeline), audiosink);
/* connect src to sink */ /* connect src to sink */
gst_pad_connect (gst_element_get_pad (filesrc, "src"), gst_element_connect_many (filesrc, decoder, audiosink, NULL);
gst_element_get_pad (decoder, "sink"));
gst_pad_connect (gst_element_get_pad (decoder, "src"),
gst_element_get_pad (audiosink, "sink"));
/* start playing */ /* start playing */
gst_element_set_state (pipeline, GST_STATE_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); gst_element_set_state (pipeline, GST_STATE_NULL);
/* we don't need a reference to these objects anymore */ /* 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)); gst_object_unref (GST_OBJECT (pipeline));
/* unreffing the pipeline unrefs the contained elements as well */
exit (0); exit (0);
} }
@ -98,8 +90,8 @@ main (int argc, char *argv[])
</programlisting> </programlisting>
<para> <para>
We are going to create 3 elements and one pipeline. Since all objects are We are going to create 3 elements and one pipeline. Since all elements share the same base
in fact elements, we can define them as: type, <classname>GstElement</classname>, we can define them as:
</para> </para>
<programlisting> <programlisting>
... ...
@ -142,7 +134,7 @@ main (int argc, char *argv[])
is installed on the system where this application is executed. is installed on the system where this application is executed.
</para> </para>
<programlisting> <programlisting>
/* now it's time to get the parser */ /* now it's time to get the decoder */
decoder = gst_elementfactory_make ("mad", "decoder"); decoder = gst_elementfactory_make ("mad", "decoder");
</programlisting> </programlisting>
<para> <para>
@ -167,9 +159,7 @@ main (int argc, char *argv[])
</para> </para>
<programlisting> <programlisting>
/* add objects to the main pipeline */ /* add objects to the main pipeline */
gst_bin_add (GST_BIN (pipeline), filesrc); gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
gst_bin_add (GST_BIN (pipeline), decoder);
gst_bin_add (GST_BIN (pipeline), audiosink);
</programlisting> </programlisting>
<para> <para>
@ -177,10 +167,7 @@ main (int argc, char *argv[])
</para> </para>
<programlisting> <programlisting>
/* connect src to sink */ /* connect src to sink */
gst_pad_connect (gst_element_get_pad (filesrc, "src"), gst_element_connect_many (filesrc, decoder, audiosink, NULL);
gst_element_get_pad (decoder, "sink"));
gst_pad_connect (gst_element_get_pad (decoder, "src"),
gst_element_get_pad (audiosink, "sink"));
</programlisting> </programlisting>
<para> <para>
@ -229,16 +216,13 @@ main (int argc, char *argv[])
/* stop the pipeline */ /* stop the pipeline */
gst_element_set_state (pipeline, GST_STATE_NULL); 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)); gst_object_unref (GST_OBJECT (pipeline));
exit (0); exit (0);
</programlisting> </programlisting>
<note> <note>
<para> <para>
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. all of the resources held by the elements.
</para> </para>
</note> </note>
@ -246,7 +230,7 @@ main (int argc, char *argv[])
</sect1> </sect1>
<sect1> <sect1>
<title>compiling helloworld.c</title> <title>Compiling helloworld.c</title>
<para> <para>
To compile the helloworld example, use: To compile the helloworld example, use:
</para> </para>
@ -268,10 +252,10 @@ main (int argc, char *argv[])
</sect1> </sect1>
<sect1> <sect1>
<title>conclusion</title> <title>Conclusion</title>
<para> <para>
This concludes our first example. As you see, setting up a pipeline 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. you can create a custom MP3 element with a more high level API.
</para> </para>
<para> <para>
@ -284,7 +268,7 @@ main (int argc, char *argv[])
We could use a disksink to write the raw samples to a file, for example. 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, 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 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.
</para> </para>
</sect1> </sect1>
</chapter> </chapter>

View file

@ -1,7 +1,7 @@
<chapter id="cha-pads"> <chapter id="cha-pads">
<title>GstPad</title> <title>GstPad</title>
<para> <para>
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. connections with the outside world.
</para> </para>
<para> <para>
@ -44,7 +44,7 @@
<title>Useful pad functions</title> <title>Useful pad functions</title>
<para> <para>
You can get the name of a pad with gst_pad_get_name () and set its name with 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().
</para> </para>
<para> <para>
gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink
@ -53,8 +53,8 @@
</para> </para>
<para> <para>
You can get the parent of the pad, this is the element that this pad belongs to, 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 with get_pad_get_parent(GstPad *pad). This function will return a pointer to a
GstObject. GstElement.
</para> </para>
</sect2> </sect2>
<sect2 id="sec-pads-dynamic"> <sect2 id="sec-pads-dynamic">
@ -66,7 +66,7 @@
system stream. system stream.
</para> </para>
<para> <para>
Running <application>gstreamer-inspect mpeg2parse</application> will show that Running <application>gst-inspect mpegdemux</application> will show that
the element has only one pad: a sink pad called 'sink'. The other pads are 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' "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 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 // 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); 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"); 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)); g_print ("new pad %s\n", gst_pad_get_name (pad));
... ...
</programlisting> </programlisting>
<para> <para>
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. from the element based on the name_template of the padtemplate.
</para> </para>
<para> <para>
It is also possible to request a pad that is compatible with another 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 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 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. is shown in the next example.
</para> </para>
<programlisting> <programlisting>
@ -162,11 +162,11 @@ main(int argc, char *argv[])
GstPad *pad; GstPad *pad;
... ...
element = gst_elementfactory_make ("tee", "element"); 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)); g_print ("new pad %s\n", gst_pad_get_name (pad));
... ...
</programlisting> </programlisting>
@ -181,7 +181,7 @@ main(int argc, char *argv[])
<para> <para>
We will briefly describe what capabilities are, enough for you to get a basic understanding 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 of the concepts. You will find more information on how to create capabilities in the
filter-writer-guide. Plugin Writer's Guide.
</para> </para>
<sect2 id="sec-pads-caps"> <sect2 id="sec-pads-caps">
@ -207,8 +207,8 @@ struct _GstCaps {
}; };
</programlisting> </programlisting>
<para> <para>
Below is a dump of the capabilities of the element mpg123, as shown by Below is a dump of the capabilities of the element mad, as shown by
<command>gstreamer-inspect</command>. <command>gst-inspect</command>.
You can see two pads: sink and src. Both pads have capability information attached to them. You can see two pads: sink and src. Both pads have capability information attached to them.
</para> </para>
<para> <para>
@ -221,26 +221,25 @@ struct _GstCaps {
</para> </para>
<programlisting> <programlisting>
Pads: Pads:
SINK: 'sink' SINK template: 'sink'
.... Availability: Always
Capabilities:
'mpg123_sink':
MIME type: 'audio/mp3':
layer: Integer range: 1 - 3
bitrate: Integer range: 8 - 320
framed: Boolean: TRUE
SRC: 'src'
....
Capabilities: Capabilities:
'mpg123_src': 'mad_sink':
MIME type: 'audio/raw': MIME type: 'audio/mp3':
format: Integer: 16
depth: Integer: 16 SRC template: 'src'
rate: Integer range: 11025 - 48000 Availability: Always
channels: List: Capabilities:
Integer: 1 'mad_src':
Integer: 2 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
</programlisting> </programlisting>
</sect2> </sect2>
<sect2 id="sec-pads-props"> <sect2 id="sec-pads-props">
@ -260,7 +259,7 @@ Pads:
<listitem> <listitem>
<para> <para>
An integer range value. The property denotes a range of possible values. In the case 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.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -349,7 +348,7 @@ Pads:
</para> </para>
<para> <para>
As we said, a capability has a name, a mime-type and some properties. The signature of the As we said, a capability has a name, a mime-type and some properties. The signature of the
function to create a new <classname>GstCaps *</classname> structure is like: function to create a new <classname>GstCaps</classname> structure is like:
<programlisting> <programlisting>
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props); GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
</programlisting> </programlisting>

View file

@ -20,6 +20,11 @@
one or more autopluggers one or more autopluggers
</para> </para>
</listitem> </listitem>
<listitem>
<para>
exported symbols for use in other plugins
</para>
</listitem>
</itemizedlist> </itemizedlist>
<para> <para>
The plugins have one simple method: plugin_init () where all the elementfactories are The plugins have one simple method: plugin_init () where all the elementfactories are

View file

@ -7,7 +7,7 @@
<para> <para>
Bins allow you to combine connected elements into one logical element. You do 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. 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. complex pipelines since it allows you to break up the pipeline in smaller chunks.
</para> </para>
<para> <para>
@ -37,9 +37,10 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
A thread (<classname>GstThread</classname>). All the elements in the thread bin will A thread (<classname>GstThread</classname>). The plan for the
run in a separate thread. You will have to use this bin if you carfully have to <classname>GstThread</classname> will be run in a separate thread. You will have to use
synchronize audio and video for example. You will learn more about threads in.. <!-- FIXME --> this bin if you have to carefully synchronize audio and video, for example. You will learn
more about threads in <xref linkend="cha-threads"/>.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@ -48,26 +49,22 @@
<sect1 id="sec-bin-create"> <sect1 id="sec-bin-create">
<title>Creating a bin</title> <title>Creating a bin</title>
<para> <para>
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:
</para> </para>
<programlisting> <programlisting>
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 */
</programlisting> bin = gst_elementfactory_make ("bin", "mybin");
<para>
A thread can be created with:
</para>
<programlisting>
GstElement *thread;
gst_thread_new ("mythread"); /* 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_&lt;bintype&gt;_new (). these are equivalent to the gst_elementfactory_make () syntax. */
pipeline = gst_pipeline_new ("pipeline_name");
</programlisting> </programlisting>
<para>
Pipelines are created with gst_pipeline_new ("name");
</para>
</sect1> </sect1>
<sect1 id="sec-bin-adding"> <sect1 id="sec-bin-adding">
@ -86,8 +83,9 @@
... ...
</programlisting> </programlisting>
<para> <para>
Bins and threads can be added to other bins too. This allows you to create nested Bins and threads can be added to other bins too. This allows you to create nested bins. Note
bins. that it doesn't make very much sense to add a <classname>GstPipeline</classname> to anything,
as it's a toplevel bin that needs to be explicitly iterated.
</para> </para>
<para> <para>
To get an element from the bin you can use: To get an element from the bin you can use:
@ -100,7 +98,7 @@
</programlisting> </programlisting>
<para> <para>
You can see that the name of the element becomes very handy for retrieving the 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. recursively search nested bins.
</para> </para>
<para> <para>
@ -114,7 +112,7 @@
while (elements) { while (elements) {
GstElement *element = GST_ELEMENT (elements-&gt;data); GstElement *element = GST_ELEMENT (elements-&gt;data);
g_print ("element in bin: &percnt;s\n", gst_element_get_name (element)); g_print ("element in bin: &percnt;s\n", GST_OBJECT_NAME (GST_OBJECT (element)));
elements = g_list_next (elements); elements = g_list_next (elements);
} }
@ -129,6 +127,18 @@
gst_bin_remove (GST_BIN (bin), element); gst_bin_remove (GST_BIN (bin), element);
... ...
</programlisting> </programlisting>
<para>
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.
</para>
<programlisting>
GstElement *filesrc, *decoder, *audiosink;
GstBin *bin;
/* instantiate the elements and the bins... */
gst_bin_add_many (bin, filesrc, decoder, audiosink, NULL);
</programlisting>
</sect1> </sect1>
<sect1 id="sec-bin-custom"> <sect1 id="sec-bin-custom">
@ -137,43 +147,56 @@
The application programmer can create custom bins packed with elements to perform a 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 specific task. This allow you to write an MPEG audio decoder with just the follwing lines
of code: of code:
</para>
<programlisting>
<programlisting> /* create the mp3player element */
// create the mp3player element
GstElement *mp3player = gst_elementfactory_make ("mp3player", "mp3player"); 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); g_object_set (G_OBJECT (mp3player), "location", "helloworld.mp3", NULL);
// start playback /* start playback */
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING); gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING);
... ...
// pause playback /* pause playback */
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED); gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED);
... ...
// stop /* stop */
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL); gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL);
</programlisting> </programlisting>
<para>
Note that the above code assumes that the mp3player bin derives itself from a
<classname>GstThread</classname>, which begins to play as soon as its state is set to PLAYING.
Other bin types may need explicit iteration. For more information, see <xref
linkend="cha-threads"/>.
Custom bins can be created with a plugin or an XML description. You will find more 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).
</para> </para>
</sect1> </sect1>
<sect1 id="sec-bin-ghostpads"> <sect1 id="sec-bin-ghostpads">
<title>Ghostpads</title> <title>Ghost pads</title>
<para> <para>
You can see from figure ... how a bin has no pads of its own. This is where Ghostpads You can see from figure <xref linkend="sec-bin-noghost-img"/> how a bin has no pads of its own.
come into play. This is where "ghost pads" come into play.
</para> </para>
<figure float="1" id="sec-bin-noghost-img">
<title>Visualisation of a <classname>GstBin</classname> element without ghost pads</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/bin-element-noghost.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
<para> <para>
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 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 you can then use the bin just like any other element. This is a very important feature
for creating custom bins. for creating custom bins.
</para> </para>
<figure float="1" id="sec-bin-ghost-img"> <figure float="1" id="sec-bin-ghost-img">
<title>Visualisation of a <classname>GstBin</classname> element with a ghostpad</title> <title>Visualisation of a <classname>GstBin</classname> element with a ghost pad</title>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/bin-element-ghost.&magic;" format="&magic;" /> <imagedata fileref="images/bin-element-ghost.&magic;" format="&magic;" />
@ -181,18 +204,18 @@
</mediaobject> </mediaobject>
</figure> </figure>
<para> <para>
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. of the bin.
</para> </para>
<para> <para>
Ghostpads can actually be added to all <classname>GstElement</classname>s and not just Ghost pads can actually be added to all <classname>GstElement</classname>s and not just
<classname>GstBin</classname>s. Use the following code example to add a ghostpad to a bin: <classname>GstBin</classname>s. Use the following code example to add a ghost pad to a bin:
</para> </para>
<programlisting> <programlisting>
GstElement *bin; GstElement *bin;
GstElement *element; GstElement *element;
element = gst_elementfactory_create ("mpg123", "decoder"); element = gst_elementfactory_create ("mad", "decoder");
bin = gst_bin_new ("mybin"); bin = gst_bin_new ("mybin");
gst_bin_add (GST_BIN (bin), element); gst_bin_add (GST_BIN (bin), element);
@ -210,7 +233,7 @@
filesrc = gst_elementfactory_create ("filesrc", "disk_reader"); filesrc = gst_elementfactory_create ("filesrc", "disk_reader");
gst_element_connect (filesrc, "src", bin, "sink"); gst_element_connect_pads (filesrc, "src", bin, "sink");
... ...
</programlisting> </programlisting>
</sect1> </sect1>

View file

@ -51,7 +51,7 @@
<para> <para>
A more complex case is when the filter modifies the data in place. It 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 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 the buffer is used in more than one element; a copy on write has to made in this
situation. situation.
</para> </para>

View file

@ -1,5 +1,10 @@
<chapter id="cha-components"> <chapter id="cha-components">
<title>Components</title> <title>Components</title>
<para>
FIXME: This chapter is way out of date.
</para>
<para> <para>
<application>GStreamer</application> includes components that people can include <application>GStreamer</application> includes components that people can include
in their programs. in their programs.

View file

@ -45,16 +45,42 @@
</programlisting> </programlisting>
<para> <para>
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: function:
</para> </para>
<programlisting> <programlisting>
// connect them // connect them
gst_element_connect (element1, "src", element2, "sink"); gst_element_connect_pads (element1, "src", element2, "sink");
.... ....
// and disconnect them // and disconnect them
gst_element_disconnect (element1, "src", element2, "sink"); gst_element_disconnect_pads (element1, "src", element2, "sink");
</programlisting>
<para>
An even more convenient shortcut for single-source, single-sink elements is the
gst_element_connect () function:
</para>
<programlisting>
// connect them
gst_element_connect (element1, element2);
....
// and disconnect them
gst_element_disconnect (element1, element2);
</programlisting>
<para>
If you have more than one element to connection, the gst_element_connect_many () function takes
a NULL-terminated list of elements:
</para>
<programlisting>
// connect them
gst_element_connect_many (element1, element2, element3, element4, NULL);
....
// and disconnect them
gst_element_disconnect_many (element1, element2, element3, element4, NULL);
</programlisting> </programlisting>
<para> <para>
@ -70,7 +96,7 @@
<title>Making filtered connections</title> <title>Making filtered connections</title>
<para> <para>
You can also force a specific media type on the connection by using gst_pad_connect_filtered () 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.
</para> </para>
</sect1> </sect1>

View file

@ -1,9 +1,9 @@
<chapter id="cha-cothreads"> <chapter id="cha-cothreads">
<title>Cothreads</title> <title>Cothreads</title>
<para> <para>
Cothreads are user-space threads that greatly reduce context Cothreads are user-space threads that greatly reduce context switching overhead introduced by
switching overhead introduced by regular kernel threads. regular kernel threads. Cothreads are also used to handle the more complex elements. They differ
Cothreads are also used to handle the more complex elements. from other user-space threading libraries in that they are scheduled explictly by GStreamer.
</para> </para>
<para> <para>
A cothread is created by a <classname>GstBin</classname> whenever an element is found A cothread is created by a <classname>GstBin</classname> whenever an element is found
@ -72,7 +72,7 @@ chain_function (GstPad *pad, GstBuffer *buffer)
<sect1 id="sec-loop-based"> <sect1 id="sec-loop-based">
<title>Loop-based elements</title> <title>Loop-based elements</title>
<para> <para>
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: infinite loop that looks like this:
<programlisting> <programlisting>
@ -97,24 +97,24 @@ chain_function (GstPad *pad, GstBuffer *buffer)
</para> </para>
<para> <para>
When the request for a buffer cannot immedialty satisfied, the control When the request for a buffer cannot immediatly satisfied, the control will be given to the
will be given to the source element of the loop-based element until it source element of the loop-based element until it performs a push on its source pad. At that
performs a push on its source pad. At that time the control is handed back time the control is handed back to the loop-based element, etc... The the execution trace can
to the loop-based element, etc... The the execution trace can get fairly get fairly complex using cothreads when there are multiple input/output pads for the
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
loop-based element. 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.
</para> </para>
<para> <para>
Loop based elements are mainly used for the more complex elements that need a Loop based elements are mainly used for the more complex elements that need a specific amount
specific amount of data before they can start to produce output. An example of data before they can start to produce output. An example of such an element is the mpeg
of such an element is the mpeg video decoder. the element will pull a buffer, video decoder. the element will pull a buffer, performs some decoding on it and optionally
performs some decoding on it and optionally requests more buffers to decode, when requests more buffers to decode, when a complete video frame has been decoded, a buffer is
a complete video frame has been decoded, a buffer is send out. send out. For example, any plugin using the bytestream library will need to be loop-based.
</para> </para>
<para> <para>
There is no problem in putting cothreaded elements into a There is no problem in putting cothreaded elements into a <classname>GstThread</classname> to
<classname>GstThread</classname> to create even more complex pipelines with create even more complex pipelines with both user and kernel space threads.
both user and kernel space threads.
</para> </para>
</sect1> </sect1>

View file

@ -32,6 +32,12 @@
Sets the mask for the info *and* the debug output. Sets the mask for the info *and* the debug output.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<option>--gst-mask-help</option>
Print out the meaning of gst-mask-* values.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<option>--gst-plugin-spew</option> <option>--gst-plugin-spew</option>
@ -47,16 +53,15 @@
<listitem> <listitem>
<para> <para>
<option>--help</option> Print the a short desciption of the <option>--help</option> Print the a short desciption of the
options and an overview of the current debugging/info masks options
set.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </para>
<para> <para>
The follwing table gives an overview of the mask values and The following table gives an overview of the mask values and their meaning. (enabled) means
their meaning. (enabled) means that the corresponding flag that the corresponding flag is set by default. This table is available to any GStreamer
has been set. application by the --gst-mask-help option.
</para> </para>
<programlisting> <programlisting>
Mask (to be OR'ed) info/debug FLAGS Mask (to be OR'ed) info/debug FLAGS

View file

@ -36,10 +36,10 @@ idle_func (gpointer data)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
GstElement *pipeline, *src, *parse; GstElement *pipeline, *src, *demux;
struct poptOption *gst_table;
gst_init (&amp;argc, &amp;argv); gst_init (&amp;argc, &amp;argv);
gnome_init ("MPEG1 Video player","0.0.1", argc, argv);
pipeline = gst_pipeline_new ("pipeline"); pipeline = gst_pipeline_new ("pipeline");
g_return_val_if_fail (pipeline != NULL, -1); 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_return_val_if_fail (src != NULL, -1);
g_object_set (G_OBJECT (src), "location", argv[1], NULL); g_object_set (G_OBJECT (src), "location", argv[1], NULL);
parse = gst_elementfactory_make ("mpeg1parse", "parse"); demux = gst_elementfactory_make ("mpegdemux", "demux");
g_return_val_if_fail (parse != NULL, -1); g_return_val_if_fail (demux != NULL, -1);
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (src)); gst_bin_add_many (GST_BIN (pipeline), src, demux, NULL);
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (parse));
g_signal_connect (G_OBJECT (parse), "new_pad", g_signal_connect (G_OBJECT (demux), "new_pad",
G_CALLBACK (new_pad_created), pipeline); G_CALLBACK (new_pad_created), pipeline);
g_signal_connect (G_OBJECT (src), "eos", g_signal_connect (G_OBJECT (src), "eos",
G_CALLBACK (eof), NULL); G_CALLBACK (eof), NULL);
gst_pad_connect (gst_element_get_pad (src, "src"), gst_element_connect (src, parse);
gst_element_get_pad (parse, "sink"));
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
@ -76,19 +74,18 @@ main(int argc, char *argv[])
</programlisting> </programlisting>
<para> <para>
We create two elements: a filesrc (the element that will read the We create two elements: a file source and an MPEG demuxer.. We also add an EOS (End Of Stream)
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
signal to the filesrc so that we will be notified when the file has ended. special about this piece of code except for the signal 'new_pad' that we connected to the
There's nothing special about this piece of code except for the signal mpegdemux using:
'new_pad' that we connected to the mpeg1parser using:
</para> </para>
<programlisting> <programlisting>
g_signal_connect (G_OBJECT (parse), "new_pad", g_signal_connect (G_OBJECT (demux), "new_pad",
G_CALLBACK (new_pad_created), pipeline); G_CALLBACK (new_pad_created), pipeline);
</programlisting> </programlisting>
<para> <para>
When an elementary stream has been detected in the system stream, 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 elementary stream. A function 'new_pad_created' will be called when
the pad is created: the pad is created:
</para> </para>
@ -96,12 +93,10 @@ main(int argc, char *argv[])
void void
new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline) 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_queue, *video_queue;
GstElement *audio_thread, *video_thread; GstElement *audio_thread, *video_thread;
GtkWidget *appwindow;
g_print ("***** a new pad &percnt;s was created\n", gst_pad_get_name (pad)); g_print ("***** a new pad &percnt;s was created\n", gst_pad_get_name (pad));
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED); 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) { if (strncmp (gst_pad_get_name (pad), "audio_", 6) == 0) {
// construct internal pipeline elements // construct internal pipeline elements
parse_audio = gst_elementfactory_make ("mp3parse", "parse_audio"); decode = gst_elementfactory_make ("mad", "decode_audio");
g_return_if_fail (parse_audio != NULL);
decode = gst_elementfactory_make ("mpg123", "decode_audio");
g_return_if_fail (decode != NULL); 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); g_return_if_fail (play != NULL);
// create the thread and pack stuff into it // create the thread and pack stuff into it
audio_thread = gst_thread_new ("audio_thread"); audio_thread = gst_thread_new ("audio_thread");
g_return_if_fail (audio_thread != NULL); g_return_if_fail (audio_thread != NULL);
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (parse_audio)); gst_bin_add_many (GST_BIN (audio_thread), decode_audio, play, NULL);
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (decode));
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (play));
// set up pad connections // set up pad connections
gst_element_add_ghost_pad (GST_ELEMENT (audio_thread), gst_element_add_ghost_pad (GST_ELEMENT (audio_thread),
gst_element_get_pad (parse_audio, "sink")); gst_element_get_pad (decode_audio, "sink"));
gst_pad_connect (gst_element_get_pad (parse_audio,"src"), gst_element_connect (decode, play);
gst_element_get_pad (decode,"sink"));
gst_pad_connect (gst_element_get_pad (decode,"src"),
gst_element_get_pad (play,"sink"));
// construct queue and connect everything in the main pipelie // construct queue and connect everything in the main pipelie
audio_queue = gst_elementfactory_make ("queue", "audio_queue"); audio_queue = gst_elementfactory_make ("queue", "audio_queue");
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_queue)); gst_bin_add_many (GST_BIN (pipeline), audio_queue, audio_thread, NULL);
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_thread));
gst_pad_connect (pad, gst_pad_connect (pad, gst_element_get_pad (audio_queue, "sink"));
gst_element_get_pad (audio_queue, "sink")); gst_element_connect (audio_queue, audio_thread);
gst_pad_connect (gst_element_get_pad (audio_queue, "src"),
gst_element_get_pad (audio_thread, "sink"));
// set up thread state and kick things off // set up thread state and kick things off
g_print ("setting to READY state\n"); 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) { else if (strncmp (gst_pad_get_name (pad), "video_", 6) == 0) {
// construct internal pipeline elements // construct internal pipeline elements
parse_video = gst_elementfactory_make ("mp1videoparse", "parse_video"); decode_video = gst_elementfactory_make ("mpeg2dec", "decode_video");
g_return_if_fail (parse_video != NULL);
decode_video = gst_elementfactory_make ("mpeg_play", "decode_video");
g_return_if_fail (decode_video != NULL); 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); 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 // create the thread and pack stuff into it
video_thread = gst_thread_new ("video_thread"); video_thread = gst_thread_new ("video_thread");
g_return_if_fail (video_thread != NULL); g_return_if_fail (video_thread != NULL);
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (parse_video)); gst_bin_add_many (GST_BIN (video_thread), decode_video, show, NULL);
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (decode_video));
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (show));
// set up pad connections // set up pad connections
gst_element_add_ghost_pad (GST_ELEMENT (video_thread), gst_element_add_ghost_pad (GST_ELEMENT (video_thread),
gst_element_get_pad (parse_video, "sink")); gst_element_get_pad (parse_video, "sink"));
gst_pad_connect (gst_element_get_pad (parse_video, "src"), gst_element_connect (decode_video, show);
gst_element_get_pad (decode_video, "sink"));
gst_pad_connect (gst_element_get_pad (decode_video, "src"),
gst_element_get_pad (show, "sink"));
// construct queue and connect everything in the main pipeline // construct queue and connect everything in the main pipeline
video_queue = gst_elementfactory_make ("queue", "video_queue"); video_queue = gst_elementfactory_make ("queue", "video_queue");
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_queue)); gst_bin_add_many (GST_BIN (pipeline), video_queue, video_thread);
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_thread));
gst_pad_connect (pad, gst_pad_connect (pad, gst_element_get_pad (video_queue, "sink"));
gst_element_get_pad (video_queue, "sink")); gst_element_connect (video_queue, video_thread);
gst_pad_connect (gst_element_get_pad (video_queue, "src"),
gst_element_get_pad (video_thread, "sink"));
// set up thread state and kick things off // 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"); g_print ("setting to READY state\n");
gst_element_set_state (GST_ELEMENT (video_thread), GST_STATE_READY); gst_element_set_state (GST_ELEMENT (video_thread), GST_STATE_READY);
} }
@ -200,9 +169,8 @@ new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline)
} }
</programlisting> </programlisting>
<para> <para>
In the above example, we created new elements based on the name of In the above example, we created new elements based on the name of the newly created pad. We
the newly created pad. We added them to a new thread There are other possibilities to check the then added them to a new thread. There are other possibilities to check the type of the pad, for
type of the pad, for example, by using the MIME type and the properties example by using the MIME type and the properties of the pad.
of the pad.
</para> </para>
</chapter> </chapter>

View file

@ -12,21 +12,16 @@
different components you are going to use are derived from this GstElement. 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. This means that a lot of functions you are going to use operate on this object.
</para> </para>
<para> <para> Elements, from the perspective of GStreamer, are viewed as "black boxes" with a number of
You will see that those elements have pads. These are the elements different aspects. One of these aspects is the presence of "pads", or connection points. This
connections with the 'outside' world. Depending on the number and direction of terminology arises from soldering; pads are where wires can be attached.
the pads, we can see three types of elements: source, filter and sink element.
</para>
<para>
These three types are all the same GstElement object, they just differ in how
the pads are.
</para> </para>
<sect2 id="sec-elements-src"> <sect2 id="sec-elements-src">
<title>GStreamer source elements</title> <title>Source elements</title>
<para> <para>
This element will generate data that will be used by the pipeline. It is Source elements generate data for use by a pipeline, for example reading from disk or from a
typically a file or an audio source. sound card.
</para> </para>
<para> <para>
Below you see how we will visualize the element. Below you see how we will visualize the element.
@ -48,18 +43,16 @@
</sect2> </sect2>
<sect2 id="sec-elements-filter"> <sect2 id="sec-elements-filter">
<title>GStreamer filter elements</title> <title>Filters and codecs</title>
<para> <para>
Filter elements both have an input and an output pad. They operate on data Filter elements both have input and output pads. They operate on data they receive in their
they receive in the sink pad and send the result to the src pad. sink pads and produce data on their src pads. For example, MPEG decoders and volume filters
would fall into this category.
</para> </para>
<para> <para>
Examples of a filter element might include: an MPEG decoder, volume filter,... Elements are not constrained as to the number of pads they migh have; for example, a video
</para> mixer might have two input pads (the images of the two different video streams) and one
<para> output pad.
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.
</para> </para>
<figure float="1" id="sec-element-filterimg"> <figure float="1" id="sec-element-filterimg">
<title>Visualisation of a filter element</title> <title>Visualisation of a filter element</title>
@ -71,7 +64,7 @@
</figure> </figure>
<para> <para>
The above figure shows the visualisation of a filter element. This element has 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. of the element.
</para> </para>
<figure float="1" id="sec-element-multifilterimg"> <figure float="1" id="sec-element-multifilterimg">
@ -84,20 +77,20 @@
</mediaobject> </mediaobject>
</figure> </figure>
<para> <para>
The above figure shows the visualisation of a filter element with more than one The above figure shows the visualisation of a filter element with more than one output pad.
output pad. An example of such a filter is the AVI splitter. This element will An example of such a filter is the AVI splitter (demuxer). This element will parse the input
parse the input data and extracts the audio and video data. Most of these filters data and extracts the audio and video data. Most of these filters dynamically send out a
dynamically send out a signal when a new pad is created so that the application signal when a new pad is created so that the application programmer can connect an arbitrary
programmer can connect an arbitrary element to the newly created pad. element to the newly created pad.
</para> </para>
</sect2> </sect2>
<sect2 id="sec-elements-sink"> <sect2 id="sec-elements-sink">
<title>GStreamer sink elements</title> <title>Sink elements</title>
<para> <para>
This element accepts data but will not generate any new data. A sink element Sink elements are terminal points in a media pipeline. They accept data but do not produce
is typically a file on disk, a soundcard, a display,... It is presented as anything. Disk writing, soundcard playback, and video output woul all be implemented by sink
below: elements.
</para> </para>
<figure float="1" id="sec-element-sinkimg"> <figure float="1" id="sec-element-sinkimg">
<title>Visualisation of a sink element</title> <title>Visualisation of a sink element</title>
@ -117,12 +110,12 @@
</para> </para>
<para> <para>
The following code example is used to get a factory that can be used to create the 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.
</para> </para>
<programlisting> <programlisting>
GstElementFactory *factory; GstElementFactory *factory;
factory = gst_elementfactory_find ("mpg123"); factory = gst_elementfactory_find ("mad");
</programlisting> </programlisting>
<para> <para>
Once you have the handle to the elementfactory, you can create a real element with Once you have the handle to the elementfactory, you can create a real element with
@ -134,22 +127,22 @@
element = gst_elementfactory_create (factory, "decoder"); element = gst_elementfactory_create (factory, "decoder");
</programlisting> </programlisting>
<para> <para>
gst_elementfactory_create () will use the elementfactory to create an element with the gst_elementfactory_create () will use the elementfactory to create an element with the given
given name. The name of the element is something you can use later on to lookup the name. The name of the element is something you can use later on to lookup the element in a
element in a bin, for example. bin, for example. You can pass NULL as the name argument to get a unique, default name.
</para> </para>
<para> <para>
A simple shortcut exists for creating an element from a factory. The following example A simple shortcut exists for creating an element from a factory. The following example creates
creates an element, named "decoder" from the elementfactory named "mpg123". This an element, named "decoder" from the elementfactory named "mad". This convenient function is
convenient function is most widly used to create an element. most widely used to create an element.
</para> </para>
<programlisting> <programlisting>
GstElement *element; GstElement *element;
element = gst_elementfactory_make ("mpg123", "decoder"); element = gst_elementfactory_make ("mad", "decoder");
</programlisting> </programlisting>
<para> <para>
An element can be destroyed with: An element can be destroyed with: FIXME talk about refcounting
</para> </para>
<programlisting> <programlisting>
GstElement *element; GstElement *element;

View file

@ -21,28 +21,27 @@
<programlisting> <programlisting>
... ...
/* now it's time to get the parser */ /* now it's time to get the parser */
parse = gst_elementfactory_make ("mp3parse", "parse"); decoder = gst_elementfactory_make ("mad", "decoder");
decoder = gst_elementfactory_make ("mpg123", "decoder");
... ...
</programlisting> </programlisting>
<para> <para>
While this mechanism is quite effective it also has some big problems: While this mechanism is quite effective it also has some big problems:
The elements are created based on their name. Indeed, we create an The elements are created based on their name. Indeed, we create an
element mpg123 by explicitly stating the mpg123 elements name. element mad by explicitly stating the mad element's name.
Our little program therefore always uses the mpg123 decoder element Our little program therefore always uses the mad decoder element
to decode the MP3 audio stream, even if there are 3 other MP3 decoders 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 in the system. We will see how we can use a more general way to create
an MP3 decoder element. an MP3 decoder element.
</para> </para>
<para> <para>
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. added to the source and sink pads.
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title>more on MIME Types</title> <title>More on MIME Types</title>
<para> <para>
GStreamer uses MIME types to indentify the different types of data GStreamer uses MIME types to indentify the different types of data
that can be handled by the elements. They are the high level that can be handled by the elements. They are the high level
@ -125,8 +124,8 @@
the given MIME type. the given MIME type.
</para> </para>
<para> <para>
There is also an association between a MIME type and a file There is also an association between a MIME type and a file extension, but the use of typefind
extension. functions (similar to file(1)) is preferred..
</para> </para>
<para> <para>
The type information is maintained in a list of 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. This function will return 0 if the extension was not known.
</para> </para>
</sect2> </sect2>
<para>
<sect2> For more information, see <xref linkend="cha-autoplug"/>.
<title>id to <classname>GstElementFactory</classname> conversion</title> </para>
<para>
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.
</para>
<para>
Obtain a list of all the elements that use this id as source with:
</para>
<programlisting>
GList *list;
list = gst_type_gst_srcs (id);
</programlisting>
<para>
Obtain a list of all the elements that use this id as sink with:
</para>
<programlisting>
GList *list;
list = gst_type_gst_sinks (id);
</programlisting>
<para>
When you have a list of elements, you can simply take the first
element of the list to obtain an appropriate element.
</para>
<note>
<para>
As you can see, there might be a multitude of elements that
are able to operate on audio/raw types. some might include:
<itemizedlist>
<listitem>
<para>
an MP3 audio encoder.
</para>
</listitem>
<listitem>
<para>
an audio sink.
</para>
</listitem>
<listitem>
<para>
an audio resampler.
</para>
</listitem>
<listitem>
<para>
a spectrum filter.
</para>
</listitem>
</itemizedlist>
Depending on the application, you might want to use a different
element. This is why GStreamer leaves that decision up to the
application programmer.
</para>
</note>
</sect2>
<sect2>
<title>id to id path detection</title>
<para>
You can obtain a <classname>GList</classname> of elements that
will transform the source id into the destination id.
</para>
<programlisting>
GList *list;
list = gst_type_gst_sink_to_src (sourceid, sinkid);
</programlisting>
<para>
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.
</para>
</sect2>
</sect1> </sect1>
<sect1> <sect1>

View file

@ -38,11 +38,11 @@
<sect2 id="sec-goals-object"> <sect2 id="sec-goals-object">
<title>Object oriented</title> <title>Object oriented</title>
<para> <para>
Adhere as much as possible to the glib2.0 object model. A programmer familiar Adhere to the GLib 2.0 object model. A programmer familiar with GLib 2.0 or older versions
with glib2 and GTK+ will be confortable with GStreamer. of Gtk+ will be comfortable with GStreamer.
</para> </para>
<para> <para>
GStreamer uses the mechanism of signals and object arguments. GStreamer uses the mechanism of signals and object properties.
</para> </para>
<para> <para>
All objects can be queried at runtime for their various properties and All objects can be queried at runtime for their various properties and
@ -53,7 +53,7 @@
<sect2 id="sec-goals-extensible"> <sect2 id="sec-goals-extensible">
<title>Extensible</title> <title>Extensible</title>
<para> <para>
All GStreamer Objects can be extended using the glib2 inheritance methods. All GStreamer Objects can be extended using the GObject inheritance methods.
</para> </para>
<para> <para>
All plugins are loaded dynamically and can be extended and upgraded All plugins are loaded dynamically and can be extended and upgraded
@ -64,14 +64,13 @@
<sect2 id="sec-goals-binary"> <sect2 id="sec-goals-binary">
<title>Allow binary only plugins</title> <title>Allow binary only plugins</title>
<para> <para>
plugins are shared libraries that are loaded at runtime. since all the Plugins are shared libraries that are loaded at runtime. Since all the properties of the
properties of the plugin can be set using the GObject properties, there plugin can be set using the GObject properties, there is no need (and in fact no way) to
is no need to have any header files installed for the plugins. have any header files installed for the plugins.
</para> </para>
<para> <para>
Special care has been taking into making the plugin completely self Special care has been taking into making the plugin completely self
contained. This is in the operations, specification of the capabilities contained. All relevant aspects of plugins can be queried at run-time.
of the plugin and properties.
</para> </para>
</sect2> </sect2>
@ -83,44 +82,43 @@
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
Using glib g_mem_chunk where possible to minimize dynamic memory Using GLib g_mem_chunk where possible to minimize dynamic memory
allocation. allocation.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Connections between plugins are extremely light-weight. Data can travel Extremely light-weight connections between plugins. Data can travel
the pipeline with minimal overhead. the pipeline with minimal overhead.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Provide a mechanism to directly work on the target memory. A Providing a mechanism to directly work on the target memory. A plugin can for example
plugin can for example directly write to the X servers shared mem. directly write to the X server's shared memory space. Buffers can also point to
Buffers can also point to arbitrary memory like kernel memory. arbitrary memory, such as a sound card's internal hardware buffer.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Refcounting and copy on write to minimize the amount of memcpy. Refcounting and copy on write minimize usage of memcpy(3).
Subbufers to efficiently split the data in a buffer. Sub-buffers efficiently split buffers into manageable pieces.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Pipelines can be constructed using cothreads to minimize the The use of cothreads to minimize the threading overhead. Cothreads are a simple and fast
threading overhead. Cothreads are a simple user-space method for user-space method for switching between subtasks.
switching between subtasks.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
HW acceleration is possible by writing a specialized plugin. Allowing HW acceleration by the use of specialized plugins.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
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 that the plugin loading can be delayed until the plugin is actually
used. used.
</para> </para>

View file

@ -61,6 +61,15 @@
</para> </para>
</authorblurb> </authorblurb>
</author> </author>
<author>
<firstname>Andy</firstname>
<surname>Wingo</surname>
<authorblurb>
<para>
<email>wingo@pobox.com</email>
</para>
</authorblurb>
</author>
</authorgroup> </authorgroup>
<legalnotice id="legalnotice"> <legalnotice id="legalnotice">
@ -82,14 +91,13 @@
<part id="overview"><title>Overview</title> <part id="overview"><title>Overview</title>
<partintro> <partintro>
<para> <para>
The first chapter of the book gives you an overview of <application>GStreamer</application> <xref linkend="overview"/> gives you an overview of <application>GStreamer</application>
design goals. Chapter 2 rapidly covers the basics of <application>GStreamer</application> design goals. <xref linkend="basic-concepts"/> rapidly covers the basics of
programming. In chapter 3 we will move on to the examples. <application>GStreamer</application> programming. In <xref linkend="build-app"/> we will move
Since <application>GStreamer</application> adheres to the GTK+/glib2 programming model, the reader is on to the examples. Since <application>GStreamer</application> uses GLib 2.0, the reader is
assumed to understand the basics of GTK+ and the glib2.0 object model. assumed to understand the basics of the GObject object model. For a gentle introduction to
For a gentle introduction to GTK+, you may wish to read the <emphasis>GTK+ this system, you may wish to read the <emphasis>GTK+ Tutorial</emphasis> or Eric Harlow's
Tutorial</emphasis> or Eric Harlow's book <emphasis>Developing Linux book <emphasis>Developing Linux Applications with GTK+ and GDK</emphasis>.
Applications with GTK+ and GDK</emphasis>.
</para> </para>
</partintro> </partintro>
@ -186,8 +194,6 @@
&HELLOWORLD2; &HELLOWORLD2;
&DPARAMS; &DPARAMS;
&UTILITY;
</part> </part>
<!-- ############ XML in GStreamer - part ############# --> <!-- ############ XML in GStreamer - part ############# -->
@ -196,9 +202,9 @@
<partintro> <partintro>
<para> <para>
<application>GStreamer</application> has the posibility to externalize the pipelines <application>GStreamer</application> has the possibility to serialize the pipelines you
you create using an XML format. You can load a previously create using an XML format. You can load a previously created pipeline by loading the XML
created pipeline by loading the XML file. file.
</para> </para>
</partintro> </partintro>

View file

@ -9,12 +9,11 @@
<sect1> <sect1>
<title>Hello world</title> <title>Hello world</title>
<para> <para>
We will create a simple first application. In fact it will be a complete We will create a simple first application, a complete MP3 player, using standard
MP3 player, using standard <application>GStreamer</application> components. The player will read from <application>GStreamer</application> components. The player will read from a file that is
a file that is given as the first argument of the program. given as the first argument of the program.
</para> </para>
<programlisting> <programlisting>
#include &lt;gst/gst.h&gt; #include &lt;gst/gst.h&gt;
@ -45,15 +44,10 @@ main (int argc, char *argv[])
audiosink = gst_elementfactory_make ("osssink", "play_audio"); audiosink = gst_elementfactory_make ("osssink", "play_audio");
/* add objects to the main pipeline */ /* add objects to the main pipeline */
gst_bin_add (GST_BIN (pipeline), filesrc); gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
gst_bin_add (GST_BIN (pipeline), decoder);
gst_bin_add (GST_BIN (pipeline), audiosink);
/* connect src to sink */ /* connect src to sink */
gst_pad_connect (gst_element_get_pad (filesrc, "src"), gst_element_connect_many (filesrc, decoder, audiosink, NULL);
gst_element_get_pad (decoder, "sink"));
gst_pad_connect (gst_element_get_pad (decoder, "src"),
gst_element_get_pad (audiosink, "sink"));
/* start playing */ /* start playing */
gst_element_set_state (pipeline, GST_STATE_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); gst_element_set_state (pipeline, GST_STATE_NULL);
/* we don't need a reference to these objects anymore */ /* 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)); gst_object_unref (GST_OBJECT (pipeline));
/* unreffing the pipeline unrefs the contained elements as well */
exit (0); exit (0);
} }
@ -98,8 +90,8 @@ main (int argc, char *argv[])
</programlisting> </programlisting>
<para> <para>
We are going to create 3 elements and one pipeline. Since all objects are We are going to create 3 elements and one pipeline. Since all elements share the same base
in fact elements, we can define them as: type, <classname>GstElement</classname>, we can define them as:
</para> </para>
<programlisting> <programlisting>
... ...
@ -142,7 +134,7 @@ main (int argc, char *argv[])
is installed on the system where this application is executed. is installed on the system where this application is executed.
</para> </para>
<programlisting> <programlisting>
/* now it's time to get the parser */ /* now it's time to get the decoder */
decoder = gst_elementfactory_make ("mad", "decoder"); decoder = gst_elementfactory_make ("mad", "decoder");
</programlisting> </programlisting>
<para> <para>
@ -167,9 +159,7 @@ main (int argc, char *argv[])
</para> </para>
<programlisting> <programlisting>
/* add objects to the main pipeline */ /* add objects to the main pipeline */
gst_bin_add (GST_BIN (pipeline), filesrc); gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
gst_bin_add (GST_BIN (pipeline), decoder);
gst_bin_add (GST_BIN (pipeline), audiosink);
</programlisting> </programlisting>
<para> <para>
@ -177,10 +167,7 @@ main (int argc, char *argv[])
</para> </para>
<programlisting> <programlisting>
/* connect src to sink */ /* connect src to sink */
gst_pad_connect (gst_element_get_pad (filesrc, "src"), gst_element_connect_many (filesrc, decoder, audiosink, NULL);
gst_element_get_pad (decoder, "sink"));
gst_pad_connect (gst_element_get_pad (decoder, "src"),
gst_element_get_pad (audiosink, "sink"));
</programlisting> </programlisting>
<para> <para>
@ -229,16 +216,13 @@ main (int argc, char *argv[])
/* stop the pipeline */ /* stop the pipeline */
gst_element_set_state (pipeline, GST_STATE_NULL); 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)); gst_object_unref (GST_OBJECT (pipeline));
exit (0); exit (0);
</programlisting> </programlisting>
<note> <note>
<para> <para>
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. all of the resources held by the elements.
</para> </para>
</note> </note>
@ -246,7 +230,7 @@ main (int argc, char *argv[])
</sect1> </sect1>
<sect1> <sect1>
<title>compiling helloworld.c</title> <title>Compiling helloworld.c</title>
<para> <para>
To compile the helloworld example, use: To compile the helloworld example, use:
</para> </para>
@ -268,10 +252,10 @@ main (int argc, char *argv[])
</sect1> </sect1>
<sect1> <sect1>
<title>conclusion</title> <title>Conclusion</title>
<para> <para>
This concludes our first example. As you see, setting up a pipeline 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. you can create a custom MP3 element with a more high level API.
</para> </para>
<para> <para>
@ -284,7 +268,7 @@ main (int argc, char *argv[])
We could use a disksink to write the raw samples to a file, for example. 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, 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 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.
</para> </para>
</sect1> </sect1>
</chapter> </chapter>

View file

@ -1,8 +1,8 @@
<chapter id="cha-hello2"> <chapter id="cha-hello2">
<title>Your second application</title> <title>Your second application</title>
<para> <para>
In a previous chapter we created a first version of the helloworld FIXME: delete this section, talk more about the spider. In a previous chapter we created a first
application. We then explained a better way of creating the elements version of the helloworld application. We then explained a better way of creating the elements
using factories identified by MIME types and the autoplugger. using factories identified by MIME types and the autoplugger.
</para> </para>
@ -35,7 +35,7 @@ main (int argc, char *argv[])
gst_init (&amp;argc, &amp;argv); gst_init (&amp;argc, &amp;argv);
if (argc != 2) { if (argc != 2) {
g_print ("usage: %s &lt;filename&gt;\n", argv[0]); g_print ("usage: &percnt;s &lt;filename&gt;\n", argv[0]);
exit (-1); exit (-1);
} }

View file

@ -1,5 +1,10 @@
<chapter id="cha-components"> <chapter id="cha-components">
<title>Components</title> <title>Components</title>
<para>
FIXME: This chapter is way out of date.
</para>
<para> <para>
<application>GStreamer</application> includes components that people can include <application>GStreamer</application> includes components that people can include
in their programs. in their programs.

View file

@ -34,5 +34,29 @@ main (int argc, char *argv[])
Use the GST_VERSION_MAJOR, GST_VERSION_MINOR and GST_VERSION_MICRO macros to Use the GST_VERSION_MAJOR, GST_VERSION_MINOR and GST_VERSION_MICRO macros to
get the <application>GStreamer</application> version you are building against. get the <application>GStreamer</application> version you are building against.
</para> </para>
<sect1>
<title>The popt interface</title>
<para>
more info here
</para>
<programlisting>
int
main(int argc, char *argv[])
{
gboolean silent = FALSE;
gchar *savefile = NULL;
struct poptOption options[] = {
{"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &amp;silent, 0,
"do not output status information", NULL},
{"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &amp;savefile, 0,
"save xml representation of pipeline to FILE and exit", "FILE"},
POPT_TABLEEND
};
gst_init_with_popt_table (&amp;argc, &amp;argv, options);
...
</programlisting>
</sect1>
</chapter> </chapter>

View file

@ -80,7 +80,7 @@
</para> </para>
<para> <para>
No provisions have been made for emerging technologies such as No provisions have been made for emerging technologies such as
the GNOME object embedding using BONOBO. the GNOME object embedding using Bonobo.
</para> </para>
<para> <para>
While the GStreamer core does not use network transparent technologies While the GStreamer core does not use network transparent technologies

View file

@ -23,11 +23,11 @@
<para> <para>
GStreamer, however, is much more than just another media player. Its GStreamer, however, is much more than just another media player. Its
main advantages are that the pluggable components also make it possible 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.
</para> </para>
<para> <para>
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 and other functionality. The plugins can be connected and arranged in
a pipeline. This pipeline defines the flow of the data. Pipelines can 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 also be edited with a GUI editor and saved as XML so that pipeline

View file

@ -23,11 +23,11 @@
<para> <para>
GStreamer, however, is much more than just another media player. Its GStreamer, however, is much more than just another media player. Its
main advantages are that the pluggable components also make it possible 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.
</para> </para>
<para> <para>
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 and other functionality. The plugins can be connected and arranged in
a pipeline. This pipeline defines the flow of the data. Pipelines can 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 also be edited with a GUI editor and saved as XML so that pipeline

View file

@ -80,7 +80,7 @@
</para> </para>
<para> <para>
No provisions have been made for emerging technologies such as No provisions have been made for emerging technologies such as
the GNOME object embedding using BONOBO. the GNOME object embedding using Bonobo.
</para> </para>
<para> <para>
While the GStreamer core does not use network transparent technologies While the GStreamer core does not use network transparent technologies

View file

@ -1,7 +1,7 @@
<chapter id="cha-pads"> <chapter id="cha-pads">
<title>GstPad</title> <title>GstPad</title>
<para> <para>
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. connections with the outside world.
</para> </para>
<para> <para>
@ -44,7 +44,7 @@
<title>Useful pad functions</title> <title>Useful pad functions</title>
<para> <para>
You can get the name of a pad with gst_pad_get_name () and set its name with 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().
</para> </para>
<para> <para>
gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink
@ -53,8 +53,8 @@
</para> </para>
<para> <para>
You can get the parent of the pad, this is the element that this pad belongs to, 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 with get_pad_get_parent(GstPad *pad). This function will return a pointer to a
GstObject. GstElement.
</para> </para>
</sect2> </sect2>
<sect2 id="sec-pads-dynamic"> <sect2 id="sec-pads-dynamic">
@ -66,7 +66,7 @@
system stream. system stream.
</para> </para>
<para> <para>
Running <application>gstreamer-inspect mpeg2parse</application> will show that Running <application>gst-inspect mpegdemux</application> will show that
the element has only one pad: a sink pad called 'sink'. The other pads are 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' "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 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 // 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); 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"); 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)); g_print ("new pad %s\n", gst_pad_get_name (pad));
... ...
</programlisting> </programlisting>
<para> <para>
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. from the element based on the name_template of the padtemplate.
</para> </para>
<para> <para>
It is also possible to request a pad that is compatible with another 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 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 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. is shown in the next example.
</para> </para>
<programlisting> <programlisting>
@ -162,11 +162,11 @@ main(int argc, char *argv[])
GstPad *pad; GstPad *pad;
... ...
element = gst_elementfactory_make ("tee", "element"); 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)); g_print ("new pad %s\n", gst_pad_get_name (pad));
... ...
</programlisting> </programlisting>
@ -181,7 +181,7 @@ main(int argc, char *argv[])
<para> <para>
We will briefly describe what capabilities are, enough for you to get a basic understanding 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 of the concepts. You will find more information on how to create capabilities in the
filter-writer-guide. Plugin Writer's Guide.
</para> </para>
<sect2 id="sec-pads-caps"> <sect2 id="sec-pads-caps">
@ -207,8 +207,8 @@ struct _GstCaps {
}; };
</programlisting> </programlisting>
<para> <para>
Below is a dump of the capabilities of the element mpg123, as shown by Below is a dump of the capabilities of the element mad, as shown by
<command>gstreamer-inspect</command>. <command>gst-inspect</command>.
You can see two pads: sink and src. Both pads have capability information attached to them. You can see two pads: sink and src. Both pads have capability information attached to them.
</para> </para>
<para> <para>
@ -221,26 +221,25 @@ struct _GstCaps {
</para> </para>
<programlisting> <programlisting>
Pads: Pads:
SINK: 'sink' SINK template: 'sink'
.... Availability: Always
Capabilities:
'mpg123_sink':
MIME type: 'audio/mp3':
layer: Integer range: 1 - 3
bitrate: Integer range: 8 - 320
framed: Boolean: TRUE
SRC: 'src'
....
Capabilities: Capabilities:
'mpg123_src': 'mad_sink':
MIME type: 'audio/raw': MIME type: 'audio/mp3':
format: Integer: 16
depth: Integer: 16 SRC template: 'src'
rate: Integer range: 11025 - 48000 Availability: Always
channels: List: Capabilities:
Integer: 1 'mad_src':
Integer: 2 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
</programlisting> </programlisting>
</sect2> </sect2>
<sect2 id="sec-pads-props"> <sect2 id="sec-pads-props">
@ -260,7 +259,7 @@ Pads:
<listitem> <listitem>
<para> <para>
An integer range value. The property denotes a range of possible values. In the case 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.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -349,7 +348,7 @@ Pads:
</para> </para>
<para> <para>
As we said, a capability has a name, a mime-type and some properties. The signature of the As we said, a capability has a name, a mime-type and some properties. The signature of the
function to create a new <classname>GstCaps *</classname> structure is like: function to create a new <classname>GstCaps</classname> structure is like:
<programlisting> <programlisting>
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props); GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
</programlisting> </programlisting>

View file

@ -20,6 +20,11 @@
one or more autopluggers one or more autopluggers
</para> </para>
</listitem> </listitem>
<listitem>
<para>
exported symbols for use in other plugins
</para>
</listitem>
</itemizedlist> </itemizedlist>
<para> <para>
The plugins have one simple method: plugin_init () where all the elementfactories are The plugins have one simple method: plugin_init () where all the elementfactories are

View file

@ -4,38 +4,35 @@
</para> </para>
<sect1> <sect1>
<title><command>gstreamer-register</command></title> <title><command>gst-register</command></title>
<para> <para>
<command>gstreamer-register</command> is used to rebuild the database of plugins. <command>gst-register</command> is used to rebuild the database of plugins.
It is used after a new plugin has been added to the system. The plugin database It is used after a new plugin has been added to the system. The plugin database
can be found in <filename>/etc/gstreamer/reg.xml</filename>. can be found, by default, in <filename>/etc/gstreamer/reg.xml</filename>.
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title><command>gstreamer-launch</command></title> <title><command>gst-launch</command></title>
<para> <para>
This is a tool that will construct pipelines based on a command-line This is a tool that will construct pipelines based on a command-line
syntax. syntax. FIXME: need a more extensive grammar reference
</para> </para>
<para> <para>
A simple commandline looks like: A simple commandline looks like:
<screen> <screen>
gstreamer-launch filesrc location=hello.mp3 ! mp3parse ! mpg123 ! audiosink gst-launch filesrc location=hello.mp3 ! mad ! osssink
</screen> </screen>
A more complex pipeline looks like: A more complex pipeline looks like:
<screen> <screen>
gstreamer-launch filesrc redpill.vob audio_00! (ac3parse ! ac3dec ! audiosink) \ gst-launch filesrc location=redpill.vob ! mpegdemux name=demux \
video_00! (mpeg2dec ! videosink) demux.audio_00! { ac3parse ! a52dec ! osssink } \
demux.video_00! { mpeg2dec ! xvideosink }
</screen> </screen>
</para>
<para>
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.
</para> </para>
<para> <para>
You can also use the the parser in you own code. <application>GStreamer</application> You can also use the the parser in you own code. <application>GStreamer</application>
@ -51,16 +48,20 @@ main (int argc, char *argv[])
{ {
GstElement *pipeline; GstElement *pipeline;
GstElement *filesrc; GstElement *filesrc;
GError *error = NULL;
gst_init (&amp;argc, &amp;argv); gst_init (&amp;argc, &amp;argv);
if (argc != 2) { if (argc != 2) {
g_print ("usage: %s &lt;filename&gt;\n", argv[0]); g_print ("usage: &percnt;s &lt;filename&gt;\n", argv[0]);
return -1; 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", &amp;error);
if (!pipeline) {
g_print ("Parse error: &percnt;s\n", error->message);
exit (1);
}
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc"); filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
@ -81,20 +82,20 @@ main (int argc, char *argv[])
</sect1> </sect1>
<sect1> <sect1>
<title><command>gstreamer-inspect</command></title> <title><command>gst-inspect</command></title>
<para> <para>
This is a tool to query a plugin or an element about its properties. This is a tool to query a plugin or an element about its properties.
</para> </para>
<para> <para>
To query the information about the element mpg123, you would specify: To query the information about the element mad, you would specify:
</para> </para>
<screen> <screen>
gstreamer-inspect mpg123 gst-inspect mad
</screen> </screen>
<para> <para>
Below is the output of a query for the audiosink element: Below is the output of a query for the osssink element:
</para> </para>
<screen> <screen>
@ -102,56 +103,72 @@ Factory Details:
Long name: Audio Sink (OSS) Long name: Audio Sink (OSS)
Class: Sink/Audio Class: Sink/Audio
Description: Output to a sound card via OSS Description: Output to a sound card via OSS
Version: 0.1.0 Version: 0.3.3.1
Author(s): Erik Walthinsen &lt;omega@cse.ogi.edu&gt; Author(s): Erik Walthinsen &lt;omega@cse.ogi.edu&gt;, Wim Taymans &lt;wim.taymans@chello.be&gt;
Copyright: (C) 1999 Copyright: (C) 1999
GObject
+----GstObject
+----GstElement
+----GstOssSink
Pad Templates: Pad Templates:
SINK template: 'sink' SINK template: 'sink'
Exists: Always Availability: Always
Capabilities: Capabilities:
'audiosink_sink': 'osssink_sink':
MIME type: 'audio/raw': MIME type: 'audio/raw':
format: Integer: 16 format: String: int
endianness: Integer: 1234
width: List:
Integer: 8
Integer: 16
depth: List: depth: List:
Integer: 8 Integer: 8
Integer: 16 Integer: 16
rate: Integer range: 8000 - 48000
channels: Integer range: 1 - 2 channels: Integer range: 1 - 2
law: Integer: 0
signed: List:
Boolean: FALSE
Boolean: TRUE
rate: Integer range: 1000 - 48000
Element Flags: Element Flags:
GST_ELEMENT_THREADSUGGESTED GST_ELEMENT_THREADSUGGESTED
no flags set
Element Implementation: Element Implementation:
No loopfunc(), must be chain-based or not configured yet 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: Pads:
SINK: 'sink' SINK: 'sink'
Implementation: Implementation:
Has chainfunc(): 0x4001cde8 Has chainfunc(): 0x40056fc0
Has default eosfunc() gst_pad_eos_func()
Pad Template: 'sink' 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: Element Arguments:
GstAudioSink::mute: Boolean name : String (Default "element")
GstAudioSink::format: Enum (default 16) device : String (Default "/dev/dsp")
(8): 8 Bits mute : Boolean (Default false)
(16): 16 Bits format : Integer (Default 16)
GstAudioSink::channels: Enum (default 2) channels : Enum "GstAudiosinkChannels" (default 1)
(0): Silence
(1): Mono (1): Mono
(2): Stereo (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);
</screen> </screen>
<para> <para>
@ -159,11 +176,11 @@ Element Arguments:
</para> </para>
<screen> <screen>
gstreamer-inspect gstelements gst-inspect gstelements
</screen> </screen>
</sect1> </sect1>
<sect1> <sect1>
<title><command>gstmediaplay</command></title> <title><command>gst-play</command></title>
<para> <para>
A sample media player. A sample media player.
</para> </para>

View file

@ -146,7 +146,7 @@
</note> </note>
<para> <para>
The pipeline has to be in the PAUSED or NULL state if you want to insert or modify an element 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 ... <!-- fixme --> in the pipeline. We will cover dynamic pipeline behaviour in <xref linkend="cha-dynamic"/>.
</para> </para>
</sect1> </sect1>

View file

@ -1,7 +1,7 @@
<chapter id="cha-threads"> <chapter id="cha-threads">
<title>Threads</title> <title>Threads</title>
<para> <para>
GStreamer has support for multithreading throught the use of GStreamer has support for multithreading through the use of
the <classname>GstThread</classname> object. This object is in fact the <classname>GstThread</classname> object. This object is in fact
a special <classname>GstBin</classname> that will become a thread when started. a special <classname>GstBin</classname> that will become a thread when started.
</para> </para>
@ -13,39 +13,58 @@
<programlisting> <programlisting>
GstElement *my_thread; GstElement *my_thread;
// create the thread object /* create the thread object */
my_thread = gst_thread_new ("my_thread"); 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 (funky_src));
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect)); 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); gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING);
</programlisting> </programlisting>
<para> <para>
The above program will create a thread with two elements in it. As soon The above program will create a thread with two elements in it. As soon as it is set to the
as it is set to the PLAYING state, the thread will start to iterate. PLAYING state, the thread will start to iterate itself. You never need to manually iterate a
thread.
</para> </para>
<note> <sect2>
<title>Constraints placed on the pipeline by the GstThread</title>
<para> <para>
A thread should normally contain a source element. Most often, the thread Within the pipeline, everything is the same as in any other bin. The difference lies at the
is fed with data from a queue. 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 <xref
linkend="cha-queues"/>. 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.
</para> </para>
</note> </sect2>
<sect2>
<title>When would you want to use a thread?</title>
<para>
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.
</para>
</sect2>
<para> <para>
A thread will be visualised as below A thread can be visualised as below
</para> </para>
<figure float="1" id="sec-threads-img"> <figure float="1" id="sec-threads-img">
<title>a thread</title> <title>A thread</title>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/thread.&magic;" format="&magic;" /> <imagedata fileref="images/thread.&magic;" format="&magic;" />

View file

@ -1,90 +0,0 @@
<chapter id="cha-utility">
<title>Utility functions</title>
<para>
while you can use the regular g_object_getv () function to
query the value of an object property, <application>GStreamer</application>
provides some easy wrappers for this common operation.
</para>
<para>
Instead of writing the following glib code to query the GTK_STRING value
of an object:
</para>
<programlisting>
GtkArg arg;
guchar *value;
arg.name = argname;
g_object_getv (G_OBJECT (object), 1, &amp;arg);
value = GTK_VALUE_STRING (arg);
</programlisting>
<para>
You can also use:
</para>
<programlisting>
value = gst_util_get_string_arg (object, argname);
</programlisting>
<para>
These convenience functions exist for the following types:
<itemizedlist>
<listitem>
<para>
gint: with gst_util_get_int_arg ();
</para>
</listitem>
<listitem>
<para>
gboolean: with gst_util_get_bool_arg ();
</para>
</listitem>
<listitem>
<para>
glong: with gst_util_get_long_arg ();
</para>
</listitem>
<listitem>
<para>
gfloat: with gst_util_get_float_arg ();
</para>
</listitem>
<listitem>
<para>
gdouble: with gst_util_get_double_arg ();
</para>
</listitem>
<listitem>
<para>
guchar*: with gst_util_get_string_arg ();
</para>
</listitem>
<listitem>
<para>
gpointer: with gst_util_get_pointer_arg ();
</para>
</listitem>
</itemizedlist>
</para>
<para>
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:
</para>
<programlisting>
gst_util_set_object_arg (someobject, "int_property", "1000");
</programlisting>
<para>
Will do The Right Thing(tm), converting the string to the type of the property when
needed.
</para>
<para>
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.
</para>
<programlisting>
void gst_util_dump_mem (guchar *mem, guint size);
</programlisting>
</chapter>

View file

@ -19,22 +19,22 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
/* disconnect the typefind from the pipeline and remove it */ /* 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); gst_bin_remove (GST_BIN (autobin), typefind);
/* and an audio sink */ /* and an audio sink */
osssink = gst_elementfactory_make("osssink", "play_audio"); osssink = gst_elementfactory_make ("osssink", "play_audio");
g_assert(osssink != NULL); g_assert (osssink != NULL);
videosink = gst_bin_new ("videosink"); videosink = gst_bin_new ("videosink");
/* and an video sink */ /* and an video sink */
videoelement = gst_elementfactory_make("xvideosink", "play_video"); videoelement = gst_elementfactory_make ("xvideosink", "play_video");
g_assert(videosink != NULL); g_assert (videosink != NULL);
colorspace = gst_elementfactory_make("colorspace", "colorspace"); colorspace = gst_elementfactory_make ("colorspace", "colorspace");
g_assert(colorspace != NULL); 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), colorspace);
gst_bin_add (GST_BIN (videosink), videoelement); 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); 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); 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"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_disconnect (filesrc, "src", cache, "sink"); gst_element_disconnect_many (filesrc, cache, new_element, NULL);
gst_element_disconnect (cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (autobin), cache); 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); 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), cache);
gst_bin_add (GST_BIN (autobin), typefind); 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_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin); gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_connect (filesrc, "src", autobin, "sink"); gst_element_connect_pads (filesrc, "src", autobin, "sink");
/* start playing */ /* 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))); while (gst_bin_iterate (GST_BIN (pipeline)));

View file

@ -22,7 +22,7 @@ int main (int argc, char *argv[])
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
/* now it's time to get the decoder */ /* now it's time to get the decoder */
decoder = gst_elementfactory_make ("mad", "parse"); decoder = gst_elementfactory_make ("mad", "decode");
if (!decoder) { if (!decoder) {
g_print ("could not find plugin \"mad\""); g_print ("could not find plugin \"mad\"");
return -1; return -1;
@ -35,7 +35,7 @@ int main (int argc, char *argv[])
gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL); gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL);
/* connect the elements */ /* connect the elements */
gst_element_connect_elements_many (filesrc, decoder, osssink, NULL); gst_element_connect_many (filesrc, decoder, osssink, NULL);
/* start playing */ /* start playing */
gst_element_set_state (bin, GST_STATE_PLAYING); gst_element_set_state (bin, GST_STATE_PLAYING);

View file

@ -18,8 +18,8 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin"); autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
/* disconnect the typefind from the pipeline and remove it */ /* disconnect_pads 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); gst_bin_remove (GST_BIN (autobin), typefind);
/* and an audio sink */ /* 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); 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); 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"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_disconnect (filesrc, "src", cache, "sink"); gst_element_disconnect_pads (filesrc, "src", cache, "sink");
gst_element_disconnect (cache, "src", new_element, "sink"); gst_element_disconnect_pads (cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (autobin), cache); 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); 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), cache);
gst_bin_add (GST_BIN (autobin), typefind); 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_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin); gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_connect (filesrc, "src", autobin, "sink"); gst_element_connect_pads (filesrc, "src", autobin, "sink");
/* start playing */ /* start playing */
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING); gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);

View file

@ -5,6 +5,7 @@ main (int argc, char *argv[])
{ {
GstElement *pipeline; GstElement *pipeline;
GstElement *filesrc; GstElement *filesrc;
GError *error = NULL;
gst_init (&argc, &argv); gst_init (&argc, &argv);
@ -13,7 +14,11 @@ main (int argc, char *argv[])
return -1; 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"); filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);

View file

@ -40,7 +40,7 @@ void eos(GstElement *element)
/* playing = FALSE; */ /* playing = FALSE; */
} }
static GstCaps* G_GNUC_UNUSED static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element) gst_play_typefind (GstBin *bin, GstElement *element)
{ {
GstElement *typefind; GstElement *typefind;
@ -140,7 +140,7 @@ int main(int argc,char *argv[])
/* request pads and connect to adder */ /* request pads and connect to adder */
GST_INFO (0, "requesting pad\n"); 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)); printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
sprintf (buffer, "channel%d", i); sprintf (buffer, "channel%d", i);
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad); 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 */ char buffer[20]; /* hold the names */
GstAutoplug *autoplug; /* GstAutoplug *autoplug;
GstCaps *srccaps; GstCaps *srccaps; */
GstElement *new_element; GstElement *new_element;
GstElement *decoder; 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), channel->volenv);
gst_bin_add (GST_BIN (channel->pipe), new_element); gst_bin_add (GST_BIN (channel->pipe), new_element);
gst_element_connect (channel->filesrc, "src", new_element, "sink"); gst_element_connect_pads (channel->filesrc, "src", new_element, "sink");
gst_element_connect (new_element, "src_00", channel->volenv, "sink"); gst_element_connect_pads (new_element, "src_00", channel->volenv, "sink");
/* add a ghost pad */ /* add a ghost pad */
sprintf (buffer, "channel%d", id); sprintf (buffer, "channel%d", id);

View file

@ -19,7 +19,7 @@ object_saved (GstObject *object, xmlNodePtr parent, gpointer data)
int main(int argc,char *argv[]) int main(int argc,char *argv[])
{ {
GstElement *filesrc, *osssink, *queue, *queue2, *parse, *decode; GstElement *filesrc, *osssink, *queue, *queue2, *decode;
GstElement *pipeline; GstElement *pipeline;
GstElement *thread, *thread2; GstElement *thread, *thread2;

View file

@ -4,7 +4,7 @@
gboolean playing; gboolean playing;
static void G_GNUC_UNUSED static void
xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data) xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data)
{ {
xmlNodePtr children = self->xmlChildrenNode; xmlNodePtr children = self->xmlChildrenNode;

View file

@ -44,8 +44,7 @@ endif
EXTRA_libgstreamer_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gsttypefind.c gstparse.c gstautoplug.c gsttrace.c 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 = parse . $(GST_AUTOPLUG_DIRS) elements schedulers types
SUBDIRS = . $(GST_AUTOPLUG_DIRS) elements schedulers types
DIST_SUBDIRS = autoplug elements parse types schedulers DIST_SUBDIRS = autoplug elements parse types schedulers
libcothreads_la_SOURCES = cothreads.c 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 # the compiler shoots cothreads.c in the head at -O6
libcothreads_la_CFLAGS = $(libgstreamer_la_CFLAGS) -O2 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@ libgstreamer_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@
EXTRA_DIST = ROADMAP EXTRA_DIST = ROADMAP

View file

@ -8,13 +8,13 @@ void cache_empty(GstElement *element, gpointer private) {
gst_element_set_state (pipeline, GST_STATE_PAUSED); 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_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_scheduler_show (GST_ELEMENT_SCHED(pipeline));
gst_bin_remove (GST_BIN(autobin), cache); gst_bin_remove (GST_BIN(autobin), cache);
gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); 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_scheduler_show (GST_ELEMENT_SCHED(pipeline));
gst_element_set_state (pipeline, GST_STATE_PLAYING); 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); gst_element_set_state (pipeline, GST_STATE_PAUSED);
/* disconnect the typefind from the pipeline and remove it */ /* 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_bin_remove(GST_BIN(autobin),typefind);
gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); 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"); sink = gst_elementfactory_make ("osssink","sink");
gst_bin_add(GST_BIN(autobin),decoder); gst_bin_add(GST_BIN(autobin),decoder);
gst_bin_add(GST_BIN(autobin),sink); 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); 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")) { else if (strstr(gst_caps_get_mime(caps),"x-ogg")) {
decoder = gst_elementfactory_make ("vorbisdec","decoder"); decoder = gst_elementfactory_make ("vorbisdec","decoder");
sink = gst_elementfactory_make ("osssink","sink"); sink = gst_elementfactory_make ("osssink","sink");
gst_bin_add(GST_BIN(autobin),decoder); gst_bin_add(GST_BIN(autobin),decoder);
gst_bin_add(GST_BIN(autobin),sink); 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); 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); 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); 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),cache);
gst_bin_add (GST_BIN(autobin),typefind); 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_element_add_ghost_pad(autobin,gst_element_get_pad(cache,"sink"),"sink");
gst_bin_add (GST_BIN(pipeline), autobin); 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); gst_element_set_state(pipeline,GST_STATE_PLAYING);
while (1) while (gst_bin_iterate(GST_BIN(pipeline)));
gst_bin_iterate(GST_BIN(pipeline));
return 0;
} }

View file

@ -533,7 +533,7 @@ gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath)
gst_bin_add (GST_BIN (spider), element); gst_bin_add (GST_BIN (spider), element);
} }
/* insert and connect new 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 */ /* check if the src has SOMETIMES templates. If so, connect a callback */
GList *templs = gst_element_get_padtemplate_list (conn->current); GList *templs = gst_element_get_padtemplate_list (conn->current);

View file

@ -119,9 +119,9 @@ int main(int argc,char *argv[])
gst_bin_add(GST_BIN(bin), videosink); gst_bin_add(GST_BIN(bin), videosink);
/* connect objects */ /* connect objects */
if (!(gst_element_connect_elements(filesrc, decoder) && if (!(gst_element_connect(filesrc, decoder) &&
gst_element_connect_elements(decoder, osssink) && gst_element_connect(decoder, osssink) &&
gst_element_connect_elements(decoder, videosink))) gst_element_connect(decoder, videosink)))
{ {
g_print ("the pipeline could not be connected\n"); g_print ("the pipeline could not be connected\n");
exit (-4); exit (-4);

View file

@ -66,6 +66,7 @@ enum {
ARG_INFO_MASK=1, ARG_INFO_MASK=1,
ARG_DEBUG_MASK, ARG_DEBUG_MASK,
ARG_MASK, ARG_MASK,
ARG_MASK_HELP,
ARG_PLUGIN_SPEW, ARG_PLUGIN_SPEW,
ARG_PLUGIN_PATH, ARG_PLUGIN_PATH,
ARG_PLUGIN_LOAD, 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-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-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", 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-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-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"}, {"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) init_post (void)
{ {
GLogLevelFlags llf; GLogLevelFlags llf;
gboolean showhelp = FALSE;
const gchar *plugin_path; const gchar *plugin_path;
#ifndef GST_DISABLE_TRACE #ifndef GST_DISABLE_TRACE
GstTrace *gst_trace; GstTrace *gst_trace;
@ -326,45 +327,34 @@ init_post (void)
if (_gst_progname == NULL) { if (_gst_progname == NULL) {
_gst_progname = g_strdup("gstprog"); _gst_progname = g_strdup("gstprog");
} }
}
/* FIXME: this is never true... */ static void
if (showhelp) { gst_mask_help (void)
guint i; {
guint i;
g_print ("usage %s [OPTION...]\n", _gst_progname); g_print ("\n Mask (to be OR'ed) info/debug FLAGS \n");
g_print ("--------------------------------------------------------\n");
g_print ("\nGStreamer options\n"); for (i = 0; i<GST_CAT_MAX_CATEGORY; i++) {
g_print (" --gst-info-mask=FLAGS GST info flags to set (current %08x)\n", gst_info_get_categories()); if (gst_get_category_name(i)) {
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; i<GST_CAT_MAX_CATEGORY; i++) {
if (gst_get_category_name(i)) {
#if GST_DEBUG_COLOR #if GST_DEBUG_COLOR
g_print (" 0x%08x %s%s \033[%sm%s\033[00m\n", 1<<i, g_print (" 0x%08x %s%s \033[%sm%s\033[00m\n", 1<<i,
(gst_info_get_categories() & (1<<i)?"(enabled)":" "), (gst_info_get_categories() & (1<<i)?"(enabled)":" "),
(gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "), (gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "),
_gst_category_colors[i], gst_get_category_name (i)); _gst_category_colors[i], gst_get_category_name (i));
#else #else
g_print (" 0x%08x %s%s %s\n", 1<<i, g_print (" 0x%08x %s%s %s\n", 1<<i,
(gst_info_get_categories() & (1<<i)?"(enabled)":" "), (gst_info_get_categories() & (1<<i)?"(enabled)":" "),
(gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "), (gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "),
gst_get_category_name (i)); gst_get_category_name (i));
#endif #endif
}
} }
} }
} }
static void static void
init_popt_callback (poptContext context, enum poptCallbackReason reason, init_popt_callback (poptContext context, enum poptCallbackReason reason,
const struct poptOption *option, const char *arg, void *data) const struct poptOption *option, const char *arg, void *data)
@ -390,6 +380,9 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason,
gst_debug_set_categories (val); gst_debug_set_categories (val);
gst_info_set_categories (val); gst_info_set_categories (val);
break; break;
case ARG_MASK_HELP:
gst_mask_help ();
exit (0);
case ARG_PLUGIN_SPEW: case ARG_PLUGIN_SPEW:
_gst_plugin_spew = TRUE; _gst_plugin_spew = TRUE;
break; break;

View file

@ -174,7 +174,6 @@ gst_element_init (GstElement *element)
element->state_cond = g_cond_new (); element->state_cond = g_cond_new ();
} }
static void static void
gst_element_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) 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); (oclass->set_property) (object, prop_id, value, pspec);
} }
static void static void
gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) 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); (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: * gst_element_set_name:
@ -482,6 +493,33 @@ gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
*/ */
GstPad* GstPad*
gst_element_get_pad (GstElement *element, const gchar *name) gst_element_get_pad (GstElement *element, const gchar *name)
{
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 ((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; GList *walk;
@ -489,27 +527,93 @@ gst_element_get_pad (GstElement *element, const gchar *name)
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
g_return_val_if_fail (name != NULL, 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;
/* look through the list, matching by name */
walk = element->pads; walk = element->pads;
while (walk) { while (walk) {
GstPad *pad; GstPad *pad;
pad = GST_PAD(walk->data); pad = GST_PAD(walk->data);
if (!strcmp (GST_PAD_NAME(pad), name)) { if (strcmp (GST_PAD_NAME(pad), name) == 0) {
GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad)); GST_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
return pad; return pad;
} }
walk = g_list_next (walk); 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; 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: * gst_element_get_pad_list:
* @element: element to get pads of * @element: element to get pads of
@ -658,19 +762,6 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
return newtempl; 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: * gst_element_request_compatible_pad:
* @element: element to request a new pad from * @element: element to request a new pad from
@ -700,78 +791,6 @@ gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
return pad; 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: * 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 * @src: the element containing source pad
* @dest: the element containing destination pad * @dest: the element containing destination pad
* @filtercaps: the caps to use as filter * @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. * Returns: TRUE if the elements could be connected.
*/ */
gboolean gboolean
gst_element_connect_elements_filtered (GstElement *src, GstElement *dest, gst_element_connect_filtered (GstElement *src, GstElement *dest,
GstCaps *filtercaps) GstCaps *filtercaps)
{ {
GList *srcpads, *destpads, *srctempls, *desttempls, *l; 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 (desttempl->presence == GST_PAD_REQUEST && desttempl->direction != srctempl->direction) {
if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctempl), if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctempl),
gst_padtemplate_get_caps (desttempl))) { gst_padtemplate_get_caps (desttempl))) {
srcpad = gst_element_request_pad_by_name (src, srctempl->name_template); srcpad = gst_element_get_request_pad (src, srctempl->name_template);
destpad = gst_element_request_pad_by_name (dest, desttempl->name_template); destpad = gst_element_get_request_pad (dest, desttempl->name_template);
if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) { if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad)); 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_1: the first element in the connection chain
* @element_2: the second element in the connection chain * @element_2: the second element in the connection chain
* @...: NULL-terminated list of elements to connect in order * @...: 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. * Returns: TRUE on success, FALSE otherwise.
*/ */
/* API FIXME: this should be called gst_element_connect_many, and connect_elements
* should just be connect */
gboolean 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; va_list args;
@ -979,7 +996,7 @@ gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2,
va_start (args, element_2); va_start (args, element_2);
while (element_2) { while (element_2) {
if (!gst_element_connect_elements (element_1, element_2)) if (!gst_element_connect (element_1, element_2))
return FALSE; return FALSE;
element_1 = element_2; 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 * @src: element containing source pad
* @dest: element containing destination 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. * Returns: TRUE if the elements could be connected.
*/ */
gboolean 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 * @src: element containing source pad
* @srcpadname: name of pad in source element * @srcpadname: name of pad in source element
* @dest: element containing destination pad * @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. * Returns: TRUE if the pads could be connected.
*/ */
gboolean gboolean
gst_element_connect_filtered (GstElement *src, const gchar *srcpadname, gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname,
GstElement *dest, const gchar *destpadname, GstElement *dest, const gchar *destpadname,
GstCaps *filtercaps) GstCaps *filtercaps)
{ {
GstPad *srcpad,*destpad; GstPad *srcpad,*destpad;
g_return_val_if_fail (src != NULL, FALSE); 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 (srcpadname != NULL, FALSE);
g_return_val_if_fail (dest != 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); g_return_val_if_fail (destpadname != NULL, FALSE);
/* obtain the pads requested */ /* 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 * @src: element containing source pad
* @srcpadname: name of pad in source element * @srcpadname: name of pad in source element
* @dest: element containing destination pad * @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. * Returns: TRUE if the pads could be connected.
*/ */
gboolean gboolean
gst_element_connect (GstElement *src, const gchar *srcpadname, gst_element_connect_pads (GstElement *src, const gchar *srcpadname,
GstElement *dest, const gchar *destpadname) 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 * @src: element containing source pad
* @srcpadname: name of pad in source element * @srcpadname: name of pad in source element
* @dest: element containing destination pad * @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. * Disconnect the two named pads of the source and destination elements.
*/ */
void void
gst_element_disconnect (GstElement *src, const gchar *srcpadname, gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
GstElement *dest, const gchar *destpadname) GstElement *dest, const gchar *destpadname)
{ {
GstPad *srcpad,*destpad; 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 * @src: source element
* @dest: sink element * @dest: sink element
* *
* Disconnect all pads connecting the two elements in the direction src -> dest. * Disconnect all pads connecting the two elements in the direction src -> dest.
*/ */
void void
gst_element_disconnect_elements (GstElement *src, GstElement *dest) gst_element_disconnect (GstElement *src, GstElement *dest)
{ {
GList *srcpads; GList *srcpads;
GstPad *pad; GstPad *pad;
@ -1157,6 +1202,7 @@ gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg
gst_object_unref (GST_OBJECT (element)); gst_object_unref (GST_OBJECT (element));
} }
} }
/** /**
* gst_element_error: * gst_element_error:
* @element: Element with the 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_cond_wait (element->state_cond, element->state_mutex);
g_mutex_unlock (element->state_mutex); g_mutex_unlock (element->state_mutex);
} }
/** /**
* gst_element_set_state: * gst_element_set_state:
* @element: element to change state of * @element: element to change state of

View file

@ -197,32 +197,37 @@ GstScheduler* gst_element_get_sched (GstElement *element);
void gst_element_add_pad (GstElement *element, GstPad *pad); void gst_element_add_pad (GstElement *element, GstPad *pad);
void gst_element_remove_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); GstPad * gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name);
void gst_element_remove_ghost_pad (GstElement *element, GstPad *pad); void gst_element_remove_ghost_pad (GstElement *element, GstPad *pad);
GstPad* gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ); GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
GstPad* gst_element_request_pad_by_name (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, GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
GstCaps *filtercaps); 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 (GstElement *src, GstElement *dest);
gboolean gst_element_connect_elements (GstElement *src, GstElement *dest); gboolean gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...);
gboolean gst_element_connect_elements_filtered (GstElement *src, GstElement *dest, gboolean gst_element_connect_filtered (GstElement *src, GstElement *dest,
GstCaps *filtercaps); 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); 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, GstElement *dest, const gchar *destpadname,
GstCaps *filtercaps); 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); 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); void gst_element_set_eos (GstElement *element);

View file

@ -25,25 +25,11 @@
#define DEBUG_NOPREFIX(format,args...) #define DEBUG_NOPREFIX(format,args...)
#define VERBOSE(format,args...) #define VERBOSE(format,args...)
#define GST_PARSE_LISTPAD(list) ((GstPad*)(list->data))
#include <string.h> #include <string.h>
#include "gst_private.h" #include "gst_private.h"
#include "gstparse.h" #include "gstparse.h"
#include "gstpipeline.h" #include "parse/types.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;
};
typedef struct _gst_parse_delayed_pad gst_parse_delayed_pad; typedef struct _gst_parse_delayed_pad gst_parse_delayed_pad;
struct _gst_parse_delayed_pad struct _gst_parse_delayed_pad
@ -60,7 +46,17 @@ typedef struct
} }
dyn_connect; 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) dynamic_connect (GstElement * element, GstPad * newpad, gpointer data)
{ {
dyn_connect *connect = (dyn_connect *) data; dyn_connect *connect = (dyn_connect *) data;
@ -74,411 +70,277 @@ dynamic_connect (GstElement * element, GstPad * newpad, gpointer data)
} }
} }
static gint static gboolean
gst_parse_launchv_recurse (const gchar **argv, GstBin * parent, gst_parse_priv * priv) make_elements (graph_t *g, GError **error)
{ {
gint i = -1, j = 0; GList *l = NULL;
const gchar *arg; gchar *bin_type;
GstElement *element = NULL, *previous = NULL, *prevelement = NULL; element_t *e;
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) { if (!(g->bins || g->elements)) {
priv = g_new0 (gst_parse_priv, 1); g_set_error (error,
GST_PARSE_ERROR,
GST_PARSE_ERROR_SYNTAX,
"Empty bin");
return FALSE;
} }
priv->binlevel++; if (g->current_bin_type)
bin_type = g->current_bin_type;
else
bin_type = "pipeline";
if (GST_IS_PIPELINE (parent)) { if (!(g->bin = gst_elementfactory_make (bin_type, NULL))) {
closingchar = '\0'; g_set_error (error,
DEBUG ("in pipeline "); GST_PARSE_ERROR,
} else if (GST_IS_THREAD (parent)) { GST_PARSE_ERROR_NO_SUCH_ELEMENT,
closingchar = '}'; "No such bin type %s", bin_type);
DEBUG ("in thread "); return FALSE;
} else {
closingchar = ')';
DEBUG ("in bin ");
} }
DEBUG_NOPREFIX ("%s\n", GST_ELEMENT_NAME (GST_ELEMENT (parent)));
while ((arg = argv[++i])) { l = g->elements;
len = strlen (arg); while (l) {
element = NULL; e = (element_t*)l->data;
DEBUG ("** ARGUMENT is '%s'\n", arg); if (!(e->element = gst_elementfactory_make (e->type, NULL))) {
g_set_error (error,
if (len == 0) { GST_PARSE_ERROR,
DEBUG ("random arg, FIXME\n"); GST_PARSE_ERROR_NO_SUCH_ELEMENT,
"No such element %s", e->type);
continue; return FALSE;
} 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;
} }
gst_bin_add (GST_BIN (g->bin), e->element);
l = g_list_next (l);
} }
/* ghost all the src pads of the bin */ l = g->bins;
if (prevelement != NULL) { while (l) {
DEBUG ("last element, ghosting all of %s's src pads to parent %s\n", if (!make_elements ((graph_t*)l->data, error))
GST_ELEMENT_NAME (prevelement), GST_ELEMENT_NAME (GST_ELEMENT (parent))); return FALSE;
pads = gst_element_get_pad_list (prevelement); gst_bin_add (GST_BIN (g->bin), ((graph_t*)l->data)->bin);
while (pads) { l = g_list_next (l);
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));
}
}
} }
priv->binlevel--; return TRUE;
if (retval)
return retval;
DEBUG (closingchar != '\0' ? "returning IN THE WRONG PLACE\n" : "ending pipeline\n");
return i + 1;
} }
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: * 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 * Returns: a new pipeline on success, NULL on failure
*/ */
GstPipeline * GstBin *
gst_parse_launchv (const gchar **argv) gst_parse_launchv (const gchar **argv, GError **error)
{ {
GstPipeline *pipeline; GstBin *pipeline;
gint ret; gchar *pipeline_description;
/* defer error detection to the _recurse function */ /* i think this cast works out ok... */
pipeline_description = g_strjoinv (" ", (gchar**)argv);
pipeline = (GstPipeline*) gst_pipeline_new ("launch"); pipeline = gst_parse_launch (pipeline_description, error);
ret = gst_parse_launchv_recurse (argv, GST_BIN (pipeline), NULL); return pipeline;
if (ret <= 0) {
/* print an error */
gst_object_unref (GST_OBJECT (pipeline));
return NULL;
} else {
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 * Returns: a new GstPipeline (cast to a Bin) on success, NULL on failure
*/ */
GstPipeline * GstBin *
gst_parse_launch (const gchar * pipeline_description) gst_parse_launch (const gchar * pipeline_description, GError **error)
{ {
gchar **argvn; graph_t *graph;
gint newargc; static GStaticMutex flex_lock = G_STATIC_MUTEX_INIT;
gint i;
const gchar *cp, *start, *end;
gchar *temp;
GSList *string_list = NULL, *slist;
GstPipeline *pipeline;
end = pipeline_description + strlen (pipeline_description); g_return_val_if_fail (pipeline_description != NULL, NULL);
newargc = 0;
temp = ""; GST_INFO (GST_CAT_PIPELINE, "parsing pipeline description %s",
pipeline_description);
/* Extract the arguments to a gslist in reverse order */ /* the need for the mutex will go away with flex 2.5.6 */
for (cp = pipeline_description; cp < end;) { g_static_mutex_lock (&flex_lock);
i = strcspn (cp, "([{}]) \"\\"); graph = _gst_parse_launch (pipeline_description, error);
g_static_mutex_unlock (&flex_lock);
if (i > 0) { if (!graph)
temp = g_strconcat (temp, g_strndup (cp, i), NULL); return NULL;
/* see if we have an escape char */ return pipeline_from_graph (graph, error);
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;
} }

View file

@ -25,22 +25,24 @@
#include <gst/gstpipeline.h> #include <gst/gstpipeline.h>
#ifdef __cplusplus G_BEGIN_DECLS
extern "C" {
#endif /* __cplusplus */
#ifndef GST_DISABLE_PARSE #ifndef GST_DISABLE_PARSE
typedef enum { GQuark gst_parse_error_quark (void);
GST_PARSE_ERROR_SYNTAX = -1, #define GST_PARSE_ERROR gst_parse_error_quark ()
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); typedef enum
GstPipeline* gst_parse_launchv (const gchar **argv); {
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 */ #else /* GST_DISABLE_PARSE */
@ -48,8 +50,6 @@ GstPipeline* gst_parse_launchv (const gchar **argv);
#endif /* GST_DISABLE_PARSE */ #endif /* GST_DISABLE_PARSE */
#ifdef __cplusplus G_END_DECLS
}
#endif /* __cplusplus */
#endif /* __GST_PARSE_H__ */ #endif /* __GST_PARSE_H__ */

View file

@ -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 BISON = bison -d -v
noinst_PROGRAMS = grammar libgstparse_la_CFLAGS = $(LIBGST_CFLAGS)
libgstparse_la_LIBADD = $(LIBGST_LIBS)
grammar_SOURCES = lex.yy.c grammar.tab.c
grammar_CFLAGS = $(GLIB_CFLAGS)
grammar_LDADD = $(GLIB_LIBS)
noinst_HEADERS = grammar.tab.h noinst_HEADERS = grammar.tab.h

View file

@ -1,73 +1,68 @@
%{ %{
#include <glib.h> #include <glib.h>
#include <stdio.h> #include <stdio.h>
#include "../gstparse.h"
#include "types.h" #include "types.h"
#define YYDEBUG 1 #define YYDEBUG 1
#define YYERROR_VERBOSE 1 #define YYERROR_VERBOSE 1
#define YYPARSE_PARAM pgraph
static int yylex (void *lvalp);
static int yyerror (const char *s);
%} %}
%union { %union {
double d;
gboolean b;
gint i;
gchar *s; gchar *s;
GValue *v;
graph_t *g; graph_t *g;
connection_t *c; connection_t *c;
property_t *p; property_t *p;
element_t *e; element_t *e;
hash_t *h;
} }
%token <s> IDENTIFIER STRING %token <s> IDENTIFIER
%token <d> FLOAT %token <c> CONNECTION BCONNECTION
%token <i> INTEGER %token <v> VALUE
%token <b> BOOLEAN
%type <s> id %type <s> id
%type <h> qid
%type <g> graph bin %type <g> graph bin
%type <e> element %type <e> element
%type <p> property_value value %type <p> property_value value
%type <c> connection lconnection rconnection qconnection iconnection %type <c> connection rconnection
%left '{' '}' '(' ')' %left '{' '}' '(' ')'
%left '!' '=' %left '!' '='
%left '+' %left ','
%left '.' %left '.'
%pure_parser
%start graph %start graph
%% %%
id: IDENTIFIER id: IDENTIFIER
; ;
qid: id { $$ = g_new0 (hash_t, 1); $$->id2 = $1 } value: VALUE { $$ = g_new0 (property_t, 1); $$->value = $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; }
; ;
property_value: id '=' value { $$ = $3; $$->name = $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: /* empty */ { $$ = g_new0 (graph_t, 1); *((graph_t**) pgraph) = $$; }
| graph element { GList *l = $$->connections_pending; | graph element { GList *l;
$$ = $1; $$ = $1; l = $$->connections_pending;
$$->elements = g_list_append ($$->elements, $2); $$->elements = g_list_append ($$->elements, $2);
$$->current = $2; $$->current = $2;
if (!$$->first)
$$->first = $$->current;
while (l) { while (l) {
((connection_t*) l->data)->sink = $$->current->name; ((connection_t*) l->data)->sink_index = $$->current->index;
l = g_list_next (l); l = g_list_next (l);
} }
if ($$->connections_pending) { if ($$->connections_pending) {
@ -75,11 +70,27 @@ graph: /* empty */ { $$ = g_new0 (graph_t, 1); }
$$->connections_pending = NULL; $$->connections_pending = NULL;
} }
} }
| graph bin { $$ = $1; $$->bins = g_list_append ($$->bins, $2); } | graph bin { GList *l; $$ = $1; l = $$->connections_pending;
| graph connection { $$ = $1; $$->connections = g_list_append ($$->connections, $2); *((graph_t**) pgraph) = $$;
if (!$2->src) $$->bins = g_list_append ($$->bins, $2);
$2->src = $$->current->name; $2->parent = $$;
if (!$2->sink) $$->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); $$->connections_pending = g_list_append ($$->connections_pending, $2);
} }
| graph property_value { $$ = $1; | 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; } | id '.' '(' graph ')' { $$ = $4; $$->current_bin_type = $1; }
; ;
connection: lconnection connection: CONNECTION
| rconnection | rconnection
| qconnection
| iconnection
; ;
lconnection: qid '+' '!' { $$ = g_new0 (connection_t, 1); rconnection: '!' { $$ = g_new0 (connection_t, 1); }
$$->src = $1->id1; | BCONNECTION { $$ = $1; }
$$->src_pads = g_list_append ($$->src_pads, $1->id2); | id ',' rconnection ',' id
}
;
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
{ $$ = $3; { $$ = $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); $$->sink_pads = g_list_append ($$->sink_pads, $5);
} }
; ;
@ -129,25 +119,47 @@ iconnection: '!' { $$ = g_new0 (connection_t, 1); }
%% %%
extern FILE *yyin; 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) yyerror (const char *s)
{ {
printf ("error: %s\n", s); printf ("error: %s\n", s);
return -1; 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 */ graph_t *g = NULL;
if ( argc > 0 ) gchar *dstr;
yyin = fopen (argv[0], "r");
else g_return_val_if_fail (str != NULL, NULL);
yyin = stdin;
dstr = g_strdup (str);
yy_scan_string (dstr);
#ifdef DEBUG #ifdef DEBUG
yydebug = 1; yydebug = 1;
#endif #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;
} }

View file

@ -12,13 +12,19 @@
#endif #endif
#define CHAR(x) PRINT ("char: %c\n", *yytext); return *yytext; #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:]]+ _integer [[:digit:]]+
_float [[:digit:]]+"."*[[:digit:]]* _double [[:digit:]]+"."*[[:digit:]]*
_number {_integer}|{_float} _number {_integer}|{_double}
_boolean "true"|"false"|"TRUE"|"FALSE" _boolean "true"|"false"|"TRUE"|"FALSE"
_identifier [[:alpha:]][[:alnum:]\-_]* _identifier [[:alpha:]][[:alnum:]\-_%]*
_lconnection ({_identifier}\.)?{_identifier}!
_rconnection !({_identifier}\.)?{_identifier}
_bconnection ({_identifier}\.)?{_identifier}!({_identifier}\.)?{_identifier}
_string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"") _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"")
%x value %x value
@ -28,21 +34,30 @@ _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"")
<value>{ <value>{
{_integer} { {_integer} {
PRINT ("An integer: %s (%d)\n", yytext, 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); BEGIN (INITIAL);
return INTEGER; return VALUE;
} }
{_float} { {_double} {
PRINT ("A float: %s (%g)\n", yytext, atof (yytext)); 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); BEGIN (INITIAL);
return FLOAT; return VALUE;
} }
{_boolean} { {_boolean} {
PRINT ("A boolean: %s (%d)\n", yytext, tolower (*yytext) == 't' ? 1 : 0); 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); BEGIN (INITIAL);
return BOOLEAN; return VALUE;
} }
{_string} { {_string} {
@ -50,20 +65,80 @@ _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"")
yytext++; yytext++;
*(yytext + strlen (yytext) - 1) = '\0'; *(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); BEGIN (INITIAL);
return STRING; return VALUE;
} }
[[:space:]]+ { /* PRINT ("space: [%s]\n", yytext); */ } [[:space:]]+ { /* PRINT ("space: [%s]\n", yytext); */ }
. { . {
PRINT ("unknown: %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} { {_identifier} {
PRINT ("An identifier: %s\n", yytext); PRINT ("An identifier: %s\n", yytext);
lvalp->s = g_strdup (yytext);
return IDENTIFIER; return IDENTIFIER;
} }

View file

@ -1,38 +1,43 @@
#include <glib-object.h> #include <glib-object.h>
#include "../gstelement.h"
typedef struct { typedef struct {
gchar *name; gchar *type;
gint index;
GList *property_values; GList *property_values;
GstElement *element;
} element_t; } element_t;
typedef struct { typedef struct {
gchar *name; gchar *name;
GType value_type; GValue *value;
union {
gdouble d;
gboolean b;
gint i;
gchar *s;
} value;
} property_t; } property_t;
typedef struct { typedef struct {
char *src; /* if the names are present, upon connection we'll search out the pads of the
char *sink; 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 *src_pads;
GList *sink_pads; GList *sink_pads;
} connection_t; } connection_t;
typedef struct { typedef struct _graph_t graph_t;
struct _graph_t {
element_t *first;
element_t *current; element_t *current;
graph_t *parent;
gchar *current_bin_type; gchar *current_bin_type;
GList *elements; GList *elements;
GList *connections; GList *connections;
GList *connections_pending; GList *connections_pending;
GList *bins; GList *bins;
} graph_t; GstElement *bin;
};
graph_t * _gst_parse_launch (const gchar *str, GError **error);
typedef struct {
gchar *id1;
gchar *id2;
} hash_t;

View file

@ -44,23 +44,18 @@ main(int argc,char *argv[])
sink = gst_elementfactory_make ("fakesink", "sink"); sink = gst_elementfactory_make ("fakesink", "sink");
g_return_val_if_fail (sink != NULL, 4); g_return_val_if_fail (sink != NULL, 4);
gst_bin_add (pipeline, GST_ELEMENT (src)); gst_bin_add_many (pipeline, src, tee, identity1, identity2, aggregator, sink, NULL);
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_element_connect (src, "src", tee, "sink"); gst_element_connect_pads (src, "src", tee, "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 (identity1, "sink")); 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_element_get_pad (identity2, "sink"));
gst_pad_connect (gst_element_get_pad (identity1, "src"), 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_pad_connect (gst_element_get_pad (identity2, "src"),
gst_element_request_pad_by_name (aggregator, "sink%d")); gst_element_get_request_pad (aggregator, "sink%d"));
gst_element_connect (aggregator, "src", sink, "sink"); gst_element_connect_pads (aggregator, "src", sink, "sink");
g_signal_connect (G_OBJECT (src), "eos", g_signal_connect (G_OBJECT (src), "eos",
G_CALLBACK (eos_signal), NULL); G_CALLBACK (eos_signal), NULL);

View file

@ -19,22 +19,22 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
/* disconnect the typefind from the pipeline and remove it */ /* 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); gst_bin_remove (GST_BIN (autobin), typefind);
/* and an audio sink */ /* and an audio sink */
osssink = gst_elementfactory_make("osssink", "play_audio"); osssink = gst_elementfactory_make ("osssink", "play_audio");
g_assert(osssink != NULL); g_assert (osssink != NULL);
videosink = gst_bin_new ("videosink"); videosink = gst_bin_new ("videosink");
/* and an video sink */ /* and an video sink */
videoelement = gst_elementfactory_make("xvideosink", "play_video"); videoelement = gst_elementfactory_make ("xvideosink", "play_video");
g_assert(videosink != NULL); g_assert (videosink != NULL);
colorspace = gst_elementfactory_make("colorspace", "colorspace"); colorspace = gst_elementfactory_make ("colorspace", "colorspace");
g_assert(colorspace != NULL); 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), colorspace);
gst_bin_add (GST_BIN (videosink), videoelement); 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); 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); 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"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_disconnect (filesrc, "src", cache, "sink"); gst_element_disconnect_many (filesrc, cache, new_element, NULL);
gst_element_disconnect (cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (autobin), cache); 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); 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), cache);
gst_bin_add (GST_BIN (autobin), typefind); 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_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin); gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_connect (filesrc, "src", autobin, "sink"); gst_element_connect_pads (filesrc, "src", autobin, "sink");
/* start playing */ /* 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))); while (gst_bin_iterate (GST_BIN (pipeline)));

View file

@ -22,7 +22,7 @@ int main (int argc, char *argv[])
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
/* now it's time to get the decoder */ /* now it's time to get the decoder */
decoder = gst_elementfactory_make ("mad", "parse"); decoder = gst_elementfactory_make ("mad", "decode");
if (!decoder) { if (!decoder) {
g_print ("could not find plugin \"mad\""); g_print ("could not find plugin \"mad\"");
return -1; return -1;
@ -35,7 +35,7 @@ int main (int argc, char *argv[])
gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL); gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL);
/* connect the elements */ /* connect the elements */
gst_element_connect_elements_many (filesrc, decoder, osssink, NULL); gst_element_connect_many (filesrc, decoder, osssink, NULL);
/* start playing */ /* start playing */
gst_element_set_state (bin, GST_STATE_PLAYING); gst_element_set_state (bin, GST_STATE_PLAYING);

View file

@ -18,8 +18,8 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin"); autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
/* disconnect the typefind from the pipeline and remove it */ /* disconnect_pads 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); gst_bin_remove (GST_BIN (autobin), typefind);
/* and an audio sink */ /* 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); 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); 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"); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_disconnect (filesrc, "src", cache, "sink"); gst_element_disconnect_pads (filesrc, "src", cache, "sink");
gst_element_disconnect (cache, "src", new_element, "sink"); gst_element_disconnect_pads (cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (autobin), cache); 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); 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), cache);
gst_bin_add (GST_BIN (autobin), typefind); 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_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin); gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_connect (filesrc, "src", autobin, "sink"); gst_element_connect_pads (filesrc, "src", autobin, "sink");
/* start playing */ /* start playing */
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING); gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);

View file

@ -5,6 +5,7 @@ main (int argc, char *argv[])
{ {
GstElement *pipeline; GstElement *pipeline;
GstElement *filesrc; GstElement *filesrc;
GError *error = NULL;
gst_init (&argc, &argv); gst_init (&argc, &argv);
@ -13,7 +14,11 @@ main (int argc, char *argv[])
return -1; 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"); filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);

View file

@ -40,7 +40,7 @@ void eos(GstElement *element)
/* playing = FALSE; */ /* playing = FALSE; */
} }
static GstCaps* G_GNUC_UNUSED static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element) gst_play_typefind (GstBin *bin, GstElement *element)
{ {
GstElement *typefind; GstElement *typefind;
@ -140,7 +140,7 @@ int main(int argc,char *argv[])
/* request pads and connect to adder */ /* request pads and connect to adder */
GST_INFO (0, "requesting pad\n"); 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)); printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
sprintf (buffer, "channel%d", i); sprintf (buffer, "channel%d", i);
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad); 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 */ char buffer[20]; /* hold the names */
GstAutoplug *autoplug; /* GstAutoplug *autoplug;
GstCaps *srccaps; GstCaps *srccaps; */
GstElement *new_element; GstElement *new_element;
GstElement *decoder; 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), channel->volenv);
gst_bin_add (GST_BIN (channel->pipe), new_element); gst_bin_add (GST_BIN (channel->pipe), new_element);
gst_element_connect (channel->filesrc, "src", new_element, "sink"); gst_element_connect_pads (channel->filesrc, "src", new_element, "sink");
gst_element_connect (new_element, "src_00", channel->volenv, "sink"); gst_element_connect_pads (new_element, "src_00", channel->volenv, "sink");
/* add a ghost pad */ /* add a ghost pad */
sprintf (buffer, "channel%d", id); sprintf (buffer, "channel%d", id);

View file

@ -19,7 +19,7 @@ object_saved (GstObject *object, xmlNodePtr parent, gpointer data)
int main(int argc,char *argv[]) int main(int argc,char *argv[])
{ {
GstElement *filesrc, *osssink, *queue, *queue2, *parse, *decode; GstElement *filesrc, *osssink, *queue, *queue2, *decode;
GstElement *pipeline; GstElement *pipeline;
GstElement *thread, *thread2; GstElement *thread, *thread2;

View file

@ -4,7 +4,7 @@
gboolean playing; gboolean playing;
static void G_GNUC_UNUSED static void
xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data) xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data)
{ {
xmlNodePtr children = self->xmlChildrenNode; xmlNodePtr children = self->xmlChildrenNode;

View file

@ -25,7 +25,7 @@ int main (int argc, char *argv[])
/* make the first pipeline */ /* make the first pipeline */
gst_bin_add (GST_BIN(pipe1), fakesrc); gst_bin_add (GST_BIN(pipe1), fakesrc);
gst_bin_add (GST_BIN(pipe1), fakesink1); gst_bin_add (GST_BIN(pipe1), fakesink1);
gst_element_connect(fakesrc, "src", fakesink1, "sink"); gst_element_connect_pads (fakesrc, "src", fakesink1, "sink");
/* initialize cothreads */ /* initialize cothreads */
gst_element_set_state(pipe1, GST_STATE_PLAYING); 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); gst_element_set_state(pipe1, GST_STATE_READY);
/* destroy the fakesink, but keep fakesrc (its state is 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_object_ref(GST_OBJECT(fakesrc));
gst_bin_remove(GST_BIN(pipe1), fakesrc); gst_bin_remove(GST_BIN(pipe1), fakesrc);
gst_bin_remove(GST_BIN(pipe1), fakesink1); 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 */ /* don't change the new pipeline's state, it should change on the bin_add */
gst_bin_add (GST_BIN(pipe2), fakesrc); 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 */ /* show the pipeline state */
gst_xml_write_file (GST_ELEMENT (pipe2), stdout); gst_xml_write_file (GST_ELEMENT (pipe2), stdout);

View file

@ -2,9 +2,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <gst/gst.h> #include <gst/gst.h>
static int launch_argc;
static char **launch_argv;
static guint64 iterations = 0; static guint64 iterations = 0;
static guint64 sum = 0; static guint64 sum = 0;
static guint64 min = G_MAXINT; static guint64 min = G_MAXINT;
@ -134,44 +131,37 @@ main(int argc, char *argv[])
{ {
/* options */ /* options */
gboolean silent = FALSE; gboolean silent = FALSE;
gchar *savefile = NULL;
struct poptOption options[] = { 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 POPT_TABLEEND
}; };
GstElement *pipeline; GstElement *pipeline;
gchar **argvn; gchar **argvn;
gboolean save_pipeline = FALSE; GError *error = NULL;
gboolean run_pipeline = TRUE;
gchar *savefile = "";
free (malloc (8)); /* -lefence */ free (malloc (8)); /* -lefence */
gst_init_with_popt_table (&argc, &argv, options); 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 */ /* 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)); memcpy (argvn, argv+1, sizeof (char*) * (argc-1));
if (strstr (argv[0], "gst-xmllaunch")) { if (strstr (argv[0], "gst-xmllaunch")) {
pipeline = xmllaunch_parse_cmdline ((const gchar **) argvn); pipeline = xmllaunch_parse_cmdline ((const gchar**)argvn);
} else { } else {
pipeline = (GstElement*) gst_parse_launchv ((const gchar **) argvn); pipeline = (GstElement*) gst_parse_launchv ((const gchar**)argvn, &error);
} }
if (!pipeline) { 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); exit(1);
} }
@ -180,12 +170,12 @@ main(int argc, char *argv[])
g_signal_connect (pipeline, "error", G_CALLBACK (error_callback), NULL); g_signal_connect (pipeline, "error", G_CALLBACK (error_callback), NULL);
#ifndef GST_DISABLE_LOADSAVE #ifndef GST_DISABLE_LOADSAVE
if (save_pipeline) { if (savefile) {
gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w")); gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w"));
} }
#endif #endif
if (run_pipeline) { if (!savefile) {
gst_buffer_print_stats(); gst_buffer_print_stats();
fprintf(stderr,"RUNNING pipeline\n"); fprintf(stderr,"RUNNING pipeline\n");
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) { if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {