mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +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>
|
||||
|
||||
* docs/manual/advanced-autoplugging.xml:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
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">
|
||||
<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 <gst/gst.h>
|
||||
|
||||
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 <your.name@your.isp>"
|
||||
};
|
||||
</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, &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 (&src_factory));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
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>
|
||||
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
|
||||
|
|
|
@ -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->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
|
||||
|
|
|
@ -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 <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 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->sinkpad = gst_pad_new_from_template (
|
||||
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_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);
|
||||
|
||||
/* pad through which data goes out of the element */
|
||||
filter->srcpad = gst_pad_new_from_template (
|
||||
gst_element_class_get_pad_template (klass, "src"), "src");
|
||||
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_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">
|
||||
<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->srcpad) ? filter->sinkpad :
|
||||
filter->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->srcpad = gst_pad_new_from_template (
|
||||
gst_element_class_get_pad_template (klass, "src"), "src");
|
||||
gst_pad_use_explicit_caps (filter->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->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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -63,25 +63,71 @@
|
|||
the pipeline and make sure it doesn't crash.
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
<programlisting><!-- example-begin test.c -->
|
||||
#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
|
||||
main (gint arcg,
|
||||
main (gint argc,
|
||||
gchar *argv[])
|
||||
{
|
||||
GstElement *pipeline, *filesrc, *decoder, *filter, *sink;
|
||||
GMainLoop *loop;
|
||||
|
||||
/* initialization */
|
||||
gst_init (&argc, &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>
|
||||
|
|
|
@ -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_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>
|
||||
|
|
|
@ -17,6 +17,7 @@ dirs = \
|
|||
cutter \
|
||||
pingpong \
|
||||
manual \
|
||||
pwg \
|
||||
retag
|
||||
|
||||
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 \
|
||||
pingpong \
|
||||
manual \
|
||||
pwg \
|
||||
retag
|
||||
|
||||
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