Loudness Normalization for Streaming: EBU R128, -16 LUFS, and Why Viewers Should Never Touch the Volume

Integrated loudness, true peak limits, and how ingest-time normalization ends the 'why is this video so loud' complaint — plus FFmpeg commands that actually work.

Users don’t experience video quality first — they experience loudness first. A catalog where every video plays at a different level is a catalog where every user is riding the volume control and blaming your platform for it. Loudness normalization is the fix, and it’s a solved problem — if you implement it at ingest, not in the player.

The Vocabulary That Matters

TermWhat It MeasuresWhy It Matters
LUFS (integrated)Perceived loudness over the full durationThe normalization target
True Peak (dBTP)Inter-sample peak, not just sample peakPrevents codec clipping
LRA (LU range)Dynamic range within the programWhether quiet parts stay quiet
Short-term loudness3-second sliding windowCatches momentary jumps

The Target: -16 LUFS Integrated, -1.0 dBTP

-16 LUFS is the streaming sweet spot — loud enough to feel full, quiet enough to leave headroom for mobile speakers and Bluetooth compression. Broadcast uses -23 LUFS (EBU R128) or -24 LKFS (ATSC A/85); streaming platforms converge on -16 (Apple) or -14 (Spotify). Pick -16 for speech-first content — it’s the safer middle.

Ingest-Time Normalization with FFmpeg

The correct approach is two-pass: measure first, then apply a filtered gain with true-peak limiting.

# Pass 1 — measure
ffmpeg -i input.mp4 -af loudnorm=I=-16:TP=-1.0:LRA=11:print_format=json -f null -

# Pass 2 — apply with measured values (the important part)
ffmpeg -i input.mp4 \
  -af "loudnorm=I=-16:TP=-1.0:LRA=11:measured_I=<X>:measured_TP=<Y>:measured_LRA=<Z>:measured_thresh=<W>" \
  -c:v copy -c:a aac -b:a 160k output.mp4

Single-pass loudnorm works but is worse — it estimates dynamics on the fly and can pump during quiet sections. Two-pass is deterministic.

“Normalization isn’t making everything loud — it’s making everything consistent. The catalog where every video starts at the same perceived volume is the one nobody ever thinks about, which is the point.”

What Happens in the Player

Do normalization at ingest, not playback. Player-side normalization (ReplayGain-style) requires analyzing every stream before playback, which you can’t do reliably on a live or adaptive stream. The player should play what’s delivered; the delivered audio should already be correct.

Our loudness targets per content type, the two-pass FFmpeg pipeline, and the QC checks that catch normalization failures are documented in the loudness normalization implementation guide.