gstreamer/docs/pwg/building-boiler.xml
Thomas Vander Stichele 5b00b55793 fix up id's
Original commit message from CVS:
fix up id's
2004-01-28 15:51:14 +00:00

384 lines
14 KiB
XML

<!-- ############ chapter ############# -->
<chapter id="chapter-building-boiler" xreflabel="Constructing the Boilerplate">
<title>Constructing the Boilerplate</title>
<para>
In this chapter you will learn how to construct the bare minimum code for a
new plugin. Starting from ground zero, you will see how to get the
&GStreamer; template source. Then you will learn how to use a few basic
tools to copy and modify a template plugin to create a new plugin. If you
follow the examples here, then by the end of this chapter you will have a
functional audio filter plugin that you can compile and use in &GStreamer;
applications.
</para>
<!-- ############ sect1 ############# -->
<sect1 id="section-boiler-source" xreflabel="Getting the GStreamer Plugin Templates">
<title>Getting the GStreamer Plugin Templates</title>
<para>
There are currently two ways to develop a new plugin for &GStreamer;: You
can write the entire plugin by hand, or you can copy an existing plugin
template and write the plugin code you need. The second method is by far
the simpler of the two, so the first method will not even be described
here. (Errm, that is, <quote>it is left as an exercise to the
reader.</quote>)
</para>
<para>
The first step is to check out a copy of the
<filename>gst-template</filename> CVS module to get an important tool and
the source code template for a basic &GStreamer; plugin. To check out the
<filename>gst-template</filename> module, make sure you are connected to
the internet, and type the following commands at a command console:
</para>
<screen>
<prompt>shell $ </prompt><userinput>cd .</userinput>
<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.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
U gst-template/gst-app/Makefile.am
U gst-template/gst-app/NEWS
U gst-template/gst-app/README
U gst-template/gst-app/autogen.sh
U gst-template/gst-app/configure.ac
U gst-template/gst-app/src/Makefile.am
...
</screen>
<para>
After the first command, you will have to press <keycap>ENTER</keycap> to
log in to the CVS server. (You might have to log in twice.) The second
command will check out a series of files and directories into <filename
class="directory">./gst-template</filename>. The template you will be
using is in <filename
class="directory">./gst-template/gst-plugin/</filename> directory. You
should look over the files in that directory to get a general idea of the
structure of a source tree for a plugin.
</para>
</sect1>
<!-- ############ sect1 ############# -->
<sect1 id="section-boiler-project-stamp" xreflabel="Using the Project Stamp">
<title>Using the Project Stamp</title>
<para>
The first thing to do when making a new element is to specify some basic
details about it: what its name is, who wrote it, what version number it
is, etc. We also need to define an object to represent the element and to
store the data the element needs. These details are collectively known as
the <emphasis>boilerplate</emphasis>.
</para>
<para>
The standard way of defining the boilerplate is simply to write some code,
and fill in some structures. As mentioned in the previous section, the
easiest way to do this is to copy a template and add functionality
according to your needs. To help you do so, there are some tools in the
<filename class="directory">./gst-template/tools/</filename> directory.
One tool, <filename>gst-quick-stamp</filename>, is a quick command line
tool. The other, <filename>gst-project-stamp</filename>, is a full GNOME
druid application that takes you through the steps of creating a new
project (either a plugin or an application).
</para>
<para>
To use <command>pluginstamp.sh</command>, first open up a terminal window.
Change to the <filename class="directory">gst-template</filename>
directory, and then run the <command>pluginstamp.sh</command> command. The
arguments to the <command>pluginstamp.sh</command> are:
</para>
<orderedlist>
<listitem>
<para>the name of the plugin, and</para>
</listitem>
<listitem>
<para>
the directory that should hold a new subdirectory for the source tree
of the plugin.
</para>
</listitem>
</orderedlist>
<para>
Note that capitalization is important for the name of the plugin. Under
some operating systems, capitalization is also important when specifying
directory names. For example, the following commands create the
ExampleFilter plugin based on the plugin template and put the output files
in a new directory called <filename
class="directory">~/src/examplefilter/</filename>:
</para>
<screen>
<prompt>shell $ </prompt><userinput>cd gst-template</userinput>
<prompt>shell $ </prompt><userinput>tools/pluginstamp.sh ExampleFilter ~/src</userinput>
</screen>
</sect1>
<!-- ############ sect1 ############# -->
<sect1 id="section-boiler-examine">
<title>Examining the Basic Code</title>
<para>
First we will examine the code you would be likely to place in a header
file (although since the interface to the code is entirely defined by the
pluging system, and doesn't depend on reading a header file, this is not
crucial.)
The code here can be found in
<filename>examples/pwg/examplefilter/boiler/gstexamplefilter.h</filename>.
</para>
<example id="ex-boiler-examine-h">
<title>Example Plugin Header File</title>
<programlisting>
/* Definition of structure storing data for this element. */
typedef struct _GstExample GstExample;
struct _GstExample {
GstElement element;
GstPad *sinkpad, *srcpad;
gboolean silent;
};
/* Standard definition defining a class for this element. */
typedef struct _GstExampleClass GstExampleClass;
struct _GstExampleClass {
GstElementClass parent_class;
};
/* Standard macros for defining types for this element. */
#define GST_TYPE_EXAMPLE \
(gst_example_get_type())
#define GST_EXAMPLE(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_EXAMPLE,GstExample))
#define GST_EXAMPLE_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_EXAMPLE,GstExample))
#define GST_IS_EXAMPLE(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_EXAMPLE))
#define GST_IS_EXAMPLE_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE))
/* Standard function returning type information. */
GType gst_example_get_type (void);
</programlisting>
</example>
</sect1>
<!-- ############ sect1 ############# -->
<sect1 id="section-boiler-details">
<title>GstElementDetails</title>
<para>
The GstElementDetails structure gives a heirarchical type for the element,
a human-readable description of the element, as well as author and version
data. The entries are:
</para>
<itemizedlist>
<listitem><para>
A long, english, name for the element.
</para></listitem><listitem><para>
The type of the element, as a heirarchy. The heirarchy is defined by
specifying the top level category, followed by a "/", followed by the
next level category, etc. The type should be defined according to the
guidelines elsewhere in this document. (FIXME: write the guidelines, and
give a better reference to them)
</para></listitem><listitem><para>
A brief description of the purpose of the element.
</para></listitem><listitem><para>
The name of the author of the element, optionally followed by a contact
email address in angle brackets.
</para></listitem>
</itemizedlist>
<para>
For example:
</para>
<programlisting>
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="section-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>
<para>
The last argument in a template is its type
or list of supported types. In this example, we use 'ANY', which means
that this element will accept all input. In real-life situations, you
would set a mimetype and optionally a set of properties to make sure
that only supported input will come in. This representation should be
a string that starts with a mimetype, then a set of comma-separates
properties with their supported values. In case of an audio filter that
supports raw integer 16-bit audio, mono or stereo at any samplerate, the
correct template would look like this:
</para>
<programlisting>
static GstStaticPadTemplate sink_factory =
GST_STATIC_PAD_TEMPLATE (
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (
"audio/x-raw-int, "
"width = (int) 16, "
"depth = (int) 16, "
"endianness = (int) BYTE_ORDER, "
"channels = (int) { 1, 2 }, "
"rate = (int) [ 8000, 96000 ]"
)
);
</programlisting>
<para>
Values surrounded by {} are lists, values surrounded by [] are ranges.
Multiple sets of types are supported too, and should be separated by
a semicolon (<quote>;</quote>). Later, in the chapter on pads, we will
see how to use types to know the exact format of a stream:
<xref linkend="chapter-building-pads"/>.
</para>
</sect1>
<!-- ############ sect1 ############# -->
<sect1 id="section-boiler-constructors">
<title>Constructor Functions</title>
<para>
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>
<!-- ############ sect1 ############# -->
<sect1 id="section-boiler-plugininit">
<title>The plugin_init function</title>
<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 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>
<programlisting>
static gboolean
plugin_init (GstPlugin *plugin)
{
return gst_element_register (plugin, "my_filter",
GST_RANK_NONE,
GST_TYPE_MY_FILTER);
}
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"my_filter",
"My filter plugin",
plugin_init,
VERSION,
"LGPL",
"GStreamer",
"http://gstreamer.net/"
)
</programlisting>
<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.
</para>
</sect1>
</chapter>