Skip to content

Trim MP3 encoder delay as FFmpeg does - #22

Merged
FedyaLight merged 1 commit into
mainfrom
fix/mp3-encoder-delay
Nov 12, 2026
Merged

FedyaLight merged 1 commit into
mainfrom
fix/mp3-encoder-delay

Conversation

@FedyaLight

Copy link
Copy Markdown
Owner

Stacked on the #16 branch (fix/damaged-audio-packets), which introduced the
extension-named container readers this change configures.

MP3 encoders prime their output: LAME adds 1105 samples of delay at the start
and padding at the end, and records both in its LAME/Info header. FFmpeg
trims them. Align's in-process decoder (Symphonia, on Windows and Linux) did
not, so MP3 audio sat 23 to 25 ms early and synchronized that far off — more
than half a frame at 25 fps.

The delay Symphonia reads from the LAME header (encoder delay plus the
decoder's 529 samples, 1105 for LAME) now becomes the stream's lead, which
whole-file decoding, seeks, refinement windows and native decoding already
skip for MP4 edit lists. Files without a LAME header are unchanged (nothing
records their delay; FFmpeg cannot trim them either).

Only the start is trimmed, deliberately. Symphonia's own gapless mode, tried
first, also trims the end at a frame count that files without a Xing header
merely estimate from their first frames, which dropped the audio after a quiet
stretch, and it underflows when the Xing frame count contradicts the LAME
delay. End padding (under one frame) does not affect synchronization.

Evidence, on the 59-file decoder differential: the three MP3 files (CBR, VBR
with ID3, 44.1 kHz mono) moved from 1.977, 1.977 and 1.975 s to exactly
2.000 s; nothing else changed.

Tests:

  • aac_priming_matches_ffmpeg_timing becomes
    encoder_priming_matches_ffmpeg_timing and also covers MP3 (skipped
    without libmp3lame). Without the trim it fails with the click at sample
    73105 instead of 72000, the 1105-sample LAME delay.
  • mp3_frame_counts_never_cut_audio: a headerless VBR file (loud, silent,
    loud) decodes as long as FFmpeg's output, and a Xing frame count of 1
    neither panics nor shortens decoding. With Symphonia's gapless mode it
    decodes 94464 of 200448 frames.

The fingerprint cache namespace moved to portable4 in the #16 branch. If
this change ships in a later release than that one, bump it again so cached
MP3 fingerprints are recomputed.

Validation:

  • cargo fmt --all -- --check
  • cargo clippy --locked --workspace --all-targets -- -D warnings
  • cargo test --locked --workspace: 382 passed, 1 ignored

MP3 encoders prime their output: LAME's delay plus the decoder's adds 1105
samples at the start, recorded in the LAME header. FFmpeg trims them;
Align's in-process decoder did not, so MP3 audio sat 23 to 25 ms early and
synchronized that far off. The delay Symphonia reports now becomes the
stream's lead, which every decode path already skips for MP4 edit lists.

Only the start is trimmed. Symphonia's gapless mode would also cut the end
at a frame count that files without a Xing header merely estimate, which
dropped audio after a quiet stretch, and it underflows on an inconsistent
Xing frame count.

The encoder priming test now covers MP3, and a new test keeps headerless
VBR files and contradictory frame counts decoding in full.
@FedyaLight
FedyaLight deleted the branch fix/damaged-audio-packets November 12, 2026 07:27
@FedyaLight FedyaLight closed this Nov 12, 2026
@FedyaLight FedyaLight reopened this Nov 12, 2026
@FedyaLight
FedyaLight changed the base branch from fix/damaged-audio-packets to main November 12, 2026 07:27
@FedyaLight
FedyaLight merged commit 1452fe4 into main Nov 12, 2026
16 of 21 checks passed
@FedyaLight
FedyaLight deleted the fix/mp3-encoder-delay branch November 12, 2026 07:35
@FedyaLight FedyaLight mentioned this pull request Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant