Skip to content
AZ Tools

Ogg Container Inspector

An Ogg file is not a codec, it is a container: a flat run of pages, each carrying a fragment of some logical stream. This inspector walks every page and shows what the 27-byte header really holds — the OggS capture pattern, the version, the header-type flags that mark a beginning-of-stream, an end-of-stream or a packet continued from the previous page, the 64-bit granule position, the serial number of the stream the page belongs to, the page sequence number and the CRC32. It then recomputes that checksum over the page with the CRC field zeroed, using the non-reflected polynomial 0x04C11DB7 that Ogg specifies rather than the reflected CRC-32 in zlib, and shows stored and computed side by side, so a bit rot that a player silently glosses over becomes a row you can point at. The segment table is the part nothing else displays. Up to 255 lacing values say how the page divides into packets, and a value of exactly 255 does not end a packet: it says the packet runs into the next segment, and if it is the last value on the page, into the next page. That is how a comment header carrying a cover image — easily a hundred kilobytes — is spread over dozens of pages whose granule position is -1, because no packet finishes on any of them. Pages are then grouped by serial number into logical streams and the identification header at the front of each is decoded: Vorbis, Opus, FLAC-in-Ogg, Theora and Speex, with the comment header read as the multimap it is, duplicate keys and all. Two questions get answered that a player will not answer for you. Are the streams interleaved — multiplexed, video with its audio — or laid end to end, chained, which is what concatenating two Ogg files produces and which players handle inconsistently? And does every stream have both a beginning-of-stream and an end-of-stream page, since a truncated download has no EOS, still plays, and reports the wrong length to everything that asks.

How to use

  1. Drop an .ogg, .oga, .ogv, .opus or .spx file on the box. The whole file is read, because the duration lives in the granule position of the very last page.
  2. Read the container tiles first: how many logical streams there are, whether they are multiplexed or chained, and whether every page CRC checks out.
  3. Open the per-stream block for the codec details — channels and rate for Vorbis, pre-skip and channel mapping for Opus, bit depth and total samples for FLAC-in-Ogg — plus the vendor string and every comment field in file order.
  4. Scan the page table for the flags: BOS on the first page of a stream, EOS on the last, and cont on any page that begins in the middle of a packet.
  5. Check the warnings. A missing EOS page, a CRC that does not match, or a gap in the sequence numbers each name a specific way the file is damaged.

Frequently asked questions

Why does my Opus stream show 16 kHz in one row and 48 kHz in another?
Because they are different things. The input sample rate in the OpusHead header is documentation: it records what was fed to the encoder so that a decoder can resample back if it wants to. Opus itself has exactly one internal rate, 48 kHz, and that is also the rate its granule positions count in, so a one-second file recorded at 16 kHz ends on a granule of roughly 48 312 rather than 16 000. Reading the input rate as the playback rate is the classic Opus mistake and it makes every duration you calculate wrong by the ratio between the two.
What is a granule position, and why do some pages show -1?
The granule position is the codec's own clock, written at the end of each page: for Vorbis and FLAC it is the sample number of the last sample decodable from that page, for Opus it is the same in 48 kHz samples including the pre-skip, and for Theora it is a packed pair of a key frame number and an offset from it. A page shows -1 (all 64 bits set) when no packet finishes on it at all, which happens whenever a packet is large enough to span pages. That is not damage; it is the only honest value, because the page ends in the middle of something.
The tool says my file is chained. What does that mean?
A chained file is two or more complete Ogg streams laid end to end, each with its own serial number, its own headers, its own beginning-of-stream and end-of-stream pages. It is exactly what you get from `cat a.ogg b.ogg`, and the specification allows it. What the specification does not do is make players agree: some play the whole chain, some play the first link and stop, some report the duration of the first link while playing all of them, and some seek bars go haywire halfway through. If you wanted one continuous file, re-encode rather than concatenate.
One page fails the CRC check. Is the file broken?
Something changed after the page was written, yes — but not necessarily the audio. Ogg's CRC covers the whole page including its header, so a tag editor that patched a byte in place without recomputing the checksum leaves exactly this trace, as does a single flipped bit from bad storage or a truncated-then-resumed download. Note that this is not zlib's CRC-32: Ogg uses polynomial 0x04C11DB7 with no input or output reflection and no final inversion, computed with the checksum field set to zero, which is why tools that reach for the usual library routine report every page as bad.
Why is one packet spread across thirty pages?
Because a page can hold at most 255 segments of at most 255 bytes, so 65 025 bytes is the ceiling, and a comment header carrying embedded cover art routinely exceeds it. The segment table encodes the overflow by ending the page on a lacing value of 255, which means "not finished"; the next page sets the continued flag and picks up where the last one stopped. This is also why you cannot cut an Ogg file at any page boundary and expect the halves to work: a page beginning with the continued flag has no complete packet at its start.
The duration here does not match what my player reports. Which one is right?
Look at the end-of-stream flag first. This page computes duration from the granule position of the last page it can find, minus the pre-skip for Opus; if that stream has no EOS page, the file was truncated and neither number means much — your player may be extrapolating from the bitrate instead. For a chained file the durations are summed here, while many players report only the first link. And for Opus, a reader that forgets to subtract pre-skip is long by about 6.5 milliseconds on every file, which is invisible on a song and obvious on a click track.

Related tools