mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-08 18:39:54 +00:00
220 lines
7.5 KiB
Text
220 lines
7.5 KiB
Text
|
XML namespaces
|
||
|
==============
|
||
|
|
||
|
1) requirements
|
||
|
---------------
|
||
|
|
||
|
GStreamer uses XML to save a complete media pipeline. This
|
||
|
opens a lot of possibilities for end user apps, eg: save
|
||
|
constructed pipelines for later reuse, send pipelines over
|
||
|
the wire to render data elsewhere etc...
|
||
|
|
||
|
We will also allow the end user app to insert its own tags
|
||
|
into the GStreamer generated XML in order to give more
|
||
|
context to the elements. An example of such an app would be
|
||
|
gsteditor; while the GStreamer core will save the plain
|
||
|
element hierarchy, the editor will insert its own tags into
|
||
|
the XML tree to describe the elements positions, the
|
||
|
signals and other project data that might need to be
|
||
|
externalised.
|
||
|
|
||
|
And inherent problem with XML is that the use and naming of
|
||
|
the tags can be done in an arbitrary way. The GStreamer core
|
||
|
will, for example, use the 'element' and 'pad' tags to store
|
||
|
the element and pad objects. The description and the nesting
|
||
|
of the tags are described in a DTD (document type definition)
|
||
|
or soon with the proposed 'new' standard of the W3C; Schemas.
|
||
|
|
||
|
We can see obvious problems when a user app (unaware of the
|
||
|
core tags) is also trying to use the 'element' tag for its
|
||
|
own purposes. The core might try to load the 'element' tag
|
||
|
desscribing the user app data and the user app might get fed
|
||
|
with XML data of the GStreamer core.
|
||
|
|
||
|
In this document we try to describe how we will solve this problem
|
||
|
using namespaces.
|
||
|
|
||
|
|
||
|
2) namespaces
|
||
|
-------------
|
||
|
|
||
|
To avoid the tag conflicts we mentioned, the W3C has incorporated
|
||
|
XML namescapes.
|
||
|
|
||
|
Were a typical XML document without namespaces would look like:
|
||
|
|
||
|
<?xml version="1.0"?>
|
||
|
<GST-Pipeline>
|
||
|
<element>
|
||
|
<name>bin</name>
|
||
|
<children>
|
||
|
...
|
||
|
</children>
|
||
|
</element>
|
||
|
</GST-Pipeline>
|
||
|
|
||
|
Tha same document with namespaces look like this:
|
||
|
|
||
|
<?xml version="1.0"?>
|
||
|
<gst:GST-Pipeline xmlns:gst="http://gstreamer.net/gst-core/1.0/">
|
||
|
<gst:element>
|
||
|
<gst:name>bin</gst:name>
|
||
|
<gst:children>
|
||
|
...
|
||
|
</gst:children>
|
||
|
</gst:element>
|
||
|
</gst:GST-Pipeline>
|
||
|
|
||
|
In front of each tag we add, in this case, gst:. gst: is called the
|
||
|
namespace of the document and is declared with a statement:
|
||
|
|
||
|
<... xmlns:gst="http://gstreamer.net/gst-core/1.0/">
|
||
|
|
||
|
In this case we define a new namespace 'gst:' that is tied to the URL
|
||
|
http://gstreamer.net/gst-core/1.0/. This URL is typically based on
|
||
|
a domain you control and doesn't have to point to something valid on
|
||
|
the internet. Note that the following document is exactly the same
|
||
|
as the one mentioned above:
|
||
|
|
||
|
<?xml version="1.0"?>
|
||
|
<core:GST-Pipeline xmlns:core="http://gstreamer.net/gst-core/1.0/">
|
||
|
<core:element>
|
||
|
<core:name>bin</gst:name>
|
||
|
<core:children>
|
||
|
...
|
||
|
</core:children>
|
||
|
</core:element>
|
||
|
</core:GST-Pipeline>
|
||
|
|
||
|
GStreamer currently uses xmlns:gst="http://gstreamer.net/gst-core/1.0" as
|
||
|
the namespace used for saving the core pipeline.
|
||
|
|
||
|
3) multi-namespace documents
|
||
|
----------------------------
|
||
|
|
||
|
Suppose we have a user app that wants to insert its own XML tags into
|
||
|
the core GStreamer XML pipelines, for the examples sake we will use the
|
||
|
editor as an example. The editor will insert XML tags inside each
|
||
|
element that describes the position and size of the element as it was
|
||
|
laid out in the editor.
|
||
|
|
||
|
For the examples sake, the tags that are used to descibe this meta data
|
||
|
will also be names 'element' in order to demonstrate the namespaces.
|
||
|
|
||
|
The editor will use its own namespace, being:
|
||
|
xmlns:editor="http://gstreamer.net/gst-editor/1.0". This namespace is
|
||
|
added to the XML documents header and all the elements the editor will
|
||
|
save will have this namespace attached to it. Our interleaved XML
|
||
|
document might look like this:
|
||
|
|
||
|
<?xml version="1.0"?>
|
||
|
<gst:GST-Pipeline xmlns:gst="http://gstreamer.net/gst-core/1.0/"
|
||
|
xmlns:editor="http://gstreamer.net/gst-editor/1.0/">
|
||
|
<gst:element>
|
||
|
<gst:name>bin</gst:name>
|
||
|
<gst:children>
|
||
|
...
|
||
|
</gst:children>
|
||
|
<editor:element>
|
||
|
<editor:position x="100" y="50"/>
|
||
|
</editor:element>
|
||
|
</gst:element>
|
||
|
</gst:GST-Pipeline>
|
||
|
|
||
|
As you can see, the namespaces clearly separate the same XML tags
|
||
|
'element'.
|
||
|
|
||
|
|
||
|
4) implementation considerations
|
||
|
--------------------------------
|
||
|
|
||
|
The GStreamer core doesn't know about user apps inserting data into the
|
||
|
XML, it does not look at XML tags not within its namespace when it
|
||
|
performs the parsing of the XML tree. The core, however, must be
|
||
|
able to hand over the XML tree to the user app so it can perform the
|
||
|
parsing of its tags inside its namespace. We therefore need hooks inside
|
||
|
the framework to accomplish this.
|
||
|
|
||
|
We also need hooks inside the GStreamer core to signal a user app that
|
||
|
it can now insert its tags into the XML tree.
|
||
|
|
||
|
4.1) XML save hooks
|
||
|
-------------------
|
||
|
|
||
|
GstObject has an abstract class method
|
||
|
|
||
|
xmlNodePtr (*save_thyself) (GstObject *object, xmlNodePtr parent)
|
||
|
|
||
|
A real element or pad will implement this function and construct an XML
|
||
|
representation of itself with the parent xmlNodePtr as the parent.
|
||
|
An element will typically call the save_thyself function of its
|
||
|
parent class before saving itself.
|
||
|
|
||
|
The XML save procedure on a GstObject is performed with:
|
||
|
|
||
|
gst_object_save_thyself (GstObject *object, xmlNodePtr parent)
|
||
|
|
||
|
Wich will call the elements implementation of the save_thyself function.
|
||
|
|
||
|
An app that wants to insert its XML tags has to connect to a signal of
|
||
|
the GstObject object called xml_saved. The object and the parent
|
||
|
xmlNodePtr will be passed to the signal handler of the user app, which
|
||
|
can then insert its tags.
|
||
|
|
||
|
The user app has no problem inserting its namespace into the xmlDoc and
|
||
|
neither will the GStreamer core.
|
||
|
|
||
|
4.2) XML load hooks
|
||
|
-------------------
|
||
|
|
||
|
The real problem lies in the loading of the XML tree. Before we load
|
||
|
the objects, we don't have anything to connect a signal to, so
|
||
|
another method has to be invented to signal the user app of the
|
||
|
freshly loaded objects.
|
||
|
|
||
|
One obvious solution would be to attach a class signal to the
|
||
|
GstObject class that would be fired whenever an object is created from
|
||
|
an XML document. Unfortunatly Gtk+ (or glib2.0) doesn't have class
|
||
|
signals so we need something else. Another problem with the class
|
||
|
signals would be that the user app would also be notified of object
|
||
|
creation outside its context. For example, if two threads perform an
|
||
|
XML load at the same time, the objects created in the first thread
|
||
|
would also notify the listener in the second thread. Both threads then
|
||
|
have to take care of not trying to parse XML documents that are from
|
||
|
the other thread, this obvously can get messy and we have to deal
|
||
|
with it without bothering the user app.
|
||
|
|
||
|
We'll continue with some random ramblings...
|
||
|
|
||
|
solution 1
|
||
|
----------
|
||
|
To solve this problem we can create a special method in gstobject
|
||
|
|
||
|
gst_object_loaded_notify_add (GstObjectLoadedCallback *callback,
|
||
|
xmlNodePtr doc)
|
||
|
|
||
|
this method would add the specified callback function to a list of
|
||
|
listeners and would perform the callback function if an object is
|
||
|
created (this can be done in the init method). The problem remains
|
||
|
though because we do not know the xmlNodePtr when we call the
|
||
|
callback. This seems messy.
|
||
|
|
||
|
sultion 2
|
||
|
---------
|
||
|
After the object has performed its restore_thyself, it is responsible
|
||
|
for signaling a object_loaded signal with the object and the xmlNodePtr
|
||
|
as an argument.
|
||
|
|
||
|
At object creation, the signal is connected to a singleton object managed
|
||
|
by GstObject that can proxy the signal to the user app. This looks a
|
||
|
lot like a class signal. apps could also specify the xmlNodePtr they
|
||
|
are interested in and the signal would only be proxied to the app
|
||
|
if the xmlNodePtrs are from the same xmlDoc.
|
||
|
|
||
|
Solution 2 seems like a reasonable solution for now...
|
||
|
|
||
|
comments?
|
||
|
|
||
|
wtay
|
||
|
|