pwg: rework dynamic pads docs

This commit is contained in:
Wim Taymans 2012-09-28 13:25:49 +02:00
parent 723c2a48b9
commit 3cc8f1412d

View file

@ -53,17 +53,18 @@ typedef struct _GstMyFilter {
GList *srcpadlist; GList *srcpadlist;
} GstMyFilter; } GstMyFilter;
static GstStaticPadTemplate src_factory =
GST_STATIC_PAD_TEMPLATE (
"src_%u",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("ANY")
);
static void static void
gst_my_filter_base_init (GstMyFilterClass *klass) gst_my_filter_class_init (GstMyFilterClass *klass)
{ {
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
static GstStaticPadTemplate src_factory =
GST_STATIC_PAD_TEMPLATE (
"src_%02d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("ANY")
);
[..] [..]
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory)); gst_static_pad_template_get (&src_factory));
@ -96,11 +97,11 @@ gst_my_filter_getline (GstMyFilter *filter)
/* newline? */ /* newline? */
if (data[n] == '\n') { if (data[n] == '\n') {
GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); GstBuffer *buf = gst_buffer_new_allocate (NULL, n + 1, NULL);
gst_bytestream_peek_bytes (filter->bs, &data, n); gst_bytestream_peek_bytes (filter->bs, &data, n);
memcpy (GST_BUFFER_DATA (buf), data, n); gst_buffer_fill (buf, 0, data, n);
GST_BUFFER_DATA (buf)[n] = '\0'; gst_buffer_memset (buf, n, '\0', 1);
gst_bytestream_flush_fast (filter->bs, n + 1); gst_bytestream_flush_fast (filter->bs, n + 1);
return buf; return buf;
@ -114,31 +115,33 @@ gst_my_filter_loopfunc (GstElement *element)
GstMyFilter *filter = GST_MY_FILTER (element); GstMyFilter *filter = GST_MY_FILTER (element);
GstBuffer *buf; GstBuffer *buf;
GstPad *pad; GstPad *pad;
GstMapInfo map;
gint num, n; gint num, n;
/* parse header */ /* parse header */
if (filter->firstrun) { if (filter->firstrun) {
GstElementClass *klass;
GstPadTemplate *templ;
gchar *padname; gchar *padname;
guint8 id;
if (!(buf = gst_my_filter_getline (filter))) { if (!(buf = gst_my_filter_getline (filter))) {
gst_element_error (element, STREAM, READ, (NULL), gst_element_error (element, STREAM, READ, (NULL),
("Stream contains no header")); ("Stream contains no header"));
return; return;
} }
num = atoi (GST_BUFFER_DATA (buf)); gst_buffer_extract (buf, 0, &id, 1);
num = atoi (id);
gst_buffer_unref (buf); gst_buffer_unref (buf);
/* for each of the streams, create a pad */ /* for each of the streams, create a pad */
klass = GST_ELEMENT_GET_CLASS (filter);
templ = gst_element_class_get_pad_template (klass, "src_%02d");
for (n = 0; n < num; n++) { for (n = 0; n < num; n++) {
padname = g_strdup_printf ("src_%02d", n); padname = g_strdup_printf ("src_%u", n);
pad = gst_pad_new_from_template (templ, padname); pad = gst_pad_new_from_static_template (src_factory, padname);
g_free (padname); g_free (padname);
/* here, you would set _getcaps () and _link () functions */ /* here, you would set _event () and _query () functions */
/* need to activate the pad before adding */
gst_pad_set_active (pad, TRUE);
gst_element_add_pad (element, pad); gst_element_add_pad (element, pad);
filter->srcpadlist = g_list_append (filter->srcpadlist, pad); filter->srcpadlist = g_list_append (filter->srcpadlist, pad);
@ -153,36 +156,37 @@ gst_my_filter_loopfunc (GstElement *element)
for (padlist = srcpadlist; for (padlist = srcpadlist;
padlist != NULL; padlist = g_list_next (padlist)) { padlist != NULL; padlist = g_list_next (padlist)) {
pad = GST_PAD (padlist->data); pad = GST_PAD (padlist->data);
gst_event_ref (event); gst_pad_push_event (pad, gst_event_ref (event));
gst_pad_push (pad, GST_DATA (event));
} }
gst_event_unref (event); gst_event_unref (event);
gst_element_set_eos (element); /* pause the task here */
return; return;
} }
/* parse stream number and go beyond the ':' in the data */ /* parse stream number and go beyond the ':' in the data */
num = atoi (GST_BUFFER_DATA (buf)); gst_buffer_map (buf, &map, GST_MAP_READ);
num = atoi (map.data[0]);
if (num >= 0 && num < g_list_length (filter->srcpadlist)) { if (num >= 0 && num < g_list_length (filter->srcpadlist)) {
pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num); pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num);
/* magic buffer parsing foo */ /* magic buffer parsing foo */
for (n = 0; GST_BUFFER_DATA (buf)[n] != ':' && for (n = 0; map.data[n] != ':' &&
GST_BUFFER_DATA (buf)[n] != '\0'; n++) ; map.data[n] != '\0'; n++) ;
if (GST_BUFFER_DATA (buf)[n] != '\0') { if (map.data[n] != '\0') {
GstBuffer *sub; GstBuffer *sub;
/* create subbuffer that starts right past the space. The reason /* create region copy that starts right past the space. The reason
* that we don't just forward the data pointer is because the * that we don't just forward the data pointer is because the
* pointer is no longer the start of an allocated block of memory, * pointer is no longer the start of an allocated block of memory,
* but just a pointer to a position somewhere in the middle of it. * but just a pointer to a position somewhere in the middle of it.
* That cannot be freed upon disposal, so we'd either crash or have * That cannot be freed upon disposal, so we'd either crash or have
* a memleak. Creating a subbuffer is a simple way to solve that. */ * a memleak. Creating a region copy is a simple way to solve that. */
sub = gst_buffer_create_sub (buf, n + 1, GST_BUFFER_SIZE (buf) - n - 1); sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
gst_pad_push (pad, GST_DATA (sub)); n + 1, map.size - n - 1);
gst_pad_push (pad, sub);
} }
} }
gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf); gst_buffer_unref (buf);
} }
]]> ]]>
@ -207,46 +211,52 @@ gst_my_filter_loopfunc (GstElement *element)
where - for each elementary stream that is to be placed in the output where - for each elementary stream that is to be placed in the output
system stream - one sink pad will be requested. It can also be used in system stream - one sink pad will be requested. It can also be used in
elements with a variable number of input or outputs pads, such as the elements with a variable number of input or outputs pads, such as the
<classname>tee</classname> (multi-output), <classname>switch</classname> <classname>tee</classname> (multi-output) or
or <classname>aggregator</classname> (both multi-input) elements. At the <classname>input-selector</classname> (multi-input) elements.
time of writing this, it is unclear to me who is responsible for cleaning </para>
up the created pad and how or when that should be done. Below is a simple <para>
example of an aggregator based on request pads. To implement request pads, you need to provide a padtemplate with a
GST_PAD_REQUEST presence and implement the
<function>request_new_pad</function> virtual method in
<classname>GstElement</classname>.
To clean up, you will need to implement the
<function>release_pad</function> virtual method.
</para> </para>
<programlisting> <programlisting>
<![CDATA[ <![CDATA[
static GstPad * gst_my_filter_request_new_pad (GstElement *element, static GstPad * gst_my_filter_request_new_pad (GstElement *element,
GstPadTemplate *templ, GstPadTemplate *templ,
const gchar *name); const gchar *name,
const GstCaps *caps);
static void static void gst_my_filter_release_pad (GstElement *element,
gst_my_filter_base_init (GstMyFilterClass *klass) GstPad *pad);
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); static GstStaticPadTemplate sink_factory =
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE (
GST_STATIC_PAD_TEMPLATE ( "sink_%u",
"sink_%d", GST_PAD_SINK,
GST_PAD_SINK, GST_PAD_REQUEST,
GST_PAD_REQUEST, GST_STATIC_CAPS ("ANY")
GST_STATIC_CAPS ("ANY") );
);
[..]
gst_element_class_add_pad_template (klass,
gst_static_pad_template_get (&sink_factory));
}
static void static void
gst_my_filter_class_init (GstMyFilterClass *klass) gst_my_filter_class_init (GstMyFilterClass *klass)
{ {
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
gst_element_class_add_pad_template (klass,
gst_static_pad_template_get (&sink_factory));
[..] [..]
element_class->request_new_pad = gst_my_filter_request_new_pad; element_class->request_new_pad = gst_my_filter_request_new_pad;
element_class->release_pad = gst_my_filter_release_pad;
} }
static GstPad * static GstPad *
gst_my_filter_request_new_pad (GstElement *element, gst_my_filter_request_new_pad (GstElement *element,
GstPadTemplate *templ, GstPadTemplate *templ,
const gchar *name) const gchar *name,
const GstCaps *caps)
{ {
GstPad *pad; GstPad *pad;
GstMyFilterInputContext *context; GstMyFilterInputContext *context;
@ -255,12 +265,25 @@ gst_my_filter_request_new_pad (GstElement *element,
pad = gst_pad_new_from_template (templ, name); pad = gst_pad_new_from_template (templ, name);
gst_pad_set_element_private (pad, context); gst_pad_set_element_private (pad, context);
/* normally, you would set _link () and _getcaps () functions here */ /* normally, you would set _chain () and _event () functions here */
gst_element_add_pad (element, pad); gst_element_add_pad (element, pad);
return pad; return pad;
} }
static void
gst_my_filter_release_pad (GstElement *element,
GstPad *pad)
{
GstMyFilterInputContext *context;
context = gst_pad_get_element_private (pad);
g_free (context);
gst_element_remove_pad (element, pad);
}
]]> ]]>
</programlisting> </programlisting>
</sect1> </sect1>