Add a chapter on caps negotiation, simplify the original code samples a bit w.r.t. caps negotiation, add link to the ...

Original commit message from CVS:
* docs/pwg/advanced-negotiation.xml:
* docs/pwg/building-boiler.xml:
* docs/pwg/building-pads.xml:
* docs/pwg/pwg.xml:
* examples/pwg/Makefile.am:
Add a chapter on caps negotiation, simplify the original code
samples a bit w.r.t. caps negotiation, add link to the advanced
section. Add a bunch of examples showing different use cases of
different types of caps negotiation. Upstream renegotiation isn't
fully documented yet since nobody knows how that works.
This commit is contained in:
Ronald S. Bultje 2005-07-06 12:18:00 +00:00
parent 2953b3174e
commit a13be0a71e
7 changed files with 526 additions and 87 deletions

View file

@ -1,3 +1,16 @@
2005-07-06 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* docs/pwg/advanced-negotiation.xml:
* docs/pwg/building-boiler.xml:
* docs/pwg/building-pads.xml:
* docs/pwg/pwg.xml:
* examples/pwg/Makefile.am:
Add a chapter on caps negotiation, simplify the original code
samples a bit w.r.t. caps negotiation, add link to the advanced
section. Add a bunch of examples showing different use cases of
different types of caps negotiation. Upstream renegotiation isn't
fully documented yet since nobody knows how that works.
2005-07-06 Thomas Vander Stichele <thomas at apestaart dot org>
* check/gst/gstpad.c:

View file

@ -0,0 +1,439 @@
<chapter id="chapter-negotiation" xreflabel="Caps negotiation">
<title>Caps negotiation</title>
<para>
Caps negotiation is the process where elements configure themselves
and each other for streaming a particular media format over their pads.
Since different types of elements have different requirements for the
media formats they can negotiate to, it is important that this process
is generic and implements all those use cases correctly.
</para>
<para>
In this chapter, we will discuss downstream negotiation and upstream
negotiation from a pipeline perspective, implicating the responsibilities
of different types of elements in a pipeline, and we will introduce the
concept of <emphasis>fixed caps</emphasis>.
</para>
<sect1 id="section-nego-requirements" xreflabel="Caps negotiation use cases">
<title>Caps negotiation use cases</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 dataflow 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-negotiatable, 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 function that tells peer elements what
formats it supports and/or preferes. When upstream renegotiation is
triggered, this becomes important.
</para>
<para>
Downstream elements are notified of a newly set caps only when data
is actually passing their pad. This is because caps is attached to
buffers during dataflow. So when the vorbis decoder sets a caps on
its source pad (to configure the output format), the converter will
not yet be notified. Instead, the converter will only be notified
when the decoder pushes a buffer over its source pad to the converter.
Right before calling the chain-function in the converter, &GStreamer;
will check whether the format that was previously negotiated still
applies to this buffer. If not, it first calls the setcaps-function
of the converter to configure it for the new format. Only after that
will it call the chain function of the converter.
</para>
</sect1>
<sect1 id="section-nego-fixedcaps" xreflabel="Fixed caps">
<title>Fixed caps</title>
<para>
The simplest way in which to do caps negotiation is setting a fixed
caps on a pad. After a fixed caps has been set, the pad can not be
renegotiated from the outside. The only way to reconfigure the pad
is for the element owning the pad to set a new fixed caps on the pad.
Fixed caps is a setup property for pads, called when creating the pad:
</para>
<programlisting>
[..]
pad = gst_pad_new_from_template (..);
gst_pad_use_fixed_caps (pad);
[..]
</programlisting>
<para>
The fixed caps can then be set on the pad by calling
<function>gst_pad_set_caps ()</function>.
</para>
<programlisting>
[..]
caps = gst_caps_new_simple ("audio/x-raw-float",
"width", G_TYPE_INT, 32,
"endianness", G_TYPE_INT, G_BYTE_ORDER,
"buffer-frames", G_TYPE_INT, &lt;bytes-per-frame&gt;,
"rate", G_TYPE_INT, &lt;samplerate&gt;,
"channels", G_TYPE_INT, &lt;num-channels&gt;, NULL);
if (!gst_pad_set_caps (pad, caps)) {
GST_ELEMENT_ERROR (element, CORE, NEGOTIATION, (NULL),
("Some debug information here"));
return GST_FLOW_ERROR;
}
[..]
</programlisting>
<para>
Elements that could implement fixed caps (on their source pads) are,
in general, all elements that are not renegotiatable. Examples include:
</para>
<itemizedlist>
<listitem>
<para>
A typefinder, since the type found is part of the actual data stream
and can thus not be re-negotiated.
</para>
</listitem>
<listitem>
<para>
Pretty much all demuxers, since the contained elementary data
streams are defined in the file headers, and thus not
renegotiatable.
</para>
</listitem>
<listitem>
<para>
Some decoders, where the format is embedded in the datastream
and not part of the peercaps <emphasis>and</emphasis> where the
decoder itself is not reconfigureable, too.
</para>
</listitem>
</itemizedlist>
<para>
All other elements that need to be configured for the format should
implement full caps negotiation, which will be explained in the next
few sections.
</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>
Many elements, particularly effects and converters, will be able
to parse the format of the stream from their input caps, and decide
the output format right at that time already. When renegotiation
takes place, some may merely need to "forward" the renegotiation
backwards upstream (more on that later). For those elements, all
(downstream) caps negotiation can be done in something that we
call the <function>_setcaps ()</function> function. This function is
called when a buffer is pushed over a pad, but the format on this
buffer is not the same as the format that was previously negotiated
(or, similarly, no format was negotiated yet so far).
</para>
<para>
In the <function>_setcaps ()</function>-function, the element can
forward the caps to the next element and, if that pad accepts the
format too, the element can parse the relevant parameters from the
caps and configure itself internally. The caps passed to this function
is <emphasis>always</emphasis> a subset of the template caps, so
there's no need for extensive safety checking. The following example
should give a clear indication of how such a function can be
implemented:
</para>
<programlisting><!-- example-begin forwardcaps.c a --><!--
#include "init.func"
static GstCaps *
gst_my_filter_getcaps (GstPad * pad)
{
return NULL;
}
--><!-- example-end forwardcaps.c a -->
<!-- example-begin forwardcaps.c b -->
static gboolean
gst_my_filter_setcaps (GstPad *pad,
GstCaps *caps)
{
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
GstStructure *s;
/* forward-negotiate */
if (!gst_pad_set_caps (filter-&gt;srcpad, caps))
return FALSE;
/* negotiation succeeded, so now configure ourselves */
s = gst_caps_get_structure (caps, 0);
gst_structure_get_int (s, "rate", &amp;filter-&gt;samplerate);
gst_structure_get_int (s, "channels", &amp;filter-&gt;channels);
return TRUE;
}
<!-- example-end forwardcaps.c b -->
<!-- example-begin forwardcaps.c c --><!--
#include "chain.func"
#include "state.func"
#include "register.func"
--><!-- example-end forwardcaps.c c --></programlisting>
<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.
</para>
<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 -->
static gboolean
gst_my_filter_setcaps (GstPad *pad,
GstCaps *caps)
{
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
if (gst_pad_set_caps (filter-&gt;sinkpad, caps)) {
filter-&gt;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);
others = gst_caps_get_structure (othercaps, 0);
gst_structure_set (others,
"channels", G_TYPE_INT, filter-&gt;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))
return FALSE;
/* we are now set up, configure internally */
filter-&gt;passthrough = FALSE;
gst_structure_get_int (s, "rate", &amp;filter-&gt;from_samplerate);
others = gst_caps_get_structure (newcaps, 0);
gst_structure_get_int (others, "rate", &amp;filter-&gt;to_samplerate);
}
return TRUE;
}
static GstFlowReturn
gst_my_filter_chain (GstPad *pad,
GstBuffer *buf)
{
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
GstBuffer *out;
/* push on if in passthrough mode */
if (filter-&gt;passthrough)
return gst_pad_push (filter-&gt;srcpad, buf);
/* convert, push */
out = gst_my_filter_convert (filter, buf);
gst_buffer_unref (buf);
return gst_pad_push (filter-&gt;srcpad, out);
}
<!-- example-end convertcaps.c b -->
<!-- example-begin convertcaps.c c --><!--
#include "state.func"
#include "register.func"
--><!-- example-end convertcaps.c c --></programlisting>
</sect2>
<sect2 id="section-nego-downstream-parse"
xreflabel="Parsing and setting caps">
<title>Parsing and setting caps</title>
<para>
Other elements, such as certain types of decoders, will not be able
to parse the caps from their input, simply because the input format
does not contain the information required to know the output format
yet; rather, the data headers need to be parsed, too. In many cases,
fixed-caps will be enough, but in some cases, particularly in cases
where such decoders are renegotiatable, it is also possible to use
full caps negotiation.
</para>
<para>
Fortunately, the code required to do so is very similar to the last
code example in <xref linkend="section-nego-downstream-embed"/>, with
the difference being that the caps is selected in the <function>_chain
()</function>-function rather than in the <function>_setcaps
()</function>-function. The rest, as for getting all allowed caps from
the source pad, fixating and such, is all the same. Re-negotiation,
which will be handled in the next section, is very different for such
elements, though.
</para>
</sect2>
</sect1>
<sect1 id="section-nego-upstream" xreflabel="Upstream caps (re)negotiation">
<title>Upstream caps (re)negotiation</title>
<para>
Upstream negotiation's primary use is to renegotiate (part of) an
already-negotiated pipeline to a new format. Some practical examples
include to select a different video size because the size of the video
window changed, and the video output itself is not capable of rescaling,
or because the audio channel configuration changed.
</para>
<para>
Upstream caps renegotiation is done in the <function>gst_pad_alloc_buffer
()</function>-function. The idea here is that an element requesting a
buffer from downstream, has to specify the type of that buffer. If
renegotiation is to take place, this type will no longer apply, and the
downstream element will set a new caps on the provided buffer. Next,
&GStreamer; will trigger renegotiation on the sourcepad of the element
before the function returns.
</para>
<para>
It is important to note here that different elements actually have
different responsibilities here:
</para>
<itemizedlist>
<listitem>
<para>
Elements should implement a <quote>padalloc</quote>-function in
order to be able to change format on renegotiation. This is also
true for filters and converters.
</para>
</listitem>
<listitem>
<para>
Elements should allocate new buffers using
<function>gst_pad_alloc_buffer ()</function>.
</para>
</listitem>
<listitem>
<para>
Elements that are renegotiatable should implement a
<quote>setcaps</quote>-function on their sourcepad as well.
</para>
</listitem>
</itemizedlist>
<para>
Unfortunately, not all details here have been worked out yet, so this
documentation is incomplete. FIXME.
</para>
</sect1>
<sect1 id="section-nego-getcaps" xreflabel="Implementing a getcaps function">
<title>Implementing a getcaps function</title>
<para>
A <function>_getcaps ()</function>-function is called when a peer
element would like to know which formats this element supports, and
in what order of preference. The return value should be all formats
that this elements supports, taking into account limitations of peer
elements further downstream or upstream, sorted by order of preference,
highest preference first.
</para>
<para>
</para>
<programlisting><!-- example-begin getcaps.c a --><!--
#include "init.func"
--><!-- example-end getcaps.c a -->
<!-- example-begin getcaps.c b -->
static GstCaps *
gst_my_filter_getcaps (GstPad *pad)
{
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
GstPad *otherpad = (pad == filter-&gt;srcpad) ? filter-&gt;sinkpad :
filter-&gt;srcpad;
GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps;
gint i;
/* We support *any* samplerate, indifferent from the samplerate
* supported by the linked elements on both sides. */
for (i = 0; i &lt; gst_caps_get_size (othercaps); i++) {
GstStructure *structure = gst_caps_get_structure (othercaps, i);
gst_structure_remove_field (structure, "rate");
}
caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
gst_caps_unref (othercaps);
return caps;
}
<!-- example-end getcaps.c b -->
<!-- example-begin getcaps.c c --><!--
static gboolean
gst_my_filter_setcaps (GstPad * pad, GstCaps * caps)
{
return FALSE;
}
#include "chain.func"
#include "state.func"
#include "register.func"
--><!-- example-end getcaps.c c --></programlisting>
<para>
Using all the knowledge you've acquired by reading this chapter, you
should be able to write an element that does correct caps negotiation.
If in doubt, look at other elements of the same type in our CVS
repository to get an idea of how they do what you want to do.
</para>
</sect1>
</chapter>

View file

@ -147,6 +147,8 @@ typedef struct _GstMyFilter {
<!-- example-end filter.h a -->
<!-- example-begin filter.h b --><!--
gint samplerate, channels;
gint from_samplerate, to_samplerate;
gboolean passthrough;
--><!-- example-end filter.h b -->
<!-- example-begin filter.h c -->
} GstMyFilter;

View file

@ -8,23 +8,20 @@
of your element, and that makes them a very important item in the process
of element creation. In the boilerplate code, we have seen how static pad
templates take care of registering pad templates with the element class.
Here, we will see how to create actual elements, use <function>_link ()</function>
and <function>_getcaps ()</function> functions to let other elements know
their capabilities and how to register functions to let data flow through
the element.
Here, we will see how to create actual elements, use a <function>_setcaps
()</function>-functions to configure for a particular format and how to
register functions to let data flow through the element.
</para>
<para>
In the element <function>_init ()</function> function, you create the pad
from the pad template that has been registered with the element class in
the <function>_base_init ()</function> function. After creating the pad,
you have to set a <function>_link ()</function> function pointer and a
<function>_getcaps ()</function> function pointer. Optionally, you can
set a <function>_chain ()</function> function pointer (on sink pads in
filter and sink elements) through which data will come in to the element,
or (on source pads in source elements) a <function>_get ()</function>
function pointer through which data will be pulled from the element. After
that, you have to register the pad with the element. This happens like
this:
you have to set a <function>_setcaps ()</function> function pointer and
optionally a <function>_getcaps ()</function> function pointer. Also, you
have to set a <function>_chain ()</function> function pointer.
Alternatively, pads can also operate in looping mode, which mans that they
can pull data themselves. More on this topic later. After that, you have
to register the pad with the element. This happens like this:
</para>
<programlisting><!-- example-begin init.func a --><!--
#include "filter.h"
@ -76,11 +73,11 @@ gst_my_filter_class_init (GstMyFilterClass * klass)
<!-- example-begin init.func b -->
static gboolean gst_my_filter_setcaps (GstPad *pad,
GstCaps *caps);
static GstCaps * gst_my_filter_getcaps (GstPad *pad);
static GstFlowReturn gst_my_filter_chain (GstPad *pad,
GstBuffer *buf);
<!-- example-end init.func b -->
<!-- example-begin init.func c --><!--
static GstCaps * gst_my_filter_getcaps (GstPad *pad);
static gboolean gst_my_filter_event (GstPad *pad,
GstEvent *event);
--><!-- example-end init.func c -->
@ -95,10 +92,10 @@ gst_my_filter_init (GstMyFilter *filter)
filter-&gt;sinkpad = gst_pad_new_from_template (
gst_element_class_get_pad_template (klass, "sink"), "sink");
gst_pad_set_setcaps_function (filter-&gt;sinkpad, gst_my_filter_setcaps);
gst_pad_set_getcaps_function (filter-&gt;sinkpad, gst_my_filter_getcaps);
gst_pad_set_chain_function (filter-&gt;sinkpad, gst_my_filter_chain);
<!-- example-end init.func d -->
<!-- example-begin init.func e --><!--
gst_pad_set_getcaps_function (filter-&gt;sinkpad, gst_my_filter_getcaps);
gst_pad_set_event_function (filter-&gt;sinkpad, gst_my_filter_event);
--><!-- example-end init.func e -->
<!-- example-begin init.func f -->
@ -107,30 +104,33 @@ gst_my_filter_init (GstMyFilter *filter)
/* pad through which data goes out of the element */
filter-&gt;srcpad = gst_pad_new_from_template (
gst_element_class_get_pad_template (klass, "src"), "src");
gst_pad_set_setcaps_function (filter-&gt;srcpad, gst_my_filter_setcaps);
<!-- example-end init.func f -->
<!-- example-begin init.func g --><!--
gst_pad_set_getcaps_function (filter-&gt;srcpad, gst_my_filter_getcaps);
--><!-- example-end init.func g -->
<!-- example-begin init.func h -->
gst_element_add_pad (GST_ELEMENT (filter), filter-&gt;srcpad);
/* properties initial value */
filter->silent = FALSE;
}
<!-- example-end init.func f --></programlisting>
<!-- example-end init.func h --></programlisting>
<sect1 id="section-pads-linkfn" xreflabel="The link function">
<title>The link function</title>
<title>The setcaps-function</title>
<para>
The <function>_link ()</function> is called during caps negotiation. This
is the process where the linked pads decide on the streamtype that will
transfer between them. A full list of type-definitions can be found in
<xref linkend="chapter-building-types"/>. A <function>_link ()</function>
The <function>_setcaps ()</function>-function is called during caps
negotiation, which is discussed in great detail in <xref
linkend="chapter-negotiation"/>. This is the process where the linked
pads decide on the streamtype that will transfer between them. A full
list of type-definitions can be found in <xref
linkend="chapter-building-types"/>. A <function>_link ()</function>
receives a pointer to a <ulink type="http"
url="../../gstreamer/html/gstreamer-GstCaps.html"><classname>GstCaps</classname>
</ulink> struct that defines the proposed streamtype, and can respond with
either <quote>yes</quote> (<symbol>GST_PAD_LINK_OK</symbol>),
<quote>no</quote> (<symbol>GST_PAD_LINK_REFUSED</symbol>) or
<quote>don't know yet</quote> (<symbol>GST_PAD_LINK_DELAYED</symbol>).
If the element responds positively towards the streamtype, that type
will be used on the pad. An example:
url="../../gstreamer/html/gstreamer-GstCaps.html"><classname>GstCaps</classname></ulink>
struct that defines the proposed streamtype, and can respond with
either <quote>yes</quote> (<symbol>TRUE</symbol>) or <quote>no</quote>
(<symbol>FALSE</symbol>). If the element responds positively towards
the streamtype, that type will be used on the pad. An example:
</para>
<programlisting><!-- example-begin caps.func a -->
static gboolean
@ -138,10 +138,7 @@ gst_my_filter_setcaps (GstPad *pad,
GstCaps *caps)
{
GstStructure *structure = gst_caps_get_structure (caps, 0);
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstPad *otherpad = (pad == filter-&gt;srcpad) ? filter-&gt;sinkpad :
filter-&gt;srcpad;
GstPadLinkReturn ret;
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
const gchar *mime;
/* Since we're an audio filter, we want to handle raw audio
@ -157,9 +154,8 @@ gst_my_filter_setcaps (GstPad *pad,
/* we're a filter and don't touch the properties of the data.
* That means we can set the given caps unmodified on the next
* element, and use that negotiation return value as ours. */
ret = gst_pad_set_caps (otherpad, gst_caps_copy (caps));
if (GST_PAD_LINK_FAILED (ret))
return ret;
if (!gst_pad_set_caps (filter-&gt;srcpad, caps))
return FALSE;
/* Capsnego succeeded, get the stream properties for internal
* usage and return success. */
@ -169,9 +165,21 @@ gst_my_filter_setcaps (GstPad *pad,
g_print ("Caps negotiation succeeded with %d Hz @ %d channels\n",
filter-&gt;samplerate, filter-&gt;channels);
return ret;
return TRUE;
}
<!-- example-end caps.func a --></programlisting>
<!-- example-end caps.func a -->
<!-- example-begin caps.func b --><!--
static GstCaps *
gst_my_filter_getcaps (GstPad * pad)
{
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
GstPad *otherpad = (pad == filter-&gt;srcpad) ? filter-&gt;sinkpad :
filter-&gt;srcpad;
GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad);
return othercaps;
}
--><!-- example-end caps.func b --></programlisting>
<para>
In here, we check the mimetype of the provided caps. Normally, you don't
need to do that in your own plugin/element, because the core does that
@ -188,58 +196,11 @@ gst_my_filter_setcaps (GstPad *pad,
<para>
If your <function>_link ()</function> function does not need to perform
any specific operation (i.e. it will only forward caps), you can set it
to <function>gst_pad_proxy_link</function>. This is a link forwarding
to <function>gst_pad_proxy_link ()</function>. This is a link forwarding
function implementation provided by the core. It is useful for elements
such as <classname>identity</classname>.
</para>
</sect1>
<sect1 id="section-pads-getcapsfn" xreflabel="The getcaps function">
<title>The getcaps function</title>
<para>
The <function>_getcaps ()</function> function is used to request the list
of supported formats and properties from the element. In some cases, this
will be equal to the formats provided by the pad template, in which case
this function can be omitted. In some cases, too, it will not depend on
anything inside this element, but it will rather depend on the input from
another element linked to this element's sink or source pads. In that case,
you can use <function>gst_pad_proxy_getcaps</function> as implementation,
it provides getcaps forwarding in the core. However, in many cases, the
format supported by this element cannot be defined externally, but is
more specific than those provided by the pad template. In this case, you
should use a <function>_getcaps ()</function> function. In the case as
specified below, we assume that our filter is able to resample sound, so
it would be able to provide any samplerate (indifferent from the samplerate
specified on the other pad) on both pads. It explains how a
<function>_getcaps ()</function> can be used to do this.
</para>
<programlisting><!-- example-begin caps.func b -->
static GstCaps *
gst_my_filter_getcaps (GstPad *pad)
{
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstPad *otherpad = (pad == filter-&gt;srcpad) ? filter-&gt;sinkpad :
filter-&gt;srcpad;
GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps;
gint i;
if (gst_caps_is_empty (othercaps))
return othercaps;
/* We support *any* samplerate, indifferent from the samplerate
* supported by the linked elements on both sides. */
for (i = 0; i &lt; gst_caps_get_size (othercaps); i++) {
GstStructure *structure = gst_caps_get_structure (othercaps, i);
gst_structure_remove_field (structure, "rate");
}
caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
gst_caps_unref (othercaps);
return caps;
}
<!-- example-end caps.func b --></programlisting>
</sect1>
<!-- example-begin pads.c --><!--
#include "init.func"
#include "caps.func"

View file

@ -21,6 +21,7 @@
<!ENTITY BUILDING_TESTAPP SYSTEM "building-testapp.xml">
<!ENTITY BUILDING_FILTERFACT SYSTEM "building-filterfactory.xml">
<!ENTITY ADVANCED_NEGOTIATION SYSTEM "advanced-negotiation.xml">
<!ENTITY ADVANCED_SCHEDULING SYSTEM "advanced-scheduling.xml">
<!ENTITY ADVANCED_TYPES SYSTEM "advanced-types.xml">
<!ENTITY ADVANCED_REQUEST SYSTEM "advanced-request.xml">
@ -136,6 +137,7 @@
</para>
</partintro>
&ADVANCED_NEGOTIATION;
&ADVANCED_SCHEDULING;
&ADVANCED_TYPES;
&ADVANCED_REQUEST;

View file

@ -7,8 +7,12 @@ libchain_la_SOURCES = chain.c
libchain2_la_SOURCES = chain2.c
libstate_la_SOURCES = state.c
libproperties_la_SOURCES = properties.c
libforwardcaps_la_SOURCES = forwardcaps.c
libconvertcaps_la_SOURCES = convertcaps.c
libgetcaps_la_SOURCES = getcaps.c
DISTCLEANFILES = \
boilerplate.c pads.c chain.c chain2.c state.c properties.c \
forwardcaps.c convertcaps.c getcaps.c \
init.func caps.func chain.func state.func register.func filter.h
EXTRA_DIST = extract.pl
@ -19,7 +23,10 @@ EXAMPLES = \
libchain.la \
libchain2.la \
libstate.la \
libproperties.la
libproperties.la \
libforwardcaps.la \
libconvertcaps.la \
libgetcaps.la
EXAMPLE_APPS = \
test
@ -64,6 +71,10 @@ test.c: $(top_srcdir)/docs/pwg/building-testapp.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-testapp.xml
forwardcaps.c convertcaps.c getcaps.c: $(top_srcdir)/docs/pwg/advanced-negotiation.xml init.func register.func chain.func state.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/advanced-negotiation.xml
noinst_PROGRAMS = $(EXAMPLE_APPS)
noinst_LTLIBRARIES = $(EXAMPLES)
LDADD = $(GST_OBJ_LIBS)

View file

@ -7,8 +7,12 @@ libchain_la_SOURCES = chain.c
libchain2_la_SOURCES = chain2.c
libstate_la_SOURCES = state.c
libproperties_la_SOURCES = properties.c
libforwardcaps_la_SOURCES = forwardcaps.c
libconvertcaps_la_SOURCES = convertcaps.c
libgetcaps_la_SOURCES = getcaps.c
DISTCLEANFILES = \
boilerplate.c pads.c chain.c chain2.c state.c properties.c \
forwardcaps.c convertcaps.c getcaps.c \
init.func caps.func chain.func state.func register.func filter.h
EXTRA_DIST = extract.pl
@ -19,7 +23,10 @@ EXAMPLES = \
libchain.la \
libchain2.la \
libstate.la \
libproperties.la
libproperties.la \
libforwardcaps.la \
libconvertcaps.la \
libgetcaps.la
EXAMPLE_APPS = \
test
@ -64,6 +71,10 @@ test.c: $(top_srcdir)/docs/pwg/building-testapp.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-testapp.xml
forwardcaps.c convertcaps.c getcaps.c: $(top_srcdir)/docs/pwg/advanced-negotiation.xml init.func register.func chain.func state.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/advanced-negotiation.xml
noinst_PROGRAMS = $(EXAMPLE_APPS)
noinst_LTLIBRARIES = $(EXAMPLES)
LDADD = $(GST_OBJ_LIBS)