Fix CTS=0 in fragmented fMP4 with multiple tracks (#317)

* Fix CTS=0 in fragmented fMP4 with multiple tracks

When muxing fragmented MP4 with both video and audio tracks,
compositionTimeOffset (CTS) was zero for all video samples, causing
B-frame content to display in decode order instead of presentation
order (visible judder).

Root cause: During finalize(), interleaveSamples(true) triggers
finalizeFragment() via the cross-track keyframe check in
addSampleToTrack. This writes the trun box before processTimestamps
has computed correct decodeTimestamp values, so CTS = PTS - DTS = 0.

Fix: Call processTimestamps() for all tracks at the start of
finalizeFragment(). This is safe because processTimestamps is a no-op
when the timestampProcessingQueue is empty.

Video-only fragmented muxing was unaffected because the single-track
case never triggers the cross-track keyframe check during
interleaveSamples.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Fix the problem at the actual root

* Oopsie doopsie

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Vanilagy <[email protected]>
This commit is contained in:
Kyle Graehl
2026-03-06 09:56:53 +00:00
committed by GitHub
co-authored by Claude Opus 4.6 Vanilagy
parent 472dc113e3
commit 6a11a1302c
4 changed files with 55 additions and 13 deletions
+4 -3
View File
@@ -18,10 +18,11 @@
});
const videoTrack = await input.getPrimaryVideoTrack();
const sink = new Mediabunny.VideoSampleSink(videoTrack);
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
const sample = await sink.getSample(await videoTrack.getFirstTimestamp());
console.log(sample);
for await (const packet of sink.packets()) {
console.log(packet.timestamp);
}
/*