manual: talk a bit about buffering
authorWim Taymans <wim.taymans@collabora.co.uk>
Mon, 8 Oct 2012 14:42:11 +0000 (16:42 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Mon, 8 Oct 2012 14:42:11 +0000 (16:42 +0200)
docs/design/part-buffering.txt
docs/manual/advanced-buffering.xml [new file with mode: 0644]
docs/manual/manual.xml

index c1b3fb6..c36f948 100644 (file)
@@ -50,7 +50,7 @@ Some use cases:
 
   This buffering method is usable when the demuxer operates in push mode.
   Seeking in the stream requires the seek to happen in the network source.
-  It is mostly desirable when the total duration of the file is not know, such
+  It is mostly desirable when the total duration of the file is not known, such
   as in live streaming or when efficient seeking is not possible/required.
 
  * Incremental download
diff --git a/docs/manual/advanced-buffering.xml b/docs/manual/advanced-buffering.xml
new file mode 100644 (file)
index 0000000..91fcb0a
--- /dev/null
@@ -0,0 +1,269 @@
+<chapter id="chapter-buffering">
+  <title>Buffering</title>
+  <para>
+    The purpose of buffering is to accumulate enough data in a pipeline so that
+    playback can occur smoothly and without interruptions. It is typically done
+    when reading from a (slow) and non-live network source but can also be
+    used for live sources.
+  </para>
+  <para>
+    &GStreamer; provides support for the following use cases:
+    <itemizedlist>
+      <listitem>
+        <para>
+          Buffering up to a specific amount of data, in memory, before starting
+          playback so that network fluctuations are minimized.
+          See <xref linkend="section-buffering-stream"/>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Download of the network file to a local disk with fast seeking in the
+          downloaded data. This is similar to the quicktime/youtube players.
+          See <xref linkend="section-buffering-download"/>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Caching of (semi)-live streams to a local, on disk, ringbuffer with
+          seeking in the cached area. This is similar to tivo-like timeshifting.
+          See <xref linkend="section-buffering-timeshift"/>.
+        </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    &GStreamer; can provide the application with progress reports about the
+    current buffering state as well as let the application decide on how
+    to buffer and when the buffering stops.
+  </para>
+  <para>
+    In the most simple case, the application has to listen for BUFFERING
+    messages on the bus. If the percent indicator inside the BUFFERING message
+    is smaller than 100, the pipeline is buffering. When a message is
+    received with 100 percent, buffering is complete. In the buffering state,
+    the application should keep the pipeline in the PAUSED state. When buffering
+    completes, it can put the pipeline (back) in the PLAYING state.
+  </para>
+  <para>
+    What follows is an example of how the message handler could deal with
+    the BUFFERING messages. We will see more advanced methods in
+    <xref linkend="section-buffering-strategies"/>.
+  </para>
+  <programlisting>
+<![CDATA[
+  [...]
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_BUFFERING:{
+      gint percent;
+
+      gst_message_parse_buffering (message, &percent);
+
+      /* no state management needed for live pipelines */
+      if (is_live)
+        break;
+
+      if (percent == 100) {
+        /* a 100% message means buffering is done */
+        buffering = FALSE;
+        /* if the desired state is playing, go back */
+        if (target_state == GST_STATE_PLAYING) {
+          gst_element_set_state (pipeline, GST_STATE_PLAYING);
+        }
+      } else {
+        /* buffering busy */
+        if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
+          /* we were not buffering but PLAYING, PAUSE  the pipeline. */
+          gst_element_set_state (pipeline, GST_STATE_PAUSED);
+        }
+        buffering = TRUE;
+      }
+      break;
+    case ...
+
+  [...]
+]]>
+  </programlisting>
+
+  <sect1 id="section-buffering-stream">
+    <title>Stream buffering </title>
+    <programlisting>
+      +---------+     +---------+     +-------+
+      | httpsrc |     | buffer  |     | demux |
+      |        src - sink      src - sink     ....
+      +---------+     +---------+     +-------+
+    </programlisting>
+    <para>
+      In this case we are reading from a slow network source into a buffer
+      element (such as queue2).
+    </para>
+    <para>
+      The buffer element has a low and high watermark expressed in bytes. The
+      buffer uses the watermarks as follows:
+    </para>
+    <itemizedlist>
+      <listitem>
+        <para>
+          The buffer element will post BUFFERING messages until the high
+          watermark is hit. This instructs the application to keep the pipeline
+          PAUSED, which will eventually block the srcpad from pushing while
+          data is prerolled in the sinks.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          When the high watermark is hit, a BUFFERING message with 100% will be
+          posted, which instructs the application to continue playback.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          When during playback, the low watermark is hit, the queue will start
+          posting BUFFERING messages again, making the application PAUSE the
+          pipeline again until the high watermark is hit again. This is called
+          the rebuffering stage.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          During playback, the queue level will fluctuate between the high and
+          the low watermark as a way to compensate for network irregularities.
+        </para>
+      </listitem>
+   </itemizedlist>
+   <para>
+     This buffering method is usable when the demuxer operates in push mode.
+     Seeking in the stream requires the seek to happen in the network source.
+     It is mostly desirable when the total duration of the file is not known,
+     such as in live streaming or when efficient seeking is not
+     possible/required.
+   </para>
+   <para>
+     The problem is configuring a good low and high watermark. Here are some
+     ideas:
+   </para>
+   <itemizedlist>
+      <listitem>
+        <para>
+          It is possible to measure the network bandwidth and configure the
+          low/high watermarks in such a way that buffering takes a fixed
+          amount of time.
+        </para>
+        <para>
+          The queue2 element in &GStreamer; core has the max-size-time property
+          that, together with the use-rate-estimate property, does exactly
+          that. Also the playbin buffer-duration property uses the rate estimate
+          to scale the amount of data that is buffered.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Based on the codec bitrate, it is also possible to set the watermarks
+          in such a way that a fixed amount of data is buffered before playback
+          starts. Normally, the buffering element doesn't know about the
+          bitrate of the stream but it can get this with a query.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Start with a fixed amount of bytes, measure the time between
+          rebuffering and increase the queue size until the time between
+          rebuffering is within the application's chosen limits.
+        </para>
+      </listitem>
+   </itemizedlist>
+   <para>
+     The buffering element can be inserted anywhere in the pipeline. You could,
+     for example, insert the buffering element before a decoder. This would
+     make it possible to set the low/high watermarks based on time.
+   </para>
+   <para>
+     The buffering flag on playbin, performs buffering on the parsed data.
+     Another advantage of doing the buffering at a later stage is that you can
+     let the demuxer operate in pull mode. When reading data from a slow
+     network drive (with filesrc) this can be an interesting way to buffer.
+   </para>
+  </sect1>
+
+  <sect1 id="section-buffering-download">
+    <title>Download buffering </title>
+    <programlisting>
+      +---------+     +---------+     +-------+
+      | httpsrc |     | buffer  |     | demux |
+      |        src - sink      src - sink     ....
+      +---------+     +----|----+     +-------+
+                           V
+                          file
+    </programlisting>
+    <para>
+      If we know the server is streaming a fixed length file to the client,
+      the application can choose to download the entire file on disk. The
+      buffer element will provide a push or pull based srcpad to the demuxer
+      to navigate in the downloaded file.
+    </para>
+    <para>
+      This mode is only suitable when the client can determine the length of
+      the file on the server.
+    </para>
+    <para>
+      In this case, buffering messages will be emited as usual when the
+      requested range is not within the downloaded area + buffersize. The
+      buffering message will also contain an indication that incremental
+      download is being performed. This flag can be used to let the application
+      control the buffering in a more intelligent way, using the BUFFERING
+      query, for example. See <xref linkend="section-buffering-strategies"/>.
+    </para>
+  </sect1>
+
+  <sect1 id="section-buffering-timeshift">
+    <title>Timeshift buffering </title>
+    <programlisting>
+      +---------+     +---------+     +-------+
+      | httpsrc |     | buffer  |     | demux |
+      |        src - sink      src - sink     ....
+      +---------+     +----|----+     +-------+
+                           V
+                       file-ringbuffer
+    </programlisting>
+    <para>
+      In this mode, a fixed size ringbuffer is kept to download the server
+      content.  This allows for seeking in the buffered data. Depending on the
+      size of the ringbuffer one can seek further back in time.
+    </para>
+    <para>
+      This mode is suitable for all live streams. As with the incremental
+      download mode, buffering messages are emited along with an indication
+      that timeshifting download is in progress.
+    </para>
+  </sect1>
+
+  <sect1 id="section-buffering-live">
+    <title>Live buffering </title>
+    <para>
+      In live pipelines we usually introduce some fixed latency between the
+      capture and the playback elements. This latency can be introduced by
+      a queue (such as a jitterbuffer) or by other means (in the audiosink).
+    </para>
+    <para>
+      Buffering messages can be emited in those live pipelines as well and
+      serve as an indication to the user of the latency buffering. The
+      application usually does not react to these buffering messages with a
+      state change.
+    </para>
+  </sect1>
+
+  <sect1 id="section-buffering-strategies">
+    <title>Buffering strategies </title>
+    <para>
+      WRITEME
+    </para>
+    <para>
+      The application can use the BUFFERING query to get the estimated
+      download time and match this time to the current/remaining playback time
+      to control when playback should start to have a non-interrupted playback
+      experience.
+    </para>
+  </sect1>
+
+</chapter>
index 14f32d1..87e5356 100644 (file)
@@ -41,6 +41,7 @@
 <!ENTITY METADATA             SYSTEM "advanced-metadata.xml">
 <!ENTITY INTERFACES           SYSTEM "advanced-interfaces.xml">
 <!ENTITY CLOCKS               SYSTEM "advanced-clocks.xml">
+<!ENTITY BUFFERING            SYSTEM "advanced-buffering.xml">
 <!ENTITY DPARAMS              SYSTEM "advanced-dparams.xml">
 <!ENTITY THREADS              SYSTEM "advanced-threads.xml">
 <!ENTITY AUTOPLUGGING         SYSTEM "advanced-autoplugging.xml">
     &METADATA;
     &INTERFACES;
     &CLOCKS;
+    &BUFFERING;
     &DPARAMS;
     &THREADS;
     &AUTOPLUGGING;