pwg: improve negotiation documentation some more

This commit is contained in:
Wim Taymans 2012-10-15 13:44:51 +02:00
parent af99d9f5e1
commit bbcdafa05f

View file

@ -296,161 +296,102 @@ gst_my_filter_sink_event (GstPad *pad,
Like with the transform negotiation in
<xref linkend="section-nego-transform"/>, dynamic negotiation will
perform a transformation on the downstream/upstream caps. Unlike the
transform
negotiation, this transform will convert fixed caps to unfixed caps. This
means that the sink pad input caps can be converted into unfixed (multiple)
formats. The source pad will have to choose a format from all the
possibilities. It would usually like to choose a format that requires the
least amount of effort to produce but it does not have to be. The selection
of the format should also depend on the caps that can be accepted downstream
transform negotiation, this transform will convert fixed caps to
unfixed caps. This means that the sink pad input caps can be converted
into unfixed (multiple) formats. The source pad will have to choose a
format from all the possibilities. It would usually like to choose a
format that requires the least amount of effort to produce but it does
not have to be. The selection of the format should also depend on the
caps that can be accepted downstream (see a QUERY_CAPS function in
<xref linkend="section-nego-getcaps"/>).
</para>
</sect2>
</sect1>
<sect1 id="section-nego-pullmode">
<title>Pull-mode Caps negotiation</title>
<para>
</para>
</sect1>
<!--
<sect1 id="section-nego-old">
<title>Old stuff</title>
<para>
Let's take the case of a file source, linked to a demuxer, linked to a
decoder, linked to a converter with a caps filter and finally an audio
output. When data flow originally starts, the demuxer will parse the
file header (e.g. the Ogg headers), and notice that there is, for
example, a Vorbis stream in this Ogg file. Noticing that, it will
create an output pad for the Vorbis elementary stream and set a
Vorbis-caps on it. Lastly, it adds the pad. As of this point, the pad
is ready to be used to stream data, and so the Ogg demuxer is now done.
This pad is <emphasis>not</emphasis> re-negotiable, since the type of
the data stream is embedded within the data.
</para>
<para>
The Vorbis decoder will decode the Vorbis headers and the Vorbis data
coming in on its sinkpad. Now, some decoders may be able to output in
multiple output formats, for example both 16-bit integer output and
floating-point output, whereas other decoders may be able to only decode
into one specific format, e.g. only floating-point (32-bit) audio. Those
two cases have consequences for how caps negotiation should be
implemented in this decoder element. In the one case, it is possible to
use fixed caps, and you're done. In the other case, however, you should
implement the possibility for <emphasis>renegotiation</emphasis> in this
element, which is the possibility for the data format to be changed to
another format at some point in the future. We will discuss how to do
this in one of the sections further on in this chapter.
</para>
<para>
The filter can be used by applications to force, for example, a specific
channel configuration (5.1/surround or 2.0/stereo), on the pipeline, so
that the user can enjoy sound coming from all its speakers. The audio
sink, in this example, is a standard ALSA output element (alsasink).
The converter element supports any-to-any, and the filter will make sure
that only a specifically wanted channel configuration streams through
this link (as provided by the user's channel configuration preference).
By changing this preference while the pipeline is running, some elements
will have to renegotiate <emphasis>while the pipeline is
running</emphasis>. This is done through upstream caps renegotiation.
That, too, will be discussed in detail in a section further below.
</para>
<para>
In order for caps negotiation on non-fixed links to work correctly,
pads can optionally implement a query function that tells peer elements
what formats it supports and/or prefers. When upstream renegotiation is
triggered, this becomes important.
</para>
<para>
Downstream elements are notified of a newly set caps with a
GST_EVENT_CAPS on the sinkpad. So when the vorbis decoder sets a caps on
its source pad (to configure the output format), the converter will
receive a caps event.
When an element receives a buffer, it should check if it has received
all needed format information in a CAPS event previously. If it hasn't,
it should return an error from the chain function.
</para>
</sect1>
-->
<sect1 id="section-nego-downstream" xreflabel="Downstream caps negotiation">
<title>Downstream caps negotiation</title>
<para>
Downstream negotiation takes place when a format needs to be set on a
source pad to configure the output format, but this element allows
renegotiation because its format is configured on the sinkpad caps,
or because it supports multiple formats. The requirements for doing
the actual negotiation differ slightly.
</para>
<sect2 id="section-nego-downstream-embed"
xreflabel="Negotiating caps embedded in input caps">
<title>Negotiating caps embedded in input caps</title>
<para>
There may also be cases where the filter actually is able to
<emphasis>change</emphasis> the format of the stream. In those cases,
it will negotiate a new format. Obviously, the element should first
attempt to configure <quote>pass-through</quote>, which means that
it does not change the stream's format. However, if that fails,
then it should call <function>gst_pad_get_allowed_caps ()</function>
on its sourcepad to get a list of supported formats on the outputs,
and pick the first. The return value of that function is guaranteed
to be a subset of the template caps or NULL when there is no peer.
A typical flow goes like this:
</para>
<itemizedlist>
<listitem>
<para>
Caps are received on the sink pad of the element.
</para>
</listitem>
<listitem>
<para>
If the element prefers to operate in passthrough mode, check
if downstream accepts the caps with the ACCEPT_CAPS query.
</para>
</listitem>
<listitem>
<para>
Calculate the possible caps for the source pad.
</para>
</listitem>
<listitem>
<para>
Query the downstream peer pad for the list of possible
caps.
</para>
</listitem>
<listitem>
<para>
Select from the downstream list the first caps that you can
transform to and set this as the output caps.
</para>
</listitem>
</itemizedlist>
<para>
Examples of this type of elements include:
</para>
<itemizedlist>
<listitem>
<para>
Converter elements such as videoconvert, audioconvert, audioresample,
videoscale, ...
</para>
</listitem>
<listitem>
<para>
Source elements such as audiotestsrc, videotestsrc, v4l2src,
pulsesrc, ...
</para>
</listitem>
</itemizedlist>
<para>
Let's look at the example of an element that can convert between
samplerates, so where input and output samplerate don't have to be
the same:
</para>
<programlisting><!-- example-begin convertcaps.c a --><!--
#include "init.func"
static GstCaps *
gst_my_filter_getcaps (GstPad * pad)
{
return NULL;
}
static GstBuffer *
gst_my_filter_convert (GstMyFilter *filter, GstBuffer *in)
{
return NULL;
}
static gboolean
gst_my_filter_event (GstPad * pad, GstEvent * event)
{
return gst_pad_event_default (pad, event);
}
--><!-- example-end convertcaps.c a -->
<!-- example-begin convertcaps.c b -->
<programlisting>
<![CDATA[
static gboolean
gst_my_filter_setcaps (GstMyFilter *filter,
GstCaps *caps)
{
if (gst_pad_set_caps (filter-&gt;sinkpad, caps)) {
filter-&gt;passthrough = TRUE;
if (gst_pad_set_caps (filter->sinkpad, caps)) {
filter->passthrough = TRUE;
} else {
GstCaps *othercaps, *newcaps;
GstStructure *s = gst_caps_get_structure (caps, 0), *others;
/* no passthrough, setup internal conversion */
gst_structure_get_int (s, "channels", &amp;filter-&gt;channels);
othercaps = gst_pad_get_allowed_caps (filter-&gt;srcpad);
gst_structure_get_int (s, "channels", &filter->channels);
othercaps = gst_pad_get_allowed_caps (filter->srcpad);
others = gst_caps_get_structure (othercaps, 0);
gst_structure_set (others,
"channels", G_TYPE_INT, filter-&gt;channels, NULL);
"channels", G_TYPE_INT, filter->channels, NULL);
/* now, the samplerate value can optionally have multiple values, so
* we "fixate" it, which means that one fixed value is chosen */
newcaps = gst_caps_copy_nth (othercaps, 0);
gst_caps_unref (othercaps);
gst_pad_fixate_caps (filter-&gt;srcpad, newcaps);
if (!gst_pad_set_caps (filter-&gt;srcpad, newcaps))
gst_pad_fixate_caps (filter->srcpad, newcaps);
if (!gst_pad_set_caps (filter->srcpad, newcaps))
return FALSE;
/* we are now set up, configure internally */
filter-&gt;passthrough = FALSE;
gst_structure_get_int (s, "rate", &amp;filter-&gt;from_samplerate);
filter->passthrough = FALSE;
gst_structure_get_int (s, "rate", &filter->from_samplerate);
others = gst_caps_get_structure (newcaps, 0);
gst_structure_get_int (others, "rate", &amp;filter-&gt;to_samplerate);
gst_structure_get_int (others, "rate", &filter->to_samplerate);
}
return TRUE;
@ -469,7 +410,7 @@ gst_my_filter_sink_event (GstPad *pad,
{
GstCaps *caps;
gst_event_parse_caps (event, &amp;caps);
gst_event_parse_caps (event, &caps);
ret = gst_my_filter_setcaps (filter, caps);
break;
}
@ -489,23 +430,26 @@ gst_my_filter_chain (GstPad *pad,
GstBuffer *out;
/* push on if in passthrough mode */
if (filter-&gt;passthrough)
return gst_pad_push (filter-&gt;srcpad, buf);
if (filter->passthrough)
return gst_pad_push (filter->srcpad, buf);
/* convert, push */
out = gst_my_filter_convert (filter, buf);
gst_buffer_unref (buf);
return gst_pad_push (filter-&gt;srcpad, out);
return gst_pad_push (filter->srcpad, out);
}
<!-- example-end convertcaps.c b -->
<!-- example-begin convertcaps.c c --><!--
#include "state.func"
#include "register.func"
--><!-- example-end convertcaps.c c --></programlisting>
]]>
</programlisting>
</sect2>
</sect1>
<sect1 id="section-nego-pullmode">
<title>Pull-mode Caps negotiation</title>
<para>
</para>
</sect1>
<sect1 id="section-nego-upstream" xreflabel="Upstream caps (re)negotiation">
<title>Upstream caps (re)negotiation</title>
<para>
@ -532,19 +476,36 @@ gst_my_filter_chain (GstPad *pad,
<itemizedlist>
<listitem>
<para>
Elements that can be reconfigured on the srcpad should check its
NEED_RECONFIGURE flag with
<function>gst_pad_check_reconfigure ()</function> and it should
start renegotiation when the function returns TRUE.
Elements that want to propose a new format upstream need to first
check if the new caps are acceptable upstream with an ACCEPT_CAPS
query. Then they would send a RECONFIGURE event and be prepared to
answer the CAPS query with the new prefered format. It should be
noted that when there is no upstream element that can (or wants)
to renegotiate, the element needs to deal with the currently
configured format.
</para>
</listitem>
<listitem>
<para>
Elements that want to propose a new format upstream need to send
a RECONFIGURE event and be prepared to answer the CAPS query with
the new prefered format. It should be noted that when there is no
upstream element that can (or wants) to renegotiate, the element
needs to deal with the currently configured format.
Elements that operate in transform negotiation according to
<xref linkend="section-nego-transform"/> pass the RECONFIGURE
event upstream.
</para>
</listitem>
<listitem>
<para>
Elements that operate in fixed negotiation
(<xref linkend="section-nego-fixed"/>) drop the RECONFIGURE event.
</para>
</listitem>
<listitem>
<para>
Elements that can be reconfigured on the source pad (source pads
implementing dynamic negotiation in
<xref linkend="section-nego-dynamic"/>) should check its
NEED_RECONFIGURE flag with
<function>gst_pad_check_reconfigure ()</function> and it should
start renegotiation when the function returns TRUE.
</para>
</listitem>
</itemizedlist>