This page describes a generic media mapping (i.e. rules for multiplexing) of "text codecs" into Ogg.
Text codecs are sequences of text chunks that have a timing relationship to an audio or video stream.
Prominent examples of such text codecs are:
- CC: closed captions (for the deaf)
- SUB: subtitles
- TAD: textual audio descriptions (for the blind)
- KTV: karaoke
- TIK: ticker text
- AR: active regions
- NB: metadata & semantic annotations
- TRX: transcripts / scripts
- LRC: lyrics
- LIN: linguistic markup
There are a multitude of existing open formats for specifying some of these - in particular for specifying closed captions and subtitles. They come in different complexities - some being simply a time stamp and a text, others providing for extensive styling, graphics, and motion of the text blocks over time.
No matter what the differences - when multiplexing such codecs into Ogg, they all have to solve the same problems. This is why this page describes generically how to multiplex text codecs into Ogg.
Codecs with existing mappings are:
Ogg codecs consist of a sequence of header packets and data packets.
Header packets contain information necessary to identify and set up the codec. Data packets contain the actual codec data, in this case the time-aligned text.
When these packets are multiplexed into Ogg, they are mapped to Ogg pages. For text codecs, there is a sequence of header pages, a sequence of data pages, and an EOS page, which finishes the stream. The pages have to be ordered non-decreasing with time. No data can come after the EOS page.
Header packets are a sequence of:
- one ident header, which identifies the codec
- one (optional) vorbis-comment header
- one or more secondary header packets that are codec specific
Any text codec has to map its header information into these header packets.
Header packets must appear in order and all header packets must appear before any data packet. Each header packet is encapsulated in one Ogg page.
The format of the ident header
0 1 2 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1| Byte +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | packtype | Identifier char: 'txt' | 0-3 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier char: codec identifier | 4-7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Version major | Version minor | 8-11 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Each text codec page starts with a one byte type, just like this ident header. Similar to Kate, a type with the MSB set (eg, between 0x80 and 0xff) indicates a header packet, while a type with the MSB cleared (eg, between 0x00 and 0x7f) indicates a data packet. We use the packtype field in order to distinguish between the different header and data packet types.
The following packtypes are distinguished:
- 0x80 ID header (BOS page)
- 0x81 vorbis-comment header (optional)
- 0x82-0xff secondary header pages of the codec in an order defined by the codec (optional)
- 0x00 text data (including optional motions and overrides)
- 0x01 keepalive
- 0x7f end page (EOS page)
As per the Ogg specification, granule positions of pages must be non decreasing within the stream. Header pages have granule position 0.
In all header pages, the packtype is followed by the text codec magic from byte offset 1 to byte offset 3 ("txt"). The succeeding four bytes are to be used by the text codec to identify itself.
For example, when CMML moves to using this generic text codec mapping approach rather than its own, the first eight bytes of the ident header will identify the track as a CMML codec track through a signature string of "\200txtCMML".
Or as another example take a signature string of "\200txtsrt\0" which will identify srt being mapped.
Version major & minor are fields that are used by the text codec to define the version of its mapping.
The format of the Skeleton Fisbone
Text codecs are required to be used in conjunction with Ogg Skeleton.
The following fields are defined in the Fisbone header for a text codec:
- granulerate numerator & denominator
- number of header pages/packets
- Content-Type message header field, e.g. text/x-cmml, text/x-srt according to rfc2045
- if no charset parameter is given, it defaults to UTF-8
- directionality of this text is implicitly given by the charset
- Content-Language, e.g. en-AU, de-DE according to rfc4646 and http://www.iana.org/assignments/language-tags
- Text-Type, e.g. CC, SUB, etc (see abbreviations as defined above)
The default granule rate for text codecs is: 1/1000.
The granule position format
Text codecs are discontinuous codecs. The data packets are placed into the Ogg stream at the time where the data starts. Their duration is given inside the data packet. Thus, when seeking to a specific time offset in a Ogg file that has a text codec, it can be quite difficult to determine what text data should still be on screen.
The solution is to seek forward to the next text codec page, which then has information on the first text codec page that is still active. Then you can seek back to this page and seek forward to the previous page to gather all the pages that are still active.
For this, the granulepos is being segmented into two parts, where one part signifies the insertion time of the current page, and the other part contains the granulepos of the first page with text codec data that is still active.
+-----------------+-----------------+ | granulepos prev | current time | +-----------------+-----------------+
The size of this segmentation is stored in the 1 Byte integer granuleshift number of the Skeleton Fisbone. It describes how many of the lower bits to use for the partitioning. The upper bits then still signify a time-continuous granule position for a directly decodable and presentable data granule. The lower bits allow for specification of the granule position of a previous still active text codec page.
The default granule shift used for text codecs is 32, which halfs the granule position to allow for the backwards pointer.
Data packets are generally the text data that is encapsulated into Ogg at a specific time.
For text codecs, each data packet is mapped onto a single Ogg data page with all its content. This is possible because generally text codec packets are rather small. The insertion time is encoded in the granule_pos of the Ogg page.
Since with text codecs we are talking about discontinuous codecs, there may be a long time between codec pages in a multiplexed stream. Therefore, optionally, the inclusion of keep-alive pages to be sent at regular intervals in the data stream is encouraged. This helps a decoder's seeking code to find a currently active text packet more easily.
Thus, the following data pages can be distinguished:
- ordinary data pages
- keep-alive pages
The format of a Data page
0 1 2 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1| Byte +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | packtype | filler / future use - 0 | 0-3 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Start Time | 4-7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Start Time (continued) | 8-11 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | End Time | 12-15 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | End Time (continued) | 16-19 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Codec Data ... | 20-... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The granulepos of a data page contains the start time encoded as a granule position in the higher bytes (see above). The lower bytes are used for seeking.
Therefore, the duration that a data page is on screen is not encoded in the encapsulation format. In CMML, the duration was set by creating pages that would end previously active pages. Here, instead, we decide to encode the duration directly into the data page and make all such calculations from the data that is stored at the beginning of the data packet.
In essence, we would only require to put the end time into the data page. However, for completeness, we add both, the start and the end time. Both are specified in seconds from the start of the video.
After that, the data of the text codec will be encapsulated. This would preferrably be without a repetition of the start and end time. For example, for srt, it makes sense to include just the subtitle text as codec data.
The EOS page ends a text codec stream. It is an empty packet because all the information of the codec is encapsulated in the earlier data pages.