2016-12-05 21:12:24 +00:00
|
|
|
|
# Implementing GstToc support in GStreamer elements
|
|
|
|
|
|
|
|
|
|
## General info about GstToc structure
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
`GstToc` introduces a general way to handle chapters within multimedia
|
|
|
|
|
formats. `GstToc` can be represented as tree structure with arbitrary
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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
|
2017-01-23 22:34:53 +00:00
|
|
|
|
the media content, for example DVD angles. `GstToc` has one constraint on
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
```
|
2017-01-23 22:27:08 +00:00
|
|
|
|
------- TOC -------
|
|
|
|
|
/ \
|
|
|
|
|
edition1 edition2
|
|
|
|
|
| |
|
|
|
|
|
-chapter1 -chapter3
|
|
|
|
|
-chapter2
|
2016-12-05 21:12:24 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
```
|
2017-01-23 22:27:08 +00:00
|
|
|
|
------- TOC -------
|
|
|
|
|
/ \
|
|
|
|
|
edition1 chapter1
|
|
|
|
|
|
|
|
|
|
|
-chapter1
|
|
|
|
|
-chapter2
|
2016-12-05 21:12:24 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Here you have edition1 and chapter1 mixed on the same level of
|
|
|
|
|
hierarchy, and such TOC will be considered broken.
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
`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
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
Let’s look at `GstTocEntry` a bit closer. One of the most important fields
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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
|
2017-01-23 22:34:53 +00:00
|
|
|
|
contains children items of type `GstTocEntry`. Thus you can achieve
|
2016-12-05 21:12:24 +00:00
|
|
|
|
arbitrary hierarchy level. Field *type* can be either
|
2017-01-23 22:34:53 +00:00
|
|
|
|
`GST_TOC_ENTRY_TYPE_CHAPTER` or `GST_TOC_ENTRY_TYPE_EDITION` which
|
2016-12-05 21:12:24 +00:00
|
|
|
|
corresponds to chapter or edition type of item respectively. Field
|
|
|
|
|
*tags* is a list of tags related to the item. And field *info* is
|
2017-01-23 22:34:53 +00:00
|
|
|
|
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
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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
|
2017-01-23 22:34:53 +00:00
|
|
|
|
message on the pipeline’s `GstBus`.
|
2016-12-05 21:12:24 +00:00
|
|
|
|
|
|
|
|
|
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).
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
`GstMessage` with `GstToc` can be created using `gst_message_new_toc()` and
|
|
|
|
|
parsed with `gst_message_parse_toc()`. The *updated* parameter in these
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
`GstToc` supports select event through `GstEvent` infrastructure. The idea
|
2016-12-05 21:12:24 +00:00
|
|
|
|
is the following: when you receive TOC select event, parse it with
|
2017-01-23 22:34:53 +00:00
|
|
|
|
`gst_event_parse_toc_select()` and seek stream (if it is not
|
|
|
|
|
streamable) for specified TOC UID (you can use `gst_toc_find_entry()`
|
2016-12-05 21:12:24 +00:00
|
|
|
|
to find entry in TOC by UID). To create TOC select event use
|
2017-01-23 22:34:53 +00:00
|
|
|
|
`gst_event_new_toc_select()`. The common action on such event is to
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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*
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
The *MARK* chunk defines a list of (cue-id, `position_in_samples`,
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
Both `CUESHEET_TRACK` and `CUESHEET_TRACK_INDEX` have a (relative) offset
|
|
|
|
|
in samples. `CUESHEET_TRACK` has ISRC metadata.
|
2016-12-05 21:12:24 +00:00
|
|
|
|
|
|
|
|
|
### 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*
|
|
|
|
|
|
2017-04-28 23:12:02 +00:00
|
|
|
|
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
|
2016-12-05 21:12:24 +00:00
|
|
|
|
in the same namespace (?).
|
|
|
|
|
|
|
|
|
|
The various *adtl* chunks: *labl*, *note* and *ltxt* refer to the
|
|
|
|
|
'cue-id’s.
|
|
|
|
|
|
2017-04-28 23:12:02 +00:00
|
|
|
|
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`).
|
2016-12-05 21:12:24 +00:00
|
|
|
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
2017-04-28 23:12:02 +00:00
|
|
|
|
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
|
2016-12-05 21:12:24 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2017-01-23 22:34:53 +00:00
|
|
|
|
We might want to introduce a new `GST_TOC_ENTRY_TYPE_MARKER` or `_CUE`.
|
2016-12-05 21:12:24 +00:00
|
|
|
|
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
|
2018-09-25 06:45:01 +00:00
|
|
|
|
TocSelect event. - exposing subtitles as a sparse stream or as ToC
|
2016-12-05 21:12:24 +00:00
|
|
|
|
sequence of markers with labels
|