mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
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:
parent
ebda7d920a
commit
cc5f591c17
15 changed files with 0 additions and 1631 deletions
13
docs/fwg/.gitignore
vendored
13
docs/fwg/.gitignore
vendored
|
@ -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
|
|
|
@ -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
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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 <gst/control/control.h>
|
|
||||||
</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->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>&(example->volume)</filename>.
|
|
||||||
</para>
|
|
||||||
<programlisting>
|
|
||||||
gst_dpman_add_required_dparam_direct (
|
|
||||||
example->dpman,
|
|
||||||
g_param_spec_float("volume","Volume","Volume of the audio",
|
|
||||||
0.0, 1.0, 0.8, G_PARAM_READWRITE),
|
|
||||||
FALSE,
|
|
||||||
FALSE,
|
|
||||||
&(example->volume)
|
|
||||||
);
|
|
||||||
</programlisting>
|
|
||||||
<para>
|
|
||||||
You can now use <filename>example->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->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->volume_f = g_value_get_float(value);
|
|
||||||
example->volume_i = example->volume_f * 8192;
|
|
||||||
}
|
|
||||||
</programlisting>
|
|
||||||
<para>
|
|
||||||
Now <filename>example->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 < num_samples; j++) {
|
|
||||||
float_data[j] *= example->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->dpman, num_samples, GST_BUFFER_TIMESTAMP(buf));
|
|
||||||
...
|
|
||||||
while (GST_DPMAN_PROCESS_COUNTDOWN(example->dpman, frame_countdown, j)) {
|
|
||||||
float_data[j++] *= example->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>
|
|
|
@ -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 <your.name@your.isp>",
|
|
||||||
"(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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<!ENTITY magic "pdf">
|
|
|
@ -1 +0,0 @@
|
||||||
<!ENTITY magic "png">
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
||||||
|
|
|
@ -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>
|
|
Loading…
Reference in a new issue