ACIDCAT . FILE FORMAT REFERENCE

MP3 Anatomy

MPEG-1/2 AudioLayer III
rev 2026.06
magic none
endian big (frames)
container no
sample FF FB 90 C0

An MP3 is not a container. It is an optional ID3v2 tag, a run of self-describing MPEG audio frames, and an optional ID3v1 trailer. Regions below expand; the MPEG frame header is drawn as a register map. Hover any field to light its exact bits and read the decode; click a field with a + to open its lookup table. Color marks kind (see the key). Example: FF FB 90 C0, a real MPEG-1 Layer III frame at 128 kbps, 44100 Hz, mono.

file regions

Top to bottom, what a reader walks. Only the frames are required.

ID3v2 tag0x00 . variable

Prepended metadata. A 10-byte header, then frames, until padding. The tag size is synchsafe (7 bits per byte) so the length can never contain a false 0xFF sync. Frame sizes differ by version: v2.3 is a plain big-endian uint32, v2.4 is synchsafe. When the unsync flag is set the writer stuffed a 0x00 after every 0xFF; strip those before reading frame sizes.

magic"ID3"
versionmajor . revision (2.2 / 2.3 / 2.4; v2.2 uses 3-char frame ids)
flagsb7 unsync (0x00 stuffed after 0xFF) . b6 extended header . b5 experimental . b4 footer
size(b0<<21)|(b1<<14)|(b2<<7)|b3
frame sizev2.3 plain uint32 . v2.4 synchsafe
framesTIT2 . TPE1 . TALB . TBPM . APIC
MPEG audio framesrequired . self-describing

Each frame opens with the 4-byte header drawn below; it carries everything needed to compute the frame length and step to the next sync.

Xing / Info + LAMEinside frame 0 . vbr header

VBR cannot be sized from one bitrate, so the encoder writes a header into the first frame after the side-info block. "Xing" is true VBR, "Info" is CBR by LAME. Offset from frame start: 36 (MPEG-1 stereo), 21 (MPEG-1 mono or MPEG-2 stereo), 13 (MPEG-2 mono). Add 2 when the frame is CRC-protected: the 2 CRC bytes sit between the header and the side info.

id"Xing" | "Info"
flagsb0 frames . b1 bytes . b2 TOC . b3 quality
frame_countexact total, gives duration with no walk
LAME9-byte encoder string, VBR method, lowpass
replay_gain16-bit word at LAME+15: 3-bit name . 3-bit originator . sign . 9-bit 0.1 dB
bitrate1 byte at LAME+20: min for VBR, target for ABR
gaplessdelay + padding, 12 bits each at LAME+21
VBRI headerinside frame 0 . frame start + 36

The Fraunhofer encoder's VBR header. Unlike Xing/Info it sits at a fixed offset, frame start + 36, independent of version, channel mode, and side-info size. All fields big-endian; a frame carries at most one of Xing/Info/VBRI.

id"VBRI"
version2 bytes at +4
byte_count4 bytes at +10
frame_count4 bytes at +14, marks the stream VBR
ID3v1 trailerlast 128 bytes

The original tag: a fixed 128-byte block at the very end. Superseded by ID3v2, but many files carry both.

magic"TAG"
title / artist / album30 bytes each, latin-1
year4 bytes
comment30 bytes; v1.1: byte 28 is 0x00, byte 29 is the track number
genre1 byte, index into a fixed table