pwg: more updates for 1.0

This commit is contained in:
Wim Taymans 2012-09-27 14:42:07 +02:00
parent b527b0b498
commit bc76088811
3 changed files with 47 additions and 39 deletions

View file

@ -1,7 +1,7 @@
<!-- ############ chapter ############# --> <!-- ############ chapter ############# -->
<chapter id="chapter-building-args" xreflabel="Adding Arguments"> <chapter id="chapter-building-args" xreflabel="Adding Properties">
<title>Adding Arguments</title> <title>Adding Properties</title>
<para> <para>
The primary and most important way of controlling how an element behaves, The primary and most important way of controlling how an element behaves,
is through GObject properties. GObject properties are defined in the is through GObject properties. GObject properties are defined in the
@ -12,6 +12,14 @@
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>
<para>
You probably also want to keep an instance variable around
with the currently configured value of the property that you use in the
get and set functions.
Note that <classname>GObject</classname> will not automatically set your
instance variable to the default value, you will have to do that in the
<function>_init ()</function> function of your element.
</para>
<programlisting><!-- example-begin properties.c a --><!-- <programlisting><!-- example-begin properties.c a --><!--
#include "filter.h" #include "filter.h"
GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT); GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT);
@ -27,8 +35,8 @@ gst_my_filter_init (GstMyFilter * filter)
<!-- example-begin properties.c b --> <!-- example-begin properties.c b -->
/* properties */ /* properties */
enum { enum {
ARG_0, PROP_0,
ARG_SILENT PROP_SILENT
/* FILL ME */ /* FILL ME */
}; };
@ -46,15 +54,15 @@ gst_my_filter_class_init (GstMyFilterClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
/* define properties */
g_object_class_install_property (object_class, ARG_SILENT,
g_param_spec_boolean ("silent", "Silent",
"Whether to be very verbose or not",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* define virtual function pointers */ /* define virtual function pointers */
object_class->set_property = gst_my_filter_set_property; object_class->set_property = gst_my_filter_set_property;
object_class->get_property = gst_my_filter_get_property; object_class->get_property = gst_my_filter_get_property;
/* define properties */
g_object_class_install_property (object_class, PROP_SILENT,
g_param_spec_boolean ("silent", "Silent",
"Whether to be very verbose or not",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
} }
static void static void
@ -66,7 +74,7 @@ gst_my_filter_set_property (GObject *object,
GstMyFilter *filter = GST_MY_FILTER (object); GstMyFilter *filter = GST_MY_FILTER (object);
switch (prop_id) { switch (prop_id) {
case ARG_SILENT: case PROP_SILENT:
filter->silent = g_value_get_boolean (value); filter->silent = g_value_get_boolean (value);
g_print ("Silent argument was changed to %s\n", g_print ("Silent argument was changed to %s\n",
filter->silent ? "true" : "false"); filter->silent ? "true" : "false");
@ -86,7 +94,7 @@ gst_my_filter_get_property (GObject *object,
GstMyFilter *filter = GST_MY_FILTER (object); GstMyFilter *filter = GST_MY_FILTER (object);
switch (prop_id) { switch (prop_id) {
case ARG_SILENT: case PROP_SILENT:
g_value_set_boolean (value, filter->silent); g_value_set_boolean (value, filter->silent);
break; break;
default: default:
@ -99,10 +107,10 @@ gst_my_filter_get_property (GObject *object,
#include "register.func" #include "register.func"
--><!-- example-end properties.c c --></programlisting> --><!-- 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 properties are used. Graphical
applications - for example GStreamer Editor - will use these properties applications will use these properties and will display a
and will display a user-controllable widget with which these properties user-controllable widget with which these properties can be changed.
can be changed. This means that - for the property to be as user-friendly This means that - for the property to be as user-friendly
as possible - you should be as exact as possible in the definition of the as possible - you should be as exact as possible in the definition of the
property. Not only in defining ranges in between which valid properties property. Not only in defining ranges in between which valid properties
can be located (for integers, floats, etc.), but also in using very can be located (for integers, floats, etc.), but also in using very
@ -150,11 +158,11 @@ static void
gst_videotestsrc_class_init (GstvideotestsrcClass *klass) gst_videotestsrc_class_init (GstvideotestsrcClass *klass)
{ {
[..] [..]
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TYPE, g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PATTERN,
g_param_spec_enum ("pattern", "Pattern", g_param_spec_enum ("pattern", "Pattern",
"Type of test pattern to generate", "Type of test pattern to generate",
GST_TYPE_VIDEOTESTSRC_PATTERN, 1, G_PARAM_READWRITE | GST_TYPE_VIDEOTESTSRC_PATTERN, GST_VIDEOTESTSRC_SMPTE,
G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
[..] [..]
} }
</programlisting> </programlisting>

View file

@ -86,8 +86,8 @@
GstElement or some other class not built on top of a base class, you GstElement or some other class not built on top of a base class, you
will most likely have to implement your own state change function to will most likely have to implement your own state change function to
be notified of state changes. This is definitively necessary if your be notified of state changes. This is definitively necessary if your
plugin is a decoder or an encoder, as there are no base classes for plugin is a demuxer or a muxer, as there are no base classes for
decoders or encoders yet. muxers or demuxers yet.
</para> </para>
<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

View file

@ -4,7 +4,7 @@
<title>Building a Test Application</title> <title>Building a Test Application</title>
<para> <para>
Often, you will want to test your newly written plugin in an as small Often, you will want to test your newly written plugin in an as small
setting as possible. Usually, <filename>gst-launch</filename> is a setting as possible. Usually, <filename>gst-launch-1.0</filename> is a
good first step at testing a plugin. If you have not installed your good first step at testing a plugin. If you have not installed your
plugin in a directory that GStreamer searches, then you will need to plugin in a directory that GStreamer searches, then you will need to
set the plugin path. Either set GST_PLUGIN_PATH to the directory set the plugin path. Either set GST_PLUGIN_PATH to the directory
@ -12,10 +12,10 @@
If you based your plugin off of the gst-plugin template, then this If you based your plugin off of the gst-plugin template, then this
will look something like will look something like
<command> <command>
gst-launch --gst-plugin-path=$HOME/gst-template/gst-plugin/src/.libs TESTPIPELINE gst-launch-1.0 --gst-plugin-path=$HOME/gst-template/gst-plugin/src/.libs TESTPIPELINE
</command> </command>
However, you will often need more However, you will often need more
testing features than gst-launch can provide, such as seeking, events, testing features than gst-launch-1.0 can provide, such as seeking, events,
interactivity and more. Writing your own small testing program is the interactivity and more. Writing your own small testing program is the
easiest way to accomplish this. This section explains - in a few words easiest way to accomplish this. This section explains - in a few words
- how to do that. For a complete application development guide, see the - how to do that. For a complete application development guide, see the
@ -26,9 +26,9 @@
<para> <para>
At the start, you need to initialize the &GStreamer; core library by At the start, you need to initialize the &GStreamer; core library by
calling <function>gst_init ()</function>. You can alternatively call calling <function>gst_init ()</function>. You can alternatively call
<function>gst_init_with_popt_tables ()</function>, which will return <function>gst_init_get_option_group ()</function>, which will return
a pointer to popt tables. You can then use libpopt to handle the a pointer to GOptionGroup. You can then use GOption to handle the
given argument table, and this will finish the &GStreamer; initialization. initialization, and this will finish the &GStreamer; initialization.
</para> </para>
<para> <para>
@ -43,22 +43,19 @@
application. Also, you can use a <classname>fakesink</classname> application. Also, you can use a <classname>fakesink</classname>
element at the end of the pipeline to dump your data to the stdout element at the end of the pipeline to dump your data to the stdout
(in order to do this, set the <function>dump</function> property to (in order to do this, set the <function>dump</function> property to
TRUE). Lastly, you can use the <classname>efence</classname> element TRUE). Lastly, you can use valgrind to check for memory errors.
(indeed, an eletric fence memory debugger wrapper element) to check
for memory errors.
</para> </para>
<para> <para>
During linking, your test application can use fixation or filtered caps During linking, your test application can use filtered caps
as a way to drive a specific type of data to or from your element. This as a way to drive a specific type of data to or from your element. This
is a very simple and effective way of checking multiple types of input is a very simple and effective way of checking multiple types of input
and output in your element. and output in your element.
</para> </para>
<para> <para>
Running the pipeline happens through the <function>gst_bin_iterate ()</function> Note that during running, you should listen for at least the
function. Note that during running, you should connect to at least the <quote>error</quote> and <quote>eos</quote> messages on the bus
<quote>error</quote> and <quote>eos</quote> signals on the pipeline
and/or your plugin/element to check for correct handling of this. Also, and/or your plugin/element to check for correct handling of this. Also,
you should add events into the pipeline and make sure your plugin handles you should add events into the pipeline and make sure your plugin handles
these correctly (with respect to clocking, internal caching, etc.). these correctly (with respect to clocking, internal caching, etc.).
@ -120,6 +117,7 @@ main (gint argc,
GstElement *convert1, *convert2, *resample; GstElement *convert1, *convert2, *resample;
GMainLoop *loop; GMainLoop *loop;
GstBus *bus; GstBus *bus;
guint watch_id;
/* initialization */ /* initialization */
gst_init (&amp;argc, &amp;argv); gst_init (&amp;argc, &amp;argv);
@ -135,7 +133,7 @@ main (gint argc,
/* watch for messages on the pipeline's bus (note that this will only /* watch for messages on the pipeline's bus (note that this will only
* work like this when a GLib main loop is running) */ * work like this when a GLib main loop is running) */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_watch (bus, bus_call, loop); watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus); gst_object_unref (bus);
filesrc = gst_element_factory_make ("filesrc", "my_filesource"); filesrc = gst_element_factory_make ("filesrc", "my_filesource");
@ -154,7 +152,7 @@ main (gint argc,
* depending on the environment (output used, sound card, driver etc.) */ * depending on the environment (output used, sound card, driver etc.) */
convert2 = gst_element_factory_make ("audioconvert", "audioconvert2"); convert2 = gst_element_factory_make ("audioconvert", "audioconvert2");
resample = gst_element_factory_make ("audioresample", "audioresample"); resample = gst_element_factory_make ("audioresample", "audioresample");
sink = gst_element_factory_make ("osssink", "audiosink"); sink = gst_element_factory_make ("pulsesink", "audiosink");
if (!sink || !decoder) { if (!sink || !decoder) {
g_print ("Decoder or output could not be found - check your install\n"); g_print ("Decoder or output could not be found - check your install\n");
@ -165,9 +163,9 @@ main (gint argc,
return -1; return -1;
} else if (!filter) { } else if (!filter) {
g_print ("Your self-written filter could not be found. Make sure it " g_print ("Your self-written filter could not be found. Make sure it "
"is installed correctly in $(libdir)/gstreamer-0.10/ or " "is installed correctly in $(libdir)/gstreamer-1.0/ or "
"~/.gstreamer-0.10/plugins/ and that gst-inspect-0.10 lists it. " "~/.gstreamer-1.0/plugins/ and that gst-inspect-1.0 lists it. "
"If it doesn't, check with 'GST_DEBUG=*:2 gst-inspect-0.10' for " "If it doesn't, check with 'GST_DEBUG=*:2 gst-inspect-1.0' for "
"the reason why it is not being loaded."); "the reason why it is not being loaded.");
return -1; return -1;
} }
@ -209,6 +207,8 @@ main (gint argc,
/* clean up */ /* clean up */
gst_element_set_state (pipeline, GST_STATE_NULL); gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline); gst_object_unref (pipeline);
g_source_remove (watch_id);
g_main_loop_unref (loop);
return 0; return 0;
} }