gstreamer/markdown/plugin-development/basics/boiler.md

369 lines
12 KiB
Markdown
Raw Normal View History

2016-06-04 06:03:13 +00:00
---
title: Constructing the Boilerplate
...
# Constructing the Boilerplate
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.
## Getting the GStreamer Plugin Templates
2016-06-04 06:03:13 +00:00
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, “it is left as an exercise to the reader.”)
The first step is to check out a copy of the `gst-template` git module
to get an important tool and the source code template for a basic
GStreamer plugin. To check out the `gst-template` module, make sure you
are connected to the internet, and type the following commands at a
command
console:
```
2016-06-04 06:03:13 +00:00
shell $ git clone git://anongit.freedesktop.org/gstreamer/gst-template.git
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.
2016-06-04 06:03:13 +00:00
```
This command will check out a series of files and directories into
`gst-template`. The template you will be using is in the
`gst-template/gst-plugin/` 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.
If for some reason you can't access the git repository, you can also
[download a snapshot of the latest
revision](http://cgit.freedesktop.org/gstreamer/gst-template/commit/)
via the cgit web interface.
## Using the Project Stamp
2016-06-04 06:03:13 +00:00
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 *boilerplate*.
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
`./gst-plugin/tools/` directory. This tool, `make_element`, is a command
line utility that creates the boilerplate code for you.
To use `make_element`, first open up a terminal window. Change to the
`gst-template/gst-plugin/src` directory, and then run the `make_element`
command. The arguments to the `make_element` are:
1. the name of the plugin, and
2. the source file that the tool will use. By default, `gstplugin` is
used.
For example, the following commands create the MyFilter plugin based on
the plugin template and put the output files in the
`gst-template/gst-plugin/src` directory:
```
2016-06-04 06:03:13 +00:00
shell $ cd gst-template/gst-plugin/src
shell $ ../tools/make_element MyFilter
2016-06-04 06:03:13 +00:00
```
> **Note**
>
2016-06-04 06:03:13 +00:00
> 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.
The last command creates two files: `gstmyfilter.c` and `gstmyfilter.h`.
> **Note**
>
2016-06-04 06:03:13 +00:00
> It is recommended that you create a copy of the `gst-plugin` directory
> before continuing.
Now one needs to adjust the `Makefile.am` to use the new filenames and
run `autogen.sh` from the parent directory to bootstrap the build
environment. After that, the project can be built and installed using
the well known `make && sudo make install` commands.
> **Note**
>
2016-06-04 06:03:13 +00:00
> Be aware that by default `autogen.sh` and `configure` would choose
> `/usr/local` as a default location. One would need to add
> `/usr/local/lib/gstreamer-1.0` to `GST_PLUGIN_PATH` in order to make
> the new plugin show up in a gstreamer that's been installed from
> packages.
> **Note**
>
2016-06-04 06:03:13 +00:00
> 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.
## Examining the Basic Code
2016-06-04 06:03:13 +00:00
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.)
``` c
2016-06-04 06:03:13 +00:00
#include <gst/gst.h>
/* Definition of structure storing data for this element. */
typedef struct _GstMyFilter {
GstElement element;
GstPad *sinkpad, *srcpad;
gboolean silent;
} 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);
2016-06-04 06:03:13 +00:00
```
Using this header file, you can use the following macro to setup the
`GObject` basics in your source file so that all functions will be
called appropriately:
``` c
2016-06-04 06:03:13 +00:00
#include "filter.h"
G_DEFINE_TYPE (GstMyFilter, gst_my_filter, GST_TYPE_ELEMENT);
2016-06-04 06:03:13 +00:00
```
## Element metadata
2016-06-04 06:03:13 +00:00
The Element metadata provides extra element information. It is
configured with `gst_element_class_set_metadata` or
`gst_element_class_set_static_metadata` which takes the following
parameters:
- A long, English, name for the element.
- The type of the element, see the docs/design/draft-klass.txt
document in the GStreamer core source tree for details and examples.
- A brief description of the purpose of the element.
- The name of the author of the element, optionally followed by a
contact email address in angle brackets.
For example:
``` c
2016-06-04 06:03:13 +00:00
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>");
2016-06-04 06:03:13 +00:00
```
The element details are registered with the plugin during the
`_class_init ()` function, which is part of the GObject system. The
`_class_init ()` function should be set for this GObject in the function
where you register the type with GLib.
``` c
2016-06-04 06:03:13 +00:00
static void
gst_my_filter_class_init (GstMyFilterClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
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>");
}
2016-06-04 06:03:13 +00:00
```
## GstStaticPadTemplate
2016-06-04 06:03:13 +00:00
A GstStaticPadTemplate is a description of a pad that the element will
(or might) create and use. It contains:
- A short name for the pad.
- Pad direction.
- Existence property. This indicates whether the pad exists always (an
“always” pad), only in some cases (a “sometimes” pad) or only if the
application requested such a pad (a “request” pad).
- Supported types by this element (capabilities).
For example:
``` c
2016-06-04 06:03:13 +00:00
static GstStaticPadTemplate sink_factory =
GST_STATIC_PAD_TEMPLATE (
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("ANY")
);
2016-06-04 06:03:13 +00:00
```
Those pad templates are registered during the `_class_init ()` function
with the `gst_element_class_add_pad_template ()`. For this function you
need a handle the `GstPadTemplate` which you can create from the static
pad template with `gst_static_pad_template_get ()`. See below for more
details on this.
Pads are created from these static templates in the element's `_init ()`
function using `gst_pad_new_from_static_template ()`. In order to create
a new pad from this template using `gst_pad_new_from_static_template
()`, you will need to declare the pad template as a global variable. More on
this subject in [Specifying the pads][pads].
2016-06-04 06:03:13 +00:00
static GstStaticPadTemplate sink_factory = [..],
src_factory = [..];
2016-06-04 06:03:13 +00:00
static void
gst_my_filter_class_init (GstMyFilterClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
2016-06-04 06:03:13 +00:00
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));
}
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:
``` c
2016-06-04 06:03:13 +00:00
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 ]"
)
);
2016-06-04 06:03:13 +00:00
```
Values surrounded by curly brackets (“{” and “}”) are lists, values
surrounded by square brackets (“\[” and “\]”) are ranges. Multiple sets
of types are supported too, and should be separated by a semicolon
(“;”). Later, in the chapter on pads, we will see how to use types
to know the exact format of a stream: [Specifying the pads][pads].
[pads]: plugin-development/basics/pads.md
2016-06-04 06:03:13 +00:00
## Constructor Functions
2016-06-04 06:03:13 +00:00
Each element has two functions which are used for construction of an
element. The `_class_init()` 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 `_init()`
function, which is used to initialise a specific instance of this type.
## The plugin\_init function
2016-06-04 06:03:13 +00:00
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.
``` c
2016-06-04 06:03:13 +00:00
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/"
)
2016-06-04 06:03:13 +00:00
```
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.