docs/pwg/: Add some paragraphs about state changes in 0.9 to the PWG and the porting guide, in particular about the n...

Original commit message from CVS:
* docs/pwg/appendix-porting.xml:
* docs/pwg/building-state.xml:
Add some paragraphs about state changes in 0.9 to the PWG
and the porting guide, in particular about the new meaning
of GST_STATE_PAUSED and how to write state change functions
with concurrent access by multiple threads in mind.
This commit is contained in:
Tim-Philipp Müller 2005-08-12 14:30:31 +00:00
parent cdd579efc9
commit f40be99d4b
3 changed files with 147 additions and 35 deletions

View file

@ -1,3 +1,12 @@
2005-08-12 Tim-Philipp Müller <tim at centricular dot net>
* docs/pwg/appendix-porting.xml:
* docs/pwg/building-state.xml:
Add some paragraphs about state changes in 0.9 to the PWG
and the porting guide, in particular about the new meaning
of GST_STATE_PAUSED and how to write state change functions
with concurrent access by multiple threads in mind.
2005-08-11 Stefan Kost <ensonic@users.sf.net>
* docs/gst/gstreamer-docs.sgml:

View file

@ -24,7 +24,7 @@
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,
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
@ -51,10 +51,10 @@
</listitem>
<listitem>
<para>
Negotiation is asynchronous. This means that negotiation is,
downstream, done as data comes in and, upstream, as renegotiation
is required. All details are described in <xref
linkend="chapter-negotiation"/>.
Negotiation is asynchronous. This means that downstream negotiation
is done as data comes in and upstream negotiation is done whenever
renegotiation is required. All details are described in
<xref linkend="chapter-negotiation"/>.
</para>
</listitem>
<listitem>
@ -73,8 +73,8 @@
In 0.9, event handling and buffers are separated once again. This
means that in order to receive events, one no longer has to set the
<classname>GST_FLAG_EVENT_AWARE</classname> flag, but can simply
set an event handling function on its sinkpad(s), using the function
<function>gst_pad_set_event_function ()</function>. The
set an event handling function on the element's sinkpad(s), using
the function <function>gst_pad_set_event_function ()</function>. The
<function>_chain ()</function>-function will only receive buffers.
</para>
</listitem>
@ -99,6 +99,48 @@
()</function>.
</para>
</listitem>
<listitem>
<para>
The semantics of <symbol>GST_STATE_PAUSED</symbol> and
<symbol>GST_STATE_PLAYING</symbol> have changed for elements that
are not sink elements. Non-sink elements need to be able to accept
and process data already in the <symbol>GST_STATE_PAUSED</symbol>
state now (ie. when prerolling the pipeline). More details can be
found in <xref linkend="chapter-statemanage-states"/>.
</para>
</listitem>
<listitem>
<para>
If your plugin's state change function hasn't been superseded by
virtual start() and stop() methods of one of the new base classes,
then your plugin's state change functions may need to be changed in
order to safely handle concurrent access by multiple threads. Your
typical state change function will now first handle upwards state
changes, then chain up to the state change function of the parent
class (usually GstElementClass in these cases), and only then handle
downwards state changes. See the vorbis decoder plugin in
gst-plugins-base for an example.
</para>
<para>
The reason for this is that in the case of downwards state changes
you don't want to destroy allocated resources while your plugin's
chain function (for example) is still accessing those resources in
another thread. Whether your chain function might be running or not
depends on the state of your plugin's pads, and the state of those
pads is closely linked to the state of the element. Pad states are
handled in the GstElement class's state change function, including
proper locking, that's why it is essential to chain up before
destroying allocated resources.
</para>
<para>
As already mentioned above, you should really rewrite your plugin
to derive from one of the new base classes though, so you don't have
to worry about these things, as the base class will handle it for you.
There are no base classes for decoders and encoders yet, so the above
paragraphs about state changes definitively apply if your plugin is a
decoder or an encoder.
</para>
</listitem>
</itemizedlist>
</sect1>
</chapter>

View file

@ -3,19 +3,41 @@
<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
are four states defined in &GStreamer;: <symbol>GST_STATE_NULL</symbol>,
<symbol>GST_STATE_READY</symbol>, <symbol>GST_STATE_PAUSED</symbol>
and <symbol>GST_STATE_PLAYING</symbol>.
are four states defined in &GStreamer;:
</para>
<itemizedlist>
<listitem>
<para>
<symbol>GST_STATE_NULL</symbol>
</para>
</listitem>
<listitem>
<para>
<symbol>GST_STATE_READY</symbol>
</para>
</listitem>
<listitem>
<para>
<symbol>GST_STATE_PAUSED</symbol>
</para>
</listitem>
<listitem>
<para>
<symbol>GST_STATE_PLAYING</symbol>
</para>
</listitem>
</itemizedlist>
<para>
which will from now on be referred to simply as <quote>NULL</quote>,
<quote>READY</quote>, <quote>PAUSED</quote> and <quote>PLAYING</quote>.
</para>
<para>
<symbol>GST_STATE_NULL</symbol> (from now on referred to as
<quote>NULL</quote>) is the default state of an element. In this state, it
<symbol>GST_STATE_NULL</symbol> is the default state of an element. In this state, it
has not allocated any runtime resources, it has not loaded any runtime
libraries and it can obviously not handle data.
</para>
<para>
<symbol>GST_STATE_READY</symbol> (from now on referred to as
<quote>READY</quote>) is the next state that an element can be in. In the
<symbol>GST_STATE_READY</symbol> is the next state that an element can be in. In the
READY state, an element has all default resources (runtime-libraries,
runtime-memory) allocated. However, it has not yet allocated or defined
anything that is stream-specific. When going from NULL to READY state
@ -29,31 +51,44 @@
they should <emphasis>not</emphasis> be allocated in this state.
</para>
<para>
<symbol>GST_STATE_PAUSED</symbol> (from now on referred to as
<quote>PAUSED</quote>) is a state in which an element is by all means able
to handle data; the only 'but' here is that it doesn't actually handle
any data. When going from the READY state into the PAUSED state
(<symbol>GST_STATE_READY_TO_PAUSED</symbol>), the element will
usually not do anything at all: all stream-specific info is generally
handled in the <function>_link ()</function>, which is called during caps
negotiation. Exceptions to this rule are, for example, files: these are
considered stream-specific data (since one file is one stream), and should
thus be opened in this state change. When going from the PAUSED back to
READY (<symbol>GST_STATE_PAUSED_TO_READY</symbol>), all
stream-specific data should be discarded.
<symbol>GST_STATE_PAUSED</symbol> is the state in which an element is
ready to accept and handle data. For most elements this state is the same
as PLAYING. The only exception to this rule are sink elements. Sink
elements only accept one single buffer of data and then block. At this
point the pipeline is 'prerolled' and ready to render data immediately.
</para>
<para>
<symbol>GST_STATE_PLAYING</symbol> (from now on referred to as
<quote>PLAYING</quote>) is the highest state that an element can be in. It
is similar to PAUSED, except that now, data is actually passing over the
pipeline. The transition from PAUSED to PLAYING
(<symbol>GST_STATE_PAUSED_TO_PLAYING</symbol>) should be as small
as possible and would ideally cause no delay at all. The same goes for the
reverse transition (<symbol>GST_STATE_PLAYING_TO_PAUSED</symbol>).
<symbol>GST_STATE_PLAYING</symbol> is the highest state that an element
can be in. For most elements this state is exactly the same as PAUSED,
they accept and process events and buffers with data. Only sink elements
need to differentiate between PAUSED and PLAYING state. In PLAYING state,
sink elements actually render incoming data, e.g. output audio to a sound
card or render video pictures to an image sink.
</para>
<sect1 id="section-statemanage-filters">
<title>Managing filter state</title>
<para>
If at all possible, your element should derive from one of the new base
classes (<xref linkend="chapter-other-base"/>). There are ready-made
general purpose base classes for different types of sources, sinks and
filter/transformation elements. In addition to those, specialised base
classes exist for audio and video elements and others.
</para>
<para>
If you use a base class, you will rarely have to handle state changes
yourself. All you have to do is override the base class's start() and
stop() virtual functions (might be called differently depending on the
base class) and the base class will take care of everything for you.
</para>
<para>
If, however, you do not derive from a ready-made base class, but from
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
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
decoders or encoders yet.
</para>
<para>
An element can be notified of state changes through a virtual function
pointer. Inside this function, the element can initialize any sort of
@ -96,6 +131,7 @@ gst_my_filter_free_memory (GstMyFilter * filter)
static GstElementStateReturn
gst_my_filter_change_state (GstElement *element)
{
GstElementStateReturn ret = GST_STATE_SUCCESS;
GstMyFilter *filter = GST_MY_FILTER (element);
switch (GST_STATE_TRANSITION (element)) {
@ -103,6 +139,13 @@ gst_my_filter_change_state (GstElement *element)
if (!gst_my_filter_allocate_memory (filter))
return GST_STATE_FAILURE;
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)-&gt;change_state (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_NULL:
gst_my_filter_free_memory (filter);
break;
@ -110,12 +153,30 @@ gst_my_filter_change_state (GstElement *element)
break;
}
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
change_state, (element), GST_STATE_SUCCESS);
return ret;
}
<!-- example-end state.func b -->
<!-- example-begin state.c b --><!--
#include "register.func"
--><!-- example-end state.c b --></programlisting>
<para>
Note that upwards (NULL=>READY, READY=>PAUSED, PAUSED=>PLAYING) and
downwards (PLAYING=>PAUSED, PAUSED=>READY, READY=>NULL) state changes
are handled in two separate blocks with the downwards state change
handled only after we have chained up to the parent class's state
change function. This is necessary in order to safely handle concurrent
access by multiple threads.
</para>
<para>
The reason for this is that in the case of downwards state changes
you don't want to destroy allocated resources while your plugin's
chain function (for example) is still accessing those resources in
another thread. Whether your chain function might be running or not
depends on the state of your plugin's pads, and the state of those
pads is closely linked to the state of the element. Pad states are
handled in the GstElement class's state change function, including
proper locking, that's why it is essential to chain up before
destroying allocated resources.
</para>
</sect1>
</chapter>