Skip to content

Align track starts at the relay so DASH output carries no video edit list#53

Merged
roddylindsay merged 1 commit into
EnvelopSound:masterfrom
mormegil6:align-track-starts
Jul 22, 2026
Merged

Align track starts at the relay so DASH output carries no video edit list#53
roddylindsay merged 1 commit into
EnvelopSound:masterfrom
mormegil6:align-track-starts

Conversation

@mormegil6

Copy link
Copy Markdown
Contributor

What this fixes

Earshot's DASH output desyncs audio and video by up to one GOP on Chromium and Safari whenever the transcoder (re)starts against a live stream. The offset is different after every restart, so it cannot be tuned away downstream.

Mechanism

The transcoder is an nginx-rtmp exec ffmpeg that subscribes to the internal live application. A subscriber joining a live stream receives audio immediately, but no decodable video until the next keyframe arrives, up to one GOP later. ffmpeg therefore sees the video track start later than the audio track, and the DASH muxer faithfully records that skew as a leading empty edit (elst, media_time = -1) on the video track in the init segment.

Firefox applies that edit through MSE and stays in sync. Chromium and Safari do not apply it through MSE, so they present video early by the edit amount. The divergence is documented with a minimal repro here:

Since most MSE players land on the dropping side, an Earshot deployment feeding dash.js/Shaka/hls.js on Chrome inherits an A/V desync that changes size on every encoder restart.

Fix

Two stock nginx-rtmp directives on the live application, in both conf variants:

wait_key on;     # relayed video starts at a keyframe
wait_video on;   # audio is held until video flows

With these, both tracks genuinely start together, so there is no skew for the muxer to record and no edit list is written at all. Every player then behaves identically because there is nothing left to interpret.

Measurements

Restart drill with a flash/beep marker contribution (flash and beep co-timed in the source; H.264 + 16-ch AAC, 2 s GOP, -c:v copy transcode):

video init edit list decoded flash-vs-beep offset
without directives leading empty edit on every join, 0.3 to 2.0 s (bounded by the GOP) equals the edit size (tracks physically skewed)
with directives [(0, 0)] on 20 of 20 runs within 3 ms

The second column is measured by decoding the output media directly (frame brightness and beep onset), independent of the edit list, which verifies the edit disappears because the tracks align, not because it was suppressed.

Why not -use_editlist 0

Suppressing the edit list would leave the tracks skewed and delete the metadata Firefox correctly honours, desyncing Firefox to match the others. Aligning the track starts fixes the cause instead of hiding the symptom.

Trade-off

wait_video delays the transcoder's input until the first keyframe after the join, so DASH output begins up to one GOP later than before. For a transcoding relay this is a startup cost only; steady-state latency is unchanged.

Copilot AI review requested due to automatic review settings July 21, 2026 18:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the nginx-rtmp “live” application configuration used by Earshot’s ffmpeg DASH transcoding relay so that relayed streams begin on a video keyframe and audio is held until video is available, preventing the DASH muxer from writing a leading empty video edit list that causes A/V desync in Chromium/Safari MSE.

Changes:

  • Enable wait_key on; so subscribers start receiving video at a keyframe boundary.
  • Enable wait_video on; so audio delivery is delayed until video is flowing.
  • Apply the same settings to both SSL and no-SSL nginx config variants.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
nginx-transcoder/nginx.conf Adds wait_key and wait_video to align audio/video track start for the transcoding relay.
nginx-transcoder/nginx-no-ssl.conf Mirrors the same wait_key/wait_video alignment behavior in the no-SSL config variant.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mormegil6
mormegil6 force-pushed the align-track-starts branch from d2bc80c to ae2a7d6 Compare July 22, 2026 09:02
@roddylindsay
roddylindsay merged commit d8039a2 into EnvelopSound:master Jul 22, 2026
@mormegil6
mormegil6 deleted the align-track-starts branch July 23, 2026 14:17
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.

3 participants