+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),
<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>
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>
<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>
<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>
<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">
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 */
/* 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">
<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>
+++ /dev/null
-<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>
<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>
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>
</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>
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.
+ 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-scheduling">
+ <title>Scheduling in &GStreamer;</title>
+
<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.
+ 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>
- Generally, if you use threads, you will encounter some problems. Don't
- hesistate to ask us for help in case of problems.
- </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.
+ 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>
--- /dev/null
+<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>
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">
--- /dev/null
+<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>
char *argv[])
{
GstElement *element;
- const gchar *name;
+ gchar *name;
/* init GStreamer */
gst_init (&argc, &argv);
/* 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));
<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>
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>
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
* 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) {
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;
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 -->[..]
}
int
-main(int argc, char *argv[])
+main (int argc,
+ char *argv[])
{
GstElement *pipeline, *source, *demux;
+ GMainLoop *loop;
/* init */
gst_init (&argc, &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;
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>
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>
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>
</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>
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;
</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>
<!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">
<!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">
<!-- 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">
&INIT;
&ELEMENTS;
&BINS;
+ &BUS;
&PADS;
&DATA;
&HELLOWORLD;
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>
&CLOCKS;
&DPARAMS;
&THREADS;
- &SCHEDULERS;
&AUTOPLUGGING;
&DATAACCESS;
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>
<!--
-->
&CHECKLIST;
+ &PORTING;
&INTEGRATION;
&LICENSING;
&WIN32;
+++ /dev/null
-#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
EXTRA_DIST = extract.pl
EXAMPLES = \
+ bus \
dynamic \
$(GNOME) \
elementcreate \
init \
popt \
query \
- threads \
typefind \
fakesrc \
playbin \
$(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
$(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
EXTRA_DIST = extract.pl
EXAMPLES = \
+ bus \
dynamic \
$(GNOME) \
elementcreate \
init \
popt \
query \
- threads \
typefind \
fakesrc \
playbin \
$(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
$(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