mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
a13be0a71e
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.
230 lines
8.8 KiB
XML
230 lines
8.8 KiB
XML
|
|
<!-- ############ chapter ############# -->
|
|
|
|
<chapter id="chapter-building-pads">
|
|
<title>Specifying the pads</title>
|
|
<para>
|
|
As explained before, pads are the port through which data goes in and out
|
|
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 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>_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"
|
|
#include <string.h>
|
|
|
|
static GstElementStateReturn
|
|
gst_my_filter_change_state (GstElement * element);
|
|
|
|
GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT);
|
|
|
|
static void
|
|
gst_my_filter_base_init (gpointer klass)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
|
static GstElementDetails my_filter_details = {
|
|
"An example plugin",
|
|
"Example/FirstExample",
|
|
"Shows the basic structure of a plugin",
|
|
"your name <your.name@your.isp>"
|
|
};
|
|
static GstStaticPadTemplate sink_factory =
|
|
GST_STATIC_PAD_TEMPLATE (
|
|
"sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("ANY")
|
|
);
|
|
static GstStaticPadTemplate src_factory =
|
|
GST_STATIC_PAD_TEMPLATE (
|
|
"src",
|
|
GST_PAD_SRC,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("ANY")
|
|
);
|
|
|
|
gst_element_class_set_details (element_class, &my_filter_details);
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&src_factory));
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&sink_factory));
|
|
}
|
|
|
|
static void
|
|
gst_my_filter_class_init (GstMyFilterClass * klass)
|
|
{
|
|
GST_ELEMENT_CLASS (klass)->change_state = gst_my_filter_change_state;
|
|
}
|
|
--><!-- example-end init.func a -->
|
|
<!-- example-begin init.func b -->
|
|
static gboolean gst_my_filter_setcaps (GstPad *pad,
|
|
GstCaps *caps);
|
|
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 -->
|
|
<!-- example-begin init.func d -->
|
|
|
|
static void
|
|
gst_my_filter_init (GstMyFilter *filter)
|
|
{
|
|
GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
|
|
|
|
/* pad through which data comes in to the element */
|
|
filter->sinkpad = gst_pad_new_from_template (
|
|
gst_element_class_get_pad_template (klass, "sink"), "sink");
|
|
gst_pad_set_setcaps_function (filter->sinkpad, gst_my_filter_setcaps);
|
|
gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain);
|
|
<!-- example-end init.func d -->
|
|
<!-- example-begin init.func e --><!--
|
|
gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps);
|
|
gst_pad_set_event_function (filter->sinkpad, gst_my_filter_event);
|
|
--><!-- example-end init.func e -->
|
|
<!-- example-begin init.func f -->
|
|
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
|
|
|
|
/* pad through which data goes out of the element */
|
|
filter->srcpad = gst_pad_new_from_template (
|
|
gst_element_class_get_pad_template (klass, "src"), "src");
|
|
<!-- example-end init.func f -->
|
|
<!-- example-begin init.func g --><!--
|
|
gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps);
|
|
--><!-- example-end init.func g -->
|
|
<!-- example-begin init.func h -->
|
|
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
|
|
|
|
/* properties initial value */
|
|
filter->silent = FALSE;
|
|
}
|
|
<!-- example-end init.func h --></programlisting>
|
|
|
|
<sect1 id="section-pads-linkfn" xreflabel="The link function">
|
|
<title>The setcaps-function</title>
|
|
<para>
|
|
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>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
|
|
gst_my_filter_setcaps (GstPad *pad,
|
|
GstCaps *caps)
|
|
{
|
|
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
|
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
|
|
const gchar *mime;
|
|
|
|
/* Since we're an audio filter, we want to handle raw audio
|
|
* and from that audio type, we need to get the samplerate and
|
|
* number of channels. */
|
|
mime = gst_structure_get_name (structure);
|
|
if (strcmp (mime, "audio/x-raw-int") != 0) {
|
|
GST_WARNING ("Wrong mimetype %s provided, we only support %s",
|
|
mime, "audio/x-raw-int");
|
|
return GST_PAD_LINK_REFUSED;
|
|
}
|
|
|
|
/* 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. */
|
|
if (!gst_pad_set_caps (filter->srcpad, caps))
|
|
return FALSE;
|
|
|
|
/* Capsnego succeeded, get the stream properties for internal
|
|
* usage and return success. */
|
|
gst_structure_get_int (structure, "rate", &filter->samplerate);
|
|
gst_structure_get_int (structure, "channels", &filter->channels);
|
|
|
|
g_print ("Caps negotiation succeeded with %d Hz @ %d channels\n",
|
|
filter->samplerate, filter->channels);
|
|
|
|
return TRUE;
|
|
}
|
|
<!-- 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->srcpad) ? filter->sinkpad :
|
|
filter->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
|
|
for you. We simply use it to show how to retrieve the mimetype from a
|
|
provided set of caps. Types are stored in <ulink type="http"
|
|
url="../../gstreamer/html/gstreamer-GstStructure.html"><classname>GstStructure
|
|
</classname></ulink> internally. A <ulink
|
|
type="http" url="../../gstreamer/html/gstreamer-GstCaps.html"><classname>GstCaps
|
|
</classname></ulink> is nothing more than a small
|
|
wrapper for 0 or more structures/types. From the structure, you can also
|
|
retrieve properties, as is shown above with the function
|
|
<function>gst_structure_get_int ()</function>.
|
|
</para>
|
|
<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
|
|
function implementation provided by the core. It is useful for elements
|
|
such as <classname>identity</classname>.
|
|
</para>
|
|
</sect1>
|
|
<!-- example-begin pads.c --><!--
|
|
#include "init.func"
|
|
#include "caps.func"
|
|
|
|
static gboolean
|
|
gst_my_filter_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
return gst_pad_event_default (pad, event);
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_my_filter_chain (GstPad * pad, GstBuffer * buf)
|
|
{
|
|
return gst_pad_push (GST_MY_FILTER (GST_OBJECT_PARENT (pad))->srcpad, buf);
|
|
}
|
|
|
|
static GstElementStateReturn
|
|
gst_my_filter_change_state (GstElement * element)
|
|
{
|
|
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
|
|
change_state, (element), GST_STATE_SUCCESS);
|
|
}
|
|
|
|
#include "register.func"
|
|
--><!-- example-end pads.c -->
|
|
</chapter>
|
|
|