Moving the "Filter Writer's Guide" to the "Plugin Writers' Guide".

Original commit message from CVS:
Moving the "Filter Writer's Guide" to the "Plugin Writers' Guide".
This commit is contained in:
Leif Johnson 2002-09-27 18:17:05 +00:00
parent ebda7d920a
commit cc5f591c17
15 changed files with 0 additions and 1631 deletions

13
docs/fwg/.gitignore vendored
View file

@ -1,13 +0,0 @@
Makefile
Makefile.in
*.bak
.deps
images
gst-plugin-writers-guide
gst-plugin-writers-guide.pdf
gst-plugin-writers-guide.ps
gst-plugin-writers-guide.dvi
gst-plugin-writers-guide.tex
gst-plugin-writers-guide.log
gst-plugin-writers-guide.aux
gst-plugin-writers-guide.junk

View file

@ -1,18 +0,0 @@
DOC=gst-plugin-writers-guide
MAIN=$(DOC).xml
XML=$(wildcard *.xml)
XSLFO=$(srcdir)/../xsl/fo.xsl
XSLFOMODS=$(srcdir)/../xsl/ulink.xsl $(srcdir)/../xsl/keycombo.xsl
XSLHTML=$(srcdir)/../xsl/html.xsl
XSLHTMLMODS=$(srcdir)/../xsl/fileext.xsl $(srcdir)/../xsl/admon.xsl \
$(srcdir)/../xsl/keycombo.xsl $(srcdir)/../xsl/css.xsl
XSLS=$(XSLFO) $(XSLFOMODS) $(XSLHTML) $(XSLHTMLMODS)
FIGS= # $(wildcard *.fig) (uncomment when pngs are added)
PNGS=$(FIGS:.fig=.png)
PDFS=$(FIGS:.fig=.pdf)
SRC=$(XML)
CSS=base.css
EXTRA_DIST = $(XML) $(FIGS) $(CSS) magic-png magic-pdf
include $(srcdir)/../manuals.mak

View file

View file

@ -1,23 +0,0 @@
<chapter id="cha-buffers-anatomy">
<title>
Anatomy of a Buffer
</title>
<para>
</para>
</chapter>
<chapter id="cha-buffers-refcounts">
<title>
Refcounts and mutability
</title>
<para>
</para>
</chapter>
<chapter id="cha-buffers-metadata">
<title>
Metadata
</title>
<para>
</para>
</chapter>

View file

@ -1,14 +0,0 @@
<chapter id="cha-checklist-filter">
<title>
Things to check when writing a filter
</title>
<para>
</para>
</chapter>
<chapter id="cha-checklist-srcsink">
<title>
Things to check when writing a source or sink
</title>
<para>
</para>
</chapter>

View file

@ -1,380 +0,0 @@
<chapter id="cha-dparam-start">
<title>Getting Started</title>
<para>
The dparams subsystem is contained within the <filename>gstcontrol</filename> library.
You need to include the header in your element's source file:
</para>
<programlisting>
#include &lt;gst/control/control.h&gt;
</programlisting>
<para>
Even though the <filename>gstcontrol</filename> library may be linked into the host
application, you should make sure it is loaded in your <filename>plugin_init</filename>
function:
</para>
<programlisting>
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
...
/* load dparam support library */
if (!gst_library_load ("gstcontrol"))
{
gst_info ("example: could not load support library: 'gstcontrol'\n");
return FALSE;
}
...
}
</programlisting>
<para>
You need to store an instance of <filename>GstDParamManager</filename> in your element's struct:
</para>
<programlisting>
struct _GstExample {
GstElement element;
...
GstDParamManager *dpman;
...
};
</programlisting>
<para>
The <filename>GstDParamManager</filename> can be initialised in your element's
init function:
</para>
<programlisting>
static void
gst_example_init (GstExample *example)
{
...
example-&gt;dpman = gst_dpman_new ("example_dpman", GST_ELEMENT(example));
...
}
</programlisting>
</chapter>
<chapter id="cha-dparam-define">
<title>Defining Parameter Specificiations</title>
<para>
You can define the dparams you need anywhere within your element but will usually
need to do so in only a couple of places:
<itemizedlist>
<listitem>
In the element <filename>init</filename> function,
just after the call to <filename>gst_dpman_new</filename>
</listitem>
<listitem>
Whenever a new pad is created so that parameters can affect data going into
or out of a specific pad. An example of this would be a mixer element where
a seperate volume parameter is needed on every pad.
</listitem>
</itemizedlist>
</para>
<para>
There are three different ways the dparams subsystem can pass parameters into your element.
Which one you use will depend on how that parameter is used within your element.
Each of these methods has its own function to define a required dparam:
<itemizedlist>
<listitem><filename>gst_dpman_add_required_dparam_direct</filename></listitem>
<listitem><filename>gst_dpman_add_required_dparam_callback</filename></listitem>
<listitem><filename>gst_dpman_add_required_dparam_array</filename></listitem>
</itemizedlist>
These functions will return TRUE if the required dparam was added successfully.
</para>
<para>
The following function will be used as an example.
<programlisting>
gboolean
gst_dpman_add_required_dparam_direct (GstDParamManager *dpman,
GParamSpec *param_spec,
gboolean is_log,
gboolean is_rate,
gpointer update_data)
</programlisting>
The common parameters to these functions are:
<itemizedlist>
<listitem><filename>GstDParamManager *dpman</filename> the element's dparam manager</listitem>
<listitem><filename>GParamSpec *param_spec</filename> the param spec which defines the required dparam</listitem>
<listitem>
<filename>gboolean is_log</filename> whether this dparam value should be
interpreted on a log scale (such as a frequency or a decibel value)
</listitem>
<listitem>
<filename>gboolean is_rate</filename> whether this dparam value is a proportion of the
sample rate. For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz.
</listitem>
</itemizedlist>
</para>
<sect2 id="sect-dparam-direct">
<title>Direct Method</title>
<para>
This method is the simplest and has the lowest overhead for parameters which change
less frequently than the sample rate. First you need somewhere to store the parameter -
this will usually be in your element's stuct.
</para>
<programlisting>
struct _GstExample {
GstElement element;
...
GstDParamManager *dpman;
gfloat volume;
...
};
</programlisting>
<para>
Then to define the required dparam just call <filename>gst_dpman_add_required_dparam_direct</filename>
and pass in the location of the parameter to change.
In this case the location is <filename>&amp;(example-&gt;volume)</filename>.
</para>
<programlisting>
gst_dpman_add_required_dparam_direct (
example-&gt;dpman,
g_param_spec_float("volume","Volume","Volume of the audio",
0.0, 1.0, 0.8, G_PARAM_READWRITE),
FALSE,
FALSE,
&amp;(example-&gt;volume)
);
</programlisting>
<para>
You can now use <filename>example-&gt;volume</filename> anywhere in your element knowing
that it will always contain the correct value to use.
</para>
</sect2>
<sect2 id="sect-dparam-callback">
<title>Callback Method</title>
<para>
This should be used if the you have other values to calculate whenever a parameter changes.
If you used the direct method you wouldn't know if a parameter had changed so you would have to
recalculate the other values every time you needed them. By using the callback method, other values
only have to be recalculated when the dparam value actually changes.
</para>
<para>
The following code illustrates an instance where you might want to use the callback method.
If you had a volume dparam which was represented by a gfloat number, your element may only deal
with integer arithmatic. The callback could be used to calculate the integer scaler when the volume
changes. First you will need somewhere to store these values.
</para>
<programlisting>
struct _GstExample {
GstElement element;
...
GstDParamManager *dpman;
gfloat volume_f;
gint volume_i;
...
};
</programlisting>
<para>
When the required dparam is defined, the callback function <filename>gst_example_update_volume</filename>
and some user data (which in this case is our element instance) is passed in to the call to
<filename>gst_dpman_add_required_dparam_callback</filename>.
</para>
<programlisting>
gst_dpman_add_required_dparam_callback (
example-&gt;dpman,
g_param_spec_float("volume","Volume","Volume of the audio",
0.0, 1.0, 0.8, G_PARAM_READWRITE),
FALSE,
FALSE,
gst_example_update_volume,
example
);
</programlisting>
<para>
The callback function needs to conform to this signiture
</para>
<programlisting>
typedef void (*GstDPMUpdateFunction) (GValue *value, gpointer data);
</programlisting>
<para>
In our example the callback function looks like this
</para>
<programlisting>
static void
gst_example_update_volume(GValue *value, gpointer data)
{
GstExample *example = (GstExample*)data;
g_return_if_fail(GST_IS_EXAMPLE(example));
example-&gt;volume_f = g_value_get_float(value);
example-&gt;volume_i = example-&gt;volume_f * 8192;
}
</programlisting>
<para>
Now <filename>example-&gt;volume_i</filename> can be used elsewhere and it will always contain the correct value.
</para>
</sect2>
<sect2 id="sect-dparam-array">
<title>Array Method</title>
<para>
This method is quite different from the other two. It could be thought of as
a specialised method which should only be used if you need the advantages that it
provides. Instead of giving the element a single value it provides an array of values
where each item in the array corresponds to a sample of audio in your buffer.
There are a couple of reasons why this might be useful.
</para>
<itemizedlist>
<listitem>
Certain optimisations may be possible since you can iterate over your dparams array
and your buffer data together.
</listitem>
<listitem>
Some dparams may be able to interpolate changing values at the sample rate. This would allow
the array to contain very smoothly changing values which may be required for the stability
and quality of some DSP algorithms.
</listitem>
</itemizedlist>
<para>
The array method is currently the least mature of the three methods and is not yet ready to be
used in elements, but plugin writers should be aware of its existance for the future.
</para>
</sect2>
</chapter>
<chapter id="cha-dparam-loop">
<title>The Data Processing Loop</title>
<para>
This is the most critical aspect of the dparams subsystem as it relates to elements.
In a traditional audio processing loop, a <filename>for</filename> loop will usually iterate over each
sample in the buffer, processing one sample at a time until the buffer is finished.
A simplified loop with no error checking might look something like this.
</para>
<programlisting>
static void
example_chain (GstPad *pad, GstBuffer *buf)
{
...
gfloat *float_data;
int j;
GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad));
int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat);
float_data = (gfloat *)GST_BUFFER_DATA(buf);
...
for (j = 0; j &lt; num_samples; j++) {
float_data[j] *= example-&gt;volume;
}
...
}
</programlisting>
<para>
To make this dparams aware, a couple of changes are needed.
</para>
<programlisting>
static void
example_chain (GstPad *pad, GstBuffer *buf)
{
...
int j = 0;
GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad));
int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat);
gfloat *float_data = (gfloat *)GST_BUFFER_DATA(buf);
int frame_countdown = GST_DPMAN_PREPROCESS(example-&gt;dpman, num_samples, GST_BUFFER_TIMESTAMP(buf));
...
while (GST_DPMAN_PROCESS_COUNTDOWN(example-&gt;dpman, frame_countdown, j)) {
float_data[j++] *= example-&gt;volume;
}
...
}
</programlisting>
<para>
The biggest changes here are 2 new macros, <filename>GST_DPMAN_PREPROCESS</filename>
and <filename>GST_DPMAN_PROCESS_COUNTDOWN</filename>.
You will also notice that the for loop has become a while loop. <filename>GST_DPMAN_PROCESS_COUNTDOWN</filename>
is called as the condition for the while loop so that any required dparams can be updated in the
middle of a buffer if required. This is because one of the required behaviours of dparams is that they
can be <emphasis>sample accurate</emphasis>. This means that parameters change at the exact timestamp
that they are supposed to - not after the buffer has finished being processed.
</para>
<para>
It may be alarming to see a macro as the condition for a while loop, but it is actually very efficient.
The macro expands to the following.
</para>
<programlisting>
#define GST_DPMAN_PROCESS_COUNTDOWN(dpman, frame_countdown, frame_count) \
(frame_countdown-- || \
(frame_countdown = GST_DPMAN_PROCESS(dpman, frame_count)))
</programlisting>
<para>
So as long as <filename>frame_countdown</filename> is greater than 0, <filename>GST_DPMAN_PROCESS</filename>
will not be called at all.
Also in many cases, <filename>GST_DPMAN_PROCESS</filename> will do nothing and simply
return 0, meaning that there is no more data in the buffer to process.
</para>
<para>
The macro <filename>GST_DPMAN_PREPROCESS</filename> will do the following:
<itemizedlist>
<listitem>
Update any dparams which are due to be updated.
</listitem>
<listitem>
Calculate how many samples should be processed before the next required update
</listitem>
<listitem>
Return the number of samples until next update, or the number of samples in the buffer -
whichever is less.
</listitem>
</itemizedlist>
In fact <filename>GST_DPMAN_PROCESS</filename> may do the same things as <filename>GST_DPMAN_PREPROCESS</filename>
depending on the mode that the dparam manager is running in (see below).
</para>
<sect2 id="sect-dparam-modes">
<title>DParam Manager Modes</title>
<para>
A brief explanation of dparam manager modes might be useful here even though it doesn't generally affect
the way your element is written. There are different ways media applications will be used which
require that an element's parameters be updated in differently. These include:
<itemizedlist>
<listitem>
<emphasis>Timelined</emphasis> - all parameter changes are known in advance before the pipeline is run.
</listitem>
<listitem>
<emphasis>Realtime low-latency</emphasis> - Nothing is known ahead of time about when a parameter
might change. Changes need to be propagated to the element as soon as possible.
</listitem>
</itemizedlist>
When a dparam-aware application gets the dparam manager for an element, the first thing it will do
is set the dparam manager mode. Current modes are <filename>"synchronous"</filename>
and <filename>"asynchronous"</filename>.
</para>
<para>
If you are in a realtime low-latency situation then the <filename>"synchronous"</filename> mode is appropriate.
During <filename>GST_DPMAN_PREPROCESS</filename> this mode will poll all dparams for required updates
and propagate them. <filename>GST_DPMAN_PROCESS</filename> will do nothing in this mode.
To then achieve the desired latency, the size of the buffers needs to be reduced so that the dparams will be
polled for updates at the desired frequency.
</para>
<para>
In a timelined situation, the <filename>"asynchronous"</filename> mode will be required. This mode
hasn't actually been implemented yet but will be described anyway.
The <filename>GST_DPMAN_PREPROCESS</filename> call will precalculate when and how often each dparam needs
to update for the duration of the current buffer. From then on <filename>GST_DPMAN_PROCESS</filename> will
propagate the calculated updates each time it is called until end of the buffer. If the application is rendering
to disk in non-realtime, the render could be sped up by increasing the buffer size. In the <filename>"asynchronous"</filename>
mode this could be done without affecting the sample accuracy of the parameter updates
</para>
</sect2>
<sect2 id="sect-dparam-audio-video">
<title>DParam Manager Modes</title>
<para>
All of the explanation so far has presumed that the buffer contains audio data with many samples.
Video should be regarded differently since a video buffer often contains only 1 frame. In this case
some of the complexity of dparams isn't required but the other benefits still make it useful for video
parameters. If a buffer only contains one frame of video, only a single call to <filename>GST_DPMAN_PREPROCESS</filename>
should be required. For more than one frame per buffer, treat it the same as the audio case.
</para>
</sect2>
</chapter>

View file

@ -1,878 +0,0 @@
<?xml version='1.0'?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % magic-entities SYSTEM "magic">
%magic-entities;
<!ENTITY TITLEPAGE SYSTEM "titlepage.xml">
<!ENTITY INTRO SYSTEM "intro.xml">
<!ENTITY TESTAPP SYSTEM "testapp.xml">
<!ENTITY LOOPBASED SYSTEM "loopbased.xml">
<!ENTITY BUFFERS SYSTEM "buffers.xml">
<!ENTITY SRCNSINK SYSTEM "srcnsink.xml">
<!ENTITY STATEMANAGE SYSTEM "statemanage.xml">
<!ENTITY CHECKLIST SYSTEM "checklist.xml">
<!ENTITY DPARAMS SYSTEM "dparams.xml">
<!ENTITY GStreamer "<application>GStreamer</application>">
]>
<book id="index">
&TITLEPAGE;
<!-- ############# part ############### -->
<part id="introduction"><title>Introduction</title>
<partintro>
<para>
&GStreamer; is a framework for creating
streaming media applications. It is extremely powerful and versatile,
and this versatility stems in part from its modularity, and its ability
to incorporate new modules seamlessly into its framework.
This document describes how to extend the capabilities of
&GStreamer; by creating new plugins.
</para>
<para>
It first describes the concepts required and the ways in which
&GStreamer; can be extended. It then goes
through a worked example of how to write a simple filter (for data
processing), and how to test and debug it. More advanced concepts are
then introduced, with worked examples of each. Next, writing source
and sink elements (for performing input and output) is discussed.
Finally, checklists of things to be sure to do when extending
&GStreamer; are presented.
</para>
</partintro>
&INTRO;
</part>
<!-- ############ part ############# -->
<part id="basic-concepts"><title>Basic concepts</title>
<partintro>
<para>
This section introduces the basic concepts required to understand the
issues involved in extending &GStreamer;
</para>
<para>
Many of these concepts are explained in greater detail in the
GStreamer Application Development Manual, and are merely mentioned
here to refresh your memory.
</para>
</partintro>
<chapter id="cha-plugins">
<title>Plugins</title>
<para>
Extensions to &GStreamer; can be made using a plugin mechanism. This is
used extensively in &GStreamer; even if only the standard package is
being used: a few very basic functions reside in the core library, and
all others are implemented in plugins.
</para>
<para>
Plugins are only loaded when needed: a plugin registry is used to
store the details of the plugins so that it is not neccessary to load
all plugins to determine which are needed.
This registry needs to be updated whenever a new plugin is added to the
system: see the <emphasis>gstreamer-register</emphasis> utility and the
documentation in the <emphasis>GStreamer Application Development
Manual</emphasis> for more details.
</para>
<para>
User extensions to &GStreamer; can be installed in the main plugin
directory, and will immediately be available for use in applications.
<emphasis>gstreamer-register</emphasis> should be run to update
the repository: but the system should work correctly even if it hasn't
been - it will just take longer to load the correct plugin.
</para>
<para>
User specific plugin directories and registries will be available
in future versions of &GStreamer;.
</para>
</chapter>
<chapter id="cha-elements">
<title>Elements</title>
<para>
Elements are at the core of &GStreamer;. Without elements, &GStreamer;
is just
a bunch of pipe fittings with nothing to connect. A large number of
elements (filters, sources and sinks) ship with &GStreamer;, but extra
elements can also be written.
</para>
<para>
An element may be constructed in several different ways, but all must
conform to the same basic rules. A simple filter may be built with the
FilterFactory, where the only code that need be written is the actual
filter code. A more complex filter, or a source or sink, will need to
be written out fully for complete access to the features and
performance possible with &GStreamer;.
</para>
<para>
The implementation of a new element will be contained in a plugin:
a single plugin may contain the implementation of several elements, or
just a single one.
</para>
</chapter>
<chapter id="cha-buffers">
<title>Buffers</title>
<para>
Buffers are structures used to pass data between elements. All streams
of data are chopped up into chunks which are stored in buffers.
Buffers can be of any size, and also contain metadata indicating the
type of data contained in them. Buffers can be allocated by various
different schemes, and may either be passed on by elements or
unreferenced (and the memory used by the buffer freed).
</para>
</chapter>
<chapter id="cha-typing">
<title>Typing and Properties</title>
<para>
A type system is used to ensure that the data passed between elements
is in a recognised format, and that the various parameters required
to fully specify that format match up correctly. Each connection
that is made between elements has a specified type. This is related,
but different, to the metadata in buffers which describes the type
of data in that particular buffer. See later in this document for
details of the available types.
</para>
</chapter>
<chapter id="cha-metadata">
<title>Metadata</title>
<para>
</para>
</chapter>
<chapter id="cha-scheduling">
<title>Scheduling</title>
<para>
</para>
</chapter>
<chapter id="cha-chainloop">
<title>Chain vs Loop Elements</title>
<para>
</para>
</chapter>
<chapter id="cha-autopluggers">
<title>Autopluggers</title>
<para>
&GStreamer; has an autoplugging mechanism, which enables application
writers to simply specify start and end elements for a path, and
the system will then create a path which links these elements,
in accordance with the type information provided by the elements.
</para>
<para>
It is possible to devise many different schemes for generating such
pathways, perhaps to optimise based on special criteria, or with
some specific constraints. It is thus possible to define new
autoplugging systems, using the plugin system.
</para>
</chapter>
</part>
<!-- ############ part ############# -->
<part id="typesnprops"><title>Types and Properties</title>
<partintro>
<para>
There is a very large set of possible types that may be used to
pass data between elements. Indeed, each new element that is defined
may use a new data format (though unless at least one other element
recognises that format, it will be most likely be useless since
nothing will be able to link with it).
</para>
<para>
In order for types to be useful, and for systems like autopluggers to
work, it is neccessary that all elements
agree on the type definitions, and which properties are required
for each type. The &GStreamer; framework itself
simply provides the ability to define types and parameters, but does
not fix the meaning of types and parameters, and does not enforce
standards on the creation of new types. This is a matter for
a policy to decide, not technical systems to enforce.
</para>
<para>
For now, the policy is simple:
<itemizedlist>
<listitem>
<para>
Do not create a new type if you could use one which already
exists.
</para>
</listitem>
<listitem>
<para>
If creating a new type, discuss it first with the other
&GStreamer; developers, on at least one of: IRC, mailing lists,
the &GStreamer; wiki.
</para>
</listitem>
<listitem>
<para>
Try to ensure that the name for a new format is as unlikely to
conflict with anything else created already, and is not a more
generalised name than it should be. For example:
"audio/compressed" would be too generalised a name to represent
audio data compressed with an mp3 codec. Instead "audio/mp3"
might be an appropriate name, or "audio/compressed" could exist
and have a property indicating the type of compression used.
</para>
</listitem>
<listitem>
<para>
Ensure that, when you do create a new type, you specify it
clearly, and get it added to the list of known types so that
other developers can use the type correctly when writing their
elements.
</para>
</listitem>
</itemizedlist>
</para>
</partintro>
<chapter id="cha-basic-types">
<title>The basic types</title>
<para>
This is a list of the basic types used for buffers. For each type, we
give the name ("mime type") of the type, the list of properties which
are associated with the type, the meaning of each property, and the
purpose of the type.
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>audio/raw</emphasis>
- Unstructured and uncompressed raw audio data.
</para><para>
<emphasis>rate</emphasis>
- The sample rate of the data, in samples per second.
</para><para>
<emphasis>channels</emphasis>
- The number of channels of audio data.
</para><para>
<emphasis>format</emphasis>
- This describes the format in which the audio data is passed.
This is a string for which there are currently two valid values:
"int" for integer data and "float" for floating point data.
</para><para>
<emphasis>law</emphasis>
- Valid only if format=int. The law used to describe the data.
This is an integer for which there are three valid values: 0 for
linear, 1 for mu law, 2 for A law.
</para><para>
<emphasis>endianness</emphasis>
- Valid only if format=int. The order of bytes in a sample. This
is a boolean: 0 means little-endian (ie, bytes are least
significant first), 1 means big-endian (ie, most significant byte
first).
</para><para>
<emphasis>signed</emphasis>
- Valid only if format=int. Whether the samples are signed or not.
This is a boolean: 0 means unsigned, 1 means signed.
</para><para>
<emphasis>width</emphasis>
- Valid only if format=int. The number of bits per sample. This
is extremely likely to be a multiple of 8, but as ever this is up
to each element supporting this format to specify.
</para><para>
<emphasis>depth</emphasis>
- Valid only if format=int. The number of bits used per sample.
This must be less than or equal to the width: if less than the
width, the low bits are assumed to be the ones used. For example,
width=32, depth=24 means that each sample is stored in a 32 bit
word, but only the low 24 bits are actually used.
</para><para>
<emphasis>layout</emphasis>
- Valid only if format=float. A string representing the way in
which the floating point data is represented. For now, the only
valid value is gfloat, meaning that the data is passed as a series
of gfloat values.
</para><para>
<emphasis>intercept</emphasis>
- Valid only if format=float. A floating point value representing
the value that the signal "centres" on.
</para><para>
<emphasis>slope</emphasis>
- Valid only if format=float. A floating point value representing
how far the signal deviates from the intercept. So a slope of 1.0
and an intercept of 0.0 would mean an audio signal with minimum
and maximum values of -1.0 and 1.0. A slope of 0.5 and intercept
of 0.5 would represent values in the range 0.0 to 1.0.
</para>
<para>
For example: 16 bit integer, unsigned, linear, monophonic, big-endian,
44100KHz audio would be represented by
"format=int,law=0,endianness=1,signed=0,width=16,depth=16,rate=44100,channels=1"
and floating point, using gfloat's, in the range -1.0 to 1.0,
8000KHz stereo audio would be represented by
"format=float,layout=gfloat,intercept=0.0,slope=1.0,rate=8000,channels=2"
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para>
<emphasis>audio/mp3</emphasis>
- Audio data compressed using the mp3 encoding scheme.
</para><para>
<emphasis>framed</emphasis>
- This is a boolean. If true (1), each buffer contains exactly
one frame. If false (0), frames and buffers do not (necessarily)
match up. If the data is not framed, the values of some of the
properties will not be available, but others will be assumed to
be constant throughout the file, or may be found in other ways.
</para><para>
<emphasis>layer</emphasis>
- The compression scheme layer used to compress the data.
This is an integer, and can currently have the value 1, 2
or 3.
</para><para>
<emphasis>bitrate</emphasis>
- The bitrate, in kilobits per second.
For VBR (variable bitrate) mp3 data, this is the average bitrate.
</para><para>
<emphasis>channels</emphasis>
- The number of channels of audio data present. This could
theoretically be any integer greater than 0, but in practice will
be either 1 or 2.
</para><para>
<emphasis>joint-stereo</emphasis>
- Boolean. If true, channels must not be zero. If true, this
implies that stereo data is stored as a combined signal and
the difference between the signals, rather than as two entirely
separate signals.
</para><para>
There are many other properties relevant for
<emphasis>audio/mp3</emphasis> data: these may be added to this
specification at a later date.
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para>
<emphasis>audio/x-ogg</emphasis>
- Audio data compressed using the Ogg Vorbis encoding scheme.
There are currently no parameters defined for this type. FIXME.
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para>
<emphasis>video/raw</emphasis>
- Raw video data.
</para><para>
<emphasis>fourcc</emphasis>
- A FOURCC code identifying the format in which this data is
stored. FOURCC (Four Character Code) is a simple system to
allow unambiguous identification of a video datastream format.
See <ulink
url="http://www.webartz.com/fourcc/"
type="http">http://www.webartz.com/fourcc/</ulink>
</para><para>
<emphasis>width</emphasis>
- The number of pixels wide that each video frame is.
</para><para>
<emphasis>height</emphasis>
- The number of pixels high that each video frame is.
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para>
<emphasis>video/mpeg</emphasis>
- Video data compressed using an mpeg encoding scheme.
</para><para>
<emphasis>mpegversion</emphasis>
</para><para>
<emphasis>systemstream</emphasis>
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para>
<emphasis>video/avi</emphasis>
- Video data compressed using the AVI encoding scheme.
There are currently no parameters defined for this type. FIXME.
</para>
</listitem>
</itemizedlist>
</chapter>
<chapter id="cha-types-test">
<title>Building a simple format for testing</title>
<para>
</para>
</chapter>
<chapter id="cha-types-simplemime">
<title>A simple MIME type</title>
<para>
</para>
</chapter>
<chapter id="cha-types-props">
<title>Type properties</title>
<para>
</para>
</chapter>
<chapter id="cha-types-typefind">
<title>Typefind functions and autoplugging</title>
<para>
</para>
</chapter>
</part>
<!-- ############ part ############# -->
<part id="first-plugin"><title>Building our first plugin</title>
<partintro>
<para>
We are now have the neccessary concepts to build our first plugin.
We are going to build an element which has a single input pad and
a single output pad, and simply passes anything it reads on
the input pad through and out on the output pad. We will also
see where we could add code to convert this plugin into something
more useful.
</para>
<para>
The example code used in this section can be found in
<filename>examples/plugins/</filename>
</para>
</partintro>
<chapter id="cha-boilerplate">
<title>Constructing the boilerplate</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. I shall refer to these details
collectively as the <emphasis>boilerplate</emphasis>.
</para>
<sect1 id="sect-boilerplate-gobject">
<title>Doing it the hard way with GstObject</title>
<para>
The standard way of defining the boilerplate is simply to write some
code, and fill in some structures. The easiest way to do this is to
copy an example and modify according to your needs.
</para>
<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/plugins/example.h</filename>
</para>
<programlisting>
/* Definition of structure storing data for this element. */
typedef struct _GstExample GstExample;
struct _GstExample {
GstElement element;
GstPad *sinkpad,*srcpad;
gint8 active;
};
/* 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. */
GtkType gst_example_get_type(void);
</programlisting>
</sect1>
<sect1 id="sect-boilerplate-filterfactory">
<title>Doing it the easy way with FilterFactory</title>
<para>
A plan for the future is to create a FilterFactory, to make the
process of making a new filter a simple process of specifying a few
details, and writing a small amount of code to perform the actual
data processing.
</para>
<para>
Unfortunately, this hasn't yet been implemented. It is also likely
that when it is, it will not be possible to cover all the possibilities
available by writing the boilerplate yourself, so some plugins will
always need to be manually registered.
</para>
<para>
As a rough outline of what is planned: the FilterFactory will take a
list of appropriate function pointers, and data structures to define
a filter. With a reasonable measure of preprocessor magic, the
plugin writer will then simply need to provide definitions of the
functions and data structures desired, and a name for the filter, and
then call a macro from within plugin_init() which will register the
new filter. All the fluff that goes into the definition of a filter
will thus be hidden from view.
</para>
<para>
Ideally, we will come up with a way for various FilterFactory-provided
functions to be overridden, to the point where you can construct
almost the most complex stuff with it, it just saves typing.
</para>
<para>
Of course, the filter factory can be used to create sources and sinks
too: simply create a filter with only source or sink pads.
</para>
<para>
You may be thinking that this should really be called an
ElementFactory. Well, we agree, but there is already something else
justifiably ealled an ElementFactory (this is the thing which actually
makes instances of elements). There is also already something called
a PluginFactory. We just have too many factories and not enough words.
And since this isn't yet written, it doesn't get priority for claiming
a name.
</para>
</sect1>
</chapter>
<chapter id="cha-defineelt">
<title>Defining an element</title>
<para>
A new element is defined by creating an element factory. This is a
structure containing all the information needed to create an instance
of the element. Creating a factory requires two things: a type for
the element to be created
(this was defined in the boilerplate above: FIXME - reorganise),
and a GstElementDetails structure, which contains some
general information about the element to be created.
</para>
<sect1 id="sect-defineelt-eltdetails">
<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 version number of the element. For elements in the main
GStreamer source code, this will often simply be VERSION, which is
a macro defined to be the version number of the current GStreamer
version. The only requirement, however, is that the version
number should increase monotonically.
</para><para>
Version numbers should be stored in major.minor.patch form: ie, 3
(decimal) numbers, separated by ".".
</para></listitem><listitem><para>
The name of the author of the element, optionally followed by
a contact email address in angle brackets.
</para></listitem><listitem><para>
The copyright details for the element.
</para></listitem>
</itemizedlist>
<para>
For example:
</para>
<programlisting>
static GstElementDetails example_details = {
"An example plugin",
"Example/FirstExample",
"Shows the basic structure of a plugin",
VERSION,
"your name &lt;your.name@your.isp&gt;",
"(C) 2001",
};
</programlisting>
</sect1>
<sect1 id="sect-defineelt-constructors">
<title>Constructor functions</title>
<para>
Each element has two functions which are used for construction of
an element. These are the _class_init() function, which is used to
initialise the class (specifying what signals and arguments the class
has and setting up global state), and the _init() function, which
is used to initialise a specific instance of the class.
</para>
</sect1>
<sect1 id="sect-defineelt-pads">
<title>Specifying the pads</title>
<para>
</para>
</sect1>
<sect1 id="sect-defineelt-fns">
<title>Attaching functions</title>
<para>
</para>
</sect1>
<sect1 id="sect-defineelt-chainfn">
<title>The chain function</title>
<para>
</para>
</sect1>
<sect1 id="sect-defineelt-arguments">
<title>Adding arguments</title>
<para>
Define arguments in enum.
</para>
</sect1>
<sect1 id="sect-defineelt-signals">
<title>Signals</title>
<para>
Define signals in enum.
</para>
</sect1>
</chapter>
<chapter id="cha-definetype">
<title>Defining a type</title>
<para>
A new type is defined by creating an type factory. This is a
structure containing all the information needed to create an instance
of the type.
</para>
</chapter>
<chapter id="cha-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
must return a pointer to a newly allocated GstPlugin structure.
This structure contains the details of all the facilities provided
by the plugin, and is the mechanism by which the definitions are
made available to the rest of the &GStreamer; system. Helper
functions are provided to help fill the
structure: for future compatability it is recommended that these
functions are used, as documented below, rather than attempting to
access the structure directly.
</para>
<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 id="sect-plugininit-types">
<title>Registering new types</title>
<para>
</para>
<programlisting>
void gst_plugin_add_type(GstPlugin *plugin,
GstTypeFactory *factory);
</programlisting>
<para>
</para>
</sect1>
<sect1 id="sect-plugininit-filter">
<title>Registering new element factories</title>
<para>
</para>
<programlisting>
void gst_plugin_add_factory(GstPlugin *plugin,
GstElementFactory *factory);
</programlisting>
<para>
Multiple element factories can be provided by a single plugin:
all it needs to do is call gst_plugin_add_factory() for each
element factory it wishes to provide.
</para>
</sect1>
<sect1 id="sect-plugininit-autopluggers">
<title>Registering new autopluggers</title>
<para>
</para>
<programlisting>
void gst_plugin_add_autoplugger(GstPlugin *plugin,
GstAutoplugFactory *factory);
</programlisting>
</sect1>
</chapter>
</part>
<!-- ############ part ############# -->
<part id="dparams"><title>Supporting Dynamic Parameters</title>
<partintro>
<para>
Sometimes object properties are not powerful enough to control the
parameters that affect the behaviour of your element. When this is
the case you can expose these parameters as Dynamic Parameters
which can be manipulated by any Dynamic Parameters aware application.
</para>
<para>
Throughout this section, the term dparams will be used as an abbreviation for Dynamic Parameters.
</para>
</partintro>
<sect2 id="sect-dparams-compare">
<title>Comparing Dynamic Parameters with GObject Properties</title>
<para>
Your first exposure to dparams may be to convert an existing element from
using object properties to using dparams. The following table gives an overview
of the difference between these approaches. The significance of these
differences should become apparent later on.
</para>
<informaltable frame="all">
<tgroup cols="3">
<thead>
<row>
<entry></entry>
<entry>Object Properties</entry>
<entry>Dynamic Parameters</entry>
</row>
</thead>
<tbody>
<row>
<entry><emphasis>Parameter definition</emphasis></entry>
<entry>Class level at compile time</entry>
<entry>Any level at run time</entry>
</row>
<row>
<entry><emphasis>Getting and setting</emphasis></entry>
<entry>Implemented by element subclass as functions</entry>
<entry>Handled entirely by dparams subsystem</entry>
</row>
<row>
<entry><emphasis>Extra objects required</emphasis></entry>
<entry>None - all functionality is derived from base GObject</entry>
<entry>Element needs to create and store a <filename>GstDParamManager</filename> at object creation</entry>
</row>
<row>
<entry><emphasis>Frequency and resolution of updates</emphasis></entry>
<entry>Object properties will only be updated between calls to _get, _chain or _loop</entry>
<entry>dparams can be updated at any rate independant of calls to _get, _chain or _loop
up to sample-level accuracy</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect2>
&DPARAMS;
</part>
<!-- ############ part ############# -->
<part id="test-app"><title>Building a simple test application</title>
<partintro>
<para>
</para>
</partintro>
&TESTAPP;
</part>
<!-- ############ part ############# -->
<part id="loopbased"><title>Loop-based Elements</title>
<partintro>
<para>
</para>
</partintro>
&LOOPBASED;
</part>
<!-- ############ part ############# -->
<part id="buffersnmeta"><title>Buffers and Metadata</title>
<partintro>
<para>
</para>
</partintro>
&BUFFERS;
</part>
<!-- ############ part ############# -->
<part id="srcnsink"><title>Sources and Sinks</title>
<partintro>
<para>
</para>
</partintro>
&SRCNSINK;
</part>
<!-- ############ part ############# -->
<part id="statemanage"><title>State management</title>
<partintro>
<para>
</para>
</partintro>
&STATEMANAGE;
</part>
<!-- ############ part ############# -->
<part id="checklist"><title>Checklist</title>
<partintro>
<para>
</para>
</partintro>
&CHECKLIST;
</part>
</book>

View file

@ -1,173 +0,0 @@
<chapter id="cha-doicare">
<title>Do I care?</title>
<para>
This guide explains how to write new modules for GStreamer. It is
relevant to:
</para>
<itemizedlist>
<listitem>
<para>
Anyone who wants to add support for new input and output
devices, often called sources and sinks. For example,
adding the ability to write to a new video output system
could be done by writing an appropriate sink plugin.
</para>
</listitem>
<listitem>
<para>
Anyone who wants to add support for new ways of processing
data in GStreamer, often called
filters. For example, a new data format converter could be
created.
</para>
</listitem>
<listitem>
<para>
Anyone who wants to extend GStreamer in
any way: you need to have an understanding of how the plugin system
works before you can understand the constraints it places on the
rest of the code. And you might be surprised at how much can be
done with plugins.
</para>
</listitem>
</itemizedlist>
<para>
This guide is not relevant to you if you only want to use the existing
functionality of GStreamer, or use an application which uses GStreamer.
You lot can go away. Shoo... (You might find the <emphasis>GStreamer
Application Development Manual</emphasis> helpful though.)
</para>
</chapter>
<chapter id="cha-prelimreading">
<title>Preliminary reading</title>
<para>
The reader should be familiar with the basic workings of
<application>GStreamer</application>. For a gentle introduction to
GStreamer, you may wish to read the <emphasis>GStreamer Application
Development Manual</emphasis>. Since <application>GStreamer</application>
adheres to the GObject programming model, the reader is also assumed to
understand the basics of GObject.
</para>
</chapter>
<chapter id="cha-structure">
<title>Structure of this guide</title>
<para>
The <application>GStreamer</application> API for developing plugins is
rather extensive and powerful. We will first try to get you up and running
with a simple plugin as fast as possible. We will then gradually add more
features to our example plugin. The basic topics will be:
</para>
<itemizedlist>
<listitem>
<para>
Short overview of the GStreamer concepts. People familiar with the
<emphasis>GStreamer Application Development Manual</emphasis> can use
this short overview to refresh their memory.
</para>
</listitem>
<listitem>
<para>
Introduction to the basic structure of the plugin. We will cover all the
different steps you have to perform in order to build a plugin. This will
include a general overview of the structure of your source files.
</para>
</listitem>
<listitem>
<para>
Creating the plugin boilerplate. We will show you how to define and set up
the different aspects for creating a plugin. This will cover extending the
GstElement class and creating the elementfactory structures. This will include
setting up the .h and .c files of your plugin.
</para>
</listitem>
<listitem>
<para>
Defining the entry point of the plugin and registering the elementfactory.
After this step your plugin will become available for application programmers.
</para>
</listitem>
<listitem>
<para>
Setting up the basic components of the element like adding pads and setting
up the scheduling entry points of your plugin.
</para>
</listitem>
<listitem>
<para>
Adding arguments and signals to the plugin. Users of your plugin will be
able to listen for specific events your plugin generates as well as change and
adjust the different properties of your plugin.
</para>
</listitem>
<listitem>
<para>
Compiling and testing the basic plugin.
</para>
</listitem>
</itemizedlist>
<para>
After this first section, you should be able to create a simple plugin. We will then
introduce the more advanced concepts of plugins, including:
</para>
<itemizedlist>
<listitem>
<para>
Adding padtemplates to the plugin. This will allow your plugin to become fully
integrated in the GStreamer plugin registry and will allow users of your plugin
to know what media types your plugin operates on.
</para>
</listitem>
<listitem>
<para>
Adding new mime-types to the registry along with typedetect functions. This will allow
your plugin to operate on a completely new media type.
</para>
</listitem>
<listitem>
<para>
Adding caps to the plugins input pads. This will allow other plugins to know what
media type your plugin is handling at runtime.
</para>
</listitem>
<listitem>
<para>
Choosing between a loop-based or a chain-based plugin. We will teach you how to
create plugins with a more complicated input/output behaviour.
</para>
</listitem>
<listitem>
<para>
Adding request pads to the plugin. Request pads allow the application programmer
to let your plugin dynamically create a pad based on a template.
</para>
</listitem>
<listitem>
<para>
Caps negotiation will show you how your plugin can addapt to the plugins it
is connected to.
</para>
</listitem>
<listitem>
<para>
Creating compound and complex elements by extending from a GstBin. This will
allow you to create plugins that have other plugins embedded in them.
</para>
</listitem>
<listitem>
<para>
Creating custom schedulers when the default schedulers are insufficient.
</para>
</listitem>
<listitem>
<para>
Creating custom autopluggers when the default ones are insufficient for your needs.
</para>
</listitem>
</itemizedlist>
<para>
As you can see, there a lot to learn, so let's get started...
</para>
</chapter>

View file

@ -1,27 +0,0 @@
<chapter id="cha-loopbased-sched">
<title>How scheduling works</title>
<para>
aka pushing and pulling
</para>
</chapter>
<chapter id="cha-loopbased-loopfn">
<title>How a loopfunc works</title>
<para>
aka pulling and pushing
</para>
</chapter>
<chapter id="cha-loopbased-secnd">
<title>Adding a second output</title>
<para>
Identity is now a tee
</para>
</chapter>
<chapter id="cha-loopbased-modappl">
<title>Modifying the test application</title>
<para>
</para>
</chapter>

View file

@ -1 +0,0 @@
<!ENTITY magic "pdf">

View file

@ -1 +0,0 @@
<!ENTITY magic "png">

View file

@ -1,16 +0,0 @@
<chapter id="cha-srcnsink-writesrc">
<title>
Writing a source
</title>
<para>
Pull vs loop based
Region pulling
</para>
</chapter>
<chapter id="cha-srcnsink-writesink">
<title>
Writing a sink
</title>
<para>
</para>
</chapter>

View file

@ -1,14 +0,0 @@
<chapter id="cha-statemanage-states">
<title>
What are states?
</title>
<para>
</para>
</chapter>
<chapter id="cha-statemanage-filters">
<title>
Mangaging filter state
</title>
<para>
</para>
</chapter>

View file

@ -1,25 +0,0 @@
<chapter id="cha-testapp-init">
<title>Initialization</title>
<para>
</para>
</chapter>
<chapter id="cha-testapp-inst">
<title>Instantiating the plugins</title>
<para>
(NOTE: we really should have a debugging Sink)
</para>
</chapter>
<chapter id="cha-testapp-connect">
<title>Connecting the plugins</title>
<para>
</para>
</chapter>
<chapter id="cha-testapp-running">
<title>Running the pipeline</title>
<para>
</para>
</chapter>

View file

@ -1,48 +0,0 @@
<bookinfo>
<authorgroup>
<author>
<firstname>Richard</firstname>
<othername>John</othername>
<surname>Boulton</surname>
<authorblurb>
<para>
<email>richard-gst@tartarus.org</email>
</para>
</authorblurb>
</author>
<author>
<firstname>Erik</firstname>
<surname>Walthinsen</surname>
<authorblurb>
<para>
<email>omega@temple-baptist.com</email>
</para>
</authorblurb>
</author>
<author>
<firstname>Steve</firstname>
<surname>Baker</surname>
<authorblurb>
<para>
<email>stevebaker_org@yahoo.co.uk</email>
</para>
</authorblurb>
</author>
</authorgroup>
<legalnotice id="legalnotice">
<para>
This material may be distributed only subject to the terms and
conditions set forth in the Open Publication License, v1.0 or
later (the latest version is presently available at <ulink
url="http://www.opencontent.org/openpub/"
type="http">http://www.opencontent.org/openpub/"</ulink> )
</para>
</legalnotice>
<title><application>GStreamer</application> Plugin Writer's Guide</title>
</bookinfo>