mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-18 21:35:44 +00:00
pwg: improve negotiation documentation some more
This commit is contained in:
parent
af99d9f5e1
commit
bbcdafa05f
1 changed files with 106 additions and 145 deletions
|
@ -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
|
||||
</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.
|
||||
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>
|
||||
<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.
|
||||
A typical flow goes like this:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<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.
|
||||
Caps are received on the sink pad of the element.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<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.
|
||||
If the element prefers to operate in passthrough mode, check
|
||||
if downstream accepts the caps with the ACCEPT_CAPS query.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<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.
|
||||
Calculate the possible caps for the source pad.
|
||||
</para>
|
||||
</sect1>
|
||||
-->
|
||||
|
||||
<sect1 id="section-nego-downstream" xreflabel="Downstream caps negotiation">
|
||||
<title>Downstream caps negotiation</title>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<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.
|
||||
Query the downstream peer pad for the list of possible
|
||||
caps.
|
||||
</para>
|
||||
|
||||
<sect2 id="section-nego-downstream-embed"
|
||||
xreflabel="Negotiating caps embedded in input caps">
|
||||
<title>Negotiating caps embedded in input caps</title>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<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.
|
||||
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->sinkpad, caps)) {
|
||||
filter->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", &filter->channels);
|
||||
othercaps = gst_pad_get_allowed_caps (filter->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->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->srcpad, newcaps);
|
||||
if (!gst_pad_set_caps (filter->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->passthrough = FALSE;
|
||||
gst_structure_get_int (s, "rate", &filter->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", &filter->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, &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->passthrough)
|
||||
return gst_pad_push (filter->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->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>
|
||||
|
|
Loading…
Reference in a new issue