Ogg mapping for Opus
The IETF Opus codec is a low-latency audio codec optimized for both voice and general-purpose audio. See [tools.ietf.org/html/draft-ietf-codec-opus the spec] for technical details.
Almost everything about this codec is either fixed or dynamically switchable, so the usual id and setup header parameters in the header packets of an Ogg encapsulation aren't useful. In particular, bitrate, frame size, mono/stereo, and coding modes are all dynamically switchable from packet to packet. A one-byte header on each data packet defines the parameters for that particular packet.
Remaining parameters we need to signal are:
- magic number for stream identification
- comment/metadata tags
Additionally there's been a desire to support some kind of channel bonding for surround, and some kind of option signalling for "Opus Custom", in particular the granulerate.
Granulepos is the count of decodeable samples at a fixed rate of 48 kHz.
Two headers: id, comment
- 8 byte 'OpusHead' magic signature (64 bits) - 4 byte Input sample rate (32 bits, max 192 kHz) - 1 byte channel mapping flags (bool in byte) - 1 byte channel count (8 bits) - 2 byte pre-gap (16 bits) - <optional channel mapping?>
- 8 byte 'OpusTags' magic signature (64 bits) - rest follows the vorbis-comment header design used in OggVorbis, OggTheora, and Speex. ** Vendor string (always present) ** tag=value metadata strings (zero or more)
Some discussion is in order.
- magic signature
The signature magic values allow codec identification and are being human readable. Starting with 'Op' helps distinguish them from data packets.
- input rate
This is not the sample rate for playback of the encoded data.
Opus has a handful of coding modes, supporting 8, 12, 16, 24, and 48 kHz signals. Which mode is chosen can be switched dynamically from packet to packet in the stream, but the reference decoder can generate output at any of those sample rates from the compressed data. Fidelity to the original sample rate of the encode input is not preserved by the lossy compression. Therefore, if the playback system supports one of those modes natively, 'the best option for quality is to not resample' but to play back directly at 48 kHz regardless of the value of this field.
However, the Ogg mapping allows the encoder to pass the sample rate of the original input stream as metadata. We felt this could be useful downstream, and as something intended for machine consumption, didn't belong in the tag header. For example, a decoder writing PCM format to disk might choose to resample the output audio back to the original input rate to reduce surprise.
- channel mapping flags
We want to support multichannel. This isn't specified yet; the plan is to modify the codec draft to allow packing frames from independent streams into the same packet. The difficulty is that each can be independently interpreted as mono or stereo, so we need both some way to signal which is which, and what mapping there is between each of those coded channels and discrete (or matrixed) output channels.
For example, we can't just code 5.1 and three stereo Opus streams, because then LFE ends up sharing a stereo pair with another channel (RR in the Vorbis channel order) which isn't a good idea, while 6 mono channels wastes bandwidth. Or, when routing multitrack audio between mixing boards, it helps to be able to flag which instruments should be treated as mono and which are stereo.
There's a lot of specify here, without a lot of demand from current implementors. Ralph suggests we just specify that this byte be 1 for mono streams, 2 for stereo, and both cases correspond to a single Opus steam in each packet. (Zero could indicate no mapping, higher bits could be static surround mappings or signal optional later fields. Once we have a concrete idea on the frame packing.)
- channel count
This is intended to signal the number of output channels in the Ogg logical stream. Only 8 bits was chosen because it limits individual packets to < 64k which is important for IP transports. Ralph doesn't see how that's relevant to Ogg, which has a fragmentation mechanism, but if it's a limit of the opus packet format, that's fine.
Ralph suggests this should be optional, since the channel number in the non-multichannel case is handled by the channel mapping flags proposal above.
This is the number of samples (at 48 kHz) to discard from the decoder output before starting playback. The idea is to mitigate transients, and to allow sample-accurate editing through Ogg chaining.