Skip to content

Trim the AC-3 decoder delay in transport streams - #21

Merged
FedyaLight merged 2 commits into
mainfrom
fix/ac3-decoder-delay
Nov 12, 2026
Merged

FedyaLight merged 2 commits into
mainfrom
fix/ac3-decoder-delay

Conversation

@FedyaLight

Copy link
Copy Markdown
Owner

AC-3 and E-AC-3 decode 256 samples (5.3 ms at 48 kHz) late. MP4 and MOV
record that in their edit list, which FFmpeg applies. MPEG-TS, the container
of AVCHD (.MTS/.M2TS), records it nowhere, so FFmpeg's raw output keeps
it, and on Windows and Linux AVCHD audio sat 5.3 ms earlier than on macOS,
where AVFoundation trims the delay.

The ffprobe parser now marks AC-3 and E-AC-3 streams in MPEG-TS with that
256-sample decoder_delay, and the FFmpeg tier starts them that much later
for whole-file analysis, refinement windows and native (export) decoding.
Every other stream keeps a delay of 0.

Exports follow the trimmed timing:

  • The trim leaves the container's last 256 samples without audio. Channel
    stems and placement pads fill that gap with silence, as they already fill
    a camera's sub-frame tail, so an audio-only transport stream still exports
    at its container length. Before, the shortfall failed the stem with
    "Cannot decode audio for drift correction." Audio missing anywhere else is
    still rejected.
  • Clean-media export of cameras outside QuickTime and MP4 runs FFmpeg on the
    recorder directly. It now skips the recorder's decoder delay too, instead
    of placing its audio 256 samples late.

The fingerprint cache namespace is not bumped here: fingerprints of AC-3 in
MPEG-TS made before this change are 5.3 ms early. This ships after
fix/damaged-audio-packets, which moves the namespace to portable4; if it
were released without it, portable3 would need the bump.

Evidence:

Clip macOS (AVFoundation) Windows/Linux before after
Sony HDR-CX6, camera original (AC-3 5.1) 0.0747 s 0.0800 s 0.0747 s
AVCHD Lite, camera original (AC-3 stereo) −0.0053 s 0.0000 s −0.0053 s
Generated MTS, AC-3, content at a known 2.000 s 2.000 s 1.9947 s 2.000 s

(The camera clips were synchronized against their own audio extracted from
the first video frame; what matters is that both engines now agree.)

Not changed: AAC in MPEG-TS. Its encoder priming is recorded nowhere either,
and the engines disagree in opposite directions (AVFoundation trims 2112
samples, FFmpeg none, an FFmpeg-encoded stream primes 1024), so there is no
reliable correction. AVCHD uses AC-3 or LPCM.

Tests, each failing without its fix:

  • ac3_in_transport_streams_starts_on_time places a click encoded at 1.5 s
    exactly, from the head, after a seek, and in a refinement window. Without
    the trim it lands at sample 72256 instead of 72000.
  • stems_of_audio_with_a_trimmed_decoder_delay_keep_their_length: a stem of
    a whole audio-only transport stream has the container's length, with the
    click on time.
  • ffmpeg_remux_trims_the_recorder_decoder_delay: a clean-media export of an
    MPEG-TS camera places the recorder's click at sample 31200, not 31456.

Validation:

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

AC-3 and E-AC-3 decode 256 samples late. MP4 and MOV record that in their
edit list, which FFmpeg applies, but MPEG-TS (AVCHD) records it nowhere,
so on Windows and Linux AVCHD audio sat 5.3 ms earlier than on macOS,
where AVFoundation trims the delay. The FFmpeg tier now starts those
streams 256 samples later for whole-file, window and native decoding.

On camera-original Sony HDR-CX6 and AVCHD Lite clips the portable engine
now places the audio exactly where AVFoundation does.
Trimming 256 samples from the start of AC-3 in MPEG-TS leaves the last
256 samples of the container without audio. Stems and placement pads now
fill that gap with silence, as they fill a camera's sub-frame tail, so an
audio-only transport stream exports at its container length instead of
failing with "Cannot decode audio for drift correction."

Clean-media export through FFmpeg (cameras outside QuickTime and MP4)
decodes the recorder with FFmpeg directly; it now skips the recorder's
decoder delay too, instead of placing its audio 256 samples late.
@FedyaLight
FedyaLight merged commit e668564 into main Nov 12, 2026
14 checks passed
@FedyaLight
FedyaLight deleted the fix/ac3-decoder-delay branch November 12, 2026 07:29
@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