What You Will Learn
- What EBU R128 loudness normalization is and why it matters
- Single-pass
loudnormfor quick normalization - Two-pass
loudnormfor accurate, broadcast-grade normalization - Key parameters: integrated loudness (
I), true peak (TP), loudness range (LRA) - How to read the JSON measurement output from pass 1
Tested version: FFmpeg 6.1 (ubuntu-latest / CI-validated)
Target OS: Windows / macOS / Linux
What Is EBU R128 Loudness Normalization?
EBU R128 is the European Broadcasting Union standard for audio loudness. It defines:
| Metric | Unit | EBU R128 Target |
|---|---|---|
| Integrated Loudness (I) | LUFS | −23 LUFS |
| True Peak (TP) | dBTP | −1 dBTP maximum |
| Loudness Range (LRA) | LU | ≤ 18 LU recommended |
LUFS (Loudness Units Full Scale) is a psychoacoustic measure of perceived loudness. Unlike peak normalization (which only looks at the highest sample value), LUFS normalization matches how loud content sounds to human ears.
Streaming platforms (YouTube, Spotify, Apple Music, etc.) use their own loudness targets, many derived from R128 or the similar ATSC A/85 standard used in broadcast.
Single-Pass Normalization (Quick)
The simplest usage applies loudnorm in a single pass:
ffmpeg -i input.mp3 -af loudnorm output.mp3
By default this targets −23 LUFS integrated loudness, −2 dBTP true peak, and 7 LU loudness range. Single-pass mode estimates the source loudness from the input stream as it processes, which is sufficient for many use cases.
Customizing Targets
ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11" output.mp3
| Parameter | Description | Default |
|---|---|---|
I | Integrated loudness target (LUFS) | −23 |
TP | True peak ceiling (dBTP) | −2 |
LRA | Loudness range target (LU) | 7 |
A target of I=-16 is closer to streaming platform targets (e.g., Spotify, YouTube). Use I=-23 for broadcast (EBU R128).
Two-Pass Normalization (Accurate)
For the most accurate normalization, use a two-pass approach:
Pass 1 — Measure the source loudness:
ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11:print_format=json" -f null /dev/null
This runs without producing output (-f null /dev/null) and prints a JSON block to stderr with the measured values:
{
"input_i" : "-27.06",
"input_tp" : "-4.28",
"input_lra" : "7.20",
"input_thresh" : "-37.06",
"output_i" : "-16.00",
"output_tp" : "-1.50",
"output_lra" : "7.20",
"output_thresh" : "-26.00",
"normalization_type" : "dynamic",
"target_offset" : "0.00"
}
Pass 2 — Apply with measured values:
Use the input_i, input_tp, input_lra, and input_thresh values from pass 1 as measured_I, measured_TP, measured_LRA, and measured_thresh in the loudnorm filter:
ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11:measured_I=-27.06:measured_TP=-4.28:measured_LRA=7.20:measured_thresh=-37.06:linear=true" output.mp3
linear=true tells the filter to apply a simple linear gain based on the measured values rather than dynamic compression. This is important: without it, the filter may apply dynamic range compression even when simple gain adjustment is sufficient.
Applying to Video Files (Audio-Only Processing)
To normalize loudness in a video file without re-encoding video:
ffmpeg -i input.mp4 -c:v copy -af "loudnorm=I=-16:TP=-1.5:LRA=11" output.mp4
-c:v copy passes video through unchanged; only the audio is re-encoded.
Understanding the Output Values
When running pass 1, the JSON output reveals:
| Field | Meaning |
|---|---|
input_i | Measured integrated loudness (LUFS) |
input_tp | Measured true peak (dBTP) |
input_lra | Measured loudness range (LU) |
input_thresh | Loudness gating threshold |
normalization_type | linear or dynamic |
If normalization_type is already linear in pass 1, the audio is within range and can be adjusted with a simple gain. If it shows dynamic, the filter will apply dynamic range compression in pass 2.
Common Pitfalls
Output Is Louder or Quieter Than Expected
In single-pass mode, loudnorm estimates loudness from the stream as it encodes. For files with varying loudness, this estimate can be inaccurate. Always use two-pass for critical content.
Audio Artifacts in Pass 1 Output
Pass 1 (-f null /dev/null) produces no output — it only measures. Do not skip pass 1 when accuracy matters.
True Peak Clipping
If the source has peaks very close to 0 dBFS, a simple gain-up can push samples over 0. The TP parameter limits the output true peak to prevent this. Set TP=-1 or lower.
Related Articles
Tested with: ffmpeg 6.1.1 / Ubuntu 24.04 (GitHub Actions runner)
Primary sources: ffmpeg.org/ffmpeg-filters.html#loudnorm / trac.ffmpeg.org/wiki/AudioVolume