Give a frame that outruns its epoch's video a provisional offset
The demuxer interleaves, so at a boundary the streams do not reset on the same frame: audio for the next segment can reach the muxer before the video frame that opens the epoch it belongs to. Only the primary video track may open one, so those frames rode the just-ended offset and landed a whole segment in the past. Downstream the strictly-monotonic block nudge then crushed the entire run onto one instant a tick apart, which is audible. Such a frame is recognised on its OWN raw PTS, which within an epoch only advances, so a large backward step is unambiguous — a different signal from the shared frontier, which is what the old false-positive ratchet keyed on. It then rides a provisional offset private to its track, computed the same way the video path computes a real one, and drops it the moment the video retires an epoch, so the run rejoins with no seam. The offset is deliberately private: it never writes offset_ns, never advances the frontier and never retires an epoch, so it cannot move the video timeline. Letting a passive track open a REAL epoch was tried first and inflated a 476.776 s title to 656.216 s, because every track meets a boundary at its own pace and the video path rebased again on top. Measured on a real DVD title with 8 cell boundaries: audio frames stamped inside one cadence 120 -> 0, outsized gaps 7 -> 0, subtitle 1 -> 0, and the video span byte-identical at 476.484. On the HD-DVD title the remaining boundary gap on its first audio track falls from 0.999 s to 0.275 s. Acceptance: 76 pass, 0 fail, 0 skip.
This commit is contained in:
@@ -1543,14 +1543,14 @@ mod tests {
|
||||
fn timeline_track0_drives_epoch_others_ride() {
|
||||
let mut tl = TimelineContinuity::new();
|
||||
// Clip 1: video 0..10s (track 0 drives the epoch).
|
||||
assert_eq!(tl.adjust(0, true), 0);
|
||||
assert_eq!(tl.adjust(0, false), 0); // audio rides the same offset
|
||||
assert_eq!(tl.adjust(10_000_000_000, true), 10_000_000_000);
|
||||
assert_eq!(tl.adjust(0, true, 0), 0);
|
||||
assert_eq!(tl.adjust(0, false, 1), 0); // audio rides the same offset
|
||||
assert_eq!(tl.adjust(10_000_000_000, true, 0), 10_000_000_000);
|
||||
// Clip 2 seam: video PTS jumps back to ~0 (> 3s back) → new epoch.
|
||||
let out = tl.adjust(0, true);
|
||||
let out = tl.adjust(0, true, 0);
|
||||
assert!(out >= 10_000_000_000, "epoch must advance past prev high");
|
||||
// Audio in clip 2 (non-epoch) gets the SAME offset (A/V sync preserved).
|
||||
let a = tl.adjust(0, false);
|
||||
let a = tl.adjust(0, false, 1);
|
||||
assert_eq!(a, out);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user