mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
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:
parent
bd72354e9a
commit
2abdd0bfda
18 changed files with 725 additions and 596 deletions
25
ChangeLog
25
ChangeLog
|
@ -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),
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:///<path>/<file></quote>,
|
||||
<quote>http://<host>/<path>/<file></quote>,
|
||||
<quote>mms://<host>/<path>/<file></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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 <gst/gst.h>
|
||||
<!-- 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, &err, &debug);
|
||||
g_print ("Error: %s\n", err->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, &fmt, &pos, &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, &fmt, &pos) &&
|
||||
gst_element_query (sink, GST_QUERY_TOTAL, &fmt, &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>
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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.ℑ" 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 <gst/gst.h>
|
||||
|
||||
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 (&argc, &argv);
|
||||
|
||||
/* make sure we have a filename argument */
|
||||
if (argc != 2) {
|
||||
g_print ("usage: %s <Ogg/Vorbis filename>\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>
|
||||
|
|
90
docs/manual/appendix-porting.xml
Normal file
90
docs/manual/appendix-porting.xml
Normal 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>
|
|
@ -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
186
docs/manual/basics-bus.xml
Normal 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 <gst/gst.h>
|
||||
|
||||
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, &err, &debug);
|
||||
g_print ("Error: %s\n", err->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 (&argc, &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>
|
|
@ -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>
|
||||
|
|
|
@ -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, &err, &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 (&argc, &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;
|
||||
|
|
|
@ -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 (&argc, &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 <gst/gst.h>
|
||||
|
@ -518,16 +546,20 @@ main (int argc,
|
|||
char *argv[])
|
||||
{
|
||||
GstElement *bin, *sink;
|
||||
GstPad *pad;
|
||||
|
||||
/* init */
|
||||
gst_init (&argc, &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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue