From 7fdc2559013527f5c5ace542b33b992c3929fcd8 Mon Sep 17 00:00:00 2001 From: Christian Pillsbury Date: Mon, 27 Jul 2026 11:55:21 -0700 Subject: [PATCH] feat(spf): relocate non-zero-PTS sources to a 0-based timeline (VOD) (#1847) Co-authored-by: Claude Opus 4.8 (1M context) --- apps/sandbox/app/shared/sources.ts | 8 + .../templates/spf-segment-loading/favicon.svg | 7 + .../templates/spf-segment-loading/index.html | 33 +- .../templates/spf-segment-loading/main.ts | 98 +++- .../end-of-stream-av-skew-recovery.md | 102 ++++ internal/decisions/mse-timestamp-offset.md | 192 ++++++++ .../spf/features/edit-list-compensation.md | 42 +- .../spf/features/non-zero-pts-support.md | 455 ++++++++---------- .../design/spf/presentation-timeline-model.md | 402 ++++++++++++++++ .../spf/src/media/buffer/forward-buffer.ts | 41 +- .../media/buffer/tests/forward-buffer.test.ts | 85 +++- .../spf/src/media/dom/mse/append-segment.ts | 6 +- packages/spf/src/media/dom/mse/duration.ts | 45 +- .../src/media/dom/mse/tests/duration.test.ts | 53 +- .../src/media/dom/text/resolve-vtt-segment.ts | 34 +- .../text/tests/resolve-vtt-segment.test.ts | 53 +- packages/spf/src/media/mp4/box.ts | 88 ++++ packages/spf/src/media/mp4/tests/box.test.ts | 66 +++ .../src/media/mp4/tests/synthetic-boxes.ts | 124 +++++ .../media/mp4/tests/timestamp-origin.test.ts | 103 ++++ .../spf/src/media/mp4/timestamp-origin.ts | 155 ++++++ .../src/media/text/parse-vtt-timestamp-map.ts | 55 +++ .../src/media/text/resolve-vtt-metadata.ts | 28 ++ .../tests/parse-vtt-timestamp-map.test.ts | 34 ++ packages/spf/src/media/types/index.ts | 45 ++ .../src/playback/actors/dom/segment-loader.ts | 247 ++++------ .../src/playback/actors/dom/source-buffer.ts | 39 +- .../src/playback/actors/dom/text-tracks.ts | 10 +- .../spf/src/playback/actors/dom/tsconfig.json | 3 +- .../actors/text-track-segment-loader.ts | 75 +-- .../spf/src/playback/actors/text-tracks.ts | 10 +- .../spf/src/playback/actors/tsconfig.json | 7 +- .../playback/behaviors/dom/end-of-stream.ts | 26 +- .../behaviors/dom/recover-end-stall.ts | 123 +++++ .../behaviors/dom/setup-buffer-actors.ts | 36 +- .../behaviors/dom/setup-text-track-actors.ts | 36 +- .../tests/load-segments-track-switch.test.ts | 226 ++++++++- .../tests/load-text-track-segments.test.ts | 6 +- .../dom/tests/recover-end-stall.test.ts | 50 ++ .../behaviors/establish-start-media-time.ts | 233 +++++++++ .../tests/establish-start-media-time.test.ts | 159 ++++++ .../playback/engines/hls/engine-audio-only.ts | 33 +- .../spf/src/playback/engines/hls/engine.ts | 69 ++- .../spf/src/playback/engines/hls/index.ts | 8 + .../src/playback/engines/hls/tsconfig.json | 1 + .../primitives/derive-start-media-time.ts | 25 + .../spf/src/playback/primitives/head-peek.ts | 45 ++ .../primitives/relocation-pipelines.ts | 267 ++++++++++ .../primitives/segment-load-pipeline.ts | 210 ++++++++ .../primitives/source-buffer-messages.ts | 38 ++ .../tests/relocation-pipelines.test.ts | 152 ++++++ .../primitives/text-segment-load-pipeline.ts | 161 +++++++ .../primitives/text-track-messages.ts | 16 + 53 files changed, 4127 insertions(+), 538 deletions(-) create mode 100644 apps/sandbox/templates/spf-segment-loading/favicon.svg create mode 100644 internal/decisions/end-of-stream-av-skew-recovery.md create mode 100644 internal/decisions/mse-timestamp-offset.md create mode 100644 internal/design/spf/presentation-timeline-model.md create mode 100644 packages/spf/src/media/mp4/box.ts create mode 100644 packages/spf/src/media/mp4/tests/box.test.ts create mode 100644 packages/spf/src/media/mp4/tests/synthetic-boxes.ts create mode 100644 packages/spf/src/media/mp4/tests/timestamp-origin.test.ts create mode 100644 packages/spf/src/media/mp4/timestamp-origin.ts create mode 100644 packages/spf/src/media/text/parse-vtt-timestamp-map.ts create mode 100644 packages/spf/src/media/text/resolve-vtt-metadata.ts create mode 100644 packages/spf/src/media/text/tests/parse-vtt-timestamp-map.test.ts create mode 100644 packages/spf/src/playback/behaviors/dom/recover-end-stall.ts create mode 100644 packages/spf/src/playback/behaviors/dom/tests/recover-end-stall.test.ts create mode 100644 packages/spf/src/playback/behaviors/establish-start-media-time.ts create mode 100644 packages/spf/src/playback/behaviors/tests/establish-start-media-time.test.ts create mode 100644 packages/spf/src/playback/primitives/derive-start-media-time.ts create mode 100644 packages/spf/src/playback/primitives/head-peek.ts create mode 100644 packages/spf/src/playback/primitives/relocation-pipelines.ts create mode 100644 packages/spf/src/playback/primitives/segment-load-pipeline.ts create mode 100644 packages/spf/src/playback/primitives/source-buffer-messages.ts create mode 100644 packages/spf/src/playback/primitives/tests/relocation-pipelines.test.ts create mode 100644 packages/spf/src/playback/primitives/text-segment-load-pipeline.ts create mode 100644 packages/spf/src/playback/primitives/text-track-messages.ts diff --git a/apps/sandbox/app/shared/sources.ts b/apps/sandbox/app/shared/sources.ts index eedd5ab9..0bfcce50 100644 --- a/apps/sandbox/app/shared/sources.ts +++ b/apps/sandbox/app/shared/sources.ts @@ -43,6 +43,14 @@ export const SOURCES = { type: 'hls', subType: 'mp4', }, + 'hls-instant-clip': { + // Clipped 60s→600s of the multi-audio asset, so A/V encode at native PTS ≈ 60s. + // Exercises non-zero-PTS timestampOffset relocation: currentTime stays 0-based. + label: 'HLS - Instant Clip (non-zero PTS)', + url: 'https://stream.mux.com/s41JYeqIpBMBzE4OzxDyGR2yrp2hD1CQ6gJN9SlVGDQ.m3u8?asset_start_time=60&asset_end_time=600', + type: 'hls', + subType: 'mp4', + }, 'hls-live': { label: 'HLS - Live Stream Big Buck Bunny', url: 'https://stream.mux.com/v69RSHhFelSm4701snP22dYz2jICy4E4FUyk02rW4gxRM.m3u8', diff --git a/apps/sandbox/templates/spf-segment-loading/favicon.svg b/apps/sandbox/templates/spf-segment-loading/favicon.svg new file mode 100644 index 00000000..e253e300 --- /dev/null +++ b/apps/sandbox/templates/spf-segment-loading/favicon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/apps/sandbox/templates/spf-segment-loading/index.html b/apps/sandbox/templates/spf-segment-loading/index.html index 9c3b862a..6a3c8c42 100644 --- a/apps/sandbox/templates/spf-segment-loading/index.html +++ b/apps/sandbox/templates/spf-segment-loading/index.html @@ -3,6 +3,7 @@ + Sandbox — SPF Segment Loading POC