gstreamer/ext/ogg
Thomas Vander Stichele 96fd3b4548 declare variable at start of block
Original commit message from CVS:
declare variable at start of block
2005-10-07 17:06:59 +00:00
..
gstogg.c Add an ogg parser element 2005-08-29 10:52:20 +00:00
gstoggdemux.c ext/ogg/gstoggdemux.c: Report the FLOW_RETURN as string in the error message. 2005-10-06 13:11:55 +00:00
gstoggmux.c All plugins updated for element state changes. 2005-09-02 15:43:18 +00:00
gstoggparse.c declare variable at start of block 2005-10-07 17:06:59 +00:00
gstogmparse.c All plugins updated for element state changes. 2005-09-02 15:43:18 +00:00
Makefile.am Add an ogg parser element 2005-08-29 10:52:20 +00:00
README ext/ogg/: Buffer on caps is not boxed anymore. 2005-06-23 15:09:31 +00:00

ogg demuxer
-----------

This ogg demuxer has two modes of operation, which both share a significant
amount of code. The first mode is the streaming mode which is automatically 
selected when the demuxer is connected to a non-getrange based element. When 
connected to a getrange based element the ogg demuxer can do full seeking
with great efficiency.

1) the streaming mode.

  In this mode, the ogg demuxer receives buffers in the _chain() function which
  are then simply submited to the ogg sync layer. Pages are then processed when the
  sync layer detects them, pads are created for new chains and packets are sent to
  the peer elements of the pads.

  In this mode, no seeking is possible. This is the typical case when the stream is
  read from a network source.

  In this mode, no setup is done at startup, the pages are just read and decoded.
  A new logical chain is detected when one of the pages has the BOS flag set. At this
  point the existing pads are removed and new pads are created for all the logical
  streams in this new chain.
  

2) the random access mode.

  In this mode, the ogg file is first scanned to detect the position and length of
  all chains. This scanning is performed using a recursive binary search algorithm
  that is explained below.

    find_chains(start, end)
    {
      ret1 = read_next_pages (start);
      ret2 = read_prev_page (end);
      
      if (WAS_HEADER (ret1)) {
      }
      else {
      }

    }

  a) read first and last pages

   start                                                      end
    V                                                          V 
    +-----------------------+-------------+--------------------+
    |  111                  |  222        |  333               |
   BOS                     BOS           BOS                  EOS

   
   after reading start, serial 111, BOS, chain[0] = 111
   after reading end,   serial 333, EOS

   start serialno != end serialno, binary search start, (end-start)/2

   start                    bisect                            end
    V                         V                                V 
    +-----------------------+-------------+--------------------+
    |  111                  |  222        |  333               |

   
   after reading start, serial 111, BOS, chain[0] = 111
   after reading end,   serial 222, EOS

   while (



testcases
---------
    
 a) stream without BOS

    +----------------------------------------------------------+
       111                                                     |
                                                              EOS

 b) chained stream, first chain without BOS
  
    +-------------------+--------------------------------------+
       111              | 222                                  |
                       BOS                                    EOS


 c) chained stream
  
    +-------------------+--------------------------------------+
    |  111              | 222                                  |
   BOS                 BOS                                    EOS


 d) chained stream, second without BOS

    +-------------------+--------------------------------------+
    |  111              | 222                                  |
   BOS                                                        EOS



ogg and the granulepos
----------------------

an ogg streams contains pages with a serial number and a granule pos. The granulepos
is a number that is codec specific and denotes the 'position' of the last sample in
the last packet in that page.

ogg has therefore no notion about time, it only knows about bytes and granule positions.

The granule position is just a number, it can contain gaps or can just be any random
number.


theora and the granulepos
-------------------------

the granulepos in theora consists of the framenumber of the last keyframe shifted some
amount of bits plus the number of p/b-frames.

This means that given a framenumber or a timestamp one cannot generate the granulepos
for that frame. eg frame 10 could have several valid granulepos values depending on if
the last keyframe was on frame 5 or 0. Given a granulepos we can, however, create a
unique correct timestamp and a framenumber.

in a raw theroa stream we use the granulepos as the offset field.

The granulepos of an ogg page is the framenumber of the last frame in the page.


vorbis and granulepos
---------------------

the granulepos in vorbis happens to be the same as the sample counter. conversion to and
from granulepos is therefore easy.

in a raw vorbis stream we use the granulepos as the offset field.

The granulepos of an ogg page is the sample number of the next page in the ogg stream.


What can ogg do?
----------------

An ogg demuxer can read pages and get the granuleposition from it. It can ask the decoder
elements to convert a granulepos to time.

An ogg demuxer can also get the granulepos of the first and the last page of a stream to
get the start and end timestamp of that stream. It can also get the length in bytes of
the stream (when the peer is seekable, that is).

An ogg demuxer is therefore basically able to seek to any byte position and timestamp.
When asked to seek to a given granulepos, the ogg demuxer should always convert the 
value to a timestamp using the peer decoder element conversion function. It can then
binary search the file to eventually end up on the page with the given granule pos or
a granulepos with the same timestamp.

Seeking in ogg currently
------------------------

When seeking in an ogg, the decoders can choose to forward the seek event as a 
granulepos or a timestamp to the ogg demuxer.

In the case of a granulepos, the ogg demuxer will seek back to the beginning of
the stream and skip pages until it finds one with the requested timestamp.

In the case of a timestamp, the ogg demuxer also seeks back to the beginning of
the stream. For each page it reads, it asks the decoder element to convert the 
granulepos back to a timestamp. The ogg demuxer keeps on skipping pages until the
page has a timestamp bigger or equal to the requested one.

It is therefore important that the decoder elements in vorbis can convert a granulepos
into a timestamp or never seek on timestamp on the oggdemuxer.

The default format on the oggdemuxer source pads is currently defined as a the 
granulepos of the packets, it is also the value of the OFFSET field in the GstBuffer.


Oggmux
------

The oggmuxer uses the offset fields to fill in the granulepos in the pages.


TODO
----

- use the OFFSET field in the GstBuffer to store/read the granulepos as 
  opposed to the OFFSET_END field.


Ogg media mapping
-----------------

Ogg defines a mapping for each media type that it embeds.

For Vorbis:

  - 3 header pages, with granulepos 0.
     - 1 page with 1 packet header identification
     - N pages with 2 packets comments and codebooks
  - granulepos is samplenumber of next page
  - one packet can contain a variable number of samples but one frame
    that should be handed to the vorbis decoder.
  
For Theora
     
  - 3 header pages, with granulepos 0.
     - 1 page with 1 packet header identification
     - N pages with 2 packets comments and codebooks
  - granulepos is framenumber of last packet in page, where framenumber
    is a combination of keyframe number and p frames since keyframe.
  - one packet contains 1 frame