mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 18:51:11 +00:00
227 lines
9.3 KiB
Markdown
227 lines
9.3 KiB
Markdown
|
# Implementing GstToc support in GStreamer elements
|
|||
|
|
|||
|
## 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: sequence or
|
|||
|
alternative. Sequence types acts like a part of the media data, for
|
|||
|
example audio track in CUE sheet, or part of the movie. Alternative
|
|||
|
types acts like some kind of selection to process a different version of
|
|||
|
the media content, for example DVD angles. GstToc has one constraint on
|
|||
|
the tree structure: it does not allow different entry types on the same
|
|||
|
level of the hierarchy, 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 (alternatives), the first contains two chapters
|
|||
|
(sequence type), 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() and
|
|||
|
loop\_type and repeat\_count using gst\_toc\_entry\_set\_loop(). 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).
|
|||
|
|
|||
|
## 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.
|
|||
|
|
|||
|
## 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.
|
|||
|
|
|||
|
## 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.
|
|||
|
|
|||
|
## Implementation coverage, Specifications, …
|
|||
|
|
|||
|
Below is a list of container formats, links to documentation and a
|
|||
|
summary of toc related features. Each section title also indicates
|
|||
|
whether reading/writing a toc is implemented. Below hollow bullet point
|
|||
|
*o* indicate no support and filled bullets *\*\* indicate that this
|
|||
|
feature is handled.
|
|||
|
|
|||
|
### AIFC: -/-
|
|||
|
<http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/AIFF-1.3.pdf>
|
|||
|
o *MARK* o *INST*
|
|||
|
|
|||
|
The *MARK* chunk defines a list of (cue-id, position\_in\_samples,
|
|||
|
label).
|
|||
|
|
|||
|
The *INST* chunk contains a sustainLoop and releaseLoop, each consisting
|
|||
|
of (loop-type, cue-begin, cue-end)
|
|||
|
|
|||
|
### FLAC: read/write
|
|||
|
|
|||
|
<http://xiph.org/flac/format.html#metadata_block_cuesheet> \*
|
|||
|
METADATA\_BLOCK\_CUESHEET \* CUESHEET\_TRACK o CUESHEET\_TRACK\_INDEX
|
|||
|
|
|||
|
Both CUESHEET\_TRACK and CUESHEET\_TRACK\_INDEX have a (relative) offset
|
|||
|
in samples. CUESHEET\_TRACK has ISRC metadata.
|
|||
|
|
|||
|
### MKV: read/write
|
|||
|
|
|||
|
<http://matroska.org/technical/specs/chapters/index.html> \* Chapters
|
|||
|
and Editions each having a uid \* Chapter have start/end time and
|
|||
|
metadata: ChapString, ChapLanguage, ChapCountry
|
|||
|
|
|||
|
### MP4: \* elst
|
|||
|
|
|||
|
The *elst* atom contains a list of edits. Each edit consists of (length,
|
|||
|
start, play-back speed).
|
|||
|
|
|||
|
### OGG: -/- <https://wiki.xiph.org/Chapter_Extension> o VorbisComment
|
|||
|
|
|||
|
fields called CHAPTERxxx and CHAPTERxxxNAME with xxx being a number
|
|||
|
between 000 and 999.
|
|||
|
|
|||
|
### WAV: read/write <http://www.sonicspot.com/guide/wavefiles.html> \* *cue
|
|||
|
' o 'plst* \* *adtl* \* *labl* \* *note* o *ltxt* o *smpl*
|
|||
|
|
|||
|
The *cue ' chunk defines a list of markers in the stream with 'cue-id’s.
|
|||
|
The 'smpl* chunk defines a list of regions in the stream with 'cue-id’s
|
|||
|
in the same namespace (?).
|
|||
|
|
|||
|
The various *adtl* chunks: *labl*, *note* and *ltxt* refer to the
|
|||
|
'cue-id’s.
|
|||
|
|
|||
|
A *plst* chunk defines a sequence of segments (cue-id, length\_samples,
|
|||
|
repeats). The *smpl* chunk defines a list of loops (cue-id, beg, end,
|
|||
|
loop-type, repeats).
|
|||
|
|
|||
|
## Conclusion/Ideas/Future work
|
|||
|
|
|||
|
Based on the data of chapter 5, a few thoughts and observations that can
|
|||
|
be used to extend and refine our API. These things below are not
|
|||
|
reflecting the current implementation.
|
|||
|
|
|||
|
All formats have table of \[cue-id, cue-start, (cue-end), (extra tags)\]
|
|||
|
- cue-id is commonly represented as and unsigned int 32bit - cue-end is
|
|||
|
optional - extra tags could be represented as a structure/taglist
|
|||
|
|
|||
|
Many formats have metadata that references the cue-table. - loops in
|
|||
|
instruments in wav, aifc - edit lists in wav, mp4
|
|||
|
|
|||
|
For mp4.edtl, wav.plst we could expose two editions. 1) the edit list is
|
|||
|
flattened: default, for playback 2) the stream has the raw data and the
|
|||
|
edit list is there as chapter markers: useful for editing software
|
|||
|
|
|||
|
We might want to introduce a new GST\_TOC\_ENTRY\_TYPE\_MARKER or \_CUE.
|
|||
|
This would be a sequence entry-type and it would not be used for
|
|||
|
navigational purposes, but to attach data to a point in time (envelopes,
|
|||
|
loops, …).
|
|||
|
|
|||
|
API wise there is some overlap between: - exposing multiple audio/video
|
|||
|
tracks as pads or as ToC editions. For ToC editions, we have the
|
|||
|
TocSelect event. - exposing subtitles as a sparse stream or as as ToC
|
|||
|
sequence of markers with labels
|