Enable building the PWG examples.

Original commit message from CVS:
* configure.ac:
* examples/Makefile.am:
* examples/pwg/Makefile.am:
* examples/pwg/extract.pl:
Enable building the PWG examples.
* docs/pwg/advanced-interfaces.xml:
Add URI interface stub.
* docs/pwg/advanced-types.xml:
* docs/pwg/other-autoplugger.xml:
* docs/pwg/appendix-porting.xml:
* docs/pwg/pwg.xml:
Add porting guide (mostly stubs), remove autoplugging (see ADM).
* docs/pwg/building-boiler.xml:
* docs/pwg/building-chainfn.xml:
* docs/pwg/building-pads.xml:
* docs/pwg/building-props.xml:
* docs/pwg/building-state.xml:
* docs/pwg/building-testapp.xml:
Update the building-*.xml parts for 0.9 changes. All examples
code blocks compile in examples/pwg/*.
This commit is contained in:
Ronald S. Bultje 2005-07-01 12:43:03 +00:00
parent edcaf2cd4f
commit c9a37cf682
19 changed files with 720 additions and 155 deletions

View file

@ -1,3 +1,26 @@
2005-07-01 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* configure.ac:
* examples/Makefile.am:
* examples/pwg/Makefile.am:
* examples/pwg/extract.pl:
Enable building the PWG examples.
* docs/pwg/advanced-interfaces.xml:
Add URI interface stub.
* docs/pwg/advanced-types.xml:
* docs/pwg/other-autoplugger.xml:
* docs/pwg/appendix-porting.xml:
* docs/pwg/pwg.xml:
Add porting guide (mostly stubs), remove autoplugging (see ADM).
* docs/pwg/building-boiler.xml:
* docs/pwg/building-chainfn.xml:
* docs/pwg/building-pads.xml:
* docs/pwg/building-props.xml:
* docs/pwg/building-state.xml:
* docs/pwg/building-testapp.xml:
Update the building-*.xml parts for 0.9 changes. All examples
code blocks compile in examples/pwg/*.
2005-06-30 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* docs/manual/advanced-autoplugging.xml:

View file

@ -701,6 +701,7 @@ examples/manual/Makefile
examples/mixer/Makefile
examples/pingpong/Makefile
examples/plugins/Makefile
examples/pwg/Makefile
examples/queue/Makefile
examples/queue2/Makefile
examples/queue3/Makefile

View file

@ -118,6 +118,13 @@ gst_my_filter_some_interface_init (GstSomeInterface *iface)
</programlisting>
</sect1>
<sect1 id="section-iface-uri" xreflabel="URI interface">
<title>URI interface</title>
<para>
WRITEME
</para>
</sect1>
<sect1 id="section-iface-mixer" xreflabel="Mixer Interface">
<title>Mixer Interface</title>
<para>

View file

@ -143,8 +143,8 @@ plugin_init (GstPlugin *plugin)
typefind functions.
</para>
<para>
Autoplugging will be discussed in great detail in the chapter called
<xref linkend="chapter-other-autoplugger"/>.
Autoplugging has been discussed in great detail in the Application
Development Manual.
</para>
</sect1>

View file

@ -0,0 +1,37 @@
<chapter id="chapter-porting">
<title>Porting 0.8 plug-ins to 0.9</title>
<para>
This section of the appendix will discuss shortly what changes to
plugins will be needed to quickly and conveniently port most
applications from &GStreamer;-0.8 to &GStreamer;-0.9, with references
to the relevant sections in this Plugin Writer's Guide where needed.
With this list, it should be possible to port most plugins to
&GStreamer;-0.9 in less than a day.
</para>
<sect1 id="section-porting-objects">
<title>List of changes</title>
<itemizedlist>
<listitem>
<para>
Most functions returning an object or an object property have
been changed to return its own reference rather than a constant
reference of the one owned by the object itself. The reason for
this change is primarily threadsafety. This means, effectively,
that return values of functions such as
<function>gst_element_get_pad ()</function>,
<function>gst_pad_get_name ()</function> and many more like these
have to be free'ed or unreferenced after use. Check the API
references of each function to know for sure whether return
values should be free'ed or not.
</para>
</listitem>
<listitem>
<para>
base classes, async capsnego (caps-on-buffer), async for sinks,
bytestream dead / pull_range, direct scheduling, etc.
</para>
</listitem>
</itemizedlist>
</sect1>
</chapter>

View file

@ -134,40 +134,54 @@ U gst-template/gst-app/src/Makefile.am
<example id="ex-boiler-examine-h">
<title>Example Plugin Header File</title>
<programlisting>
/* Definition of structure storing data for this element. */
typedef struct _GstExample GstExample;
<programlisting><!-- example-begin filter.h a -->
#include &lt;gst/gst.h&gt;
struct _GstExample {
GstElement element;
/* Definition of structure storing data for this element. */
typedef struct _GstMyFilter {
GstElement element;
GstPad *sinkpad, *srcpad;
GstPad *sinkpad, *srcpad;
gboolean silent;
};
gboolean silent;
<!-- example-end filter.h a -->
<!-- example-begin filter.h b --><!--
gint samplerate, channels;
--><!-- example-end filter.h b -->
<!-- example-begin filter.h c -->
} GstMyFilter;
/* Standard definition defining a class for this element. */
typedef struct _GstExampleClass GstExampleClass;
struct _GstExampleClass {
GstElementClass parent_class;
};
/* Standard definition defining a class for this element. */
typedef struct _GstMyFilterClass {
GstElementClass parent_class;
} GstMyFilterClass;
/* Standard macros for defining types for this element. */
#define GST_TYPE_EXAMPLE \
(gst_example_get_type())
#define GST_EXAMPLE(obj) \
(G_TYPE_CHECK_CAST((obj),GST_TYPE_EXAMPLE,GstExample))
#define GST_EXAMPLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EXAMPLE,GstExample))
#define GST_IS_EXAMPLE(obj) \
(G_TYPE_CHECK_TYPE((obj),GST_TYPE_EXAMPLE))
#define GST_IS_EXAMPLE_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE))
/* Standard macros for defining types for this element. */
#define GST_TYPE_MY_FILTER \
(gst_my_filter_get_type())
#define GST_MY_FILTER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MY_FILTER,GstMyFilter))
#define GST_MY_FILTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MY_FILTER,GstMyFilterClass))
#define GST_IS_MY_FILTER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MY_FILTER))
#define GST_IS_MY_FILTER_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MY_FILTER))
/* Standard function returning type information. */
GType gst_example_get_type (void);
</programlisting>
/* Standard function returning type information. */
GType gst_my_filter_get_type (void);
<!-- example-end filter.h c --></programlisting>
</example>
<para>
Using this header file, you can use the following macro to setup
the <classname>GObject</classname> basics in your source file so
that all functions will be called appropriately:
</para>
<programlisting><!-- example-begin boilerplate.c a -->
#include "filter.h"
GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT);
<!-- example-end boilerplate.c a --></programlisting>
</sect1>
<!-- ############ sect1 ############# -->
@ -198,14 +212,14 @@ U gst-template/gst-app/src/Makefile.am
<para>
For example:
</para>
<programlisting>
static GstElementDetails example_details = {
<programlisting><!-- example-begin boilerplate.c b -->
static GstElementDetails my_filter_details = {
"An example plugin",
"Example/FirstExample",
"Shows the basic structure of a plugin",
"your name &lt;your.name@your.isp&gt;"
};
</programlisting>
<!-- example-end boilerplate.c b --></programlisting>
<para>
The element details are registered with the plugin during
the <function>_base_init ()</function> function, which is part of
@ -213,17 +227,19 @@ static GstElementDetails example_details = {
should be set for this GObject in the function where you register
the type with Glib.
</para>
<programlisting>
<programlisting><!-- example-begin boilerplate.c c -->
static void
gst_my_filter_base_init (GstMyFilterClass *klass)
gst_my_filter_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
<!-- example-end boilerplate.c c -->
static GstElementDetails my_filter_details = {
[..]
};
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
[..]<!-- example-begin boilerplate.c d -->
gst_element_class_set_details (element_class, &amp;my_filter_details);
<!-- example-end boilerplate.c d -->
}
</programlisting>
</sect1>
@ -258,7 +274,7 @@ gst_my_filter_base_init (GstMyFilterClass *klass)
<para>
For example:
</para>
<programlisting>
<programlisting><!-- example-begin boilerplate.c e -->
static GstStaticPadTemplate sink_factory =
GST_STATIC_PAD_TEMPLATE (
"sink",
@ -266,6 +282,16 @@ GST_STATIC_PAD_TEMPLATE (
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("ANY")
);
<!-- example-end boilerplate.c e -->
<!-- example-begin boilerplate.c f --><!--
static GstStaticPadTemplate src_factory =
GST_STATIC_PAD_TEMPLATE (
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("ANY")
);
--><!-- example-end boilerplate.c f -->
</programlisting>
<para>
Those pad templates are registered during the
@ -284,18 +310,30 @@ static GstStaticPadTemplate sink_factory = [..],
src_factory = [..];
static void
gst_my_filter_base_init (GstMyFilterClass *klass)
gst_my_filter_base_init (gpointer klass)
{
[..]
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
<!-- example-begin boilerplate.c g -->
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&amp;src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&amp;sink_factory));
[..]
}
</programlisting>
<!-- example-end boilerplate.c g -->
<!-- example-begin boilerplate.c h --><!--
static void
gst_my_filter_class_init (GstMyFilterClass * klass)
{
}
static void
gst_my_filter_init (GstMyFilter * filter)
{
}
#include "register.func"
--><!-- example-end boilerplate.c h --></programlisting>
<para>
The last argument in a template is its type
or list of supported types. In this example, we use 'ANY', which means
@ -362,7 +400,7 @@ GST_STATIC_PAD_TEMPLATE (
Also, in this function, any supported element type in the plugin should
be registered.
</para>
<programlisting>
<programlisting><!-- example-begin register.func -->
static gboolean
plugin_init (GstPlugin *plugin)
{
@ -382,7 +420,7 @@ GST_PLUGIN_DEFINE (
"GStreamer",
"http://gstreamer.net/"
)
</programlisting>
<!-- example-end register.func --></programlisting>
<para>
Note that the information returned by the plugin_init() function will be
cached in a central registry. For this reason, it is important that the

View file

@ -10,61 +10,117 @@
one buffer will go out, too. Below is a very simple implementation of
a chain function:
</para>
<programlisting>
static void
gst_my_filter_chain (GstPad *pad,
GstData *data)
<programlisting><!-- example-begin chain.c a --><!--
#include "init.func"
#include "caps.func"
static gboolean
gst_my_filter_event (GstPad * pad, GstEvent * event)
{
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstBuffer *buf = GST_BUFFER (data);
return gst_pad_event_default (pad, event);
}
--><!-- example-end chain.c a -->
<!-- example-begin chain.c b -->
static GstFlowReturn
gst_my_filter_chain (GstPad *pad,
GstBuffer *buf)
{
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
if (!filter->silent)
g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf));
gst_pad_push (filter->srcpad, GST_DATA (buf));
return gst_pad_push (filter->srcpad, buf);
}
</programlisting>
<!-- example-end chain.c b -->
<!-- example-begin chain.c c --><!--
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 chain.c c --></programlisting>
<para>
Obviously, the above doesn't do much useful. Instead of printing that the
data is in, you would normally process the data there. Remember, however,
that buffers are not always writable. In more advanced elements (the ones
that do event processing), the incoming data might not even be a buffer.
that do event processing), you may want to additionally specify an event
handling function, which will be called when stream-events are sent (such
as end-of-stream, discontinuities, tags, etc.).
</para>
<programlisting>
static void
gst_my_filter_chain (GstPad *pad,
GstData *data)
gst_my_filter_init (GstMyFilter * filter)
{
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstBuffer *buf, *outbuf;
[..]
gst_pad_set_event_function (filter-&gt;sinkpad,
gst_my_filter_event);
[..]
}
<!-- example-begin chain2.c a --><!--
#include "init.func"
#include "caps.func"
#include "chain.func"
--><!-- example-end chain2.c a -->
<!-- example-begin chain.func a --><!--
static void
gst_my_filter_stop_processing (GstMyFilter * filter)
{
}
if (GST_IS_EVENT (data)) {
GstEvent *event = GST_EVENT (data);
static GstBuffer *
gst_my_filter_process_data (GstMyFilter * filter, const GstBuffer * buf)
{
return NULL;
}
--><!-- example-end chain.func a -->
<!-- example-begin chain.func b -->
static gboolean
gst_my_filter_event (GstPad *pad,
GstEvent *event)
{
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
/* end-of-stream, we should close down all stream leftovers here */
gst_my_filter_stop_processing (filter);
/* fall-through to default event handling */
default:
gst_pad_event_default (pad, event);
break;
}
return;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
/* end-of-stream, we should close down all stream leftovers here */
gst_my_filter_stop_processing (filter);
break;
default:
break;
}
buf = GST_BUFFER (data);
outbuf = gst_my_filter_process_data (buf);
return gst_pad_event_default (pad, event);
}
static GstFlowReturn
gst_my_filter_chain (GstPad *pad,
GstBuffer *buf)
{
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
GstBuffer *outbuf;
outbuf = gst_my_filter_process_data (filter, buf);
gst_buffer_unref (buf);
if (!outbuf) {
/* something went wrong - signal an error */
gst_element_error (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
return;
GST_ELEMENT_ERROR (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
return GST_FLOW_ERROR;
}
gst_pad_push (filter->srcpad, GST_DATA (outbuf));
return gst_pad_push (filter->srcpad, outbuf);
}
</programlisting>
<!-- example-end chain.func b -->
<!-- example-begin chain2.c b --><!--
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 chain2.c b --></programlisting>
<para>
In some cases, it might be useful for an element to have control over the
input data rate, too. In that case, you probably want to write a so-called

View file

@ -26,12 +26,65 @@
that, you have to register the pad with the element. This happens like
this:
</para>
<programlisting>
static GstPadLinkReturn gst_my_filter_link (GstPad *pad,
const GstCaps *caps);
<programlisting><!-- example-begin init.func a --><!--
#include "filter.h"
#include &lt;string.h&gt;
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 GstCaps * gst_my_filter_getcaps (GstPad *pad);
static void gst_my_filter_chain (GstPad *pad,
GstData *data);
static GstFlowReturn gst_my_filter_chain (GstPad *pad,
GstBuffer *buf);
<!-- example-end init.func b -->
<!-- example-begin init.func c --><!--
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)
@ -41,20 +94,27 @@ gst_my_filter_init (GstMyFilter *filter)
/* pad through which data comes in to the element */
filter-&gt;sinkpad = gst_pad_new_from_template (
gst_element_class_get_pad_template (klass, "sink"), "sink");
gst_pad_set_link_function (filter-&gt;sinkpad, gst_my_filter_link);
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_event_function (filter-&gt;sinkpad, gst_my_filter_event);
--><!-- example-end init.func e -->
<!-- example-begin init.func f -->
gst_element_add_pad (GST_ELEMENT (filter), filter-&gt;sinkpad);
/* 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_link_function (filter-&gt;srcpad, gst_my_filter_link);
gst_pad_set_setcaps_function (filter-&gt;srcpad, gst_my_filter_setcaps);
gst_pad_set_getcaps_function (filter-&gt;srcpad, gst_my_filter_getcaps);
gst_element_add_pad (GST_ELEMENT (filter), filter-&gt;srcpad);
[..]
/* properties initial value */
filter->silent = FALSE;
}
</programlisting>
<!-- example-end init.func f --></programlisting>
<sect1 id="section-pads-linkfn" xreflabel="The link function">
<title>The link function</title>
@ -72,10 +132,10 @@ gst_my_filter_init (GstMyFilter *filter)
If the element responds positively towards the streamtype, that type
will be used on the pad. An example:
</para>
<programlisting>
static GstPadLinkReturn
gst_my_filter_link (GstPad *pad,
const GstCaps *caps)
<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_pad_get_parent (pad));
@ -97,7 +157,7 @@ gst_my_filter_link (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_try_set_caps (otherpad, gst_caps_copy (caps));
ret = gst_pad_set_caps (otherpad, gst_caps_copy (caps));
if (GST_PAD_LINK_FAILED (ret))
return ret;
@ -111,7 +171,7 @@ gst_my_filter_link (GstPad *pad,
return ret;
}
</programlisting>
<!-- example-end caps.func a --></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
@ -153,7 +213,7 @@ gst_my_filter_link (GstPad *pad,
specified on the other pad) on both pads. It explains how a
<function>_getcaps ()</function> can be used to do this.
</para>
<programlisting>
<programlisting><!-- example-begin caps.func b -->
static GstCaps *
gst_my_filter_getcaps (GstPad *pad)
{
@ -161,7 +221,7 @@ gst_my_filter_getcaps (GstPad *pad)
GstPad *otherpad = (pad == filter-&gt;srcpad) ? filter-&gt;sinkpad :
filter-&gt;srcpad;
GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps;
gint n;
gint i;
if (gst_caps_is_empty (othercaps))
return othercaps;
@ -174,49 +234,36 @@ gst_my_filter_getcaps (GstPad *pad)
gst_structure_remove_field (structure, "rate");
}
caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
gst_caps_free (othercaps);
gst_caps_unref (othercaps);
return caps;
}
</programlisting>
<!-- example-end caps.func b --></programlisting>
</sect1>
<!-- example-begin pads.c --><!--
#include "init.func"
#include "caps.func"
<sect1 id="section-pads-explicitcaps" xreflabel="Explicit caps">
<title>Explicit caps</title>
<para>
Obviously, many elements will not need the complex mechanism described in
the previous sections, because they are much simpler than that.
Such elements only support one format, or their format
is fixed but the contents of the format depend on the stream or something
else. In those cases, <emphasis>explicit caps</emphasis> are an easy way
of handling caps. Explicit caps are an easy way of specifying one, fixed,
supported format on a pad. Pads using explicit caps do not implement their
own <function>_getcaps ()</function> or <function>_link ()</function>
functions. When the exact format is known, an elements uses
<function>gst_pad_set_explicit_caps ()</function> to specify the exact
format. This is very useful for demuxers, for example.
</para>
<programlisting>
static void
gst_my_filter_init (GstMyFilter *filter)
static gboolean
gst_my_filter_event (GstPad * pad, GstEvent * event)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
[..]
filter-&gt;srcpad = gst_pad_new_from_template (
gst_element_class_get_pad_template (klass, "src"), "src");
gst_pad_use_explicit_caps (filter-&gt;srcpad);
[..]
return gst_pad_event_default (pad, event);
}
static void
gst_my_filter_somefunction (GstMyFilter *filter)
static GstFlowReturn
gst_my_filter_chain (GstPad * pad, GstBuffer * buf)
{
GstCaps *caps = ..;
[..]
gst_pad_set_explicit_caps (filter-&gt;srcpad, caps);
[..]
return gst_pad_push (GST_MY_FILTER (GST_OBJECT_PARENT (pad))->srcpad, buf);
}
</programlisting>
</sect1>
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>

View file

@ -12,7 +12,19 @@
and can then fill in the value or take action required for that property
to change value internally.
</para>
<programlisting>
<programlisting><!-- example-begin properties.c a --><!--
#include "filter.h"
GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT);
static void
gst_my_filter_base_init (gpointer klass)
{
}
static void
gst_my_filter_init (GstMyFilter * filter)
{
}
--><!-- example-end properties.c a -->
<!-- example-begin properties.c b -->
/* properties */
enum {
ARG_0,
@ -82,7 +94,10 @@ gst_my_filter_get_property (GObject *object,
break;
}
}
</programlisting>
<!-- example-end properties.c b -->
<!-- example-begin properties.c c --><!--
#include "register.func"
--><!-- example-end properties.c c --></programlisting>
<para>
The above is a very simple example of how arguments are used. Graphical
applications - for example GStreamer Editor - will use these properties

View file

@ -1,7 +1,5 @@
<chapter id="chapter-statemanage-states">
<title>
What are states?
</title>
<title>What are states?</title>
<para>
A state describes whether the element instance is initialized, whether it
is ready to transfer data and whether it is currently handling data. There
@ -55,9 +53,7 @@
</para>
<sect1 id="section-statemanage-filters">
<title>
Managing filter state
</title>
<title>Managing filter state</title>
<para>
An element can be notified of state changes through a virtual function
pointer. Inside this function, the element can initialize any sort of
@ -79,7 +75,24 @@ gst_my_filter_class_init (GstMyFilterClass *klass)
element_class->change_state = gst_my_filter_change_state;
}
<!-- example-begin state.c a --><!--
#include "init.func"
#include "caps.func"
#include "chain.func"
#include "state.func"
--><!-- example-end state.c a -->
<!-- example-begin state.func a --><!--
static gboolean
gst_my_filter_allocate_memory (GstMyFilter * filter)
{
return TRUE;
}
static void
gst_my_filter_free_memory (GstMyFilter * filter)
{
}
--><!-- example-end state.func a -->
<!-- example-begin state.func b -->
static GstElementStateReturn
gst_my_filter_change_state (GstElement *element)
{
@ -97,11 +110,12 @@ gst_my_filter_change_state (GstElement *element)
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
change_state, (element), GST_STATE_SUCCESS);
}
</programlisting>
<!-- example-end state.func b -->
<!-- example-begin state.c b --><!--
#include "register.func"
--><!-- example-end state.c b --></programlisting>
</sect1>
</chapter>

View file

@ -63,25 +63,71 @@
the pipeline and make sure it doesn't crash.
</para>
<programlisting>
<programlisting><!-- example-begin test.c -->
#include &lt;gst/gst.h&gt;
static gboolean
bus_call (GstBus *bus,
GstMessage *msg,
gpointer data)
{
GMainLoop *loop = data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print ("End-of-stream\n");
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *err;
gst_message_parse_error (msg, &amp;err, &amp;debug);
g_free (debug);
g_print ("Error: %s\n", err->message);
g_error_free (err);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
gint
main (gint arcg,
main (gint argc,
gchar *argv[])
{
GstElement *pipeline, *filesrc, *decoder, *filter, *sink;
GMainLoop *loop;
/* initialization */
gst_init (&amp;argc, &amp;argv);
loop = g_main_loop_new (NULL, FALSE);
/* create elements */
pipeline = gst_pipeline_new ("my_pipeline");
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
bus_call, loop);
filesrc = gst_element_factory_make ("filesrc", "my_filesource");
decoder = gst_element_factory_make ("mad", "my_decoder");
filter = gst_element_factory_make ("my_filter", "my_filter");
sink = gst_element_factory_make ("osssink", "audiosink");
if (!sink || !decoder) {
g_print ("Decoder or output could not be found - check your install\n");
return -1;
} else if (!filter) {
g_print ("Your self-written filter could not be found. Make sure it "
"is installed correctly in $(libdir)/gstreamer-0.9/ and that "
"you've ran gst-register-0.9 to register it. Check availability "
"of the plugin afterwards using \"gst-inspect-0.9 my_filter\"");
return -1;
}
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
@ -91,7 +137,7 @@ main (gint arcg,
/* run */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
while (gst_bin_iterate (GST_BIN (pipeline)));
g_main_loop_run (loop);
/* clean up */
gst_element_set_state (pipeline, GST_STATE_NULL);
@ -99,5 +145,5 @@ main (gint arcg,
return 0;
}
</programlisting>
<!-- example-end test.c --></programlisting>
</chapter>

View file

@ -1,9 +0,0 @@
<!-- ############ chapter ############# -->
<chapter id="chapter-other-autoplugger" xreflabel="Writing an Autoplugger">
<title>Writing an Autoplugger</title>
<para>
FIXME: write.
</para>
</chapter>

View file

@ -36,10 +36,10 @@
<!ENTITY OTHER_ONETON SYSTEM "other-oneton.xml">
<!ENTITY OTHER_NTOONE SYSTEM "other-ntoone.xml">
<!ENTITY OTHER_NTON SYSTEM "other-nton.xml">
<!ENTITY OTHER_AUTOPLUGGER SYSTEM "other-autoplugger.xml">
<!ENTITY OTHER_MANAGER SYSTEM "other-manager.xml">
<!ENTITY APPENDIX_CHECKLIST SYSTEM "appendix-checklist.xml">
<!ENTITY APPENDIX_PORTING SYSTEM "appendix-porting.xml">
<!ENTITY APPENDIX_LICENSING SYSTEM "appendix-licensing.xml">
<!ENTITY APPENDIX_PYTHON SYSTEM "appendix-python.xml">
@ -172,7 +172,6 @@
&OTHER_ONETON;
&OTHER_NTOONE;
&OTHER_NTON;
&OTHER_AUTOPLUGGER;
&OTHER_MANAGER;
</part>
@ -187,6 +186,7 @@
</partintro>
&APPENDIX_CHECKLIST;
&APPENDIX_PORTING;
&APPENDIX_LICENSING;
&APPENDIX_PYTHON;
</part>

View file

@ -17,6 +17,7 @@ dirs = \
cutter \
pingpong \
manual \
pwg \
retag
SUBDIRS = $(dirs) \

66
examples/pwg/Makefile.am Normal file
View file

@ -0,0 +1,66 @@
INCLUDES = $(GST_OBJ_CFLAGS) \
-DVERSION="\"0.0.1\""
libboilerplate_la_SOURCES = boilerplate.c
libpads_la_SOURCES = pads.c
libchain_la_SOURCES = chain.c
libchain2_la_SOURCES = chain2.c
libstate_la_SOURCES = state.c
libproperties_la_SOURCES = properties.c
EXTRA_DIST = extract.pl
EXAMPLES = \
libboilerplate.la \
libpads.la \
libchain.la \
libchain2.la \
libstate.la \
libproperties.la
EXAMPLE_APPS = \
test
filter.h register.func: $(top_srcdir)/docs/pwg/building-boiler.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-boiler.xml
boilerplate.c: $(top_srcdir)/docs/pwg/building-boiler.xml filter.h register.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-boiler.xml
caps.func init.func: $(top_srcdir)/docs/pwg/building-pads.xml filter.h
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-pads.xml
pads.c: $(top_srcdir)/docs/pwg/building-pads.xml register.func caps.func init.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-pads.xml
chain.func: $(top_srcdir)/docs/pwg/building-chainfn.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-chainfn.xml
chain.c chain2.c: $(top_srcdir)/docs/pwg/building-chainfn.xml register.func caps.func init.func chain.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-chainfn.xml
state.func: $(top_srcdir)/docs/pwg/building-state.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-state.xml
state.c: $(top_srcdir)/docs/pwg/building-state.xml register.func caps.func init.func chain.func state.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-state.xml
properties.c: $(top_srcdir)/docs/pwg/building-props.xml filter.h register.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-props.xml
test.c: $(top_srcdir)/docs/pwg/building-testapp.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-testapp.xml
noinst_PROGRAMS = $(EXAMPLE_APPS)
noinst_LTLIBRARIES = $(EXAMPLES)
LDADD = $(GST_OBJ_LIBS)

78
examples/pwg/extract.pl Executable file
View file

@ -0,0 +1,78 @@
#!/usr/bin/perl
# extract code fragments from xml program listings
# first argument: source code file to find
# second argument: xml files to extract code from
# main
# decodes xml by translating &amp; &lt; &gt; back to what they should be
# and also ignore
# <![CDATA[ and ]]> and <!-- and -->
sub
xml_decode ($)
{
my $input = shift;
$input =~ s/\&amp;/&/g;
$input =~ s/&lt;/</g;
$input =~ s/&gt;/>/g;
if ($input =~ /<!\[CDATA\[/) { $input = ""; }
if ($input =~ /]]>/) { $input = ""; }
if ($input =~ /<!--/) { $input = ""; }
if ($input =~ /-->/) { $input = ""; }
#print "Returning line $input";
return $input;
}
# main
my $output = shift @ARGV;
$found = 0;
%blocks = ();
foreach $file (@ARGV)
{
open FILE, $file or die "Cannot open file $file";
while ($line = <FILE>)
{
if ($line =~ /<!-- example-begin $output (.*?)-->/)
{
$found = 1;
$block_id = $1;
$block = "\n/*** block $block_id from $file ***/\n";
print "Extracting $output block $block_id from $file\n";
while ($line = <FILE>)
{
if ($line =~ /<!-- example-end $output (.*?)-->/)
{
last;
}
$block .= xml_decode ($line);
}
$blocks{$block_id} = $block;
}
}
}
if (!$found)
{
print "Could not find $output example !\n";
exit(1);
}
# now output all the blocks in the right order
open OUTPUT, ">$output";
@block_ids = keys %blocks;
foreach $block_id (sort @block_ids)
{
print "Writing $output block $block_id\n";
print OUTPUT $blocks{$block_id};
}
close OUTPUT;

View file

@ -17,6 +17,7 @@ dirs = \
cutter \
pingpong \
manual \
pwg \
retag
SUBDIRS = $(dirs) \

View file

@ -0,0 +1,66 @@
INCLUDES = $(GST_OBJ_CFLAGS) \
-DVERSION="\"0.0.1\""
libboilerplate_la_SOURCES = boilerplate.c
libpads_la_SOURCES = pads.c
libchain_la_SOURCES = chain.c
libchain2_la_SOURCES = chain2.c
libstate_la_SOURCES = state.c
libproperties_la_SOURCES = properties.c
EXTRA_DIST = extract.pl
EXAMPLES = \
libboilerplate.la \
libpads.la \
libchain.la \
libchain2.la \
libstate.la \
libproperties.la
EXAMPLE_APPS = \
test
filter.h register.func: $(top_srcdir)/docs/pwg/building-boiler.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-boiler.xml
boilerplate.c: $(top_srcdir)/docs/pwg/building-boiler.xml filter.h register.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-boiler.xml
caps.func init.func: $(top_srcdir)/docs/pwg/building-pads.xml filter.h
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-pads.xml
pads.c: $(top_srcdir)/docs/pwg/building-pads.xml register.func caps.func init.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-pads.xml
chain.func: $(top_srcdir)/docs/pwg/building-chainfn.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-chainfn.xml
chain.c chain2.c: $(top_srcdir)/docs/pwg/building-chainfn.xml register.func caps.func init.func chain.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-chainfn.xml
state.func: $(top_srcdir)/docs/pwg/building-state.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-state.xml
state.c: $(top_srcdir)/docs/pwg/building-state.xml register.func caps.func init.func chain.func state.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-state.xml
properties.c: $(top_srcdir)/docs/pwg/building-props.xml filter.h register.func
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-props.xml
test.c: $(top_srcdir)/docs/pwg/building-testapp.xml
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/pwg/building-testapp.xml
noinst_PROGRAMS = $(EXAMPLE_APPS)
noinst_LTLIBRARIES = $(EXAMPLES)
LDADD = $(GST_OBJ_LIBS)

View file

@ -0,0 +1,78 @@
#!/usr/bin/perl
# extract code fragments from xml program listings
# first argument: source code file to find
# second argument: xml files to extract code from
# main
# decodes xml by translating &amp; &lt; &gt; back to what they should be
# and also ignore
# <![CDATA[ and ]]> and <!-- and -->
sub
xml_decode ($)
{
my $input = shift;
$input =~ s/\&amp;/&/g;
$input =~ s/&lt;/</g;
$input =~ s/&gt;/>/g;
if ($input =~ /<!\[CDATA\[/) { $input = ""; }
if ($input =~ /]]>/) { $input = ""; }
if ($input =~ /<!--/) { $input = ""; }
if ($input =~ /-->/) { $input = ""; }
#print "Returning line $input";
return $input;
}
# main
my $output = shift @ARGV;
$found = 0;
%blocks = ();
foreach $file (@ARGV)
{
open FILE, $file or die "Cannot open file $file";
while ($line = <FILE>)
{
if ($line =~ /<!-- example-begin $output (.*?)-->/)
{
$found = 1;
$block_id = $1;
$block = "\n/*** block $block_id from $file ***/\n";
print "Extracting $output block $block_id from $file\n";
while ($line = <FILE>)
{
if ($line =~ /<!-- example-end $output (.*?)-->/)
{
last;
}
$block .= xml_decode ($line);
}
$blocks{$block_id} = $block;
}
}
}
if (!$found)
{
print "Could not find $output example !\n";
exit(1);
}
# now output all the blocks in the right order
open OUTPUT, ">$output";
@block_ids = keys %blocks;
foreach $block_id (sort @block_ids)
{
print "Writing $output block $block_id\n";
print OUTPUT $blocks{$block_id};
}
close OUTPUT;