gstreamer/docs/pwg/advanced-dparams.xml
Stefan Kost dad303a342 docs/: more dparam docs
Original commit message from CVS:
* docs/manual/advanced-dparams.xml:
* docs/pwg/advanced-dparams.xml:
more dparam docs
* gst/gstindex.c:
fix docs
* libs/gst/controller/lib.c: (gst_controller_init):
init just once
2006-01-31 16:56:28 +00:00

224 lines
8.6 KiB
XML

<!-- ############ chapter ############# -->
<chapter id="chapter-dparams">
<title>Supporting Dynamic Parameters</title>
<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 mark these parameters as beeing Controllable.
Aware appliations can use the controller subsystem to dynamically adjust
the property values over time.
</para>
<sect1 id="section-dparam-start">
<title>Getting Started</title>
<para>
The controller subsystem is contained within the
<filename>gstcontroller</filename> library. You need to include the header in
your element's source file:
</para>
<programlisting>
...
#include &lt;gst/gst.h&gt;
#include &lt;gst/controller/gstcontroller.h&gt;
...
</programlisting>
<para>
Even though the <filename>gstcontroller</filename> library may be linked into
the host application, you should make sure it is initialized in your
<filename>plugin_init</filename> function:
</para>
<programlisting>
static gboolean
plugin_init (GstPlugin *plugin)
{
...
/* initialize library */
gst_controller_init (NULL, NULL);
...
}
</programlisting>
<para>
It makes not sense for all GObject parameter to be real-time controlled.
Therefore the next step is to mark controllable parameters.
This is done by using the special flag <constant>GST_PARAM_CONTROLLABLE</constant>.
when setting up GObject params in the <function>_class_init</function> method.
</para>
<programlisting>
g_object_class_install_property (gobject_class, PROP_FREQ,
g_param_spec_double ("freq", "Frequency", "Frequency of test signal",
0.0, 20000.0, 440.0,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
</programlisting>
</sect1>
<sect1 id="chapter-dparam-loop">
<title>The Data Processing Loop</title>
<!-- FIXME -->
<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>
<para>
Update any dparams which are due to be updated.
</para>
</listitem>
<listitem>
<para>
Calculate how many samples should be processed before the next required
update
</para>
</listitem>
<listitem>
<para>
Return the number of samples until next update, or the number of samples
in the buffer - whichever is less.
</para>
</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="section-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>
<para>
<emphasis>Timelined</emphasis> - all parameter changes are known in
advance before the pipeline is run.
</para>
</listitem>
<listitem>
<para>
<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.
</para>
</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="section-dparam-audio-video">
<title>Dynamic Parameters for Video</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>
</sect1>
</chapter>