OPUS File Documentation


Summary

An Opus Audio File is lossy compressed audio using the royalty-free Opus codec inside an Ogg container. Most people meet a .opus file as an exported WhatsApp or Telegram voice message. The codec is an open standard, IETF RFC 6716 (2012), and the file’s MIME type is audio/ogg; codecs=opus. The container always starts with the ASCII bytes OggS, and the string OpusHead appears at byte offset 28. VLC plays it on every platform; Windows Media Player needs Microsoft’s free Web Media Extensions add-on.

Technical details

FeatureValue
Full nameOpus Audio File (Ogg Opus)
File extension.opus
MIME typeaudio/ogg; codecs=opus (streaming: audio/opus)
Format typeLossy compressed audio — Opus codec in an Ogg container
DeveloperXiph.Org Foundation / IETF
Introduced2012 (RFC 6716); Ogg encapsulation RFC 7845 (2016)
Standard / specIETF RFC 6716 (codec); IETF RFC 7845 (Ogg mapping)
Open standardYes — royalty-free
Container / base formatOgg
Byte orderLittle-endian (OpusHead fields)
Magic number (hex)4F 67 67 53 (“OggS”) at offset 0; OpusHead at offset 28
Internal sample rate48 kHz (all timing referenced to 48 kHz)
Bitrate range6 kbit/s (narrowband speech) to 510 kbit/s (stereo)
Coding modesSILK (speech), CELT (music), Hybrid
LatencyAs low as 5 ms
MetadataOpusTags (Vorbis-comment style)
Typical useWhatsApp/Telegram/Discord/Signal voice, WebRTC, YouTube
Related extensions.ogg, .oga, .mp3, .m4a, .weba
Specification URLdatatracker.ietf.org/doc/html/rfc6716
File signature (magic bytes)
4F 67 67 53

Offset 0, 4 bytes, ASCII OggS — the Ogg page-capture pattern that begins every Ogg stream, shared with Ogg Vorbis and Ogg FLAC. What identifies the stream as Opus is the 8-byte magic string OpusHead (4F 70 75 73 48 65 61 64) that starts the first page’s payload at offset 28. A reader confirms an Ogg Opus file by matching OggS at 0 and OpusHead at 28; the second identification header, OpusTags, begins the following page.

What is an OPUS file?

A file with the .opus extension is audio compressed with the Opus codec and wrapped in an Ogg container. Opus is an open, royalty-free codec standardised by the IETF as RFC 6716 in September 2012, developed at the Xiph.Org Foundation with contributions from Skype/Microsoft and Mozilla. The way Opus is stored inside Ogg is defined separately by RFC 7845 (2016). The codec and the container are two layers: RFC 6716 describes how the audio is compressed into packets, and RFC 7845 describes how those packets are framed on disk.

Opus was built by fusing two codecs. SILK, a speech codec from Skype, handles low-bitrate voice; CELT, a low-latency music codec from Xiph, handles full-band audio; and a hybrid mode uses both. That range lets a single codec run from 6 kbit/s narrowband speech up to 510 kbit/s stereo music, with latency as low as 5 ms. It is the mandatory audio codec for WebRTC and the default voice codec of WhatsApp, Telegram, Discord and Signal, which is why the most common .opus file an ordinary user encounters is an exported voice message.

The Ogg page: capture pattern, granule position and CRC

An Ogg Opus file is a sequence of Ogg pages. Each page carries a fixed 27-byte header followed by a table of segment lengths and then the packet data, so a parser can walk pages without understanding the audio inside.

Ogg page header (27 bytes + segment table)
 0  capture_pattern    'OggS' (4F 67 67 53)
 4  version            0
 5  header_type        bit0 continued, bit1 BOS, bit2 EOS
 6  granule_position   int64: 48 kHz sample count at end of page
14  bitstream_serial   uint32: identifies this logical stream
18  page_sequence_no   uint32: increments per page
22  CRC_checksum       uint32: CRC-32 over the whole page
26  page_segments      uint8: number of segment-table entries
27  segment_table[]    lacing values (each 0-255)

Two fields matter for timing and integrity. The granule_position is a 64-bit count that, for Opus, is always expressed in 48 kHz samples regardless of the audio’s original rate; it tells a player the PCM sample number reached at the end of that page, which is how seeking works. The CRC_checksum is a CRC-32 computed over the entire page (with the checksum field zeroed during calculation), so a corrupt page is detected rather than played as noise. The header_type flags mark the beginning-of-stream (BOS) and end-of-stream (EOS) pages.

The OpusHead identification header

The payload of the very first page (the BOS page) is the OpusHead header, and because the Ogg page header is 27 bytes plus a one-byte segment count, OpusHead begins at byte offset 28 of the file. It is 19 bytes of fixed fields, optionally followed by a channel-mapping table.

OpusHead
 0  Magic Signature      'OpusHead' (8 bytes)
 8  Version              1
 9  Channel Count 'C'    uint8: number of output channels
10  Pre-skip             uint16 LE: samples (48 kHz) to discard at start
12  Input Sample Rate    uint32 LE: original rate, informational only
16  Output Gain          int16 LE: Q7.8 gain applied on decode
18  Channel Mapping Fam. uint8: 0 mono/stereo, 1 Vorbis order, ...
[19 Channel Mapping Table for family > 0]

Several fields have exact, load-bearing meanings. Pre-skip is a 16-bit little-endian value giving the number of 48 kHz samples the decoder must discard from the very start of output; it exists because the codec needs a few milliseconds to converge, and RFC 7845 recommends at least 3,840 samples (80 ms) of pre-skip when cropping the front of a stream. Input Sample Rate records the audio’s original rate for information only: Opus always decodes internally at 48 kHz, so this field does not change playback. Output Gain is a signed Q7.8 fixed-point value applied during decoding, which lets a file be normalised without re-encoding. The Channel Mapping Family selects how output channels are ordered; family 0 covers mono and stereo, and higher families add surround layouts with an explicit mapping table.

OpusTags: metadata and the comment header

The second mandatory header, carried on the next page, is OpusTags. It reuses the Vorbis-comment format: an 8-byte magic string OpusTags, a length-prefixed vendor string (typically the encoder, for example the libopus version), and then a list of FIELD=value UTF-8 comments such as TITLE=, ARTIST= and ENCODER=. All string lengths are 32-bit little-endian. Unlike ID3 tags in MP3, these comments live inside the Ogg stream as a normal packet, so a tag editor rewrites a page rather than appending a trailing block.

SILK, CELT and hybrid: what the TOC byte selects

Every Opus packet starts with a one-byte table-of-contents (TOC) header that tells the decoder which of the three modes to use and at what audio bandwidth and frame size. The top five bits form a configuration number (0–31): configurations 0–11 are SILK-only for speech at narrowband through wideband, 12–15 are hybrid, and 16–31 are CELT-only for full-band music. The next bit is the stereo flag, and the final two bits encode how many frames the packet contains.

TOC configModeTypical use
0–11SILK-onlySpeech, narrowband to wideband
12–15Hybrid (SILK + CELT)Speech and music, super-wideband/fullband
16–31CELT-onlyMusic, low latency, fullband

Frames are usually 20 ms, though the format allows 2.5, 5, 10, 20, 40 and 60 ms. Because the mode is chosen per packet, an encoder can switch from SILK to CELT mid-stream, for example when a voice note transitions from speech to background music, without a new file or a container change.

How OpusHead sits alongside other Ogg codecs

The Ogg container is codec-agnostic: the same OggS page framing carries Vorbis, FLAC or Opus. What differs is the identification header at the start of the first page’s payload. Ogg Vorbis begins with \x01vorbis, Ogg FLAC with \x7FFLAC, and Ogg Opus with OpusHead. A reader that finds OggS at offset 0 checks the bytes at offset 28 to decide which decoder to hand the packets to. This is why a .ogg file and a .opus file can share byte-identical page structure yet need different decoders.

Timing: why everything is measured at 48 kHz

Opus fixes its internal and granule clock at 48 kHz. A packet that encodes 20 ms of audio advances the granule position by 960 samples (48000 × 0.02), whatever the source rate was. To find the presentation time of a page, a player takes the page’s granule_position, subtracts the pre-skip from OpusHead, and divides by 48000. Seeking reverses this: the player picks the target sample number, finds the page whose granule position covers it, and starts decoding a little earlier so the codec state converges before the target. Getting the pre-skip subtraction wrong is the classic cause of a few milliseconds of clicks at the very start of playback.

Frequently asked questions

Why does OpusHead sit at offset 28 rather than 0?

Because the file must start with the Ogg container, not the codec. Bytes 0–26 are the first Ogg page header, byte 27 is its single segment-count entry, and the page payload (the OpusHead identification header) begins at byte 28. The OggS capture pattern at offset 0 identifies the container; OpusHead at offset 28 identifies the codec inside it.

What is pre-skip for?

The Opus decoder produces a short run of imperfect samples while its internal filters converge. Pre-skip is the exact number of 48 kHz samples to throw away at the start so that the audio you hear begins cleanly. It is stored in OpusHead so any decoder discards the same amount and playback stays sample-accurate.

References