Anatomy of an MP3 file
An MP3 looks like a single opaque blob, but it is really two things glued together: a block of ID3 metadata and a long run of independent MPEG audio frames. This is a byte-level tour of both — for MPEG-1, MPEG-2 and MPEG-2.5 Layer III — with a short history of how the format took over the world.
A short history of the MP3
MP3 — formally MPEG-1/2 Audio Layer III — grew out of psychoacoustic research at Germany's Fraunhofer IIS, led by Karlheinz Brandenburg, together with the University of Erlangen and partners across Europe. The idea was radical for the late 1980s: throw away the parts of an audio signal the human ear can't hear (frequencies masked by louder ones) and encode only what's left, shrinking CD-quality audio roughly tenfold.
- 1991–1993 — Layer III is standardised as part of MPEG-1 (ISO/IEC 11172-3). It targets the CD sample rates: 32, 44.1 and 48 kHz.
- 1995 — MPEG-2 (ISO/IEC 13818-3) adds the lower "half" sample rates (16, 22.05, 24 kHz) for lower-bitrate use. On 14 July 1995 Fraunhofer settles on the now-famous
.mp3file extension. - 1997 — Nullsoft's Winamp ships and makes MP3 playback effortless on the PC. Encoders like the open-source LAME project make ripping CDs to MP3 mainstream.
- 1999 — Napster turns MP3 into a cultural and legal earthquake; the small, portable file is perfect for the early internet.
- 2001 — Apple's first iPod (“1,000 songs in your pocket”) cements compressed audio as the default way people carry music.
DRM-free, thanks in large part to Amazon. For years, legal downloads were wrapped in copy-protection (DRM) that locked songs to one store's players. That changed in September 2007 when Amazon.com launched Amazon MP3 — the first major online music store to sell DRM-free MP3s, and the first to offer that catalogue from all four major record labels. Buyers finally got a plain .mp3 they could play anywhere, on any device, forever. It pushed the whole industry toward unrestricted downloads (Apple's iTunes went fully DRM-free in 2009).
The last of the MP3 patents expired around 2017, and Fraunhofer ended its licensing program that April — making MP3 not just ubiquitous but fully free to implement. Newer codecs (AAC, Opus) are more efficient, but MP3's universal compatibility keeps it everywhere.
The overall file layout
Read from offset 0, a typical MP3 is:
┌───────────────────────────────────────────────┐
│ ID3v2 tag "ID3" + version + size + frames │ ← optional, at the very start
│ TIT2 title · TPE1 artist · TALB album · APIC │ (title/artist/album/cover art)
├───────────────────────────────────────────────┤
│ MPEG audio frame #0 [Xing/Info VBR header] │ ← first frame often holds the
│ MPEG audio frame #1 │ duration/VBR table
│ MPEG audio frame #2 │
│ … thousands of independent frames … │
│ MPEG audio frame #N │
├───────────────────────────────────────────────┤
│ ID3v1 tag "TAG" + 125 bytes │ ← optional, the last 128 bytes
└───────────────────────────────────────────────┘
The ID3v2 block and the ID3v1 trailer are both optional. The audio itself is just a stream of self-describing frames — each frame carries its own header, so a player can start decoding from almost anywhere. That's exactly why streaming and “seek by scanning for the next sync word” work.
Open any MP3 in the OmniViewer hex view and you'll see the 49 44 33 (“ID3”) magic at offset 0, then FF Fx sync bytes where the first audio frame begins. The METADATA tab decodes the ID3 frames for you.
The 32-bit frame header
Every audio frame begins with a four-byte header. All 32 bits:
AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
A (11) frame sync — all 1s (bytes read FF Ex/Fx)
B (2) MPEG version 00=2.5 01=reserved 10=MPEG-2 11=MPEG-1
C (2) layer 01 = Layer III (MP3)
D (1) protection 0 = a 16-bit CRC follows the header
E (4) bitrate index → looked up in a per-version table
F (2) sample-rate index → per-version table (see below)
G (1) padding 1 = frame is 1 byte longer (keeps avg bitrate exact)
H (1) private bit
I (2) channel mode 00 stereo · 01 joint · 10 dual · 11 mono
J (2) mode extension (joint-stereo params)
K (1) copyright L (1) original M (2) emphasis
Because bitrate and sample rate live in every header, a file can switch bitrate frame to frame — that's VBR (variable bitrate). The header also fixes how long the frame is:
MPEG-1 Layer III: frameLength = 144 × bitrate / sampleRate + padding
MPEG-2 / 2.5 Layer III: frameLength = 72 × bitrate / sampleRate + padding
The 144 vs 72 is not arbitrary: it's samplesPerFrame / 8. An MPEG-1 frame carries 1152 samples; an MPEG-2 or 2.5 frame carries 576. Fewer samples per frame is how the lower sample-rate versions keep frames small.
Anatomy per MPEG version
Layer III comes in three flavours. They share the header format above but differ in the sample rates they allow, how many samples a frame holds, and the size of the per-frame “side information” block:
| Property | MPEG-1 Layer III | MPEG-2 Layer III | MPEG-2.5 Layer III |
|---|---|---|---|
| Version bits (B) | 11 | 10 | 00 |
| Sample rates | 32 · 44.1 · 48 kHz | 16 · 22.05 · 24 kHz | 8 · 11.025 · 12 kHz |
| Samples per frame | 1152 | 576 | 576 |
| Bitrates (kbps) | 32–320 | 8–160 | 8–160 |
| Side info — stereo | 32 bytes | 17 bytes | 17 bytes |
| Side info — mono | 17 bytes | 9 bytes | 9 bytes |
| Length constant | 144 | 72 | 72 |
| Standard | ISO/IEC 11172-3 | ISO/IEC 13818-3 | Fraunhofer extension |
MPEG-2.5 is worth a note: it is not part of any ISO standard. It's a Fraunhofer extension that reuses the reserved version bits (00) to reach very low sample rates (down to 8 kHz) for speech and ultra-low-bitrate streams. Most decoders support it anyway.
Inside a single frame
┌────────┬──────┬────────────┬──────────────────────────┐
│ header │ CRC │ side info │ main data (Huffman-coded) │
│ 4 B │ 0/2B │ 9–32 B │ scalefactors + frequencies │
└────────┴──────┴────────────┴──────────────────────────┘
▲ present only if the protection bit (D) = 0
The side info tells the decoder how to read the main data (bit reservoir pointer, scalefactor layout, Huffman table selection). A frame whose side info and main data are all zero decodes to silence — which is exactly the trick the MP3 generator uses to build valid files of any size.
ID3 tags: the metadata
The audio frames carry no title or artist — that's what ID3 is for. Two incompatible schemes coexist:
ID3v1 — 128 bytes at the end
offset bytes field
0 3 "TAG" magic
3 30 title
33 30 artist
63 30 album
93 4 year
97 30 comment (last 2 bytes may encode a track number → "ID3v1.1")
127 1 genre (index into a fixed list)
Fixed-width, ASCII/Latin-1, no room for cover art — a relic, but still written by many tools. Because it's a fixed 128-byte trailer, a reader only has to look at the last 128 bytes.
ID3v2 — a rich block at the start
ID3v2 (v2.2/2.3/2.4) sits before the audio and is a container of frames, each a four-character ID plus a size and payload:
"ID3" ver(2) flags(1) size(4, "synchsafe" — 7 bits per byte)
then repeating frames:
TIT2 title TPE1 artist TALB album
TPE2 album artist TRCK track TCON genre
TYER/TDRC year COMM comment APIC attached picture (cover art)
The size is synchsafe — only the low 7 bits of each byte are used — so a tag's length can never accidentally contain the FF byte that would look like a frame sync. OmniViewer's METADATA tab reads and rewrites these v2.3/v2.4 text frames; the generator writes a fresh v2.4 tag.
The Xing / Info / VBRI header
One more wrinkle: for a variable-bitrate file you can't work out the duration by dividing file size by bitrate — the bitrate changes. So encoders put a special metadata block inside the first audio frame (which is otherwise silent):
- Xing — the classic VBR header: total frame count, total bytes, and a 100-point seek table.
- Info — the same structure but written for constant-bitrate files (so players know it's CBR).
- VBRI — Fraunhofer's own variant, occasionally seen from their encoders.
This is why a player can show an accurate track length and seek instantly even in a VBR MP3. LAME also appends a small “LAME tag” here recording the encoder version and settings — the LAME3.100 strings you'll spot scattered through the raw bytes of many files.