| <!-- ############ 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>cvs -d:pserver:anoncvs@cvs.freedesktop.org/cvs/gstreamer login</userinput> |
| Logging in to :pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer |
| CVS password: <keycap>[ENTER]</keycap> |
| |
| <prompt>shell $ </prompt><userinput>cvs -z3 -d:pserver:anoncvs@cvs.freedesktop.org:/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> |
| <!-- FIXME |
| This section needs some fixing from someone that is aware of how this |
| works. The only tool that looks like the ones cited there is |
| <filename>gst-plugins/tools/filterstamp.sh</filename> |
| --> |
| <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-plugins/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 |
| plugin 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><!-- example-begin filter.h a --> |
| #include <gst/gst.h> |
| |
| /* Definition of structure storing data for this element. */ |
| typedef struct _GstMyFilter { |
| GstElement element; |
| |
| GstPad *sinkpad, *srcpad; |
| |
| gboolean silent; |
| <!-- example-end filter.h a --> |
| <!-- example-begin filter.h b --><!-- |
| gint samplerate, channels; |
| gint from_samplerate, to_samplerate; |
| gboolean passthrough; |
| guint64 offset; |
| --><!-- example-end filter.h b --> |
| <!-- example-begin filter.h c --> |
| } GstMyFilter; |
| |
| /* Standard definition defining a class for this element. */ |
| typedef struct _GstMyFilterClass { |
| GstElementClass parent_class; |
| } GstMyFilterClass; |
| |
| /* Standard macros for defining types for this element. */ |
| #define GST_TYPE_MY_FILTER \ |
| (gst_my_filter_get_type()) |
| #define GST_MY_FILTER(obj) \ |
| (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MY_FILTER,GstMyFilter)) |
| #define GST_MY_FILTER_CLASS(klass) \ |
| (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MY_FILTER,GstMyFilterClass)) |
| #define GST_IS_MY_FILTER(obj) \ |
| (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MY_FILTER)) |
| #define GST_IS_MY_FILTER_CLASS(obj) \ |
| (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MY_FILTER)) |
| |
| /* Standard function returning type information. */ |
| GType gst_my_filter_get_type (void); |
| <!-- example-end filter.h c --></programlisting> |
| </example> |
| <para> |
| Using this header file, you can use the following macro to setup |
| the <classname>GObject</classname> basics in your source file so |
| that all functions will be called appropriately: |
| </para> |
| <programlisting><!-- example-begin boilerplate.c a --> |
| #include "filter.h" |
| |
| GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT); |
| <!-- example-end boilerplate.c a --></programlisting> |
| </sect1> |
| |
| <!-- ############ sect1 ############# --> |
| |
| <sect1 id="section-boiler-details"> |
| <title>GstElementDetails</title> |
| <para> |
| The GstElementDetails structure gives a hierarchical 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 hierarchy. The hierarchy 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><!-- example-begin boilerplate.c b --> |
| static GstElementDetails my_filter_details = { |
| "An example plugin", |
| "Example/FirstExample", |
| "Shows the basic structure of a plugin", |
| "your name <your.name@your.isp>" |
| }; |
| <!-- example-end boilerplate.c b --></programlisting> |
| <para> |
| The element details are registered with the plugin during |
| the <function>_base_init ()</function> function, which is part of |
| the GObject system. The <function>_base_init ()</function> function |
| should be set for this GObject in the function where you register |
| the type with Glib. |
| </para> |
| <programlisting><!-- example-begin boilerplate.c c --> |
| static void |
| gst_my_filter_base_init (gpointer klass) |
| { |
| GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
| <!-- example-end boilerplate.c c --> |
| static GstElementDetails my_filter_details = { |
| [..] |
| }; |
| |
| [..]<!-- example-begin boilerplate.c d --> |
| gst_element_class_set_details (element_class, &my_filter_details); |
| <!-- example-end boilerplate.c d --> |
| } |
| </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><!-- example-begin boilerplate.c e --> |
| static GstStaticPadTemplate sink_factory = |
| GST_STATIC_PAD_TEMPLATE ( |
| "sink", |
| GST_PAD_SINK, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS ("ANY") |
| ); |
| <!-- example-end boilerplate.c e --> |
| <!-- example-begin boilerplate.c f --><!-- |
| static GstStaticPadTemplate src_factory = |
| GST_STATIC_PAD_TEMPLATE ( |
| "src", |
| GST_PAD_SRC, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS ("ANY") |
| ); |
| --><!-- example-end boilerplate.c f --> |
| </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. In order to create a new pad from this |
| template using <function>gst_pad_new_from_template ()</function>, you |
| will need to declare the pad template as a global variable. More on |
| this subject in <xref linkend="chapter-building-pads"/>. |
| </para> |
| <programlisting> |
| static GstStaticPadTemplate sink_factory = [..], |
| src_factory = [..]; |
| |
| static void |
| gst_my_filter_base_init (gpointer klass) |
| { |
| GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
| [..] |
| <!-- example-begin boilerplate.c g --> |
| gst_element_class_add_pad_template (element_class, |
| gst_static_pad_template_get (&src_factory)); |
| gst_element_class_add_pad_template (element_class, |
| gst_static_pad_template_get (&sink_factory)); |
| } |
| <!-- example-end boilerplate.c g --> |
| <!-- example-begin boilerplate.c h --><!-- |
| static void |
| gst_my_filter_class_init (GstMyFilterClass * klass) |
| { |
| } |
| |
| static void |
| gst_my_filter_init (GstMyFilter * filter) |
| { |
| } |
| |
| #include "register.func" |
| --><!-- example-end boilerplate.c h --></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 curly brackets (<quote>{</quote> and |
| <quote>}</quote>) are lists, values surrounded by square brackets |
| (<quote>[</quote> and <quote>]</quote>) 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><!-- example-begin register.func --> |
| 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/" |
| ) |
| <!-- example-end register.func --></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> |