docs/manual/: Update (until threads/scheduling) Application Development Manual; remove GstThread, add GstBus, add sim...

Original commit message from CVS:
* docs/manual/advanced-clocks.xml:
* docs/manual/advanced-interfaces.xml:
* docs/manual/advanced-metadata.xml:
* docs/manual/advanced-position.xml:
* docs/manual/advanced-schedulers.xml:
* docs/manual/advanced-threads.xml:
* docs/manual/appendix-porting.xml:
* docs/manual/basics-bins.xml:
* docs/manual/basics-bus.xml:
* docs/manual/basics-elements.xml:
* docs/manual/basics-helloworld.xml:
* docs/manual/basics-pads.xml:
* docs/manual/highlevel-components.xml:
* docs/manual/manual.xml:
* docs/manual/thread.fig:
Update (until threads/scheduling) Application Development Manual;
remove GstThread, add GstBus, add simple porting checklist, add
documentation for tag writing, clocks, make all examples until this
part compile and run.
* examples/manual/Makefile.am:
Update from changes to Application Development Manual; add bus
example, remove thread example.
This commit is contained in:
Ronald S. Bultje 2005-06-29 09:25:51 +00:00
parent bd72354e9a
commit 2abdd0bfda
18 changed files with 725 additions and 596 deletions

View file

@ -1,3 +1,28 @@
2005-06-29 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* docs/manual/advanced-clocks.xml:
* docs/manual/advanced-interfaces.xml:
* docs/manual/advanced-metadata.xml:
* docs/manual/advanced-position.xml:
* docs/manual/advanced-schedulers.xml:
* docs/manual/advanced-threads.xml:
* docs/manual/appendix-porting.xml:
* docs/manual/basics-bins.xml:
* docs/manual/basics-bus.xml:
* docs/manual/basics-elements.xml:
* docs/manual/basics-helloworld.xml:
* docs/manual/basics-pads.xml:
* docs/manual/highlevel-components.xml:
* docs/manual/manual.xml:
* docs/manual/thread.fig:
Update (until threads/scheduling) Application Development Manual;
remove GstThread, add GstBus, add simple porting checklist, add
documentation for tag writing, clocks, make all examples until this
part compile and run.
* examples/manual/Makefile.am:
Update from changes to Application Development Manual; add bus
example, remove thread example.
2005-06-28 Wim Taymans <wim@fluendo.com>
* gst/gstbus.c: (gst_bus_post), (gst_bus_have_pending),

View file

@ -1,7 +1,63 @@
<chapter id="chapter-clocks">
<title>Clocks in GStreamer</title>
<para>
WRITEME
<para>
To maintain sync in pipeline playback (which is the only case where this
really matters), &GStreamer; uses <emphasis>clocks</emphasis>. Clocks
are exposed by some elements, whereas other elements are merely clock
slaves. The primary task of a clock is to represent the time progress
according to the element exposing the clock, based on its own playback
rate. If no clock provider is available in a pipeline, the system clock
is used instead.
</para>
<sect1 id="section-clocks-providers">
<title>Clock providers</title>
<para>
Clock providers exist because they play back media at some rate, and
this rate is not necessarily the same as the system clock rate. For
example, a soundcard may playback at 44,1 kHz, but that doesn't mean
that after <emphasis>exactly</emphasis> 1 second <emphasis>according
to the system clock</emphasis>, the soundcard has played back 44.100
samples. This is only true by approximation. Therefore, generally,
pipelines with an audio output use the audiosink as clock provider.
This ensures that one second of video will be played back at the same
rate as that the soundcard plays back 1 second of audio.
</para>
<para>
Whenever some part of the pipeline requires to know the current clock
time, it will be requested from the clock through
<function>gst_clock_get_time ()</function>. The clock-time does not
need to start at 0. The pipeline, which contains the global clock that
all elements in the pipeline will use, in addition has a <quote>base
time</quote>, which is the clock time at the the point where media time
is starting from zero. This timestamp is subctracted from the clock
time, and that value is returned by <function>_get_time ()</function>.
</para>
<para>
The clock provider is responsible for making sure that the clock time
always represents the current media time as closely as possible; it
has to take care of things such as playback latencies, buffering in
audio-kernel modules, and so on, since all those could affect a/v sync
and thus decrease the user experience.
</para>
</sect1>
<sect1 id="section-clocks-slaves">
<title>Clock slaves</title>
<para>
Clock slaves get assigned a clock by their containing pipeline. Their
task is to make sure that media playback follows the time progress as
represented by this clock as closely as possible. For most elements,
that will simply mean to wait until a certain time is reached before
playing back their current sample; this can be done with the function
<function>gst_clock_id_wait ()</function>. Some elements may need to
support dropping samples too, however.
</para>
<para>
For more information on how to write elements that conform to this
required behaviour, see the Plugin Writer's Guide.
</para>
</sect1>
</chapter>

View file

@ -16,6 +16,31 @@
scope and purpose of each interface.
</para>
<sect1 id="section-interfaces-uri">
<title>The URI interface</title>
<para>
In all examples so far, we have only supported local files through the
<quote>filesrc</quote> element. &GStreamer;, obviously, supports many
more location sources. However, we don't want applications to need to
know any particular element implementation details, such as element
names for particular network source types and so on. Therefore, there
is a URI interface, which can be used to get the source element that
supports a particular URI type. There is no strict rule for URI naming,
but in general we follow naming conventions that others use, too. For
example, assuming you have the correct plugins installed, &GStreamer;
supports <quote>file:///&lt;path&gt;/&lt;file&gt;</quote>,
<quote>http://&lt;host&gt;/&lt;path&gt;/&lt;file&gt;</quote>,
<quote>mms://&lt;host&gt;/&lt;path&gt;/&lt;file&gt;</quote>, and so on.
</para>
<para>
In order to get the source or sink element supporting a particular URI,
use <function>gst_element_make_from_uri ()</function>, with the URI
type being either <classname>GST_URI_SRC</classname> for a source
element, or <classname>GST_URI_SINK</classname> for a sink element.
</para>
</sect1>
<sect1 id="section-interfaces-mixer">
<title>The Mixer interface</title>

View file

@ -13,34 +13,34 @@
<classname>GstPad</classname>.
</para>
<sect1 id="section-streaminfo">
<title>Stream information</title>
<sect1 id="section-tags-read">
<title>Metadata reading</title>
<para>
Stream information can most easily be read by reading them from a
<classname>GstPad</classname>. This has already been discussed before
in <xref linkend="section-caps-metadata"/>. Therefore, we will skip
it here.
it here. Note that this requires access to all pads of which you
want stream information.
</para>
</sect1>
<sect1 id="section-tags-read">
<title>Tag reading</title>
<para>
Tag reading is remarkably simple in &GStreamer; Every element supports
the <quote>found-tag</quote> signal, which will be fired each the time
the element reads tags from the stream. A <classname>GstBin</classname>
will conveniently forward tags found by its childs. Therefore, in most
applications, you will only need to connect to the
<quote>found-tag</quote> signal on the top-most bin in your pipeline,
and you will automatically retrieve all tags from the stream.
Tag reading is done through a bus in &GStreamer;, which has been
discussed previously in <xref linkend="chapter-bus"/>. You can
listen for <classname>GST_MESSAGE_TAG</classname> messages and handle
them as you wish.
</para>
<para>
Note, however, that the <quote>found-tag</quote> might be fired
multiple times and by multiple elements in the pipeline. It is the
Note, however, that the <classname>GST_MESSAGE_TAG</classname>
message may be fired multiple times in the pipeline. It is the
application's responsibility to put all those tags together and
display them to the user in a nice, coherent way.
display them to the user in a nice, coherent way. Usually, using
<function>gst_tag_list_merge ()</function> is a good enough way
of doing this; make sure to empty the cache when loading a new song,
or after every few minutes when listening to internet radio. Also,
make sure you use <classname>GST_TAG_MERGE_PREPEND</classname> as
merging mode, so that a new title (which came in later) has a
preference over the old one for display.
</para>
</sect1>
@ -48,7 +48,22 @@
<title>Tag writing</title>
<para>
WRITEME
Tag writing is done using the <classname>GstTagSetter</classname>
interface. All that's required is a tag-set-supporting element in
your pipeline. In order to see if any of the elements in your
pipeline supports tag writing, you can use the function
<function>gst_bin_iterate_all_by_interface (pipeline,
GST_TYPE_TAG_SETTER)</function>. On the resulting element, usually
an encoder or muxer, you can use <function>gst_tag_setter_merge
()</function> (with a taglist) or <function>gst_tag_setter_add
()</function> (with individual tags) to set tags on it.
</para>
<para>
A nice extra feature in &GStreamer; tag support is that tags are
preserved in pipelines. This means that if you transcode one file
containing tags into another media type, and that new media type
supports tags too, then the tags will be handled as part of the
data stream and be merged into the newly written media file, too.
</para>
</sect1>
</chapter>

View file

@ -3,15 +3,15 @@
<para>
So far, we've looked at how to create a pipeline to do media processing
and how to make it run ("iterate"). Most application developers will be
interested in providing feedback to the user on media progress. Media
players, for example, will want to show a slider showing the progress in
the song, and usually also a label indicating stream length. Transcoding
applications will want to show a progress bar on how much % of the task
is done. &GStreamer; has built-in support for doing all this using a
concept known as <emphasis>querying</emphasis>. Since seeking is very
similar, it will be discussed here as well. Seeking is done using the
concept of <emphasis>events</emphasis>.
and how to make it run. Most application developers will be interested
in providing feedback to the user on media progress. Media players, for
example, will want to show a slider showing the progress in the song,
and usually also a label indicating stream length. Transcoding
applications will want to show a progress bar on how much percent of
the task is done. &GStreamer; has built-in support for doing all this
using a concept known as <emphasis>querying</emphasis>. Since seeking
is very similar, it will be discussed here as well. Seeking is done
using the concept of <emphasis>events</emphasis>.
</para>
<sect1 id="section-querying">
@ -22,42 +22,82 @@
to progress tracking. This includes getting the length of a stream (if
available) or getting the current position. Those stream properties
can be retrieved in various formats such as time, audio samples, video
frames or bytes. The functions used are <function>gst_element_query
()</function> and <function>gst_pad_query ()</function>.
frames or bytes. The function most commonly used for this is
<function>gst_element_query ()</function>, although some convenience
wrappers are provided as well (such as
<function>gst_element_query_position ()</function>). You can generally
query the pipeline directly, it'll figure out the internal details
for you, like which element to query.
</para>
<para>
Obviously, using either of the above-mentioned functions requires the
application to know <emphasis>which</emphasis> element or pad to run
the query on. This is tricky, but there are some good sides to the
story. The good thing is that elements (or, rather, pads - since
<function>gst_element_query ()</function> internally calls
<function>gst_pad_query ()</function>) forward (<quote>dispatch</quote>)
events and queries to peer pads (or elements) if they don't handle it
themselves. The bad side is that some elements (or pads) will handle
events, but not the specific formats that you want, and therefore it
still won't work.
</para>
<para>
Most queries will, fortunately, work fine. Queries are always
dispatched backwards. This means, effectively, that it's easiest to
run the query on your video or audio output element, and it will take
care of dispatching the query to the element that knows the answer
(such as the current position or the media length; usually the demuxer
or decoder).
Internally, queries will be sent to the sinks, and
<quote>dispatched</quote> backwards until one element can handle it;
that result will be sent back to the function caller. Usually, that
is the demuxer, although with live sources (from a webcam), it is the
source itself.
</para>
<programlisting><!-- example-begin query.c a -->
#include &lt;gst/gst.h&gt;
<!-- example-end query.c a -->
<!-- example-begin query.c b --><!--
static gboolean
my_bus_callback (GstBus *bus,
GstMessage *message,
gpointer data)
{
GMainLoop *loop = data;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR: {
GError *err;
gchar *debug;
gst_message_parse_error (message, &amp;err, &amp;debug);
g_print ("Error: %s\n", err-&gt;message);
g_error_free (err);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
g_main_loop_quit (loop);
break;
default:
break;
}
/* remove from queue */
return TRUE;
}
--><!-- example-end query.c b -->
<!-- example-begin query.c c -->
static gboolean
cb_print_position (GstElement *pipeline)
{
GstFormat fmt = GST_FORMAT_TIME;
gint64 pos, len;
if (gst_element_query_position (pipeline, &amp;fmt, &amp;pos, &amp;len)) {
g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
GST_TIME_ARGS (pos), GST_TIME_ARGS (len));
}
/* call me again */
return TRUE;
}
gint
main (gint argc,
gchar *argv[])
{
GstElement *sink, *pipeline;
<!-- example-end query.c a -->
[..]<!-- example-begin query.c b --><!--
GstElement *pipeline;
<!-- example-end query.c c -->
[..]<!-- example-begin query.c d --><!--
GMainLoop *loop;
gchar *l;
/* init */
@ -71,45 +111,32 @@ main (gint argc,
/* build pipeline, the easy way */
l = g_strdup_printf ("filesrc location=\"%s\" ! oggdemux ! vorbisdec ! "
"audioconvert ! audioscale ! alsasink name=a",
"audioconvert ! audioscale ! alsasink",
argv[1]);
pipeline = gst_parse_launch (l, NULL);
sink = gst_bin_get_by_name (GST_BIN (pipeline), "a");
g_free (l);
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
my_bus_callback, NULL);
/* play */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
--><!-- example-end query.c b -->
<!-- example-begin query.c c -->
loop = g_main_loop_new (NULL, FALSE);
--><!-- example-end query.c d -->
<!-- example-begin query.c e -->
/* run pipeline */
do {
gint64 len, pos;
GstFormat fmt = GST_FORMAT_TIME;
if (gst_element_query (sink, GST_QUERY_POSITION, &amp;fmt, &amp;pos) &amp;&amp;
gst_element_query (sink, GST_QUERY_TOTAL, &amp;fmt, &amp;len)) {
g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
GST_TIME_ARGS (pos), GST_TIME_ARGS (len));
}
} while (gst_bin_iterate (GST_BIN (pipeline)));
<!-- example-end query.c c -->
[..]<!-- example-begin query.c d --><!--
g_timeout_add (200, (GSourceFunc) cb_print_position, pipeline);
g_main_loop_run (loop);
<!-- example-end query.c e -->
[..]<!-- example-begin query.c f --><!--
/* clean up */
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
return 0;
--><!-- example-end query.c d -->
<!-- example-begin query.c e -->
--><!-- example-end query.c f -->
<!-- example-begin query.c g -->
}
<!-- example-end query.c e --></programlisting>
<para>
If you are having problems with the dispatching behaviour, your best
bet is to manually decide which element to start running the query on.
You can get a list of supported formats and query-types with
<function>gst_element_get_query_types ()</function> and
<function>gst_element_get_formats ()</function>.
</para>
<!-- example-end query.c g --></programlisting>
</sect1>
<sect1 id="section-eventsseek">
@ -118,27 +145,39 @@ main (gint argc,
<para>
Events work in a very similar way as queries. Dispatching, for
example, works exactly the same for events (and also has the same
limitations). Although there are more ways in which applications
and elements can interact using events, we will only focus on seeking
here. This is done using the seek-event. A seek-event contains a
seeking offset, a seek method (which indicates relative to what the
offset was given), a seek format (which is the unit of the offset,
e.g. time, audio samples, video frames or bytes) and optionally a
set of seeking-related flags (e.g. whether internal buffers should be
flushed). The behaviour of a seek is also wrapped in the function
<function>gst_element_seek ()</function>.
limitations), and they can similarly be sent to the toplevel pipeline
and it will figure out everything for you. Although there are more
ways in which applications and elements can interact using events,
we will only focus on seeking here. This is done using the seek-event.
A seek-event contains a seeking offset, a seek method (which indicates
relative to what the offset was given), a seek format (which is the
unit of the offset, e.g. time, audio samples, video frames or bytes)
and optionally a set of seeking-related flags (e.g. whether internal
buffers should be flushed). The behaviour of a seek is also wrapped
in the function <function>gst_element_seek ()</function>.
</para>
<programlisting>
static void
seek_to_time (GstElement *audiosink,
gint64 time_nanonseconds)
seek_to_time (GstElement *pipeline,
gint64 time_nanoseconds)
{
gst_element_seek (audiosink,
gst_element_seek (pipeline,
GST_SEEK_METHOD_SET | GST_FORMAT_TIME |
GST_SEEK_FLAG_FLUSH, time_nanoseconds);
}
</programlisting>
<para>
It is possible to do multiple seeks in short time-intervals, such as
a direct response to slider movement. After a seek, internally, the
pipeline will be paused (if it was playing), the position will be
re-set internally, the demuxers and decoders will decode from the new
position onwards and this will continue until all sinks have data
again. If it was playing originally, it will be set to playing again,
too. Since the new position is immediately available in a video output,
you will see the new frame, even if your pipeline is not in the playing
state.
</para>
</sect1>
</chapter>

View file

@ -1,152 +0,0 @@
<chapter id="chapter-scheduler">
<title>Scheduling</title>
<para>
By now, you've seen several example applications. All of them would set
up a pipeline and call <function>gst_bin_iterate ()</function> to start
media processing. You might have started wondering what happens during
pipeline iteration. This whole process of media processing is called
scheduling. Scheduling is considered one of the most complex parts of
&GStreamer;. Here, we will do no more than give a global overview of
scheduling, most of which will be purely informative. It might help in
understanding the underlying parts of &GStreamer;.
</para>
<para>
The scheduler is responsible for managing the plugins at runtime. Its
main responsibilities are:
<itemizedlist>
<listitem>
<para>
Managing data throughput between pads and elements in a pipeline.
This might sometimes imply temporary data storage between elements.
</para>
</listitem>
<listitem>
<para>
Calling functions in elements that do the actual data processing.
</para>
</listitem>
<listitem>
<para>
Monitoring state changes and enabling/disabling elements in the
chain.
</para>
</listitem>
<listitem>
<para>
Selecting and distributing the global clock.
<!-- FIXME: is this still true? -->
</para>
</listitem>
</itemizedlist>
</para>
<para>
The scheduler is a pluggable component; this means that alternative
schedulers can be written and plugged into GStreamer. There is usually
no need for interaction in the process of choosing the scheduler, though.
The default scheduler in &GStreamer; is called <quote>opt</quote>. Some
of the concepts discussed here are specific to opt.
</para>
<sect1 id="section-scheduler-manage">
<title>Managing elements and data throughput</title>
<para>
To understand some specifics of scheduling, it is important to know
how elements work internally. Largely, there are four types of elements:
<function>_chain ()</function>-based elements, <function>_loop
()</function>-based elements, <function>_get ()</function>-based
elements and decoupled elements. Each of those have a set of features
and limitations that are important for how they are scheduled.
</para>
<itemizedlist>
<listitem>
<para>
<function>_chain ()</function>-based elements are elements that
have a <function>_chain ()</function>-function defined for each of
their sinkpads. Those functions will receive data whenever input
data is available. In those functions, the element can
<emphasis>push</emphasis> data over its source pad(s) to peer
elements. <function>_chain ()</function>-based elements cannot
<emphasis>pull</emphasis> additional data from their sinkpad(s).
Most elements in &GStreamer; are <function>_chain
()</function>-based.
</para>
</listitem>
<listitem>
<para>
<function>_loop ()</function>-based elements are elements that have
a <function>_loop ()</function>-function defined for the whole
element. Inside this function, the element can pull buffers from
its sink pad(s) and push data over its source pad(s) as it sees fit.
Such elements usually require specific control over their input.
Muxers and demuxers are usually <function>_loop ()</function>-based.
</para>
</listitem>
<listitem>
<para>
<function>_get ()</function>-based elements are elements with only
source pads. For each source pad, a <function>_get
()</function>-function is defined, which is called whenever the peer
element needs additional input data. Most source elements are, in
fact, <function>_get ()</function>-based. Such an element cannot
actively push data.
</para>
</listitem>
<listitem>
<para>
Decoupled elements are elements whose source pads are
<function>_get ()</function>-based and whose sink pads are
<function>_chain ()</function>-based. The <function>_chain
()</function>-function cannot push data over its source pad(s),
however. One such element is the <quote>queue</quote> element,
which is a thread boundary element. Since only one side of such
elements are interesting for one particular scheduler, we can
safely handle those elements as if they were either
<function>_get ()</function>- or <function>_chain
()</function>-based. Therefore, we will further omit this type
of elements in the discussion.
</para>
</listitem>
</itemizedlist>
<para>
Obviously, the type of elements that are linked together have
implications for how the elements will be scheduled. If a get-based
element is linked to a loop-based element and the loop-based element
requests data from its sinkpad, we can just call the get-function and
be done with it. However, if two loop-based elements are linked to
each other, it's a lot more complicated. Similarly, a loop-based
element linked to a chain-based element is a lot easier than two
loop-based elements linked to each other.
</para>
<para>
The default &GStreamer; scheduler, <quote>opt</quote>, uses a concept
of chains and groups. A group is a series of elements that
do not require any context switches or intermediate data stores to
be executed. In practice, this implies zero or one loop-based elements,
one get-based element (at the beginning) and an infinite amount of
chain-based elements. If there is a loop-based element, then the
scheduler will simply call this elements loop-function to iterate.
If there is no loop-based element, then data will be pulled from the
get-based element and will be pushed over the chain-based elements.
</para>
<para>
A chain is a series of groups that depend on each other for data.
For example, two linked loop-based elements would end up in different
groups, but in the same chain. Whenever the first loop-based element
pushes data over its source pad, the data will be temporarily stored
inside the scheduler until the loop-function returns. When it's done,
the loop-function of the second element will be called to process this
data. If it pulls data from its sinkpad while no data is available,
the scheduler will <quote>emulate</quote> a get-function and, in this
function, iterate the first group until data is available.
</para>
<para>
The above is roughly how scheduling works in &GStreamer;. This has
some implications for ideal pipeline design. An pipeline would
ideally contain at most one loop-based element, so that all data
processing is immediate and no data is stored inside the scheduler
during group switches. You would think that this decreases overhead
significantly. In practice, this is not so bad, however. It's something
to keep in the back of your mind, nothing more.
</para>
</sect1>
</chapter>

View file

@ -1,43 +1,22 @@
<chapter id="chapter-threads">
<title>Threads</title>
<para>
GStreamer has support for multithreading through the use of
the <ulink type="http"
url="&URLAPI;GstThread.html"><classname>GstThread</classname></ulink>
object. This object is in fact a special <ulink type="http"
url="&URLAPI;GstBin.html"><classname>GstBin</classname></ulink>
that will start a new thread (using Glib's
<classname>GThread</classname> system) when started.
&GStreamer; is inherently multi-threaded, and is fully thread-safe.
Most threading internals are hidden from the application, which should
make application development easier. However, in some cases, applications
may want to have influence on some parts of those. &GStreamer; allows
applications to force the use of multiple threads over some parts of
a pipeline.
</para>
<para>
To create a new thread, you can simply use <function>gst_thread_new
()</function>. From then on, you can use it similar to how you would
use a <classname>GstBin</classname>. You can add elements to it,
change state and so on. The largest difference between a thread and
other bins is that the thread does not require iteration. Once set to
the <classname>GST_STATE_PLAYING</classname> state, it will iterate
its contained children elements automatically.
</para>
<para>
<xref linkend="section-threads-img"/> shows how a thread can be
visualised.
</para>
<figure float="1" id="section-threads-img">
<title>A thread</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/thread.&image;" format="&IMAGE;"/>
</imageobject>
</mediaobject>
</figure>
<sect1 id="section-threads-uses">
<title>When would you want to use a thread?</title>
<title>When would you want to force a thread?</title>
<para>
There are several reasons to use threads. However, there's also some
reasons to limit the use of threads as much as possible. We will go
into the drawbacks of threading in &GStreamer; in the next section.
Let's first list some situations where threads can be useful:
There are several reasons to force the use of threads. However,
for performance reasons, you never want to use one thread for every
element out there, since that will create some overhead.
Let's now list some situations where threads can be particularly
useful:
</para>
<itemizedlist>
<listitem>
@ -56,15 +35,6 @@
will run independently and their synchronization will be better.
</para>
</listitem>
<listitem>
<para>
Data pre-rolls. You can use threads and queues (thread boundaries)
to cache a few seconds of data before playing. By using this
approach, the whole pipeline will already be setup and data will
already be decoded. When activating the rest of the pipeline, the
switch from PAUSED to PLAYING will be instant.
</para>
</listitem>
</itemizedlist>
<figure float="1" id="section-queues-img">
<title>a two-threaded decoder with a queue</title>
@ -76,8 +46,9 @@
</figure>
<para>
Above, we've mentioned the <quote>queue</quote> element several times
now. A queue is a thread boundary element. It does so by using a
classic provider/receiver model as learned in threading classes at
now. A queue is the thread boundary element through which you can
force the use of threads. It does so by using a classic
provider/receiver model as learned in threading classes at
universities all around the world. By doing this, it acts both as a
means to make data throughput between threads threadsafe, and it can
also act as a buffer. Queues have several <classname>GObject</classname>
@ -87,164 +58,33 @@
there's more data than the upper treshold, it will block input or
(if configured to do so) drop data.
</para>
</sect1>
<sect1 id="section-threads-constraints">
<title>Constraints placed on the pipeline by the GstThread</title>
<para>
Within the pipeline, everything is the same as in any other bin. The
difference lies at the thread boundary, at the link 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
<quote>queue</quote> element. A queue should be placed in between any
two elements whose pads are linked together while the elements live in
different threads. 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 or the other to enable inter-thread communication.
</para>
<para>
If you are writing a GUI application, making the top-level bin a
thread will make your GUI more responsive. If it were a pipeline
instead, it would have to be iterated by your application's event
loop, which increases the latency between events (say, keyboard
presses) and responses from the GUI. In addition, any slight hang
in the GUI would delay iteration of the pipeline, which (for example)
could cause pops in the output of the sound card, if it is an audio
pipeline.
</para>
<para>
A problem with using threads is, however, thread contexts. If you
connect to a signal that is emitted inside a thread, then the signal
handler for this thread <emphasis>will be executed in that same
thread</emphasis>! This is very important to remember, because many
graphical toolkits can not run multi-threaded. Gtk+, for example,
only allows threaded access to UI objects if you explicitely use
mutexes. Not doing so will result in random crashes and X errors.
A solution many people use is to place an idle handler in the signal
handler, and have the actual signal emission code be executed in the
idle handler, which will be executed from the mainloop.
</para>
<para>
Generally, if you use threads, you will encounter some problems. Don't
hesistate to ask us for help in case of problems.
To use a queues (and therefore force the use of two distinct threads
in the pipeline), one can simply create a <quote>queue</quote> element
and put this in as part of the pipeline. &GStreamer; will take care of
all threading details internally.
</para>
</sect1>
<sect1 id="section-threads-example">
<title>A threaded example application</title>
<para>
As an example we show the helloworld program that we coded in
<xref linkend="chapter-helloworld"/> using a thread. Note that
the whole application lives in a thread (as opposed to half
of the application living in a thread and the other half being
another thread or a pipeline). Therefore, it does not need a
queue element in this specific case.
<sect1 id="section-threads-scheduling">
<title>Scheduling in &GStreamer;</title>
<para>
Scheduling of pipelines in &GStreamer; is done by using a thread for
each <quote>group</quote>, where a group is a set of elements separated
by <quote>queue</quote> elements. Within such a group, scheduling is
either push-based or pull-based, depending on which mode is supported
by the particular element. If elements support random access to data,
such as file sources, then elements downstream in the pipeline become
the entry point of this group (i.e. the element controlling the
scheduling of other elements). The entry point pulls data from upstream
and pushes data downstream, thereby calling data handling functions on
either type of element.
</para>
<para>
In practice, most elements in &GStreamer;, such as decoders, encoders,
etc. only support push-based scheduling, which means that in practice,
&GStreamer; uses a push-based scheduling model.
</para>
<programlisting><!-- example-begin threads.c -->
#include &lt;gst/gst.h&gt;
GstElement *thread, *source, *decodebin, *audiosink;
static gboolean
idle_eos (gpointer data)
{
g_print ("Have idle-func in thread %p\n", g_thread_self ());
gst_main_quit ();
/* do this function only once */
return FALSE;
}
/*
* EOS will be called when the src element has an end of stream.
* Note that this function will be called in the thread context.
* We will place an idle handler to the function that really
* quits the application.
*/
static void
cb_eos (GstElement *thread,
gpointer data)
{
g_print ("Have eos in thread %p\n", g_thread_self ());
g_idle_add ((GSourceFunc) idle_eos, NULL);
}
/*
* On error, too, you'll want to forward signals to the main
* thread, especially when using GUI applications.
*/
static void
cb_error (GstElement *thread,
GstElement *source,
GError *error,
gchar *debug,
gpointer data)
{
g_print ("Error in thread %p: %s\n", g_thread_self (), error->message);
g_idle_add ((GSourceFunc) idle_eos, NULL);
}
/*
* Link new pad from decodebin to audiosink.
* Contains no further error checking.
*/
static void
cb_newpad (GstElement *decodebin,
GstPad *pad,
gboolean last,
gpointer data)
{
gst_pad_link (pad, gst_element_get_pad (audiosink, "sink"));
gst_bin_add (GST_BIN (thread), audiosink);
gst_bin_sync_children_state (GST_BIN (thread));
}
gint
main (gint argc,
gchar *argv[])
{
/* init GStreamer */
gst_init (&amp;argc, &amp;argv);
/* make sure we have a filename argument */
if (argc != 2) {
g_print ("usage: %s &lt;Ogg/Vorbis filename&gt;\n", argv[0]);
return -1;
}
/* create a new thread to hold the elements */
thread = gst_thread_new ("thread");
g_signal_connect (thread, "eos", G_CALLBACK (cb_eos), NULL);
g_signal_connect (thread, "error", G_CALLBACK (cb_error), NULL);
/* create elements */
source = gst_element_factory_make ("filesrc", "source");
g_object_set (G_OBJECT (source), "location", argv[1], NULL);
decodebin = gst_element_factory_make ("decodebin", "decoder");
g_signal_connect (decodebin, "new-decoded-pad",
G_CALLBACK (cb_newpad), NULL);
audiosink = gst_element_factory_make ("alsasink", "audiosink");
/* setup */
gst_bin_add_many (GST_BIN (thread), source, decodebin, NULL);
gst_element_link (source, decodebin);
gst_element_set_state (audiosink, GST_STATE_PAUSED);
gst_element_set_state (thread, GST_STATE_PLAYING);
/* no need to iterate. We can now use a mainloop */
gst_main ();
/* unset */
gst_element_set_state (thread, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (thread));
return 0;
}
<!-- example-end threads.c --></programlisting>
</sect1>
</chapter>

View file

@ -0,0 +1,90 @@
<chapter id="chapter-porting">
<title>Porting 0.8 applications to 0.9</title>
<para>
This section of the appendix will discuss shortly what changes to
applications will be needed to quickly and conveniently port most
applications from &GStreamer;-0.8 to &GStreamer;-0.9, with references
to the relevant sections in this Application Development Manual
where needed. With this list, it should be possible to port simple
applications to &GStreamer;-0.9 in less than a day.
</para>
<sect1 id="section-porting-objects">
<title>List of changes</title>
<itemizedlist>
<listitem>
<para>
Most functions returning an object or an object property have
been changed to return its own reference rather than a constant
reference of the one owned by the object itself. The reason for
this change is primarily threadsafety. This means, effectively,
that return values of functions such as
<function>gst_element_get_pad ()</function>,
<function>gst_pad_get_name ()</function> and many more like these
have to be free'ed or unreferenced after use. Check the API
references of each function to know for sure whether return
values should be free'ed or not.
</para>
</listitem>
<listitem>
<para>
Applications should no longer use signal handlers to be notified
of errors, end-of-stream and other similar pipeline events.
Instead, they should use the <classname>GstBus</classname>, which
has been discussed in <xref linkend="chapter-bus"/>. The bus will
take care that the messages will be delivered in the context of
mainloop, which is almost certainly the application's main thread.
The big advantage of this is that applications no longer need to
be thread-aware; they don't need to use <function>g_idle_add
()</function> in the signal handler and do the actual real work
in the idle-callback. &GStreamer; now does all that internally.
</para>
</listitem>
<listitem>
<para>
Related to this, <function>gst_bin_iterate ()</function> has been
removed. Pipelines will iterate in their own thread, and applications
can simply run a <classname>GMainLoop</classname> (or call the
mainloop of their UI toolkit, such as <function>gtk_main
()</function>).
</para>
</listitem>
<listitem>
<para>
State changes can be delayed; ASYNC.
</para>
</listitem>
<listitem>
<para>
In 0.8, events and queries had to manually be sent to sinks in
pipelines (unless you were using playbin). This is no longer
the case in 0.9. In 0.9, queries and events can be sent to
toplevel pipelines, and the pipeline will do the dispatching
internally for you. This means less bookkeeping in your
application. For a short code example, see <xref
linkend="chapter-queryevents"/>. Related, seeking is now
threadsafe, and your video output will show the new video
position's frame while seeking, providing a better user
experience.
</para>
</listitem>
<listitem>
<para>
The <classname>GstThread</classname> object has been removed.
Applications can now simply put elements in a pipeline with
optionally some <quote>queue</quote> elements in between for
buffering, and &GStreamer; will take care of creating threads
internally. It is still possible to have parts of a pipeline
run in different threads than others, by using the
<quote>queue</quote> element. See <xref linkend="chapter-threads"/>
for details.
</para>
</listitem>
<listitem>
<para>
Filtered caps -> caps-filter.
</para>
</listitem>
</itemizedlist>
</sect1>
</chapter>

View file

@ -23,7 +23,7 @@
optimal plan for that data flow. Plan generation is one of the
most complicated procedures in &GStreamer;. You will learn more
about this process, called scheduling, in <xref
linkend="chapter-scheduler"/>.
linkend="section-threads-scheduling"/>.
</para>
<figure float="1" id="section-bin-img">

186
docs/manual/basics-bus.xml Normal file
View file

@ -0,0 +1,186 @@
<chapter id="chapter-bus">
<title>Bus</title>
<para>
A bus is a simple system that takes care of forwarding messages from
the pipeline threads to an application in its own thread context. The
advantage of a bus is that an application does not need to be
thread-aware in order to use &GStreamer;, even though &GStreamer;
itself is heavily threaded.
</para>
<para>
Every pipeline contains a bus by default, so applications do not need
to create a bus or anything. The only thing applications should do is
set a message handler on a bus, which is similar to a signal handler
to an object. When the mainloop is running, the bus will periodically
be checked for new messages, and the callback will be called when any
message is available.
</para>
<sect1 id="section-bus-howto">
<title>How to use a bus</title>
<para>
To use a bus, attach a message handler to the default bus of a pipeline
using <function>gst_bus_add_watch ()</function>. This handler will be
called whenever the pipeline emits a message to the bus. In this
handler, check the signal type (see next section) and do something
accordingly. The return value of the handler should be TRUE to remove
the message from the bus.
</para>
<programlisting><!-- example-begin bus.c a -->
#include &lt;gst/gst.h&gt;
static GMainLoop *loop;
static gboolean
my_bus_callback (GstBus *bus,
GstMessage *message,
gpointer data)
{
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR: {
GError *err;
gchar *debug;
gst_message_parse_error (message, &amp;err, &amp;debug);
g_print ("Error: %s\n", err-&gt;message);
g_error_free (err);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
g_main_loop_quit (loop);
break;
default:
/* unhandled message */
break;
}
/* remove message from the queue */
return TRUE;
}
gint
main (gint argc,
gchar *argv[])
{
GMainLoop *loop;
GstElement *pipeline;
/* init */
gst_init (&amp;argc, &amp;argv);
/* create pipeline, add handler */
pipeline = gst_pipeline_new ("my_pipeline");
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
my_bus_callback, NULL);
<!-- example-end bus.c a -->
[..]<!-- example-begin bus.c b -->
<!-- example-begin bus.c c -->
/* in the mainloop, all messages posted to the bus by the pipeline
* will automatically be sent to our callback. */
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
return 0;
}
<!-- example-end bus.c c -->
</programlisting>
<para>
It is important to know that the handler will be called in the thread
context of the mainloop. This means that the interaction between the
pipeline and application over the bus is
<emphasis>asynchronous</emphasis>, and thus not suited for some
real-time purposes, such as cross-fading between audio tracks, doing
(theoretically) gapless playback or video effects. All such things
should be done in the pipeline context, which is easiest by writing
a &GStreamer; plug-in. It is very useful for its primary purpose,
though: passing messages from pipeline to application.
</para>
</sect1>
<sect1 id="section-bus-message-types">
<title>Message types</title>
<para>
&GStreamer; has a few pre-defined message types that can be passed
over the bus. The messages are extendible, however. Plug-ins can
define additional messages, and applications can decide to either
have specific code for those or ignore them. All applications are
strongly recommended to at least handle error messages by providing
visual feedback to the user.
</para>
<para>
All messages have a message source, type and timestamp. The message
source can be used to see which element emitted the message. For some
messages, for example, only the ones emitted by the top-level pipeline
will be interesting to most applications (e.g. for state-change
notifications). Below is a list of all messages and a short explanation
of what they do and how to parse message-specific content.
</para>
<itemizedlist>
<listitem>
<para>
Error, warning and information notifications: those are used
by elements if a message should be shown to the user about the
state of the pipeline. Error messages are fatal and terminate
the data-passing. The error should be repaired to resume pipeline
acvitity. Warnings are not fatal, but imply a problem nevertheless.
Information messages are for non-problem notifications. All those
messages contain a <classname>GError</classname> with the main
error type and message, and optionally a debug string. Both
can be extracted using <function>gst_message_parse_error
()</function>, <function>_parse_warning ()</function> and
<function>_parse_info ()</function>. Both error and debug string
should be free'ed after use.
</para>
</listitem>
<listitem>
<para>
End-of-stream notification: this is emitted when the stream has
ended. The state of the pipeline will not change, but further
media handling will stall. Applications can use this to skip to
the next song in their playlist. After end-of-stream, it is also
possible to seek back in the stream. Playback will then continue
automatically. This message has no specific arguments.
</para>
</listitem>
<listitem>
<para>
Tags: emitted when metadata was found in the stream. This can be
emitted multiple times for a pipeline (e.g. once for descriptive
metadata such as artist name or song title, and another one for
stream-information, such as samplerate and bitrate). Applications
should cache metadata internally. <function>gst_message_parse_tag
()</function> should be used to parse the taglist, which should
be dereferenced after use.
</para>
</listitem>
<listitem>
<para>
State-changes: emitted after a successful state change.
<function>gst_message_parse_state_changed ()</function> can be
used to parse the old and new state of this transition.
</para>
</listitem>
<listitem>
<para>
Buffering: emitted during caching of network-streams. One can
manually extract the progress (in percent) from the message by
extracting the <quote>buffer-percent</quote> property from the
structure returned by <function>gst_message_parse_structure
()</function>.
</para>
</listitem>
<listitem>
<para>
Other application-specific messages: any information on those can
be extracted by getting a structure (see above) and reading
properties. In most cases, such messages can conveniently be
ignored.
</para>
</listitem>
</itemizedlist>
</sect1>
</chapter>

View file

@ -252,7 +252,7 @@ main (int argc,
char *argv[])
{
GstElement *element;
const gchar *name;
gchar *name;
/* init GStreamer */
gst_init (&argc, &argv);
@ -263,6 +263,7 @@ main (int argc,
/* get name */
g_object_get (G_OBJECT (element), "name", &name, NULL);
g_print ("The name of the element is '%s'.\n", name);
g_free (name);
gst_object_unref (GST_OBJECT (element));
@ -489,17 +490,30 @@ main (int argc,
<para>
<classname>GST_STATE_PAUSED</classname>: in this state, an
element has opened the stream, but is not actively processing
it. An element should not modify the stream's position, data or
anything else in this state. When set back to PLAYING, it should
continue processing at the point where it left off as soon as
possible.
it. An element is allowed to modify a stream's position, read
and process data and such to prepare for playback as soon as
state is changed to PLAYING, but it is <emphasis>not</emphasis>
allowed to play the data which would make the clock run.
In summary, PAUSED is the same as PLAYING but without a running
clock.
</para>
<para>
Elements going into the PAUSED state should prepare themselves
for moving over to the PLAYING state as soon as possible. Video
or audio outputs would, for example, wait for data to arrive and
queue it so they can play it right after the state change. Also,
video sinks can already play the first frame (since this does
not affect the clock yet). Autopluggers could use this same
state transition to already plug together a pipeline. Most other
elements, such as codecs or filters, do not need to explicitely
do anything in this state, however.
</para>
</listitem>
<listitem>
<para>
<classname>GST_STATE_PLAYING</classname>: in the PLAYING state,
an element does exactly the same as in the PAUSED state, except
that it actually processes data.
that the clock now runs.
</para>
</listitem>
</itemizedlist>
@ -511,12 +525,12 @@ main (int argc,
will internally set the element to READY and PAUSED in between.
</para>
<para>
Even though an element in <classname>GST_STATE_PLAYING</classname>
is ready for data processing, it will not necessarily do that. If
the element is placed in a thread (see <xref
linkend="chapter-threads"/>), it will process data automatically.
In other cases, however, you will need to <emphasis>iterate</emphasis>
the element's container.
When moved to <classname>GST_STATE_PLAYING</classname>, pipelines
will process data automatically. They do not need to be iterated in
any form. Internally, &GStreamer; will start threads that take this
task on to them. &GStreamer; will also take care of switching
messages from the pipeline's thread into the application's own
thread, by using a <xref linkend="chapter-bus"/>.
</para>
</sect1>
</chapter>

View file

@ -48,9 +48,9 @@
pipeline until we've played the whole song. We've previously
learned how to add elements to a container bin in <xref
linkend="chapter-bins"/>, and we've learned about element states
in <xref linkend="section-elements-states"/>. We will use the function
<function>gst_bin_sync_children_state ()</function> to synchronize
the state of a bin on all of its contained children.
in <xref linkend="section-elements-states"/>. We will also attach
a message handler to the pipeline bus so we can retrieve errors
and detect the end-of-stream.
</para>
<para>
Let's now add all the code together to get our very first audio
@ -65,29 +65,59 @@
* example, we will use them, however.
*/
GstElement *pipeline, *source, *parser, *decoder, *sink;
GstElement *pipeline, *source, *parser, *decoder, *conv, *sink;
static gboolean
bus_call (GstBus *bus,
GstMessage *msg,
gpointer data)
{
GMainLoop *loop = data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print ("End-of-stream\n");
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *err;
gst_message_parse_error (msg, &amp;err, &amp;debug);
g_free (debug);
g_print ("Error: %s\n", err->message);
g_error_free (err);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
static void
new_pad (GstElement *element,
GstPad *pad,
gpointer data)
{
/* We can now link this pad with the audio decoder and
* add both decoder and audio output to the pipeline. */
/* We can now link this pad with the audio decoder */
g_print ("Dynamic pad created, linking parser/decoder\n");
gst_pad_link (pad, gst_element_get_pad (decoder, "sink"));
gst_bin_add_many (GST_BIN (pipeline), decoder, sink, NULL);
/* This function synchronizes a bins state on all of its
* contained children. */
gst_bin_sync_children_state (GST_BIN (pipeline));
}
int
main (int argc,
char *argv[])
{
GMainLoop *loop;
/* initialize GStreamer */
gst_init (&amp;argc, &amp;argv);
loop = g_main_loop_new (NULL, FALSE);
/* check input arguments */
if (argc != 2) {
@ -100,37 +130,40 @@ main (int argc,
source = gst_element_factory_make ("filesrc", "file-source");
parser = gst_element_factory_make ("oggdemux", "ogg-parser");
decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder");
conv = gst_element_factory_make ("audioconvert", "converter");
sink = gst_element_factory_make ("alsasink", "alsa-output");
if (!pipeline || !source || !parser || !decoder || !conv || !sink) {
g_print ("One element could not be created\n");
return -1;
}
/* set filename property on the file source */
/* set filename property on the file source. Also add a message
* handler. */
g_object_set (G_OBJECT (source), "location", argv[1], NULL);
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
bus_call, loop);
/* link together - note that we cannot link the parser and
* decoder yet, becuse the parser uses dynamic pads. For that,
* we set a new-pad signal handler. */
gst_element_link (source, parser);
gst_element_link (decoder, sink);
gst_element_link_many (decoder, conv, sink, NULL);
g_signal_connect (parser, "new-pad", G_CALLBACK (new_pad), NULL);
/* put all elements in a bin - or at least the ones we will use
* instantly. */
gst_bin_add_many (GST_BIN (pipeline), source, parser, NULL);
/* put all elements in a bin */
gst_bin_add_many (GST_BIN (pipeline),
source, parser, decoder, conv, sink, NULL);
/* Now set to playing and iterate. We will set the decoder and
* audio output to ready so they initialize their memory already.
* This will decrease the amount of time spent on linking these
* elements when the Ogg parser emits the new-pad signal. */
gst_element_set_state (decoder, GST_STATE_READY);
gst_element_set_state (sink, GST_STATE_READY);
/* Now set to playing and iterate. */
g_print ("Setting to PLAYING\n");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* and now iterate - the rest will be automatic from here on.
* When the file is finished, gst_bin_iterate () will return
* FALSE, thereby terminating this loop. */
while (gst_bin_iterate (GST_BIN (pipeline))) ;
g_print ("Running\n");
g_main_loop_run (loop);
/* clean up nicely */
g_print ("Returned, stopping playback\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
g_print ("Deleting pipeline\n");
gst_object_unref (GST_OBJECT (pipeline));
return 0;

View file

@ -71,7 +71,11 @@ cb_new_pad (GstElement *element,
GstPad *pad,
gpointer data)
{
g_print ("A new pad %s was created\n", gst_pad_get_name (pad));
gchar *name;
name = gst_pad_get_name (pad);
g_print ("A new pad %s was created\n", name);
g_free (name);
/* here, you would setup a new pad link for the newly created pad */
<!-- example-end pad.c a -->[..]
@ -79,9 +83,11 @@ cb_new_pad (GstElement *element,
}
int
main(int argc, char *argv[])
main (int argc,
char *argv[])
{
GstElement *pipeline, *source, *demux;
GMainLoop *loop;
/* init */
gst_init (&amp;argc, &amp;argv);
@ -96,14 +102,15 @@ main(int argc, char *argv[])
/* put together a pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, demux, NULL);
gst_element_link (source, demux);
gst_element_link_pads (source, "src", demux, "sink");
/* listen for newly created pads */
g_signal_connect (demux, "new-pad", G_CALLBACK (cb_new_pad), NULL);
/* start the pipeline */
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
while (gst_bin_iterate (GST_BIN (pipeline)));
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
<!--example-end pad.c b -->
[..]<!-- example-begin pad.c c --><!--
return 0;
@ -135,12 +142,18 @@ static void
some_function (GstElement *tee)
{
GstPad * pad;
gchar *name;
pad = gst_element_get_request_pad (tee, "src%d");
g_print ("A new pad %s was created\n", gst_pad_get_name (pad));
name = gst_pad_get_name (pad);
g_print ("A new pad %s was created\n", name);
g_free (name);
/* here, you would link the pad */
[..]
/* and, after doing that, free our reference */
gst_object_unref (GST_OBJECT (pad));
}
</programlisting>
<para>
@ -161,12 +174,16 @@ link_to_multiplexer (GstPad *tolink_pad,
GstElement *mux)
{
GstPad *pad;
gchar *srcname = gst_pad_get_name (tolink_pad), *sinkname;
pad = gst_element_get_compatible_pad (mux, tolink_pad);
gst_pad_link (tolinkpad, pad);
sinkname = gst_pad_get_name (pad);
gst_object_unref (GST_OBJECT (pad));
g_print ("A new pad %s was created and linked to %s\n",
gst_pad_get_name (pad), gst_pad_get_name (tolink_pad));
g_print ("A new pad %s was created and linked to %s\n", srcname, sinkname);
g_free (sinkname);
g_free (srcname);
}
</programlisting>
</sect2>
@ -321,6 +338,17 @@ Pad Templates:
given in this list.
</para>
</listitem>
<listitem>
<para>
An array value (<classname>GST_TYPE_FIXED_LIST</classname>): the
property is an array of values. Each value in the array is a
full value on its own, too. All values in the array should be
of the same elementary type. This means that an array can
contain any combination of integers, lists of integers, integer
ranges together, and the same for floats or strings, but it can
not contain both floats and ints at the same time.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
@ -508,7 +536,7 @@ link_pads_with_filter (GstPad *one,
</para>
<para>
A ghostpad is created using the function
<function>gst_element_add_ghost_pad ()</function>:
<function>gst_ghost_pad_new ()</function>:
</para>
<programlisting><!-- example-begin ghostpad.c a -->
#include &lt;gst/gst.h&gt;
@ -518,16 +546,20 @@ main (int argc,
char *argv[])
{
GstElement *bin, *sink;
GstPad *pad;
/* init */
gst_init (&amp;argc, &amp;argv);
/* create element, add to bin, add ghostpad */
/* create element, add to bin */
sink = gst_element_factory_make ("fakesink", "sink");
bin = gst_bin_new ("mybin");
gst_bin_add (GST_BIN (bin), sink);
gst_element_add_ghost_pad (bin,
gst_element_get_pad (sink, "sink"), "sink");
/* add ghostpad */
pad = gst_element_get_pad (sink, "sink");
gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
gst_object_unref (GST_OBJECT (pad));
<!-- example-end ghostpad.c a -->
[..]<!-- example-begin ghostpad.c b --><!--
return 0;

View file

@ -291,44 +291,6 @@ main (gint argc,
</para>
</sect1>
<sect1 id="section-components-spider">
<title>Spider</title>
<para>
Spider is an autoplugger that looks and feels very much like decodebin.
On the commandline, you can literally switch between spider and
decodebin and it'll mostly just work. Try, for example,
<command>gst-launch-0.8 filesrc location=file.ogg ! spider !
audioconvert ! audioscale ! alsasink</command>. Although the two may
seem very much alike from the outside, they are very different from
the inside. Those internal differences are the main reason why spider
is currently considered deprecated (along with the fact that it was
hard to maintain).
</para>
<para>
As opposed to decodebin, spider does not decode pads and emit signals
for each detected stream. Instead, you have to add output sinks to
spider by create source request pads and connecting those to sink
elements. This means that streams decoded by spider cannot be dynamic.
Also, spider uses many loop-based elements internally, which is rather
heavy scheduler-wise.
</para>
<para>
Code for using spider would look almost identical to the code of
decodebin, and is therefore omitted. Also, featureset and limitations
are very much alike, except for the above-mentioned extra limitations
for spider with respect to decodebin.
</para>
</sect1>
<sect1 id="section-components-gst-play">
<title>GstPlay</title>
<para>
GstPlay is a GtkWidget with a simple API to play, pause and stop a media file.
</para>
</sect1>
<sect1 id="section-components-gst-editor">
<title>GstEditor</title>
<para>

View file

@ -27,6 +27,7 @@
<!ENTITY INIT SYSTEM "basics-init.xml">
<!ENTITY ELEMENTS SYSTEM "basics-elements.xml">
<!ENTITY BINS SYSTEM "basics-bins.xml">
<!ENTITY BUS SYSTEM "basics-bus.xml">
<!ENTITY PADS SYSTEM "basics-pads.xml">
<!ENTITY DATA SYSTEM "basics-data.xml">
<!ENTITY HELLOWORLD SYSTEM "basics-helloworld.xml">
@ -38,7 +39,6 @@
<!ENTITY CLOCKS SYSTEM "advanced-clocks.xml">
<!ENTITY DPARAMS SYSTEM "advanced-dparams.xml">
<!ENTITY THREADS SYSTEM "advanced-threads.xml">
<!ENTITY SCHEDULERS SYSTEM "advanced-schedulers.xml">
<!ENTITY AUTOPLUGGING SYSTEM "advanced-autoplugging.xml">
<!ENTITY DATAACCESS SYSTEM "advanced-dataaccess.xml">
@ -48,6 +48,7 @@
<!-- Appendices -->
<!ENTITY CHECKLIST SYSTEM "appendix-checklist.xml">
<!ENTITY PORTING SYSTEM "appendix-porting.xml">
<!ENTITY INTEGRATION SYSTEM "appendix-integration.xml">
<!ENTITY LICENSING SYSTEM "appendix-licensing.xml">
<!ENTITY WIN32 SYSTEM "appendix-win32.xml">
@ -170,6 +171,7 @@
&INIT;
&ELEMENTS;
&BINS;
&BUS;
&PADS;
&DATA;
&HELLOWORLD;
@ -187,9 +189,18 @@
able to create a <emphasis>simple</emphasis> application. However,
&GStreamer; provides much more candy than just the basics of playing
back audio files. In this chapter, you will learn more of the
low-level features and internals of &GStreamer;, such as threads,
scheduling, synchronization, metadata, interfaces and dynamic
parameters.
low-level features and internals of &GStreamer;.
</para>
<para>
Some parts of this part will serve mostly as an explanation of
how &GStreamer; works internally; they are not actually needed for
actual application development. This includes chapter such as the
ones covering scheduling, autoplugging and synchronization. Other
chapters, however, discuss more advanced ways of
pipeline-application interaction, and can turn out to be very useful
for certain applications. This includes the chapters on metadata,
querying and events, interfaces, dynamic parameters and pipeline
data manipulation.
</para>
</partintro>
@ -199,7 +210,6 @@
&CLOCKS;
&DPARAMS;
&THREADS;
&SCHEDULERS;
&AUTOPLUGGING;
&DATAACCESS;
@ -245,6 +255,10 @@
shortly explain how applications included with &GStreamer; can help
making your life easier, and some information on debugging.
</para>
<para>
In addition, we also provide a porting guide which will explain
easily how to port &GStreamer;-0.8 applications to &GStreamer;-0.9.
</para>
</partintro>
<!--
@ -278,6 +292,7 @@ Idea:
-->
&CHECKLIST;
&PORTING;
&INTEGRATION;
&LICENSING;
&WIN32;

View file

@ -1,51 +0,0 @@
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 77.53 103.38
3759 3501 4212 3501
2 2 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5
4212 3371 4858 3371 4858 3824 4212 3824 4212 3371
2 2 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5
5245 3371 5892 3371 5892 3824 5245 3824 5245 3371
2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 77.53 103.38
5892 3501 6408 3501
2 2 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5
6408 3371 7055 3371 7055 3824 6408 3824 6408 3371
2 2 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5
7442 3371 8088 3371 8088 3824 7442 3824 7442 3371
2 2 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5
8541 3371 9187 3371 9187 3824 8541 3824 8541 3371
2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 77.53 103.38
8088 3501 8541 3501
2 2 0 1 0 6 49 0 20 0.000 0 0 -1 0 0 5
3113 3371 3759 3371 3759 3824 3113 3824 3113 3371
2 2 0 1 0 7 50 0 20 0.000 0 0 -1 0 0 5
2079 2661 3759 2661 3759 4082 2079 4082 2079 2661
2 2 0 1 0 7 51 0 20 0.000 0 0 -1 0 0 5
4212 2661 5892 2661 5892 4082 4212 4082 4212 2661
2 2 0 1 0 7 51 0 20 0.000 0 0 -1 0 0 5
6408 2661 8088 2661 8088 4082 6408 4082 6408 2661
2 2 0 1 0 7 51 0 20 0.000 0 0 -1 0 0 5
8541 2661 10221 2661 10221 4082 8541 4082 8541 2661
2 2 0 1 0 7 100 0 19 0.000 0 0 -1 0 0 5
1950 1950 10350 1950 10350 4405 1950 4405 1950 1950
4 0 0 50 0 16 10 0.0000 4 116 284 4341 3694 sink\001
4 0 0 50 0 16 10 0.0000 4 90 220 5504 3694 src\001
4 0 0 50 0 16 10 0.0000 4 116 284 6602 3694 sink\001
4 0 0 50 0 16 10 0.0000 4 90 220 7701 3694 src\001
4 0 0 50 0 16 10 0.0000 4 116 284 8670 3694 sink\001
4 0 0 50 0 16 10 0.0000 4 142 866 2208 2919 disk_source\001
4 0 0 50 0 16 10 0.0000 4 129 401 4341 2919 parse\001
4 0 0 50 0 16 10 0.0000 4 116 594 6538 2919 decoder\001
4 0 0 50 0 16 10 0.0000 4 155 801 8670 2919 play_audio\001
4 0 0 48 0 16 10 0.0000 4 90 220 3307 3694 src\001
4 0 0 50 0 16 10 0.0000 4 116 452 2144 2208 thread\001

View file

@ -20,6 +20,7 @@ gnome_CFLAGS = $(GST_OBJ_CFLAGS) $(LIBGNOMEUI_CFLAGS)
EXTRA_DIST = extract.pl
EXAMPLES = \
bus \
dynamic \
$(GNOME) \
elementcreate \
@ -34,7 +35,6 @@ EXAMPLES = \
init \
popt \
query \
threads \
typefind \
fakesrc \
playbin \
@ -49,6 +49,10 @@ bin.c : $(top_srcdir)/docs/manual/basics-bins.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/basics-bins.xml
bus.c: $(top_srcdir)/docs/manual/basics-bus.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/basics-bus.xml
pad.c ghostpad.c: $(top_srcdir)/docs/manual/basics-pads.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/basics-pads.xml
@ -69,10 +73,6 @@ query.c: $(top_srcdir)/docs/manual/advanced-position.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/advanced-position.xml
threads.c: $(top_srcdir)/docs/manual/advanced-threads.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/advanced-threads.xml
typefind.c dynamic.c: $(top_srcdir)/docs/manual/advanced-autoplugging.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/advanced-autoplugging.xml

View file

@ -20,6 +20,7 @@ gnome_CFLAGS = $(GST_OBJ_CFLAGS) $(LIBGNOMEUI_CFLAGS)
EXTRA_DIST = extract.pl
EXAMPLES = \
bus \
dynamic \
$(GNOME) \
elementcreate \
@ -34,7 +35,6 @@ EXAMPLES = \
init \
popt \
query \
threads \
typefind \
fakesrc \
playbin \
@ -49,6 +49,10 @@ bin.c : $(top_srcdir)/docs/manual/basics-bins.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/basics-bins.xml
bus.c: $(top_srcdir)/docs/manual/basics-bus.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/basics-bus.xml
pad.c ghostpad.c: $(top_srcdir)/docs/manual/basics-pads.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/basics-pads.xml
@ -69,10 +73,6 @@ query.c: $(top_srcdir)/docs/manual/advanced-position.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/advanced-position.xml
threads.c: $(top_srcdir)/docs/manual/advanced-threads.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/advanced-threads.xml
typefind.c dynamic.c: $(top_srcdir)/docs/manual/advanced-autoplugging.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/advanced-autoplugging.xml