mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-29 11:40:38 +00:00
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:
parent
3cbe1bacd0
commit
70cfc6cb4d
86 changed files with 2621 additions and 2495 deletions
|
@ -93,15 +93,6 @@ GST_DEBUG_ENABLED
|
|||
GST_DEBUG_ENABLE_CATEGORIES
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gstextratypes</FILE>
|
||||
<TITLE>GstExtraTypes</TITLE>
|
||||
GST_TYPE_FILENAME
|
||||
<SUBSECTION Standard>
|
||||
gst_extra_get_filename_type
|
||||
GST_DISABLE_LOADSAVE_REGISTRY
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gstscheduler</FILE>
|
||||
<TITLE>GstScheduler</TITLE>
|
||||
|
@ -202,7 +193,7 @@ gst_bin_details
|
|||
<SECTION>
|
||||
<FILE>gstparse</FILE>
|
||||
<TITLE>GstParse</TITLE>
|
||||
GstParseErrors
|
||||
GstParseError
|
||||
gst_parse_launch
|
||||
gst_parse_launchv
|
||||
</SECTION>
|
||||
|
@ -360,22 +351,25 @@ gst_element_get_managing_bin
|
|||
gst_element_add_pad
|
||||
gst_element_remove_pad
|
||||
gst_element_get_pad
|
||||
gst_element_get_static_pad
|
||||
gst_element_get_request_pad
|
||||
gst_element_get_pad_list
|
||||
gst_element_get_padtemplate_list
|
||||
gst_element_get_padtemplate_by_name
|
||||
gst_element_add_ghost_pad
|
||||
gst_element_remove_ghost_pad
|
||||
gst_element_request_compatible_pad
|
||||
gst_element_request_pad_by_name
|
||||
gst_element_get_compatible_pad
|
||||
gst_element_get_compatible_static_pad
|
||||
gst_element_get_compatible_request_pad
|
||||
gst_element_get_compatible_pad_filtered
|
||||
gst_element_connect
|
||||
gst_element_connect_many
|
||||
gst_element_connect_filtered
|
||||
gst_element_connect_elements
|
||||
gst_element_connect_elements_filtered
|
||||
gst_element_connect_elements_many
|
||||
gst_element_connect_pads
|
||||
gst_element_connect_pads_filtered
|
||||
gst_element_disconnect
|
||||
gst_element_disconnect_elements
|
||||
gst_element_disconnect_many
|
||||
gst_element_disconnect_pads
|
||||
gst_element_set_state
|
||||
gst_element_get_state
|
||||
gst_element_wait_state_change
|
||||
|
@ -499,22 +493,6 @@ GST_IS_CLOCK
|
|||
GST_IS_CLOCK_CLASS
|
||||
</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>
|
||||
<FILE>gstlog</FILE>
|
||||
<SUBSECTION Standard>
|
||||
|
@ -1096,211 +1074,3 @@ gst_static_autoplug_render_get_type
|
|||
GST_STATIC_AUTOPLUG_RENDER_CLASS
|
||||
GST_IS_STATIC_AUTOPLUG_RENDER_CLASS
|
||||
</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>
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ gst_pad_get_type
|
|||
gst_padtemplate_get_type
|
||||
gst_ghost_pad_get_type
|
||||
gst_thread_get_type
|
||||
gst_tee_get_type
|
||||
gst_plugin_feature_get_type
|
||||
gst_autoplug_get_type
|
||||
gst_autoplugfactory_get_type
|
||||
|
@ -18,25 +17,5 @@ gst_typefactory_get_type
|
|||
gst_elementfactory_get_type
|
||||
gst_schedulerfactory_get_type
|
||||
gst_scheduler_get_type
|
||||
gst_system_clock_get_type
|
||||
gst_timecache_get_type
|
||||
gst_xml_get_type
|
||||
|
||||
gst_aggregator_get_type
|
||||
gst_fakesrc_get_type
|
||||
gst_fakesink_get_type
|
||||
|
||||
gst_filesrc_get_type
|
||||
gst_fdsrc_get_type
|
||||
|
||||
gst_fdsink_get_type
|
||||
gst_disksink_get_type
|
||||
|
||||
gst_pipefilter_get_type
|
||||
gst_identity_get_type
|
||||
gst_queue_get_type
|
||||
|
||||
gst_statistics_get_type
|
||||
gst_md5sink_get_type
|
||||
gst_typefind_get_type
|
||||
|
||||
|
|
|
@ -25,23 +25,3 @@ methods to request buffers from its pads.
|
|||
@AGGREGATOR_LOOP_SELECT:
|
||||
@AGGREGATOR_CHAIN:
|
||||
|
||||
<!-- ##### ARG GstAggregator:num-pads ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstAggregator:silent ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstAggregator:sched ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstAggregator:last-message ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ Flags for a bin.
|
|||
@GST_BIN_SELF_SCHEDULABLE:
|
||||
@GST_BIN_FLAG_PREFER_COTHREADS:
|
||||
@GST_BIN_FLAG_FIXED_CLOCK:
|
||||
@GST_BIN_SELF_ITERATING:
|
||||
@GST_BIN_FLAG_LAST:
|
||||
|
||||
<!-- ##### STRUCT GstBin ##### -->
|
||||
|
|
|
@ -14,20 +14,3 @@ The disksink write to a file. The filename can be given as an argument.
|
|||
#GstFdSink
|
||||
</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>
|
||||
|
||||
|
|
|
@ -376,6 +376,26 @@ instead.
|
|||
@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 ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -424,7 +444,17 @@ instead.
|
|||
@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>
|
||||
|
@ -434,23 +464,13 @@ instead.
|
|||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_request_pad_by_name ##### -->
|
||||
<!-- ##### FUNCTION gst_element_get_compatible_request_pad ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@element:
|
||||
@name:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_get_compatible_pad ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@element:
|
||||
@pad:
|
||||
@templ:
|
||||
@Returns:
|
||||
|
||||
|
||||
|
@ -471,47 +491,14 @@ instead.
|
|||
</para>
|
||||
|
||||
@src:
|
||||
@dest:
|
||||
@Returns:
|
||||
<!-- # Unused Parameters # -->
|
||||
@srcpadname:
|
||||
@dest:
|
||||
@destpadname:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_connect_filtered ##### -->
|
||||
<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 ##### -->
|
||||
<!-- ##### FUNCTION gst_element_connect_many ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
@ -522,7 +509,21 @@ instead.
|
|||
@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>
|
||||
|
@ -531,15 +532,53 @@ instead.
|
|||
@srcpadname:
|
||||
@dest:
|
||||
@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>
|
||||
|
||||
@src:
|
||||
@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 ##### -->
|
||||
|
|
|
@ -16,36 +16,3 @@ with the buffer. (fakesink)
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -14,86 +14,3 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -14,8 +14,3 @@ Write data to a file descriptor.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstFdSink:fd ##### -->
|
||||
<para>
|
||||
The filedescriptor to write to.
|
||||
</para>
|
||||
|
||||
|
|
|
@ -14,18 +14,3 @@ Read buffers from a file descriptor.
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -15,38 +15,3 @@ and subbuffers.
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -14,51 +14,3 @@ Pass data without modification.
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -44,15 +44,14 @@ can be made with <option>{}</option>.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### ENUM GstParseErrors ##### -->
|
||||
<!-- ##### ENUM GstParseError ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@GST_PARSE_ERROR_SYNTAX:
|
||||
@GST_PARSE_ERROR_CREATING_ELEMENT:
|
||||
@GST_PARSE_ERROR_NOSUCH_ELEMENT:
|
||||
@GST_PARSE_ERROR_INTERNAL:
|
||||
@GST_PARSE_ERROR_NO_SUCH_ELEMENT:
|
||||
@GST_PARSE_ERROR_NO_SUCH_PROPERTY:
|
||||
@GST_PARSE_ERROR_CONNECT:
|
||||
|
||||
<!-- ##### FUNCTION gst_parse_launch ##### -->
|
||||
|
@ -61,6 +60,7 @@ can be made with <option>{}</option>.
|
|||
</para>
|
||||
|
||||
@pipeline_description:
|
||||
@error:
|
||||
@Returns:
|
||||
<!-- # Unused Parameters # -->
|
||||
@cmdline:
|
||||
|
@ -73,6 +73,7 @@ can be made with <option>{}</option>.
|
|||
</para>
|
||||
|
||||
@argv:
|
||||
@error:
|
||||
@Returns:
|
||||
|
||||
|
||||
|
|
|
@ -15,8 +15,3 @@ buffers from its output.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstPipefilter:command ##### -->
|
||||
<para>
|
||||
Sets the command to be executed.
|
||||
</para>
|
||||
|
||||
|
|
|
@ -25,24 +25,3 @@ The queue blocks by default.
|
|||
|
||||
</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
|
@ -15,55 +15,3 @@ the data stream, such as buffers/bytes/events etc.
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -14,18 +14,3 @@ A tee can be used to split out the filter graph.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstTee:silent ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstTee:num-pads ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstTee:last-message ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
|
|
|
@ -15,16 +15,3 @@ the detected mime type of the stream. It is used in autoplugging.
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -21,16 +21,15 @@
|
|||
<programlisting>
|
||||
...
|
||||
/* now it's time to get the parser */
|
||||
parse = gst_elementfactory_make ("mp3parse", "parse");
|
||||
decoder = gst_elementfactory_make ("mpg123", "decoder");
|
||||
decoder = gst_elementfactory_make ("mad", "decoder");
|
||||
...
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
While this mechanism is quite effective it also has some big problems:
|
||||
The elements are created based on their name. Indeed, we create an
|
||||
element mpg123 by explicitly stating the mpg123 elements name.
|
||||
Our little program therefore always uses the mpg123 decoder element
|
||||
element mad by explicitly stating the mad element's name.
|
||||
Our little program therefore always uses the mad decoder element
|
||||
to decode the MP3 audio stream, even if there are 3 other MP3 decoders
|
||||
in the system. We will see how we can use a more general way to create
|
||||
an MP3 decoder element.
|
||||
|
@ -42,7 +41,7 @@
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>more on MIME Types</title>
|
||||
<title>More on MIME Types</title>
|
||||
<para>
|
||||
GStreamer uses MIME types to indentify the different types of data
|
||||
that can be handled by the elements. They are the high level
|
||||
|
@ -125,8 +124,8 @@
|
|||
the given MIME type.
|
||||
</para>
|
||||
<para>
|
||||
There is also an association between a MIME type and a file
|
||||
extension.
|
||||
There is also an association between a MIME type and a file extension, but the use of typefind
|
||||
functions (similar to file(1)) is preferred..
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>id to <classname>GstElementFactory</classname> conversion</title>
|
||||
<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.
|
||||
For more information, see <xref linkend="cha-autoplug"/>.
|
||||
</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>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<chapter id="cha-threads">
|
||||
<title>Threads</title>
|
||||
<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
|
||||
a special <classname>GstBin</classname> that will become a thread when started.
|
||||
</para>
|
||||
|
@ -13,39 +13,58 @@
|
|||
<programlisting>
|
||||
GstElement *my_thread;
|
||||
|
||||
// create the thread object
|
||||
/* create the thread object */
|
||||
my_thread = gst_thread_new ("my_thread");
|
||||
g_return_if_fail (audio_thread != NULL);
|
||||
/* you could have used gst_elementfactory_make ("thread", "my_thread"); */
|
||||
g_return_if_fail (my_thread != NULL);
|
||||
|
||||
// add some plugins
|
||||
/* add some plugins */
|
||||
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (funky_src));
|
||||
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect));
|
||||
|
||||
// connect the elements here...
|
||||
/* connect the elements here... */
|
||||
...
|
||||
|
||||
// start playing
|
||||
/* start playing */
|
||||
gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING);
|
||||
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
The above program will create a thread with two elements in it. As soon
|
||||
as it is set to the PLAYING state, the thread will start to iterate.
|
||||
The above program will create a thread with two elements in it. As soon as it is set to the
|
||||
PLAYING state, the thread will start to iterate itself. You never need to manually iterate a
|
||||
thread.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<sect2>
|
||||
<title>Constraints placed on the pipeline by the GstThread</title>
|
||||
<para>
|
||||
A thread should normally contain a source element. Most often, the thread
|
||||
is fed with data from a queue.
|
||||
Within the pipeline, everything is the same as in any other bin. The difference lies at the
|
||||
thread boundary, at the connection between the thread and the outside world (containing bin).
|
||||
Since GStreamer is fundamentally buffer-oriented rather than byte-oriented, the natural
|
||||
solution to this problem is an element that can "buffer" the buffers between the threads, in a
|
||||
thread-safe fashion. This element is the queue, described more fully in <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>
|
||||
</note>
|
||||
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>When would you want to use a thread?</title>
|
||||
<para>
|
||||
A thread will be visualised as below
|
||||
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>
|
||||
A thread can be visualised as below
|
||||
</para>
|
||||
<figure float="1" id="sec-threads-img">
|
||||
<title>a thread</title>
|
||||
<title>A thread</title>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/thread.&magic;" format="&magic;" />
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
Sets the mask for the info *and* the debug output.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>--gst-mask-help</option>
|
||||
Print out the meaning of gst-mask-* values.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>--gst-plugin-spew</option>
|
||||
|
@ -47,16 +53,15 @@
|
|||
<listitem>
|
||||
<para>
|
||||
<option>--help</option> Print the a short desciption of the
|
||||
options and an overview of the current debugging/info masks
|
||||
set.
|
||||
options
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
The follwing table gives an overview of the mask values and
|
||||
their meaning. (enabled) means that the corresponding flag
|
||||
has been set.
|
||||
The following table gives an overview of the mask values and their meaning. (enabled) means
|
||||
that the corresponding flag is set by default. This table is available to any GStreamer
|
||||
application by the --gst-mask-help option.
|
||||
</para>
|
||||
<programlisting>
|
||||
Mask (to be OR'ed) info/debug FLAGS
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
Sets the mask for the info *and* the debug output.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>--gst-mask-help</option>
|
||||
Print out the meaning of gst-mask-* values.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>--gst-plugin-spew</option>
|
||||
|
@ -47,16 +53,15 @@
|
|||
<listitem>
|
||||
<para>
|
||||
<option>--help</option> Print the a short desciption of the
|
||||
options and an overview of the current debugging/info masks
|
||||
set.
|
||||
options
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
The follwing table gives an overview of the mask values and
|
||||
their meaning. (enabled) means that the corresponding flag
|
||||
has been set.
|
||||
The following table gives an overview of the mask values and their meaning. (enabled) means
|
||||
that the corresponding flag is set by default. This table is available to any GStreamer
|
||||
application by the --gst-mask-help option.
|
||||
</para>
|
||||
<programlisting>
|
||||
Mask (to be OR'ed) info/debug FLAGS
|
||||
|
|
|
@ -4,38 +4,35 @@
|
|||
</para>
|
||||
|
||||
<sect1>
|
||||
<title><command>gstreamer-register</command></title>
|
||||
<title><command>gst-register</command></title>
|
||||
<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
|
||||
can be found in <filename>/etc/gstreamer/reg.xml</filename>.
|
||||
can be found, by default, in <filename>/etc/gstreamer/reg.xml</filename>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title><command>gstreamer-launch</command></title>
|
||||
<title><command>gst-launch</command></title>
|
||||
<para>
|
||||
This is a tool that will construct pipelines based on a command-line
|
||||
syntax.
|
||||
syntax. FIXME: need a more extensive grammar reference
|
||||
</para>
|
||||
<para>
|
||||
A simple commandline looks like:
|
||||
|
||||
<screen>
|
||||
gstreamer-launch filesrc location=hello.mp3 ! mp3parse ! mpg123 ! audiosink
|
||||
gst-launch filesrc location=hello.mp3 ! mad ! osssink
|
||||
</screen>
|
||||
|
||||
A more complex pipeline looks like:
|
||||
|
||||
<screen>
|
||||
gstreamer-launch filesrc redpill.vob audio_00! (ac3parse ! ac3dec ! audiosink) \
|
||||
video_00! (mpeg2dec ! videosink)
|
||||
gst-launch filesrc location=redpill.vob ! mpegdemux name=demux \
|
||||
demux.audio_00! { ac3parse ! a52dec ! osssink } \
|
||||
demux.video_00! { mpeg2dec ! xvideosink }
|
||||
</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>
|
||||
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 *filesrc;
|
||||
GError *error = NULL;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
pipeline = gst_pipeline_new ("my_pipeline");
|
||||
|
||||
gst_parse_launch ("filesrc[my_filesrc] ! mp3parse ! mpg123 ! osssink", GST_BIN (pipeline));
|
||||
pipeline = gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error);
|
||||
if (!pipeline) {
|
||||
g_print ("Parse error: %s\n", error->message);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
@ -81,20 +82,20 @@ main (int argc, char *argv[])
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title><command>gstreamer-inspect</command></title>
|
||||
<title><command>gst-inspect</command></title>
|
||||
<para>
|
||||
This is a tool to query a plugin or an element about its properties.
|
||||
</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>
|
||||
|
||||
<screen>
|
||||
gstreamer-inspect mpg123
|
||||
gst-inspect mad
|
||||
</screen>
|
||||
|
||||
<para>
|
||||
Below is the output of a query for the audiosink element:
|
||||
Below is the output of a query for the osssink element:
|
||||
</para>
|
||||
|
||||
<screen>
|
||||
|
@ -102,56 +103,72 @@ Factory Details:
|
|||
Long name: Audio Sink (OSS)
|
||||
Class: Sink/Audio
|
||||
Description: Output to a sound card via OSS
|
||||
Version: 0.1.0
|
||||
Author(s): Erik Walthinsen <omega@cse.ogi.edu>
|
||||
Version: 0.3.3.1
|
||||
Author(s): Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim.taymans@chello.be>
|
||||
Copyright: (C) 1999
|
||||
|
||||
GObject
|
||||
+----GstObject
|
||||
+----GstElement
|
||||
+----GstOssSink
|
||||
|
||||
Pad Templates:
|
||||
SINK template: 'sink'
|
||||
Exists: Always
|
||||
Availability: Always
|
||||
Capabilities:
|
||||
'audiosink_sink':
|
||||
'osssink_sink':
|
||||
MIME type: 'audio/raw':
|
||||
format: Integer: 16
|
||||
format: String: int
|
||||
endianness: Integer: 1234
|
||||
width: List:
|
||||
Integer: 8
|
||||
Integer: 16
|
||||
depth: List:
|
||||
Integer: 8
|
||||
Integer: 16
|
||||
rate: Integer range: 8000 - 48000
|
||||
channels: Integer range: 1 - 2
|
||||
law: Integer: 0
|
||||
signed: List:
|
||||
Boolean: FALSE
|
||||
Boolean: TRUE
|
||||
rate: Integer range: 1000 - 48000
|
||||
|
||||
|
||||
Element Flags:
|
||||
GST_ELEMENT_THREADSUGGESTED
|
||||
no flags set
|
||||
|
||||
Element Implementation:
|
||||
No loopfunc(), must be chain-based or not configured yet
|
||||
Has change_state() function
|
||||
Has change_state() function: gst_osssink_change_state
|
||||
Has custom save_thyself() function: gst_element_save_thyself
|
||||
Has custom restore_thyself() function: gst_element_restore_thyself
|
||||
|
||||
Clocking Interaction:
|
||||
element requires a clock
|
||||
element provides a clock: GstOssClock
|
||||
|
||||
Pads:
|
||||
SINK: 'sink'
|
||||
Implementation:
|
||||
Has chainfunc(): 0x4001cde8
|
||||
Has default eosfunc() gst_pad_eos_func()
|
||||
Has chainfunc(): 0x40056fc0
|
||||
Pad Template: 'sink'
|
||||
Capabilities:
|
||||
'audiosink_sink':
|
||||
MIME type: 'audio/raw':
|
||||
format: Integer: 16
|
||||
depth: List:
|
||||
Integer: 8
|
||||
Integer: 16
|
||||
rate: Integer range: 8000 - 48000
|
||||
channels: Integer range: 1 - 2
|
||||
|
||||
Element Arguments:
|
||||
GstAudioSink::mute: Boolean
|
||||
GstAudioSink::format: Enum (default 16)
|
||||
(8): 8 Bits
|
||||
(16): 16 Bits
|
||||
GstAudioSink::channels: Enum (default 2)
|
||||
name : String (Default "element")
|
||||
device : String (Default "/dev/dsp")
|
||||
mute : Boolean (Default false)
|
||||
format : Integer (Default 16)
|
||||
channels : Enum "GstAudiosinkChannels" (default 1)
|
||||
(0): Silence
|
||||
(1): Mono
|
||||
(2): Stereo
|
||||
GstAudioSink::frequency: Integer
|
||||
frequency : Integer (Default 11025)
|
||||
fragment : Integer (Default 6)
|
||||
buffer-size : Integer (Default 4096)
|
||||
|
||||
Element Signals:
|
||||
"handoff" : void user_function (GstOssSink* object,
|
||||
gpointer user_data);
|
||||
</screen>
|
||||
|
||||
<para>
|
||||
|
@ -159,11 +176,11 @@ Element Arguments:
|
|||
</para>
|
||||
|
||||
<screen>
|
||||
gstreamer-inspect gstelements
|
||||
gst-inspect gstelements
|
||||
</screen>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title><command>gstmediaplay</command></title>
|
||||
<title><command>gst-play</command></title>
|
||||
<para>
|
||||
A sample media player.
|
||||
</para>
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<title>Autoplugging</title>
|
||||
<para>
|
||||
<application>GStreamer</application> provides an API to automatically
|
||||
construct complex pipelinebased on source and destination capabilities.
|
||||
This feature is very usefull if you want to convert type X to type Y but
|
||||
construct complex pipelines based on source and destination capabilities.
|
||||
This feature is very useful if you want to convert type X to type Y but
|
||||
don't care about the plugins needed to accomplish this task. The
|
||||
autoplugger will consult the plugin repository, select and connect the
|
||||
elements needed for the conversion.
|
||||
|
@ -106,7 +106,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
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>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@ -141,8 +141,52 @@
|
|||
</orderedlist>
|
||||
</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.
|
||||
</para>
|
||||
</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>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<para>
|
||||
Bins allow you to combine connected elements into one logical element. You do
|
||||
not deal with the individual elements anymore but with just one element, the bin.
|
||||
We will see that this is extremely powerfull when you are going to construct
|
||||
We will see that this is extremely powerful when you are going to construct
|
||||
complex pipelines since it allows you to break up the pipeline in smaller chunks.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -37,9 +37,10 @@
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
A thread (<classname>GstThread</classname>). All the elements in the thread bin will
|
||||
run in a separate thread. You will have to use this bin if you carfully have to
|
||||
synchronize audio and video for example. You will learn more about threads in.. <!-- FIXME -->
|
||||
A thread (<classname>GstThread</classname>). The plan for the
|
||||
<classname>GstThread</classname> will be run in a separate thread. You will have to use
|
||||
this bin if you have to carefully synchronize audio and video, for example. You will learn
|
||||
more about threads in <xref linkend="cha-threads"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -48,26 +49,22 @@
|
|||
<sect1 id="sec-bin-create">
|
||||
<title>Creating a bin</title>
|
||||
<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>
|
||||
<programlisting>
|
||||
GstElement *bin;
|
||||
GstElement *bin, *thread, *pipeline;
|
||||
|
||||
gst_bin_new ("mybin");
|
||||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
A thread can be created with:
|
||||
</para>
|
||||
<programlisting>
|
||||
GstElement *thread;
|
||||
/* create a new bin called 'mybin'. this bin will be only for organizational purposes; a normal
|
||||
GstBin doesn't affect plan generation */
|
||||
bin = gst_elementfactory_make ("bin", "mybin");
|
||||
|
||||
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_<bintype>_new (). these are equivalent to the gst_elementfactory_make () syntax. */
|
||||
pipeline = gst_pipeline_new ("pipeline_name");
|
||||
</programlisting>
|
||||
<para>
|
||||
Pipelines are created with gst_pipeline_new ("name");
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="sec-bin-adding">
|
||||
|
@ -86,8 +83,9 @@
|
|||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
Bins and threads can be added to other bins too. This allows you to create nested
|
||||
bins.
|
||||
Bins and threads can be added to other bins too. This allows you to create nested bins. Note
|
||||
that it doesn't make very much sense to add a <classname>GstPipeline</classname> to anything,
|
||||
as it's a toplevel bin that needs to be explicitly iterated.
|
||||
</para>
|
||||
<para>
|
||||
To get an element from the bin you can use:
|
||||
|
@ -100,7 +98,7 @@
|
|||
</programlisting>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -114,7 +112,7 @@
|
|||
while (elements) {
|
||||
GstElement *element = GST_ELEMENT (elements->data);
|
||||
|
||||
g_print ("element in bin: %s\n", gst_element_get_name (element));
|
||||
g_print ("element in bin: %s\n", GST_OBJECT_NAME (GST_OBJECT (element)));
|
||||
|
||||
elements = g_list_next (elements);
|
||||
}
|
||||
|
@ -129,6 +127,18 @@
|
|||
gst_bin_remove (GST_BIN (bin), element);
|
||||
...
|
||||
</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 id="sec-bin-custom">
|
||||
|
@ -137,34 +147,47 @@
|
|||
The application programmer can create custom bins packed with elements to perform a
|
||||
specific task. This allow you to write an MPEG audio decoder with just the follwing lines
|
||||
of code:
|
||||
|
||||
</para>
|
||||
<programlisting>
|
||||
|
||||
// create the mp3player element
|
||||
/* create the mp3player element */
|
||||
GstElement *mp3player = gst_elementfactory_make ("mp3player", "mp3player");
|
||||
// set the source mp3 audio file
|
||||
/* set the source mp3 audio file */
|
||||
g_object_set (G_OBJECT (mp3player), "location", "helloworld.mp3", NULL);
|
||||
// start playback
|
||||
/* start playback */
|
||||
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING);
|
||||
...
|
||||
// pause playback
|
||||
/* pause playback */
|
||||
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED);
|
||||
...
|
||||
// stop
|
||||
/* stop */
|
||||
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL);
|
||||
</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
|
||||
information about creating custom bin in the Filter-Writers-Guide.
|
||||
information about creating custom bin in the Plugin Writers Guide (FIXME ref).
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="sec-bin-ghostpads">
|
||||
<title>Ghost pads</title>
|
||||
<para>
|
||||
You can see from figure ... how a bin has no pads of its own. This is where Ghostpads
|
||||
come into play.
|
||||
You can see from figure <xref linkend="sec-bin-noghost-img"/> how a bin has no pads of its own.
|
||||
This is where "ghost pads" come into play.
|
||||
</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>
|
||||
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
|
||||
|
@ -181,7 +204,7 @@
|
|||
</mediaobject>
|
||||
</figure>
|
||||
<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.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -192,7 +215,7 @@
|
|||
GstElement *bin;
|
||||
GstElement *element;
|
||||
|
||||
element = gst_elementfactory_create ("mpg123", "decoder");
|
||||
element = gst_elementfactory_create ("mad", "decoder");
|
||||
bin = gst_bin_new ("mybin");
|
||||
|
||||
gst_bin_add (GST_BIN (bin), element);
|
||||
|
@ -210,7 +233,7 @@
|
|||
|
||||
filesrc = gst_elementfactory_create ("filesrc", "disk_reader");
|
||||
|
||||
gst_element_connect (filesrc, "src", bin, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", bin, "sink");
|
||||
...
|
||||
</programlisting>
|
||||
</sect1>
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<para>
|
||||
A more complex case is when the filter modifies the data in place. It
|
||||
does so and simply passes on the buffer to the next element. This is just
|
||||
as easy to deal with. An element that works in place has to be carefull when
|
||||
as easy to deal with. An element that works in place has to be careful when
|
||||
the buffer is used in more than one element; a copy on write has to made in this
|
||||
situation.
|
||||
</para>
|
||||
|
|
|
@ -12,21 +12,16 @@
|
|||
different components you are going to use are derived from this GstElement.
|
||||
This means that a lot of functions you are going to use operate on this object.
|
||||
</para>
|
||||
<para>
|
||||
You will see that those elements have pads. These are the elements
|
||||
connections with the 'outside' world. Depending on the number and direction of
|
||||
the pads, we can see three types of elements: source, filter and sink element.
|
||||
</para>
|
||||
<para>
|
||||
These three types are all the same GstElement object, they just differ in how
|
||||
the pads are.
|
||||
<para> Elements, from the perspective of GStreamer, are viewed as "black boxes" with a number of
|
||||
different aspects. One of these aspects is the presence of "pads", or connection points. This
|
||||
terminology arises from soldering; pads are where wires can be attached.
|
||||
</para>
|
||||
|
||||
<sect2 id="sec-elements-src">
|
||||
<title>GStreamer source elements</title>
|
||||
<title>Source elements</title>
|
||||
<para>
|
||||
This element will generate data that will be used by the pipeline. It is
|
||||
typically a file or an audio source.
|
||||
Source elements generate data for use by a pipeline, for example reading from disk or from a
|
||||
sound card.
|
||||
</para>
|
||||
<para>
|
||||
Below you see how we will visualize the element.
|
||||
|
@ -48,18 +43,16 @@
|
|||
</sect2>
|
||||
|
||||
<sect2 id="sec-elements-filter">
|
||||
<title>GStreamer filter elements</title>
|
||||
<title>Filters and codecs</title>
|
||||
<para>
|
||||
Filter elements both have an input and an output pad. They operate on data
|
||||
they receive in the sink pad and send the result to the src pad.
|
||||
Filter elements both have input and output pads. They operate on data they receive in their
|
||||
sink pads and produce data on their src pads. For example, MPEG decoders and volume filters
|
||||
would fall into this category.
|
||||
</para>
|
||||
<para>
|
||||
Examples of a filter element might include: an MPEG decoder, volume filter,...
|
||||
</para>
|
||||
<para>
|
||||
Filters may also contain any number of input pads and output pads. For example,
|
||||
a video mixer might have to input pads (the images of the two different video
|
||||
streams) and one output pad.
|
||||
Elements are not constrained as to the number of pads they migh have; for example, a video
|
||||
mixer might have two input pads (the images of the two different video streams) and one
|
||||
output pad.
|
||||
</para>
|
||||
<figure float="1" id="sec-element-filterimg">
|
||||
<title>Visualisation of a filter element</title>
|
||||
|
@ -71,7 +64,7 @@
|
|||
</figure>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<figure float="1" id="sec-element-multifilterimg">
|
||||
|
@ -84,20 +77,20 @@
|
|||
</mediaobject>
|
||||
</figure>
|
||||
<para>
|
||||
The above figure shows the visualisation of a filter element with more than one
|
||||
output pad. An example of such a filter is the AVI splitter. This element will
|
||||
parse the input data and extracts the audio and video data. Most of these filters
|
||||
dynamically send out a signal when a new pad is created so that the application
|
||||
programmer can connect an arbitrary element to the newly created pad.
|
||||
The above figure shows the visualisation of a filter element with more than one output pad.
|
||||
An example of such a filter is the AVI splitter (demuxer). This element will parse the input
|
||||
data and extracts the audio and video data. Most of these filters dynamically send out a
|
||||
signal when a new pad is created so that the application programmer can connect an arbitrary
|
||||
element to the newly created pad.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="sec-elements-sink">
|
||||
<title>GStreamer sink elements</title>
|
||||
<title>Sink elements</title>
|
||||
<para>
|
||||
This element accepts data but will not generate any new data. A sink element
|
||||
is typically a file on disk, a soundcard, a display,... It is presented as
|
||||
below:
|
||||
Sink elements are terminal points in a media pipeline. They accept data but do not produce
|
||||
anything. Disk writing, soundcard playback, and video output woul all be implemented by sink
|
||||
elements.
|
||||
</para>
|
||||
<figure float="1" id="sec-element-sinkimg">
|
||||
<title>Visualisation of a sink element</title>
|
||||
|
@ -117,12 +110,12 @@
|
|||
</para>
|
||||
<para>
|
||||
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>
|
||||
<programlisting>
|
||||
GstElementFactory *factory;
|
||||
|
||||
factory = gst_elementfactory_find ("mpg123");
|
||||
factory = gst_elementfactory_find ("mad");
|
||||
</programlisting>
|
||||
<para>
|
||||
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");
|
||||
</programlisting>
|
||||
<para>
|
||||
gst_elementfactory_create () will use the elementfactory to create an element with the
|
||||
given name. The name of the element is something you can use later on to lookup the
|
||||
element in a bin, for example.
|
||||
gst_elementfactory_create () will use the elementfactory to create an element with the given
|
||||
name. The name of the element is something you can use later on to lookup the element in a
|
||||
bin, for example. You can pass NULL as the name argument to get a unique, default name.
|
||||
</para>
|
||||
<para>
|
||||
A simple shortcut exists for creating an element from a factory. The following example
|
||||
creates an element, named "decoder" from the elementfactory named "mpg123". This
|
||||
convenient function is most widly used to create an element.
|
||||
A simple shortcut exists for creating an element from a factory. The following example creates
|
||||
an element, named "decoder" from the elementfactory named "mad". This convenient function is
|
||||
most widely used to create an element.
|
||||
</para>
|
||||
<programlisting>
|
||||
GstElement *element;
|
||||
|
||||
element = gst_elementfactory_make ("mpg123", "decoder");
|
||||
element = gst_elementfactory_make ("mad", "decoder");
|
||||
</programlisting>
|
||||
<para>
|
||||
An element can be destroyed with:
|
||||
An element can be destroyed with: FIXME talk about refcounting
|
||||
</para>
|
||||
<programlisting>
|
||||
GstElement *element;
|
||||
|
|
|
@ -9,12 +9,11 @@
|
|||
<sect1>
|
||||
<title>Hello world</title>
|
||||
<para>
|
||||
We will create a simple first application. In fact it will be a complete
|
||||
MP3 player, using standard <application>GStreamer</application> components. The player will read from
|
||||
a file that is given as the first argument of the program.
|
||||
We will create a simple first application, a complete MP3 player, using standard
|
||||
<application>GStreamer</application> components. The player will read from a file that is
|
||||
given as the first argument of the program.
|
||||
</para>
|
||||
|
||||
|
||||
<programlisting>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
@ -45,15 +44,10 @@ main (int argc, char *argv[])
|
|||
audiosink = gst_elementfactory_make ("osssink", "play_audio");
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add (GST_BIN (pipeline), filesrc);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (pipeline), audiosink);
|
||||
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect (gst_element_get_pad (filesrc, "src"),
|
||||
gst_element_get_pad (decoder, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (decoder, "src"),
|
||||
gst_element_get_pad (audiosink, "sink"));
|
||||
gst_element_connect_many (filesrc, decoder, audiosink, NULL);
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
@ -64,10 +58,8 @@ main (int argc, char *argv[])
|
|||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
/* we don't need a reference to these objects anymore */
|
||||
gst_object_unref (GST_OBJECT (audiosink));
|
||||
gst_object_unref (GST_OBJECT (decoder));
|
||||
gst_object_unref (GST_OBJECT (filesrc));
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
/* unreffing the pipeline unrefs the contained elements as well */
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
@ -98,8 +90,8 @@ main (int argc, char *argv[])
|
|||
</programlisting>
|
||||
|
||||
<para>
|
||||
We are going to create 3 elements and one pipeline. Since all objects are
|
||||
in fact elements, we can define them as:
|
||||
We are going to create 3 elements and one pipeline. Since all elements share the same base
|
||||
type, <classname>GstElement</classname>, we can define them as:
|
||||
</para>
|
||||
<programlisting>
|
||||
...
|
||||
|
@ -142,7 +134,7 @@ main (int argc, char *argv[])
|
|||
is installed on the system where this application is executed.
|
||||
</para>
|
||||
<programlisting>
|
||||
/* now it's time to get the parser */
|
||||
/* now it's time to get the decoder */
|
||||
decoder = gst_elementfactory_make ("mad", "decoder");
|
||||
</programlisting>
|
||||
<para>
|
||||
|
@ -167,9 +159,7 @@ main (int argc, char *argv[])
|
|||
</para>
|
||||
<programlisting>
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add (GST_BIN (pipeline), filesrc);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (pipeline), audiosink);
|
||||
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -177,10 +167,7 @@ main (int argc, char *argv[])
|
|||
</para>
|
||||
<programlisting>
|
||||
/* connect src to sink */
|
||||
gst_pad_connect (gst_element_get_pad (filesrc, "src"),
|
||||
gst_element_get_pad (decoder, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (decoder, "src"),
|
||||
gst_element_get_pad (audiosink, "sink"));
|
||||
gst_element_connect_many (filesrc, decoder, audiosink, NULL);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -229,16 +216,13 @@ main (int argc, char *argv[])
|
|||
/* stop the pipeline */
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
gst_object_unref (GST_OBJECT (audiosink));
|
||||
gst_object_unref (GST_OBJECT (decoder));
|
||||
gst_object_unref (GST_OBJECT (filesrc));
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
exit (0);
|
||||
</programlisting>
|
||||
<note>
|
||||
<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.
|
||||
</para>
|
||||
</note>
|
||||
|
@ -246,7 +230,7 @@ main (int argc, char *argv[])
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>compiling helloworld.c</title>
|
||||
<title>Compiling helloworld.c</title>
|
||||
<para>
|
||||
To compile the helloworld example, use:
|
||||
</para>
|
||||
|
@ -268,10 +252,10 @@ main (int argc, char *argv[])
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>conclusion</title>
|
||||
<title>Conclusion</title>
|
||||
<para>
|
||||
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.
|
||||
</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.
|
||||
It should also be clear that inserting filters, like a stereo effect,
|
||||
into the pipeline is not that hard to do. The most important thing is
|
||||
that you can reuse allready existing elements.
|
||||
that you can reuse already existing elements.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<chapter id="cha-pads">
|
||||
<title>GstPad</title>
|
||||
<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.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -44,7 +44,7 @@
|
|||
<title>Useful pad functions</title>
|
||||
<para>
|
||||
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>
|
||||
gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink
|
||||
|
@ -53,8 +53,8 @@
|
|||
</para>
|
||||
<para>
|
||||
You can get the parent of the pad, this is the element that this pad belongs to,
|
||||
with get_pad_set_parent(GstPad *pad). This function will return a pointer to a
|
||||
GstObject.
|
||||
with get_pad_get_parent(GstPad *pad). This function will return a pointer to a
|
||||
GstElement.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="sec-pads-dynamic">
|
||||
|
@ -66,7 +66,7 @@
|
|||
system stream.
|
||||
</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
|
||||
"dormant" as you can see in the padtemplates from the 'Exists: Sometimes'
|
||||
property. Depending on the type of MPEG2 file you play, the pads are created. We
|
||||
|
@ -104,7 +104,7 @@ main(int argc, char *argv[])
|
|||
// create pipeline and do something usefull
|
||||
...
|
||||
|
||||
mpeg2parser = gst_elementfactory_make ("mpeg2parse", "mpeg2parse");
|
||||
mpeg2parser = gst_elementfactory_make ("mpegdemux", "mpegdemux");
|
||||
g_signal_connect (G_OBJECT (mpeg2parser), "new_pad", pad_connect_func, pipeline);
|
||||
...
|
||||
|
||||
|
@ -141,19 +141,19 @@ main(int argc, char *argv[])
|
|||
...
|
||||
element = gst_elementfactory_make ("tee", "element");
|
||||
|
||||
pad = gst_element_request_pad_by_name (element, "src%d");
|
||||
pad = gst_element_get_request_pad (element, "src%d");
|
||||
g_print ("new pad %s\n", gst_pad_get_name (pad));
|
||||
...
|
||||
</programlisting>
|
||||
<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.
|
||||
</para>
|
||||
<para>
|
||||
It is also possible to request a pad that is compatible with another
|
||||
padtemplate. This is very usefull if you want to connect an element to
|
||||
a muxer element and you need to request a pad that is compatible. The
|
||||
gst_element_request_compatible_pad is used to request a compatible pad, as
|
||||
gst_element_get_compatible_pad is used to request a compatible pad, as
|
||||
is shown in the next example.
|
||||
</para>
|
||||
<programlisting>
|
||||
|
@ -162,11 +162,11 @@ main(int argc, char *argv[])
|
|||
GstPad *pad;
|
||||
...
|
||||
element = gst_elementfactory_make ("tee", "element");
|
||||
mp3parse = gst_elementfactory_make ("mp3parse", "mp3parse");
|
||||
mad = gst_elementfactory_make ("mad", "mad");
|
||||
|
||||
templ = gst_element_get_padtemplate_by_name (mp3parse, "sink");
|
||||
templ = gst_element_get_padtemplate_by_name (mad, "sink");
|
||||
|
||||
pad = gst_element_request_compatible_pad (element, templ);
|
||||
pad = gst_element_get_compatible_pad (element, templ);
|
||||
g_print ("new pad %s\n", gst_pad_get_name (pad));
|
||||
...
|
||||
</programlisting>
|
||||
|
@ -181,7 +181,7 @@ main(int argc, char *argv[])
|
|||
<para>
|
||||
We will briefly describe what capabilities are, enough for you to get a basic understanding
|
||||
of the concepts. You will find more information on how to create capabilities in the
|
||||
filter-writer-guide.
|
||||
Plugin Writer's Guide.
|
||||
</para>
|
||||
|
||||
<sect2 id="sec-pads-caps">
|
||||
|
@ -207,8 +207,8 @@ struct _GstCaps {
|
|||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
Below is a dump of the capabilities of the element mpg123, as shown by
|
||||
<command>gstreamer-inspect</command>.
|
||||
Below is a dump of the capabilities of the element mad, as shown by
|
||||
<command>gst-inspect</command>.
|
||||
You can see two pads: sink and src. Both pads have capability information attached to them.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -221,26 +221,25 @@ struct _GstCaps {
|
|||
</para>
|
||||
<programlisting>
|
||||
Pads:
|
||||
SINK: 'sink'
|
||||
....
|
||||
SINK template: 'sink'
|
||||
Availability: Always
|
||||
Capabilities:
|
||||
'mpg123_sink':
|
||||
'mad_sink':
|
||||
MIME type: 'audio/mp3':
|
||||
layer: Integer range: 1 - 3
|
||||
bitrate: Integer range: 8 - 320
|
||||
framed: Boolean: TRUE
|
||||
|
||||
SRC: 'src'
|
||||
....
|
||||
SRC template: 'src'
|
||||
Availability: Always
|
||||
Capabilities:
|
||||
'mpg123_src':
|
||||
'mad_src':
|
||||
MIME type: 'audio/raw':
|
||||
format: Integer: 16
|
||||
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
|
||||
channels: List:
|
||||
Integer: 1
|
||||
Integer: 2
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="sec-pads-props">
|
||||
|
@ -260,7 +259,7 @@ Pads:
|
|||
<listitem>
|
||||
<para>
|
||||
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>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@ -349,7 +348,7 @@ Pads:
|
|||
</para>
|
||||
<para>
|
||||
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>
|
||||
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
|
||||
</programlisting>
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
one or more autopluggers
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
exported symbols for use in other plugins
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The plugins have one simple method: plugin_init () where all the elementfactories are
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<para>
|
||||
Bins allow you to combine connected elements into one logical element. You do
|
||||
not deal with the individual elements anymore but with just one element, the bin.
|
||||
We will see that this is extremely powerfull when you are going to construct
|
||||
We will see that this is extremely powerful when you are going to construct
|
||||
complex pipelines since it allows you to break up the pipeline in smaller chunks.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -37,9 +37,10 @@
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
A thread (<classname>GstThread</classname>). All the elements in the thread bin will
|
||||
run in a separate thread. You will have to use this bin if you carfully have to
|
||||
synchronize audio and video for example. You will learn more about threads in.. <!-- FIXME -->
|
||||
A thread (<classname>GstThread</classname>). The plan for the
|
||||
<classname>GstThread</classname> will be run in a separate thread. You will have to use
|
||||
this bin if you have to carefully synchronize audio and video, for example. You will learn
|
||||
more about threads in <xref linkend="cha-threads"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -48,26 +49,22 @@
|
|||
<sect1 id="sec-bin-create">
|
||||
<title>Creating a bin</title>
|
||||
<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>
|
||||
<programlisting>
|
||||
GstElement *bin;
|
||||
GstElement *bin, *thread, *pipeline;
|
||||
|
||||
gst_bin_new ("mybin");
|
||||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
A thread can be created with:
|
||||
</para>
|
||||
<programlisting>
|
||||
GstElement *thread;
|
||||
/* create a new bin called 'mybin'. this bin will be only for organizational purposes; a normal
|
||||
GstBin doesn't affect plan generation */
|
||||
bin = gst_elementfactory_make ("bin", "mybin");
|
||||
|
||||
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_<bintype>_new (). these are equivalent to the gst_elementfactory_make () syntax. */
|
||||
pipeline = gst_pipeline_new ("pipeline_name");
|
||||
</programlisting>
|
||||
<para>
|
||||
Pipelines are created with gst_pipeline_new ("name");
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="sec-bin-adding">
|
||||
|
@ -86,8 +83,9 @@
|
|||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
Bins and threads can be added to other bins too. This allows you to create nested
|
||||
bins.
|
||||
Bins and threads can be added to other bins too. This allows you to create nested bins. Note
|
||||
that it doesn't make very much sense to add a <classname>GstPipeline</classname> to anything,
|
||||
as it's a toplevel bin that needs to be explicitly iterated.
|
||||
</para>
|
||||
<para>
|
||||
To get an element from the bin you can use:
|
||||
|
@ -100,7 +98,7 @@
|
|||
</programlisting>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -114,7 +112,7 @@
|
|||
while (elements) {
|
||||
GstElement *element = GST_ELEMENT (elements->data);
|
||||
|
||||
g_print ("element in bin: %s\n", gst_element_get_name (element));
|
||||
g_print ("element in bin: %s\n", GST_OBJECT_NAME (GST_OBJECT (element)));
|
||||
|
||||
elements = g_list_next (elements);
|
||||
}
|
||||
|
@ -129,6 +127,18 @@
|
|||
gst_bin_remove (GST_BIN (bin), element);
|
||||
...
|
||||
</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 id="sec-bin-custom">
|
||||
|
@ -137,34 +147,47 @@
|
|||
The application programmer can create custom bins packed with elements to perform a
|
||||
specific task. This allow you to write an MPEG audio decoder with just the follwing lines
|
||||
of code:
|
||||
|
||||
</para>
|
||||
<programlisting>
|
||||
|
||||
// create the mp3player element
|
||||
/* create the mp3player element */
|
||||
GstElement *mp3player = gst_elementfactory_make ("mp3player", "mp3player");
|
||||
// set the source mp3 audio file
|
||||
/* set the source mp3 audio file */
|
||||
g_object_set (G_OBJECT (mp3player), "location", "helloworld.mp3", NULL);
|
||||
// start playback
|
||||
/* start playback */
|
||||
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING);
|
||||
...
|
||||
// pause playback
|
||||
/* pause playback */
|
||||
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED);
|
||||
...
|
||||
// stop
|
||||
/* stop */
|
||||
gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL);
|
||||
</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
|
||||
information about creating custom bin in the Filter-Writers-Guide.
|
||||
information about creating custom bin in the Plugin Writers Guide (FIXME ref).
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="sec-bin-ghostpads">
|
||||
<title>Ghost pads</title>
|
||||
<para>
|
||||
You can see from figure ... how a bin has no pads of its own. This is where Ghostpads
|
||||
come into play.
|
||||
You can see from figure <xref linkend="sec-bin-noghost-img"/> how a bin has no pads of its own.
|
||||
This is where "ghost pads" come into play.
|
||||
</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>
|
||||
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
|
||||
|
@ -181,7 +204,7 @@
|
|||
</mediaobject>
|
||||
</figure>
|
||||
<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.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -192,7 +215,7 @@
|
|||
GstElement *bin;
|
||||
GstElement *element;
|
||||
|
||||
element = gst_elementfactory_create ("mpg123", "decoder");
|
||||
element = gst_elementfactory_create ("mad", "decoder");
|
||||
bin = gst_bin_new ("mybin");
|
||||
|
||||
gst_bin_add (GST_BIN (bin), element);
|
||||
|
@ -210,7 +233,7 @@
|
|||
|
||||
filesrc = gst_elementfactory_create ("filesrc", "disk_reader");
|
||||
|
||||
gst_element_connect (filesrc, "src", bin, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", bin, "sink");
|
||||
...
|
||||
</programlisting>
|
||||
</sect1>
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<para>
|
||||
A more complex case is when the filter modifies the data in place. It
|
||||
does so and simply passes on the buffer to the next element. This is just
|
||||
as easy to deal with. An element that works in place has to be carefull when
|
||||
as easy to deal with. An element that works in place has to be careful when
|
||||
the buffer is used in more than one element; a copy on write has to made in this
|
||||
situation.
|
||||
</para>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<chapter id="cha-components">
|
||||
<title>Components</title>
|
||||
|
||||
<para>
|
||||
FIXME: This chapter is way out of date.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<application>GStreamer</application> includes components that people can include
|
||||
in their programs.
|
||||
|
|
|
@ -45,16 +45,42 @@
|
|||
|
||||
</programlisting>
|
||||
<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:
|
||||
</para>
|
||||
<programlisting>
|
||||
|
||||
// connect them
|
||||
gst_element_connect (element1, "src", element2, "sink");
|
||||
gst_element_connect_pads (element1, "src", element2, "sink");
|
||||
....
|
||||
// and disconnect them
|
||||
gst_element_disconnect (element1, "src", element2, "sink");
|
||||
gst_element_disconnect_pads (element1, "src", element2, "sink");
|
||||
|
||||
</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>
|
||||
<para>
|
||||
|
@ -70,7 +96,7 @@
|
|||
<title>Making filtered connections</title>
|
||||
<para>
|
||||
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>
|
||||
</sect1>
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<chapter id="cha-cothreads">
|
||||
<title>Cothreads</title>
|
||||
<para>
|
||||
Cothreads are user-space threads that greatly reduce context
|
||||
switching overhead introduced by regular kernel threads.
|
||||
Cothreads are also used to handle the more complex elements.
|
||||
Cothreads are user-space threads that greatly reduce context switching overhead introduced by
|
||||
regular kernel threads. Cothreads are also used to handle the more complex elements. They differ
|
||||
from other user-space threading libraries in that they are scheduled explictly by GStreamer.
|
||||
</para>
|
||||
<para>
|
||||
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">
|
||||
<title>Loop-based elements</title>
|
||||
<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:
|
||||
|
||||
<programlisting>
|
||||
|
@ -97,24 +97,24 @@ chain_function (GstPad *pad, GstBuffer *buffer)
|
|||
</para>
|
||||
|
||||
<para>
|
||||
When the request for a buffer cannot immedialty satisfied, the control
|
||||
will be given to the source element of the loop-based element until it
|
||||
performs a push on its source pad. At that time the control is handed back
|
||||
to the loop-based element, etc... The the execution trace can get fairly
|
||||
complex using cothreads when there are multiple input/output pads for the
|
||||
loop-based element.
|
||||
When the request for a buffer cannot immediatly satisfied, the control will be given to the
|
||||
source element of the loop-based element until it performs a push on its source pad. At that
|
||||
time the control is handed back to the loop-based element, etc... The the execution trace can
|
||||
get fairly complex using cothreads when there are multiple input/output pads for the
|
||||
loop-based element. Cothread switches are performed within the call to gst_pad_pull and
|
||||
gst_pad_push; from the perspective of the loop-based element, it just "appears" that
|
||||
gst_pad_push (or _pull) might take a long time to return.
|
||||
</para>
|
||||
<para>
|
||||
Loop based elements are mainly used for the more complex elements that need a
|
||||
specific amount of data before they can start to produce output. An example
|
||||
of such an element is the mpeg video decoder. the element will pull a buffer,
|
||||
performs some decoding on it and optionally requests more buffers to decode, when
|
||||
a complete video frame has been decoded, a buffer is send out.
|
||||
Loop based elements are mainly used for the more complex elements that need a specific amount
|
||||
of data before they can start to produce output. An example of such an element is the mpeg
|
||||
video decoder. the element will pull a buffer, performs some decoding on it and optionally
|
||||
requests more buffers to decode, when a complete video frame has been decoded, a buffer is
|
||||
send out. For example, any plugin using the bytestream library will need to be loop-based.
|
||||
</para>
|
||||
<para>
|
||||
There is no problem in putting cothreaded elements into a
|
||||
<classname>GstThread</classname> to create even more complex pipelines with
|
||||
both user and kernel space threads.
|
||||
There is no problem in putting cothreaded elements into a <classname>GstThread</classname> to
|
||||
create even more complex pipelines with both user and kernel space threads.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
Sets the mask for the info *and* the debug output.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>--gst-mask-help</option>
|
||||
Print out the meaning of gst-mask-* values.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>--gst-plugin-spew</option>
|
||||
|
@ -47,16 +53,15 @@
|
|||
<listitem>
|
||||
<para>
|
||||
<option>--help</option> Print the a short desciption of the
|
||||
options and an overview of the current debugging/info masks
|
||||
set.
|
||||
options
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
The follwing table gives an overview of the mask values and
|
||||
their meaning. (enabled) means that the corresponding flag
|
||||
has been set.
|
||||
The following table gives an overview of the mask values and their meaning. (enabled) means
|
||||
that the corresponding flag is set by default. This table is available to any GStreamer
|
||||
application by the --gst-mask-help option.
|
||||
</para>
|
||||
<programlisting>
|
||||
Mask (to be OR'ed) info/debug FLAGS
|
||||
|
|
|
@ -36,10 +36,10 @@ idle_func (gpointer data)
|
|||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
GstElement *pipeline, *src, *parse;
|
||||
GstElement *pipeline, *src, *demux;
|
||||
struct poptOption *gst_table;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
gnome_init ("MPEG1 Video player","0.0.1", argc, argv);
|
||||
|
||||
pipeline = gst_pipeline_new ("pipeline");
|
||||
g_return_val_if_fail (pipeline != NULL, -1);
|
||||
|
@ -48,20 +48,18 @@ main(int argc, char *argv[])
|
|||
g_return_val_if_fail (src != NULL, -1);
|
||||
g_object_set (G_OBJECT (src), "location", argv[1], NULL);
|
||||
|
||||
parse = gst_elementfactory_make ("mpeg1parse", "parse");
|
||||
g_return_val_if_fail (parse != NULL, -1);
|
||||
demux = gst_elementfactory_make ("mpegdemux", "demux");
|
||||
g_return_val_if_fail (demux != NULL, -1);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (src));
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (parse));
|
||||
gst_bin_add_many (GST_BIN (pipeline), src, demux, NULL);
|
||||
|
||||
g_signal_connect (G_OBJECT (parse), "new_pad",
|
||||
g_signal_connect (G_OBJECT (demux), "new_pad",
|
||||
G_CALLBACK (new_pad_created), pipeline);
|
||||
|
||||
g_signal_connect (G_OBJECT (src), "eos",
|
||||
G_CALLBACK (eof), NULL);
|
||||
|
||||
gst_pad_connect (gst_element_get_pad (src, "src"),
|
||||
gst_element_get_pad (parse, "sink"));
|
||||
gst_element_connect (src, parse);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
||||
|
@ -76,19 +74,18 @@ main(int argc, char *argv[])
|
|||
|
||||
</programlisting>
|
||||
<para>
|
||||
We create two elements: a filesrc (the element that will read the
|
||||
file from disk) and an mpeg1parser. We also add an EOS (End Of Stream)
|
||||
signal to the filesrc so that we will be notified when the file has ended.
|
||||
There's nothing special about this piece of code except for the signal
|
||||
'new_pad' that we connected to the mpeg1parser using:
|
||||
We create two elements: a file source and an MPEG demuxer.. We also add an EOS (End Of Stream)
|
||||
signal to the filesrc so that we will be notified when the file has ended. There's nothing
|
||||
special about this piece of code except for the signal 'new_pad' that we connected to the
|
||||
mpegdemux using:
|
||||
</para>
|
||||
<programlisting>
|
||||
g_signal_connect (G_OBJECT (parse), "new_pad",
|
||||
g_signal_connect (G_OBJECT (demux), "new_pad",
|
||||
G_CALLBACK (new_pad_created), pipeline);
|
||||
</programlisting>
|
||||
<para>
|
||||
When an elementary stream has been detected in the system stream,
|
||||
mpeg1parse will create a new pad that will provide the data of the
|
||||
mpegdemux will create a new pad that will provide the data of the
|
||||
elementary stream. A function 'new_pad_created' will be called when
|
||||
the pad is created:
|
||||
</para>
|
||||
|
@ -96,12 +93,10 @@ main(int argc, char *argv[])
|
|||
void
|
||||
new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline)
|
||||
{
|
||||
GstElement *parse_audio, *parse_video, *decode, *decode_video, *play, *videoscale, *show;
|
||||
GstElement *decode_audio, *parse_video, *decode_video, *play, *videoscale, *show;
|
||||
GstElement *audio_queue, *video_queue;
|
||||
GstElement *audio_thread, *video_thread;
|
||||
|
||||
GtkWidget *appwindow;
|
||||
|
||||
g_print ("***** a new pad %s was created\n", gst_pad_get_name (pad));
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED);
|
||||
|
@ -110,38 +105,28 @@ new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline)
|
|||
if (strncmp (gst_pad_get_name (pad), "audio_", 6) == 0) {
|
||||
|
||||
// construct internal pipeline elements
|
||||
parse_audio = gst_elementfactory_make ("mp3parse", "parse_audio");
|
||||
g_return_if_fail (parse_audio != NULL);
|
||||
decode = gst_elementfactory_make ("mpg123", "decode_audio");
|
||||
decode = gst_elementfactory_make ("mad", "decode_audio");
|
||||
g_return_if_fail (decode != NULL);
|
||||
play = gst_elementfactory_make ("audiosink", "play_audio");
|
||||
play = gst_elementfactory_make ("osssink", "play_audio");
|
||||
g_return_if_fail (play != NULL);
|
||||
|
||||
// create the thread and pack stuff into it
|
||||
audio_thread = gst_thread_new ("audio_thread");
|
||||
g_return_if_fail (audio_thread != NULL);
|
||||
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (parse_audio));
|
||||
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (decode));
|
||||
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (play));
|
||||
gst_bin_add_many (GST_BIN (audio_thread), decode_audio, play, NULL);
|
||||
|
||||
// set up pad connections
|
||||
gst_element_add_ghost_pad (GST_ELEMENT (audio_thread),
|
||||
gst_element_get_pad (parse_audio, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (parse_audio,"src"),
|
||||
gst_element_get_pad (decode,"sink"));
|
||||
gst_pad_connect (gst_element_get_pad (decode,"src"),
|
||||
gst_element_get_pad (play,"sink"));
|
||||
gst_element_get_pad (decode_audio, "sink"));
|
||||
gst_element_connect (decode, play);
|
||||
|
||||
// construct queue and connect everything in the main pipelie
|
||||
audio_queue = gst_elementfactory_make ("queue", "audio_queue");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_queue));
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_thread));
|
||||
gst_bin_add_many (GST_BIN (pipeline), audio_queue, audio_thread, NULL);
|
||||
|
||||
gst_pad_connect (pad,
|
||||
gst_element_get_pad (audio_queue, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (audio_queue, "src"),
|
||||
gst_element_get_pad (audio_thread, "sink"));
|
||||
gst_pad_connect (pad, gst_element_get_pad (audio_queue, "sink"));
|
||||
gst_element_connect (audio_queue, audio_thread);
|
||||
|
||||
// set up thread state and kick things off
|
||||
g_print ("setting to READY state\n");
|
||||
|
@ -151,47 +136,31 @@ new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline)
|
|||
else if (strncmp (gst_pad_get_name (pad), "video_", 6) == 0) {
|
||||
|
||||
// construct internal pipeline elements
|
||||
parse_video = gst_elementfactory_make ("mp1videoparse", "parse_video");
|
||||
g_return_if_fail (parse_video != NULL);
|
||||
decode_video = gst_elementfactory_make ("mpeg_play", "decode_video");
|
||||
decode_video = gst_elementfactory_make ("mpeg2dec", "decode_video");
|
||||
g_return_if_fail (decode_video != NULL);
|
||||
|
||||
show = gst_elementfactory_make ("videosink", "show");
|
||||
show = gst_elementfactory_make ("xvideosink", "show");
|
||||
g_return_if_fail (show != NULL);
|
||||
|
||||
appwindow = gnome_app_new ("MPEG1 player", "MPEG1 player");
|
||||
gnome_app_set_contents (GNOME_APP (appwindow),
|
||||
gst_util_get_widget_arg (GTK_OBJECT (show), "widget"));
|
||||
gtk_widget_show_all (appwindow);
|
||||
|
||||
// create the thread and pack stuff into it
|
||||
video_thread = gst_thread_new ("video_thread");
|
||||
g_return_if_fail (video_thread != NULL);
|
||||
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (parse_video));
|
||||
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (decode_video));
|
||||
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (show));
|
||||
gst_bin_add_many (GST_BIN (video_thread), decode_video, show, NULL);
|
||||
|
||||
// set up pad connections
|
||||
gst_element_add_ghost_pad (GST_ELEMENT (video_thread),
|
||||
gst_element_get_pad (parse_video, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (parse_video, "src"),
|
||||
gst_element_get_pad (decode_video, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (decode_video, "src"),
|
||||
gst_element_get_pad (show, "sink"));
|
||||
gst_element_connect (decode_video, show);
|
||||
|
||||
// construct queue and connect everything in the main pipeline
|
||||
video_queue = gst_elementfactory_make ("queue", "video_queue");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_queue));
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_thread));
|
||||
gst_bin_add_many (GST_BIN (pipeline), video_queue, video_thread);
|
||||
|
||||
gst_pad_connect (pad,
|
||||
gst_element_get_pad (video_queue, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (video_queue, "src"),
|
||||
gst_element_get_pad (video_thread, "sink"));
|
||||
gst_pad_connect (pad, gst_element_get_pad (video_queue, "sink"));
|
||||
gst_element_connect (video_queue, video_thread);
|
||||
|
||||
// set up thread state and kick things off
|
||||
g_object_set (G_OBJECT (video_thread), "create_thread", TRUE, NULL);
|
||||
g_print ("setting to READY state\n");
|
||||
gst_element_set_state (GST_ELEMENT (video_thread), GST_STATE_READY);
|
||||
}
|
||||
|
@ -200,9 +169,8 @@ new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline)
|
|||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
In the above example, we created new elements based on the name of
|
||||
the newly created pad. We added them to a new thread There are other possibilities to check the
|
||||
type of the pad, for example, by using the MIME type and the properties
|
||||
of the pad.
|
||||
In the above example, we created new elements based on the name of the newly created pad. We
|
||||
then added them to a new thread. There are other possibilities to check the type of the pad, for
|
||||
example by using the MIME type and the properties of the pad.
|
||||
</para>
|
||||
</chapter>
|
||||
|
|
|
@ -12,21 +12,16 @@
|
|||
different components you are going to use are derived from this GstElement.
|
||||
This means that a lot of functions you are going to use operate on this object.
|
||||
</para>
|
||||
<para>
|
||||
You will see that those elements have pads. These are the elements
|
||||
connections with the 'outside' world. Depending on the number and direction of
|
||||
the pads, we can see three types of elements: source, filter and sink element.
|
||||
</para>
|
||||
<para>
|
||||
These three types are all the same GstElement object, they just differ in how
|
||||
the pads are.
|
||||
<para> Elements, from the perspective of GStreamer, are viewed as "black boxes" with a number of
|
||||
different aspects. One of these aspects is the presence of "pads", or connection points. This
|
||||
terminology arises from soldering; pads are where wires can be attached.
|
||||
</para>
|
||||
|
||||
<sect2 id="sec-elements-src">
|
||||
<title>GStreamer source elements</title>
|
||||
<title>Source elements</title>
|
||||
<para>
|
||||
This element will generate data that will be used by the pipeline. It is
|
||||
typically a file or an audio source.
|
||||
Source elements generate data for use by a pipeline, for example reading from disk or from a
|
||||
sound card.
|
||||
</para>
|
||||
<para>
|
||||
Below you see how we will visualize the element.
|
||||
|
@ -48,18 +43,16 @@
|
|||
</sect2>
|
||||
|
||||
<sect2 id="sec-elements-filter">
|
||||
<title>GStreamer filter elements</title>
|
||||
<title>Filters and codecs</title>
|
||||
<para>
|
||||
Filter elements both have an input and an output pad. They operate on data
|
||||
they receive in the sink pad and send the result to the src pad.
|
||||
Filter elements both have input and output pads. They operate on data they receive in their
|
||||
sink pads and produce data on their src pads. For example, MPEG decoders and volume filters
|
||||
would fall into this category.
|
||||
</para>
|
||||
<para>
|
||||
Examples of a filter element might include: an MPEG decoder, volume filter,...
|
||||
</para>
|
||||
<para>
|
||||
Filters may also contain any number of input pads and output pads. For example,
|
||||
a video mixer might have to input pads (the images of the two different video
|
||||
streams) and one output pad.
|
||||
Elements are not constrained as to the number of pads they migh have; for example, a video
|
||||
mixer might have two input pads (the images of the two different video streams) and one
|
||||
output pad.
|
||||
</para>
|
||||
<figure float="1" id="sec-element-filterimg">
|
||||
<title>Visualisation of a filter element</title>
|
||||
|
@ -71,7 +64,7 @@
|
|||
</figure>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<figure float="1" id="sec-element-multifilterimg">
|
||||
|
@ -84,20 +77,20 @@
|
|||
</mediaobject>
|
||||
</figure>
|
||||
<para>
|
||||
The above figure shows the visualisation of a filter element with more than one
|
||||
output pad. An example of such a filter is the AVI splitter. This element will
|
||||
parse the input data and extracts the audio and video data. Most of these filters
|
||||
dynamically send out a signal when a new pad is created so that the application
|
||||
programmer can connect an arbitrary element to the newly created pad.
|
||||
The above figure shows the visualisation of a filter element with more than one output pad.
|
||||
An example of such a filter is the AVI splitter (demuxer). This element will parse the input
|
||||
data and extracts the audio and video data. Most of these filters dynamically send out a
|
||||
signal when a new pad is created so that the application programmer can connect an arbitrary
|
||||
element to the newly created pad.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="sec-elements-sink">
|
||||
<title>GStreamer sink elements</title>
|
||||
<title>Sink elements</title>
|
||||
<para>
|
||||
This element accepts data but will not generate any new data. A sink element
|
||||
is typically a file on disk, a soundcard, a display,... It is presented as
|
||||
below:
|
||||
Sink elements are terminal points in a media pipeline. They accept data but do not produce
|
||||
anything. Disk writing, soundcard playback, and video output woul all be implemented by sink
|
||||
elements.
|
||||
</para>
|
||||
<figure float="1" id="sec-element-sinkimg">
|
||||
<title>Visualisation of a sink element</title>
|
||||
|
@ -117,12 +110,12 @@
|
|||
</para>
|
||||
<para>
|
||||
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>
|
||||
<programlisting>
|
||||
GstElementFactory *factory;
|
||||
|
||||
factory = gst_elementfactory_find ("mpg123");
|
||||
factory = gst_elementfactory_find ("mad");
|
||||
</programlisting>
|
||||
<para>
|
||||
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");
|
||||
</programlisting>
|
||||
<para>
|
||||
gst_elementfactory_create () will use the elementfactory to create an element with the
|
||||
given name. The name of the element is something you can use later on to lookup the
|
||||
element in a bin, for example.
|
||||
gst_elementfactory_create () will use the elementfactory to create an element with the given
|
||||
name. The name of the element is something you can use later on to lookup the element in a
|
||||
bin, for example. You can pass NULL as the name argument to get a unique, default name.
|
||||
</para>
|
||||
<para>
|
||||
A simple shortcut exists for creating an element from a factory. The following example
|
||||
creates an element, named "decoder" from the elementfactory named "mpg123". This
|
||||
convenient function is most widly used to create an element.
|
||||
A simple shortcut exists for creating an element from a factory. The following example creates
|
||||
an element, named "decoder" from the elementfactory named "mad". This convenient function is
|
||||
most widely used to create an element.
|
||||
</para>
|
||||
<programlisting>
|
||||
GstElement *element;
|
||||
|
||||
element = gst_elementfactory_make ("mpg123", "decoder");
|
||||
element = gst_elementfactory_make ("mad", "decoder");
|
||||
</programlisting>
|
||||
<para>
|
||||
An element can be destroyed with:
|
||||
An element can be destroyed with: FIXME talk about refcounting
|
||||
</para>
|
||||
<programlisting>
|
||||
GstElement *element;
|
||||
|
|
|
@ -21,16 +21,15 @@
|
|||
<programlisting>
|
||||
...
|
||||
/* now it's time to get the parser */
|
||||
parse = gst_elementfactory_make ("mp3parse", "parse");
|
||||
decoder = gst_elementfactory_make ("mpg123", "decoder");
|
||||
decoder = gst_elementfactory_make ("mad", "decoder");
|
||||
...
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
While this mechanism is quite effective it also has some big problems:
|
||||
The elements are created based on their name. Indeed, we create an
|
||||
element mpg123 by explicitly stating the mpg123 elements name.
|
||||
Our little program therefore always uses the mpg123 decoder element
|
||||
element mad by explicitly stating the mad element's name.
|
||||
Our little program therefore always uses the mad decoder element
|
||||
to decode the MP3 audio stream, even if there are 3 other MP3 decoders
|
||||
in the system. We will see how we can use a more general way to create
|
||||
an MP3 decoder element.
|
||||
|
@ -42,7 +41,7 @@
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>more on MIME Types</title>
|
||||
<title>More on MIME Types</title>
|
||||
<para>
|
||||
GStreamer uses MIME types to indentify the different types of data
|
||||
that can be handled by the elements. They are the high level
|
||||
|
@ -125,8 +124,8 @@
|
|||
the given MIME type.
|
||||
</para>
|
||||
<para>
|
||||
There is also an association between a MIME type and a file
|
||||
extension.
|
||||
There is also an association between a MIME type and a file extension, but the use of typefind
|
||||
functions (similar to file(1)) is preferred..
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>id to <classname>GstElementFactory</classname> conversion</title>
|
||||
<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.
|
||||
For more information, see <xref linkend="cha-autoplug"/>.
|
||||
</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>
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
<sect2 id="sec-goals-object">
|
||||
<title>Object oriented</title>
|
||||
<para>
|
||||
Adhere as much as possible to the glib2.0 object model. A programmer familiar
|
||||
with glib2 and GTK+ will be confortable with GStreamer.
|
||||
Adhere to the GLib 2.0 object model. A programmer familiar with GLib 2.0 or older versions
|
||||
of Gtk+ will be comfortable with GStreamer.
|
||||
</para>
|
||||
<para>
|
||||
GStreamer uses the mechanism of signals and object arguments.
|
||||
GStreamer uses the mechanism of signals and object properties.
|
||||
</para>
|
||||
<para>
|
||||
All objects can be queried at runtime for their various properties and
|
||||
|
@ -53,7 +53,7 @@
|
|||
<sect2 id="sec-goals-extensible">
|
||||
<title>Extensible</title>
|
||||
<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>
|
||||
All plugins are loaded dynamically and can be extended and upgraded
|
||||
|
@ -64,14 +64,13 @@
|
|||
<sect2 id="sec-goals-binary">
|
||||
<title>Allow binary only plugins</title>
|
||||
<para>
|
||||
plugins are shared libraries that are loaded at runtime. since all the
|
||||
properties of the plugin can be set using the GObject properties, there
|
||||
is no need to have any header files installed for the plugins.
|
||||
Plugins are shared libraries that are loaded at runtime. Since all the properties of the
|
||||
plugin can be set using the GObject properties, there is no need (and in fact no way) to
|
||||
have any header files installed for the plugins.
|
||||
</para>
|
||||
<para>
|
||||
Special care has been taking into making the plugin completely self
|
||||
contained. This is in the operations, specification of the capabilities
|
||||
of the plugin and properties.
|
||||
contained. All relevant aspects of plugins can be queried at run-time.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
|
@ -83,44 +82,43 @@
|
|||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Using glib g_mem_chunk where possible to minimize dynamic memory
|
||||
Using GLib g_mem_chunk where possible to minimize dynamic memory
|
||||
allocation.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<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.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Provide a mechanism to directly work on the target memory. A
|
||||
plugin can for example directly write to the X servers shared mem.
|
||||
Buffers can also point to arbitrary memory like kernel memory.
|
||||
Providing a mechanism to directly work on the target memory. A plugin can for example
|
||||
directly write to the X server's shared memory space. Buffers can also point to
|
||||
arbitrary memory, such as a sound card's internal hardware buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Refcounting and copy on write to minimize the amount of memcpy.
|
||||
Subbufers to efficiently split the data in a buffer.
|
||||
Refcounting and copy on write minimize usage of memcpy(3).
|
||||
Sub-buffers efficiently split buffers into manageable pieces.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Pipelines can be constructed using cothreads to minimize the
|
||||
threading overhead. Cothreads are a simple user-space method for
|
||||
switching between subtasks.
|
||||
The use of cothreads to minimize the threading overhead. Cothreads are a simple and fast
|
||||
user-space method for switching between subtasks.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HW acceleration is possible by writing a specialized plugin.
|
||||
Allowing HW acceleration by the use of specialized plugins.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<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
|
||||
used.
|
||||
</para>
|
||||
|
|
|
@ -61,6 +61,15 @@
|
|||
</para>
|
||||
</authorblurb>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Andy</firstname>
|
||||
<surname>Wingo</surname>
|
||||
<authorblurb>
|
||||
<para>
|
||||
<email>wingo@pobox.com</email>
|
||||
</para>
|
||||
</authorblurb>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<legalnotice id="legalnotice">
|
||||
|
@ -82,14 +91,13 @@
|
|||
<part id="overview"><title>Overview</title>
|
||||
<partintro>
|
||||
<para>
|
||||
The first chapter of the book gives you an overview of <application>GStreamer</application>
|
||||
design goals. Chapter 2 rapidly covers the basics of <application>GStreamer</application>
|
||||
programming. In chapter 3 we will move on to the examples.
|
||||
Since <application>GStreamer</application> adheres to the GTK+/glib2 programming model, the reader is
|
||||
assumed to understand the basics of GTK+ and the glib2.0 object model.
|
||||
For a gentle introduction to GTK+, you may wish to read the <emphasis>GTK+
|
||||
Tutorial</emphasis> or Eric Harlow's book <emphasis>Developing Linux
|
||||
Applications with GTK+ and GDK</emphasis>.
|
||||
<xref linkend="overview"/> gives you an overview of <application>GStreamer</application>
|
||||
design goals. <xref linkend="basic-concepts"/> rapidly covers the basics of
|
||||
<application>GStreamer</application> programming. In <xref linkend="build-app"/> we will move
|
||||
on to the examples. Since <application>GStreamer</application> uses GLib 2.0, the reader is
|
||||
assumed to understand the basics of the GObject object model. For a gentle introduction to
|
||||
this system, you may wish to read the <emphasis>GTK+ Tutorial</emphasis> or Eric Harlow's
|
||||
book <emphasis>Developing Linux Applications with GTK+ and GDK</emphasis>.
|
||||
</para>
|
||||
</partintro>
|
||||
|
||||
|
@ -186,8 +194,6 @@
|
|||
&HELLOWORLD2;
|
||||
|
||||
&DPARAMS;
|
||||
|
||||
&UTILITY;
|
||||
</part>
|
||||
|
||||
<!-- ############ XML in GStreamer - part ############# -->
|
||||
|
@ -196,9 +202,9 @@
|
|||
|
||||
<partintro>
|
||||
<para>
|
||||
<application>GStreamer</application> has the posibility to externalize the pipelines
|
||||
you create using an XML format. You can load a previously
|
||||
created pipeline by loading the XML file.
|
||||
<application>GStreamer</application> has the possibility to serialize the pipelines you
|
||||
create using an XML format. You can load a previously created pipeline by loading the XML
|
||||
file.
|
||||
</para>
|
||||
</partintro>
|
||||
|
||||
|
|
|
@ -9,12 +9,11 @@
|
|||
<sect1>
|
||||
<title>Hello world</title>
|
||||
<para>
|
||||
We will create a simple first application. In fact it will be a complete
|
||||
MP3 player, using standard <application>GStreamer</application> components. The player will read from
|
||||
a file that is given as the first argument of the program.
|
||||
We will create a simple first application, a complete MP3 player, using standard
|
||||
<application>GStreamer</application> components. The player will read from a file that is
|
||||
given as the first argument of the program.
|
||||
</para>
|
||||
|
||||
|
||||
<programlisting>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
@ -45,15 +44,10 @@ main (int argc, char *argv[])
|
|||
audiosink = gst_elementfactory_make ("osssink", "play_audio");
|
||||
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add (GST_BIN (pipeline), filesrc);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (pipeline), audiosink);
|
||||
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
|
||||
|
||||
/* connect src to sink */
|
||||
gst_pad_connect (gst_element_get_pad (filesrc, "src"),
|
||||
gst_element_get_pad (decoder, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (decoder, "src"),
|
||||
gst_element_get_pad (audiosink, "sink"));
|
||||
gst_element_connect_many (filesrc, decoder, audiosink, NULL);
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
@ -64,10 +58,8 @@ main (int argc, char *argv[])
|
|||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
/* we don't need a reference to these objects anymore */
|
||||
gst_object_unref (GST_OBJECT (audiosink));
|
||||
gst_object_unref (GST_OBJECT (decoder));
|
||||
gst_object_unref (GST_OBJECT (filesrc));
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
/* unreffing the pipeline unrefs the contained elements as well */
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
@ -98,8 +90,8 @@ main (int argc, char *argv[])
|
|||
</programlisting>
|
||||
|
||||
<para>
|
||||
We are going to create 3 elements and one pipeline. Since all objects are
|
||||
in fact elements, we can define them as:
|
||||
We are going to create 3 elements and one pipeline. Since all elements share the same base
|
||||
type, <classname>GstElement</classname>, we can define them as:
|
||||
</para>
|
||||
<programlisting>
|
||||
...
|
||||
|
@ -142,7 +134,7 @@ main (int argc, char *argv[])
|
|||
is installed on the system where this application is executed.
|
||||
</para>
|
||||
<programlisting>
|
||||
/* now it's time to get the parser */
|
||||
/* now it's time to get the decoder */
|
||||
decoder = gst_elementfactory_make ("mad", "decoder");
|
||||
</programlisting>
|
||||
<para>
|
||||
|
@ -167,9 +159,7 @@ main (int argc, char *argv[])
|
|||
</para>
|
||||
<programlisting>
|
||||
/* add objects to the main pipeline */
|
||||
gst_bin_add (GST_BIN (pipeline), filesrc);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (pipeline), audiosink);
|
||||
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -177,10 +167,7 @@ main (int argc, char *argv[])
|
|||
</para>
|
||||
<programlisting>
|
||||
/* connect src to sink */
|
||||
gst_pad_connect (gst_element_get_pad (filesrc, "src"),
|
||||
gst_element_get_pad (decoder, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (decoder, "src"),
|
||||
gst_element_get_pad (audiosink, "sink"));
|
||||
gst_element_connect_many (filesrc, decoder, audiosink, NULL);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -229,16 +216,13 @@ main (int argc, char *argv[])
|
|||
/* stop the pipeline */
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
gst_object_unref (GST_OBJECT (audiosink));
|
||||
gst_object_unref (GST_OBJECT (decoder));
|
||||
gst_object_unref (GST_OBJECT (filesrc));
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
exit (0);
|
||||
</programlisting>
|
||||
<note>
|
||||
<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.
|
||||
</para>
|
||||
</note>
|
||||
|
@ -246,7 +230,7 @@ main (int argc, char *argv[])
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>compiling helloworld.c</title>
|
||||
<title>Compiling helloworld.c</title>
|
||||
<para>
|
||||
To compile the helloworld example, use:
|
||||
</para>
|
||||
|
@ -268,10 +252,10 @@ main (int argc, char *argv[])
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>conclusion</title>
|
||||
<title>Conclusion</title>
|
||||
<para>
|
||||
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.
|
||||
</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.
|
||||
It should also be clear that inserting filters, like a stereo effect,
|
||||
into the pipeline is not that hard to do. The most important thing is
|
||||
that you can reuse allready existing elements.
|
||||
that you can reuse already existing elements.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<chapter id="cha-hello2">
|
||||
<title>Your second application</title>
|
||||
<para>
|
||||
In a previous chapter we created a first version of the helloworld
|
||||
application. We then explained a better way of creating the elements
|
||||
FIXME: delete this section, talk more about the spider. In a previous chapter we created a first
|
||||
version of the helloworld application. We then explained a better way of creating the elements
|
||||
using factories identified by MIME types and the autoplugger.
|
||||
</para>
|
||||
|
||||
|
@ -35,7 +35,7 @@ main (int argc, char *argv[])
|
|||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<chapter id="cha-components">
|
||||
<title>Components</title>
|
||||
|
||||
<para>
|
||||
FIXME: This chapter is way out of date.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<application>GStreamer</application> includes components that people can include
|
||||
in their programs.
|
||||
|
|
|
@ -34,5 +34,29 @@ main (int argc, char *argv[])
|
|||
Use the GST_VERSION_MAJOR, GST_VERSION_MINOR and GST_VERSION_MICRO macros to
|
||||
get the <application>GStreamer</application> version you are building against.
|
||||
</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, &silent, 0,
|
||||
"do not output status information", NULL},
|
||||
{"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0,
|
||||
"save xml representation of pipeline to FILE and exit", "FILE"},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
|
||||
...
|
||||
</programlisting>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
</para>
|
||||
<para>
|
||||
No provisions have been made for emerging technologies such as
|
||||
the GNOME object embedding using BONOBO.
|
||||
the GNOME object embedding using Bonobo.
|
||||
</para>
|
||||
<para>
|
||||
While the GStreamer core does not use network transparent technologies
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
<para>
|
||||
GStreamer, however, is much more than just another media player. Its
|
||||
main advantages are that the pluggable components also make it possible
|
||||
to write a full flegded video or audio editing application.
|
||||
to write a full fledged video or audio editing application.
|
||||
</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
|
||||
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
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
<para>
|
||||
GStreamer, however, is much more than just another media player. Its
|
||||
main advantages are that the pluggable components also make it possible
|
||||
to write a full flegded video or audio editing application.
|
||||
to write a full fledged video or audio editing application.
|
||||
</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
|
||||
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
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
</para>
|
||||
<para>
|
||||
No provisions have been made for emerging technologies such as
|
||||
the GNOME object embedding using BONOBO.
|
||||
the GNOME object embedding using Bonobo.
|
||||
</para>
|
||||
<para>
|
||||
While the GStreamer core does not use network transparent technologies
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<chapter id="cha-pads">
|
||||
<title>GstPad</title>
|
||||
<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.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -44,7 +44,7 @@
|
|||
<title>Useful pad functions</title>
|
||||
<para>
|
||||
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>
|
||||
gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink
|
||||
|
@ -53,8 +53,8 @@
|
|||
</para>
|
||||
<para>
|
||||
You can get the parent of the pad, this is the element that this pad belongs to,
|
||||
with get_pad_set_parent(GstPad *pad). This function will return a pointer to a
|
||||
GstObject.
|
||||
with get_pad_get_parent(GstPad *pad). This function will return a pointer to a
|
||||
GstElement.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="sec-pads-dynamic">
|
||||
|
@ -66,7 +66,7 @@
|
|||
system stream.
|
||||
</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
|
||||
"dormant" as you can see in the padtemplates from the 'Exists: Sometimes'
|
||||
property. Depending on the type of MPEG2 file you play, the pads are created. We
|
||||
|
@ -104,7 +104,7 @@ main(int argc, char *argv[])
|
|||
// create pipeline and do something usefull
|
||||
...
|
||||
|
||||
mpeg2parser = gst_elementfactory_make ("mpeg2parse", "mpeg2parse");
|
||||
mpeg2parser = gst_elementfactory_make ("mpegdemux", "mpegdemux");
|
||||
g_signal_connect (G_OBJECT (mpeg2parser), "new_pad", pad_connect_func, pipeline);
|
||||
...
|
||||
|
||||
|
@ -141,19 +141,19 @@ main(int argc, char *argv[])
|
|||
...
|
||||
element = gst_elementfactory_make ("tee", "element");
|
||||
|
||||
pad = gst_element_request_pad_by_name (element, "src%d");
|
||||
pad = gst_element_get_request_pad (element, "src%d");
|
||||
g_print ("new pad %s\n", gst_pad_get_name (pad));
|
||||
...
|
||||
</programlisting>
|
||||
<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.
|
||||
</para>
|
||||
<para>
|
||||
It is also possible to request a pad that is compatible with another
|
||||
padtemplate. This is very usefull if you want to connect an element to
|
||||
a muxer element and you need to request a pad that is compatible. The
|
||||
gst_element_request_compatible_pad is used to request a compatible pad, as
|
||||
gst_element_get_compatible_pad is used to request a compatible pad, as
|
||||
is shown in the next example.
|
||||
</para>
|
||||
<programlisting>
|
||||
|
@ -162,11 +162,11 @@ main(int argc, char *argv[])
|
|||
GstPad *pad;
|
||||
...
|
||||
element = gst_elementfactory_make ("tee", "element");
|
||||
mp3parse = gst_elementfactory_make ("mp3parse", "mp3parse");
|
||||
mad = gst_elementfactory_make ("mad", "mad");
|
||||
|
||||
templ = gst_element_get_padtemplate_by_name (mp3parse, "sink");
|
||||
templ = gst_element_get_padtemplate_by_name (mad, "sink");
|
||||
|
||||
pad = gst_element_request_compatible_pad (element, templ);
|
||||
pad = gst_element_get_compatible_pad (element, templ);
|
||||
g_print ("new pad %s\n", gst_pad_get_name (pad));
|
||||
...
|
||||
</programlisting>
|
||||
|
@ -181,7 +181,7 @@ main(int argc, char *argv[])
|
|||
<para>
|
||||
We will briefly describe what capabilities are, enough for you to get a basic understanding
|
||||
of the concepts. You will find more information on how to create capabilities in the
|
||||
filter-writer-guide.
|
||||
Plugin Writer's Guide.
|
||||
</para>
|
||||
|
||||
<sect2 id="sec-pads-caps">
|
||||
|
@ -207,8 +207,8 @@ struct _GstCaps {
|
|||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
Below is a dump of the capabilities of the element mpg123, as shown by
|
||||
<command>gstreamer-inspect</command>.
|
||||
Below is a dump of the capabilities of the element mad, as shown by
|
||||
<command>gst-inspect</command>.
|
||||
You can see two pads: sink and src. Both pads have capability information attached to them.
|
||||
</para>
|
||||
<para>
|
||||
|
@ -221,26 +221,25 @@ struct _GstCaps {
|
|||
</para>
|
||||
<programlisting>
|
||||
Pads:
|
||||
SINK: 'sink'
|
||||
....
|
||||
SINK template: 'sink'
|
||||
Availability: Always
|
||||
Capabilities:
|
||||
'mpg123_sink':
|
||||
'mad_sink':
|
||||
MIME type: 'audio/mp3':
|
||||
layer: Integer range: 1 - 3
|
||||
bitrate: Integer range: 8 - 320
|
||||
framed: Boolean: TRUE
|
||||
|
||||
SRC: 'src'
|
||||
....
|
||||
SRC template: 'src'
|
||||
Availability: Always
|
||||
Capabilities:
|
||||
'mpg123_src':
|
||||
'mad_src':
|
||||
MIME type: 'audio/raw':
|
||||
format: Integer: 16
|
||||
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
|
||||
channels: List:
|
||||
Integer: 1
|
||||
Integer: 2
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="sec-pads-props">
|
||||
|
@ -260,7 +259,7 @@ Pads:
|
|||
<listitem>
|
||||
<para>
|
||||
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>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@ -349,7 +348,7 @@ Pads:
|
|||
</para>
|
||||
<para>
|
||||
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>
|
||||
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
|
||||
</programlisting>
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
one or more autopluggers
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
exported symbols for use in other plugins
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The plugins have one simple method: plugin_init () where all the elementfactories are
|
||||
|
|
|
@ -4,38 +4,35 @@
|
|||
</para>
|
||||
|
||||
<sect1>
|
||||
<title><command>gstreamer-register</command></title>
|
||||
<title><command>gst-register</command></title>
|
||||
<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
|
||||
can be found in <filename>/etc/gstreamer/reg.xml</filename>.
|
||||
can be found, by default, in <filename>/etc/gstreamer/reg.xml</filename>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title><command>gstreamer-launch</command></title>
|
||||
<title><command>gst-launch</command></title>
|
||||
<para>
|
||||
This is a tool that will construct pipelines based on a command-line
|
||||
syntax.
|
||||
syntax. FIXME: need a more extensive grammar reference
|
||||
</para>
|
||||
<para>
|
||||
A simple commandline looks like:
|
||||
|
||||
<screen>
|
||||
gstreamer-launch filesrc location=hello.mp3 ! mp3parse ! mpg123 ! audiosink
|
||||
gst-launch filesrc location=hello.mp3 ! mad ! osssink
|
||||
</screen>
|
||||
|
||||
A more complex pipeline looks like:
|
||||
|
||||
<screen>
|
||||
gstreamer-launch filesrc redpill.vob audio_00! (ac3parse ! ac3dec ! audiosink) \
|
||||
video_00! (mpeg2dec ! videosink)
|
||||
gst-launch filesrc location=redpill.vob ! mpegdemux name=demux \
|
||||
demux.audio_00! { ac3parse ! a52dec ! osssink } \
|
||||
demux.video_00! { mpeg2dec ! xvideosink }
|
||||
</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>
|
||||
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 *filesrc;
|
||||
GError *error = NULL;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
pipeline = gst_pipeline_new ("my_pipeline");
|
||||
|
||||
gst_parse_launch ("filesrc[my_filesrc] ! mp3parse ! mpg123 ! osssink", GST_BIN (pipeline));
|
||||
pipeline = gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error);
|
||||
if (!pipeline) {
|
||||
g_print ("Parse error: %s\n", error->message);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
@ -81,20 +82,20 @@ main (int argc, char *argv[])
|
|||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title><command>gstreamer-inspect</command></title>
|
||||
<title><command>gst-inspect</command></title>
|
||||
<para>
|
||||
This is a tool to query a plugin or an element about its properties.
|
||||
</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>
|
||||
|
||||
<screen>
|
||||
gstreamer-inspect mpg123
|
||||
gst-inspect mad
|
||||
</screen>
|
||||
|
||||
<para>
|
||||
Below is the output of a query for the audiosink element:
|
||||
Below is the output of a query for the osssink element:
|
||||
</para>
|
||||
|
||||
<screen>
|
||||
|
@ -102,56 +103,72 @@ Factory Details:
|
|||
Long name: Audio Sink (OSS)
|
||||
Class: Sink/Audio
|
||||
Description: Output to a sound card via OSS
|
||||
Version: 0.1.0
|
||||
Author(s): Erik Walthinsen <omega@cse.ogi.edu>
|
||||
Version: 0.3.3.1
|
||||
Author(s): Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim.taymans@chello.be>
|
||||
Copyright: (C) 1999
|
||||
|
||||
GObject
|
||||
+----GstObject
|
||||
+----GstElement
|
||||
+----GstOssSink
|
||||
|
||||
Pad Templates:
|
||||
SINK template: 'sink'
|
||||
Exists: Always
|
||||
Availability: Always
|
||||
Capabilities:
|
||||
'audiosink_sink':
|
||||
'osssink_sink':
|
||||
MIME type: 'audio/raw':
|
||||
format: Integer: 16
|
||||
format: String: int
|
||||
endianness: Integer: 1234
|
||||
width: List:
|
||||
Integer: 8
|
||||
Integer: 16
|
||||
depth: List:
|
||||
Integer: 8
|
||||
Integer: 16
|
||||
rate: Integer range: 8000 - 48000
|
||||
channels: Integer range: 1 - 2
|
||||
law: Integer: 0
|
||||
signed: List:
|
||||
Boolean: FALSE
|
||||
Boolean: TRUE
|
||||
rate: Integer range: 1000 - 48000
|
||||
|
||||
|
||||
Element Flags:
|
||||
GST_ELEMENT_THREADSUGGESTED
|
||||
no flags set
|
||||
|
||||
Element Implementation:
|
||||
No loopfunc(), must be chain-based or not configured yet
|
||||
Has change_state() function
|
||||
Has change_state() function: gst_osssink_change_state
|
||||
Has custom save_thyself() function: gst_element_save_thyself
|
||||
Has custom restore_thyself() function: gst_element_restore_thyself
|
||||
|
||||
Clocking Interaction:
|
||||
element requires a clock
|
||||
element provides a clock: GstOssClock
|
||||
|
||||
Pads:
|
||||
SINK: 'sink'
|
||||
Implementation:
|
||||
Has chainfunc(): 0x4001cde8
|
||||
Has default eosfunc() gst_pad_eos_func()
|
||||
Has chainfunc(): 0x40056fc0
|
||||
Pad Template: 'sink'
|
||||
Capabilities:
|
||||
'audiosink_sink':
|
||||
MIME type: 'audio/raw':
|
||||
format: Integer: 16
|
||||
depth: List:
|
||||
Integer: 8
|
||||
Integer: 16
|
||||
rate: Integer range: 8000 - 48000
|
||||
channels: Integer range: 1 - 2
|
||||
|
||||
Element Arguments:
|
||||
GstAudioSink::mute: Boolean
|
||||
GstAudioSink::format: Enum (default 16)
|
||||
(8): 8 Bits
|
||||
(16): 16 Bits
|
||||
GstAudioSink::channels: Enum (default 2)
|
||||
name : String (Default "element")
|
||||
device : String (Default "/dev/dsp")
|
||||
mute : Boolean (Default false)
|
||||
format : Integer (Default 16)
|
||||
channels : Enum "GstAudiosinkChannels" (default 1)
|
||||
(0): Silence
|
||||
(1): Mono
|
||||
(2): Stereo
|
||||
GstAudioSink::frequency: Integer
|
||||
frequency : Integer (Default 11025)
|
||||
fragment : Integer (Default 6)
|
||||
buffer-size : Integer (Default 4096)
|
||||
|
||||
Element Signals:
|
||||
"handoff" : void user_function (GstOssSink* object,
|
||||
gpointer user_data);
|
||||
</screen>
|
||||
|
||||
<para>
|
||||
|
@ -159,11 +176,11 @@ Element Arguments:
|
|||
</para>
|
||||
|
||||
<screen>
|
||||
gstreamer-inspect gstelements
|
||||
gst-inspect gstelements
|
||||
</screen>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title><command>gstmediaplay</command></title>
|
||||
<title><command>gst-play</command></title>
|
||||
<para>
|
||||
A sample media player.
|
||||
</para>
|
||||
|
|
|
@ -146,7 +146,7 @@
|
|||
</note>
|
||||
<para>
|
||||
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>
|
||||
</sect1>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<chapter id="cha-threads">
|
||||
<title>Threads</title>
|
||||
<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
|
||||
a special <classname>GstBin</classname> that will become a thread when started.
|
||||
</para>
|
||||
|
@ -13,39 +13,58 @@
|
|||
<programlisting>
|
||||
GstElement *my_thread;
|
||||
|
||||
// create the thread object
|
||||
/* create the thread object */
|
||||
my_thread = gst_thread_new ("my_thread");
|
||||
g_return_if_fail (audio_thread != NULL);
|
||||
/* you could have used gst_elementfactory_make ("thread", "my_thread"); */
|
||||
g_return_if_fail (my_thread != NULL);
|
||||
|
||||
// add some plugins
|
||||
/* add some plugins */
|
||||
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (funky_src));
|
||||
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect));
|
||||
|
||||
// connect the elements here...
|
||||
/* connect the elements here... */
|
||||
...
|
||||
|
||||
// start playing
|
||||
/* start playing */
|
||||
gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING);
|
||||
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
The above program will create a thread with two elements in it. As soon
|
||||
as it is set to the PLAYING state, the thread will start to iterate.
|
||||
The above program will create a thread with two elements in it. As soon as it is set to the
|
||||
PLAYING state, the thread will start to iterate itself. You never need to manually iterate a
|
||||
thread.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<sect2>
|
||||
<title>Constraints placed on the pipeline by the GstThread</title>
|
||||
<para>
|
||||
A thread should normally contain a source element. Most often, the thread
|
||||
is fed with data from a queue.
|
||||
Within the pipeline, everything is the same as in any other bin. The difference lies at the
|
||||
thread boundary, at the connection between the thread and the outside world (containing bin).
|
||||
Since GStreamer is fundamentally buffer-oriented rather than byte-oriented, the natural
|
||||
solution to this problem is an element that can "buffer" the buffers between the threads, in a
|
||||
thread-safe fashion. This element is the queue, described more fully in <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>
|
||||
</note>
|
||||
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>When would you want to use a thread?</title>
|
||||
<para>
|
||||
A thread will be visualised as below
|
||||
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>
|
||||
A thread can be visualised as below
|
||||
</para>
|
||||
<figure float="1" id="sec-threads-img">
|
||||
<title>a thread</title>
|
||||
<title>A thread</title>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/thread.&magic;" format="&magic;" />
|
||||
|
|
|
@ -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, &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>
|
|
@ -19,7 +19,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
|
||||
/* disconnect the typefind from the pipeline and remove it */
|
||||
gst_element_disconnect (cache, "src", typefind, "sink");
|
||||
gst_element_disconnect_pads (cache, "src", typefind, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), typefind);
|
||||
|
||||
/* and an audio sink */
|
||||
|
@ -34,7 +34,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
colorspace = gst_elementfactory_make ("colorspace", "colorspace");
|
||||
g_assert (colorspace != NULL);
|
||||
|
||||
gst_element_connect (colorspace, "src", videoelement, "sink");
|
||||
gst_element_connect_pads (colorspace, "src", videoelement, "sink");
|
||||
gst_bin_add (GST_BIN (videosink), colorspace);
|
||||
gst_bin_add (GST_BIN (videosink), videoelement);
|
||||
|
||||
|
@ -61,7 +61,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
|
||||
g_object_set (G_OBJECT (cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect (cache, "src", new_element, "sink");
|
||||
gst_element_connect_pads (cache, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
|
@ -87,10 +87,9 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline)
|
|||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
|
||||
|
||||
gst_element_disconnect (filesrc, "src", cache, "sink");
|
||||
gst_element_disconnect (cache, "src", new_element, "sink");
|
||||
gst_element_disconnect_many (filesrc, cache, new_element, NULL);
|
||||
gst_bin_remove (GST_BIN (autobin), cache);
|
||||
gst_element_connect (filesrc, "src", new_element, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
|
@ -132,11 +131,11 @@ int main(int argc,char *argv[])
|
|||
gst_bin_add (GST_BIN (autobin), cache);
|
||||
gst_bin_add (GST_BIN (autobin), typefind);
|
||||
|
||||
gst_element_connect (cache, "src", typefind, "sink");
|
||||
gst_element_connect_pads (cache, "src", typefind, "sink");
|
||||
gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
|
||||
|
||||
gst_bin_add (GST_BIN( pipeline), autobin);
|
||||
gst_element_connect (filesrc, "src", autobin, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", autobin, "sink");
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
|
|
@ -22,7 +22,7 @@ int main (int argc, char *argv[])
|
|||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
||||
/* now it's time to get the decoder */
|
||||
decoder = gst_elementfactory_make ("mad", "parse");
|
||||
decoder = gst_elementfactory_make ("mad", "decode");
|
||||
if (!decoder) {
|
||||
g_print ("could not find plugin \"mad\"");
|
||||
return -1;
|
||||
|
@ -35,7 +35,7 @@ int main (int argc, char *argv[])
|
|||
gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL);
|
||||
|
||||
/* connect the elements */
|
||||
gst_element_connect_elements_many (filesrc, decoder, osssink, NULL);
|
||||
gst_element_connect_many (filesrc, decoder, osssink, NULL);
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state (bin, GST_STATE_PLAYING);
|
||||
|
|
|
@ -18,8 +18,8 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
|
||||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
|
||||
/* disconnect the typefind from the pipeline and remove it */
|
||||
gst_element_disconnect (cache, "src", typefind, "sink");
|
||||
/* disconnect_pads the typefind from the pipeline and remove it */
|
||||
gst_element_disconnect_pads (cache, "src", typefind, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), typefind);
|
||||
|
||||
/* and an audio sink */
|
||||
|
@ -45,7 +45,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
|
||||
g_object_set (G_OBJECT (cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect (cache, "src", new_element, "sink");
|
||||
gst_element_connect_pads (cache, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
}
|
||||
|
@ -67,10 +67,10 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline)
|
|||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
|
||||
|
||||
gst_element_disconnect (filesrc, "src", cache, "sink");
|
||||
gst_element_disconnect (cache, "src", new_element, "sink");
|
||||
gst_element_disconnect_pads (filesrc, "src", cache, "sink");
|
||||
gst_element_disconnect_pads (cache, "src", new_element, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), cache);
|
||||
gst_element_connect (filesrc, "src", new_element, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
|
@ -114,11 +114,11 @@ main (int argc, char *argv[])
|
|||
gst_bin_add (GST_BIN (autobin), cache);
|
||||
gst_bin_add (GST_BIN (autobin), typefind);
|
||||
|
||||
gst_element_connect (cache, "src", typefind, "sink");
|
||||
gst_element_connect_pads (cache, "src", typefind, "sink");
|
||||
gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
|
||||
|
||||
gst_bin_add (GST_BIN( pipeline), autobin);
|
||||
gst_element_connect (filesrc, "src", autobin, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", autobin, "sink");
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
|
|
@ -5,6 +5,7 @@ main (int argc, char *argv[])
|
|||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *filesrc;
|
||||
GError *error = NULL;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
|
@ -13,7 +14,11 @@ main (int argc, char *argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
pipeline = (GstElement*) gst_parse_launch ("filesrc [ my_filesrc ] ! mad ! osssink");
|
||||
pipeline = (GstElement*) gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error);
|
||||
if (!pipeline) {
|
||||
fprintf (stderr, "Parse error: %s", error->message);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
|
|
@ -40,7 +40,7 @@ void eos(GstElement *element)
|
|||
/* playing = FALSE; */
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
G_GNUC_UNUSED static GstCaps*
|
||||
gst_play_typefind (GstBin *bin, GstElement *element)
|
||||
{
|
||||
GstElement *typefind;
|
||||
|
@ -140,7 +140,7 @@ int main(int argc,char *argv[])
|
|||
|
||||
/* request pads and connect to adder */
|
||||
GST_INFO (0, "requesting pad\n");
|
||||
pad = gst_element_request_pad_by_name (adder, "sink%d");
|
||||
pad = gst_element_get_request_pad (adder, "sink%d");
|
||||
printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
|
||||
sprintf (buffer, "channel%d", i);
|
||||
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
|
||||
|
@ -237,8 +237,8 @@ create_input_channel (int id, char* location)
|
|||
|
||||
char buffer[20]; /* hold the names */
|
||||
|
||||
GstAutoplug *autoplug;
|
||||
GstCaps *srccaps;
|
||||
/* GstAutoplug *autoplug;
|
||||
GstCaps *srccaps; */
|
||||
GstElement *new_element;
|
||||
GstElement *decoder;
|
||||
|
||||
|
@ -364,8 +364,8 @@ create_input_channel (int id, char* location)
|
|||
gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
|
||||
gst_bin_add (GST_BIN (channel->pipe), new_element);
|
||||
|
||||
gst_element_connect (channel->filesrc, "src", new_element, "sink");
|
||||
gst_element_connect (new_element, "src_00", channel->volenv, "sink");
|
||||
gst_element_connect_pads (channel->filesrc, "src", new_element, "sink");
|
||||
gst_element_connect_pads (new_element, "src_00", channel->volenv, "sink");
|
||||
|
||||
/* add a ghost pad */
|
||||
sprintf (buffer, "channel%d", id);
|
||||
|
|
|
@ -19,7 +19,7 @@ object_saved (GstObject *object, xmlNodePtr parent, gpointer data)
|
|||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
GstElement *filesrc, *osssink, *queue, *queue2, *parse, *decode;
|
||||
GstElement *filesrc, *osssink, *queue, *queue2, *decode;
|
||||
GstElement *pipeline;
|
||||
GstElement *thread, *thread2;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
gboolean playing;
|
||||
|
||||
static void
|
||||
G_GNUC_UNUSED static void
|
||||
xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data)
|
||||
{
|
||||
xmlNodePtr children = self->xmlChildrenNode;
|
||||
|
|
|
@ -44,8 +44,7 @@ endif
|
|||
|
||||
EXTRA_libgstreamer_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gsttypefind.c gstparse.c gstautoplug.c gsttrace.c
|
||||
|
||||
# cheap trick to build . first...
|
||||
SUBDIRS = . $(GST_AUTOPLUG_DIRS) elements schedulers types
|
||||
SUBDIRS = parse . $(GST_AUTOPLUG_DIRS) elements schedulers types
|
||||
DIST_SUBDIRS = autoplug elements parse types schedulers
|
||||
|
||||
libcothreads_la_SOURCES = cothreads.c
|
||||
|
@ -156,7 +155,7 @@ libgstreamer_la_CFLAGS = -D_GNU_SOURCE -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\"
|
|||
# the compiler shoots cothreads.c in the head at -O6
|
||||
libcothreads_la_CFLAGS = $(libgstreamer_la_CFLAGS) -O2
|
||||
|
||||
libgstreamer_la_LIBADD = $(LIBGST_LIBS)
|
||||
libgstreamer_la_LIBADD = $(LIBGST_LIBS) parse/libgstparse.la
|
||||
libgstreamer_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@
|
||||
|
||||
EXTRA_DIST = ROADMAP
|
||||
|
|
|
@ -8,13 +8,13 @@ void cache_empty(GstElement *element, gpointer private) {
|
|||
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
gst_element_disconnect(src,"src",cache,"sink");
|
||||
gst_element_disconnect_pads (src,"src",cache,"sink");
|
||||
gst_scheduler_show (GST_ELEMENT_SCHED(pipeline));
|
||||
gst_element_disconnect(cache,"src",decoder,"sink");
|
||||
gst_element_disconnect_pads (cache,"src",decoder,"sink");
|
||||
gst_scheduler_show (GST_ELEMENT_SCHED(pipeline));
|
||||
gst_bin_remove (GST_BIN(autobin), cache);
|
||||
gst_scheduler_show (GST_ELEMENT_SCHED(pipeline));
|
||||
gst_element_connect(src,"src",decoder,"sink");
|
||||
gst_element_connect_pads (src,"src",decoder,"sink");
|
||||
gst_scheduler_show (GST_ELEMENT_SCHED(pipeline));
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
@ -29,7 +29,7 @@ void have_type(GstElement *element, GstCaps *caps, GstCaps **private_caps) {
|
|||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
/* disconnect the typefind from the pipeline and remove it */
|
||||
gst_element_disconnect(cache,"src",typefind,"sink");
|
||||
gst_element_disconnect(cache,typefind);
|
||||
gst_bin_remove(GST_BIN(autobin),typefind);
|
||||
|
||||
gst_scheduler_show (GST_ELEMENT_SCHED(pipeline));
|
||||
|
@ -39,22 +39,22 @@ void have_type(GstElement *element, GstCaps *caps, GstCaps **private_caps) {
|
|||
sink = gst_elementfactory_make ("osssink","sink");
|
||||
gst_bin_add(GST_BIN(autobin),decoder);
|
||||
gst_bin_add(GST_BIN(autobin),sink);
|
||||
gst_element_connect(decoder,"src",sink,"sink");
|
||||
gst_element_connect_pads(decoder,"src",sink,"sink");
|
||||
|
||||
g_object_set (G_OBJECT(cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect(cache,"src",decoder,"sink");
|
||||
gst_element_connect_pads(cache,"src",decoder,"sink");
|
||||
}
|
||||
else if (strstr(gst_caps_get_mime(caps),"x-ogg")) {
|
||||
decoder = gst_elementfactory_make ("vorbisdec","decoder");
|
||||
sink = gst_elementfactory_make ("osssink","sink");
|
||||
gst_bin_add(GST_BIN(autobin),decoder);
|
||||
gst_bin_add(GST_BIN(autobin),sink);
|
||||
gst_element_connect(decoder,"src",sink,"sink");
|
||||
gst_element_connect_pads(decoder,"src",sink,"sink");
|
||||
|
||||
g_object_set (G_OBJECT(cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect(cache,"src",decoder,"sink");
|
||||
gst_element_connect_pads(cache,"src",decoder,"sink");
|
||||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
@ -78,14 +78,15 @@ int main (int argc,char *argv[]) {
|
|||
g_signal_connect (G_OBJECT(typefind),"have_type",(GCallback)have_type,&caps);
|
||||
gst_bin_add (GST_BIN(autobin),cache);
|
||||
gst_bin_add (GST_BIN(autobin),typefind);
|
||||
gst_element_connect(cache,"src",typefind,"sink");
|
||||
gst_element_connect_pads (cache,"src",typefind,"sink");
|
||||
gst_element_add_ghost_pad(autobin,gst_element_get_pad(cache,"sink"),"sink");
|
||||
|
||||
gst_bin_add (GST_BIN(pipeline), autobin);
|
||||
gst_element_connect (src,"src",autobin,"sink");
|
||||
gst_element_connect_pads (src,"src",autobin,"sink");
|
||||
|
||||
gst_element_set_state(pipeline,GST_STATE_PLAYING);
|
||||
|
||||
while (1)
|
||||
gst_bin_iterate(GST_BIN(pipeline));
|
||||
while (gst_bin_iterate(GST_BIN(pipeline)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -533,7 +533,7 @@ gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath)
|
|||
gst_bin_add (GST_BIN (spider), element);
|
||||
}
|
||||
/* insert and connect new element */
|
||||
if (!gst_element_connect_elements (conn->current, element))
|
||||
if (!gst_element_connect (conn->current, element))
|
||||
{
|
||||
/* check if the src has SOMETIMES templates. If so, connect a callback */
|
||||
GList *templs = gst_element_get_padtemplate_list (conn->current);
|
||||
|
|
|
@ -119,9 +119,9 @@ int main(int argc,char *argv[])
|
|||
gst_bin_add(GST_BIN(bin), videosink);
|
||||
|
||||
/* connect objects */
|
||||
if (!(gst_element_connect_elements(filesrc, decoder) &&
|
||||
gst_element_connect_elements(decoder, osssink) &&
|
||||
gst_element_connect_elements(decoder, videosink)))
|
||||
if (!(gst_element_connect(filesrc, decoder) &&
|
||||
gst_element_connect(decoder, osssink) &&
|
||||
gst_element_connect(decoder, videosink)))
|
||||
{
|
||||
g_print ("the pipeline could not be connected\n");
|
||||
exit (-4);
|
||||
|
|
27
gst/gst.c
27
gst/gst.c
|
@ -66,6 +66,7 @@ enum {
|
|||
ARG_INFO_MASK=1,
|
||||
ARG_DEBUG_MASK,
|
||||
ARG_MASK,
|
||||
ARG_MASK_HELP,
|
||||
ARG_PLUGIN_SPEW,
|
||||
ARG_PLUGIN_PATH,
|
||||
ARG_PLUGIN_LOAD,
|
||||
|
@ -82,6 +83,7 @@ static const struct poptOption options[] = {
|
|||
{"gst-info-mask", NUL, POPT_ARG_INT|POPT_ARGFLAG_STRIP, NULL, ARG_INFO_MASK, "info bitmask", "MASK"},
|
||||
{"gst-debug-mask", NUL, POPT_ARG_INT|POPT_ARGFLAG_STRIP, NULL, ARG_DEBUG_MASK, "debugging bitmask", "MASK"},
|
||||
{"gst-mask", NUL, POPT_ARG_INT|POPT_ARGFLAG_STRIP, NULL, ARG_MASK, "bitmask for both info and debugging", "MASK"},
|
||||
{"gst-mask-help", NUL, POPT_ARG_NONE|POPT_ARGFLAG_STRIP, NULL, ARG_MASK_HELP, "how to set the level of diagnostic output (-mask values)", NULL},
|
||||
{"gst-plugin-spew", NUL, POPT_ARG_NONE|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_SPEW, "enable verbose plugin loading diagnostics", NULL},
|
||||
{"gst-plugin-path", NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_PATH, "'" G_SEARCHPATH_SEPARATOR_S "'--separated path list for loading plugins", "PATHS"},
|
||||
{"gst-plugin-load", NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_LOAD, "comma-separated list of plugins to preload in addition to the list stored in env variable GST_PLUGIN_PATH", "PLUGINS"},
|
||||
|
@ -265,7 +267,6 @@ static void
|
|||
init_post (void)
|
||||
{
|
||||
GLogLevelFlags llf;
|
||||
gboolean showhelp = FALSE;
|
||||
const gchar *plugin_path;
|
||||
#ifndef GST_DISABLE_TRACE
|
||||
GstTrace *gst_trace;
|
||||
|
@ -326,24 +327,13 @@ init_post (void)
|
|||
if (_gst_progname == NULL) {
|
||||
_gst_progname = g_strdup("gstprog");
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: this is never true... */
|
||||
if (showhelp) {
|
||||
static void
|
||||
gst_mask_help (void)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_print ("usage %s [OPTION...]\n", _gst_progname);
|
||||
|
||||
g_print ("\nGStreamer options\n");
|
||||
g_print (" --gst-info-mask=FLAGS GST info flags to set (current %08x)\n", gst_info_get_categories());
|
||||
g_print (" --gst-debug-mask=FLAGS GST debugging flags to set\n");
|
||||
g_print (" --gst-mask=FLAGS GST info *and* debug flags to set\n");
|
||||
g_print (" --gst-plugin-spew Enable printout of errors while loading GST plugins\n");
|
||||
g_print (" --gst-plugin-path=PATH Add directories separated with '%s' to the plugin search path\n",
|
||||
G_SEARCHPATH_SEPARATOR_S);
|
||||
g_print (" --gst-plugin-load=PLUGINS Load plugins separated with '%s'\n",
|
||||
GST_PLUGIN_SEPARATOR);
|
||||
g_print (" --gst-scheduler=NAME Use a nonstandard scheduler\n");
|
||||
|
||||
g_print ("\n Mask (to be OR'ed) info/debug FLAGS \n");
|
||||
g_print ("--------------------------------------------------------\n");
|
||||
|
||||
|
@ -363,7 +353,7 @@ init_post (void)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_popt_callback (poptContext context, enum poptCallbackReason reason,
|
||||
|
@ -390,6 +380,9 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason,
|
|||
gst_debug_set_categories (val);
|
||||
gst_info_set_categories (val);
|
||||
break;
|
||||
case ARG_MASK_HELP:
|
||||
gst_mask_help ();
|
||||
exit (0);
|
||||
case ARG_PLUGIN_SPEW:
|
||||
_gst_plugin_spew = TRUE;
|
||||
break;
|
||||
|
|
279
gst/gstelement.c
279
gst/gstelement.c
|
@ -174,7 +174,6 @@ gst_element_init (GstElement *element)
|
|||
element->state_cond = g_cond_new ();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_element_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
|
@ -184,7 +183,6 @@ gst_element_set_property (GObject *object, guint prop_id, const GValue *value, G
|
|||
(oclass->set_property) (object, prop_id, value, pspec);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
|
@ -194,6 +192,19 @@ gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamS
|
|||
(oclass->get_property) (object, prop_id, value, pspec);
|
||||
}
|
||||
|
||||
static GstPad*
|
||||
gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
|
||||
{
|
||||
GstPad *newpad = NULL;
|
||||
GstElementClass *oclass;
|
||||
|
||||
oclass = CLASS (element);
|
||||
if (oclass->request_new_pad)
|
||||
newpad = (oclass->request_new_pad)(element, templ, name);
|
||||
|
||||
return newpad;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_element_set_name:
|
||||
|
@ -482,6 +493,33 @@ gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
|
|||
*/
|
||||
GstPad*
|
||||
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;
|
||||
|
||||
|
@ -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 (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;
|
||||
while (walk) {
|
||||
GstPad *pad;
|
||||
|
||||
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));
|
||||
return pad;
|
||||
}
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
|
||||
GST_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_get_request_pad:
|
||||
* @element: element to find pad of
|
||||
* @name: name of pad to retrieve
|
||||
*
|
||||
* Retrieve a pad from the element by name. This version only retrieves
|
||||
* request pads.
|
||||
*
|
||||
* Returns: requested pad if found, otherwise NULL.
|
||||
*/
|
||||
GstPad*
|
||||
gst_element_get_request_pad (GstElement *element, const gchar *name)
|
||||
{
|
||||
GstPadTemplate *templ = NULL;
|
||||
GstPad *pad;
|
||||
const gchar *req_name = NULL;
|
||||
gboolean templ_found = FALSE;
|
||||
GList *list;
|
||||
gint n;
|
||||
const gchar *data;
|
||||
gchar *str, *endptr = NULL;
|
||||
|
||||
g_return_val_if_fail (element != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
if (strstr (name, "%")) {
|
||||
templ = gst_element_get_padtemplate_by_name (element, name);
|
||||
req_name = NULL;
|
||||
if (templ)
|
||||
templ_found = TRUE;
|
||||
} else {
|
||||
list = gst_element_get_padtemplate_list(element);
|
||||
while (!templ_found && list) {
|
||||
templ = (GstPadTemplate*) list->data;
|
||||
if (templ->presence == GST_PAD_REQUEST) {
|
||||
/* we know that %s and %d are the only possibilities because of sanity
|
||||
checks in gst_padtemplate_new */
|
||||
GST_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
|
||||
if ((str = strchr (templ->name_template, '%')) &&
|
||||
strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
|
||||
strlen (name) > str - templ->name_template) {
|
||||
data = name + (str - templ->name_template);
|
||||
if (*(str+1) == 'd') {
|
||||
/* it's an int */
|
||||
n = (gint) strtol (data, &endptr, 10);
|
||||
if (endptr && *endptr == '\0') {
|
||||
templ_found = TRUE;
|
||||
req_name = name;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* it's a string */
|
||||
templ_found = TRUE;
|
||||
req_name = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!templ_found)
|
||||
return NULL;
|
||||
|
||||
pad = gst_element_request_pad (element, templ, req_name);
|
||||
|
||||
return pad;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_get_pad_list:
|
||||
* @element: element to get pads of
|
||||
|
@ -658,19 +762,6 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
|
|||
return newtempl;
|
||||
}
|
||||
|
||||
static GstPad*
|
||||
gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
|
||||
{
|
||||
GstPad *newpad = NULL;
|
||||
GstElementClass *oclass;
|
||||
|
||||
oclass = CLASS (element);
|
||||
if (oclass->request_new_pad)
|
||||
newpad = (oclass->request_new_pad)(element, templ, name);
|
||||
|
||||
return newpad;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_request_compatible_pad:
|
||||
* @element: element to request a new pad from
|
||||
|
@ -700,78 +791,6 @@ gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
|
|||
return pad;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_request_pad_by_name:
|
||||
* @element: element to request a new pad from
|
||||
* @name: the name of the padtemplate to use.
|
||||
*
|
||||
* Request a new pad from the element. The name argument will
|
||||
* be used to decide what padtemplate to use. This function
|
||||
* is typically used for elements with a padtemplate with presence
|
||||
* GST_PAD_REQUEST.
|
||||
*
|
||||
* Returns: the new pad that was created.
|
||||
*/
|
||||
GstPad*
|
||||
gst_element_request_pad_by_name (GstElement *element, const gchar *name)
|
||||
{
|
||||
GstPadTemplate *templ = NULL;
|
||||
GstPad *pad;
|
||||
const gchar *req_name = NULL;
|
||||
gboolean templ_found = FALSE;
|
||||
GList *list;
|
||||
gint n;
|
||||
const gchar *data;
|
||||
gchar *str, *endptr;
|
||||
|
||||
g_return_val_if_fail (element != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
|
||||
if (strstr (name, "%")) {
|
||||
templ = gst_element_get_padtemplate_by_name (element, name);
|
||||
req_name = NULL;
|
||||
if (templ)
|
||||
templ_found = TRUE;
|
||||
} else {
|
||||
list = gst_element_get_padtemplate_list(element);
|
||||
while (!templ_found && list) {
|
||||
templ = (GstPadTemplate*) list->data;
|
||||
if (templ->presence == GST_PAD_REQUEST) {
|
||||
/* we know that %s and %d are the only possibilities because of sanity
|
||||
checks in gst_padtemplate_new */
|
||||
if ((str = strchr (templ->name_template, '%')) &&
|
||||
strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
|
||||
strlen (name) > str - templ->name_template) {
|
||||
data = name + (str - templ->name_template);
|
||||
if (*(str+1) == 'd') {
|
||||
/* it's an int */
|
||||
n = (gint) strtol (data, &endptr, 10);
|
||||
if (endptr == NULL) {
|
||||
templ_found = TRUE;
|
||||
req_name = name;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* it's a string */
|
||||
templ_found = TRUE;
|
||||
req_name = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!templ_found)
|
||||
return NULL;
|
||||
|
||||
pad = gst_element_request_pad (element, templ, req_name);
|
||||
|
||||
return pad;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_get_compatible_pad_filtered:
|
||||
|
@ -860,7 +879,7 @@ gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_element_connect_elements_filtered:
|
||||
* gst_element_connect_filtered:
|
||||
* @src: the element containing source pad
|
||||
* @dest: the element containing destination pad
|
||||
* @filtercaps: the caps to use as filter
|
||||
|
@ -875,7 +894,7 @@ gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
|
|||
* Returns: TRUE if the elements could be connected.
|
||||
*/
|
||||
gboolean
|
||||
gst_element_connect_elements_filtered (GstElement *src, GstElement *dest,
|
||||
gst_element_connect_filtered (GstElement *src, GstElement *dest,
|
||||
GstCaps *filtercaps)
|
||||
{
|
||||
GList *srcpads, *destpads, *srctempls, *desttempls, *l;
|
||||
|
@ -936,8 +955,8 @@ gst_element_connect_elements_filtered (GstElement *src, GstElement *dest,
|
|||
if (desttempl->presence == GST_PAD_REQUEST && desttempl->direction != srctempl->direction) {
|
||||
if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctempl),
|
||||
gst_padtemplate_get_caps (desttempl))) {
|
||||
srcpad = gst_element_request_pad_by_name (src, srctempl->name_template);
|
||||
destpad = gst_element_request_pad_by_name (dest, desttempl->name_template);
|
||||
srcpad = gst_element_get_request_pad (src, srctempl->name_template);
|
||||
destpad = gst_element_get_request_pad (dest, desttempl->name_template);
|
||||
if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
|
||||
GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s",
|
||||
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
|
||||
|
@ -957,19 +976,17 @@ gst_element_connect_elements_filtered (GstElement *src, GstElement *dest,
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_element_connect_elements_many:
|
||||
* gst_element_connect_many:
|
||||
* @element_1: the first element in the connection chain
|
||||
* @element_2: the second element in the connection chain
|
||||
* @...: NULL-terminated list of elements to connect in order
|
||||
*
|
||||
* Chain together a series of elements. Uses #gst_element_connect_elements.
|
||||
* Chain together a series of elements. Uses #gst_element_connect.
|
||||
*
|
||||
* Returns: TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
/* API FIXME: this should be called gst_element_connect_many, and connect_elements
|
||||
* should just be connect */
|
||||
gboolean
|
||||
gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, ...)
|
||||
gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
|
@ -979,7 +996,7 @@ gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2,
|
|||
va_start (args, element_2);
|
||||
|
||||
while (element_2) {
|
||||
if (!gst_element_connect_elements (element_1, element_2))
|
||||
if (!gst_element_connect (element_1, element_2))
|
||||
return FALSE;
|
||||
|
||||
element_1 = element_2;
|
||||
|
@ -992,7 +1009,7 @@ gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2,
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_element_connect_elements:
|
||||
* gst_element_connect:
|
||||
* @src: element containing source pad
|
||||
* @dest: element containing destination pad
|
||||
*
|
||||
|
@ -1006,13 +1023,13 @@ gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2,
|
|||
* Returns: TRUE if the elements could be connected.
|
||||
*/
|
||||
gboolean
|
||||
gst_element_connect_elements (GstElement *src, GstElement *dest)
|
||||
gst_element_connect (GstElement *src, GstElement *dest)
|
||||
{
|
||||
return gst_element_connect_elements_filtered (src, dest, NULL);
|
||||
return gst_element_connect_filtered (src, dest, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_connect_filtered:
|
||||
* gst_element_connect_pads_filtered:
|
||||
* @src: element containing source pad
|
||||
* @srcpadname: name of pad in source element
|
||||
* @dest: element containing destination pad
|
||||
|
@ -1027,7 +1044,7 @@ gst_element_connect_elements (GstElement *src, GstElement *dest)
|
|||
* Returns: TRUE if the pads could be connected.
|
||||
*/
|
||||
gboolean
|
||||
gst_element_connect_filtered (GstElement *src, const gchar *srcpadname,
|
||||
gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname,
|
||||
GstCaps *filtercaps)
|
||||
{
|
||||
|
@ -1057,7 +1074,7 @@ gst_element_connect_filtered (GstElement *src, const gchar *srcpadname,
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_element_connect:
|
||||
* gst_element_connect_pads:
|
||||
* @src: element containing source pad
|
||||
* @srcpadname: name of pad in source element
|
||||
* @dest: element containing destination pad
|
||||
|
@ -1071,14 +1088,14 @@ gst_element_connect_filtered (GstElement *src, const gchar *srcpadname,
|
|||
* Returns: TRUE if the pads could be connected.
|
||||
*/
|
||||
gboolean
|
||||
gst_element_connect (GstElement *src, const gchar *srcpadname,
|
||||
gst_element_connect_pads (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname)
|
||||
{
|
||||
return gst_element_connect_filtered (src, srcpadname, dest, destpadname, NULL);
|
||||
return gst_element_connect_pads_filtered (src, srcpadname, dest, destpadname, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_disconnect:
|
||||
* gst_element_disconnect_pads:
|
||||
* @src: element containing source pad
|
||||
* @srcpadname: name of pad in source element
|
||||
* @dest: element containing destination pad
|
||||
|
@ -1087,7 +1104,7 @@ gst_element_connect (GstElement *src, const gchar *srcpadname,
|
|||
* Disconnect the two named pads of the source and destination elements.
|
||||
*/
|
||||
void
|
||||
gst_element_disconnect (GstElement *src, const gchar *srcpadname,
|
||||
gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname)
|
||||
{
|
||||
GstPad *srcpad,*destpad;
|
||||
|
@ -1116,14 +1133,42 @@ gst_element_disconnect (GstElement *src, const gchar *srcpadname,
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_element_disconnect_elements:
|
||||
* gst_element_disconnect_many:
|
||||
* @element_1: the first element in the connection chain
|
||||
* @element_2: the second element in the connection chain
|
||||
* @...: NULL-terminated list of elements to disconnect in order
|
||||
*
|
||||
* Disconnect a series of elements. Uses #gst_element_disconnect.
|
||||
*/
|
||||
void
|
||||
gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
g_return_if_fail (element_1 != NULL && element_2 != NULL);
|
||||
g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
|
||||
|
||||
va_start (args, element_2);
|
||||
|
||||
while (element_2) {
|
||||
gst_element_disconnect (element_1, element_2);
|
||||
|
||||
element_1 = element_2;
|
||||
element_2 = va_arg (args, GstElement*);
|
||||
}
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_disconnect:
|
||||
* @src: source element
|
||||
* @dest: sink element
|
||||
*
|
||||
* Disconnect all pads connecting the two elements in the direction src -> dest.
|
||||
*/
|
||||
void
|
||||
gst_element_disconnect_elements (GstElement *src, GstElement *dest)
|
||||
gst_element_disconnect (GstElement *src, GstElement *dest)
|
||||
{
|
||||
GList *srcpads;
|
||||
GstPad *pad;
|
||||
|
@ -1157,6 +1202,7 @@ gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg
|
|||
gst_object_unref (GST_OBJECT (element));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_error:
|
||||
* @element: Element with the error
|
||||
|
@ -1226,6 +1272,7 @@ gst_element_wait_state_change (GstElement *element)
|
|||
g_cond_wait (element->state_cond, element->state_mutex);
|
||||
g_mutex_unlock (element->state_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_set_state:
|
||||
* @element: element to change state of
|
||||
|
|
|
@ -197,32 +197,37 @@ GstScheduler* gst_element_get_sched (GstElement *element);
|
|||
|
||||
void gst_element_add_pad (GstElement *element, GstPad *pad);
|
||||
void gst_element_remove_pad (GstElement *element, GstPad *pad);
|
||||
GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
|
||||
GList* gst_element_get_pad_list (GstElement *element);
|
||||
GList* gst_element_get_padtemplate_list (GstElement *element);
|
||||
GstPadTemplate* gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name);
|
||||
GstPad * gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name);
|
||||
void gst_element_remove_ghost_pad (GstElement *element, GstPad *pad);
|
||||
|
||||
GstPad* gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ);
|
||||
GstPad* gst_element_request_pad_by_name (GstElement *element, const gchar *name);
|
||||
GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
|
||||
GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name);
|
||||
GstPad* gst_element_get_request_pad (GstElement *element, const gchar *name);
|
||||
|
||||
GList* gst_element_get_pad_list (GstElement *element);
|
||||
GList* gst_element_get_padtemplate_list (GstElement *element);
|
||||
GstPadTemplate* gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name);
|
||||
|
||||
GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad);
|
||||
GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
|
||||
GstCaps *filtercaps);
|
||||
GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad);
|
||||
GstPad* gst_element_get_compatible_request_pad (GstElement *element, GstPadTemplate *templ);
|
||||
GstPad* gst_element_get_compatible_static_pad (GstElement *element, GstPadTemplate *templ);
|
||||
|
||||
/* these functions should probably have another name, but gst_element_connect is already used */
|
||||
gboolean gst_element_connect_elements (GstElement *src, GstElement *dest);
|
||||
gboolean gst_element_connect_elements_filtered (GstElement *src, GstElement *dest,
|
||||
gboolean gst_element_connect (GstElement *src, GstElement *dest);
|
||||
gboolean gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...);
|
||||
gboolean gst_element_connect_filtered (GstElement *src, GstElement *dest,
|
||||
GstCaps *filtercaps);
|
||||
gboolean gst_element_connect (GstElement *src, const gchar *srcpadname,
|
||||
void gst_element_disconnect (GstElement *src, GstElement *dest);
|
||||
void gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...);
|
||||
|
||||
gboolean gst_element_connect_pads (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname);
|
||||
gboolean gst_element_connect_filtered (GstElement *src, const gchar *srcpadname,
|
||||
gboolean gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname,
|
||||
GstCaps *filtercaps);
|
||||
void gst_element_disconnect (GstElement *src, const gchar *srcpadname,
|
||||
void gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname);
|
||||
void gst_element_disconnect_elements (GstElement *src, GstElement *dest);
|
||||
gboolean gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, ...);
|
||||
|
||||
void gst_element_set_eos (GstElement *element);
|
||||
|
||||
|
|
761
gst/gstparse.c
761
gst/gstparse.c
|
@ -25,25 +25,11 @@
|
|||
#define DEBUG_NOPREFIX(format,args...)
|
||||
#define VERBOSE(format,args...)
|
||||
|
||||
#define GST_PARSE_LISTPAD(list) ((GstPad*)(list->data))
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gst_private.h"
|
||||
#include "gstparse.h"
|
||||
#include "gstpipeline.h"
|
||||
#include "gstthread.h"
|
||||
#include "gstutils.h"
|
||||
|
||||
typedef struct _gst_parse_priv gst_parse_priv;
|
||||
struct _gst_parse_priv
|
||||
{
|
||||
guint bincount;
|
||||
guint threadcount;
|
||||
gint binlevel;
|
||||
gboolean verbose;
|
||||
gboolean debug;
|
||||
};
|
||||
#include "parse/types.h"
|
||||
|
||||
typedef struct _gst_parse_delayed_pad gst_parse_delayed_pad;
|
||||
struct _gst_parse_delayed_pad
|
||||
|
@ -60,7 +46,17 @@ typedef struct
|
|||
}
|
||||
dyn_connect;
|
||||
|
||||
static void
|
||||
|
||||
GQuark
|
||||
gst_parse_error_quark (void)
|
||||
{
|
||||
static GQuark quark = 0;
|
||||
if (!quark)
|
||||
quark = g_quark_from_static_string ("gst_parse_error");
|
||||
return quark;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
dynamic_connect (GstElement * element, GstPad * newpad, gpointer data)
|
||||
{
|
||||
dyn_connect *connect = (dyn_connect *) data;
|
||||
|
@ -74,411 +70,277 @@ dynamic_connect (GstElement * element, GstPad * newpad, gpointer data)
|
|||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
gst_parse_launchv_recurse (const gchar **argv, GstBin * parent, gst_parse_priv * priv)
|
||||
static gboolean
|
||||
make_elements (graph_t *g, GError **error)
|
||||
{
|
||||
gint i = -1, j = 0;
|
||||
const gchar *arg;
|
||||
GstElement *element = NULL, *previous = NULL, *prevelement = NULL;
|
||||
gchar closingchar = '\0';
|
||||
gint len;
|
||||
const gchar *cptr;
|
||||
gchar *ptr;
|
||||
gchar *sinkpadname = NULL, *srcpadname = NULL, *tempname;
|
||||
GstPad *temppad;
|
||||
GSList *sinkpads = NULL, *srcpads = NULL;
|
||||
gint numsrcpads = 0, numsinkpads = 0;
|
||||
GList *pads;
|
||||
gint elementcount = 0;
|
||||
gint retval = 0;
|
||||
gboolean backref = FALSE;
|
||||
GList *l = NULL;
|
||||
gchar *bin_type;
|
||||
element_t *e;
|
||||
|
||||
if (!priv) {
|
||||
priv = g_new0 (gst_parse_priv, 1);
|
||||
if (!(g->bins || g->elements)) {
|
||||
g_set_error (error,
|
||||
GST_PARSE_ERROR,
|
||||
GST_PARSE_ERROR_SYNTAX,
|
||||
"Empty bin");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
priv->binlevel++;
|
||||
|
||||
if (GST_IS_PIPELINE (parent)) {
|
||||
closingchar = '\0';
|
||||
DEBUG ("in pipeline ");
|
||||
} else if (GST_IS_THREAD (parent)) {
|
||||
closingchar = '}';
|
||||
DEBUG ("in thread ");
|
||||
} else {
|
||||
closingchar = ')';
|
||||
DEBUG ("in bin ");
|
||||
}
|
||||
DEBUG_NOPREFIX ("%s\n", GST_ELEMENT_NAME (GST_ELEMENT (parent)));
|
||||
|
||||
while ((arg = argv[++i])) {
|
||||
len = strlen (arg);
|
||||
element = NULL;
|
||||
DEBUG ("** ARGUMENT is '%s'\n", arg);
|
||||
|
||||
if (len == 0) {
|
||||
DEBUG ("random arg, FIXME\n");
|
||||
|
||||
continue;
|
||||
} else if (arg[0] == closingchar) {
|
||||
DEBUG ("exiting container %s\n", GST_ELEMENT_NAME (GST_ELEMENT (parent)));
|
||||
|
||||
retval = i + 1;
|
||||
break;
|
||||
} else if ((cptr = strchr (arg, '!'))) {
|
||||
DEBUG ("attempting to connect pads together....\n");
|
||||
|
||||
/* if it starts with the ! */
|
||||
if (arg[0] == '!') {
|
||||
srcpadname = NULL;
|
||||
/* if there's a sinkpad... */
|
||||
if (len > 1)
|
||||
sinkpadname = g_strdup (&arg[1]);
|
||||
if (g->current_bin_type)
|
||||
bin_type = g->current_bin_type;
|
||||
else
|
||||
sinkpadname = NULL;
|
||||
bin_type = "pipeline";
|
||||
|
||||
if (!(g->bin = gst_elementfactory_make (bin_type, NULL))) {
|
||||
g_set_error (error,
|
||||
GST_PARSE_ERROR,
|
||||
GST_PARSE_ERROR_NO_SUCH_ELEMENT,
|
||||
"No such bin type %s", bin_type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
l = g->elements;
|
||||
while (l) {
|
||||
e = (element_t*)l->data;
|
||||
if (!(e->element = gst_elementfactory_make (e->type, NULL))) {
|
||||
g_set_error (error,
|
||||
GST_PARSE_ERROR,
|
||||
GST_PARSE_ERROR_NO_SUCH_ELEMENT,
|
||||
"No such element %s", e->type);
|
||||
return FALSE;
|
||||
}
|
||||
gst_bin_add (GST_BIN (g->bin), e->element);
|
||||
l = g_list_next (l);
|
||||
}
|
||||
|
||||
l = g->bins;
|
||||
while (l) {
|
||||
if (!make_elements ((graph_t*)l->data, error))
|
||||
return FALSE;
|
||||
gst_bin_add (GST_BIN (g->bin), ((graph_t*)l->data)->bin);
|
||||
l = g_list_next (l);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_properties (graph_t *g, GError **error)
|
||||
{
|
||||
GList *l, *l2;
|
||||
element_t *e;
|
||||
property_t *p;
|
||||
GParamSpec *pspec;
|
||||
|
||||
l = g->elements;
|
||||
while (l) {
|
||||
e = (element_t*)l->data;
|
||||
l2 = e->property_values;
|
||||
while (l2) {
|
||||
p = (property_t*)l2->data;
|
||||
if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (e->element), p->name))) {
|
||||
g_object_set_property (G_OBJECT (e->element), p->name, p->value);
|
||||
} else {
|
||||
srcpadname = g_strndup (arg, (cptr - arg));
|
||||
/* if there's a sinkpad */
|
||||
if (len > (cptr - arg) + 1)
|
||||
sinkpadname = g_strdup(&cptr[1]);
|
||||
else
|
||||
sinkpadname = NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
l = g->bins;
|
||||
while (l) {
|
||||
if (!set_properties ((graph_t*)l->data, error))
|
||||
return FALSE;
|
||||
l = g_list_next (l);
|
||||
}
|
||||
|
||||
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;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* look for pad with that name */
|
||||
if ((temppad = gst_element_get_pad (previous, tempname))) {
|
||||
srcpads = g_slist_append (srcpads, temppad);
|
||||
numsrcpads++;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
l = g->bins;
|
||||
while (l) {
|
||||
if ((element = find_element_by_index_recurse ((graph_t*)l->data, i)))
|
||||
return element;
|
||||
l = g_list_next (l);
|
||||
}
|
||||
|
||||
/* if there is no more commas in srcpadname then we're done */
|
||||
if (tempname == srcpadname)
|
||||
break;
|
||||
g_free (tempname);
|
||||
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 {
|
||||
/* 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;
|
||||
src = find_element_by_index (g, c->src_index);
|
||||
g_assert (src);
|
||||
}
|
||||
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;
|
||||
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 {
|
||||
fprintf (stderr, "error, expected ], found end of arguments\n");
|
||||
return GST_PARSE_ERROR_SYNTAX;
|
||||
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 {
|
||||
/* 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 (!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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
l = g->bins;
|
||||
while (l) {
|
||||
if (!make_connections ((graph_t*)l->data, error))
|
||||
return FALSE;
|
||||
l = g_list_next (l);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
previous = element;
|
||||
if (!GST_IS_BIN (element))
|
||||
prevelement = element;
|
||||
}
|
||||
}
|
||||
static GstBin*
|
||||
pipeline_from_graph (graph_t *g, GError **error)
|
||||
{
|
||||
if (!make_elements (g, error))
|
||||
return NULL;
|
||||
|
||||
/* ghost all the src pads of the bin */
|
||||
if (prevelement != NULL) {
|
||||
DEBUG ("last element, ghosting all of %s's src pads to parent %s\n",
|
||||
GST_ELEMENT_NAME (prevelement), GST_ELEMENT_NAME (GST_ELEMENT (parent)));
|
||||
pads = gst_element_get_pad_list (prevelement);
|
||||
while (pads) {
|
||||
temppad = GST_PAD (pads->data);
|
||||
pads = g_list_next (pads);
|
||||
if (!temppad)
|
||||
DEBUG ("much oddness, pad doesn't seem to exist\n");
|
||||
else if (gst_pad_get_direction (temppad) == GST_PAD_SRC) {
|
||||
gst_element_add_ghost_pad (GST_ELEMENT (parent), temppad,
|
||||
g_strdup_printf ("%s-ghost", GST_PAD_NAME (temppad)));
|
||||
GST_DEBUG (0, "GHOSTED %s:%s to %s as %s-ghost",
|
||||
GST_DEBUG_PAD_NAME (temppad), GST_ELEMENT_NAME (parent), GST_PAD_NAME (temppad));
|
||||
if (!set_properties (g, error))
|
||||
return NULL;
|
||||
|
||||
if (!make_connections (g, error))
|
||||
return NULL;
|
||||
|
||||
return (GstBin*)g->bin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
priv->binlevel--;
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
DEBUG (closingchar != '\0' ? "returning IN THE WRONG PLACE\n" : "ending pipeline\n");
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_parse_launchv:
|
||||
|
@ -488,26 +350,19 @@ gst_parse_launchv_recurse (const gchar **argv, GstBin * parent, gst_parse_priv *
|
|||
*
|
||||
* Returns: a new pipeline on success, NULL on failure
|
||||
*/
|
||||
GstPipeline *
|
||||
gst_parse_launchv (const gchar **argv)
|
||||
GstBin *
|
||||
gst_parse_launchv (const gchar **argv, GError **error)
|
||||
{
|
||||
GstPipeline *pipeline;
|
||||
gint ret;
|
||||
GstBin *pipeline;
|
||||
gchar *pipeline_description;
|
||||
|
||||
/* defer error detection to the _recurse function */
|
||||
/* i think this cast works out ok... */
|
||||
pipeline_description = g_strjoinv (" ", (gchar**)argv);
|
||||
|
||||
pipeline = (GstPipeline*) gst_pipeline_new ("launch");
|
||||
pipeline = gst_parse_launch (pipeline_description, error);
|
||||
|
||||
ret = gst_parse_launchv_recurse (argv, GST_BIN (pipeline), NULL);
|
||||
|
||||
if (ret <= 0) {
|
||||
/* print an error */
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
return NULL;
|
||||
} else {
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_parse_launch:
|
||||
|
@ -517,98 +372,24 @@ gst_parse_launchv (const gchar **argv)
|
|||
*
|
||||
* Returns: a new GstPipeline (cast to a Bin) on success, NULL on failure
|
||||
*/
|
||||
GstPipeline *
|
||||
gst_parse_launch (const gchar * pipeline_description)
|
||||
GstBin *
|
||||
gst_parse_launch (const gchar * pipeline_description, GError **error)
|
||||
{
|
||||
gchar **argvn;
|
||||
gint newargc;
|
||||
gint i;
|
||||
const gchar *cp, *start, *end;
|
||||
gchar *temp;
|
||||
GSList *string_list = NULL, *slist;
|
||||
GstPipeline *pipeline;
|
||||
graph_t *graph;
|
||||
static GStaticMutex flex_lock = G_STATIC_MUTEX_INIT;
|
||||
|
||||
end = pipeline_description + strlen (pipeline_description);
|
||||
newargc = 0;
|
||||
g_return_val_if_fail (pipeline_description != NULL, NULL);
|
||||
|
||||
temp = "";
|
||||
GST_INFO (GST_CAT_PIPELINE, "parsing pipeline description %s",
|
||||
pipeline_description);
|
||||
|
||||
/* Extract the arguments to a gslist in reverse order */
|
||||
for (cp = pipeline_description; cp < end;) {
|
||||
i = strcspn (cp, "([{}]) \"\\");
|
||||
/* the need for the mutex will go away with flex 2.5.6 */
|
||||
g_static_mutex_lock (&flex_lock);
|
||||
graph = _gst_parse_launch (pipeline_description, error);
|
||||
g_static_mutex_unlock (&flex_lock);
|
||||
|
||||
if (i > 0) {
|
||||
temp = g_strconcat (temp, g_strndup (cp, i), NULL);
|
||||
if (!graph)
|
||||
return NULL;
|
||||
|
||||
/* see if we have an escape char */
|
||||
if (cp[i] != '\\') {
|
||||
/* normal argument - copy and add to the list */
|
||||
string_list = g_slist_prepend (string_list, temp);
|
||||
newargc++;
|
||||
temp = "";
|
||||
} else {
|
||||
temp = g_strconcat (temp, g_strndup (&cp[++i], 1), NULL);
|
||||
}
|
||||
cp += i;
|
||||
}
|
||||
|
||||
/* skip spaces */
|
||||
while (cp < end && *cp == ' ') {
|
||||
cp++;
|
||||
}
|
||||
|
||||
/* handle quoted arguments */
|
||||
if (*cp == '"') {
|
||||
start = ++cp;
|
||||
|
||||
/* find matching quote */
|
||||
while (cp < end && *cp != '"')
|
||||
cp++;
|
||||
|
||||
/* make sure we got it */
|
||||
if (cp == end) {
|
||||
g_warning ("gst_parse_launch: Unbalanced quote in command line");
|
||||
/* FIXME: The list leaks here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copy the string sans quotes */
|
||||
string_list = g_slist_prepend (string_list, g_strndup (start, cp - start));
|
||||
newargc++;
|
||||
cp += 2; /* skip the quote aswell */
|
||||
}
|
||||
|
||||
/* brackets exist in a separate argument slot */
|
||||
if (*cp && strchr ("([{}])", *cp)) {
|
||||
string_list = g_slist_prepend (string_list, g_strndup (cp, 1));
|
||||
newargc++;
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
/* now allocate the new argv array, with room for NULL termination */
|
||||
argvn = g_new0 (char *, newargc + 1);
|
||||
|
||||
GST_DEBUG (0, "got %d args", newargc);
|
||||
|
||||
/* reverse the list and put the strings in the new array */
|
||||
i = newargc;
|
||||
|
||||
for (slist = string_list; slist; slist = slist->next)
|
||||
argvn[--i] = slist->data;
|
||||
|
||||
g_slist_free (string_list);
|
||||
|
||||
/* print them out */
|
||||
while (argvn[i++]) {
|
||||
GST_DEBUG (0, "arg %d is: %s", i-1, argvn[i-1]);
|
||||
}
|
||||
|
||||
/* do it! */
|
||||
pipeline = gst_parse_launchv ((const char**) argvn);
|
||||
|
||||
GST_DEBUG(0, "Finished - freeing temporary argument array");
|
||||
g_strfreev(argvn);
|
||||
|
||||
return pipeline;
|
||||
return pipeline_from_graph (graph, error);
|
||||
}
|
||||
|
|
|
@ -25,22 +25,24 @@
|
|||
|
||||
#include <gst/gstpipeline.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifndef GST_DISABLE_PARSE
|
||||
|
||||
typedef enum {
|
||||
GST_PARSE_ERROR_SYNTAX = -1,
|
||||
GST_PARSE_ERROR_CREATING_ELEMENT = -2,
|
||||
GST_PARSE_ERROR_NOSUCH_ELEMENT = -3,
|
||||
GST_PARSE_ERROR_INTERNAL = -4,
|
||||
GST_PARSE_ERROR_CONNECT = -5,
|
||||
} GstParseErrors;
|
||||
GQuark gst_parse_error_quark (void);
|
||||
#define GST_PARSE_ERROR gst_parse_error_quark ()
|
||||
|
||||
GstPipeline* gst_parse_launch (const gchar *pipeline_description);
|
||||
GstPipeline* gst_parse_launchv (const gchar **argv);
|
||||
typedef enum
|
||||
{
|
||||
GST_PARSE_ERROR_SYNTAX,
|
||||
GST_PARSE_ERROR_NO_SUCH_ELEMENT,
|
||||
GST_PARSE_ERROR_NO_SUCH_PROPERTY,
|
||||
GST_PARSE_ERROR_CONNECT
|
||||
} GstParseError;
|
||||
|
||||
|
||||
GstBin* gst_parse_launch (const gchar *pipeline_description, GError **error);
|
||||
GstBin* gst_parse_launchv (const gchar **argv, GError **error);
|
||||
|
||||
#else /* GST_DISABLE_PARSE */
|
||||
|
||||
|
@ -48,8 +50,6 @@ GstPipeline* gst_parse_launchv (const gchar **argv);
|
|||
|
||||
#endif /* GST_DISABLE_PARSE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_PARSE_H__ */
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
#noinst_LTLIBRARIES = libgstparse.la
|
||||
noinst_LTLIBRARIES = libgstparse.la
|
||||
|
||||
#libgstparse_la_SOURCES = parse.c grammar.c
|
||||
libgstparse_la_SOURCES = lex.yy.c grammar.tab.c
|
||||
|
||||
BISON = bison -d -v
|
||||
|
||||
noinst_PROGRAMS = grammar
|
||||
|
||||
grammar_SOURCES = lex.yy.c grammar.tab.c
|
||||
grammar_CFLAGS = $(GLIB_CFLAGS)
|
||||
grammar_LDADD = $(GLIB_LIBS)
|
||||
libgstparse_la_CFLAGS = $(LIBGST_CFLAGS)
|
||||
libgstparse_la_LIBADD = $(LIBGST_LIBS)
|
||||
|
||||
noinst_HEADERS = grammar.tab.h
|
||||
|
||||
|
|
|
@ -1,73 +1,68 @@
|
|||
%{
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include "../gstparse.h"
|
||||
#include "types.h"
|
||||
|
||||
#define YYDEBUG 1
|
||||
#define YYERROR_VERBOSE 1
|
||||
#define YYPARSE_PARAM pgraph
|
||||
|
||||
static int yylex (void *lvalp);
|
||||
static int yyerror (const char *s);
|
||||
%}
|
||||
|
||||
%union {
|
||||
double d;
|
||||
gboolean b;
|
||||
gint i;
|
||||
gchar *s;
|
||||
GValue *v;
|
||||
graph_t *g;
|
||||
connection_t *c;
|
||||
property_t *p;
|
||||
element_t *e;
|
||||
hash_t *h;
|
||||
}
|
||||
|
||||
%token <s> IDENTIFIER STRING
|
||||
%token <d> FLOAT
|
||||
%token <i> INTEGER
|
||||
%token <b> BOOLEAN
|
||||
%token <s> IDENTIFIER
|
||||
%token <c> CONNECTION BCONNECTION
|
||||
%token <v> VALUE
|
||||
|
||||
%type <s> id
|
||||
%type <h> qid
|
||||
%type <g> graph bin
|
||||
%type <e> element
|
||||
%type <p> property_value value
|
||||
%type <c> connection lconnection rconnection qconnection iconnection
|
||||
%type <c> connection rconnection
|
||||
|
||||
%left '{' '}' '(' ')'
|
||||
%left '!' '='
|
||||
%left '+'
|
||||
%left ','
|
||||
%left '.'
|
||||
|
||||
%pure_parser
|
||||
|
||||
%start graph
|
||||
%%
|
||||
|
||||
id: IDENTIFIER
|
||||
;
|
||||
|
||||
qid: id { $$ = g_new0 (hash_t, 1); $$->id2 = $1 }
|
||||
| id '.' id { $$ = g_new0 (hash_t, 1); $$->id1 = $1; $$->id2 = $3; }
|
||||
;
|
||||
|
||||
value: STRING { $$ = g_new0 (property_t, 1);
|
||||
$$->value_type = G_TYPE_STRING; $$->value.s = $1; }
|
||||
| FLOAT { $$ = g_new0 (property_t, 1);
|
||||
$$->value_type = G_TYPE_DOUBLE; $$->value.d = $1; }
|
||||
| INTEGER { $$ = g_new0 (property_t, 1);
|
||||
$$->value_type = G_TYPE_INT; $$->value.i = $1; }
|
||||
| BOOLEAN { $$ = g_new0 (property_t, 1);
|
||||
$$->value_type = G_TYPE_BOOLEAN; $$->value.b = $1; }
|
||||
value: VALUE { $$ = g_new0 (property_t, 1); $$->value = $1; }
|
||||
;
|
||||
|
||||
property_value: id '=' value { $$ = $3; $$->name = $1; }
|
||||
;
|
||||
|
||||
element: id { $$ = g_new0 (element_t, 1); $$->name = $1; }
|
||||
element: id { static int i = 0; $$ = g_new0 (element_t, 1);
|
||||
$$->type = $1; $$->index = ++i; }
|
||||
;
|
||||
|
||||
graph: /* empty */ { $$ = g_new0 (graph_t, 1); }
|
||||
| graph element { GList *l = $$->connections_pending;
|
||||
$$ = $1;
|
||||
graph: /* empty */ { $$ = g_new0 (graph_t, 1); *((graph_t**) pgraph) = $$; }
|
||||
| graph element { GList *l;
|
||||
$$ = $1; l = $$->connections_pending;
|
||||
$$->elements = g_list_append ($$->elements, $2);
|
||||
$$->current = $2;
|
||||
if (!$$->first)
|
||||
$$->first = $$->current;
|
||||
while (l) {
|
||||
((connection_t*) l->data)->sink = $$->current->name;
|
||||
((connection_t*) l->data)->sink_index = $$->current->index;
|
||||
l = g_list_next (l);
|
||||
}
|
||||
if ($$->connections_pending) {
|
||||
|
@ -75,11 +70,27 @@ graph: /* empty */ { $$ = g_new0 (graph_t, 1); }
|
|||
$$->connections_pending = NULL;
|
||||
}
|
||||
}
|
||||
| graph bin { $$ = $1; $$->bins = g_list_append ($$->bins, $2); }
|
||||
| graph connection { $$ = $1; $$->connections = g_list_append ($$->connections, $2);
|
||||
if (!$2->src)
|
||||
$2->src = $$->current->name;
|
||||
if (!$2->sink)
|
||||
| graph bin { GList *l; $$ = $1; l = $$->connections_pending;
|
||||
*((graph_t**) pgraph) = $$;
|
||||
$$->bins = g_list_append ($$->bins, $2);
|
||||
$2->parent = $$;
|
||||
$$->current = $2->first;
|
||||
if (!$$->first)
|
||||
$$->first = $$->current;
|
||||
while (l) {
|
||||
((connection_t*) l->data)->sink_index = $$->current->index;
|
||||
l = g_list_next (l);
|
||||
}
|
||||
if ($$->connections_pending) {
|
||||
g_list_free ($$->connections_pending);
|
||||
$$->connections_pending = NULL;
|
||||
}
|
||||
$$->current = $2->current;
|
||||
}
|
||||
| graph connection { $$ = $1;
|
||||
$$->connections = g_list_append ($$->connections, $2);
|
||||
$2->src_index = $$->current->index;
|
||||
if (!$2->sink_name)
|
||||
$$->connections_pending = g_list_append ($$->connections_pending, $2);
|
||||
}
|
||||
| graph property_value { $$ = $1;
|
||||
|
@ -88,40 +99,19 @@ graph: /* empty */ { $$ = g_new0 (graph_t, 1); }
|
|||
}
|
||||
;
|
||||
|
||||
bin: '{' graph '}' { $$ = $2; $$->current_bin_type = "gstthread"; }
|
||||
bin: '{' graph '}' { $$ = $2; $$->current_bin_type = "thread"; }
|
||||
| id '.' '(' graph ')' { $$ = $4; $$->current_bin_type = $1; }
|
||||
;
|
||||
|
||||
connection: lconnection
|
||||
connection: CONNECTION
|
||||
| rconnection
|
||||
| qconnection
|
||||
| iconnection
|
||||
;
|
||||
|
||||
lconnection: qid '+' '!' { $$ = g_new0 (connection_t, 1);
|
||||
$$->src = $1->id1;
|
||||
$$->src_pads = g_list_append ($$->src_pads, $1->id2);
|
||||
}
|
||||
;
|
||||
|
||||
rconnection: '!' '+' qid { $$ = g_new0 (connection_t, 1);
|
||||
$$->sink = $3->id1;
|
||||
$$->sink_pads = g_list_append ($$->src_pads, $3->id2);
|
||||
}
|
||||
;
|
||||
|
||||
qconnection: qid '+' '!' '+' qid { $$ = g_new0 (connection_t, 1);
|
||||
$$->src = $1->id1;
|
||||
$$->src_pads = g_list_append ($$->src_pads, $1->id2);
|
||||
$$->sink = $5->id1;
|
||||
$$->sink_pads = g_list_append ($$->sink_pads, $5->id2);
|
||||
}
|
||||
;
|
||||
|
||||
iconnection: '!' { $$ = g_new0 (connection_t, 1); }
|
||||
| id '+' iconnection '+' id
|
||||
rconnection: '!' { $$ = g_new0 (connection_t, 1); }
|
||||
| BCONNECTION { $$ = $1; }
|
||||
| id ',' rconnection ',' id
|
||||
{ $$ = $3;
|
||||
$$->src_pads = g_list_append ($$->src_pads, $1);
|
||||
$$->src_pads = g_list_prepend ($$->src_pads, $1);
|
||||
$$->sink_pads = g_list_append ($$->sink_pads, $5);
|
||||
}
|
||||
;
|
||||
|
@ -129,25 +119,47 @@ iconnection: '!' { $$ = g_new0 (connection_t, 1); }
|
|||
%%
|
||||
|
||||
extern FILE *yyin;
|
||||
int _gst_parse_yylex (YYSTYPE *lvalp);
|
||||
|
||||
int
|
||||
static int yylex (void *lvalp) {
|
||||
return _gst_parse_yylex ((YYSTYPE*) lvalp);
|
||||
}
|
||||
|
||||
static int
|
||||
yyerror (const char *s)
|
||||
{
|
||||
printf ("error: %s\n", s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
int yy_scan_string (char*);
|
||||
|
||||
graph_t * _gst_parse_launch (const gchar *str, GError **error)
|
||||
{
|
||||
++argv, --argc; /* skip over program name */
|
||||
if ( argc > 0 )
|
||||
yyin = fopen (argv[0], "r");
|
||||
else
|
||||
yyin = stdin;
|
||||
graph_t *g = NULL;
|
||||
gchar *dstr;
|
||||
|
||||
g_return_val_if_fail (str != NULL, NULL);
|
||||
|
||||
dstr = g_strdup (str);
|
||||
yy_scan_string (dstr);
|
||||
|
||||
#ifdef DEBUG
|
||||
yydebug = 1;
|
||||
#endif
|
||||
|
||||
return yyparse();
|
||||
if (yyparse (&g) != 0) {
|
||||
g_set_error (error,
|
||||
GST_PARSE_ERROR,
|
||||
GST_PARSE_ERROR_SYNTAX,
|
||||
"Invalid syntax");
|
||||
g_free (dstr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_assert (g != NULL);
|
||||
|
||||
g_free (dstr);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
|
|
@ -12,13 +12,19 @@
|
|||
#endif
|
||||
|
||||
#define CHAR(x) PRINT ("char: %c\n", *yytext); return *yytext;
|
||||
|
||||
#define YY_DECL int _gst_parse_yylex (YYSTYPE *lvalp)
|
||||
#define YY_NO_UNPUT
|
||||
%}
|
||||
|
||||
_integer [[:digit:]]+
|
||||
_float [[:digit:]]+"."*[[:digit:]]*
|
||||
_number {_integer}|{_float}
|
||||
_double [[:digit:]]+"."*[[:digit:]]*
|
||||
_number {_integer}|{_double}
|
||||
_boolean "true"|"false"|"TRUE"|"FALSE"
|
||||
_identifier [[:alpha:]][[:alnum:]\-_]*
|
||||
_identifier [[:alpha:]][[:alnum:]\-_%]*
|
||||
_lconnection ({_identifier}\.)?{_identifier}!
|
||||
_rconnection !({_identifier}\.)?{_identifier}
|
||||
_bconnection ({_identifier}\.)?{_identifier}!({_identifier}\.)?{_identifier}
|
||||
_string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"")
|
||||
|
||||
%x value
|
||||
|
@ -29,20 +35,29 @@ _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"")
|
|||
{_integer} {
|
||||
PRINT ("An integer: %s (%d)\n", yytext,
|
||||
atoi (yytext));
|
||||
lvalp->v = g_new0 (GValue, 1);
|
||||
g_value_init (lvalp->v, G_TYPE_INT);
|
||||
g_value_set_int (lvalp->v, atoi (yytext));
|
||||
BEGIN (INITIAL);
|
||||
return INTEGER;
|
||||
return VALUE;
|
||||
}
|
||||
|
||||
{_float} {
|
||||
PRINT ("A float: %s (%g)\n", yytext, atof (yytext));
|
||||
{_double} {
|
||||
PRINT ("A double: %s (%g)\n", yytext, atof (yytext));
|
||||
lvalp->v = g_new0 (GValue, 1);
|
||||
g_value_init (lvalp->v, G_TYPE_DOUBLE);
|
||||
g_value_set_double (lvalp->v, atof (yytext));
|
||||
BEGIN (INITIAL);
|
||||
return FLOAT;
|
||||
return VALUE;
|
||||
}
|
||||
|
||||
{_boolean} {
|
||||
PRINT ("A boolean: %s (%d)\n", yytext, tolower (*yytext) == 't' ? 1 : 0);
|
||||
lvalp->v = g_new0 (GValue, 1);
|
||||
g_value_init (lvalp->v, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (lvalp->v, tolower (*yytext) == 't' ? TRUE : FALSE);
|
||||
BEGIN (INITIAL);
|
||||
return BOOLEAN;
|
||||
return VALUE;
|
||||
}
|
||||
|
||||
{_string} {
|
||||
|
@ -50,20 +65,80 @@ _string ([^[:space:]\"]|"\\\"")+|("\""([^\"]|"\\\"")*"\"")
|
|||
yytext++;
|
||||
*(yytext + strlen (yytext) - 1) = '\0';
|
||||
}
|
||||
PRINT ("A string: %s\n", yytext);
|
||||
PRINT ("A string: \"%s\"\n", yytext);
|
||||
lvalp->v = g_new0 (GValue, 1);
|
||||
g_value_init (lvalp->v, G_TYPE_STRING);
|
||||
g_value_set_string (lvalp->v, yytext);
|
||||
BEGIN (INITIAL);
|
||||
return STRING;
|
||||
return VALUE;
|
||||
}
|
||||
|
||||
[[:space:]]+ { /* PRINT ("space: [%s]\n", yytext); */ }
|
||||
|
||||
. {
|
||||
PRINT ("unknown: %s\n", yytext);
|
||||
return *yytext;
|
||||
}
|
||||
}
|
||||
|
||||
{_lconnection} {
|
||||
gchar *d1, *q;
|
||||
lvalp->c = g_new0 (connection_t, 1);
|
||||
PRINT ("An connection: %s\n", yytext);
|
||||
q = strchr (yytext, '!');
|
||||
d1 = strchr (yytext, '.');
|
||||
if (d1) {
|
||||
lvalp->c->src_name = g_strndup (yytext, d1 - yytext);
|
||||
lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (d1 + 1, q - d1 - 1));
|
||||
} else {
|
||||
lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (yytext, q - yytext));
|
||||
}
|
||||
|
||||
return CONNECTION;
|
||||
}
|
||||
|
||||
{_rconnection} {
|
||||
gchar *d2;
|
||||
lvalp->c = g_new0 (connection_t, 1);
|
||||
PRINT ("An rconnection: %s\n", yytext);
|
||||
d2 = strchr (yytext, '.');
|
||||
if (d2) {
|
||||
lvalp->c->sink_name = g_strndup (yytext + 1, d2 - yytext - 1);
|
||||
lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (d2 + 1));
|
||||
} else {
|
||||
lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (yytext + 1));
|
||||
}
|
||||
|
||||
return CONNECTION;
|
||||
}
|
||||
|
||||
{_bconnection} {
|
||||
gchar *d1, *d2, *q;
|
||||
lvalp->c = g_new0 (connection_t, 1);
|
||||
PRINT ("A bconnection: %s\n", yytext);
|
||||
q = strchr (yytext, '!');
|
||||
d1 = strchr (yytext, '.');
|
||||
d2 = strchr (q, '.');
|
||||
if (d1 && d1 < q) {
|
||||
lvalp->c->src_name = g_strndup (yytext, d1 - yytext);
|
||||
lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (d1 + 1, q - d1 - 1));
|
||||
} else {
|
||||
lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (yytext, q - yytext));
|
||||
}
|
||||
|
||||
if (d2) {
|
||||
lvalp->c->sink_name = g_strndup (q + 1, d2 - q - 1);
|
||||
lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (d2 + 1));
|
||||
} else {
|
||||
lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (q + 1));
|
||||
}
|
||||
|
||||
return BCONNECTION;
|
||||
}
|
||||
|
||||
{_identifier} {
|
||||
PRINT ("An identifier: %s\n", yytext);
|
||||
lvalp->s = g_strdup (yytext);
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,38 +1,43 @@
|
|||
#include <glib-object.h>
|
||||
#include "../gstelement.h"
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
gchar *type;
|
||||
gint index;
|
||||
GList *property_values;
|
||||
GstElement *element;
|
||||
} element_t;
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
GType value_type;
|
||||
union {
|
||||
gdouble d;
|
||||
gboolean b;
|
||||
gint i;
|
||||
gchar *s;
|
||||
} value;
|
||||
GValue *value;
|
||||
} property_t;
|
||||
|
||||
typedef struct {
|
||||
char *src;
|
||||
char *sink;
|
||||
/* if the names are present, upon connection we'll search out the pads of the
|
||||
proper name and use those. otherwise, we'll search for elements of src_index
|
||||
and sink_index. */
|
||||
char *src_name;
|
||||
char *sink_name;
|
||||
int src_index;
|
||||
int sink_index;
|
||||
GList *src_pads;
|
||||
GList *sink_pads;
|
||||
} connection_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct _graph_t graph_t;
|
||||
|
||||
struct _graph_t {
|
||||
element_t *first;
|
||||
element_t *current;
|
||||
graph_t *parent;
|
||||
gchar *current_bin_type;
|
||||
GList *elements;
|
||||
GList *connections;
|
||||
GList *connections_pending;
|
||||
GList *bins;
|
||||
} graph_t;
|
||||
GstElement *bin;
|
||||
};
|
||||
|
||||
graph_t * _gst_parse_launch (const gchar *str, GError **error);
|
||||
|
||||
typedef struct {
|
||||
gchar *id1;
|
||||
gchar *id2;
|
||||
} hash_t;
|
||||
|
|
|
@ -44,23 +44,18 @@ main(int argc,char *argv[])
|
|||
sink = gst_elementfactory_make ("fakesink", "sink");
|
||||
g_return_val_if_fail (sink != NULL, 4);
|
||||
|
||||
gst_bin_add (pipeline, GST_ELEMENT (src));
|
||||
gst_bin_add (pipeline, GST_ELEMENT (tee));
|
||||
gst_bin_add (pipeline, GST_ELEMENT (identity1));
|
||||
gst_bin_add (pipeline, GST_ELEMENT (identity2));
|
||||
gst_bin_add (pipeline, GST_ELEMENT (aggregator));
|
||||
gst_bin_add (pipeline, GST_ELEMENT (sink));
|
||||
gst_bin_add_many (pipeline, src, tee, identity1, identity2, aggregator, sink, NULL);
|
||||
|
||||
gst_element_connect (src, "src", tee, "sink");
|
||||
gst_pad_connect (gst_element_request_pad_by_name (tee, "src%d"),
|
||||
gst_element_connect_pads (src, "src", tee, "sink");
|
||||
gst_pad_connect (gst_element_get_request_pad (tee, "src%d"),
|
||||
gst_element_get_pad (identity1, "sink"));
|
||||
gst_pad_connect (gst_element_request_pad_by_name (tee, "src%d"),
|
||||
gst_pad_connect (gst_element_get_request_pad (tee, "src%d"),
|
||||
gst_element_get_pad (identity2, "sink"));
|
||||
gst_pad_connect (gst_element_get_pad (identity1, "src"),
|
||||
gst_element_request_pad_by_name (aggregator, "sink%d"));
|
||||
gst_element_get_request_pad (aggregator, "sink%d"));
|
||||
gst_pad_connect (gst_element_get_pad (identity2, "src"),
|
||||
gst_element_request_pad_by_name (aggregator, "sink%d"));
|
||||
gst_element_connect (aggregator, "src", sink, "sink");
|
||||
gst_element_get_request_pad (aggregator, "sink%d"));
|
||||
gst_element_connect_pads (aggregator, "src", sink, "sink");
|
||||
|
||||
g_signal_connect (G_OBJECT (src), "eos",
|
||||
G_CALLBACK (eos_signal), NULL);
|
||||
|
|
|
@ -19,7 +19,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
|
||||
/* disconnect the typefind from the pipeline and remove it */
|
||||
gst_element_disconnect (cache, "src", typefind, "sink");
|
||||
gst_element_disconnect_pads (cache, "src", typefind, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), typefind);
|
||||
|
||||
/* and an audio sink */
|
||||
|
@ -34,7 +34,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
colorspace = gst_elementfactory_make ("colorspace", "colorspace");
|
||||
g_assert (colorspace != NULL);
|
||||
|
||||
gst_element_connect (colorspace, "src", videoelement, "sink");
|
||||
gst_element_connect_pads (colorspace, "src", videoelement, "sink");
|
||||
gst_bin_add (GST_BIN (videosink), colorspace);
|
||||
gst_bin_add (GST_BIN (videosink), videoelement);
|
||||
|
||||
|
@ -61,7 +61,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
|
||||
g_object_set (G_OBJECT (cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect (cache, "src", new_element, "sink");
|
||||
gst_element_connect_pads (cache, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
|
@ -87,10 +87,9 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline)
|
|||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
|
||||
|
||||
gst_element_disconnect (filesrc, "src", cache, "sink");
|
||||
gst_element_disconnect (cache, "src", new_element, "sink");
|
||||
gst_element_disconnect_many (filesrc, cache, new_element, NULL);
|
||||
gst_bin_remove (GST_BIN (autobin), cache);
|
||||
gst_element_connect (filesrc, "src", new_element, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
|
@ -132,11 +131,11 @@ int main(int argc,char *argv[])
|
|||
gst_bin_add (GST_BIN (autobin), cache);
|
||||
gst_bin_add (GST_BIN (autobin), typefind);
|
||||
|
||||
gst_element_connect (cache, "src", typefind, "sink");
|
||||
gst_element_connect_pads (cache, "src", typefind, "sink");
|
||||
gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
|
||||
|
||||
gst_bin_add (GST_BIN( pipeline), autobin);
|
||||
gst_element_connect (filesrc, "src", autobin, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", autobin, "sink");
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
|
|
@ -22,7 +22,7 @@ int main (int argc, char *argv[])
|
|||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
||||
/* now it's time to get the decoder */
|
||||
decoder = gst_elementfactory_make ("mad", "parse");
|
||||
decoder = gst_elementfactory_make ("mad", "decode");
|
||||
if (!decoder) {
|
||||
g_print ("could not find plugin \"mad\"");
|
||||
return -1;
|
||||
|
@ -35,7 +35,7 @@ int main (int argc, char *argv[])
|
|||
gst_bin_add_many (GST_BIN (bin), filesrc, decoder, osssink, NULL);
|
||||
|
||||
/* connect the elements */
|
||||
gst_element_connect_elements_many (filesrc, decoder, osssink, NULL);
|
||||
gst_element_connect_many (filesrc, decoder, osssink, NULL);
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state (bin, GST_STATE_PLAYING);
|
||||
|
|
|
@ -18,8 +18,8 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
|
||||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
|
||||
/* disconnect the typefind from the pipeline and remove it */
|
||||
gst_element_disconnect (cache, "src", typefind, "sink");
|
||||
/* disconnect_pads the typefind from the pipeline and remove it */
|
||||
gst_element_disconnect_pads (cache, "src", typefind, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), typefind);
|
||||
|
||||
/* and an audio sink */
|
||||
|
@ -45,7 +45,7 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
|||
|
||||
g_object_set (G_OBJECT (cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect (cache, "src", new_element, "sink");
|
||||
gst_element_connect_pads (cache, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
}
|
||||
|
@ -67,10 +67,10 @@ gst_play_cache_empty (GstElement *element, GstElement *pipeline)
|
|||
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
|
||||
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
|
||||
|
||||
gst_element_disconnect (filesrc, "src", cache, "sink");
|
||||
gst_element_disconnect (cache, "src", new_element, "sink");
|
||||
gst_element_disconnect_pads (filesrc, "src", cache, "sink");
|
||||
gst_element_disconnect_pads (cache, "src", new_element, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), cache);
|
||||
gst_element_connect (filesrc, "src", new_element, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", new_element, "sink");
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
|
@ -114,11 +114,11 @@ main (int argc, char *argv[])
|
|||
gst_bin_add (GST_BIN (autobin), cache);
|
||||
gst_bin_add (GST_BIN (autobin), typefind);
|
||||
|
||||
gst_element_connect (cache, "src", typefind, "sink");
|
||||
gst_element_connect_pads (cache, "src", typefind, "sink");
|
||||
gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
|
||||
|
||||
gst_bin_add (GST_BIN( pipeline), autobin);
|
||||
gst_element_connect (filesrc, "src", autobin, "sink");
|
||||
gst_element_connect_pads (filesrc, "src", autobin, "sink");
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
|
|
@ -5,6 +5,7 @@ main (int argc, char *argv[])
|
|||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *filesrc;
|
||||
GError *error = NULL;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
|
@ -13,7 +14,11 @@ main (int argc, char *argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
pipeline = (GstElement*) gst_parse_launch ("filesrc [ my_filesrc ] ! mad ! osssink");
|
||||
pipeline = (GstElement*) gst_parse_launch ("filesrc name=my_filesrc ! mad ! osssink", &error);
|
||||
if (!pipeline) {
|
||||
fprintf (stderr, "Parse error: %s", error->message);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_filesrc");
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
|
|
@ -40,7 +40,7 @@ void eos(GstElement *element)
|
|||
/* playing = FALSE; */
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
G_GNUC_UNUSED static GstCaps*
|
||||
gst_play_typefind (GstBin *bin, GstElement *element)
|
||||
{
|
||||
GstElement *typefind;
|
||||
|
@ -140,7 +140,7 @@ int main(int argc,char *argv[])
|
|||
|
||||
/* request pads and connect to adder */
|
||||
GST_INFO (0, "requesting pad\n");
|
||||
pad = gst_element_request_pad_by_name (adder, "sink%d");
|
||||
pad = gst_element_get_request_pad (adder, "sink%d");
|
||||
printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
|
||||
sprintf (buffer, "channel%d", i);
|
||||
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
|
||||
|
@ -237,8 +237,8 @@ create_input_channel (int id, char* location)
|
|||
|
||||
char buffer[20]; /* hold the names */
|
||||
|
||||
GstAutoplug *autoplug;
|
||||
GstCaps *srccaps;
|
||||
/* GstAutoplug *autoplug;
|
||||
GstCaps *srccaps; */
|
||||
GstElement *new_element;
|
||||
GstElement *decoder;
|
||||
|
||||
|
@ -364,8 +364,8 @@ create_input_channel (int id, char* location)
|
|||
gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
|
||||
gst_bin_add (GST_BIN (channel->pipe), new_element);
|
||||
|
||||
gst_element_connect (channel->filesrc, "src", new_element, "sink");
|
||||
gst_element_connect (new_element, "src_00", channel->volenv, "sink");
|
||||
gst_element_connect_pads (channel->filesrc, "src", new_element, "sink");
|
||||
gst_element_connect_pads (new_element, "src_00", channel->volenv, "sink");
|
||||
|
||||
/* add a ghost pad */
|
||||
sprintf (buffer, "channel%d", id);
|
||||
|
|
|
@ -19,7 +19,7 @@ object_saved (GstObject *object, xmlNodePtr parent, gpointer data)
|
|||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
GstElement *filesrc, *osssink, *queue, *queue2, *parse, *decode;
|
||||
GstElement *filesrc, *osssink, *queue, *queue2, *decode;
|
||||
GstElement *pipeline;
|
||||
GstElement *thread, *thread2;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
gboolean playing;
|
||||
|
||||
static void
|
||||
G_GNUC_UNUSED static void
|
||||
xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data)
|
||||
{
|
||||
xmlNodePtr children = self->xmlChildrenNode;
|
||||
|
|
|
@ -25,7 +25,7 @@ int main (int argc, char *argv[])
|
|||
/* make the first pipeline */
|
||||
gst_bin_add (GST_BIN(pipe1), fakesrc);
|
||||
gst_bin_add (GST_BIN(pipe1), fakesink1);
|
||||
gst_element_connect(fakesrc, "src", fakesink1, "sink");
|
||||
gst_element_connect_pads (fakesrc, "src", fakesink1, "sink");
|
||||
|
||||
/* initialize cothreads */
|
||||
gst_element_set_state(pipe1, GST_STATE_PLAYING);
|
||||
|
@ -33,7 +33,7 @@ int main (int argc, char *argv[])
|
|||
gst_element_set_state(pipe1, GST_STATE_READY);
|
||||
|
||||
/* destroy the fakesink, but keep fakesrc (its state is GST_STATE_READY) */
|
||||
gst_element_disconnect(fakesrc, "src", fakesink1, "sink");
|
||||
gst_element_disconnect_pads (fakesrc, "src", fakesink1, "sink");
|
||||
gst_object_ref(GST_OBJECT(fakesrc));
|
||||
gst_bin_remove(GST_BIN(pipe1), fakesrc);
|
||||
gst_bin_remove(GST_BIN(pipe1), fakesink1);
|
||||
|
@ -44,7 +44,7 @@ int main (int argc, char *argv[])
|
|||
|
||||
/* don't change the new pipeline's state, it should change on the bin_add */
|
||||
gst_bin_add (GST_BIN(pipe2), fakesrc);
|
||||
gst_element_connect(fakesrc, "src", fakesink2, "sink");
|
||||
gst_element_connect_pads (fakesrc, "src", fakesink2, "sink");
|
||||
|
||||
/* show the pipeline state */
|
||||
gst_xml_write_file (GST_ELEMENT (pipe2), stdout);
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
static int launch_argc;
|
||||
static char **launch_argv;
|
||||
|
||||
static guint64 iterations = 0;
|
||||
static guint64 sum = 0;
|
||||
static guint64 min = G_MAXINT;
|
||||
|
@ -134,43 +131,36 @@ main(int argc, char *argv[])
|
|||
{
|
||||
/* options */
|
||||
gboolean silent = FALSE;
|
||||
gchar *savefile = NULL;
|
||||
struct poptOption options[] = {
|
||||
{"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0, "do not output status information", NULL},
|
||||
{"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0,
|
||||
"do not output status information", NULL},
|
||||
{"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0,
|
||||
"save xml representation of pipeline to FILE and exit", "FILE"},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
GstElement *pipeline;
|
||||
gchar **argvn;
|
||||
gboolean save_pipeline = FALSE;
|
||||
gboolean run_pipeline = TRUE;
|
||||
gchar *savefile = "";
|
||||
GError *error = NULL;
|
||||
|
||||
free (malloc (8)); /* -lefence */
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
|
||||
if (argc >= 3 && !strcmp(argv[1], "-o")) {
|
||||
save_pipeline = TRUE;
|
||||
run_pipeline = FALSE;
|
||||
savefile = argv[2];
|
||||
argv[2] = argv[0];
|
||||
argv+=2;
|
||||
argc-=2;
|
||||
}
|
||||
|
||||
launch_argc = argc;
|
||||
launch_argv = argv;
|
||||
|
||||
/* make a null-terminated version of argv */
|
||||
argvn = g_new0 (char*, argc);
|
||||
memcpy (argvn, argv+1, sizeof (char*) * (argc-1));
|
||||
if (strstr (argv[0], "gst-xmllaunch")) {
|
||||
pipeline = xmllaunch_parse_cmdline ((const gchar**)argvn);
|
||||
} else {
|
||||
pipeline = (GstElement*) gst_parse_launchv ((const gchar **) argvn);
|
||||
pipeline = (GstElement*) gst_parse_launchv ((const gchar**)argvn, &error);
|
||||
}
|
||||
|
||||
if (!pipeline) {
|
||||
if (error)
|
||||
fprintf(stderr, "ERROR: pipeline could not be constructed: %s\n", error->message);
|
||||
else
|
||||
fprintf(stderr, "ERROR: pipeline could not be constructed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -180,12 +170,12 @@ main(int argc, char *argv[])
|
|||
g_signal_connect (pipeline, "error", G_CALLBACK (error_callback), NULL);
|
||||
|
||||
#ifndef GST_DISABLE_LOADSAVE
|
||||
if (save_pipeline) {
|
||||
if (savefile) {
|
||||
gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (run_pipeline) {
|
||||
if (!savefile) {
|
||||
gst_buffer_print_stats();
|
||||
fprintf(stderr,"RUNNING pipeline\n");
|
||||
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {
|
||||
|
|
Loading…
Reference in a new issue