| <!-- ############ 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> git 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>git clone git://anongit.freedesktop.org/gstreamer/gst-template.git</userinput> |
| Initialized empty Git repository in /some/path/gst-template/.git/ |
| remote: Counting objects: 373, done. |
| remote: Compressing objects: 100% (114/114), done. |
| remote: Total 373 (delta 240), reused 373 (delta 240) |
| Receiving objects: 100% (373/373), 75.16 KiB | 78 KiB/s, done. |
| Resolving deltas: 100% (240/240), done. |
| </screen> |
| <para> |
| This 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 the |
| <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> |
| <para> |
| If for some reason you can't access the git repository, you can also |
| <ulink type="http" |
| url="http://cgit.freedesktop.org/gstreamer/gst-template/commit/"> |
| download a snapshot of the latest revision</ulink> via the cgit web |
| interface. |
| </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 is a tool in the |
| <filename class="directory">./gst-plugin/tools/</filename> directory. |
| This tool, <filename>make_element</filename>, is a command line utility |
| that creates the boilerplate code for you. |
| </para> |
| <para> |
| To use <command>make_element</command>, first open up a terminal window. |
| Change to the <filename class="directory">gst-template/gst-plugin/src</filename> |
| directory, and then run the <command>make_element</command> command. The |
| arguments to the <command>make_element</command> are: |
| </para> |
| <orderedlist> |
| <listitem> |
| <para>the name of the plugin, and</para> |
| </listitem> |
| <listitem> |
| <para> |
| the source file that the tool will use. By default, |
| <filename>gstplugin</filename> is used. |
| </para> |
| </listitem> |
| </orderedlist> |
| <para> |
| For example, the following commands create the MyFilter plugin based on |
| the plugin template and put the output files in the |
| <filename class="directory">gst-template/gst-plugin/src</filename> |
| directory: |
| </para> |
| <screen> |
| <prompt>shell $ </prompt><userinput>cd gst-template/gst-plugin/src</userinput> |
| <prompt>shell $ </prompt><userinput>../tools/make_element MyFilter</userinput> |
| </screen> |
| <note> |
| <para> |
| Capitalization is important for the name of the plugin. Keep in mind |
| that under some operating systems, capitalization is also important |
| when specifying directory and file names in general. |
| </para> |
| </note> |
| <para> |
| The last command creates two files: |
| <filename>gstmyfilter.c</filename> and |
| <filename>gstmyfilter.h</filename>. |
| </para> |
| <note> |
| <para> |
| It is recommended that you create a copy of the <filename |
| class="directory">gst-plugin</filename> |
| directory before continuing. |
| </para> |
| </note> |
| <para> |
| Now one needs to adjust the <filename>Makefile.am</filename> to use the |
| new filenames and run <filename>autogen.sh</filename> from the parent |
| directory to bootstrap the build environment. After that, the project |
| can be built and installed using the well known |
| <userinput>make && sudo make install</userinput> commands. |
| </para> |
| <note> |
| <para> |
| Be aware that by default <filename>autogen.sh</filename> and |
| <filename>configure</filename> would choose <filename class="directory">/usr/local</filename> |
| as a default location. One would need to add |
| <filename class="directory">/usr/local/lib/gstreamer-1.0</filename> |
| to <symbol>GST_PLUGIN_PATH</symbol> in order to make the new plugin |
| show up in a gstreamer that's been installed from packages. |
| </para> |
| </note> |
| <note> |
| <para> |
| FIXME: this section is slightly outdated. gst-template is still useful |
| as an example for a minimal plugin build system skeleton. However, for |
| creating elements the tool gst-element-maker from gst-plugins-bad is |
| recommended these days. |
| </para> |
| </note> |
| </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.) |
| </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(klass) \ |
| (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" |
| |
| G_DEFINE_TYPE (GstMyFilter, gst_my_filter, GST_TYPE_ELEMENT); |
| <!-- example-end boilerplate.c a --></programlisting> |
| </sect1> |
| |
| <!-- ############ sect1 ############# --> |
| |
| <sect1 id="section-boiler-details"> |
| <title>Element metadata</title> |
| <para> |
| The Element metadata provides extra element information. It is configured |
| with <function>gst_element_class_set_metadata</function> or |
| <function>gst_element_class_set_static_metadata</function> which takes the |
| following parameters: |
| </para> |
| <itemizedlist> |
| <listitem><para> |
| A long, English, name for the element. |
| </para></listitem><listitem><para> |
| The type of the element, see the docs/design/draft-klass.txt document |
| in the GStreamer core source tree for details and examples. |
| </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> |
| gst_element_class_set_static_metadata (klass, |
| "An example plugin", |
| "Example/FirstExample", |
| "Shows the basic structure of a plugin", |
| "your name <your.name@your.isp>"); |
| </programlisting> |
| <para> |
| The element details are registered with the plugin during |
| the <function>_class_init ()</function> function, which is part of |
| the GObject system. The <function>_class_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_class_init (GstMyFilterClass * klass) |
| { |
| GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
| <!-- example-end boilerplate.c c --> |
| [..]<!-- example-begin boilerplate.c d --> |
| gst_element_class_set_static_metadata (element_klass, |
| "An example plugin", |
| "Example/FirstExample", |
| "Shows the basic structure of a plugin", |
| "your name <your.name@your.isp>"); |
| <!-- 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>_class_init ()</function> function with the |
| <function>gst_element_class_add_pad_template ()</function>. For this |
| function you need a handle the <classname>GstPadTemplate</classname> |
| which you can create from the static pad template with |
| <function>gst_static_pad_template_get ()</function>. See below for more |
| details on this. |
| </para> |
| <para> |
| Pads are created from these static templates in the element's |
| <function>_init ()</function> function using |
| <function>gst_pad_new_from_static_template ()</function>. |
| In order to create a new pad from this |
| template using <function>gst_pad_new_from_static_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_class_init (GstMyFilterClass * 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_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 media type 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 media type, 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> |
| <![CDATA[ |
| static GstStaticPadTemplate sink_factory = |
| GST_STATIC_PAD_TEMPLATE ( |
| "sink", |
| GST_PAD_SINK, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS ( |
| "audio/x-raw, " |
| "format = (string) " GST_AUDIO_NE (S16) ", " |
| "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 two functions which are used for construction of an |
| element. 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 --> |
| <![CDATA[ |
| 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> |