Commit 8e29a588 authored by Ronald S. Bultje's avatar Ronald S. Bultje
Browse files

docs/pwg/advanced_types.xml: Finish documenting the current state of mimetypes.

Original commit message from CVS:
2004-01-27  Ronald Bultje  <rbultje@ronald.bitfreak.net>

* docs/pwg/advanced_types.xml:
Finish documenting the current state of mimetypes.
* docs/pwg/building_boiler.xml:
* docs/pwg/building_chainfn.xml:
* docs/pwg/building_pads.xml:
* docs/pwg/building_props.xml:
* docs/pwg/building_testapp.xml:
Start documenting the "how to build a simple audio filter" part
of the PWG. Most stuff is ready by now. Stuff remaining: signals,
states and (maybe?) a short introduction to capsnego in the chapter
on pads (building_pads.xml). Capsnego should probably be explained
fully in advanced_capsnego.xml or so.
parent 3607f4f0
2004-01-27 Ronald Bultje <rbultje@ronald.bitfreak.net>
* docs/pwg/advanced_types.xml:
Finish documenting the current state of mimetypes.
* docs/pwg/building_boiler.xml:
* docs/pwg/building_chainfn.xml:
* docs/pwg/building_pads.xml:
* docs/pwg/building_props.xml:
* docs/pwg/building_testapp.xml:
Start documenting the "how to build a simple audio filter" part
of the PWG. Most stuff is ready by now. Stuff remaining: signals,
states and (maybe?) a short introduction to capsnego in the chapter
on pads (building_pads.xml). Capsnego should probably be explained
fully in advanced_capsnego.xml or so.
2004-01-26 David Schleef <ds@schleef.org> 2004-01-26 David Schleef <ds@schleef.org>
* gst/gstpad.c: (gst_pad_try_set_caps_nonfixed): * gst/gstpad.c: (gst_pad_try_set_caps_nonfixed):
......
This diff is collapsed.
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
</para> </para>
<screen> <screen>
<prompt>shell $ </prompt><userinput>cd .</userinput> <prompt>shell $ </prompt><userinput>cd .</userinput>
<prompt>shell $ </prompt><userinput>cvs -d:pserver:anonymous@cvs.gstreamer.sourceforge.net:/cvsroot/gstreamer login</userinput> <prompt>shell $ </prompt><userinput>cvs -d:pserver:anonymous@cvs.freedesktop.org:/home/cvs/gstreamer login</userinput>
Logging in to :pserver:anonymous@cvs.gstreamer.sourceforge.net:2401/cvsroot/gstreamer Logging in to :pserver:anonymous@cvs.freedesktop.org:2401/home/cvs/gstreamer
CVS password: CVS password:
<prompt>shell $ </prompt><userinput>cvs -z3 -d:pserver:anonymous@cvs.gstreamer.sourceforge.net:/cvsroot/gstreamer co gst-template</userinput> <prompt>shell $ </prompt><userinput>cvs -z3 -d:pserver:anonymous@cvs.freedesktop.org:/home/cvs/gstreamer co gst-template</userinput>
U gst-template/README U gst-template/README
U gst-template/gst-app/AUTHORS U gst-template/gst-app/AUTHORS
U gst-template/gst-app/ChangeLog U gst-template/gst-app/ChangeLog
...@@ -136,9 +136,9 @@ U gst-template/gst-app/src/Makefile.am ...@@ -136,9 +136,9 @@ U gst-template/gst-app/src/Makefile.am
struct _GstExample { struct _GstExample {
GstElement element; GstElement element;
GstPad *sinkpad,*srcpad; GstPad *sinkpad, *srcpad;
gint8 active; gboolean silent;
}; };
/* Standard definition defining a class for this element. */ /* Standard definition defining a class for this element. */
...@@ -160,7 +160,7 @@ U gst-template/gst-app/src/Makefile.am ...@@ -160,7 +160,7 @@ U gst-template/gst-app/src/Makefile.am
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE)) (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE))
/* Standard function returning type information. */ /* Standard function returning type information. */
GtkType gst_example_get_type(void); GType gst_example_get_type (void);
</programlisting> </programlisting>
</example> </example>
</sect1> </sect1>
...@@ -213,35 +213,105 @@ U gst-template/gst-app/src/Makefile.am ...@@ -213,35 +213,105 @@ U gst-template/gst-app/src/Makefile.am
give a better reference to them) give a better reference to them)
</para></listitem><listitem><para> </para></listitem><listitem><para>
A brief description of the purpose of the element. A brief description of the purpose of the element.
</para></listitem><listitem><para>
The version number of the element. For elements in the main GStreamer
source code, this will often simply be VERSION, which is a macro defined
to be the version number of the current GStreamer version. The only
requirement, however, is that the version number should increase
monotonically.
</para>
<para>
Version numbers should be stored in major.minor.patch form: ie, 3
(decimal) numbers, separated by periods (.).
</para></listitem><listitem><para> </para></listitem><listitem><para>
The name of the author of the element, optionally followed by a contact The name of the author of the element, optionally followed by a contact
email address in angle brackets. email address in angle brackets.
</para></listitem><listitem><para>
The copyright details for the element.
</para></listitem> </para></listitem>
</itemizedlist> </itemizedlist>
<para> <para>
For example: For example:
</para> </para>
<programlisting> <programlisting>
static GstElementDetails example_details = { static GstElementDetails example_details = {
"An example plugin", "An example plugin",
"Example/FirstExample", "Example/FirstExample",
"Shows the basic structure of a plugin", "Shows the basic structure of a plugin",
VERSION, "your name &lt;your.name@your.isp&gt;"
"your name &lt;your.name@your.isp&gt;", };
"(C) 2001", </programlisting>
<para>
The element details are registered with the plugin during
<function>_base_init ()</function>.
</para>
<programlisting>
static void
gst_my_filter_base_init (GstMyFilterClass *klass)
{
static GstElementDetails my_filter_details = {
[..]
}; };
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
gst_element_class_set_details (element_class, &amp;my_filter_details);
}
</programlisting>
</sect1>
<!-- ############ sect1 ############# -->
<sect1 id="sect1-boiler-padtemplates">
<title>GstStaticPadTemplate</title>
<para>
A GstStaticPadTemplate is a description of a pad that the element will
(or might) create and use. It contains:
</para>
<itemizedlist>
<listitem>
<para>A short name for the pad.</para>
</listitem>
<listitem>
<para>Pad direction.</para>
</listitem>
<listitem>
<para>
Existence property. This indicates whether the pad exists always (an
<quote>always</quote> pad), only in some cases (a
<quote>sometimes</quote> pad) or only if the application requested
such a pad (a <quote>request</quote> pad).
</para>
</listitem>
<listitem>
<para>Supported types by this element (capabilities).</para>
</listitem>
</itemizedlist>
<para>
For example:
</para>
<programlisting>
static GstStaticPadTemplate sink_factory =
GST_STATIC_PAD_TEMPLATE (
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("ANY")
);
</programlisting>
<para>
Those pad templates are registered during the
<function>_base_init ()</function> function. Pads are created from these
templates in the element's <function>_init ()</function> function using
<function>gst_pad_new_from_template ()</function>. The template can be
retrieved from the element class using
<function>gst_element_class_get_pad_template ()</function>. See below
for more details on this.
</para>
<programlisting>
static void
gst_my_filter_base_init (GstMyFilterClass *klass)
{
static GstStaticPadTemplate sink_factory =
[..]
, src_factory =
[..]
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&amp;src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&amp;sink_factory));
[..]
}
</programlisting> </programlisting>
</sect1> </sect1>
...@@ -250,11 +320,14 @@ U gst-template/gst-app/src/Makefile.am ...@@ -250,11 +320,14 @@ U gst-template/gst-app/src/Makefile.am
<sect1 id="sect1-boiler-constructors"> <sect1 id="sect1-boiler-constructors">
<title>Constructor Functions</title> <title>Constructor Functions</title>
<para> <para>
Each element has two functions which are used for construction of an Each element has three functions which are used for construction of an
element. These are the _class_init() function, which is used to initialise element. These are the <function>_base_init()</function> function which
the class (specifying what signals and arguments the class has and setting is meant to initialize class and child class properties during each new
up global state), and the _init() function, which is used to initialise a child class creation; the <function>_class_init()</function> function,
specific instance of the class. which is used to initialise the class only once (specifying what signals,
arguments and virtual functions the class has and setting up global
state); and the <function>_init()</function> function, which is used to
initialise a specific instance of this type.
</para> </para>
</sect1> </sect1>
...@@ -265,36 +338,20 @@ U gst-template/gst-app/src/Makefile.am ...@@ -265,36 +338,20 @@ U gst-template/gst-app/src/Makefile.am
<para> <para>
Once we have written code defining all the parts of the plugin, we need to Once we have written code defining all the parts of the plugin, we need to
write the plugin_init() function. This is a special function, which is write the plugin_init() function. This is a special function, which is
called as soon as the plugin is loaded, and must return a pointer to a called as soon as the plugin is loaded, and should return TRUE or FALSE
newly allocated GstPlugin structure. This structure contains the details depending on whether it loaded initialized any dependencies correctly.
of all the facilities provided by the plugin, and is the mechanism by Also, in this function, any supported element type in the plugin should
which the definitions are made available to the rest of the &GStreamer; be registered.
system. Helper functions are provided to help fill the structure: for
future compatability it is required that these functions are used, as
documented below, rather than attempting to access the structure directly.
</para> </para>
<para> <para>
Note that the information returned by the plugin_init() function will be Note that the information returned by the plugin_init() function will be
cached in a central registry. For this reason, it is important that the cached in a central registry. For this reason, it is important that the
same information is always returned by the function: for example, it same information is always returned by the function: for example, it
must not make element factories available based on runtime conditions. If an element must not make element factories available based on runtime conditions.
can only work in certain conditions (for example, if the soundcard is not If an element can only work in certain conditions (for example, if the
being used by some other process) this must be reflected by the element soundcard is not being used by some other process) this must be reflected
being unable to enter the READY state if unavailable, rather than the plugin by the element being unable to enter the READY state if unavailable,
attempting to deny existence of the plugin. rather than the plugin attempting to deny existence of the plugin.
</para> </para>
</sect1> </sect1>
</chapter> </chapter>
...@@ -4,5 +4,73 @@ ...@@ -4,5 +4,73 @@
<chapter id="cha-building-chainfn"> <chapter id="cha-building-chainfn">
<title>The chain function</title> <title>The chain function</title>
<para> <para>
The chain function is the function in which all data processing takes
place. In the case of a simple filter, <function>_chain ()</function>
functions are mostly lineair functions - so for each incoming buffer,
one buffer will go out, too. Below is a very simple implementation of
a chain function:
</para>
<programlisting>
static void
gst_my_filter_chain (GstPad *pad,
GstData *data)
{
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstBuffer *buf = GST_BUFFER (data);
if (!filter->silent)
g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf));
gst_pad_push (filter->srcpad, GST_DATA (buf));
}
</programlisting>
<para>
Obviously, the above doesn't do much useful. Instead of printing that the
data is in, you would normally process the data there. Remember, however,
that buffers are not always writable. In more advanced elements (the ones
that do event processing), the incoming data might not even be a buffer.
</para>
<programlisting>
static void
gst_my_filter_chain (GstPad *pad,
GstData *data)
{
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstBuffer *buf, *outbuf;
if (GST_IS_EVENT (data)) {
GstEvent *event = GST_EVENT (data);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
/* end-of-stream, we should close down all stream leftovers here */
gst_my_filter_stop_processing (filter);
/* fall-through to default event handling */
default:
gst_pad_event_default (pad, event);
break;
}
return;
}
buf = GST_BUFFER (data);
outbuf = gst_my_filter_process_data (buf);
gst_buffer_unref (buf);
if (!outbuf) {
/* something went wrong - signal an error */
gst_element_error (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
return;
}
gst_pad_push (filter->srcpad, GST_DATA (outbuf));
}
</programlisting>
<para>
In some cases, it might be useful for an element to have control over the
input data rate, too. In that case, you probably want to write a so-called
<emphasis>loop-based</emphasis> element. Source elements (with only source
pads) can also be <emphasis>get-based</emphasis> elements. These concepts
will be explained in the advanced section of this guide, and in the section
that specifically discusses source pads.
</para> </para>
</chapter> </chapter>
...@@ -4,6 +4,192 @@ ...@@ -4,6 +4,192 @@
<chapter id="cha-building-pads"> <chapter id="cha-building-pads">
<title>Specifying the pads</title> <title>Specifying the pads</title>
<para> <para>
As explained before, pads are the port through which data goes in and out
of your element, and that makes them a very important item in the process
of element creation. In the boilerplate code, we have seen how static pad
templates take care of registering pad templates with the element class.
Here, we will see how to create actual elements, use <function>_link ()</function>
and <function>_getcaps ()</function> functions to let other elements know
their capabilities and how to register functions to let data flow through
the element.
</para> </para>
<para>
In the element <function>_init ()</function> function, you create the pad
from the pad template that has been registered with the element class in
the <function>_base_init ()</function> function. After creating the pad,
you have to set a <function>_link ()</function> function pointer and a
<function>_getcaps ()</function> function pointer. Optionally, you can
set a <function>_chain ()</function> function pointer (on sink pads in
filter and sink elements) through which data will come in to the element,
or (on source pads in source elements) a <function>_get ()</function>
function pointer through which data will be pulled from the element. After
that, you have to register the pad with the element. This happens like
this:
</para>
<programlisting>
static GstPadLinkReturn gst_my_filter_link (GstPad *pad,
const GstCaps *caps);
static GstCaps * gst_my_filter_getcaps (GstPad *pad);
static void gst_my_filter_chain (GstPad *pad,
GstData *data);
static void
gst_my_filter_init (GstMyFilter *filter)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
/* pad through which data comes in to the element */
filter->sinkpad = gst_pad_new_from_template (
gst_element_class_get_pad_template (klass, "sink"), "sink");
gst_pad_set_link_function (filter->sinkpad, gst_my_filter_link);
gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps);
gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain);
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
/* pad through which data goes out of the element */
filter->srcpad = gst_pad_new_from_template (
gst_element_class_get_pad_template (klass, "src"), "src");
gst_pad_set_link_function (filter->srcpad, gst_my_filter_link);
gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
[..]
}
</programlisting>
<para>
The <function>_link ()</function> is called during caps negotiation. This
is the process where the linked pads decide on the streamtype that will
transfer between them. A full list of type-definitions can be found in
<xref linkend="cha-building-types"/>. A <function>_link ()</function>
receives a pointer to a <classname>GstCaps</classname> struct that
defines the proposed streamtype, and can respond with either
<quote>yes</quote> (<classname>GST_PAD_LINK_OK</classname>),
<quote>no</quote> (<classname>GST_PAD_LINK_REFUSED</classname>) or
<quote>don't know yet</quote> (<classname>GST_PAD_LINK_DELAYED</classname>).
If the element responds positively towards the streamtype, that type
will be used on the pad. An example:
</para>
<programlisting>
static GstPadLinkReturn
gst_my_filter_link (GstPad *pad,
const GstCaps *caps)
{
GstStructure *structure = gst_caps_get_structure (caps, 0);
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad :
filter->srcpad;
GstPadLinkReturn ret;
const gchar *mime;
/* Since we're an audio filter, we want to handle raw audio
* and from that audio type, we need to get the samplerate and
* number of channels. */
mime = gst_structure_get_name (structure);
if (strcmp (mime, "audio/x-raw-int") != 0) {
GST_WARNING ("Wrong mimetype %s provided, we only support %s",
mime, "audio/x-raw-int");
return GST_PAD_LINK_REFUSED;
}
/* we're a filter and don't touch the properties of the data.
* That means we can set the given caps unmodified on the next
* element, and use that negotiation return value as ours. */
ret = gst_pad_try_set_caps (otherpad, gst_caps_copy (caps));
if (GST_PAD_LINK_FAILED (ret))
return ret;
/* Capsnego succeeded, get the stream properties for internal
* usage and return success. */
gst_structure_get_int (structure, "rate", &amp;filter->samplerate);
gst_structure_get_int (structure, "channels", &amp;filter->channels);
g_print ("Caps negotiation succeeded with %d Hz @ %d channels\n",
filter->samplerate, filter->channels);
return ret;
}
</programlisting>
<para>
If your <function>_link ()</function> function does not need to perform
any specific operation (i.e. it will only forward caps), you can set it
to <function>gst_pad_proxy_link</function>. This is a link forwarding
function implementation provided by the core. It is useful for elements
such as <classname>identity</classname>.
</para>
<para>
The <function>_getcaps ()</function> funtion is used to request the list
of supported formats and properties from the element. In some cases, this
will be equal to the formats provided by the pad template, in which case
this function can be omitted. In some cases, too, it will not depend on
anything inside this element, but it will rather depend on the input from
another element linked to this element's sink or source pads. In that case,
you can use <function>gst_pad_proxy_getcaps</function> as implementation,
it provides getcaps forwarding in the core. However, in many cases, the
format supported by this element cannot be defined externally, but is
more specific than those provided by the pad template. In this case, you
should use a <function>_getcaps ()</function> function. In the case as
specified below, we assume that our filter is able to resample sound, so
it would be able to provide any samplerate (indifferent from the samplerate
specified on the other pad) on both pads. It explains how a
<function>_getcaps ()</function> can be used to do this.
</para>
<programlisting>
static GstCaps *
gst_my_filter_getcaps (GstPad *pad)
{
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad :
filter->srcpad;
GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps;
gint n;
if (gst_caps_is_empty (othercaps))
return othercaps;
/* We support *any* samplerate, indifferent from the samplerate
* supported by the linked elements on both sides. */
for (i = 0; i < gst_caps_get_size (othercaps); i++) {
GstStructure *structure = gst_caps_get_structure (othercaps, i);
gst_structure_remove_field (structure, "rate");
}
caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
gst_caps_free (othercaps);
return caps;
}
</programlisting>
<para>
Obviously, many elements will not need this complex mechanism, because they
are much simpler than that. They only support one format, or their format
is fixed but the contents of the format depend on the stream or something
else. In those cases, <emphasis>explicit caps</emphasis> are an easy way
of handling caps. Explicit caps are an easy way of specifying one, fixed,
supported format on a pad. Pads using explicit caps do not implement their
own <function>_getcaps ()</function> or <function>_link ()</function>
functions. When the exact format is known, an elements uses
<function>gst_pad_set_explicit_caps ()</function> to specify the exact
format. This is very useful for demuxers, for example.
</para>
<programlisting>
static void
gst_my_filter_init (GstMyFilter *filter)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
[..]
filter->srcpad = gst_pad_new_from_template (
gst_element_class_get_pad_template (klass, "src"), "src");
gst_pad_use_explicit_caps (filter->srcpad);
[..]
}
static void
gst_my_filter_somefunction (GstMyFilter *filter)
{
GstCaps *caps = ..;
[..]
gst_pad_set_explicit_caps (filter->srcpad, caps);
[..]
}
</programlisting>
</chapter> </chapter>
...@@ -3,7 +3,143 @@ ...@@ -3,7 +3,143 @@
<chapter id="cha-building-args" xreflabel="Adding Arguments"> <chapter id="cha-building-args" xreflabel="Adding Arguments">
<title>Adding Arguments</title> <title>Adding Arguments</title>
<para> <para>
Define arguments in enum. The primary and most important way of controlling how an element behaves,
is through GObject properties. GObject properties are defined in the
<function>_class_init ()</function> function. The element optionally
implements a <function>_get_property ()</function> and a
<function>_set_property ()</function> function. These functions will be
notified if an application changes or requests the value of a property,
and can then fill in the value or take action required for that property
to change value internally.
</para> </para>
</chapter> <programlisting>
/* properties */
enum {
ARG_0,
ARG_SILENT
/* FILL ME */
};
static void gst_my_filter_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gst_my_filter_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void
gst_my_filter_class_init (GstMyFilterClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
/* define properties */
g_object_class_install_property (object_class, ARG_SILENT,
g_param_spec_boolean ("silent", "Silent",
"Whether to be very verbose or not",
FALSE, G_PARAM_READWRITE));
/* define virtual function pointers */
object_class->set_property = gst_my_filter_set_property;
object_class->get_property = gst_my_filter_get_property;
}
static void
gst_my_filter_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GstMyFilter *filter = GST_MY_FILTER (object);
switch (prop_id) {
case ARG_SILENT:
filter->silent = g_value_get_boolean (value);
g_print ("Silent argument was changed to %s\n",
filter->silent ? "true" : "false");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_my_filter_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GstMyFilter *filter = GST_MY_FILTER (object);
switch (prop_id) {
case ARG_SILENT: