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>
* gst/gstpad.c: (gst_pad_try_set_caps_nonfixed):
......
This diff is collapsed.
......@@ -33,10 +33,10 @@
</para>
<screen>
<prompt>shell $ </prompt><userinput>cd .</userinput>
<prompt>shell $ </prompt><userinput>cvs -d:pserver:anonymous@cvs.gstreamer.sourceforge.net:/cvsroot/gstreamer login</userinput>
Logging in to :pserver:anonymous@cvs.gstreamer.sourceforge.net:2401/cvsroot/gstreamer
<prompt>shell $ </prompt><userinput>cvs -d:pserver:anonymous@cvs.freedesktop.org:/home/cvs/gstreamer login</userinput>
Logging in to :pserver:anonymous@cvs.freedesktop.org:2401/home/cvs/gstreamer
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/gst-app/AUTHORS
U gst-template/gst-app/ChangeLog
......@@ -136,9 +136,9 @@ U gst-template/gst-app/src/Makefile.am
struct _GstExample {
GstElement element;
GstPad *sinkpad,*srcpad;
GstPad *sinkpad, *srcpad;
gint8 active;
gboolean silent;
};
/* Standard definition defining a class for this element. */
......@@ -160,7 +160,7 @@ U gst-template/gst-app/src/Makefile.am
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE))
/* Standard function returning type information. */
GtkType gst_example_get_type(void);
GType gst_example_get_type (void);
</programlisting>
</example>
</sect1>
......@@ -213,35 +213,105 @@ U gst-template/gst-app/src/Makefile.am
give a better reference to them)
</para></listitem><listitem><para>
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>
The name of the author of the element, optionally followed by a contact
email address in angle brackets.
</para></listitem><listitem><para>
The copyright details for the element.
</para></listitem>
</itemizedlist>
<para>
For example:
</para>
<programlisting>
static GstElementDetails example_details = {
"An example plugin",
"Example/FirstExample",
"Shows the basic structure of a plugin",
VERSION,
"your name &lt;your.name@your.isp&gt;",
"(C) 2001",
static GstElementDetails example_details = {
"An example plugin",
"Example/FirstExample",
"Shows the basic structure of a plugin",
"your name &lt;your.name@your.isp&gt;"
};
</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>
</sect1>
......@@ -250,11 +320,14 @@ U gst-template/gst-app/src/Makefile.am
<sect1 id="sect1-boiler-constructors">
<title>Constructor Functions</title>
<para>
Each element has two functions which are used for construction of an
element. These are the _class_init() function, which is used to initialise
the class (specifying what signals and arguments the class has and setting
up global state), and the _init() function, which is used to initialise a
specific instance of the class.
Each element has three functions which are used for construction of an
element. These are the <function>_base_init()</function> function which
is meant to initialize class and child class properties during each new
child class creation; the <function>_class_init()</function> function,
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>
</sect1>
......@@ -265,36 +338,20 @@ U gst-template/gst-app/src/Makefile.am
<para>
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
called as soon as the plugin is loaded, and must return a pointer to a
newly allocated GstPlugin structure. This structure contains the details
of all the facilities provided by the plugin, and is the mechanism by
which the definitions are made available to the rest of the &GStreamer;
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.
called as soon as the plugin is loaded, and should return TRUE or FALSE
depending on whether it loaded initialized any dependencies correctly.
Also, in this function, any supported element type in the plugin should
be registered.
</para>
<para>
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
same information is always returned by the function: for example, it
must not make element factories available based on runtime conditions. If an element
can only work in certain conditions (for example, if the soundcard is not
being used by some other process) this must be reflected by the element
being unable to enter the READY state if unavailable, rather than the plugin
attempting to deny existence of the plugin.
must not make element factories available based on runtime conditions.
If an element can only work in certain conditions (for example, if the
soundcard is not being used by some other process) this must be reflected
by the element being unable to enter the READY state if unavailable,
rather than the plugin attempting to deny existence of the plugin.
</para>
</sect1>
</chapter>
......@@ -4,5 +4,73 @@
<chapter id="cha-building-chainfn">
<title>The chain function</title>
<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>
</chapter>
......@@ -4,6 +4,192 @@
<chapter id="cha-building-pads">
<title>Specifying the pads</title>
<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>
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>
......@@ -3,7 +3,143 @@
<chapter id="cha-building-args" xreflabel="Adding Arguments">
<title>Adding Arguments</title>
<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>
</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:
g_value_set_boolean (value, filter->silent);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
</programlisting>
<para>
The above is a very simple example of how arguments are used. Graphical
applications - for example GStreamer Editor - will use these properties
and will display a user-controlleable widget with which these properties
can be changed. This means that - for the property to be as user-friendly
as possible - you should be as exact as possible in the definition of the
property. Not only in defining ranges in between which valid properties
can be located (for integers, floats, etc.), but also in using very
descriptive (better yet: internationalized) strings in the definition of
the property, and if possible using enums and flags instead of integers.
The GObject documentation describes these in a very complete way, but
below, we'll give a short example of where this is useful. Note that using
integers here would probably completely confuse the user, because they
make no sense in this context. The example is stolen from videotestsrc.
</para>
<programlisting>
typedef enum {
GST_VIDEOTESTSRC_SMPTE,
GST_VIDEOTESTSRC_SNOW,
GST_VIDEOTESTSRC_BLACK
} GstVideotestsrcPattern;
[..]
#define GST_TYPE_VIDEOTESTSRC_PATTERN (gst_videotestsrc_pattern_get_type ())
static GType
gst_videotestsrc_pattern_get_type (void)
{
static GType videotestsrc_pattern_type = 0;
if (!videotestsrc_pattern_type) {
static GEnumValue pattern_types[] = {
{ GST_VIDEOTESTSRC_SMPTE, "smpte", "SMPTE 100% color bars" },
{ GST_VIDEOTESTSRC_SNOW, "snow", "Random (television snow)" },
{ GST_VIDEOTESTSRC_BLACK, "black", "0% Black" },
{ 0, NULL, NULL },
};
videotestsrc_pattern_type =