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 Like with the transform negotiation in
<xref linkend="section-nego-transform"/>, dynamic negotiation will <xref linkend="section-nego-transform"/>, dynamic negotiation will
perform a transformation on the downstream/upstream caps. Unlike the perform a transformation on the downstream/upstream caps. Unlike the
transform transform negotiation, this transform will convert fixed caps to
negotiation, this transform will convert fixed caps to unfixed caps. This unfixed caps. This means that the sink pad input caps can be converted
means that the sink pad input caps can be converted into unfixed (multiple) into unfixed (multiple) formats. The source pad will have to choose a
formats. The source pad will have to choose a format from all the format from all the possibilities. It would usually like to choose a
possibilities. It would usually like to choose a format that requires the format that requires the least amount of effort to produce but it does
least amount of effort to produce but it does not have to be. The selection not have to be. The selection of the format should also depend on the
of the format should also depend on the caps that can be accepted downstream caps that can be accepted downstream (see a QUERY_CAPS function in
</para> <xref linkend="section-nego-getcaps"/>).
</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>
<para> <para>
The Vorbis decoder will decode the Vorbis headers and the Vorbis data A typical flow goes like this:
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>
<itemizedlist>
<listitem>
<para> <para>
The filter can be used by applications to force, for example, a specific Caps are received on the sink pad of the element.
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>
</listitem>
<listitem>
<para> <para>
In order for caps negotiation on non-fixed links to work correctly, If the element prefers to operate in passthrough mode, check
pads can optionally implement a query function that tells peer elements if downstream accepts the caps with the ACCEPT_CAPS query.
what formats it supports and/or prefers. When upstream renegotiation is
triggered, this becomes important.
</para> </para>
</listitem>
<listitem>
<para> <para>
Downstream elements are notified of a newly set caps with a Calculate the possible caps for the source pad.
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> </para>
</sect1> </listitem>
--> <listitem>
<sect1 id="section-nego-downstream" xreflabel="Downstream caps negotiation">
<title>Downstream caps negotiation</title>
<para> <para>
Downstream negotiation takes place when a format needs to be set on a Query the downstream peer pad for the list of possible
source pad to configure the output format, but this element allows caps.
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> </para>
</listitem>
<sect2 id="section-nego-downstream-embed" <listitem>
xreflabel="Negotiating caps embedded in input caps">
<title>Negotiating caps embedded in input caps</title>
<para> <para>
There may also be cases where the filter actually is able to Select from the downstream list the first caps that you can
<emphasis>change</emphasis> the format of the stream. In those cases, transform to and set this as the output caps.
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.
</para> </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> <para>
Let's look at the example of an element that can convert between 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 samplerates, so where input and output samplerate don't have to be
the same: the same:
</para> </para>
<programlisting><!-- example-begin convertcaps.c a --><!-- <programlisting>
#include "init.func" <![CDATA[
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 -->
static gboolean static gboolean
gst_my_filter_setcaps (GstMyFilter *filter, gst_my_filter_setcaps (GstMyFilter *filter,
GstCaps *caps) GstCaps *caps)
{ {
if (gst_pad_set_caps (filter-&gt;sinkpad, caps)) { if (gst_pad_set_caps (filter->sinkpad, caps)) {
filter-&gt;passthrough = TRUE; filter->passthrough = TRUE;
} else { } else {
GstCaps *othercaps, *newcaps; GstCaps *othercaps, *newcaps;
GstStructure *s = gst_caps_get_structure (caps, 0), *others; GstStructure *s = gst_caps_get_structure (caps, 0), *others;
/* no passthrough, setup internal conversion */ /* no passthrough, setup internal conversion */
gst_structure_get_int (s, "channels", &amp;filter-&gt;channels); gst_structure_get_int (s, "channels", &filter->channels);
othercaps = gst_pad_get_allowed_caps (filter-&gt;srcpad); othercaps = gst_pad_get_allowed_caps (filter->srcpad);
others = gst_caps_get_structure (othercaps, 0); others = gst_caps_get_structure (othercaps, 0);
gst_structure_set (others, 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 /* now, the samplerate value can optionally have multiple values, so
* we "fixate" it, which means that one fixed value is chosen */ * we "fixate" it, which means that one fixed value is chosen */
newcaps = gst_caps_copy_nth (othercaps, 0); newcaps = gst_caps_copy_nth (othercaps, 0);
gst_caps_unref (othercaps); gst_caps_unref (othercaps);
gst_pad_fixate_caps (filter-&gt;srcpad, newcaps); gst_pad_fixate_caps (filter->srcpad, newcaps);
if (!gst_pad_set_caps (filter-&gt;srcpad, newcaps)) if (!gst_pad_set_caps (filter->srcpad, newcaps))
return FALSE; return FALSE;
/* we are now set up, configure internally */ /* we are now set up, configure internally */
filter-&gt;passthrough = FALSE; filter->passthrough = FALSE;
gst_structure_get_int (s, "rate", &amp;filter-&gt;from_samplerate); gst_structure_get_int (s, "rate", &filter->from_samplerate);
others = gst_caps_get_structure (newcaps, 0); 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; return TRUE;
@ -469,7 +410,7 @@ gst_my_filter_sink_event (GstPad *pad,
{ {
GstCaps *caps; GstCaps *caps;
gst_event_parse_caps (event, &amp;caps); gst_event_parse_caps (event, &caps);
ret = gst_my_filter_setcaps (filter, caps); ret = gst_my_filter_setcaps (filter, caps);
break; break;
} }
@ -489,23 +430,26 @@ gst_my_filter_chain (GstPad *pad,
GstBuffer *out; GstBuffer *out;
/* push on if in passthrough mode */ /* push on if in passthrough mode */
if (filter-&gt;passthrough) if (filter->passthrough)
return gst_pad_push (filter-&gt;srcpad, buf); return gst_pad_push (filter->srcpad, buf);
/* convert, push */ /* convert, push */
out = gst_my_filter_convert (filter, buf); out = gst_my_filter_convert (filter, buf);
gst_buffer_unref (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 --><!-- </programlisting>
#include "state.func"
#include "register.func"
--><!-- example-end convertcaps.c c --></programlisting>
</sect2> </sect2>
</sect1> </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"> <sect1 id="section-nego-upstream" xreflabel="Upstream caps (re)negotiation">
<title>Upstream caps (re)negotiation</title> <title>Upstream caps (re)negotiation</title>
<para> <para>
@ -532,19 +476,36 @@ gst_my_filter_chain (GstPad *pad,
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
Elements that can be reconfigured on the srcpad should check its Elements that want to propose a new format upstream need to first
NEED_RECONFIGURE flag with check if the new caps are acceptable upstream with an ACCEPT_CAPS
<function>gst_pad_check_reconfigure ()</function> and it should query. Then they would send a RECONFIGURE event and be prepared to
start renegotiation when the function returns TRUE. 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> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Elements that want to propose a new format upstream need to send Elements that operate in transform negotiation according to
a RECONFIGURE event and be prepared to answer the CAPS query with <xref linkend="section-nego-transform"/> pass the RECONFIGURE
the new prefered format. It should be noted that when there is no event upstream.
upstream element that can (or wants) to renegotiate, the element </para>
needs to deal with the currently configured format. </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> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>