mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
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:
parent
edcaf2cd4f
commit
c9a37cf682
19 changed files with 720 additions and 155 deletions
23
ChangeLog
23
ChangeLog
|
@ -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>
|
2005-06-30 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||||
|
|
||||||
* docs/manual/advanced-autoplugging.xml:
|
* docs/manual/advanced-autoplugging.xml:
|
||||||
|
|
|
@ -701,6 +701,7 @@ examples/manual/Makefile
|
||||||
examples/mixer/Makefile
|
examples/mixer/Makefile
|
||||||
examples/pingpong/Makefile
|
examples/pingpong/Makefile
|
||||||
examples/plugins/Makefile
|
examples/plugins/Makefile
|
||||||
|
examples/pwg/Makefile
|
||||||
examples/queue/Makefile
|
examples/queue/Makefile
|
||||||
examples/queue2/Makefile
|
examples/queue2/Makefile
|
||||||
examples/queue3/Makefile
|
examples/queue3/Makefile
|
||||||
|
|
|
@ -118,6 +118,13 @@ gst_my_filter_some_interface_init (GstSomeInterface *iface)
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</sect1>
|
</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">
|
<sect1 id="section-iface-mixer" xreflabel="Mixer Interface">
|
||||||
<title>Mixer Interface</title>
|
<title>Mixer Interface</title>
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -143,8 +143,8 @@ plugin_init (GstPlugin *plugin)
|
||||||
typefind functions.
|
typefind functions.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Autoplugging will be discussed in great detail in the chapter called
|
Autoplugging has been discussed in great detail in the Application
|
||||||
<xref linkend="chapter-other-autoplugger"/>.
|
Development Manual.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
|
37
docs/pwg/appendix-porting.xml
Normal file
37
docs/pwg/appendix-porting.xml
Normal 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>
|
|
@ -134,40 +134,54 @@ U gst-template/gst-app/src/Makefile.am
|
||||||
|
|
||||||
<example id="ex-boiler-examine-h">
|
<example id="ex-boiler-examine-h">
|
||||||
<title>Example Plugin Header File</title>
|
<title>Example Plugin Header File</title>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin filter.h a -->
|
||||||
/* Definition of structure storing data for this element. */
|
#include <gst/gst.h>
|
||||||
typedef struct _GstExample GstExample;
|
|
||||||
|
|
||||||
struct _GstExample {
|
/* Definition of structure storing data for this element. */
|
||||||
GstElement 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. */
|
/* Standard definition defining a class for this element. */
|
||||||
typedef struct _GstExampleClass GstExampleClass;
|
typedef struct _GstMyFilterClass {
|
||||||
struct _GstExampleClass {
|
GstElementClass parent_class;
|
||||||
GstElementClass parent_class;
|
} GstMyFilterClass;
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard macros for defining types for this element. */
|
/* Standard macros for defining types for this element. */
|
||||||
#define GST_TYPE_EXAMPLE \
|
#define GST_TYPE_MY_FILTER \
|
||||||
(gst_example_get_type())
|
(gst_my_filter_get_type())
|
||||||
#define GST_EXAMPLE(obj) \
|
#define GST_MY_FILTER(obj) \
|
||||||
(G_TYPE_CHECK_CAST((obj),GST_TYPE_EXAMPLE,GstExample))
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MY_FILTER,GstMyFilter))
|
||||||
#define GST_EXAMPLE_CLASS(klass) \
|
#define GST_MY_FILTER_CLASS(klass) \
|
||||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EXAMPLE,GstExample))
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MY_FILTER,GstMyFilterClass))
|
||||||
#define GST_IS_EXAMPLE(obj) \
|
#define GST_IS_MY_FILTER(obj) \
|
||||||
(G_TYPE_CHECK_TYPE((obj),GST_TYPE_EXAMPLE))
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MY_FILTER))
|
||||||
#define GST_IS_EXAMPLE_CLASS(obj) \
|
#define GST_IS_MY_FILTER_CLASS(obj) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE))
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MY_FILTER))
|
||||||
|
|
||||||
/* Standard function returning type information. */
|
/* Standard function returning type information. */
|
||||||
GType gst_example_get_type (void);
|
GType gst_my_filter_get_type (void);
|
||||||
</programlisting>
|
<!-- example-end filter.h c --></programlisting>
|
||||||
</example>
|
</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>
|
||||||
|
|
||||||
<!-- ############ sect1 ############# -->
|
<!-- ############ sect1 ############# -->
|
||||||
|
@ -198,14 +212,14 @@ U gst-template/gst-app/src/Makefile.am
|
||||||
<para>
|
<para>
|
||||||
For example:
|
For example:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin boilerplate.c b -->
|
||||||
static GstElementDetails example_details = {
|
static GstElementDetails my_filter_details = {
|
||||||
"An example plugin",
|
"An example plugin",
|
||||||
"Example/FirstExample",
|
"Example/FirstExample",
|
||||||
"Shows the basic structure of a plugin",
|
"Shows the basic structure of a plugin",
|
||||||
"your name <your.name@your.isp>"
|
"your name <your.name@your.isp>"
|
||||||
};
|
};
|
||||||
</programlisting>
|
<!-- example-end boilerplate.c b --></programlisting>
|
||||||
<para>
|
<para>
|
||||||
The element details are registered with the plugin during
|
The element details are registered with the plugin during
|
||||||
the <function>_base_init ()</function> function, which is part of
|
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
|
should be set for this GObject in the function where you register
|
||||||
the type with Glib.
|
the type with Glib.
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin boilerplate.c c -->
|
||||||
static void
|
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 = {
|
static GstElementDetails my_filter_details = {
|
||||||
[..]
|
[..]
|
||||||
};
|
};
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
|
||||||
|
|
||||||
[..]
|
[..]<!-- example-begin boilerplate.c d -->
|
||||||
gst_element_class_set_details (element_class, &my_filter_details);
|
gst_element_class_set_details (element_class, &my_filter_details);
|
||||||
|
<!-- example-end boilerplate.c d -->
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
@ -258,7 +274,7 @@ gst_my_filter_base_init (GstMyFilterClass *klass)
|
||||||
<para>
|
<para>
|
||||||
For example:
|
For example:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin boilerplate.c e -->
|
||||||
static GstStaticPadTemplate sink_factory =
|
static GstStaticPadTemplate sink_factory =
|
||||||
GST_STATIC_PAD_TEMPLATE (
|
GST_STATIC_PAD_TEMPLATE (
|
||||||
"sink",
|
"sink",
|
||||||
|
@ -266,6 +282,16 @@ GST_STATIC_PAD_TEMPLATE (
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("ANY")
|
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>
|
</programlisting>
|
||||||
<para>
|
<para>
|
||||||
Those pad templates are registered during the
|
Those pad templates are registered during the
|
||||||
|
@ -284,18 +310,30 @@ static GstStaticPadTemplate sink_factory = [..],
|
||||||
src_factory = [..];
|
src_factory = [..];
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_my_filter_base_init (GstMyFilterClass *klass)
|
gst_my_filter_base_init (gpointer klass)
|
||||||
{
|
{
|
||||||
[..]
|
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
[..]
|
||||||
|
<!-- example-begin boilerplate.c g -->
|
||||||
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));
|
||||||
gst_element_class_add_pad_template (element_class,
|
gst_element_class_add_pad_template (element_class,
|
||||||
gst_static_pad_template_get (&sink_factory));
|
gst_static_pad_template_get (&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>
|
<para>
|
||||||
The last argument in a template is its type
|
The last argument in a template is its type
|
||||||
or list of supported types. In this example, we use 'ANY', which means
|
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
|
Also, in this function, any supported element type in the plugin should
|
||||||
be registered.
|
be registered.
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin register.func -->
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_init (GstPlugin *plugin)
|
plugin_init (GstPlugin *plugin)
|
||||||
{
|
{
|
||||||
|
@ -382,7 +420,7 @@ GST_PLUGIN_DEFINE (
|
||||||
"GStreamer",
|
"GStreamer",
|
||||||
"http://gstreamer.net/"
|
"http://gstreamer.net/"
|
||||||
)
|
)
|
||||||
</programlisting>
|
<!-- example-end register.func --></programlisting>
|
||||||
<para>
|
<para>
|
||||||
Note that the information returned by the plugin_init() function will be
|
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
|
cached in a central registry. For this reason, it is important that the
|
||||||
|
|
|
@ -10,61 +10,117 @@
|
||||||
one buffer will go out, too. Below is a very simple implementation of
|
one buffer will go out, too. Below is a very simple implementation of
|
||||||
a chain function:
|
a chain function:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin chain.c a --><!--
|
||||||
static void
|
#include "init.func"
|
||||||
gst_my_filter_chain (GstPad *pad,
|
#include "caps.func"
|
||||||
GstData *data)
|
static gboolean
|
||||||
|
gst_my_filter_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
|
return gst_pad_event_default (pad, event);
|
||||||
GstBuffer *buf = GST_BUFFER (data);
|
}
|
||||||
|
--><!-- 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)
|
if (!filter->silent)
|
||||||
g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf));
|
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>
|
<para>
|
||||||
Obviously, the above doesn't do much useful. Instead of printing that the
|
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,
|
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 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>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
static void
|
static void
|
||||||
gst_my_filter_chain (GstPad *pad,
|
gst_my_filter_init (GstMyFilter * filter)
|
||||||
GstData *data)
|
|
||||||
{
|
{
|
||||||
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
|
[..]
|
||||||
GstBuffer *buf, *outbuf;
|
gst_pad_set_event_function (filter->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)) {
|
static GstBuffer *
|
||||||
GstEvent *event = GST_EVENT (data);
|
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)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
/* end-of-stream, we should close down all stream leftovers here */
|
/* end-of-stream, we should close down all stream leftovers here */
|
||||||
gst_my_filter_stop_processing (filter);
|
gst_my_filter_stop_processing (filter);
|
||||||
/* fall-through to default event handling */
|
break;
|
||||||
default:
|
default:
|
||||||
gst_pad_event_default (pad, event);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = GST_BUFFER (data);
|
return gst_pad_event_default (pad, event);
|
||||||
outbuf = gst_my_filter_process_data (buf);
|
}
|
||||||
|
|
||||||
|
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);
|
gst_buffer_unref (buf);
|
||||||
if (!outbuf) {
|
if (!outbuf) {
|
||||||
/* something went wrong - signal an error */
|
/* something went wrong - signal an error */
|
||||||
gst_element_error (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
|
GST_ELEMENT_ERROR (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
|
||||||
return;
|
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>
|
<para>
|
||||||
In some cases, it might be useful for an element to have control over the
|
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
|
input data rate, too. In that case, you probably want to write a so-called
|
||||||
|
|
|
@ -26,12 +26,65 @@
|
||||||
that, you have to register the pad with the element. This happens like
|
that, you have to register the pad with the element. This happens like
|
||||||
this:
|
this:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin init.func a --><!--
|
||||||
static GstPadLinkReturn gst_my_filter_link (GstPad *pad,
|
#include "filter.h"
|
||||||
const GstCaps *caps);
|
#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 GstCaps * gst_my_filter_getcaps (GstPad *pad);
|
static GstCaps * gst_my_filter_getcaps (GstPad *pad);
|
||||||
static void gst_my_filter_chain (GstPad *pad,
|
static GstFlowReturn gst_my_filter_chain (GstPad *pad,
|
||||||
GstData *data);
|
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
|
static void
|
||||||
gst_my_filter_init (GstMyFilter *filter)
|
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 */
|
/* pad through which data comes in to the element */
|
||||||
filter->sinkpad = gst_pad_new_from_template (
|
filter->sinkpad = gst_pad_new_from_template (
|
||||||
gst_element_class_get_pad_template (klass, "sink"), "sink");
|
gst_element_class_get_pad_template (klass, "sink"), "sink");
|
||||||
gst_pad_set_link_function (filter->sinkpad, gst_my_filter_link);
|
gst_pad_set_setcaps_function (filter->sinkpad, gst_my_filter_setcaps);
|
||||||
gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps);
|
gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps);
|
||||||
gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain);
|
gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain);
|
||||||
|
<!-- example-end init.func d -->
|
||||||
|
<!-- example-begin init.func e --><!--
|
||||||
|
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);
|
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
|
||||||
|
|
||||||
/* pad through which data goes out of the element */
|
/* pad through which data goes out of the element */
|
||||||
filter->srcpad = gst_pad_new_from_template (
|
filter->srcpad = gst_pad_new_from_template (
|
||||||
gst_element_class_get_pad_template (klass, "src"), "src");
|
gst_element_class_get_pad_template (klass, "src"), "src");
|
||||||
gst_pad_set_link_function (filter->srcpad, gst_my_filter_link);
|
gst_pad_set_setcaps_function (filter->srcpad, gst_my_filter_setcaps);
|
||||||
gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps);
|
gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps);
|
||||||
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
|
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
|
||||||
[..]
|
|
||||||
|
/* properties initial value */
|
||||||
|
filter->silent = FALSE;
|
||||||
}
|
}
|
||||||
</programlisting>
|
<!-- example-end init.func f --></programlisting>
|
||||||
|
|
||||||
<sect1 id="section-pads-linkfn" xreflabel="The link function">
|
<sect1 id="section-pads-linkfn" xreflabel="The link function">
|
||||||
<title>The link function</title>
|
<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
|
If the element responds positively towards the streamtype, that type
|
||||||
will be used on the pad. An example:
|
will be used on the pad. An example:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin caps.func a -->
|
||||||
static GstPadLinkReturn
|
static gboolean
|
||||||
gst_my_filter_link (GstPad *pad,
|
gst_my_filter_setcaps (GstPad *pad,
|
||||||
const GstCaps *caps)
|
GstCaps *caps)
|
||||||
{
|
{
|
||||||
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
||||||
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
|
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.
|
/* 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
|
* That means we can set the given caps unmodified on the next
|
||||||
* element, and use that negotiation return value as ours. */
|
* 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))
|
if (GST_PAD_LINK_FAILED (ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -111,7 +171,7 @@ gst_my_filter_link (GstPad *pad,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
</programlisting>
|
<!-- example-end caps.func a --></programlisting>
|
||||||
<para>
|
<para>
|
||||||
In here, we check the mimetype of the provided caps. Normally, you don't
|
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
|
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
|
specified on the other pad) on both pads. It explains how a
|
||||||
<function>_getcaps ()</function> can be used to do this.
|
<function>_getcaps ()</function> can be used to do this.
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting><!-- example-begin caps.func b -->
|
||||||
static GstCaps *
|
static GstCaps *
|
||||||
gst_my_filter_getcaps (GstPad *pad)
|
gst_my_filter_getcaps (GstPad *pad)
|
||||||
{
|
{
|
||||||
|
@ -161,7 +221,7 @@ gst_my_filter_getcaps (GstPad *pad)
|
||||||
GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad :
|
GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad :
|
||||||
filter->srcpad;
|
filter->srcpad;
|
||||||
GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps;
|
GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps;
|
||||||
gint n;
|
gint i;
|
||||||
|
|
||||||
if (gst_caps_is_empty (othercaps))
|
if (gst_caps_is_empty (othercaps))
|
||||||
return othercaps;
|
return othercaps;
|
||||||
|
@ -174,49 +234,36 @@ gst_my_filter_getcaps (GstPad *pad)
|
||||||
gst_structure_remove_field (structure, "rate");
|
gst_structure_remove_field (structure, "rate");
|
||||||
}
|
}
|
||||||
caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
|
caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
|
||||||
gst_caps_free (othercaps);
|
gst_caps_unref (othercaps);
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
</programlisting>
|
<!-- example-end caps.func b --></programlisting>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
<!-- example-begin pads.c --><!--
|
||||||
|
#include "init.func"
|
||||||
|
#include "caps.func"
|
||||||
|
|
||||||
<sect1 id="section-pads-explicitcaps" xreflabel="Explicit caps">
|
static gboolean
|
||||||
<title>Explicit caps</title>
|
gst_my_filter_event (GstPad * pad, GstEvent * event)
|
||||||
<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)
|
|
||||||
{
|
{
|
||||||
GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
|
return gst_pad_event_default (pad, event);
|
||||||
[..]
|
|
||||||
filter->srcpad = gst_pad_new_from_template (
|
|
||||||
gst_element_class_get_pad_template (klass, "src"), "src");
|
|
||||||
gst_pad_use_explicit_caps (filter->srcpad);
|
|
||||||
[..]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GstFlowReturn
|
||||||
gst_my_filter_somefunction (GstMyFilter *filter)
|
gst_my_filter_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstCaps *caps = ..;
|
return gst_pad_push (GST_MY_FILTER (GST_OBJECT_PARENT (pad))->srcpad, buf);
|
||||||
[..]
|
|
||||||
gst_pad_set_explicit_caps (filter->srcpad, caps);
|
|
||||||
[..]
|
|
||||||
}
|
}
|
||||||
</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>
|
</chapter>
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,19 @@
|
||||||
and can then fill in the value or take action required for that property
|
and can then fill in the value or take action required for that property
|
||||||
to change value internally.
|
to change value internally.
|
||||||
</para>
|
</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 */
|
/* properties */
|
||||||
enum {
|
enum {
|
||||||
ARG_0,
|
ARG_0,
|
||||||
|
@ -82,7 +94,10 @@ gst_my_filter_get_property (GObject *object,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</programlisting>
|
<!-- example-end properties.c b -->
|
||||||
|
<!-- example-begin properties.c c --><!--
|
||||||
|
#include "register.func"
|
||||||
|
--><!-- example-end properties.c c --></programlisting>
|
||||||
<para>
|
<para>
|
||||||
The above is a very simple example of how arguments are used. Graphical
|
The above is a very simple example of how arguments are used. Graphical
|
||||||
applications - for example GStreamer Editor - will use these properties
|
applications - for example GStreamer Editor - will use these properties
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<chapter id="chapter-statemanage-states">
|
<chapter id="chapter-statemanage-states">
|
||||||
<title>
|
<title>What are states?</title>
|
||||||
What are states?
|
|
||||||
</title>
|
|
||||||
<para>
|
<para>
|
||||||
A state describes whether the element instance is initialized, whether it
|
A state describes whether the element instance is initialized, whether it
|
||||||
is ready to transfer data and whether it is currently handling data. There
|
is ready to transfer data and whether it is currently handling data. There
|
||||||
|
@ -55,9 +53,7 @@
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect1 id="section-statemanage-filters">
|
<sect1 id="section-statemanage-filters">
|
||||||
<title>
|
<title>Managing filter state</title>
|
||||||
Managing filter state
|
|
||||||
</title>
|
|
||||||
<para>
|
<para>
|
||||||
An element can be notified of state changes through a virtual function
|
An element can be notified of state changes through a virtual function
|
||||||
pointer. Inside this function, the element can initialize any sort of
|
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;
|
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
|
static GstElementStateReturn
|
||||||
gst_my_filter_change_state (GstElement *element)
|
gst_my_filter_change_state (GstElement *element)
|
||||||
{
|
{
|
||||||
|
@ -97,11 +110,12 @@ gst_my_filter_change_state (GstElement *element)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
change_state, (element), GST_STATE_SUCCESS);
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
</programlisting>
|
<!-- example-end state.func b -->
|
||||||
|
<!-- example-begin state.c b --><!--
|
||||||
|
#include "register.func"
|
||||||
|
--><!-- example-end state.c b --></programlisting>
|
||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
|
@ -63,25 +63,71 @@
|
||||||
the pipeline and make sure it doesn't crash.
|
the pipeline and make sure it doesn't crash.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting><!-- example-begin test.c -->
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
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, &err, &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
|
gint
|
||||||
main (gint arcg,
|
main (gint argc,
|
||||||
gchar *argv[])
|
gchar *argv[])
|
||||||
{
|
{
|
||||||
GstElement *pipeline, *filesrc, *decoder, *filter, *sink;
|
GstElement *pipeline, *filesrc, *decoder, *filter, *sink;
|
||||||
|
GMainLoop *loop;
|
||||||
|
|
||||||
/* initialization */
|
/* initialization */
|
||||||
gst_init (&argc, &argv);
|
gst_init (&argc, &argv);
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
/* create elements */
|
/* create elements */
|
||||||
pipeline = gst_pipeline_new ("my_pipeline");
|
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");
|
filesrc = gst_element_factory_make ("filesrc", "my_filesource");
|
||||||
decoder = gst_element_factory_make ("mad", "my_decoder");
|
decoder = gst_element_factory_make ("mad", "my_decoder");
|
||||||
filter = gst_element_factory_make ("my_filter", "my_filter");
|
filter = gst_element_factory_make ("my_filter", "my_filter");
|
||||||
sink = gst_element_factory_make ("osssink", "audiosink");
|
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);
|
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||||
|
|
||||||
|
@ -91,7 +137,7 @@ main (gint arcg,
|
||||||
|
|
||||||
/* run */
|
/* run */
|
||||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
/* clean up */
|
/* clean up */
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
@ -99,5 +145,5 @@ main (gint arcg,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
</programlisting>
|
<!-- example-end test.c --></programlisting>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
|
|
||||||
<!-- ############ chapter ############# -->
|
|
||||||
|
|
||||||
<chapter id="chapter-other-autoplugger" xreflabel="Writing an Autoplugger">
|
|
||||||
<title>Writing an Autoplugger</title>
|
|
||||||
<para>
|
|
||||||
FIXME: write.
|
|
||||||
</para>
|
|
||||||
</chapter>
|
|
|
@ -36,10 +36,10 @@
|
||||||
<!ENTITY OTHER_ONETON SYSTEM "other-oneton.xml">
|
<!ENTITY OTHER_ONETON SYSTEM "other-oneton.xml">
|
||||||
<!ENTITY OTHER_NTOONE SYSTEM "other-ntoone.xml">
|
<!ENTITY OTHER_NTOONE SYSTEM "other-ntoone.xml">
|
||||||
<!ENTITY OTHER_NTON SYSTEM "other-nton.xml">
|
<!ENTITY OTHER_NTON SYSTEM "other-nton.xml">
|
||||||
<!ENTITY OTHER_AUTOPLUGGER SYSTEM "other-autoplugger.xml">
|
|
||||||
<!ENTITY OTHER_MANAGER SYSTEM "other-manager.xml">
|
<!ENTITY OTHER_MANAGER SYSTEM "other-manager.xml">
|
||||||
|
|
||||||
<!ENTITY APPENDIX_CHECKLIST SYSTEM "appendix-checklist.xml">
|
<!ENTITY APPENDIX_CHECKLIST SYSTEM "appendix-checklist.xml">
|
||||||
|
<!ENTITY APPENDIX_PORTING SYSTEM "appendix-porting.xml">
|
||||||
<!ENTITY APPENDIX_LICENSING SYSTEM "appendix-licensing.xml">
|
<!ENTITY APPENDIX_LICENSING SYSTEM "appendix-licensing.xml">
|
||||||
<!ENTITY APPENDIX_PYTHON SYSTEM "appendix-python.xml">
|
<!ENTITY APPENDIX_PYTHON SYSTEM "appendix-python.xml">
|
||||||
|
|
||||||
|
@ -172,7 +172,6 @@
|
||||||
&OTHER_ONETON;
|
&OTHER_ONETON;
|
||||||
&OTHER_NTOONE;
|
&OTHER_NTOONE;
|
||||||
&OTHER_NTON;
|
&OTHER_NTON;
|
||||||
&OTHER_AUTOPLUGGER;
|
|
||||||
&OTHER_MANAGER;
|
&OTHER_MANAGER;
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
|
@ -187,6 +186,7 @@
|
||||||
</partintro>
|
</partintro>
|
||||||
|
|
||||||
&APPENDIX_CHECKLIST;
|
&APPENDIX_CHECKLIST;
|
||||||
|
&APPENDIX_PORTING;
|
||||||
&APPENDIX_LICENSING;
|
&APPENDIX_LICENSING;
|
||||||
&APPENDIX_PYTHON;
|
&APPENDIX_PYTHON;
|
||||||
</part>
|
</part>
|
||||||
|
|
|
@ -17,6 +17,7 @@ dirs = \
|
||||||
cutter \
|
cutter \
|
||||||
pingpong \
|
pingpong \
|
||||||
manual \
|
manual \
|
||||||
|
pwg \
|
||||||
retag
|
retag
|
||||||
|
|
||||||
SUBDIRS = $(dirs) \
|
SUBDIRS = $(dirs) \
|
||||||
|
|
66
examples/pwg/Makefile.am
Normal file
66
examples/pwg/Makefile.am
Normal 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
78
examples/pwg/extract.pl
Executable 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 & < > back to what they should be
|
||||||
|
# and also ignore
|
||||||
|
# <![CDATA[ and ]]> and <!-- and -->
|
||||||
|
sub
|
||||||
|
xml_decode ($)
|
||||||
|
{
|
||||||
|
my $input = shift;
|
||||||
|
|
||||||
|
$input =~ s/\&/&/g;
|
||||||
|
$input =~ s/</</g;
|
||||||
|
$input =~ s/>/>/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;
|
|
@ -17,6 +17,7 @@ dirs = \
|
||||||
cutter \
|
cutter \
|
||||||
pingpong \
|
pingpong \
|
||||||
manual \
|
manual \
|
||||||
|
pwg \
|
||||||
retag
|
retag
|
||||||
|
|
||||||
SUBDIRS = $(dirs) \
|
SUBDIRS = $(dirs) \
|
||||||
|
|
66
tests/old/examples/pwg/Makefile.am
Normal file
66
tests/old/examples/pwg/Makefile.am
Normal 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
tests/old/examples/pwg/extract.pl
Executable file
78
tests/old/examples/pwg/extract.pl
Executable 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 & < > back to what they should be
|
||||||
|
# and also ignore
|
||||||
|
# <![CDATA[ and ]]> and <!-- and -->
|
||||||
|
sub
|
||||||
|
xml_decode ($)
|
||||||
|
{
|
||||||
|
my $input = shift;
|
||||||
|
|
||||||
|
$input =~ s/\&/&/g;
|
||||||
|
$input =~ s/</</g;
|
||||||
|
$input =~ s/>/>/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;
|
Loading…
Reference in a new issue