-manualname = gst-plugin-writers-guide
-htmlname = index.html
+DOC=gst-plugin-writers-guide
+MAIN=$(DOC).xml
+XML=$(shell echo *.xml)
+XSLFO=$(srcdir)/../xsl/fo.xsl
+XSLFOMODS=$(srcdir)/../xsl/ulink.xsl $(srcdir)/../xsl/keycombo.xsl
+XSLHTML=$(srcdir)/../xsl/html.xsl
+XSLHTMLMODS=$(srcdir)/../xsl/fileext.xsl $(srcdir)/../xsl/admon.xsl \
+ $(srcdir)/../xsl/keycombo.xsl $(srcdir)/../xsl/css.xsl
+XSLS=$(XSLFO) $(XSLFOMODS) $(XSLHTML) $(XSLHTMLMODS)
+FIGS= # $(shell echo *.fig) (uncomment when pngs are added)
+PNGS=$(FIGS:.fig=.png)
+PDFS=$(FIGS:.fig=.pdf)
+SRC=$(XML)
+CSS=base.css
-sgml_files = gst-plugin-writers-guide.sgml \
- titlepage.sgml \
- intro.sgml \
- testapp.sgml \
- loopbased.sgml \
- buffers.sgml \
- srcnsink.sgml \
- statemanage.sgml \
- checklist.sgml
+STYLESHEET_IMAGES=/usr/share/doc/docbook-xsl/images
-fig_files =
-eps_files =
-png_files =
+EXTRA_DIST = $(XML) $(FIGS)
-EXTRA_DIST = $(sgml_files) $(fig_files)
+## FIXME if we don't do this they don't get cleaned up in make distcheck
+## but maybe this is not the best way to do it
+CONFIG_CLEAN_FILES = $(XML) $(FIGS)
include $(srcdir)/../manuals.mak
-<!DOCTYPE book PUBLIC "-//GNOME//DTD DocBook PNG Variant V1.0//EN" "" [
-<!ENTITY TITLEPAGE SYSTEM "titlepage.sgml">
+<?xml version='1.0'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY % magic-entities SYSTEM "magic">
+%magic-entities;
+<!ENTITY TITLEPAGE SYSTEM "titlepage.sgml">
<!ENTITY INTRO SYSTEM "intro.sgml">
-
<!ENTITY TESTAPP SYSTEM "testapp.sgml">
-
<!ENTITY LOOPBASED SYSTEM "loopbased.sgml">
-
<!ENTITY BUFFERS SYSTEM "buffers.sgml">
-
<!ENTITY SRCNSINK SYSTEM "srcnsink.sgml">
-
<!ENTITY STATEMANAGE SYSTEM "statemanage.sgml">
-
<!ENTITY CHECKLIST SYSTEM "checklist.sgml">
-
<!ENTITY GStreamer "<application>GStreamer</application>">
]>
--- /dev/null
+<!ENTITY magic "pdf">
--- /dev/null
+<!ENTITY magic "png">
-manualname = gstreamer-manual
-htmlname = index.html
-
-sgml_files = gstreamer-manual.sgml \
- advanced.sgml \
- autoplugging.sgml \
- bins.sgml \
- buffers.sgml \
- components.sgml \
- quotes.sgml \
- pads.sgml \
- connections.sgml \
- cothreads.sgml \
- dynamic.sgml \
- elements.sgml \
- factories.sgml \
- goals.sgml \
- helloworld.sgml \
- helloworld2.sgml \
- init.sgml \
- intro.sgml \
- motivation.sgml \
- plugins.sgml \
- programs.sgml \
- debugging.sgml \
- queues.sgml \
- states.sgml \
- threads.sgml \
- typedetection.sgml \
- utility.sgml \
- xml.sgml
-
-fig_files = bin-element.fig \
- bin-element-ghost.fig \
- connected-elements.fig \
- filter-element-multi.fig \
- filter-element.fig \
- hello-world.fig \
- mime-world.fig \
- queue.fig \
- sink-element.fig \
- src-element.fig \
- state-diagram.fig \
- thread.fig
-
-eps_files = images/bin-element.eps \
- images/bin-element-ghost.eps \
- images/connected-elements.eps \
- images/filter-element-multi.eps \
- images/filter-element.eps \
- images/hello-world.eps \
- images/mime-world.eps \
- images/queue.eps \
- images/sink-element.eps \
- images/src-element.eps \
- images/state-diagram.eps \
- images/thread.eps
-
-png_files = images/bin-element.png \
- images/bin-element-ghost.png \
- images/connected-elements.png \
- images/filter-element-multi.png \
- images/filter-element.png \
- images/hello-world.png \
- images/mime-world.png \
- images/queue.png \
- images/sink-element.png \
- images/src-element.png \
- images/state-diagram.png \
- images/thread.png
-
-EXTRA_DIST = $(sgml_files) $(fig_files)
+DOC=gstreamer-manual
+MAIN=$(DOC).xml
+XML=$(shell echo *.xml)
+XSLFO=$(srcdir)/../xsl/fo.xsl
+XSLFOMODS=$(srcdir)/../xsl/ulink.xsl $(srcdir)/../xsl/keycombo.xsl
+XSLHTML=$(srcdir)/../xsl/html.xsl
+XSLHTMLMODS=$(srcdir)/../xsl/fileext.xsl $(srcdir)/../xsl/admon.xsl \
+ $(srcdir)/../xsl/keycombo.xsl $(srcdir)/../xsl/css.xsl
+XSLS=$(XSLFO) $(XSLFOMODS) $(XSLHTML) $(XSLHTMLMODS)
+FIGS=$(shell echo *.fig)
+PNGS=$(FIGS:.fig=.png)
+PDFS=$(FIGS:.fig=.pdf)
+SRC=$(XML)
+CSS=base.css
+
+STYLESHEET_IMAGES=/usr/share/doc/docbook-xsl/images
+
+EXTRA_DIST = $(XML) $(FIGS)
## FIXME if we don't do this they don't get cleaned up in make distcheck
## but maybe this is not the best way to do it
-CONFIG_CLEAN_FILES = $(sgml_files) $(fig_files)
+CONFIG_CLEAN_FILES = $(XML) $(FIGS)
include $(srcdir)/../manuals.mak
-
-
<title>The Hello world pipeline with MIME types</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/mime-world" format="PNG">
+ <imagedata fileref="images/mime-world.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
<title>a thread</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/thread" format="PNG">
+ <imagedata fileref="images/thread.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
--- /dev/null
+<chapter id="cha-debugging">
+ <title>Debugging</title>
+ <para>
+ GStreamer has an extensive set of debugging tools for
+ plugin developers.
+ </para>
+
+ <sect1>
+ <title>Command line options</title>
+ <para>
+ Applications using the GStreamer libraries accept the following set
+ of command line argruments to enable the debugging system.
+ </para>
+
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <option>--gst-debug-mask=<replaceable>mask</replaceable></option>
+ Sets the mask for the debugging output.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-info-mask=<replaceable>mask</replaceable></option>
+ Sets the mask for the info output.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-mask=<replaceable>mask</replaceable></option>
+ Sets the mask for the info *and* the debug output.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-plugin-spew</option>
+ Enable printout of errors while loading GST plugins.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-plugin-path=<replaceable>PATH</replaceable></option>
+ Add a directory to the plugin search path.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--help</option> Print the a short desciption of the
+ options and an overview of the current debugging/info masks
+ set.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The follwing table gives an overview of the mask values and
+ their meaning. (enabled) means that the corresponding flag
+ has been set.
+ </para>
+ <programlisting>
+Mask (to be OR'ed) info/debug FLAGS
+--------------------------------------------------------
+0x00000001 (enabled)/ GST_INIT
+0x00000002 / COTHREADS
+0x00000004 / COTHREAD_SWITCH
+0x00000008 / AUTOPLUG
+0x00000010 / AUTOPLUG_ATTEMPT
+0x00000020 / PARENTAGE
+0x00000040 / STATES
+0x00000080 / PLANING
+0x00000100 / SCHEDULING
+0x00000200 / OPERATION
+0x00000400 / BUFFER
+0x00000800 / CAPS
+0x00001000 / CLOCK
+0x00002000 / ELEMENT_PADS
+0x00004000 / ELEMENTFACTORY
+0x00008000 / PADS
+0x00010000 / PIPELINE
+0x00020000 / PLUGIN_LOADING
+0x00040000 / PLUGIN_ERRORS
+0x00080000 / PLUGIN_INFO
+0x00100000 / PROPERTIES
+0x00200000 / THREAD
+0x00400000 / TYPES
+0x00800000 / XML
+0x01000000 / NEGOTIATION
+0x02000000 / REFCOUNTING
+ </programlisting>
+ </sect1>
+ <sect1>
+ <title>Adding a custom debug handler</title>
+ <para>
+ </para>
+ </sect1>
+
+</chapter>
<title>Visualisation of a <classname>GstBin</classname> element with some elements in it</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/bin-element" format="PNG">
+ <imagedata fileref="images/bin-element.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
<title>Visualisation of a <classname>GstBin</classname> element with a ghostpad</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/bin-element-ghost" format="PNG">
+ <imagedata fileref="images/bin-element-ghost.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
<title>Visualisation of a source element</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/src-element" format="PNG">
+ <imagedata fileref="images/src-element.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
<title>Visualisation of a filter element</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/filter-element" format="PNG">
+ <imagedata fileref="images/filter-element.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
more than one output pad</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/filter-element-multi" format="PNG">
+ <imagedata fileref="images/filter-element-multi.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
<title>Visualisation of a sink element</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/sink-element" format="PNG">
+ <imagedata fileref="images/sink-element.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
<title>The Hello world pipeline</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/hello-world" format="PNG">
+ <imagedata fileref="images/hello-world.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
--- /dev/null
+<chapter id="cha-bins">
+ <title>Bins</title>
+ <para>
+ A Bin is a container element. You can add elements to a bin. Since a bin is
+ an <classname>GstElement</classname> itself, it can also be added to another bin.
+ </para>
+ <para>
+ Bins allow you to combine connected elements into one logical element. You do
+ not deal with the individual elements anymore but with just one element, the bin.
+ We will see that this is extremely powerfull when you are going to construct
+ complex pipelines since it allows you to break up the pipeline in smaller chunks.
+ </para>
+ <para>
+ The bin will also manage the elements contained in it. It will figure out how
+ the data will flow in the bin and generate an optimal plan for that data flow. Plan
+ generation is one of the most complicated procedures in GStreamer.
+ </para>
+
+ <figure float="1" id="sec-bin-img">
+ <title>Visualisation of a <classname>GstBin</classname> element with some elements in it</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/bin-element.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ There are two standard bins available to the GStreamer programmer:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ A pipeline (<classname>GstPipeline</classname>). Which is a generic container you will
+ use most of the time. The toplevel bin has to be a pipeline.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A thread (<classname>GstThread</classname>). All the elements in the thread bin will
+ run in a separate thread. You will have to use this bin if you carfully have to
+ synchronize audio and video for example. You will learn more about threads in.. <!-- FIXME -->
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <sect1 id="sec-bin-create">
+ <title>Creating a bin</title>
+ <para>
+ You create a bin with a specified name 'mybin' with:
+ </para>
+ <programlisting>
+ GstElement *bin;
+
+ gst_bin_new ("mybin");
+ ...
+ </programlisting>
+ <para>
+ A thread can be created with:
+ </para>
+ <programlisting>
+ GstElement *thread;
+
+ gst_thread_new ("mythread");
+ ...
+ </programlisting>
+ <para>
+ Pipelines are created with gst_pipeline_new ("name");
+ </para>
+ </sect1>
+
+ <sect1 id="sec-bin-adding">
+ <title>Adding elements to a bin</title>
+ <para>
+ Elements are added to a bin with the following code sample:
+ </para>
+ <programlisting>
+ GstElement *element;
+ GstElement *bin;
+
+ bin = gst_bin_new ("mybin");
+
+ element = gst_elementfactory_make ("mpg123", "decoder");
+ gst_bin_add (GST_BIN (bin), element);
+ ...
+ </programlisting>
+ <para>
+ Bins and threads can be added to other bins too. This allows you to create nested
+ bins.
+ </para>
+ <para>
+ To get an element from the bin you can use:
+ </para>
+ <programlisting>
+ GstElement *element;
+
+ element = gst_bin_get_by_name (GST_BIN (bin), "decoder");
+ ...
+ </programlisting>
+ <para>
+ You can see that the name of the element becomes very handy for retrieving the
+ element from an bin by using the elements name. gst_bin_get_by_name () will
+ recursively search nested bins.
+ </para>
+ <para>
+ To get a list of elements in a bin, use:
+ </para>
+ <programlisting>
+ GList *elements;
+
+ elements = gst_bin_get_list (GST_BIN (bin));
+
+ while (elements) {
+ GstElement *element = GST_ELEMENT (elements->data);
+
+ g_print ("element in bin: %s\n", gst_element_get_name (element));
+
+ elements = g_list_next (elements);
+ }
+ ...
+ </programlisting>
+ <para>
+ To remove an element from a bin use:
+ </para>
+ <programlisting>
+ GstElement *element;
+
+ gst_bin_remove (GST_BIN (bin), element);
+ ...
+ </programlisting>
+ </sect1>
+
+ <sect1 id="sec-bin-custom">
+ <title>Custom bins</title>
+ <para>
+ The application programmer can create custom bins packed with elements to perform a
+ specific task. This allow you to write an MPEG audio decoder with just the follwing lines
+ of code:
+
+ <programlisting>
+
+ // create the mp3player element
+ GstElement *mp3player = gst_elementfactory_make ("mp3player", "mp3player");
+ // set the source mp3 audio file
+ g_object_set (G_OBJECT (mp3player), "location", "helloworld.mp3", NULL);
+ // start playback
+ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PLAYING);
+ ...
+ // pause playback
+ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_PAUSED);
+ ...
+ // stop
+ gst_element_set_state (GST_ELEMENT (mp3player), GST_STATE_NULL);
+ </programlisting>
+
+ Custom bins can be created with a plugin or an XML description. You will find more
+ information about creating custom bin in the Filter-Writers-Guide.
+ </para>
+ </sect1>
+
+ <sect1 id="sec-bin-ghostpads">
+ <title>Ghostpads</title>
+ <para>
+ You can see from figure ... how a bin has no pads of its own. This is where Ghostpads
+ come into play.
+ </para>
+ <para>
+ A ghostpad is a pad from some element in the bin that has been promoted to the bin.
+ This way, the bin also has a pad. The bin becomes just another element with a pad and
+ you can then use the bin just like any other element. This is a very important feature
+ for creating custom bins.
+ </para>
+
+ <figure float="1" id="sec-bin-ghost-img">
+ <title>Visualisation of a <classname>GstBin</classname> element with a ghostpad</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/bin-element-ghost.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ Above is a representation of a ghostpad. the sinkpad of element one is now also a pad
+ of the bin.
+ </para>
+ <para>
+ Ghostpads can actually be added to all <classname>GstElement</classname>s and not just
+ <classname>GstBin</classname>s. Use the following code example to add a ghostpad to a bin:
+ </para>
+ <programlisting>
+ GstElement *bin;
+ GstElement *element;
+
+ element = gst_elementfactory_create ("mpg123", "decoder");
+ bin = gst_bin_new ("mybin");
+
+ gst_bin_add (GST_BIN (bin), element);
+
+ gst_element_add_ghost_pad (bin, gst_element_get_pad (element, "sink"), "sink");
+
+ </programlisting>
+ <para>
+ In the above example, the bin now also has a pad: the pad called 'sink' of the
+ given element. We can now, for example, connect the srcpad of a disksrc to the
+ bin with:
+ </para>
+ <programlisting>
+ GstElement *disksrc;
+
+ disksrc = gst_elementfactory_create ("disksrc", "disk_reader");
+
+ gst_element_connect (disksrc, "src", bin, "sink");
+ ...
+ </programlisting>
+ </sect1>
+
+</chapter>
--- /dev/null
+<chapter id="cha-buffers">
+ <title>Buffers</title>
+ <para>
+ Buffers contain the data that will flow through the pipeline you have created. A source
+ element will typically create a new buffer and pass it through the pad to the next
+ element in the chain.
+ When using the GStreamer infrastructure to create a media pipeline you will not have
+ to deal with buffers yourself; the elements will do that for you.
+ </para>
+ <para>
+ The most important information in the buffer is:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ A pointer to a piece of memory.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The size of the memory.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A refcount that indicates how many elements are using this buffer. This refcount
+ will be used to destroy the buffer when no element is having a reference to it.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ GStreamer provides functions to create custom buffer create/destroy algorithms, called
+ a <classname>GstBufferPool</classname>. This makes it possible to efficiently
+ allocate and destroy buffer memory. It also makes it possible to exchange memory between
+ elements by passing the <classname>GstBufferPool</classname>. A video element can,
+ for example, create a custom buffer allocation algorithm that creates buffers with XSHM
+ as the buffer memory. An element can use this algorithm to create and fill the buffer
+ with data.
+ </para>
+
+ <para>
+ The simple case is that a buffer is created, memory allocated, data put
+ in it, and passed to the next filter. That filter reads the data, does
+ something (like creating a new buffer and decoding into it), and
+ unreferences the buffer. This causes the data to be freed and the buffer
+ to be destroyed. A typical MPEG audio decoder works like this.
+ </para>
+
+ <para>
+ A more complex case is when the filter modifies the data in place. It
+ does so and simply passes on the buffer to the next element. This is just
+ as easy to deal with. An element that works in place has to be carefull when
+ the buffer is used in more than one element; a copy on write has to made in this
+ situation.
+ </para>
+
+</chapter>
<title>Visualisation of three connected elements</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/connected-elements" format="PNG">
+ <imagedata fileref="images/connected-elements.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
--- /dev/null
+<chapter id="cha-debugging">
+ <title>Debugging</title>
+ <para>
+ GStreamer has an extensive set of debugging tools for
+ plugin developers.
+ </para>
+
+ <sect1>
+ <title>Command line options</title>
+ <para>
+ Applications using the GStreamer libraries accept the following set
+ of command line argruments to enable the debugging system.
+ </para>
+
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <option>--gst-debug-mask=<replaceable>mask</replaceable></option>
+ Sets the mask for the debugging output.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-info-mask=<replaceable>mask</replaceable></option>
+ Sets the mask for the info output.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-mask=<replaceable>mask</replaceable></option>
+ Sets the mask for the info *and* the debug output.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-plugin-spew</option>
+ Enable printout of errors while loading GST plugins.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--gst-plugin-path=<replaceable>PATH</replaceable></option>
+ Add a directory to the plugin search path.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--help</option> Print the a short desciption of the
+ options and an overview of the current debugging/info masks
+ set.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The follwing table gives an overview of the mask values and
+ their meaning. (enabled) means that the corresponding flag
+ has been set.
+ </para>
+ <programlisting>
+Mask (to be OR'ed) info/debug FLAGS
+--------------------------------------------------------
+0x00000001 (enabled)/ GST_INIT
+0x00000002 / COTHREADS
+0x00000004 / COTHREAD_SWITCH
+0x00000008 / AUTOPLUG
+0x00000010 / AUTOPLUG_ATTEMPT
+0x00000020 / PARENTAGE
+0x00000040 / STATES
+0x00000080 / PLANING
+0x00000100 / SCHEDULING
+0x00000200 / OPERATION
+0x00000400 / BUFFER
+0x00000800 / CAPS
+0x00001000 / CLOCK
+0x00002000 / ELEMENT_PADS
+0x00004000 / ELEMENTFACTORY
+0x00008000 / PADS
+0x00010000 / PIPELINE
+0x00020000 / PLUGIN_LOADING
+0x00040000 / PLUGIN_ERRORS
+0x00080000 / PLUGIN_INFO
+0x00100000 / PROPERTIES
+0x00200000 / THREAD
+0x00400000 / TYPES
+0x00800000 / XML
+0x01000000 / NEGOTIATION
+0x02000000 / REFCOUNTING
+ </programlisting>
+ </sect1>
+ <sect1>
+ <title>Adding a custom debug handler</title>
+ <para>
+ </para>
+ </sect1>
+
+</chapter>
--- /dev/null
+<chapter id="cha-elements">
+ <title>GstElement</title>
+ <para>
+ The most important object in <application>GStreamer</application> for the
+ application programmer is the <classname>GstElement</classname> object.
+ </para>
+
+ <sect1 id="sec-elements-design">
+ <title>What is a GstElement</title>
+ <para>
+ The GstElement is the basic building block for the media pipeline. All the
+ different components you are going to use are derived from this GstElement.
+ This means that a lot of functions you are going to use operate on this object.
+ </para>
+ <para>
+ You will see that those elements have pads. These are the elements
+ connections with the 'outside' world. Depending on the number and direction of
+ the pads, we can see three types of elements: source, filter and sink element.
+ </para>
+ <para>
+ These three types are all the same GstElement object, they just differ in how
+ the pads are.
+ </para>
+
+ <sect2 id="sec-elements-src">
+ <title>GStreamer source elements</title>
+ <para>
+ This element will generate data that will be used by the pipeline. It is
+ typically a file or an audio source.
+ </para>
+ <para>
+ Below you see how we will visualize the element.
+ We always draw a src pad to the right of the element.
+ </para>
+ <figure float="1" id="sec-element-srcimg">
+ <title>Visualisation of a source element</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/src-element.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ Source elements do not accept data, they only generate data. You can see
+ this in the figure because it only has a src pad. A src pad can only
+ generate buffers.
+ </para>
+ </sect2>
+
+ <sect2 id="sec-elements-filter">
+ <title>GStreamer filter elements</title>
+ <para>
+ Filter elements both have an input and an output pad. They operate on data
+ they receive in the sink pad and send the result to the src pad.
+ </para>
+ <para>
+ Examples of a filter element might include: an MPEG decoder, volume filter,...
+ </para>
+ <para>
+ Filters may also contain any number of input pads and output pads. For example,
+ a video mixer might have to input pads (the images of the two different video
+ streams) and one output pad.
+ </para>
+ <figure float="1" id="sec-element-filterimg">
+ <title>Visualisation of a filter element</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/filter-element.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ The above figure shows the visualisation of a filter element. This element has
+ one sink pad (input) and one src (output) pad. Sink pads are drawn on the left
+ of the element.
+ </para>
+ <figure float="1" id="sec-element-multifilterimg">
+ <title>Visualisation of a filter element with
+ more than one output pad</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/filter-element-multi.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ The above figure shows the visualisation of a filter element with more than one
+ output pad. An example of such a filter is the AVI splitter. This element will
+ parse the input data and extracts the audio and video data. Most of these filters
+ dynamically send out a signal when a new pad is created so that the application
+ programmer can connect an arbitrary element to the newly created pad.
+ </para>
+ </sect2>
+
+ <sect2 id="sec-elements-sink">
+ <title>GStreamer sink elements</title>
+ <para>
+ This element accepts data but will not generate any new data. A sink element
+ is typically a file on disk, a soundcard, a display,... It is presented as
+ below:
+ </para>
+ <figure float="1" id="sec-element-sinkimg">
+ <title>Visualisation of a sink element</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/sink-element.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </sect2>
+ </sect1>
+ <sect1 id="sec-elements-create">
+ <title>Creating a GstElement</title>
+ <para>
+ GstElements are created from factories. To create an element, one has to get
+ access the a <classname>GstElementFactory</classname> using a unique factoryname.
+ </para>
+ <para>
+ The following code example is used to get a factory that can be used to create the
+ mpg123 element, an mp3 decoder.
+ </para>
+ <programlisting>
+ GstElementFactory *factory;
+
+ factory = gst_elementfactory_find ("mpg123");
+ </programlisting>
+ <para>
+ Once you have the handle to the elementfactory, you can create a real element with
+ the following code fragment:
+ </para>
+ <programlisting>
+ GstElement *element;
+
+ element = gst_elementfactory_create (factory, "decoder");
+ </programlisting>
+ <para>
+ gst_elementfactory_create () will use the elementfactory to create an element with the
+ given name. The name of the element is something you can use later on to lookup the
+ element in a bin, for example.
+ </para>
+ <para>
+ A simple shortcut exists for creating an element from a factory. The following example
+ creates an element, named "decoder" from the elementfactory named "mpg123". This
+ convenient function is most widly used to create an element.
+ </para>
+ <programlisting>
+ GstElement *element;
+
+ element = gst_elementfactory_make ("mpg123", "decoder");
+ </programlisting>
+ <para>
+ An element can be destroyed with:
+ </para>
+ <programlisting>
+ GstElement *element;
+
+ ...
+ gst_element_destroy (element);
+ </programlisting>
+ </sect1>
+</chapter>
--- /dev/null
+<chapter id="cha-factories">
+ <title>More on factories</title>
+ <para>
+ The small application we created in the previous chapter used the
+ concept of a factory to create the elements. In this chapter we will
+ show you how to use the factory concepts to create elements based
+ on what they do instead of how they are called.
+ </para>
+
+ <para>
+ We will first explain the concepts involved before we move on
+ to the reworked helloworld example using autoplugging.
+ </para>
+ <sect1>
+ <title>The problems with the helloworld example</title>
+ <para>
+ If we take a look at how the elements were created in the previous
+ example we used a rather crude mechanism:
+ </para>
+
+ <programlisting>
+ ...
+ /* now it's time to get the parser */
+ parse = gst_elementfactory_make ("mp3parse", "parse");
+ decoder = gst_elementfactory_make ("mpg123", "decoder");
+ ...
+ </programlisting>
+
+ <para>
+ While this mechanism is quite effective it also has some big problems:
+ The elements are created based on their name. Indeed, we create an
+ element mpg123 by explicitly stating the mpg123 elements name.
+ Our little program therefore always uses the mpg123 decoder element
+ to decode the MP3 audio stream, even if there are 3 other MP3 decoders
+ in the system. We will see how we can use a more general way to create
+ an MP3 decoder element.
+ </para>
+ <para>
+ We have to introduce the concept of MIME types and capabilities
+ added to the source and sink pads.
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>more on MIME Types</title>
+ <para>
+ GStreamer uses MIME types to indentify the different types of data
+ that can be handled by the elements. They are the high level
+ mechanisms to make sure that everyone is talking about the right
+ kind of data.
+ </para>
+ <para>
+ A MIME (Multipurpose Internet Mail Extension) types are a set of
+ string that denote a certain type of data. examples include:
+ <itemizedlist>
+ <listitem>
+ <para>
+ audio/raw : raw audio samples
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ audio/mpeg : mpeg audio
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ video/mpeg : mpeg video
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ An element must associate a MIME type to its source and sink pads
+ when it is loaded into the system. GStreamer knows about the
+ different elements and what type of data they expect and emit.
+ This allows for very dynamic and extensible element creation as we
+ will see.
+ </para>
+ <para>
+ As we have seen in the previous chapter, the MIME types are added
+ to the Capability structure of a pad.
+ </para>
+
+ <para>
+ In our helloworld example the elements we constructed would have the
+ following MIME types associated with their source and sink pads:
+ </para>
+ <figure float="1" id="sec-mime-img">
+ <title>The Hello world pipeline with MIME types</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/mime-world.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+
+ </figure>
+ <para>
+ We will see how you can create an element based on the MIME types
+ of its source and sink pads. This way the end-user will have the
+ ability to choose his/her favorite audio/mpeg decoder without
+ you even having to care about it.
+ </para>
+ <para>
+ The typing of the source and sink pads also makes it possible to
+ 'autoplug' a pipeline. We will have the ability to say: "construct
+ me a pipeline that does an audio/mpeg to audio/raw conversion".
+ </para>
+ <note>
+ <para>
+ The basic GStreamer library does not try to solve all of your
+ autoplug problems. It leaves the hard decisions to the application
+ programmer, where they belong.
+ </para>
+ </note>
+
+ </sect1>
+
+ <sect1>
+ <title>GStreamer types</title>
+ <para>
+ GStreamer assigns a unique number to all registered MIME types.
+ GStreamer also keeps a reference to
+ a function that can be used to determine if a given buffer is of
+ the given MIME type.
+ </para>
+ <para>
+ There is also an association between a MIME type and a file
+ extension.
+ </para>
+ <para>
+ The type information is maintained in a list of
+ <classname>GstType</classname>. The definition of a
+ <classname>GstType</classname> is like:
+ </para>
+ <programlisting>
+typedef GstCaps (*GstTypeFindFunc) (GstBuffer *buf,gpointer *priv);
+
+typedef struct _GstType GstType;
+
+struct _GstType {
+ guint16 id; /* type id (assigned) */
+
+ gchar *mime; /* MIME type */
+ gchar *exts; /* space-delimited list of extensions */
+
+ GstTypeFindFunc typefindfunc; /* typefind function */
+};
+ </programlisting>
+ <para>
+ All operations on <classname>GstType</classname> occur via their
+ <classname>guint16 id</classname> numbers, with <classname>GstType</classname>
+ structure private to the GStreamer library.
+ </para>
+
+ <sect2>
+ <title>MIME type to id conversion</title>
+
+ <para>
+ We can obtain the id for a given MIME type
+ with the following piece of code:
+ </para>
+ <programlisting>
+ guint16 id;
+
+ id = gst_type_find_by_mime ("audio/mpeg");
+ </programlisting>
+ <para>
+ This function will return 0 if the type was not known.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>id to <classname>GstType</classname> conversion</title>
+ <para>
+ We can obtain the <classname>GstType</classname> for a given id
+ with the following piece of code:
+ </para>
+ <programlisting>
+ GstType *type;
+
+ type = gst_type_find_by_id (id);
+ </programlisting>
+ <para>
+ This function will return NULL if the id was associated with
+ any known <classname>GstType</classname>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>extension to id conversion</title>
+ <para>
+ We can obtain the id for a given file extension
+ with the following piece of code:
+ </para>
+ <programlisting>
+ guint16 id;
+
+ id = gst_type_find_by_ext (".mp3");
+ </programlisting>
+ <para>
+ This function will return 0 if the extension was not known.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>id to <classname>GstElementFactory</classname> conversion</title>
+ <para>
+ When we have obtained a given type id using one of the above methods,
+ we can obtain a list of all the elements that operate on this MIME
+ type or extension.
+ </para>
+ <para>
+ Obtain a list of all the elements that use this id as source with:
+ </para>
+ <programlisting>
+ GList *list;
+
+ list = gst_type_gst_srcs (id);
+ </programlisting>
+
+ <para>
+ Obtain a list of all the elements that use this id as sink with:
+ </para>
+ <programlisting>
+ GList *list;
+
+ list = gst_type_gst_sinks (id);
+ </programlisting>
+ <para>
+ When you have a list of elements, you can simply take the first
+ element of the list to obtain an appropriate element.
+ </para>
+ <note>
+ <para>
+ As you can see, there might be a multitude of elements that
+ are able to operate on audio/raw types. some might include:
+ <itemizedlist>
+ <listitem>
+ <para>
+ an MP3 audio encoder.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ an audio sink.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ an audio resampler.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a spectrum filter.
+ </para>
+ </listitem>
+ </itemizedlist>
+ Depending on the application, you might want to use a different
+ element. This is why GStreamer leaves that decision up to the
+ application programmer.
+ </para>
+ </note>
+
+ </sect2>
+
+ <sect2>
+ <title>id to id path detection</title>
+ <para>
+ You can obtain a <classname>GList</classname> of elements that
+ will transform the source id into the destination id.
+ </para>
+ <programlisting>
+ GList *list;
+
+ list = gst_type_gst_sink_to_src (sourceid, sinkid);
+ </programlisting>
+ <para>
+ This piece of code will give you the elements needed to construct
+ a path from sourceid to sinkid. This function is mainly used in
+ autoplugging the pipeline.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1>
+ <title>creating elements with the factory</title>
+ <para>
+ In the previous section we described how you could obtain
+ an element factory using MIME types. One the factory has been
+ obtained, you can create an element using:
+ </para>
+ <programlisting>
+ GstElementFactory *factory;
+ GstElement *element;
+
+ // obtain the factory
+ factory = ...
+
+ element = gst_elementfactory_create (factory, "name");
+ </programlisting>
+ <para>
+ This way, you do not have to create elements by name which
+ allows the end-user to select the elements he/she prefers for the
+ given MIME types.
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>GStreamer basic types</title>
+ <para>
+ GStreamer only has two builtin types:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ audio/raw : raw audio samples
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ video/raw and image/raw : raw video data
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ All other MIME types are maintained by the plugin elements.
+ </para>
+
+ </sect1>
+</chapter>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
-<!ENTITY INTRO SYSTEM "intro.sgml">
-<!ENTITY MOTIVATION SYSTEM "motivation.sgml">
-<!ENTITY GOALS SYSTEM "goals.sgml">
-
-<!ENTITY INIT SYSTEM "init.sgml">
-<!ENTITY ELEMENTS SYSTEM "elements.sgml">
-<!ENTITY PADS SYSTEM "pads.sgml">
-<!ENTITY CONNECTIONS SYSTEM "connections.sgml">
-<!ENTITY BINS SYSTEM "bins.sgml">
-<!ENTITY BUFFERS SYSTEM "buffers.sgml">
-<!ENTITY STATES SYSTEM "states.sgml">
-
-<!ENTITY HELLOWORLD SYSTEM "helloworld.sgml">
-<!ENTITY FACTORIES SYSTEM "factories.sgml">
-<!ENTITY AUTOPLUGGING SYSTEM "autoplugging.sgml">
-<!ENTITY HELLOWORLD2 SYSTEM "helloworld2.sgml">
-
-<!ENTITY THREADS SYSTEM "threads.sgml">
-<!ENTITY QUEUES SYSTEM "queues.sgml">
-<!ENTITY COTHREADS SYSTEM "cothreads.sgml">
-<!ENTITY DYNAMIC SYSTEM "dynamic.sgml">
-<!ENTITY TYPEDETECTION SYSTEM "typedetection.sgml">
-<!ENTITY UTILITY SYSTEM "utility.sgml">
-
-<!ENTITY XML SYSTEM "xml.sgml">
-<!ENTITY PLUGINS SYSTEM "plugins.sgml">
-<!ENTITY DEBUGGING SYSTEM "debugging.sgml">
-<!ENTITY PROGRAMS SYSTEM "programs.sgml">
-<!ENTITY COMPONENTS SYSTEM "components.sgml">
-<!ENTITY QUOTES SYSTEM "quotes.sgml">
+<?xml version='1.0'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY % magic-entities SYSTEM "magic">
+%magic-entities;
+
+<!ENTITY INTRO SYSTEM "intro.xml">
+<!ENTITY MOTIVATION SYSTEM "motivation.xml">
+<!ENTITY GOALS SYSTEM "goals.xml">
+
+<!ENTITY INIT SYSTEM "init.xml">
+<!ENTITY ELEMENTS SYSTEM "elements.xml">
+<!ENTITY PADS SYSTEM "pads.xml">
+<!ENTITY CONNECTIONS SYSTEM "connections.xml">
+<!ENTITY BINS SYSTEM "bins.xml">
+<!ENTITY BUFFERS SYSTEM "buffers.xml">
+<!ENTITY STATES SYSTEM "states.xml">
+
+<!ENTITY HELLOWORLD SYSTEM "helloworld.xml">
+<!ENTITY FACTORIES SYSTEM "factories.xml">
+<!ENTITY AUTOPLUGGING SYSTEM "autoplugging.xml">
+<!ENTITY HELLOWORLD2 SYSTEM "helloworld2.xml">
+
+<!ENTITY THREADS SYSTEM "threads.xml">
+<!ENTITY QUEUES SYSTEM "queues.xml">
+<!ENTITY COTHREADS SYSTEM "cothreads.xml">
+<!ENTITY DYNAMIC SYSTEM "dynamic.xml">
+<!ENTITY TYPEDETECTION SYSTEM "typedetection.xml">
+<!ENTITY UTILITY SYSTEM "utility.xml">
+
+<!ENTITY XML SYSTEM "xml.xml">
+<!ENTITY PLUGINS SYSTEM "plugins.xml">
+<!ENTITY DEBUGGING SYSTEM "debugging.xml">
+<!ENTITY PROGRAMS SYSTEM "programs.xml">
+<!ENTITY COMPONENTS SYSTEM "components.xml">
+<!ENTITY QUOTES SYSTEM "quotes.xml">
]>
<book id="index">
--- /dev/null
+<chapter id="cha-hello">
+ <title>Your first application</title>
+ <para>
+ This chapter describes the most rudimentary aspects of a <application>GStreamer</application> application,
+ including initializing the libraries, creating elements, packing them into
+ a pipeline and playing, pause and stop the pipeline.
+ </para>
+
+ <sect1>
+ <title>Hello world</title>
+ <para>
+ We will create a simple first application. In fact it will be a complete
+ MP3 player, using standard <application>GStreamer</application> components. The player will read from
+ a file that is given as the first argument of the program.
+ </para>
+
+
+ <programlisting>
+
+#include <gst/gst.h>
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *pipeline, *disksrc, *parse, *decoder, *audiosink;
+
+ gst_init(&argc, &argv);
+
+ if (argc != 2) {
+ g_print ("usage: %s <filename>\n", argv[0]);
+ exit (-1);
+ }
+
+ /* create a new pipeline to hold the elements */
+ pipeline = gst_pipeline_new ("pipeline");
+
+ /* create a disk reader */
+ disksrc = gst_elementfactory_make ("disksrc", "disk_source");
+ g_object_set (G_OBJECT (disksrc), "location", argv[1], NULL);
+
+ /* now it's time to get the parser */
+ parse = gst_elementfactory_make ("mp3parse", "parse");
+ decoder = gst_elementfactory_make ("mpg123", "decoder");
+
+ /* and an audio sink */
+ audiosink = gst_elementfactory_make ("osssink", "play_audio");
+
+ /* add objects to the main pipeline */
+ gst_bin_add (GST_BIN (pipeline), disksrc);
+ gst_bin_add (GST_BIN (pipeline), parse);
+ gst_bin_add (GST_BIN (pipeline), decoder);
+ gst_bin_add (GST_BIN (pipeline), audiosink);
+
+ /* connect src to sink */
+ gst_pad_connect (gst_element_get_pad (disksrc, "src"),
+ gst_element_get_pad (parse, "sink"));
+ gst_pad_connect (gst_element_get_pad (parse, "src"),
+ gst_element_get_pad (decoder, "sink"));
+ gst_pad_connect (gst_element_get_pad (decoder, "src"),
+ gst_element_get_pad (audiosink, "sink"));
+
+ /* start playing */
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+ while (gst_bin_iterate (GST_BIN (pipeline)));
+
+ /* stop the pipeline */
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+
+ /* we don't need a reference to these objects anymore */
+ gst_object_unref (GST_OBJECT (audiosink));
+ gst_object_unref (GST_OBJECT (parse));
+ gst_object_unref (GST_OBJECT (decoder));
+ gst_object_unref (GST_OBJECT (disksrc));
+ gst_object_unref (GST_OBJECT (pipeline));
+
+ exit (0);
+}
+
+ </programlisting>
+
+ <para>
+ Let's go through this example step by step.
+ </para>
+
+ <para>
+ The first thing you have to do is to include the standard <application>GStreamer</application> headers and
+ initialize the framework.
+ </para>
+ <programlisting>
+
+#include <gst/gst.h>
+
+ ...
+
+int
+main (int argc, char *argv[])
+{
+ ...
+ gst_init(&argc, &argv);
+ ...
+
+ </programlisting>
+
+ <para>
+ We are going to create 4 elements and one pipeline. Since all objects are
+ in fact elements, we can define them as:
+ </para>
+ <programlisting>
+ ...
+ GstElement *pipeline, *disksrc, *parse, *decoder, *audiosink;
+ ...
+ </programlisting>
+
+ <para>
+ Next, we are going to create an empty pipeline. As you have seen in the basic
+ introduction, this pipeline will hold and manage all the elements we are
+ going to stuff into it.
+ </para>
+ <programlisting>
+ /* create a new pipeline to hold the elements */
+ pipeline = gst_pipeline_new ("pipeline");
+ </programlisting>
+ <para>
+ We use the standard constructor for a pipeline: gst_pipeline_new ("name").
+ </para>
+
+ <para>
+ We then create a disk source element. The disk source element is able to
+ read from a file. We use the standard GObject property mechanism to set
+ a property of the element: the file to read from.
+ </para>
+ <programlisting>
+ /* create a disk reader */
+ disksrc = gst_elementfactory_make ("disksrc", "disk_source");
+ g_object_set (G_OBJECT (disksrc), "location", argv[1], NULL);
+ </programlisting>
+ <note>
+ <para>
+ You can check if the disksrc != NULL to verify the creation of the
+ disk source element.
+ </para>
+ </note>
+
+ <para>
+ We now create the MP3 decoder element. <application>GStreamer</application> requires you
+ to put a parser in front of the decoder. This parser will
+ cut the raw data from the disk source into MP3 frames
+ suitable for the decoder. In the advanced concepts chapter we will
+ see how this can be avoided.
+ </para>
+ <programlisting>
+ /* now it's time to get the parser */
+ parse = gst_elementfactory_make ("mp3parse", "parse");
+ decoder = gst_elementfactory_make ("mpg123", "decoder");
+ </programlisting>
+ <para>
+ gst_elementfactory_make() takes two arguments: a string that will
+ identify the element you need and a second argument: how you want
+ to name the element. The name of the element is something you can
+ choose yourself and might be used to retrieve the element from a
+ bin/pipeline.
+ </para>
+
+ <para>
+ Finally we create our audio sink element. This element will be able
+ to playback the audio using OSS.
+ </para>
+ <programlisting>
+ /* and an audio sink */
+ audiosink = gst_elementfactory_make ("audiosink", "play_audio");
+ </programlisting>
+
+ <para>
+ We then add the elements to the pipeline.
+ </para>
+ <programlisting>
+ /* add objects to the main pipeline */
+ gst_bin_add (GST_BIN (pipeline), disksrc);
+ gst_bin_add (GST_BIN (pipeline), parse);
+ gst_bin_add (GST_BIN (pipeline), decoder);
+ gst_bin_add (GST_BIN (pipeline), audiosink);
+ </programlisting>
+
+ <para>
+ We connect the different pads of the elements together like this:
+ </para>
+ <programlisting>
+ /* connect src to sink */
+ gst_pad_connect (gst_element_get_pad (disksrc, "src"),
+ gst_element_get_pad (parse, "sink"));
+ gst_pad_connect (gst_element_get_pad (parse, "src"),
+ gst_element_get_pad (decoder, "sink"));
+ gst_pad_connect (gst_element_get_pad (decoder, "src"),
+ gst_element_get_pad (audiosink, "sink"));
+ </programlisting>
+
+ <para>
+ We now have a created a complete pipeline. We can visualise the
+ pipeline as follows:
+ </para>
+ <figure float="1" id="sec-hello-img">
+ <title>The Hello world pipeline</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/hello-world.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+
+ </figure>
+
+ <para>
+ Everything is now set up to start the streaming. We use the following
+ statements to change the state of the pipeline:
+ </para>
+ <programlisting>
+ /* start playing */
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+ </programlisting>
+ <note>
+ <para>
+ <application>GStreamer</application> will take care of the READY and PAUSED state for y
+ ou when going from NULL to PLAYING.
+ </para>
+ </note>
+
+ <para>
+ Since we do not use threads, nothing will happen yet. We manually have to
+ call gst_bin_iterate() to execute one iteration of the pipeline.
+ </para>
+ <programlisting>
+ while (gst_bin_iterate (GST_BIN (pipeline)));
+ </programlisting>
+ <para>
+ The gst_bin_iterate() function will return TRUE as long as something interesting
+ happended inside the pipeline. When the end-of-file has been reached the _iterate
+ function will return FALSE and we can end the loop.
+ </para>
+ <programlisting>
+ /* stop the pipeline */
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+
+ gst_object_unref (GST_OBJECT (audiosink));
+ gst_object_unref (GST_OBJECT (decoder));
+ gst_object_unref (GST_OBJECT (disksrc));
+ gst_object_unref (GST_OBJECT (pipeline));
+
+ exit (0);
+ </programlisting>
+ <note>
+ <para>
+ don't forget to set the state of the pipeline to NULL. This will free
+ all of the resources held by the elements.
+ </para>
+ </note>
+
+ </sect1>
+
+ <sect1>
+ <title>compiling helloworld.c</title>
+ <para>
+ To compile the helloworld example, use:
+ </para>
+ <programlisting>
+ gcc -Wall `gstreamer-config --cflags --libs` helloworld.c \
+ -o helloworld
+ </programlisting>
+ <para>
+ This uses the program gstreamer-config, which comes with <application>GStreamer</application>. This program "knows"
+ what compiler switches are needed to compile programs that use <application>GStreamer</application>.
+ gstreamer-config --cflags will output a list of include
+ directories for the compiler to look in, and gstreamer-config --libs will output the
+ list of libraries for the compiler to link with and the directories to find them
+ in.
+ </para>
+ <para>
+ You can run the example with (substitute helloworld.mp3 with you favorite MP3 file):
+ </para>
+ <programlisting>
+ ./helloworld helloworld.mp3
+ </programlisting>
+ </sect1>
+
+ <sect1>
+ <title>conclusion</title>
+ <para>
+ This concludes our first example. As you see, setting up a pipeline
+ is very lowlevel but powerfull. You will later in this manual how
+ you can create a custom MP3 element with a more high level API.
+ </para>
+ <para>
+ It should be clear from the example that we can very easily replace the
+ disksrc element with an httpsrc, giving you instant network streaming.
+ An element could be build to handle icecast connections, for example.
+ </para>
+ <para>
+ We can also choose to use another type of sink instead of the audiosink.
+ We could use a disksink to write the raw samples to a file, for example.
+ It should also be clear that inserting filters, like a stereo effect,
+ into the pipeline is not that hard to do. The most important thing is
+ that you can reuse allready existing elements.
+ </para>
+
+
+ </sect1>
+</chapter>
--- /dev/null
+<chapter id="cha-components">
+ <title>Components</title>
+ <para>
+ <application>GStreamer</application> includes components that people can include
+ in their programs.
+ </para>
+
+ <sect1>
+ <title>GstPlay</title>
+ <para>
+ GstPlay is a GtkWidget with a simple API to play, pause and stop a media file.
+ </para>
+
+ </sect1>
+
+ <sect1>
+ <title>GstMediaPlay</title>
+ <para>
+ GstMediaply is a complete player widget.
+ </para>
+
+ </sect1>
+
+ <sect1>
+ <title>GstEditor</title>
+ <para>
+ GstEditor is a set of widgets to display a graphical representation of a
+ pipeline.
+ </para>
+ </sect1>
+
+</chapter>
--- /dev/null
+<chapter id="cha-intro">
+ <title>Introduction</title>
+ <para>
+ This chapter gives you an overview of the technologies described in this
+ book.
+ </para>
+
+ <sect1 id="sec-intro-what">
+ <title>What is GStreamer?</title>
+ <para>
+ GStreamer is a framework for creating streaming media applications.
+ The fundamental design comes from the video pipeline at Oregon Graduate
+ Institute, as well as some ideas from DirectShow.
+ </para>
+
+ <para>
+ GStreamer's development framework makes it possible to write any
+ streaming multimedia application. The framework includes several
+ components to build a full featured media player capable of playing
+ MPEG1, MPEG2, AVI, MP3, WAV, AU, ...
+ </para>
+
+ <para>
+ GStreamer, however, is much more than just another media player. Its
+ main advantages are that the pluggable components also make it possible
+ to write a full flegded video or audio editing application.
+ </para>
+
+ <para>
+ The framework is based on plug-ins that will provide the various codec
+ and other functionality. The plugins can be connected and arranged in
+ a pipeline. This pipeline defines the flow of the data. Pipelines can
+ also be edited with a GUI editor and saved as XML so that pipeline
+ libraries can be made with a minimum of effort.
+ </para>
+
+ <para>
+ The GStreamer core function is to provide a framework for plugins, data flow
+ and media type handling/negotiation.
+ It also provides an API to write applications using the various plugins.
+ </para>
+
+ <para>
+ This book is about GStreamer from a developer's point of view; it describes
+ how to write a GStreamer application using the GStreamer libraries and tools.
+ </para>
+
+ </sect1>
+</chapter>
--- /dev/null
+<!ENTITY magic "pdf">
--- /dev/null
+<!ENTITY magic "png">
--- /dev/null
+<chapter id="cha-motivation">
+ <title>Motivation</title>
+ <para>
+ Linux has historically lagged behind other operating systems in the multimedia
+ arena. Microsoft's Windows[tm] and Apple's MacOS[tm] both have strong support
+ for multimedia devices, multimedia content creation,
+ playback, and realtime processing. Linux, on the other hand, has a poorly integrated
+ collection of multimedia utilities and applications available, which can hardly compete
+ with the professional level of software available for MS Windows and MacOS.
+ </para>
+
+ <sect1 id="sec-motivation-problems">
+ <title>Current problems</title>
+ <para>
+ We descibe the typical problems in todays media handling on Linux.
+ </para>
+ <sect2 id="sec-motivation-duplicate">
+ <title>Multitude of duplicate code</title>
+ <para>
+ The Linux user who wishes to hear a sound file must hunt through their collection of
+ sound file players in order to play the tens of sound file formats in wide use today.
+ Most of these players basically reimplement the same code over and over again.
+ </para>
+ <para>
+ The Linux developer who wishes to embed a video clip in their application must use
+ crude hacks to run an external video player. There is no library available that a
+ developer can use to create a custom media player.
+ </para>
+
+ </sect2>
+ <sect2 id="sec-motivation-goal">
+ <title>'One goal' media players/libraries</title>
+ <para>
+ Your typical MPEG player was designed to play MPEG video and audio. Most of
+ these players have implemented a complete infrastructure focused on
+ achieving their only goal: playback. No provisions were made to add
+ filters or special effects to the video or audio data.
+ </para>
+ <para>
+ If I wanted to convert an MPEG2 video stream into an AVI file, my best
+ option would be to take all of the MPEG2 decoding algorithms out
+ of the player and duplicate them into my own AVI encoder. These
+ algorithms cannot easily be shared accross applications.
+ </para>
+ <para>
+ Attempts have been made to create libraries for handling various media types.
+ Because they focus on a very specific media type (avifile, libmpeg2, ...),
+ significant work is needed to integrate them due to a lack of a common API.
+ GStreamer allows you to wrap these libraries with a common API, which
+ significantly simplifies integration and reuse.
+ </para>
+ </sect2>
+
+ <sect2 id="sec-motivation-plugin">
+ <title>Non unified plugin mechanisms</title>
+ <para>
+ Your typical media player might have a plugin for different media
+ types. Two media players will typically implement their own plugin
+ mechanism so that the codecs cannot be easily exchanged.
+ </para>
+ <para>
+ The lack of a unified plugin mechanism also seriously hinders the
+ creation of binary only codecs. No company is willing to port their
+ code to all the different plugin mechanisms.
+ </para>
+ <para>
+ While GStreamer also uses it own plugin system it offers a very rich
+ framework for the plugin developper and ensures the plugin can be used
+ in a wide range of applications, transparently interacting with other
+ plugins.
+ </para>
+ </sect2>
+
+ <sect2 id="sec-motivation-network">
+ <title>Provision for network transparency</title>
+ <para>
+ No infrastructure is present to allow network transparent media
+ handling. A distributed MPEG encoder will typically duplicate the
+ same encoder algorithms found in a non-distributed encoder.
+ </para>
+ <para>
+ No provisions have been made for emerging technologies such as
+ the GNOME object embedding using BONOBO.
+ </para>
+ </sect2>
+
+ <sect2 id="sec-motivation-catchup">
+ <title>Catch up with the Windows(tm) world</title>
+ <para>
+ We need solid media handling if we want to see Linux succeed on
+ the desktop.
+ </para>
+ <para>
+ We must clear the road for commercially backed codecs and multimedia
+ applications so that Linux can become an option for doing multimedia.
+ </para>
+ </sect2>
+ </sect1>
+</chapter>
--- /dev/null
+<chapter id="cha-pads">
+ <title>GstPad</title>
+ <para>
+ As we have seen in the previous chapter (GstElement), the pads are the elements
+ connections with the outside world.
+ </para>
+ <para>
+ The specific type of media that the element can handle will be exposed by the pads.
+ The description of this media type is done with capabilities (<classname>GstCaps</classname>)
+ </para>
+
+ <sect1 id="sec-pads-get">
+ <title>Getting pads from an element</title>
+ <para>
+ Once you have created an element, you can get one of its pads with:
+ </para>
+ <programlisting>
+ GstPad *srcpad;
+ ...
+ srcpad = gst_element_get_pad (element, "src");
+ ...
+ </programlisting>
+ <para>
+ This function will get the pad named "src" from the given element.
+ </para>
+ <para>
+ Alternatively, you can also request a GList of pads from the element. The following
+ code example will print the names of all the pads of an element.
+ </para>
+ <programlisting>
+ GList *pads;
+ ...
+ pads = gst_element_get_pad_list (element);
+ while (pads) {
+ GstPad *pad = GST_PAD (pads->data);
+
+ g_print ("pad name %s\n", gst_pad_get_name (pad));
+
+ pads = g_list_next (pads);
+ }
+ ...
+ </programlisting>
+ <sect2 id="sec-pads-functions">
+ <title>Useful pad functions</title>
+ <para>
+ You can get the name of a pad with gst_pad_get_name () and set its name with
+ get_pad_set_name();
+ </para>
+ <para>
+ gst_pad_get_direction (GstPad *pad) can be used to query if the pad is a sink
+ or a src pad. Remember a src pad is a pad that can output data and a sink pad is
+ one that accepts data.
+ </para>
+ <para>
+ You can get the parent of the pad, this is the element that this pad belongs to,
+ with get_pad_set_parent(GstPad *pad). This function will return a pointer to a
+ GstObject.
+ </para>
+ </sect2>
+ <sect2 id="sec-pads-dynamic">
+ <title>Dynamic pads</title>
+ <para>
+ Some elements might not have their pads when they are created. This can, for
+ example, happen with an MPEG2 system demuxer. The demuxer will create its
+ pads at runtime when it detects the different elementary streams in the MPEG2
+ system stream.
+ </para>
+ <para>
+ Running <application>gstreamer-inspect mpeg2parse</application> will show that
+ the element has only one pad: a sink pad called 'sink'. The other pads are
+ "dormant" as you can see in the padtemplates from the 'Exists: Sometimes'
+ property. Depending on the type of MPEG2 file you play, the pads are created. We
+ will see that this is very important when you are going to create dynamic
+ pipelines later on in this manual.
+ </para>
+ <para>
+ You can attach a signal to an element to inform you when the element has created
+ a new pad from one of its padtemplates. The following piece of code is an example
+ of how to do this:
+ </para>
+ <programlisting>
+static void
+pad_connect_func (GstElement *parser, GstPad *pad, GstElement *pipeline)
+{
+ g_print("***** a new pad %s was created\n", gst_pad_get_name(pad));
+
+ gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+ if (strncmp (gst_pad_get_name (pad), "private_stream_1.0", 18) == 0) {
+ // set up an AC3 decoder pipeline
+ ...
+ // connect pad to the AC3 decoder pipeline
+ ...
+ }
+ gst_element_set_state (GST_ELEMENT (audio_thread), GST_STATE_READY);
+}
+
+int
+main(int argc, char *argv[])
+{
+ GstElement *pipeline;
+ GstElement *mpeg2parser;
+
+ // create pipeline and do something usefull
+ ...
+
+ mpeg2parser = gst_elementfactory_make ("mpeg2parse", "mpeg2parse");
+ g_signal_connect (G_OBJECT (mpeg2parser), "new_pad", pad_connect_func, pipeline);
+ ...
+
+ // start the pipeline
+ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
+ ...
+}
+ </programlisting>
+ <note>
+ <para>
+ You need to set the pipeline to READY or NULL if you want to change it.
+ </para>
+ </note>
+ </sect2>
+ <sect2 id="sec-pads-request">
+ <title>Request pads</title>
+ <para>
+ An element can also have request pads. These pads are not created automatically
+ but are only created on demand. This is very usefull for muxers, aggregators
+ and tee elements.
+ </para>
+ <para>
+ The tee element, for example, has one input pad and a request padtemplate for the
+ output pads. Whenever an element wants to get an output pad from the tee element, it
+ has to request the pad.
+ </para>
+ <para>
+ The following piece of code can be used to get a pad from the tee element. After
+ the pad has been requested, it can be used to connect another element to it.
+ </para>
+ <programlisting>
+ ...
+ GstPad *pad;
+ ...
+ element = gst_elementfactory_make ("tee", "element");
+
+ pad = gst_element_request_pad_by_name (element, "src%d");
+ g_print ("new pad %s\n", gst_pad_get_name (pad));
+ ...
+ </programlisting>
+ <para>
+ The gst_element_request_pad_by_name method can be used to get a pad
+ from the element based on the name_template of the padtemplate.
+ </para>
+ <para>
+ It is also possible to request a pad that is compatible with another
+ padtemplate. This is very usefull if you want to connect an element to
+ a muxer element and you need to request a pad that is compatible. The
+ gst_element_request_compatible_pad is used to request a compatible pad, as
+ is shown in the next example.
+ </para>
+ <programlisting>
+ ...
+ GstPadTemplate *templ;
+ GstPad *pad;
+ ...
+ element = gst_elementfactory_make ("tee", "element");
+ mp3parse = gst_elementfactory_make ("mp3parse", "mp3parse");
+
+ templ = gst_element_get_padtemplate_by_name (mp3parse, "sink");
+
+ pad = gst_element_request_compatible_pad (element, templ);
+ g_print ("new pad %s\n", gst_pad_get_name (pad));
+ ...
+ </programlisting>
+ </sect2>
+ </sect1>
+ <sect1 id="sec-pads-description">
+ <title>Capabilities of a GstPad</title>
+ <para>
+ Since the pads play a very important role in how the element is viewed by the
+ outside world, a mechanism is implemented to describe the pad by using capabilities.
+ </para>
+ <para>
+ We will briefly describe what capabilities are, enough for you to get a basic understanding
+ of the concepts. You will find more information on how to create capabilities in the
+ filter-writer-guide.
+ </para>
+
+ <sect2 id="sec-pads-caps">
+ <title>What is a capability</title>
+ <para>
+ A capability is attached to a pad in order to describe what type of media the pad
+ can handle.
+ </para>
+ <para>
+ A capability is named and consists of a MIME type and a set of properties. Its data
+ structure is:
+ </para>
+ <programlisting>
+struct _GstCaps {
+ gchar *name; /* the name of this caps */
+ guint16 id; /* type id (major type) */
+
+ guint refcount; /* caps are refcounted */
+
+ GstProps *properties; /* properties for this capability */
+
+ GstCaps *next; /* caps can be chained together */
+};
+ </programlisting>
+ <para>
+ Below is a dump of the capabilities of the element mpg123, as shown by
+ <command>gstreamer-inspect</command>.
+ You can see two pads: sink and src. Both pads have capability information attached to them.
+ </para>
+ <para>
+ The sink pad (input pad) is called 'sink' and takes data of MIME type 'audio/mp3'. It also has
+ three properties: layer, bitrate and framed.
+ </para>
+ <para>
+ The src pad (output pad) is called 'src' and outputs data of MIME type 'audio/raw'. It also has
+ four properties: format, depth, rate and channels.
+ </para>
+ <programlisting>
+Pads:
+ SINK: 'sink'
+ ....
+ Capabilities:
+ 'mpg123_sink':
+ MIME type: 'audio/mp3':
+ layer: Integer range: 1 - 3
+ bitrate: Integer range: 8 - 320
+ framed: Boolean: TRUE
+
+ SRC: 'src'
+ ....
+ Capabilities:
+ 'mpg123_src':
+ MIME type: 'audio/raw':
+ format: Integer: 16
+ depth: Integer: 16
+ rate: Integer range: 11025 - 48000
+ channels: List:
+ Integer: 1
+ Integer: 2
+ </programlisting>
+ </sect2>
+ <sect2 id="sec-pads-props">
+ <title>What are properties</title>
+ <para>
+ Properties are used to describe extra information for the capabilities. The properties
+ basically exist of a key (a string) and a value. There are different possibile value types
+ that can be used:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ An integer value: the property has this exact value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ An integer range value. The property denotes a range of possible values. In the case
+ of the mpg123 element: the src pad has a property rate that can go from 11025 to 48000.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A boolean value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a fourcc value: this is a value that is commonly used to describe an encoding for video,
+ as used be the AVI specification.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A list value: the property can take any value from a list.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A float value: the property has this exact floating point value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A float range value: denotes a range of possible floating point values.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A string value.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+ <sect2 id="sec-pads-caps-use">
+ <title>What are the capabilities used for?</title>
+ <para>
+ Capabilities describe in great detail the type of media that is handled by the pads.
+ They are mostly used for:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Autoplugging: automatically finding plugins for a set of capabilities
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Compatibility detection: when two pads are connected, <application>GStreamer</application>
+ can verify if the two pads are talking about the same media types.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ <sect2 id="sec-pads-caps-get">
+ <title>Getting the capabilities of a pad</title>
+ <para>
+ A pad can have a chain of capabilities attached to it. You can get the capabilities chain
+ with:
+ </para>
+ <programlisting>
+ GstCaps *caps;
+ ...
+ caps = gst_pad_get_caps (pad);
+
+ g_print ("pad name %s\n", gst_pad_get_name (pad));
+
+ while (caps) {
+ g_print (" Capability name %s, MIME type %s\n",
+ gst_caps_get_name (cap),
+ gst_caps_get_mime (cap));
+
+ caps = caps->next;
+ }
+ ...
+ </programlisting>
+ </sect2>
+ <sect2 id="sec-pads-caps-create">
+ <title>Creating capabilities structures</title>
+ <para>
+ While the capabilities are mainly used inside the plugin to describe the media type of the
+ pads, the application programmer also has to have basic understanding of caps in order to
+ interface with the plugins, specially when using the autopluggers.
+ </para>
+ <para>
+ As we said, a capability has a name, a mime-type and some properties. The signature of the
+ function to create a new <classname>GstCaps *</classname> structure is like:
+ <programlisting>
+GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
+ </programlisting>
+ </para>
+ <para>
+ You can therefore create a new capability with no properties like this:
+ <programlisting>
+ GstCaps *newcaps;
+
+ newcaps = gst_caps_new ("my_caps", "audio/wav", NULL);
+ </programlisting>
+ </para>
+ <para>
+ <classname>GstProps</classname> basically consist of a set of key-value pairs
+ and are created with a function with this signature:
+ <programlisting>
+GstProps* gst_props_new (const gchar *firstname, ...);
+ </programlisting>
+ </para>
+ <para>
+ The keys are given as strings and the values are given with a set of macros:
+ <itemizedlist>
+ <listitem>
+ <para>
+ GST_PROPS_INT(a): An integer value
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ GST_PROPS_FLOAT(a): A floating point value
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ GST_PROPS_FOURCC(a): A fourcc value
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ GST_PROPS_BOOLEAN(a): A boolean value
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ GST_PROPS_STRING(a): A string value
+ </para>
+ </listitem>
+ </itemizedlist>
+ The values can also be specified as ranges with:
+ <itemizedlist>
+ <listitem>
+ <para>
+ GST_PROPS_INT_RANGE(a,b): An integer ragne from a to b
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ GST_PROPS_FLOAT_RANGE(a,b): A float ragne from a to b
+ </para>
+ </listitem>
+ </itemizedlist>
+ All of the above values can be given with a list too, using:
+ <itemizedlist>
+ <listitem>
+ <para>
+ GST_PROPS_LIST(a,...): A list of property values.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ A more complex capability with properties is created like this:
+ <programlisting>
+ GstCaps *newcaps;
+
+ newcaps = gst_caps_new ("my_caps",
+ "audio/wav",
+ gst_props_new (
+ "bitrate", GST_PROPS_INT_RANGE (11025,22050),
+ "depth", GST_PROPS_INT (16),
+ "signed", GST_PROPS_LIST (
+ GST_PROPS_BOOLEAN (TRUE),
+ GST_PROPS_BOOLEAN (FALSE)
+ ),
+ NULL
+ );
+ </programlisting>
+ Optionally the convenient shortcut macro can be used. The above complex
+ capability can be created with:
+ <programlisting>
+ GstCaps *newcaps;
+
+ newcaps = GST_CAPS_NEW ("my_caps",
+ "audio/wav",
+ "bitrate", GST_PROPS_INT_RANGE (11025,22050),
+ "depth", GST_PROPS_INT (16),
+ "signed", GST_PROPS_LIST (
+ GST_PROPS_BOOLEAN (TRUE),
+ GST_PROPS_BOOLEAN (FALSE)
+ )
+ );
+ </programlisting>
+ </para>
+ </sect2>
+
+ </sect1>
+</chapter>
--- /dev/null
+<chapter id="cha-plugins">
+ <title>What are Plugins</title>
+ <para>
+ A plugin is a shared library that contains at least one of the following items:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ one or more elementfactories
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ one or more typedefinitions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ one or more autopluggers
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ The plugins have one simple method: plugin_init () where all the elementfactories are
+ created and the typedefinitions are registered.
+ </para>
+ <para>
+ the plugins are maintained in the plugin system. Optionally, the typedefinitions and
+ the elementfactories can be saved into an XML representation so that the plugin system
+ does not have to load all available plugins in order to know their definition.
+ </para>
+
+ <para>
+ The basic plugin structure has the following fields:
+ </para>
+ <programlisting>
+struct _GstPlugin {
+ gchar *name; /* name of the plugin */
+ gchar *longname; /* long name of plugin */
+ gchar *filename; /* filename it came from */
+
+ GList *types; /* list of types provided */
+ gint numtypes;
+ GList *elements; /* list of elements provided */
+ gint numelements;
+ GList *autopluggers; /* list of autopluggers provided */
+ gint numautopluggers;
+
+ gboolean loaded; /* if the plugin is in memory */
+};
+ </programlisting>
+
+ <para>
+ You can query a GList of available plugins with:
+ </para>
+ <programlisting>
+ GList *plugins;
+
+ plugins = gst_plugin_get_list ();
+
+ while (plugins) {
+ GstPlugin *plugin = (GstPlugin *)plugins->data;
+
+ g_print ("plugin: %s\n", gst_plugin_get_name (plugin));
+
+ plugins = g_list_next (plugins);
+ }
+ </programlisting>
+</chapter>
--- /dev/null
+<chapter id="cha-programs">
+ <title>Programs</title>
+ <para>
+ </para>
+
+ <sect1>
+ <title><command>gstreamer-config</command></title>
+ <para>
+ <command>gstreamer-config</command> is a script to get information about the installed
+ version of <application>GStreamer</application>.
+ This program "knows" what compiler switches are needed to compile programs that use
+ <application>GStreamer</application>.
+ </para>
+
+ <para>
+ <command>gstreamer-config</command> accepts the following options:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <option>--version</option> Print the currently installed version of
+ <application>GStreamer</application> on the standard output.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--libs</option> Print the linker flags that are necessary to link a
+ <application>GStreamer</application> program.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--cflags</option> Print the compiler flags that are necessary to compile a
+ <application>GStreamer</application> program.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--prefix=<replaceable>PREFIX</replaceable></option>
+ If specified, use <replaceable>PREFIX</replaceable> instead of the installation
+ prefix that <application>GStreamer</application> was built with when computing the
+ output for the <option>--cflags</option> and <option>--libs</option> options.
+ This option is also used for the exec prefix if
+ <option>--exec-prefix</option> was not specified. This option must be specified before any
+ <option>--libs</option> or <option>--cflags</option> options.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>--exec-prefix=<replaceable>PREFIX</replaceable></option>
+ If specified, use <replaceable>PREFIX</replaceable> instead of the installation exec
+ prefix that <application>GStreamer</application> was built with when computing the
+ output for the <option>--cflags</option> and <option>--libs</option> options. This option must be
+ specified before any <option>--libs</option> or <option>--cflags</option>
+ options.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ A simple <filename>Makefile</filename> will contain something like:
+ <programlisting>
+CC = gcc
+
+helloworld2: helloworld2.c
+ $(CC) -Wall `gstreamer-config --cflags --libs` helloworld2.c -o helloworld2
+
+clean:
+ rm -f *.o helloworld2
+ </programlisting>
+ </para>
+ </sect1>
+
+ <sect1>
+ <title><command>gstreamer-register</command></title>
+ <para>
+ <command>gstreamer-register</command> is used to rebuild the database of plugins.
+ It is used after a new plugin has been added to the system. The plugin database
+ can be found in <filename>/etc/gstreamer/reg.xml</filename>.
+ </para>
+ </sect1>
+
+ <sect1>
+ <title><command>gstreamer-launch</command></title>
+ <para>
+ This is a tool that will construct pipelines based on a command-line
+ syntax.
+ </para>
+ <para>
+ A simple commandline looks like:
+
+ <screen>
+gstreamer-launch disksrc location=hello.mp3 ! mp3parse ! mpg123 ! audiosink
+ </screen>
+
+ A more complex pipeline looks like:
+
+ <screen>
+gstreamer-launch disksrc redpill.vob audio_00! (ac3parse ! ac3dec ! audiosink) \
+video_00! (mpeg2dec ! videosink)
+ </screen>
+
+ </para>
+ <para>
+ Note that the parser isn't capable of more complex pipelines yet, including
+ the VOB player above. The minor tweaks will be made post 0.2.1.
+ </para>
+ <para>
+ You can also use the the parser in you own code. <application>GStreamer</application>
+ provides a function gst_parse_launch () that you can use to construt a pipeline.
+ The following programs lets you create an mp3 pipeline using the gst_parse_launch ()
+ function:
+ </para>
+ <programlisting>
+#include <gst/gst.h>
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *pipeline;
+ GstElement *disksrc;
+
+ gst_init (&argc, &argv);
+
+ if (argc != 2) {
+ g_print ("usage: %s <filename>\n", argv[0]);
+ return -1;
+ }
+ pipeline = gst_pipeline_new ("my_pipeline");
+
+ gst_parse_launch ("disksrc[my_disksrc] ! mp3parse ! mpg123 ! osssink", GST_BIN (pipeline));
+
+ disksrc = gst_bin_get_by_name (GST_BIN (pipeline), "my_disksrc");
+ g_object_set (G_OBJECT (disksrc), "location", argv[1], NULL);
+
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+ while (gst_bin_iterate (GST_BIN (pipeline)));
+
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+
+ return 0;
+}
+ </programlisting>
+ <para>
+ Note how we can retrieve the disksrc element from the constructed bin using the
+ element name.
+ </para>
+ </sect1>
+
+ <sect1>
+ <title><command>gstreamer-inspect</command></title>
+ <para>
+ This is a tool to query a plugin or an element about its properties.
+ </para>
+ <para>
+ To query the information about the element mpg123, you would specify:
+ </para>
+
+ <screen>
+gstreamer-inspect mpg123
+ </screen>
+
+ <para>
+ Below is the output of a query for the audiosink element:
+ </para>
+
+ <screen>
+Factory Details:
+ Long name: Audio Sink (OSS)
+ Class: Sink/Audio
+ Description: Output to a sound card via OSS
+ Version: 0.1.0
+ Author(s): Erik Walthinsen <omega@cse.ogi.edu>
+ Copyright: (C) 1999
+
+Pad Templates:
+ SINK template: 'sink'
+ Exists: Always
+ Capabilities:
+ 'audiosink_sink':
+ MIME type: 'audio/raw':
+ format: Integer: 16
+ depth: List:
+ Integer: 8
+ Integer: 16
+ rate: Integer range: 8000 - 48000
+ channels: Integer range: 1 - 2
+
+Element Flags:
+ GST_ELEMENT_THREADSUGGESTED
+ no flags set
+
+Element Implementation:
+ No loopfunc(), must be chain-based or not configured yet
+ Has change_state() function
+
+Pads:
+ SINK: 'sink'
+ Implementation:
+ Has chainfunc(): 0x4001cde8
+ Has default eosfunc() gst_pad_eos_func()
+ Pad Template: 'sink'
+ Capabilities:
+ 'audiosink_sink':
+ MIME type: 'audio/raw':
+ format: Integer: 16
+ depth: List:
+ Integer: 8
+ Integer: 16
+ rate: Integer range: 8000 - 48000
+ channels: Integer range: 1 - 2
+
+Element Arguments:
+ GstAudioSink::mute: Boolean
+ GstAudioSink::format: Enum (default 16)
+ (8): 8 Bits
+ (16): 16 Bits
+ GstAudioSink::channels: Enum (default 2)
+ (1): Mono
+ (2): Stereo
+ GstAudioSink::frequency: Integer
+ </screen>
+
+ <para>
+ To query the information about a plugin, you would do:
+ </para>
+
+ <screen>
+gstreamer-inspect gstelements
+ </screen>
+ </sect1>
+ <sect1>
+ <title><command>gstmediaplay</command></title>
+ <para>
+ A sample media player.
+ </para>
+ </sect1>
+
+</chapter>
<title>a two-threaded decoder with a queue</title>
<mediaobject>
<imageobject>
- <imagedata fileref="images/queue" format="PNG">
+ <imagedata fileref="images/queue.&magic;" format="&magic;" />
</imageobject>
</mediaobject>
</figure>
--- /dev/null
+<chapter id="cha-quotes">
+ <title>Quotes from the Developers</title>
+ <para>
+ As well as being a cool piece of software,
+ <application>GStreamer</application> is a lively project, with
+ developers from around the globe very actively contributing.
+ We often hang out on the #gstreamer IRC channel on
+ irc.openprojects.net: the following are a selection of amusing<footnote>
+ <para>No guarantee of sense of humour compatibility is given.</para>
+ </footnote> quotes from our conversations.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>16 Feb 2001</term>
+ <listitem>
+ <para>
+ <emphasis>wtay:</emphasis>
+ I shipped a few commerical products to >40000 people now but
+ GStreamer is way more exciting...
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>16 Feb 2001</term>
+ <listitem>
+ <para>
+ *
+ <emphasis>tool-man</emphasis>
+ is a gstreamer groupie
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>14 Jan 2001</term>
+ <listitem>
+ <para>
+ <emphasis>Omega:</emphasis>
+ did you run ldconfig? maybe it talks to init?
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ not sure, don't think so...
+ I did run gstreamer-register though :-)
+ </para>
+ <para>
+ <emphasis>Omega:</emphasis>
+ ah, that did it then ;-)
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ right
+ </para>
+ <para>
+ <emphasis>Omega:</emphasis>
+ probably not, but in case GStreamer starts turning into an OS, someone please let me know?
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>9 Jan 2001</term>
+ <listitem>
+ <para>
+ <emphasis>wtay:</emphasis>
+ me tar, you rpm?
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ hehe, forgot "zan"
+ </para>
+ <para>
+ <emphasis>Omega:</emphasis>
+ ?
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ me tar"zan", you ...
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>7 Jan 2001</term>
+ <listitem>
+ <para>
+ <emphasis>Omega:</emphasis>
+ that means probably building an agreggating, cache-massaging
+ queue to shove N buffers across all at once, forcing cache
+ transfer.
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ never done that before...
+ </para>
+ <para>
+ <emphasis>Omega:</emphasis>
+ nope, but it's easy to do in gstreamer <g>
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ sure, I need to rewrite cp with gstreamer too, someday :-)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>7 Jan 2001</term>
+ <listitem>
+ <para>
+ <emphasis>wtay:</emphasis>
+ GStreamer; always at least one developer is awake...
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>5/6 Jan 2001</term>
+ <listitem>
+ <para>
+ <emphasis>wtay:</emphasis>
+ we need to cut down the time to create an mp3 player down to
+ seconds...
+ </para>
+ <para>
+ <emphasis>richardb:</emphasis>
+ :)
+ </para>
+ <para>
+ <emphasis>Omega:</emphasis>
+ I'm wanting to something more interesting soon, I did the "draw an mp3
+ player in 15sec" back in October '99.
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ by the time Omega gets his hands on the editor, you'll see a
+ complete audio mixer in the editor :-)
+ </para>
+ <para>
+ <emphasis>richardb:</emphasis>
+ Well, it clearly has the potential...
+ </para>
+ <para>
+ <emphasis>Omega:</emphasis>
+ Working on it... ;-)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>28 Dec 2000</term>
+ <listitem>
+ <para>
+ <emphasis>MPAA:</emphasis>
+ We will sue you now, you have violated oru IP rights!
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ hehehe
+ </para>
+ <para>
+ <emphasis>MPAA:</emphasis>
+ How dare you laugh at us? We have lawyers! We have Congressmen! We have <emphasis>LARS</emphasis>!
+ </para>
+ <para>
+ <emphasis>wtay:</emphasis>
+ I'm so sorry your honor
+ </para>
+ <para>
+ <emphasis>MPAA:</emphasis>
+ Hrumph.
+ </para>
+ <para>
+ *
+ <emphasis>wtay</emphasis>
+ bows before thy
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>4 Jun 2001</term>
+ <listitem>
+ <para><emphasis>taaz:</emphasis> you witchdoctors and your voodoo mpeg2 black magic... </para>
+ <para><emphasis>omega_:</emphasis> um. I count three, no four different cults there <g> </para>
+ <para><emphasis>ajmitch:</emphasis> hehe </para>
+ <para><emphasis>omega_:</emphasis> witchdoctors, voodoo, black magic, </para>
+ <para><emphasis>omega_:</emphasis> and mpeg </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+</chapter>
<para>
You can set the following states to an element:
</para>
- <informaltable pgwide=1 frame="none" role="enum">
+ <informaltable pgwide="1" frame="none" role="enum">
<tgroup cols="2">
- <colspec colwidth="2*">
- <colspec colwidth="8*">
+ <colspec colwidth="2*" />
+ <colspec colwidth="8*" />
<tbody>
<row>
<entry><literal>GST_STATE_NULL</literal></entry>
--- /dev/null
+<chapter id="cha-threads">
+ <title>Threads</title>
+ <para>
+ GStreamer has support for multithreading throught the use of
+ the <classname>GstThread</classname> object. This object is in fact
+ a special <classname>GstBin</classname> that will become a thread when started.
+ </para>
+
+ <para>
+ To construct a new thread you will perform something like:
+ </para>
+
+ <programlisting>
+ GstElement *my_thread;
+
+ // create the thread object
+ my_thread = gst_thread_new ("my_thread");
+ g_return_if_fail (audio_thread != NULL);
+
+ // add some plugins
+ gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (funky_src));
+ gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect));
+
+ // connect the elements here...
+ ...
+
+ // start playing
+ gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING);
+
+ </programlisting>
+
+ <para>
+ The above program will create a thread with two elements in it. As soon
+ as it is set to the PLAYING state, the thread will start to iterate.
+ </para>
+
+ <note>
+ <para>
+ A thread should normally contain a source element. Most often, the thread
+ is fed with data from a queue.
+ </para>
+ </note>
+
+ <para>
+ A thread will be visualised as below
+ </para>
+ <figure float="1" id="sec-threads-img">
+ <title>a thread</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/thread.&magic;" format="&magic;" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ As an example we show the helloworld program using a thread.
+ </para>
+
+ <programlisting>
+#include <gst/gst.h>
+
+/* eos will be called when the src element has an end of stream */
+void
+eos (GstSrc *src, gpointer data)
+{
+ GstThread *thread = GST_THREAD (data);
+ g_print ("have eos, quitting\n");
+
+ /* stop the bin */
+ gst_element_set_state (GST_ELEMENT (thread), GST_STATE_NULL);
+
+ gst_main_quit ();
+}
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *disksrc, *audiosink;
+ GstElement *pipeline;
+ GstElement *thread;
+
+ if (argc != 2) {
+ g_print ("usage: %s <filename>\n", argv[0]);
+ exit (-1);
+ }
+
+ gst_init (&argc, &argv);
+
+ /* create a new thread to hold the elements */
+ thread = gst_thread_new ("thread");
+ g_assert (thread != NULL);
+
+ /* create a new bin to hold the elements */
+ pipeline = gst_pipeline_new ("pipeline");
+ g_assert (pipeline != NULL);
+
+ /* create a disk reader */
+ disksrc = gst_elementfactory_make ("disksrc", "disk_source");
+ g_assert (disksrc != NULL);
+ g_object_set (G_OBJECT (disksrc), "location", argv[1], NULL);
+ g_signal_connect (G_OBJECT (disksrc), "eos",
+ G_CALLBACK (eos), thread);
+
+ /* and an audio sink */
+ audiosink = gst_elementfactory_make ("audiosink", "play_audio");
+ g_assert (audiosink != NULL);
+
+ /* add objects to the main pipeline */
+ gst_bin_add (GST_BIN (pipeline), disksrc);
+ gst_bin_add (GST_BIN (pipeline), audiosink);
+
+ /* automatically setup the pipeline */
+ if (!gst_pipeline_autoplug (GST_PIPELINE (pipeline))) {
+ g_print ("unable to handle stream\n");
+ exit (-1);
+ }
+
+ /* remove the source element from the pipeline */
+ gst_bin_remove (GST_BIN (pipeline), disksrc);
+
+ /* insert the source element in the thread, remember a thread needs at
+ least one source or connection element */
+ gst_bin_add (GST_BIN (thread), disksrc);
+
+ /* add the pipeline to the thread too */
+ gst_bin_add (GST_BIN (thread), GST_ELEMENT (pipeline));
+
+ /* start playing */
+ gst_element_set_state (GST_ELEMENT (thread), GST_STATE_PLAYING);
+
+ /* do whatever you want here, the thread will be playing */
+ ...
+
+ gst_main ();
+
+ gst_pipeline_destroy (thread);
+
+ exit (0);
+}
+ </programlisting>
+
+</chapter>
--- /dev/null
+<chapter id="cha-xml">
+ <title>XML in <application>GStreamer</application></title>
+ <para>
+ <application>GStreamer</application> uses XML to store and load
+ its pipeline definitions. XML is also used internally to manage the
+ plugin registry. The plugin registry is a file that contains the definition
+ of all the plugins <application>GStreamer</application> knows about to have
+ quick access to the specifics of the plugins.
+ </para>
+
+ <para>
+ We will show you how you can save a pipeline to XML and how you can reload that
+ XML file again for later use.
+ </para>
+
+ <sect1 id="sec-xml-write">
+ <title>Turning GstElements into XML</title>
+
+ <para>
+ We create a simple pipeline and save it to disk with gst_xml_write (). The following
+ code constructs an mp3 player pipeline with two threads and finaly writes it to disk.
+ use this program with one argument: the mp3 file on disk.
+ </para>
+
+ <programlisting>
+#include <stdlib.h>
+#include <gst/gst.h>
+
+gboolean playing;
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *disksrc, *audiosink, *queue, *queue2, *parse, *decode;
+ GstElement *bin;
+ GstElement *thread, *thread2;
+
+ gst_init (&argc,&argv);
+
+ if (argc != 2) {
+ g_print ("usage: %s <filename>\n", argv[0]);
+ exit (-1);
+ }
+
+ /* create a new thread to hold the elements */
+ thread = gst_elementfactory_make ("thread", "thread");
+ g_assert (thread != NULL);
+ thread2 = gst_elementfactory_make ("thread", "thread2");
+ g_assert (thread2 != NULL);
+
+ /* create a new bin to hold the elements */
+ bin = gst_bin_new ("bin");
+ g_assert (bin != NULL);
+
+ /* create a disk reader */
+ disksrc = gst_elementfactory_make ("disksrc", "disk_source");
+ g_assert (disksrc != NULL);
+ g_object_set (G_OBJECT (disksrc), "location", argv[1], NULL);
+
+ queue = gst_elementfactory_make ("queue", "queue");
+ queue2 = gst_elementfactory_make ("queue", "queue2");
+
+ /* and an audio sink */
+ audiosink = gst_elementfactory_make ("audiosink", "play_audio");
+ g_assert (audiosink != NULL);
+
+ parse = gst_elementfactory_make ("mp3parse", "parse");
+ decode = gst_elementfactory_make ("mpg123", "decode");
+
+ /* add objects to the main bin */
+ gst_bin_add (GST_BIN (bin), disksrc);
+ gst_bin_add (GST_BIN (bin), queue);
+
+ gst_bin_add (GST_BIN (thread), parse);
+ gst_bin_add (GST_BIN (thread), decode);
+ gst_bin_add (GST_BIN (thread), queue2);
+
+ gst_bin_add (GST_BIN (thread2), audiosink);
+
+ gst_pad_connect (gst_element_get_pad (disksrc,"src"),
+ gst_element_get_pad (queue,"sink"));
+
+ gst_pad_connect (gst_element_get_pad (queue,"src"),
+ gst_element_get_pad (parse,"sink"));
+ gst_pad_connect (gst_element_get_pad (parse,"src"),
+ gst_element_get_pad (decode,"sink"));
+ gst_pad_connect (gst_element_get_pad (decode,"src"),
+ gst_element_get_pad (queue2,"sink"));
+
+ gst_pad_connect (gst_element_get_pad (queue2,"src"),
+ gst_element_get_pad (audiosink,"sink"));
+
+ gst_bin_add (GST_BIN (bin), thread);
+ gst_bin_add (GST_BIN (bin), thread2);
+
+ // write the bin to disk
+ xmlSaveFile ("xmlTest.gst", gst_xml_write (GST_ELEMENT (bin)));
+
+ exit (0);
+}
+ </programlisting>
+ <para>
+ The most important line is:
+ </para>
+ <programlisting>
+ xmlSaveFile ("xmlTest.gst", gst_xml_write (GST_ELEMENT (bin)));
+ </programlisting>
+ <para>
+ gst_xml_write () will turn the given element into and xmlDocPtr that
+ can be saved with the xmlSaveFile () function found in the gnome-xml
+ package. The result is an XML file named xmlTest.gst.
+ </para>
+ <para>
+ The complete element hierarchy will be saved along with the inter element
+ pad connections and the element parameters. Future <application>GStreamer</application>
+ versions will also allow you to store the signals in the XML file.
+ </para>
+ </sect1>
+
+ <sect1 id="sec-xml-load">
+ <title>Loading a GstElement from an XML file</title>
+ <para>
+ Before an XML file can be loaded, you must create a GstXML object.
+ A saved XML file can then be loaded with the
+ gst_xml_parse_file (xml, filename, rootelement) method.
+ The root element can optionally left NULL. The following code example loads
+ the previously created XML file and runs it.
+ </para>
+ <programlisting>
+#include <stdlib.h>
+#include <gst/gst.h>
+
+int
+main(int argc, char *argv[])
+{
+ GstXML *xml;
+ GstElement *bin;
+ gboolean ret;
+
+ gst_init (&argc, &argv);
+
+ xml = gst_xml_new ();
+
+ ret = gst_xml_parse_file(xml, "xmlTest.gst", NULL);
+ g_assert (ret == TRUE);
+
+ bin = gst_xml_get_element (xml, "bin");
+ g_assert (bin != NULL);
+
+ gst_element_set_state (bin, GST_STATE_PLAYING);
+
+ while (gst_bin_iterate(GST_BIN(bin)));
+
+ gst_element_set_state (bin, GST_STATE_NULL);
+
+ exit (0);
+}
+ </programlisting>
+ <para>
+ gst_xml_get_element (xml, "name") can be used to get a specific element
+ from the XML file.
+ </para>
+ <para>
+ gst_xml_get_topelements (xml) can be used to get a list of all toplevel elements
+ in the XML file.
+ </para>
+ <para>
+ In addition to loading a file, you can also load a from a xmlDocPtr and
+ an in memory buffer using gst_xml_parse_doc and gst_xml_parse_memory
+ respectivily. both of these methods return a gboolean indicating success
+ or failure of the requested action.
+ </para>
+ </sect1>
+ <sect1 id="sec-xml-custom">
+ <title>Adding custom XML tags into the core XML data</title>
+
+ <para>
+ It is possible to add custom XML tags to the core XML created with
+ gst_xml_write. This feature can be used by an application to add more
+ information to the save plugins. the editor will for example insert
+ the position of the elements on the screen using the custom XML tags.
+ </para>
+ <para>
+ It is strongly suggested to save and load the custom XML tags using
+ a namespace. This will solve the problem of having your XML tags
+ interfere with the core XML tags.
+ </para>
+ <para>
+ To insert a hook into the element saving procedure you can connect
+ a signal to the GstElement using the following piece of code:
+ </para>
+ <programlisting>
+xmlNsPtr ns;
+
+ ...
+ ns = xmlNewNs (NULL, "http://gstreamer.net/gst-test/1.0/", "test");
+ ...
+ thread = gst_elementfactory_make ("thread", "thread");
+ g_signal_connect (G_OBJECT (thread), "object_saved",
+ G_CALLBACK (object_saved), g_strdup ("decoder thread"));
+ ...
+ </programlisting>
+ <para>
+ When the thread is saved, the object_save method will be caled. Our example
+ will insert a comment tag:
+ </para>
+ <programlisting>
+static void
+object_saved (GstObject *object, xmlNodePtr parent, gpointer data)
+{
+ xmlNodePtr child;
+
+ child = xmlNewChild (parent, ns, "comment", NULL);
+ xmlNewChild (child, ns, "text", (gchar *)data);
+}
+ </programlisting>
+ <para>
+ Adding the custom tag code to the above example you will get an XML file
+ with the custom tags in it. Here's an excerpt:
+ </para>
+ <programlisting>
+ ...
+ <gst:element>
+ <gst:name>thread</gst:name>
+ <gst:type>thread</gst:type>
+ <gst:version>0.1.0</gst:version>
+ ...
+ </gst:children>
+ <test:comment>
+ <test:text>decoder thread</test:text>
+ </test:comment>
+ </gst:element>
+ ...
+ </programlisting>
+ <para>
+ To retrieve the custom XML again, you need to attach a signal to
+ the GstXML object used to load the XML data. You can then parse your
+ custom XML from the XML tree whenever an object is loaded.
+ </para>
+
+ <para>
+ We can extend our previous example with the following piece of
+ code.
+ </para>
+
+ <programlisting>
+ xml = gst_xml_new ();
+
+ g_signal_connect (G_OBJECT (xml), "object_loaded",
+ G_CALLBACK (xml_loaded), xml);
+
+ ret = gst_xml_parse_file (xml, "xmlTest.gst", NULL);
+ g_assert (ret == TRUE);
+ </programlisting>
+
+ <para>
+ Whenever a new object has been loaded, the xml_loaded function will be
+ called. this function looks like:
+ </para>
+ <programlisting>
+static void
+xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data)
+{
+ xmlNodePtr children = self->xmlChildrenNode;
+
+ while (children) {
+ if (!strcmp (children->name, "comment")) {
+ xmlNodePtr nodes = children->xmlChildrenNode;
+
+ while (nodes) {
+ if (!strcmp (nodes->name, "text")) {
+ gchar *name = g_strdup (xmlNodeGetContent (nodes));
+ g_print ("object %s loaded with comment '%s'\n",
+ gst_object_get_name (object), name);
+ }
+ nodes = nodes->next;
+ }
+ }
+ children = children->next;
+ }
+}
+ </programlisting>
+ <para>
+ As you can see, you'll get a handle to the GstXML object, the
+ newly loaded GstObject and the xmlNodePtr that was used to create
+ this object. In the above example we look for our special tag inside
+ the XML tree that was used to load the object and we print our
+ comment to the console.
+ </para>
+ </sect1>
+
+</chapter>
-# Included by directories containing manuals.
-# Expects the following to be defined:
-# manualname
-# htmlname
-# sgml_files
-# fig_files
-# eps_files
-# png_files
-
-PDFFILES=$(manualname).pdf
-PSFILES=$(manualname).ps
-
-if HAVE_FIG2DEV_PNG
-PNGS_TO_MAKE=$(png_files)
-else
-PNGS_TO_MAKE=
-endif
-
-$(manualname)/$(htmlname): $(sgml_files) $(PNGS_TO_MAKE)
-if HAVE_DB2HTML
- db2html $(manualname).sgml
-else
- @echo "Can't build $@: don't have db2html tool"
-endif
-
-$(manualname).pdf: $(manualname).ps
-if HAVE_PS2PDF
- @if [ -r $< ] ; then ps2pdf $< $@ ; fi
-else
- @echo "Can't build $@: don't have ps2pdf tool"
-endif
-
-if HAVE_FIG2DEV_EPS
-$(manualname).ps: $(sgml_files) $(eps_files)
-else
-$(manualname).ps: $(sgml_files)
-endif
-if HAVE_DB2PS
- @if [ -r $< ] ; then db2ps $(manualname).sgml ; fi
-else
- @echo "Can't build $@: don't have db2ps tool"
-endif
-
-images :
- mkdir images
-
-if HAVE_FIG2DEV_PNG
-images/%.png : %.fig images
- fig2dev -L png -s 16 $< $@
-endif
-
-if HAVE_FIG2DEV_EPS
-images/%.eps : %.fig images
- fig2dev -L eps -s 16 -m 0.5 $< $@
-endif
-
-$(manualname)/images:
- @if [ -d $(manualname) ] ; then \
- if [ -d images ] ; then \
- ln -sf ../images $(manualname)/images ;\
- fi \
- fi
-
-htmldocs: $(manualname)/$(htmlname) $(manualname)/images
-pdfdocs: $(PDFFILES)
-psdocs: $(PSFILES)
-
-# Data to install, in the usual automake way
-docdatadir = $(datadir)/gstreamer
-docdata_DATA = $(PDFFILES) $(PSFILES)
-
-htmlinst: htmldocs
- @if [ -r $(manualname)/$(htmlname) ] ; then \
- echo "Installing $(manualname)" ; \
- $(mkinstalldirs) $(DESTDIR)$(docdatadir)/$(manualname) ; \
- $(mkinstalldirs) $(DESTDIR)$(docdatadir)/$(manualname)/images ; \
- $(INSTALL_DATA) $(manualname)/*.html $(DESTDIR)$(docdatadir)/$(manualname) ; \
- for a in "x" $(png_files); do \
- if [ "x$$a" != "xx" ] ; then \
- if [ -r $$a ] ; then \
- $(INSTALL_DATA) $$a $(DESTDIR)$(docdatadir)/$(manualname)/images ; \
- fi; fi; done \
- else \
- if [ -r $(srcdir)/$(manualname)/$(htmlname) ] ; then \
- echo "Installing $(srcdir)/$(manualname)" ; \
- $(mkinstalldirs) $(DESTDIR)$(docdatadir)/$(manualname) ; \
- $(mkinstalldirs) $(DESTDIR)$(docdatadir)/$(manualname)/images ; \
- $(INSTALL_DATA) $(srcdir)/$(manualname)/*.html $(DESTDIR)$(docdatadir)/$(manualname) ; \
- for a in "x" $(png_files); do \
- if [ "x$$a" != "xx" ] ; then \
- if [ -r $$a ] ; then \
- $(INSTALL_DATA) $$a $(DESTDIR)$(docdatadir)/$(manualname)/images ; \
- fi; fi; done \
- else \
- echo "NOT installing HTML documentation: not present, and can't generate" ; \
- fi \
- fi
-
-htmluninst:
- $(RM) -rf $(DESTDIR)$(docdatadir)/$(manualname)
-
-all-local: htmldocs pdfdocs psdocs
-clean-local:
- $(RM) -rf $(manualname)/ $(manualname).junk/ images/*.eps images/*.png *.eps *.png *.ps *.pdf *.aux *.dvi *.log *.tex DBTOHTML_OUTPUT_DIR*
-install-data-local: htmlinst
-uninstall-local: htmluninst
+# taken from selfdocbookx, http://cyberelk.net/tim/docbook/selfdocbookx/index.html
+
+# modified by andy wingo <apwingo@eos.ncsu.edu> 14 dec 2001 for use by gstreamer
+
+all: html ps pdf
+
+if HAVE_XSLTPROC
+
+if HAVE_FIG2DEV_PNG
+html: $(DOC)
+else !HAVE_FIG2DEV_PNG
+html:
+endif !HAVE_FIG2DEV_PNG
+
+if HAVE_FIG2DEV_PDF
+if HAVE_PDFXMLTEX
+pdf: $(DOC).pdf
+
+if HAVE_PDFTOPS
+ps: $(DOC).ps
+else !HAVE_PDFTOPS
+ps:
+endif !HAVE_PDFTOPS
+
+else !HAVE_PDFXMLTEX
+pdf:
+ps:
+endif !HAVE_PDFXMLTEX
+
+else !HAVE_FIG2DEV_PDF
+pdf:
+ps:
+endif !HAVE_FIG2DEV_PDF
+
+else !HAVE_XSLTPROC
+html:
+ps:
+pdf:
+endif !HAVE_XSLTPROC
+
+$(DOC).fo: $(XML) $(PDFS) $(XSLFO) $(XSLFOMODS)
+ cp magic-pdf magic
+ xsltproc $(XSLFO) $(MAIN) > $@-t
+ mv -f $@-t $@
+
+$(DOC).pdf: $(DOC).fo
+ pdfxmltex $<
+ pdfxmltex $<
+
+$(DOC).ps: $(DOC).pdf
+ pdftops $< $@
+
+$(DOC): $(XML) $(PNGS) $(XSLHTML) $(XSLHTMLMODS)
+ -$(RM) *.html
+ -$(RM) -r $@
+ mkdir $@
+ cp magic-png magic
+ xsltproc $(XSLHTML) $(MAIN)
+ mv *.html $@
+ cp -a $(STYLESHEET_IMAGES) $@/stylesheet-images
+ cp $(CSS) $@
+ test "x$(PNGS)" != "x" && mkdir $@/images && cp $(PNGS) $@/images || true
+
+builddate:
+ echo -n $$(date "+%e %B %Y") > $@
+
+clean:
+ -$(RM) -f *.log *.dvi *.aux *.tex *.out *-t
+ -$(RM) -f $(PNGS) $(PDFS) builddate *.html
+ -$(RM) -rf $(DOC) $(DOC).ps $(DOC).pdf $(DOC).fo
+
+distclean: clean
+ -$(RM) -f *~ $(DOC).tar.gz docbook.tar.gz
+# -$(RM) -r docbook
+
+$(DOC).tar.gz: distclean
+ (cd ..; tar zcf /tmp/$(DOC).tar.gz $(DOC) )
+ mv /tmp/$(DOC).tar.gz .
+
+#docbook: $(DOC).tar.gz all
+# -$(RM) -r $@
+# mkdir $@
+# cp $(DOC).tar.gz $(DOC).ps $(DOC).pdf $@
+# tar cf - $(DOC) | (cd $@; tar xf -)
+
+#docbook.tar.gz: docbook
+# tar zcf docbook.tar.gz docbook
+
+# Make png from xfig
+%.png: %.fig
+ fig2dev -Lpng $< $@
+
+# Make pdf from xfig
+%.pdf: %.fig
+ fig2dev -Lpdf $< $@
+
+.PHONY: distclean clean all builddate
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ version='1.0'>
+
+<!-- Turn on admonition graphics. -->
+<xsl:param name="admon.graphics" select="'1'"/>
+<xsl:param name="admon.graphics.path" select="'stylesheet-images/'"/>
+
+</xsl:stylesheet>
+
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ version='1.0'>
+
+<!-- Use an HTML CSS stylesheet. -->
+<xsl:param name="html.stylesheet" select="'base.css'"/>
+
+</xsl:stylesheet>
+
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ version='1.0'>
+
+<!-- This sets the extension for HTML files to ".html". -->
+<!-- (The stylesheet's default for XHTML files is ".xhtm".) -->
+<xsl:param name="html.ext" select="'.html'"/>
+
+</xsl:stylesheet>
+
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version='1.0'
+ xmlns="http://www.w3.org/TR/xhtml1/transitional"
+ exclude-result-prefixes="#default">
+
+<!-- This file is for customizing the default XSL stylesheets. -->
+<!-- We include them here (this one is for print output): -->
+<xsl:import
+ href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
+
+<!-- .. and customize them here: -->
+<xsl:include href="ulink.xsl"/>
+<xsl:include href="keycombo.xsl"/>
+
+</xsl:stylesheet>
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version='1.0'
+ xmlns="http://www.w3.org/TR/xhtml1/transitional"
+ exclude-result-prefixes="#default">
+
+<!-- This file is for customizing the default XSL stylesheets. -->
+<!-- We include them here (this one is for HTML output): -->
+<xsl:import
+ href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
+
+<!-- .. and customize them here: -->
+<xsl:include href="fileext.xsl"/>
+<xsl:include href="keycombo.xsl"/>
+<xsl:include href="admon.xsl"/>
+<xsl:include href="css.xsl"/>
+
+</xsl:stylesheet>
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ version='1.0'>
+
+<!-- There is a bug in docbook-xsl-1.45; work around it here. -->
+<!-- Also change it slightly for emacs key descriptions. -->
+<xsl:template match="keycombo">
+ <xsl:variable name="action" select="@action"/>
+ <xsl:variable name="joinchar">
+ <xsl:choose>
+ <xsl:when test="$action='seq'"><xsl:text> </xsl:text></xsl:when>
+ <xsl:when test="$action='simul'">-</xsl:when>
+ <xsl:otherwise>-</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="./*">
+ <xsl:if test="position()>1">
+ <xsl:value-of select="$joinchar"/>
+ </xsl:if>
+ <xsl:apply-templates select="."/>
+ </xsl:for-each>
+</xsl:template>
+
+</xsl:stylesheet>
+
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ version='1.0'>
+
+<!-- This alters the rendering of URLs. Let's follow RFC 2396 -->
+<!-- guidelines. -->
+<xsl:template match="ulink">
+ <fo:basic-link external-destination="{@url}"
+ xsl:use-attribute-sets="xref.properties">
+ <xsl:choose>
+ <xsl:when test="count(child::node())=0">
+ <xsl:text><</xsl:text>
+ <xsl:value-of select="@url"/>
+ <xsl:text>></xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </fo:basic-link>
+ <xsl:if test="count(child::node()) != 0">
+ <fo:inline hyphenate="false">
+ <xsl:text> at <</xsl:text>
+ <xsl:value-of select="@url"/>
+ <xsl:text>></xsl:text>
+ </fo:inline>
+ </xsl:if>
+</xsl:template>
+
+</xsl:stylesheet>
+