docs: update 'XML in GStreamer' section in application developer's manual

This commit is contained in:
Tim-Philipp Müller 2010-06-30 13:16:35 +01:00
parent dbaae8f244
commit cda5a353d2

View file

@ -1,264 +1,17 @@
<chapter id="chapter-xml"> <chapter id="chapter-xml">
<title>XML in <application>GStreamer</application></title> <title>XML in <application>GStreamer</application> (deprecated)</title>
<para> <para>
<application>GStreamer</application> can use XML to store and load <application>GStreamer</application> used to provide functions to
its pipeline definitions. save pipeline definitions into XML format and later restore them
again from XML.
</para> </para>
<para> <para>
We will show you how you can save a pipeline to XML and how you can reload that This never really worked properly for all but the most simple use cases
XML file again for later use. though, and is also pretty much impossible to make work correctly in a
useful way due to the dynamic nature of almost all non-trivial GStreamer
pipelines. Consequently, this API has been deprecated and will be
removed at some point. Don't use it.
</para> </para>
<sect1 id="section-xml-write">
<title>Turning GstElements into XML</title>
<para>
We create a simple pipeline and write it to stdout with
gst_xml_write_file (). The following code constructs an MP3 player
pipeline and then writes out the XML both to stdout
and to a file. Use this program with one argument: the MP3 file on disk.
</para>
<programlisting>
<!-- example-begin xml-mp3.c -->
#include &lt;stdlib.h&gt;
#include &lt;gst/gst.h&gt;
gboolean playing;
int
main (int argc, char *argv[])
{
GstElement *filesrc, *osssink, *decode;
GstElement *pipeline;
gst_init (&amp;argc,&amp;argv);
if (argc != 2) {
g_print ("usage: %s &lt;mp3 filename&gt;\n", argv[0]);
exit (-1);
}
/* create a new pipeline to hold the elements */
pipeline = gst_element_factory_make ("pipeline", "pipeline");
g_assert (pipeline != NULL);
/* create a disk reader */
filesrc = gst_element_factory_make ("filesrc", "disk_source");
g_assert (filesrc != NULL);
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
/* and an audio sink */
osssink = gst_element_factory_make ("osssink", "play_audio");
g_assert (osssink != NULL);
decode = gst_element_factory_make ("mad", "decode");
g_assert (decode != NULL);
/* add objects to the main pipeline */
gst_bin_add_many (GST_BIN (pipeline), filesrc, decode, osssink, NULL);
gst_element_link_many (filesrc, decode, osssink, NULL);
/* write the pipeline to stdout */
gst_xml_write_file (GST_ELEMENT (pipeline), stdout);
/* write the bin to a file */
gst_xml_write_file (GST_ELEMENT (pipeline), fopen ("xmlTest.gst", "w"));
exit (0);
}
<!-- example-end xml-mp3.c -->
</programlisting>
<para>
The most important line is:
</para>
<programlisting>
gst_xml_write_file (GST_ELEMENT (pipeline), stdout);
</programlisting>
<para>
gst_xml_write_file () will turn the given element into an xmlDocPtr that
is then formatted and saved to a file. To save to disk, pass the result
of a fopen(2) as the second argument.
</para>
<para>
The complete element hierarchy will be saved along with the inter element
pad links 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="section-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 &lt;stdlib.h&gt;
#include &lt;gst/gst.h&gt;
int
main(int argc, char *argv[])
{
GstXML *xml;
GstElement *pipeline;
gboolean ret;
gst_init (&amp;argc, &amp;argv);
xml = gst_xml_new ();
ret = gst_xml_parse_file(xml, "xmlTest.gst", NULL);
g_assert (ret == TRUE);
pipeline = gst_xml_get_element (xml, "pipeline");
g_assert (pipeline != NULL);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_sleep (4);
gst_element_set_state (pipeline, 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 from a xmlDocPtr and
an in-memory buffer using gst_xml_parse_doc and gst_xml_parse_memory
respectively. Both of these methods return a gboolean indicating
success or failure of the requested action.
</para>
</sect1>
<sect1 id="section-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 link
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");
...
pipeline = gst_element_factory_make ("pipeline", "pipeline");
g_signal_connect (G_OBJECT (pipeline), "object_saved",
G_CALLBACK (object_saved), g_strdup ("decoder pipeline"));
...
</programlisting>
<para>
When the thread is saved, the object_save method will be called. 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>
...
&lt;gst:element&gt;
&lt;gst:name&gt;pipeline&lt;/gst:name&gt;
&lt;gst:type&gt;pipeline&lt;/gst:type&gt;
&lt;gst:version&gt;0.1.0&lt;/gst:version&gt;
...
&lt;/gst:children&gt;
&lt;test:comment&gt;
&lt;test:text&gt;decoder pipeline&lt;/test:text&gt;
&lt;/test:comment&gt;
&lt;/gst:element&gt;
...
</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-&gt;xmlChildrenNode;
while (children) {
if (!strcmp (children-&gt;name, "comment")) {
xmlNodePtr nodes = children-&gt;xmlChildrenNode;
while (nodes) {
if (!strcmp (nodes-&gt;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-&gt;next;
}
}
children = children-&gt;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> </chapter>