docs/pwg/: Add some paragraphs about state changes in 0.9 to the PWG and the porting...
authorTim-Philipp Müller <tim@centricular.net>
Fri, 12 Aug 2005 14:30:31 +0000 (14:30 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Fri, 12 Aug 2005 14:30:31 +0000 (14:30 +0000)
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.

ChangeLog
docs/pwg/appendix-porting.xml
docs/pwg/building-state.xml

index b8a34ac..4bcde0c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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:
index 1d12bc3..921e276 100644 (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
       </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>
           ()</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>
index d7ff8bb..5aa6c80 100644 (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>
-    <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
+    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> (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
     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
     specific data needed by the element, and it can optionally fail to
@@ -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>