mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
d0bcc34dad
Original commit message from CVS: * docs/manual/advanced-autoplugging.xml: * docs/manual/advanced-clocks.xml: * docs/manual/advanced-interfaces.xml: * docs/manual/advanced-metadata.xml: * docs/manual/advanced-position.xml: * docs/manual/advanced-schedulers.xml: * docs/manual/advanced-threads.xml: * docs/manual/appendix-gnome.xml: * docs/manual/appendix-programs.xml: * docs/manual/appendix-quotes.xml: * docs/manual/autoplugging.xml: * docs/manual/basics-bins.xml: * docs/manual/basics-data.xml: * docs/manual/basics-elements.xml: * docs/manual/basics-helloworld.xml: * docs/manual/basics-init.xml: * docs/manual/basics-pads.xml: * docs/manual/basics-plugins.xml: * docs/manual/bins-api.xml: * docs/manual/bins.xml: * docs/manual/buffers-api.xml: * docs/manual/buffers.xml: * docs/manual/clocks.xml: * docs/manual/components.xml: * docs/manual/cothreads.xml: * docs/manual/debugging.xml: * docs/manual/dparams-app.xml: * docs/manual/dynamic.xml: * docs/manual/elements-api.xml: * docs/manual/elements.xml: * docs/manual/factories.xml: * docs/manual/gnome.xml: * docs/manual/goals.xml: * docs/manual/helloworld.xml: * docs/manual/helloworld2.xml: * docs/manual/highlevel-components.xml: * docs/manual/highlevel-xml.xml: * docs/manual/init-api.xml: * docs/manual/intro-basics.xml: * docs/manual/intro-motivation.xml: * docs/manual/intro-preface.xml: * docs/manual/intro.xml: * docs/manual/links-api.xml: * docs/manual/links.xml: * docs/manual/manual.xml: * docs/manual/motivation.xml: * docs/manual/pads-api.xml: * docs/manual/pads.xml: * docs/manual/plugins-api.xml: * docs/manual/plugins.xml: * docs/manual/programs.xml: * docs/manual/queues.xml: * docs/manual/quotes.xml: * docs/manual/schedulers.xml: * docs/manual/states-api.xml: * docs/manual/states.xml: * docs/manual/threads.xml: * docs/manual/typedetection.xml: * docs/manual/win32.xml: * docs/manual/xml.xml: Try 2. This time, include a short preface as a "general introduction", also add code blocks around all code samples so they get compiled. We still need a way to tell readers the filename of the code sample. In some cases, don't show all code in the documentation, but do include it in the generated code. This allows for focussing on specific bits in the docs, while still having a full test application available. * examples/manual/Makefile.am: Fix up examples for new ADM. Add several of the new examples that were either added or were missing from the build system. * examples/manual/extract.pl: Allow nameless blocks.
283 lines
8.7 KiB
XML
283 lines
8.7 KiB
XML
<chapter id="chapter-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="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 with two threads 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 <stdlib.h>
|
|
#include <gst/gst.h>
|
|
|
|
gboolean playing;
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GstElement *filesrc, *osssink, *queue, *queue2, *decode;
|
|
GstElement *bin;
|
|
GstElement *thread, *thread2;
|
|
|
|
gst_init (&argc,&argv);
|
|
|
|
if (argc != 2) {
|
|
g_print ("usage: %s <mp3 filename>\n", argv[0]);
|
|
exit (-1);
|
|
}
|
|
|
|
/* create a new thread to hold the elements */
|
|
thread = gst_element_factory_make ("thread", "thread");
|
|
g_assert (thread != NULL);
|
|
thread2 = gst_element_factory_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 */
|
|
filesrc = gst_element_factory_make ("filesrc", "disk_source");
|
|
g_assert (filesrc != NULL);
|
|
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
|
|
|
queue = gst_element_factory_make ("queue", "queue");
|
|
queue2 = gst_element_factory_make ("queue", "queue2");
|
|
|
|
/* 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 bin */
|
|
gst_bin_add_many (GST_BIN (bin), filesrc, queue, NULL);
|
|
|
|
gst_bin_add_many (GST_BIN (thread), decode, queue2, NULL);
|
|
|
|
gst_bin_add (GST_BIN (thread2), osssink);
|
|
|
|
gst_element_link_many (filesrc, queue, decode, queue2, osssink, NULL);
|
|
|
|
gst_bin_add_many (GST_BIN (bin), thread, thread2, NULL);
|
|
|
|
/* write the bin to stdout */
|
|
gst_xml_write_file (GST_ELEMENT (bin), stdout);
|
|
|
|
/* write the bin to a file */
|
|
gst_xml_write_file (GST_ELEMENT (bin), 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 (bin), 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 <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
|
|
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");
|
|
...
|
|
thread = gst_element_factory_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 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>
|
|
...
|
|
<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>
|