mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 02:30:35 +00:00
bce6eeb204
Original commit message from CVS: * docs/pwg/building-chainfn.xml: * docs/pwg/building-pads.xml: * docs/pwg/building-state.xml: * docs/pwg/other-source.xml: Update state change stuff for 0.10 (fixes #322969).
184 lines
7 KiB
XML
184 lines
7 KiB
XML
<chapter id="chapter-statemanage-states">
|
|
<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
|
|
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> 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> 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
|
|
(<symbol>GST_STATE_CHANGE_NULL_TO_READY</symbol>), an element should
|
|
allocate any non-stream-specific resources and should load runtime-loadable
|
|
libraries (if any). When going the other way around (from READY to NULL,
|
|
<symbol>GST_STATE_CHANGE_READY_TO_NULL</symbol>), an element should unload
|
|
these libraries and free all allocated resources. Examples of such
|
|
resources are hardware devices. Note that files are generally streams,
|
|
and these should thus be considered as stream-specific resources; therefore,
|
|
they should <emphasis>not</emphasis> be allocated in this state.
|
|
</para>
|
|
<para>
|
|
<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> 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
|
|
specific data needed by the element, and it can optionally fail to
|
|
go from one state to another.
|
|
</para>
|
|
<para>
|
|
Do not g_assert for unhandled state changes; this is taken care of by
|
|
the GstElement base class.
|
|
</para>
|
|
<programlisting>
|
|
static GstStateChangeReturn
|
|
gst_my_filter_change_state (GstElement *element, GstStateChange transition);
|
|
|
|
static void
|
|
gst_my_filter_class_init (GstMyFilterClass *klass)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (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 GstStateChangeReturn
|
|
gst_my_filter_change_state (GstElement *element, GstStateChange transition)
|
|
{
|
|
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
|
GstMyFilter *filter = GST_MY_FILTER (element);
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
if (!gst_my_filter_allocate_memory (filter))
|
|
return GST_STATE_CHANGE_FAILURE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
if (ret == GST_STATE_CHANGE_FAILURE)
|
|
return ret;
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
gst_my_filter_free_memory (filter);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
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>
|