summaryrefslogtreecommitdiff
path: root/docs/pwg/building-boiler.xml
blob: fd171adfdabb892034074e4993493e4d6cafee0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
<!-- ############ 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-plugins/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 &amp;&amp; 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.)

      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 &lt;gst/gst.h&gt;

/* 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 &lt;your.name@your.isp&gt;");
    </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 &lt;your.name@your.isp&gt;");
<!-- 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 (&amp;src_factory));
  gst_element_class_add_pad_template (element_class,
	gst_static_pad_template_get (&amp;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>