Implementing GstToc support in GStreamer elements

1. General info about GstToc structure

GstToc introduces a general way to handle chapters within multimedia
formats. GstToc can be represented as tree structure with arbitrary
hierarchy. Tree item can be either of two types: chapter or edition.
Chapter acts like a part of the media data, for example audio track
in CUE sheet, or part of the movie. Edition acts like some kind of
alternative way to process media content, for example DVD angles.
GstToc has one limitation on tree structure: on the same level of
hierarchy there couldn't be items of different type, i.e. you shouldn't
have editions and chapters mixed together. Here is an example of right TOC:

  -------  TOC  -------
           /  \
   edition1    edition2
   |           |
   -chapter1   -chapter3
   -chapter2       

Here are two editions, the first contains two chapters, and the second
has only one chapter. And here is an example of invalid TOC:

  -------  TOC  -------
           /  \
   edition1    chapter1
   |                 
   -chapter1
   -chapter2    
 
Here you have edition1 and chapter1 mixed on the same level of hierarchy,
and such TOC will be considered broken.

GstToc has 'entries' field of GList type which consists of children items.
Each item is of type GstTocEntry. Also GstToc has list of tags and
GstStructure called 'info'. Please, use GstToc.info and GstTocEntry.info
fields this way: create a GstStructure, put all info related to your element
there and put this structure into the 'info' field under the name of your
element. Some fields in the 'info' structure can be used for internal
purposes, so you should use it in the way described above to not to
overwrite already existent fields.

Let's look at GstTocEntry a bit closer. One of the most important fields
is 'uid', which must be unique for each item within the TOC. This is used
to identify each item inside TOC, especially when element receives TOC
select event with UID to seek on. Field 'subentries' of type GList contains
children items of type GstTocEntry. Thus you can achieve arbitrary hierarchy
level. Field 'type' can be either GST_TOC_ENTRY_TYPE_CHAPTER or
GST_TOC_ENTRY_TYPE_EDITION which corresponds to chapter or edition type of
item respectively. Field 'tags' is a list of tags related to the item. And field
'info' is similar to GstToc.info described above.

So, a little more about managing GstToc. Use gst_toc_new() and gst_toc_unref()
to create/free it. GstTocEntry can be created using gst_toc_entry_new().
While building GstToc you can set start and stop
timestamps for each item using gst_toc_entry_set_start_stop().
The best way to process already created GstToc is to recursively go through
the 'entries' and 'subentries' fields.

Applications and plugins should not rely on TOCs having a certain kind of
structure, but should allow for different alternatives. For example, a
simple CUE sheet embedded in a file may be presented as a flat list of
track entries, or could have a top-level edition node (or some other
alternative type entry) with track entries underneath that node; or even
multiple top-level edition nodes (or some other alternative type entries)
each with track entries underneath, in case the source file has extracted
a track listing from different sources).


2. TOC scope: global and current

There are two main consumers for TOC information: applications and elements
in the pipeline that are TOC writers (such as e.g. matroskamux).

Applications typically want to know the entire table of contents (TOC) with
all entries that can possibly be selected.

TOC writers in the pipeline, however, would not want to write a TOC for all
possible/available streams, but only for the current stream.

When transcoding a title from a DVD, for example, the application would still
want to know the entire TOC, with all titles, the chapters for each title,
and the available angles. When transcoding to a file, we only want the TOC
information that is relevant to the transcoded stream to be written into
the file structure, e.g. the chapters of the title being transcoded (or
possibly only chapters 5-7 if only those have been selected for playback/
transcoding).

This is why we may need to create two different TOCs for those two types
of consumers.

Elements that extract TOC information should send TOC events downstream.

Like with tags, sinks will post a TOC message on the bus for the application
with the global TOC, once a global TOC event reaches the sink.


3. Working with GstMessage

If a table of contents is available, applications will receive a TOC message
on the pipeline's GstBus.

A TOC message will be posted on the bus by sinks when the receive a TOC event
containing a TOC with global scope. Elements extracting TOCs should not post
a TOC message themselves, but send a TOC event downstream.

The reason for this is that there may be cascades of TOCs (e.g. a zip archive
containing multiple matroska files, each with a TOC).

GstMessage with GstToc can be created using gst_message_new_toc() and parsed
with gst_message_parse_toc(). The 'updated' parameter in these methods indicates
whether the TOC was just discovered (set to false) or TOC was already found and
have been updated (set to true). This message will typically be posted by sinks
to pipeline in case you have discovered TOC data within your element.


4. Working with GstEvent

There are two types of TOC-related events:

 - downstream TOC events that contain TOC information and
   travel downstream

 - toc-select events that travel upstream and can be used to select
   a certain TOC entry for playback (similar to seek events)

GstToc supports select event through GstEvent infrastructure. The idea is the
following: when you receive TOC select event, parse it with
gst_event_parse_toc_select() and seek stream (if it is not streamable) for
specified TOC UID (you can use gst_toc_find_entry() to find entry in TOC by UID).
To create TOC select event use gst_event_new_toc_select(). The common action on
such event is to seek to specified UID within your element. 

