Capture the decision to hold one rolling (media-time ↔ PDT) anchor — learned from the first A/V track to obtain SourceBuffer ground truth and applied to all selected tracks (incl. text) by per-segment PDT — replacing today's per-track buffer pins, which are redundant under the no-skew assumption and can't anchor text (no SourceBuffer). New decision doc live-presentation-anchor.md; resolves the deferred single-rolling-anchor question in live-timeline-anchoring and promotes [4] in live-presentation-modeling to presentation-level. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.9 KiB
status, date
| status | date |
|---|---|
| decided | 2026-06-15 |
Live timeline anchoring via PROGRAM-DATE-TIME
Decision
Anchor the live timeline on EXT-X-PROGRAM-DATE-TIME (PDT), not on media
sequence number. PDT gives each segment an absolute wall-clock time (epoch
seconds) used for two things:
- Cross-track alignment — demuxed audio and video are aligned by equal
PDT (same real instant), not by equal sequence number or per-track relative
startTime. - Turnover recovery — on a full live-window slide with no overlap, the
absolute
startTimeis recovered from PDT rather than estimated fromtargetDuration × offset.
Scope of this decision: the anchor source is PDT. The parser surfaces
Segment.programDateTime (landed; see Verification). Whether the model holds a
single rolling anchor vs. per-segment measured times is fixed in
live-presentation-anchor — a single
presentation-level (media-time ↔ PDT) anchor, learned from the first A/V
track to buffer and applied to all tracks (incl. text) by PDT. The remaining
per-track presentationTimeOffset derivation for the skew case is downstream
and not fixed here.
This resolves open questions [4] sync anchor and turnover startTime
recovery in
live-presentation-modeling.
Context
For demuxed live HLS, each track is parsed independently and its segment
startTimes accumulate from 0, so the same real instant lands at different
per-track startTimes (measured: a demuxed Mux CMAF stream put segment-82 at
startTime 2 in video but 0 in audio — a 2 s A/V skew). Sequence number
identifies and orders segments but does not place them in time. The model needs
a shared, absolute anchor that survives variable durations and window turnover.
Alternatives Considered
-
Sequence × duration. Reconstruct a segment's time as
(seq − seq₀) × duration. Rejected — it assumes uniform duration, which fails three ways: (a) audio and video segment durations differ (AAC frames are 1024 samples → a "2 s" audio segment is 2.005 s / 2.048 s, never the video's exact duration), so the tracks drift apart; (b) manifests roundEXTINF(both Mux streams advertised integer durations over non-integer media), compounding error; (c) once a segment rolls out of the window its actualEXTINFis gone, so absolute time can't be reconstructed by summing. PDT gives each in-window segment its own absolute time, immune to all three. -
CMAF-HAM
presentationTimeOffset. Borrow the model shape from common-media-library. Rejected as a source — HAM declares the field but never populates it for HLS, its HLS mapper accumulates each track from 0 (same skew as ours), and it drops PDT entirely. We adopt the namepresentationTimeOffsetfor the per-track offset, not HAM's DASH-centric (and unimplemented) derivation.
Rationale
PDT is the mechanism RFC 8216 itself describes for correlating positions across renditions (§4.3.2.6 associates a segment's first sample with absolute time). It is optional in RFC 8216 but required by Apple's HLS Authoring Specification, so it is reliably present on conformant content — Mux emits it on every segment of both the TS and CMAF/LL-HLS profiles we captured. It is the only anchor that is duration-variance-robust, survives window turnover, and is already shared across tracks.
Boundary. PDT aligns the manifest timelines across tracks. It does not by
itself align the buffer (native-PTS) coordinate — that rides on CMAF's
common encoded presentation timeline plus the per-track offset learned from
buffered/tfdt (see mse-timestamp-offset). Two
distinct steps: PDT → shared manifest timeline (alignment); manifest → buffer
(the learned offset). PDT does the first only.
Verification
Segment.programDateTime (epoch seconds) and PDT capture landed in the parser
(parse-media-playlist.ts), covered by parse-media-playlist.test.ts:
synthetic cases (capture, EXTINF forward-interpolation, re-anchor on an
explicit tag, variable-duration interpolation, absent-PDT → undefined) and real
Mux fixtures — the demuxed CMAF case asserts video/audio segment-82 share PDT
while per-track startTime disagrees (2 vs 0). PDT-anchored placement and the
cross-track adjuster are not yet implemented.
See also
- live-presentation-anchor — fixes how this anchor drives a single shared presentation timeline (the deferred single-rolling-anchor question).
- mse-timestamp-offset — the buffer-layer half; the manifest→buffer offset this decision's anchor feeds into.
- live-presentation-modeling — open questions [4] and turnover recovery, resolved here.
- non-zero-pts-support — consumes the offset-corrected timeline.