Skip to content

recorder: fix timestamps of MPEG-1/2 Audio tracks in fMP4 recordings - #6361

Merged
aler9 merged 1 commit into
bluenviron:mainfrom
spicysharkco:fix/recorder-mpeg1-audio-dts
Oct 19, 2026
Merged

aler9 merged 1 commit into
bluenviron:mainfrom
spicysharkco:fix/recorder-mpeg1-audio-dts

Conversation

@spicysharkco

Copy link
Copy Markdown
Contributor

A path has record: yes and recordFormat: fmp4 (the default), and a client publishes MP3 or MP2 audio. The recorder writes every sample with a DTS of twice the PTS, so recorded time runs twice as fast as absolute time. After 5 seconds the drift check in formatFMP4Track.write fires, the log shows detected drift between recording duration and absolute time, resetting, and the segment is closed; a new one starts 2 seconds later. A 20 second stream gives three files, each with about 5 seconds of audio that it says lasts about 10, and the audio between them is lost. Inside each file a 44.1 kHz sample is 4702 ticks long instead of 2351, and when a unit holds several frames, all but the last get a duration of 0.

Cause: the MPEG-1/2 Audio case computes dts: u.PTS + u.PTS (format_fmp4.go#L752). A dt that adds up the frame durations is declared at L732 and updated per frame but never read. This came with #2925 (v1.5.0), which moved the other codecs to PTS + dt and wrote PTS + PTS here; before it, this case used dts: pts with a per-frame advance. Since the drift reset of #5239 (v1.15.5), the doubled time also cuts the recording.

Fix: keep a pts that starts at the unit PTS and moves forward by each frame's length in clock rate ticks, and use it as the DTS. The NTP of each frame moves by the same offset, as in the Opus, MPEG-4 Audio and AC-3 cases. The RTMP muxer already steps through these frames the same way.

The new TestRecorderFMP4MPEG1AudioDuration is shaped like TestRecorderFMP4H264RecoveryPoint. It records three units of two frames each, reads the parts back with fmp4.Parts.Unmarshal, and checks that the five samples last 2351 ticks.

go test -count=1 -v -run '^TestRecorderFMP4MPEG1AudioDuration$' ./internal/recorder
go test -race -count=1 ./internal/recorder

Before the fix the test fails with expected: 0x92f, actual : 0x0. After it, the test passes (-count=10), and the package passes with -race. Putting back any one of the three DTS changes fails it again.

No open PR touches this case. #5714, #5984 and #6305 also edit recorder_test.go, and none conflicts with this change.

The DTS of every sample was computed as the unit PTS plus the unit PTS,
so sample durations in the recording were twice the real ones, and the
frames of a unit that holds several of them got the same timestamp.
Advance the PTS by the duration of each frame instead, and move the NTP
of each frame by the same offset, as the Opus, MPEG-4 Audio and AC-3
cases do.
@codecov

codecov Bot commented Oct 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.14%. Comparing base (4495015) to head (e8dd049).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6361      +/-   ##
==========================================
+ Coverage   70.97%   71.14%   +0.16%     
==========================================
  Files         282      282              
  Lines       21611    21610       -1     
==========================================
+ Hits        15339    15374      +35     
+ Misses       6272     6236      -36     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aler9
aler9 merged commit ab611af into bluenviron:main Oct 19, 2026
12 checks passed
@aler9

aler9 commented Oct 19, 2026

Copy link
Copy Markdown
Member

merged, thanks!

@github-actions

Copy link
Copy Markdown
Contributor

This issue is mentioned in release v1.21.3 🚀
Check out the entire changelog by clicking here

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.

2 participants