@videojs/spf 10.0.0-beta.3 → 10.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -38
- package/dist/default/core/actors/create-machine-actor.js +91 -0
- package/dist/default/core/actors/create-machine-actor.js.map +1 -0
- package/dist/default/core/actors/create-transition-actor.js +46 -0
- package/dist/default/core/actors/create-transition-actor.js.map +1 -0
- package/dist/default/core/composition/create-composition.js +85 -0
- package/dist/default/core/composition/create-composition.js.map +1 -0
- package/dist/default/core/composition/share-signals.js +39 -0
- package/dist/default/core/composition/share-signals.js.map +1 -0
- package/dist/default/core/machine.js +26 -0
- package/dist/default/core/machine.js.map +1 -0
- package/dist/default/core/reactors/create-machine-reactor.js +83 -0
- package/dist/default/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/default/core/signals/effect.js +41 -0
- package/dist/default/core/signals/effect.js.map +1 -0
- package/dist/default/core/signals/primitives.js +54 -0
- package/dist/default/core/signals/primitives.js.map +1 -0
- package/dist/default/core/signals/when.js +38 -0
- package/dist/default/core/signals/when.js.map +1 -0
- package/dist/default/core/tasks/delayed-reschedule.js +31 -0
- package/dist/default/core/tasks/delayed-reschedule.js.map +1 -0
- package/dist/default/core/tasks/task.js +321 -0
- package/dist/default/core/tasks/task.js.map +1 -0
- package/dist/default/dom.js +9 -0
- package/dist/default/hls-audio.js +3 -0
- package/dist/default/hls-background-video.js +3 -0
- package/dist/default/hls-video.js +4 -0
- package/dist/default/hls.js +8 -0
- package/dist/default/index.js +23 -0
- package/dist/default/index.js.map +1 -0
- package/dist/default/media/abr/quality-selection.js +21 -0
- package/dist/default/media/abr/quality-selection.js.map +1 -0
- package/dist/default/media/buffer/back-buffer.js +46 -0
- package/dist/default/media/buffer/back-buffer.js.map +1 -0
- package/dist/default/media/buffer/forward-buffer.js +119 -0
- package/dist/default/media/buffer/forward-buffer.js.map +1 -0
- package/dist/default/media/dom/capabilities.js +72 -0
- package/dist/default/media/dom/capabilities.js.map +1 -0
- package/dist/default/media/dom/mse/append-segment.js +60 -0
- package/dist/default/media/dom/mse/append-segment.js.map +1 -0
- package/dist/default/media/dom/mse/buffer-flusher.js +55 -0
- package/dist/default/media/dom/mse/buffer-flusher.js.map +1 -0
- package/dist/default/media/dom/mse/duration.js +95 -0
- package/dist/default/media/dom/mse/duration.js.map +1 -0
- package/dist/default/media/dom/mse/end-of-stream.js +20 -0
- package/dist/default/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/default/media/dom/mse/mediasource-setup.js +242 -0
- package/dist/default/media/dom/mse/mediasource-setup.js.map +1 -0
- package/dist/default/media/dom/screen.js +112 -0
- package/dist/default/media/dom/screen.js.map +1 -0
- package/dist/default/media/dom/text/resolve-vtt-segment.js +50 -0
- package/dist/default/media/dom/text/resolve-vtt-segment.js.map +1 -0
- package/dist/default/media/dom/text/text-track-slots.js +69 -0
- package/dist/default/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/default/media/errors.js +69 -0
- package/dist/default/media/errors.js.map +1 -0
- package/dist/default/media/hls/parse-attributes.js +148 -0
- package/dist/default/media/hls/parse-attributes.js.map +1 -0
- package/dist/default/media/hls/parse-media-playlist.js +261 -0
- package/dist/default/media/hls/parse-media-playlist.js.map +1 -0
- package/dist/default/media/hls/parse-multivariant.js +234 -0
- package/dist/default/media/hls/parse-multivariant.js.map +1 -0
- package/dist/default/media/hls/reload-policy.js +71 -0
- package/dist/default/media/hls/reload-policy.js.map +1 -0
- package/dist/default/media/hls/resolve-url.js +11 -0
- package/dist/default/media/hls/resolve-url.js.map +1 -0
- package/dist/default/media/live-window.js +36 -0
- package/dist/default/media/live-window.js.map +1 -0
- package/dist/default/media/media-tracks/media-tracks.js +101 -0
- package/dist/default/media/media-tracks/media-tracks.js.map +1 -0
- package/dist/default/media/mp4/box.js +58 -0
- package/dist/default/media/mp4/box.js.map +1 -0
- package/dist/default/media/mp4/timestamp-origin.js +107 -0
- package/dist/default/media/mp4/timestamp-origin.js.map +1 -0
- package/dist/default/media/primitives/resolution.js +29 -0
- package/dist/default/media/primitives/resolution.js.map +1 -0
- package/dist/default/media/primitives/select-tracks.js +107 -0
- package/dist/default/media/primitives/select-tracks.js.map +1 -0
- package/dist/default/media/text/parse-vtt-timestamp-map.js +42 -0
- package/dist/default/media/text/parse-vtt-timestamp-map.js.map +1 -0
- package/dist/default/media/text/resolve-vtt-metadata.js +23 -0
- package/dist/default/media/text/resolve-vtt-metadata.js.map +1 -0
- package/dist/default/media/types/index.js +50 -0
- package/dist/default/media/types/index.js.map +1 -0
- package/dist/default/media/utils/cdn.js +56 -0
- package/dist/default/media/utils/cdn.js.map +1 -0
- package/dist/default/media/utils/preload.js +22 -0
- package/dist/default/media/utils/preload.js.map +1 -0
- package/dist/default/media/utils/track-selection.js +47 -0
- package/dist/default/media/utils/track-selection.js.map +1 -0
- package/dist/default/media/utils/tracks.js +144 -0
- package/dist/default/media/utils/tracks.js.map +1 -0
- package/dist/default/media-tracks.js +2 -0
- package/dist/default/mux-audio.js +3 -0
- package/dist/default/mux-background-video.js +3 -0
- package/dist/default/mux-video.js +3 -0
- package/dist/default/network/bandwidth-estimator.js +96 -0
- package/dist/default/network/bandwidth-estimator.js.map +1 -0
- package/dist/default/network/chunked-stream-iterable.js +49 -0
- package/dist/default/network/chunked-stream-iterable.js.map +1 -0
- package/dist/default/network/ewma.js +71 -0
- package/dist/default/network/ewma.js.map +1 -0
- package/dist/default/network/fetch.js +115 -0
- package/dist/default/network/fetch.js.map +1 -0
- package/dist/default/playback/actors/dom/segment-loader.js +249 -0
- package/dist/default/playback/actors/dom/segment-loader.js.map +1 -0
- package/dist/default/playback/actors/dom/source-buffer.js +139 -0
- package/dist/default/playback/actors/dom/source-buffer.js.map +1 -0
- package/dist/default/playback/actors/dom/text-tracks.js +46 -0
- package/dist/default/playback/actors/dom/text-tracks.js.map +1 -0
- package/dist/default/playback/actors/text-track-segment-loader.js +149 -0
- package/dist/default/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/default/playback/adapters/hls-audio/adapter.js +186 -0
- package/dist/default/playback/adapters/hls-audio/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-audio/media.js +9 -0
- package/dist/default/playback/adapters/hls-audio/media.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/adapter.js +211 -0
- package/dist/default/playback/adapters/hls-background-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/host.js +60 -0
- package/dist/default/playback/adapters/hls-background-video/host.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/media.js +21 -0
- package/dist/default/playback/adapters/hls-background-video/media.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/adapter.js +316 -0
- package/dist/default/playback/adapters/hls-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/error-surface.js +51 -0
- package/dist/default/playback/adapters/hls-video/error-surface.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/media-tracks.js +126 -0
- package/dist/default/playback/adapters/hls-video/media-tracks.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/media.js +11 -0
- package/dist/default/playback/adapters/hls-video/media.js.map +1 -0
- package/dist/default/playback/adapters/mux-audio/media.js +26 -0
- package/dist/default/playback/adapters/mux-audio/media.js.map +1 -0
- package/dist/default/playback/adapters/mux-video/adapter.js +105 -0
- package/dist/default/playback/adapters/mux-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/mux-video/media.js +23 -0
- package/dist/default/playback/adapters/mux-video/media.js.map +1 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js +36 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/default/playback/behaviors/collect-errors.js +111 -0
- package/dist/default/playback/behaviors/collect-errors.js.map +1 -0
- package/dist/default/playback/behaviors/derive-cdn-priority.js +68 -0
- package/dist/default/playback/behaviors/derive-cdn-priority.js.map +1 -0
- package/dist/default/playback/behaviors/dom/airplay.js +211 -0
- package/dist/default/playback/behaviors/dom/airplay.js.map +1 -0
- package/dist/default/playback/behaviors/dom/apply-start-position.js +93 -0
- package/dist/default/playback/behaviors/dom/apply-start-position.js.map +1 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js +102 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/default/playback/behaviors/dom/load-segments.js +181 -0
- package/dist/default/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/default/playback/behaviors/dom/recover-end-stall.js +77 -0
- package/dist/default/playback/behaviors/dom/recover-end-stall.js.map +1 -0
- package/dist/default/playback/behaviors/dom/seek-to-live-edge.js +132 -0
- package/dist/default/playback/behaviors/dom/seek-to-live-edge.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-buffer-actors.js +205 -0
- package/dist/default/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-mediasource.js +114 -0
- package/dist/default/playback/behaviors/dom/setup-mediasource.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-text-track-actors.js +40 -0
- package/dist/default/playback/behaviors/dom/setup-text-track-actors.js.map +1 -0
- package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js +26 -0
- package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -0
- package/dist/default/playback/behaviors/dom/sync-text-tracks.js +124 -0
- package/dist/default/playback/behaviors/dom/sync-text-tracks.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js +52 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js +94 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js +37 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-player-resolution.js +57 -0
- package/dist/default/playback/behaviors/dom/track-player-resolution.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js +29 -0
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js +113 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js.map +1 -0
- package/dist/default/playback/behaviors/establish-start-media-time.js +197 -0
- package/dist/default/playback/behaviors/establish-start-media-time.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-presentation.js +85 -0
- package/dist/default/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-track.js +141 -0
- package/dist/default/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/default/playback/behaviors/select-tracks.js +216 -0
- package/dist/default/playback/behaviors/select-tracks.js.map +1 -0
- package/dist/default/playback/behaviors/setup-failover-monitor.js +66 -0
- package/dist/default/playback/behaviors/setup-failover-monitor.js.map +1 -0
- package/dist/default/playback/behaviors/sync-preload.js +59 -0
- package/dist/default/playback/behaviors/sync-preload.js.map +1 -0
- package/dist/default/playback/behaviors/track-switching.js +391 -0
- package/dist/default/playback/behaviors/track-switching.js.map +1 -0
- package/dist/default/playback/engines/hls/engine-audio-only.js +98 -0
- package/dist/default/playback/engines/hls/engine-audio-only.js.map +1 -0
- package/dist/default/playback/engines/hls/engine-background-video.js +92 -0
- package/dist/default/playback/engines/hls/engine-background-video.js.map +1 -0
- package/dist/default/playback/engines/hls/engine.js +147 -0
- package/dist/default/playback/engines/hls/engine.js.map +1 -0
- package/dist/default/playback/primitives/error-messages.js +51 -0
- package/dist/default/playback/primitives/error-messages.js.map +1 -0
- package/dist/default/playback/primitives/failover-fetch.js +42 -0
- package/dist/default/playback/primitives/failover-fetch.js.map +1 -0
- package/dist/default/playback/primitives/head-peek.js +44 -0
- package/dist/default/playback/primitives/head-peek.js.map +1 -0
- package/dist/default/playback/primitives/live-window.js +66 -0
- package/dist/default/playback/primitives/live-window.js.map +1 -0
- package/dist/default/playback/primitives/relocation-pipelines.js +203 -0
- package/dist/default/playback/primitives/relocation-pipelines.js.map +1 -0
- package/dist/default/playback/primitives/report-track-conditions.js +86 -0
- package/dist/default/playback/primitives/report-track-conditions.js.map +1 -0
- package/dist/default/playback/primitives/segment-load-pipeline.js +96 -0
- package/dist/default/playback/primitives/segment-load-pipeline.js.map +1 -0
- package/dist/default/playback/primitives/selection-rules.js +86 -0
- package/dist/default/playback/primitives/selection-rules.js.map +1 -0
- package/dist/default/playback/primitives/text-segment-load-pipeline.js +37 -0
- package/dist/default/playback/primitives/text-segment-load-pipeline.js.map +1 -0
- package/dist/default/playback/primitives/track-types.js +61 -0
- package/dist/default/playback/primitives/track-types.js.map +1 -0
- package/dist/dev/core/actors/actor.d.ts +26 -0
- package/dist/dev/core/actors/actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-machine-actor.d.ts +128 -0
- package/dist/dev/core/actors/create-machine-actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-machine-actor.js +91 -0
- package/dist/dev/core/actors/create-machine-actor.js.map +1 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts +41 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-transition-actor.js +46 -0
- package/dist/dev/core/actors/create-transition-actor.js.map +1 -0
- package/dist/dev/core/composition/create-composition.d.ts +273 -0
- package/dist/dev/core/composition/create-composition.d.ts.map +1 -0
- package/dist/dev/core/composition/create-composition.js +85 -0
- package/dist/dev/core/composition/create-composition.js.map +1 -0
- package/dist/dev/core/composition/share-signals.d.ts +46 -0
- package/dist/dev/core/composition/share-signals.d.ts.map +1 -0
- package/dist/dev/core/composition/share-signals.js +39 -0
- package/dist/dev/core/composition/share-signals.js.map +1 -0
- package/dist/dev/core/machine.d.ts +21 -0
- package/dist/dev/core/machine.d.ts.map +1 -0
- package/dist/dev/core/machine.js +26 -0
- package/dist/dev/core/machine.js.map +1 -0
- package/dist/dev/core/reactors/create-machine-reactor.d.ts +93 -0
- package/dist/dev/core/reactors/create-machine-reactor.d.ts.map +1 -0
- package/dist/dev/core/reactors/create-machine-reactor.js +83 -0
- package/dist/dev/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/dev/core/signals/effect.d.ts +15 -0
- package/dist/dev/core/signals/effect.d.ts.map +1 -0
- package/dist/dev/core/signals/effect.js +41 -0
- package/dist/dev/core/signals/effect.js.map +1 -0
- package/dist/dev/core/signals/primitives.d.ts +46 -0
- package/dist/dev/core/signals/primitives.d.ts.map +1 -0
- package/dist/dev/core/signals/primitives.js +54 -0
- package/dist/dev/core/signals/primitives.js.map +1 -0
- package/dist/dev/core/signals/when.js +38 -0
- package/dist/dev/core/signals/when.js.map +1 -0
- package/dist/dev/core/tasks/delayed-reschedule.js +31 -0
- package/dist/dev/core/tasks/delayed-reschedule.js.map +1 -0
- package/dist/dev/core/tasks/task.d.ts +166 -0
- package/dist/dev/core/tasks/task.d.ts.map +1 -0
- package/dist/dev/core/tasks/task.js +321 -0
- package/dist/dev/core/tasks/task.js.map +1 -0
- package/dist/dev/dom.d.ts +9 -0
- package/dist/dev/dom.js +9 -0
- package/dist/dev/hls-audio.d.ts +3 -0
- package/dist/dev/hls-audio.js +3 -0
- package/dist/dev/hls-background-video.d.ts +4 -0
- package/dist/dev/hls-background-video.js +3 -0
- package/dist/dev/hls-video.d.ts +5 -0
- package/dist/dev/hls-video.js +4 -0
- package/dist/dev/hls.d.ts +9 -0
- package/dist/dev/hls.js +8 -0
- package/dist/dev/index.d.ts +24 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +23 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/media/abr/quality-selection.d.ts +22 -0
- package/dist/dev/media/abr/quality-selection.d.ts.map +1 -0
- package/dist/dev/media/abr/quality-selection.js +21 -0
- package/dist/dev/media/abr/quality-selection.js.map +1 -0
- package/dist/dev/media/buffer/back-buffer.d.ts +14 -0
- package/dist/dev/media/buffer/back-buffer.d.ts.map +1 -0
- package/dist/dev/media/buffer/back-buffer.js +46 -0
- package/dist/dev/media/buffer/back-buffer.js.map +1 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts +14 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts.map +1 -0
- package/dist/dev/media/buffer/forward-buffer.js +119 -0
- package/dist/dev/media/buffer/forward-buffer.js.map +1 -0
- package/dist/dev/media/dom/capabilities.js +72 -0
- package/dist/dev/media/dom/capabilities.js.map +1 -0
- package/dist/dev/media/dom/mse/append-segment.d.ts +18 -0
- package/dist/dev/media/dom/mse/append-segment.d.ts.map +1 -0
- package/dist/dev/media/dom/mse/append-segment.js +60 -0
- package/dist/dev/media/dom/mse/append-segment.js.map +1 -0
- package/dist/dev/media/dom/mse/buffer-flusher.d.ts +24 -0
- package/dist/dev/media/dom/mse/buffer-flusher.d.ts.map +1 -0
- package/dist/dev/media/dom/mse/buffer-flusher.js +55 -0
- package/dist/dev/media/dom/mse/buffer-flusher.js.map +1 -0
- package/dist/dev/media/dom/mse/duration.js +95 -0
- package/dist/dev/media/dom/mse/duration.js.map +1 -0
- package/dist/dev/media/dom/mse/end-of-stream.js +20 -0
- package/dist/dev/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/dev/media/dom/mse/mediasource-setup.js +242 -0
- package/dist/dev/media/dom/mse/mediasource-setup.js.map +1 -0
- package/dist/dev/media/dom/screen.d.ts +7 -0
- package/dist/dev/media/dom/screen.d.ts.map +1 -0
- package/dist/dev/media/dom/screen.js +112 -0
- package/dist/dev/media/dom/screen.js.map +1 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts +6 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts.map +1 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.js +50 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.js.map +1 -0
- package/dist/dev/media/dom/text/text-track-slots.d.ts +30 -0
- package/dist/dev/media/dom/text/text-track-slots.d.ts.map +1 -0
- package/dist/dev/media/dom/text/text-track-slots.js +69 -0
- package/dist/dev/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/dev/media/errors.d.ts +82 -0
- package/dist/dev/media/errors.d.ts.map +1 -0
- package/dist/dev/media/errors.js +69 -0
- package/dist/dev/media/errors.js.map +1 -0
- package/dist/dev/media/hls/parse-attributes.js +148 -0
- package/dist/dev/media/hls/parse-attributes.js.map +1 -0
- package/dist/dev/media/hls/parse-media-playlist.js +261 -0
- package/dist/dev/media/hls/parse-media-playlist.js.map +1 -0
- package/dist/dev/media/hls/parse-multivariant.js +234 -0
- package/dist/dev/media/hls/parse-multivariant.js.map +1 -0
- package/dist/dev/media/hls/reload-policy.js +71 -0
- package/dist/dev/media/hls/reload-policy.js.map +1 -0
- package/dist/dev/media/hls/resolve-url.js +11 -0
- package/dist/dev/media/hls/resolve-url.js.map +1 -0
- package/dist/dev/media/live-window.js +36 -0
- package/dist/dev/media/live-window.js.map +1 -0
- package/dist/dev/media/media-tracks/media-tracks.d.ts +51 -0
- package/dist/dev/media/media-tracks/media-tracks.d.ts.map +1 -0
- package/dist/dev/media/media-tracks/media-tracks.js +101 -0
- package/dist/dev/media/media-tracks/media-tracks.js.map +1 -0
- package/dist/dev/media/mp4/box.js +58 -0
- package/dist/dev/media/mp4/box.js.map +1 -0
- package/dist/dev/media/mp4/timestamp-origin.js +107 -0
- package/dist/dev/media/mp4/timestamp-origin.js.map +1 -0
- package/dist/dev/media/primitives/resolution.d.ts +24 -0
- package/dist/dev/media/primitives/resolution.d.ts.map +1 -0
- package/dist/dev/media/primitives/resolution.js +29 -0
- package/dist/dev/media/primitives/resolution.js.map +1 -0
- package/dist/dev/media/primitives/select-tracks.js +107 -0
- package/dist/dev/media/primitives/select-tracks.js.map +1 -0
- package/dist/dev/media/text/parse-vtt-timestamp-map.js +42 -0
- package/dist/dev/media/text/parse-vtt-timestamp-map.js.map +1 -0
- package/dist/dev/media/text/resolve-vtt-metadata.js +23 -0
- package/dist/dev/media/text/resolve-vtt-metadata.js.map +1 -0
- package/dist/dev/media/types/index.d.ts +377 -0
- package/dist/dev/media/types/index.d.ts.map +1 -0
- package/dist/dev/media/types/index.js +50 -0
- package/dist/dev/media/types/index.js.map +1 -0
- package/dist/dev/media/utils/cdn.d.ts +13 -0
- package/dist/dev/media/utils/cdn.d.ts.map +1 -0
- package/dist/dev/media/utils/cdn.js +56 -0
- package/dist/dev/media/utils/cdn.js.map +1 -0
- package/dist/dev/media/utils/preload.js +22 -0
- package/dist/dev/media/utils/preload.js.map +1 -0
- package/dist/dev/media/utils/track-selection.js +47 -0
- package/dist/dev/media/utils/track-selection.js.map +1 -0
- package/dist/dev/media/utils/tracks.js +144 -0
- package/dist/dev/media/utils/tracks.js.map +1 -0
- package/dist/dev/media-tracks.d.ts +3 -0
- package/dist/dev/media-tracks.js +2 -0
- package/dist/dev/mux-audio.d.ts +4 -0
- package/dist/dev/mux-audio.js +3 -0
- package/dist/dev/mux-background-video.d.ts +4 -0
- package/dist/dev/mux-background-video.js +3 -0
- package/dist/dev/mux-video.d.ts +4 -0
- package/dist/dev/mux-video.js +3 -0
- package/dist/dev/network/bandwidth-estimator.d.ts +50 -0
- package/dist/dev/network/bandwidth-estimator.d.ts.map +1 -0
- package/dist/dev/network/bandwidth-estimator.js +96 -0
- package/dist/dev/network/bandwidth-estimator.js.map +1 -0
- package/dist/dev/network/chunked-stream-iterable.js +49 -0
- package/dist/dev/network/chunked-stream-iterable.js.map +1 -0
- package/dist/dev/network/ewma.js +71 -0
- package/dist/dev/network/ewma.js.map +1 -0
- package/dist/dev/network/fetch.js +115 -0
- package/dist/dev/network/fetch.js.map +1 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts +48 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts.map +1 -0
- package/dist/dev/playback/actors/dom/segment-loader.js +249 -0
- package/dist/dev/playback/actors/dom/segment-loader.js.map +1 -0
- package/dist/dev/playback/actors/dom/source-buffer.d.ts +47 -0
- package/dist/dev/playback/actors/dom/source-buffer.d.ts.map +1 -0
- package/dist/dev/playback/actors/dom/source-buffer.js +139 -0
- package/dist/dev/playback/actors/dom/source-buffer.js.map +1 -0
- package/dist/dev/playback/actors/dom/text-tracks.d.ts +3 -0
- package/dist/dev/playback/actors/dom/text-tracks.js +46 -0
- package/dist/dev/playback/actors/dom/text-tracks.js.map +1 -0
- package/dist/dev/playback/actors/text-track-segment-loader.d.ts +54 -0
- package/dist/dev/playback/actors/text-track-segment-loader.d.ts.map +1 -0
- package/dist/dev/playback/actors/text-track-segment-loader.js +149 -0
- package/dist/dev/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/dev/playback/actors/text-tracks.d.ts +33 -0
- package/dist/dev/playback/actors/text-tracks.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.d.ts +54 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.js +186 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/media.d.ts +10 -0
- package/dist/dev/playback/adapters/hls-audio/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/media.js +9 -0
- package/dist/dev/playback/adapters/hls-audio/media.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts +77 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.js +211 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/host.d.ts +38 -0
- package/dist/dev/playback/adapters/hls-background-video/host.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/host.js +60 -0
- package/dist/dev/playback/adapters/hls-background-video/host.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/media.d.ts +20 -0
- package/dist/dev/playback/adapters/hls-background-video/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/media.js +21 -0
- package/dist/dev/playback/adapters/hls-background-video/media.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/adapter.d.ts +63 -0
- package/dist/dev/playback/adapters/hls-video/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/adapter.js +316 -0
- package/dist/dev/playback/adapters/hls-video/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.d.ts +18 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.js +51 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts +22 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.js +126 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media.d.ts +10 -0
- package/dist/dev/playback/adapters/hls-video/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media.js +11 -0
- package/dist/dev/playback/adapters/hls-video/media.js.map +1 -0
- package/dist/dev/playback/adapters/mux-audio/media.d.ts +28 -0
- package/dist/dev/playback/adapters/mux-audio/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/mux-audio/media.js +26 -0
- package/dist/dev/playback/adapters/mux-audio/media.js.map +1 -0
- package/dist/dev/playback/adapters/mux-video/adapter.d.ts +34 -0
- package/dist/dev/playback/adapters/mux-video/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/mux-video/adapter.js +105 -0
- package/dist/dev/playback/adapters/mux-video/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/mux-video/media.d.ts +24 -0
- package/dist/dev/playback/adapters/mux-video/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/mux-video/media.js +23 -0
- package/dist/dev/playback/adapters/mux-video/media.js.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts +26 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js +36 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/dev/playback/behaviors/collect-errors.js +111 -0
- package/dist/dev/playback/behaviors/collect-errors.js.map +1 -0
- package/dist/dev/playback/behaviors/derive-cdn-priority.js +68 -0
- package/dist/dev/playback/behaviors/derive-cdn-priority.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/airplay.js +211 -0
- package/dist/dev/playback/behaviors/dom/airplay.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/apply-start-position.js +93 -0
- package/dist/dev/playback/behaviors/dom/apply-start-position.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js +102 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts +72 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js +181 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/recover-end-stall.js +77 -0
- package/dist/dev/playback/behaviors/dom/recover-end-stall.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js +132 -0
- package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js +205 -0
- package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-mediasource.js +114 -0
- package/dist/dev/playback/behaviors/dom/setup-mediasource.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts +28 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.js +40 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js +26 -0
- package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/sync-text-tracks.js +124 -0
- package/dist/dev/playback/behaviors/dom/sync-text-tracks.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.d.ts +33 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.js +52 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts +47 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.js +94 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts +33 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.js +37 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.d.ts +8 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.js +57 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js +29 -0
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js +113 -0
- package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js.map +1 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.d.ts +36 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.js +197 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.js.map +1 -0
- package/dist/dev/playback/behaviors/resolve-presentation.d.ts +8 -0
- package/dist/dev/playback/behaviors/resolve-presentation.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/resolve-presentation.js +85 -0
- package/dist/dev/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/dev/playback/behaviors/resolve-track.js +141 -0
- package/dist/dev/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.d.ts +72 -0
- package/dist/dev/playback/behaviors/select-tracks.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.js +216 -0
- package/dist/dev/playback/behaviors/select-tracks.js.map +1 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts +14 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.js +66 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.js.map +1 -0
- package/dist/dev/playback/behaviors/sync-preload.js +59 -0
- package/dist/dev/playback/behaviors/sync-preload.js.map +1 -0
- package/dist/dev/playback/behaviors/track-switching.js +391 -0
- package/dist/dev/playback/behaviors/track-switching.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.d.ts +173 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.js +98 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine-background-video.d.ts +158 -0
- package/dist/dev/playback/engines/hls/engine-background-video.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine-background-video.js +92 -0
- package/dist/dev/playback/engines/hls/engine-background-video.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine.d.ts +329 -0
- package/dist/dev/playback/engines/hls/engine.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine.js +147 -0
- package/dist/dev/playback/engines/hls/engine.js.map +1 -0
- package/dist/dev/playback/primitives/derive-start-media-time.d.ts +16 -0
- package/dist/dev/playback/primitives/derive-start-media-time.d.ts.map +1 -0
- package/dist/dev/playback/primitives/error-messages.js +51 -0
- package/dist/dev/playback/primitives/error-messages.js.map +1 -0
- package/dist/dev/playback/primitives/failover-fetch.js +42 -0
- package/dist/dev/playback/primitives/failover-fetch.js.map +1 -0
- package/dist/dev/playback/primitives/head-peek.js +44 -0
- package/dist/dev/playback/primitives/head-peek.js.map +1 -0
- package/dist/dev/playback/primitives/live-window.js +66 -0
- package/dist/dev/playback/primitives/live-window.js.map +1 -0
- package/dist/dev/playback/primitives/relocation-pipelines.js +203 -0
- package/dist/dev/playback/primitives/relocation-pipelines.js.map +1 -0
- package/dist/dev/playback/primitives/report-track-conditions.d.ts +11 -0
- package/dist/dev/playback/primitives/report-track-conditions.d.ts.map +1 -0
- package/dist/dev/playback/primitives/report-track-conditions.js +86 -0
- package/dist/dev/playback/primitives/report-track-conditions.js.map +1 -0
- package/dist/dev/playback/primitives/segment-load-pipeline.d.ts +2 -0
- package/dist/dev/playback/primitives/segment-load-pipeline.js +96 -0
- package/dist/dev/playback/primitives/segment-load-pipeline.js.map +1 -0
- package/dist/dev/playback/primitives/selection-rules.d.ts +38 -0
- package/dist/dev/playback/primitives/selection-rules.d.ts.map +1 -0
- package/dist/dev/playback/primitives/selection-rules.js +86 -0
- package/dist/dev/playback/primitives/selection-rules.js.map +1 -0
- package/dist/dev/playback/primitives/source-buffer-messages.d.ts +43 -0
- package/dist/dev/playback/primitives/source-buffer-messages.d.ts.map +1 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts +65 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts.map +1 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.js +37 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.js.map +1 -0
- package/dist/dev/playback/primitives/text-track-messages.d.ts +14 -0
- package/dist/dev/playback/primitives/text-track-messages.d.ts.map +1 -0
- package/dist/dev/playback/primitives/track-types.js +61 -0
- package/dist/dev/playback/primitives/track-types.js.map +1 -0
- package/package.json +63 -26
- package/dist/adapter-CMw-rvbk.js +0 -3512
- package/dist/adapter-CMw-rvbk.js.map +0 -1
- package/dist/adapter-l8iJN_GI.d.ts +0 -689
- package/dist/adapter-l8iJN_GI.d.ts.map +0 -1
- package/dist/dom/index.d.ts +0 -243
- package/dist/dom/index.d.ts.map +0 -1
- package/dist/dom/index.js +0 -38
- package/dist/dom/index.js.map +0 -1
- package/dist/dom/playback-engine/index.d.ts +0 -2
- package/dist/dom/playback-engine/index.js +0 -4
- package/dist/index.d.ts +0 -13
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -3
- package/dist/src-DRsS_H80.js +0 -14
- package/dist/src-DRsS_H80.js.map +0 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { matchTag, parseCodecs } from "./parse-attributes.js";
|
|
2
|
+
import { resolveUrl } from "./resolve-url.js";
|
|
3
|
+
import { generateId } from "@videojs/utils/string";
|
|
4
|
+
//#region src/media/hls/parse-multivariant.ts
|
|
5
|
+
/**
|
|
6
|
+
* Parse HLS multivariant playlist into a Presentation.
|
|
7
|
+
*
|
|
8
|
+
* Returns Presentation with partially resolved tracks (no segment information).
|
|
9
|
+
* Tracks contain metadata from multivariant playlist (bandwidth, resolution, codecs)
|
|
10
|
+
* but segment information is added when media playlists are fetched.
|
|
11
|
+
*
|
|
12
|
+
* @param text - Raw playlist text content
|
|
13
|
+
* @param unresolved - Unresolved presentation (contains URL for base URL resolution)
|
|
14
|
+
* @returns Presentation with partially resolved tracks (duration is undefined)
|
|
15
|
+
*/
|
|
16
|
+
function parseMultivariantPlaylist(text, unresolved) {
|
|
17
|
+
const baseUrl = unresolved.url;
|
|
18
|
+
const lines = text.split(/\r?\n/);
|
|
19
|
+
const streams = [];
|
|
20
|
+
const audioRenditions = [];
|
|
21
|
+
const subtitleRenditions = [];
|
|
22
|
+
let pendingStreamInfo = null;
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.startsWith("#") && !trimmed.startsWith("#EXT")) continue;
|
|
26
|
+
if (trimmed === "#EXTM3U" || trimmed.startsWith("#EXT-X-VERSION:") || trimmed.startsWith("#EXT-X-INDEPENDENT-SEGMENTS")) continue;
|
|
27
|
+
const mediaAttrs = matchTag(trimmed, "EXT-X-MEDIA");
|
|
28
|
+
if (mediaAttrs) {
|
|
29
|
+
const type = mediaAttrs.get("TYPE");
|
|
30
|
+
const groupId = mediaAttrs.get("GROUP-ID");
|
|
31
|
+
const name = mediaAttrs.get("NAME");
|
|
32
|
+
if (type === "AUDIO" && groupId && name) {
|
|
33
|
+
const uri = mediaAttrs.get("URI");
|
|
34
|
+
audioRenditions.push({
|
|
35
|
+
groupId,
|
|
36
|
+
name,
|
|
37
|
+
language: mediaAttrs.get("LANGUAGE"),
|
|
38
|
+
uri: uri ? resolveUrl(uri, baseUrl) : void 0,
|
|
39
|
+
default: mediaAttrs.getBool("DEFAULT"),
|
|
40
|
+
autoselect: mediaAttrs.getBool("AUTOSELECT"),
|
|
41
|
+
channels: mediaAttrs.getInt("CHANNELS")
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (type === "SUBTITLES" && groupId && name) {
|
|
45
|
+
const uri = mediaAttrs.get("URI");
|
|
46
|
+
if (uri) subtitleRenditions.push({
|
|
47
|
+
groupId,
|
|
48
|
+
name,
|
|
49
|
+
language: mediaAttrs.get("LANGUAGE"),
|
|
50
|
+
uri: resolveUrl(uri, baseUrl),
|
|
51
|
+
default: mediaAttrs.getBool("DEFAULT"),
|
|
52
|
+
autoselect: mediaAttrs.getBool("AUTOSELECT"),
|
|
53
|
+
forced: mediaAttrs.getBool("FORCED")
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const streamInfAttrs = matchTag(trimmed, "EXT-X-STREAM-INF");
|
|
59
|
+
if (streamInfAttrs) {
|
|
60
|
+
pendingStreamInfo = {
|
|
61
|
+
bandwidth: streamInfAttrs.getInt("BANDWIDTH", 0),
|
|
62
|
+
resolution: streamInfAttrs.getResolution("RESOLUTION"),
|
|
63
|
+
codecs: streamInfAttrs.get("CODECS"),
|
|
64
|
+
frameRate: streamInfAttrs.getFrameRate("FRAME-RATE"),
|
|
65
|
+
audioGroupId: streamInfAttrs.get("AUDIO")
|
|
66
|
+
};
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (!trimmed.startsWith("#") && pendingStreamInfo) {
|
|
70
|
+
streams.push({
|
|
71
|
+
...pendingStreamInfo,
|
|
72
|
+
uri: resolveUrl(trimmed, baseUrl)
|
|
73
|
+
});
|
|
74
|
+
pendingStreamInfo = null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const videoStreams = [];
|
|
78
|
+
const audioOnlyStreams = [];
|
|
79
|
+
for (const stream of streams) {
|
|
80
|
+
if (!stream.codecs) {
|
|
81
|
+
videoStreams.push(stream);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const parsedCodecs = parseCodecs(stream.codecs);
|
|
85
|
+
if (stream.codecs.split(",").length === 1) if (parsedCodecs.audio && !parsedCodecs.video) audioOnlyStreams.push(stream);
|
|
86
|
+
else videoStreams.push(stream);
|
|
87
|
+
else videoStreams.push(stream);
|
|
88
|
+
}
|
|
89
|
+
const videoTracksByUrl = /* @__PURE__ */ new Map();
|
|
90
|
+
for (const stream of videoStreams) {
|
|
91
|
+
const existing = videoTracksByUrl.get(stream.uri);
|
|
92
|
+
if (existing) {
|
|
93
|
+
if (stream.audioGroupId && !existing.audioGroupIds?.includes(stream.audioGroupId)) existing.audioGroupIds = [...existing.audioGroupIds ?? [], stream.audioGroupId];
|
|
94
|
+
if (stream.bandwidth < existing.bandwidth) existing.bandwidth = stream.bandwidth;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const codecs = stream.codecs ? parseCodecs(stream.codecs) : void 0;
|
|
98
|
+
const track = {
|
|
99
|
+
type: "video",
|
|
100
|
+
id: generateId(),
|
|
101
|
+
url: stream.uri,
|
|
102
|
+
bandwidth: stream.bandwidth,
|
|
103
|
+
mimeType: "video/mp4",
|
|
104
|
+
codecs: []
|
|
105
|
+
};
|
|
106
|
+
if (stream.resolution?.width !== void 0) track.width = stream.resolution.width;
|
|
107
|
+
if (stream.resolution?.height !== void 0) track.height = stream.resolution.height;
|
|
108
|
+
if (codecs?.video) track.codecs = codecs.audio && !stream.audioGroupId ? [codecs.video, codecs.audio] : [codecs.video];
|
|
109
|
+
if (stream.frameRate) track.frameRate = stream.frameRate;
|
|
110
|
+
if (stream.audioGroupId) track.audioGroupIds = [stream.audioGroupId];
|
|
111
|
+
videoTracksByUrl.set(stream.uri, track);
|
|
112
|
+
}
|
|
113
|
+
const videoTracks = [...videoTracksByUrl.values()];
|
|
114
|
+
const audioOnlyTracks = audioOnlyStreams.map((stream) => {
|
|
115
|
+
const codecs = stream.codecs ? parseCodecs(stream.codecs) : void 0;
|
|
116
|
+
return {
|
|
117
|
+
type: "audio",
|
|
118
|
+
id: generateId(),
|
|
119
|
+
url: stream.uri,
|
|
120
|
+
bandwidth: stream.bandwidth,
|
|
121
|
+
mimeType: "audio/mp4",
|
|
122
|
+
codecs: codecs?.audio ? [codecs.audio] : [],
|
|
123
|
+
groupId: stream.audioGroupId || "default",
|
|
124
|
+
name: "Default",
|
|
125
|
+
sampleRate: 48e3,
|
|
126
|
+
channels: 2
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
const audioTracks = [...audioRenditions.flatMap((rendition) => {
|
|
130
|
+
let audioCodecs;
|
|
131
|
+
for (const stream of streams) if (stream.audioGroupId === rendition.groupId && stream.codecs) {
|
|
132
|
+
const codecs = parseCodecs(stream.codecs);
|
|
133
|
+
if (codecs.audio) {
|
|
134
|
+
audioCodecs = [codecs.audio];
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (!rendition.uri) {
|
|
139
|
+
const carrier = audioOnlyTracks.find((track) => track.groupId === rendition.groupId);
|
|
140
|
+
if (carrier) {
|
|
141
|
+
carrier.name = rendition.name;
|
|
142
|
+
if (rendition.language) carrier.language = rendition.language;
|
|
143
|
+
if (rendition.channels) carrier.channels = rendition.channels;
|
|
144
|
+
if (rendition.default) carrier.default = rendition.default;
|
|
145
|
+
if (rendition.autoselect) carrier.autoselect = rendition.autoselect;
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const track = {
|
|
150
|
+
type: "audio",
|
|
151
|
+
id: generateId(),
|
|
152
|
+
url: rendition.uri ?? "",
|
|
153
|
+
groupId: rendition.groupId,
|
|
154
|
+
name: rendition.name,
|
|
155
|
+
mimeType: "audio/mp4",
|
|
156
|
+
bandwidth: 0,
|
|
157
|
+
sampleRate: 48e3,
|
|
158
|
+
channels: rendition.channels ?? 2,
|
|
159
|
+
codecs: []
|
|
160
|
+
};
|
|
161
|
+
if (rendition.language) track.language = rendition.language;
|
|
162
|
+
if (audioCodecs) track.codecs = audioCodecs;
|
|
163
|
+
if (rendition.default) track.default = rendition.default;
|
|
164
|
+
if (rendition.autoselect) track.autoselect = rendition.autoselect;
|
|
165
|
+
return [track];
|
|
166
|
+
}), ...audioOnlyTracks];
|
|
167
|
+
const textTracks = subtitleRenditions.map((rendition) => {
|
|
168
|
+
const track = {
|
|
169
|
+
type: "text",
|
|
170
|
+
id: generateId(),
|
|
171
|
+
url: rendition.uri,
|
|
172
|
+
groupId: rendition.groupId,
|
|
173
|
+
label: rendition.name,
|
|
174
|
+
kind: "subtitles",
|
|
175
|
+
mimeType: "text/vtt",
|
|
176
|
+
bandwidth: 0
|
|
177
|
+
};
|
|
178
|
+
if (rendition.language) track.language = rendition.language;
|
|
179
|
+
if (rendition.default && rendition.autoselect) track.default = true;
|
|
180
|
+
if (rendition.autoselect) track.autoselect = rendition.autoselect;
|
|
181
|
+
if (rendition.forced) track.forced = rendition.forced;
|
|
182
|
+
return track;
|
|
183
|
+
});
|
|
184
|
+
const selectionSets = [];
|
|
185
|
+
if (videoTracks.length > 0) {
|
|
186
|
+
const videoSwitchingSet = {
|
|
187
|
+
id: generateId(),
|
|
188
|
+
type: "video",
|
|
189
|
+
tracks: videoTracks
|
|
190
|
+
};
|
|
191
|
+
const videoSelectionSet = {
|
|
192
|
+
id: generateId(),
|
|
193
|
+
type: "video",
|
|
194
|
+
switchingSets: [videoSwitchingSet]
|
|
195
|
+
};
|
|
196
|
+
selectionSets.push(videoSelectionSet);
|
|
197
|
+
}
|
|
198
|
+
if (audioTracks.length > 0) {
|
|
199
|
+
const audioSwitchingSet = {
|
|
200
|
+
id: generateId(),
|
|
201
|
+
type: "audio",
|
|
202
|
+
tracks: audioTracks
|
|
203
|
+
};
|
|
204
|
+
const audioSelectionSet = {
|
|
205
|
+
id: generateId(),
|
|
206
|
+
type: "audio",
|
|
207
|
+
switchingSets: [audioSwitchingSet]
|
|
208
|
+
};
|
|
209
|
+
selectionSets.push(audioSelectionSet);
|
|
210
|
+
}
|
|
211
|
+
if (textTracks.length > 0) {
|
|
212
|
+
const textSwitchingSet = {
|
|
213
|
+
id: generateId(),
|
|
214
|
+
type: "text",
|
|
215
|
+
tracks: textTracks
|
|
216
|
+
};
|
|
217
|
+
const textSelectionSet = {
|
|
218
|
+
id: generateId(),
|
|
219
|
+
type: "text",
|
|
220
|
+
switchingSets: [textSwitchingSet]
|
|
221
|
+
};
|
|
222
|
+
selectionSets.push(textSelectionSet);
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
id: generateId(),
|
|
226
|
+
url: unresolved.url,
|
|
227
|
+
startTime: 0,
|
|
228
|
+
selectionSets
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
232
|
+
export { parseMultivariantPlaylist };
|
|
233
|
+
|
|
234
|
+
//# sourceMappingURL=parse-multivariant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-multivariant.js","names":[],"sources":["../../../../src/media/hls/parse-multivariant.ts"],"sourcesContent":["import { generateId } from '@videojs/utils/string';\nimport type {\n AddressableObject,\n AudioSelectionSet,\n AudioSwitchingSet,\n FrameRate,\n PartiallyResolvedAudioTrack,\n PartiallyResolvedTextTrack,\n PartiallyResolvedVideoTrack,\n Presentation,\n SelectionSet,\n TextSelectionSet,\n TextSwitchingSet,\n VideoSelectionSet,\n VideoSwitchingSet,\n} from '../types';\nimport { matchTag, parseCodecs } from './parse-attributes';\nimport { resolveUrl } from './resolve-url';\n\n/**\n * Parse HLS multivariant playlist into a Presentation.\n *\n * Returns Presentation with partially resolved tracks (no segment information).\n * Tracks contain metadata from multivariant playlist (bandwidth, resolution, codecs)\n * but segment information is added when media playlists are fetched.\n *\n * @param text - Raw playlist text content\n * @param unresolved - Unresolved presentation (contains URL for base URL resolution)\n * @returns Presentation with partially resolved tracks (duration is undefined)\n */\nexport function parseMultivariantPlaylist(text: string, unresolved: AddressableObject): Presentation {\n const baseUrl = unresolved.url;\n const lines = text.split(/\\r?\\n/);\n\n // Intermediate parsing structures\n interface StreamInfo {\n uri: string;\n bandwidth: number;\n resolution?: { width: number; height: number } | undefined;\n codecs?: string | undefined;\n frameRate?: FrameRate | undefined;\n audioGroupId?: string | undefined;\n }\n\n interface AudioRenditionInfo {\n groupId: string;\n name: string;\n language?: string | undefined;\n uri?: string | undefined;\n default?: boolean | undefined;\n autoselect?: boolean | undefined;\n channels?: number | undefined;\n }\n\n interface SubtitleRenditionInfo {\n groupId: string;\n name: string;\n language?: string | undefined;\n uri: string;\n default?: boolean | undefined;\n autoselect?: boolean | undefined;\n forced?: boolean | undefined;\n }\n\n const streams: StreamInfo[] = [];\n const audioRenditions: AudioRenditionInfo[] = [];\n const subtitleRenditions: SubtitleRenditionInfo[] = [];\n\n // State for STREAM-INF parsing (URI follows on next line)\n let pendingStreamInfo: Omit<StreamInfo, 'uri'> | null = null;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines and comments\n if (!trimmed || (trimmed.startsWith('#') && !trimmed.startsWith('#EXT'))) {\n continue;\n }\n\n // Skip tags not used in Presentation model\n if (\n trimmed === '#EXTM3U' ||\n trimmed.startsWith('#EXT-X-VERSION:') ||\n trimmed.startsWith('#EXT-X-INDEPENDENT-SEGMENTS')\n ) {\n continue;\n }\n\n // #EXT-X-MEDIA:TYPE=AUDIO/SUBTITLES\n const mediaAttrs = matchTag(trimmed, 'EXT-X-MEDIA');\n if (mediaAttrs) {\n const type = mediaAttrs.get('TYPE');\n const groupId = mediaAttrs.get('GROUP-ID');\n const name = mediaAttrs.get('NAME');\n\n if (type === 'AUDIO' && groupId && name) {\n const uri = mediaAttrs.get('URI');\n audioRenditions.push({\n groupId,\n name,\n language: mediaAttrs.get('LANGUAGE'),\n uri: uri ? resolveUrl(uri, baseUrl) : undefined,\n default: mediaAttrs.getBool('DEFAULT'),\n autoselect: mediaAttrs.getBool('AUTOSELECT'),\n // CHANNELS is a quoted string whose first parameter is the channel\n // count (\"6\", or \"16/JOC\" for spatial audio); getInt reads the\n // leading integer.\n channels: mediaAttrs.getInt('CHANNELS'),\n });\n }\n\n if (type === 'SUBTITLES' && groupId && name) {\n const uri = mediaAttrs.get('URI');\n // URI is required for subtitle tracks\n if (uri) {\n subtitleRenditions.push({\n groupId,\n name,\n language: mediaAttrs.get('LANGUAGE'),\n uri: resolveUrl(uri, baseUrl),\n default: mediaAttrs.getBool('DEFAULT'),\n autoselect: mediaAttrs.getBool('AUTOSELECT'),\n forced: mediaAttrs.getBool('FORCED'),\n });\n }\n }\n continue;\n }\n\n // #EXT-X-STREAM-INF:BANDWIDTH=...\n const streamInfAttrs = matchTag(trimmed, 'EXT-X-STREAM-INF');\n if (streamInfAttrs) {\n pendingStreamInfo = {\n bandwidth: streamInfAttrs.getInt('BANDWIDTH', 0)!,\n resolution: streamInfAttrs.getResolution('RESOLUTION'),\n codecs: streamInfAttrs.get('CODECS'),\n frameRate: streamInfAttrs.getFrameRate('FRAME-RATE'),\n audioGroupId: streamInfAttrs.get('AUDIO'),\n };\n continue;\n }\n\n // URI line following STREAM-INF\n if (!trimmed.startsWith('#') && pendingStreamInfo) {\n streams.push({\n ...pendingStreamInfo,\n uri: resolveUrl(trimmed, baseUrl),\n });\n pendingStreamInfo = null;\n }\n }\n\n // Separate streams into video and audio based on codecs\n // If CODECS has single codec, use parseCodecs to determine type\n const videoStreams: typeof streams = [];\n const audioOnlyStreams: typeof streams = [];\n\n for (const stream of streams) {\n if (!stream.codecs) {\n // No codecs - assume video (default behavior)\n videoStreams.push(stream);\n continue;\n }\n\n const parsedCodecs = parseCodecs(stream.codecs);\n const codecCount = stream.codecs.split(',').length;\n\n // Single codec - determine type from parseCodecs result\n if (codecCount === 1) {\n if (parsedCodecs.audio && !parsedCodecs.video) {\n // Audio-only stream\n audioOnlyStreams.push(stream);\n } else {\n // Video stream (or unknown - default to video)\n videoStreams.push(stream);\n }\n } else {\n // Multiple codecs - video stream with muxed audio\n videoStreams.push(stream);\n }\n }\n\n // Build PartiallyResolvedVideoTracks from video streams, de-duplicating the\n // HLS cross-product: one video rendition is listed across several\n // `EXT-X-STREAM-INF` entries — one per audio group it can pair with, all\n // sharing the same media-playlist URI. Collapse them to one track per URI,\n // accumulating every advertised audio group. (Redundant-stream renditions\n // live at *distinct* per-CDN URIs, so they stay separate — only the same-URI\n // cross-product merges.)\n const videoTracksByUrl = new Map<string, PartiallyResolvedVideoTrack>();\n for (const stream of videoStreams) {\n const existing = videoTracksByUrl.get(stream.uri);\n if (existing) {\n if (stream.audioGroupId && !existing.audioGroupIds?.includes(stream.audioGroupId)) {\n existing.audioGroupIds = [...(existing.audioGroupIds ?? []), stream.audioGroupId];\n }\n // BANDWIDTH is video + audio combined; the duplicates differ only in the\n // paired audio. Keep the lowest as the closest proxy to video-only, which\n // is what ABR should rank on.\n if (stream.bandwidth < existing.bandwidth) {\n existing.bandwidth = stream.bandwidth;\n }\n continue;\n }\n\n const codecs = stream.codecs ? parseCodecs(stream.codecs) : undefined;\n\n const track: PartiallyResolvedVideoTrack = {\n type: 'video' as const,\n id: generateId(),\n url: stream.uri,\n bandwidth: stream.bandwidth,\n // Type-specific defaults (CMAF video)\n mimeType: 'video/mp4',\n codecs: [],\n };\n\n if (stream.resolution?.width !== undefined) {\n track.width = stream.resolution.width;\n }\n if (stream.resolution?.height !== undefined) {\n track.height = stream.resolution.height;\n }\n if (codecs?.video) {\n // When the STREAM-INF lists an audio codec but declares no AUDIO group,\n // the audio is muxed into this rendition's segments — keep both codecs so\n // the SourceBuffer mimetype matches the muxed media (otherwise the muxed\n // audio fails to append: \"audio object type does not match the mimetype\").\n // With an AUDIO group the audio is a separate rendition, so only the video\n // codec belongs here.\n track.codecs = codecs.audio && !stream.audioGroupId ? [codecs.video, codecs.audio] : [codecs.video];\n }\n if (stream.frameRate) {\n track.frameRate = stream.frameRate;\n }\n if (stream.audioGroupId) {\n track.audioGroupIds = [stream.audioGroupId];\n }\n\n videoTracksByUrl.set(stream.uri, track);\n }\n const videoTracks: PartiallyResolvedVideoTrack[] = [...videoTracksByUrl.values()];\n\n // Build PartiallyResolvedAudioTracks from audio-only streams\n const audioOnlyTracks: PartiallyResolvedAudioTrack[] = audioOnlyStreams.map((stream) => {\n const codecs = stream.codecs ? parseCodecs(stream.codecs) : undefined;\n\n const track: PartiallyResolvedAudioTrack = {\n type: 'audio' as const,\n id: generateId(),\n url: stream.uri,\n bandwidth: stream.bandwidth,\n mimeType: 'audio/mp4',\n codecs: codecs?.audio ? [codecs.audio] : [],\n groupId: stream.audioGroupId || 'default',\n name: 'Default',\n sampleRate: 48000, // Default - will be in media playlist if available\n channels: 2, // Default - will be in media playlist if available\n };\n\n return track;\n });\n\n // Build PartiallyResolvedAudioTracks from audio renditions (EXT-X-MEDIA)\n // Extract audio codecs from referencing streams\n const audioRenditionTracks: PartiallyResolvedAudioTrack[] = audioRenditions.flatMap((rendition) => {\n let audioCodecs: string[] | undefined;\n for (const stream of streams) {\n if (stream.audioGroupId === rendition.groupId && stream.codecs) {\n const codecs = parseCodecs(stream.codecs);\n if (codecs.audio) {\n audioCodecs = [codecs.audio];\n break;\n }\n }\n }\n\n // A rendition with no URI names media carried in the streams referencing its\n // group. When such a stream is audio-only it is already a track of its own, so\n // the two describe one rendition: merge rather than add a second entry that has\n // nothing to fetch. The rendition holds the naming and selection metadata, the\n // stream the URL and bandwidth.\n if (!rendition.uri) {\n const carrier = audioOnlyTracks.find((track) => track.groupId === rendition.groupId);\n if (carrier) {\n carrier.name = rendition.name;\n if (rendition.language) carrier.language = rendition.language;\n if (rendition.channels) carrier.channels = rendition.channels;\n if (rendition.default) carrier.default = rendition.default;\n if (rendition.autoselect) carrier.autoselect = rendition.autoselect;\n return [];\n }\n }\n\n const track: PartiallyResolvedAudioTrack = {\n type: 'audio' as const,\n id: generateId(),\n url: rendition.uri ?? '',\n groupId: rendition.groupId,\n name: rendition.name,\n // Type-specific defaults (CMAF audio)\n mimeType: 'audio/mp4',\n bandwidth: 0, // Not available in multivariant for demuxed audio\n sampleRate: 48000, // CMAF default\n channels: rendition.channels ?? 2, // From EXT-X-MEDIA CHANNELS; stereo default\n codecs: [],\n };\n\n if (rendition.language) {\n track.language = rendition.language;\n }\n if (audioCodecs) {\n track.codecs = audioCodecs;\n }\n if (rendition.default) {\n track.default = rendition.default;\n }\n if (rendition.autoselect) {\n track.autoselect = rendition.autoselect;\n }\n\n return [track];\n });\n\n // Combine audio tracks from both EXT-X-MEDIA renditions and audio-only STREAM-INF\n const audioTracks = [...audioRenditionTracks, ...audioOnlyTracks];\n\n // Build PartiallyResolvedTextTracks from subtitle renditions\n const textTracks: PartiallyResolvedTextTrack[] = subtitleRenditions.map((rendition) => {\n const track: PartiallyResolvedTextTrack = {\n type: 'text' as const,\n id: generateId(),\n url: rendition.uri,\n groupId: rendition.groupId,\n label: rendition.name,\n kind: 'subtitles' as const,\n // Type-specific defaults (VTT)\n mimeType: 'text/vtt',\n bandwidth: 0, // Text tracks don't consume bandwidth\n };\n\n if (rendition.language) {\n track.language = rendition.language;\n }\n // Match hls.js/http-streaming: only set default=true when BOTH DEFAULT=YES AND AUTOSELECT=YES\n if (rendition.default && rendition.autoselect) {\n track.default = true;\n }\n if (rendition.autoselect) {\n track.autoselect = rendition.autoselect;\n }\n if (rendition.forced) {\n track.forced = rendition.forced;\n }\n\n return track;\n });\n\n // Build selection sets\n const selectionSets: SelectionSet[] = [];\n\n if (videoTracks.length > 0) {\n const videoSwitchingSet: VideoSwitchingSet = {\n id: generateId(),\n type: 'video',\n tracks: videoTracks,\n };\n\n const videoSelectionSet: VideoSelectionSet = {\n id: generateId(),\n type: 'video',\n switchingSets: [videoSwitchingSet],\n };\n\n selectionSets.push(videoSelectionSet);\n }\n\n if (audioTracks.length > 0) {\n const audioSwitchingSet: AudioSwitchingSet = {\n id: generateId(),\n type: 'audio',\n tracks: audioTracks,\n };\n\n const audioSelectionSet: AudioSelectionSet = {\n id: generateId(),\n type: 'audio',\n switchingSets: [audioSwitchingSet],\n };\n\n selectionSets.push(audioSelectionSet);\n }\n\n if (textTracks.length > 0) {\n const textSwitchingSet: TextSwitchingSet = {\n id: generateId(),\n type: 'text',\n tracks: textTracks,\n };\n\n const textSelectionSet: TextSelectionSet = {\n id: generateId(),\n type: 'text',\n switchingSets: [textSwitchingSet],\n };\n\n selectionSets.push(textSelectionSet);\n }\n\n // Build presentation (duration is undefined until tracks are resolved)\n return {\n id: generateId(),\n url: unresolved.url,\n startTime: 0,\n // duration: undefined, // Won't be known until after at least one media playlist is fetched + parsed\n selectionSets,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getMediaPlaylistMetadata, isResolvedPresentation, isResolvedTrack } from "../types/index.js";
|
|
2
|
+
import { findTrackById } from "../utils/tracks.js";
|
|
3
|
+
//#region src/media/hls/reload-policy.ts
|
|
4
|
+
/** Reload cadence when a playlist carries no usable target duration. */
|
|
5
|
+
const FALLBACK_TARGET_DURATION = 6;
|
|
6
|
+
/**
|
|
7
|
+
* Default `HOLD-BACK` as a multiple of the target duration when the playlist
|
|
8
|
+
* declares none — the HLS spec default (RFC 8216bis `EXT-X-SERVER-CONTROL`).
|
|
9
|
+
*/
|
|
10
|
+
const HOLD_BACK_TARGET_MULTIPLIER = 3;
|
|
11
|
+
/** Identity of a reload snapshot — window position + length. Changes when the window slid or grew. */
|
|
12
|
+
function snapshotSignature(track) {
|
|
13
|
+
return `${getMediaPlaylistMetadata(track)?.mediaSequence ?? 0}:${track.segments.length}`;
|
|
14
|
+
}
|
|
15
|
+
function targetDurationOf(track) {
|
|
16
|
+
return getMediaPlaylistMetadata(track)?.targetDuration || FALLBACK_TARGET_DURATION;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Live media-playlist reload cadence, per RFC 8216bis §6.3.4 — a
|
|
20
|
+
* {@link RecurrencePolicy} for a `RecurringRunner` re-resolving the selected
|
|
21
|
+
* track. Structurally matches `RecurrencePolicy<ResolvedTrack>` without
|
|
22
|
+
* importing it (media stays core-free): `current` is the freshly resolved track,
|
|
23
|
+
* `previous` the prior resolved snapshot.
|
|
24
|
+
*
|
|
25
|
+
* - Complete playlist (VoD, or live that hit `#EXT-X-ENDLIST`) → `null`: stop.
|
|
26
|
+
* Keys off `Track.duration` (finite once complete), the single completeness
|
|
27
|
+
* source of truth.
|
|
28
|
+
* - Unchanged window (same media sequence + segment count as `previous`) → poll
|
|
29
|
+
* at half the target duration; a moved/grown window (or the first reload) →
|
|
30
|
+
* full target duration.
|
|
31
|
+
*
|
|
32
|
+
* A failed reload doesn't reach here — the rejection propagates through the
|
|
33
|
+
* `RecurringRunner`; transient-failure recovery belongs at the fetch layer.
|
|
34
|
+
*
|
|
35
|
+
* Returned delays are milliseconds.
|
|
36
|
+
*/
|
|
37
|
+
function mediaPlaylistReloadDelay(current, previous) {
|
|
38
|
+
if (Number.isFinite(current.duration)) return null;
|
|
39
|
+
const target = targetDurationOf(current);
|
|
40
|
+
return (!previous || snapshotSignature(current) !== snapshotSignature(previous) ? target : target / 2) * 1e3;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Target live latency (seconds) for a resolved track — how far behind the live
|
|
44
|
+
* edge the playhead should sit. Prefers the server's declared
|
|
45
|
+
* `EXT-X-SERVER-CONTROL` `HOLD-BACK`, falling back to
|
|
46
|
+
* {@link HOLD_BACK_TARGET_MULTIPLIER}× the target duration when absent (the
|
|
47
|
+
* spec default). This is the HLS side of the format-neutral
|
|
48
|
+
* `resolveLiveLatency` seam consumed by `seek-to-live-edge`; a DASH engine
|
|
49
|
+
* supplies its own (`suggestedPresentationDelay`).
|
|
50
|
+
*
|
|
51
|
+
* Only `HOLD-BACK` — never `PART-HOLD-BACK`, which assumes partial-segment
|
|
52
|
+
* playback. See {@link MediaPlaylistMetadata.holdBack}.
|
|
53
|
+
*/
|
|
54
|
+
function liveLatencyFor(track) {
|
|
55
|
+
return getMediaPlaylistMetadata(track)?.holdBack ?? HOLD_BACK_TARGET_MULTIPLIER * targetDurationOf(track);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the target live latency for a presentation's timeline-bearing track —
|
|
59
|
+
* the HLS engine injects this as `seekToLiveEdge`'s format-neutral
|
|
60
|
+
* `resolveLiveLatency` seam. `0` when there is no resolved track to read (the
|
|
61
|
+
* behavior then seeks straight to the edge).
|
|
62
|
+
*/
|
|
63
|
+
function resolveLiveLatency(presentation, trackId) {
|
|
64
|
+
if (!isResolvedPresentation(presentation) || !trackId) return 0;
|
|
65
|
+
const track = findTrackById(presentation, trackId);
|
|
66
|
+
return track && isResolvedTrack(track) ? liveLatencyFor(track) : 0;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { liveLatencyFor, mediaPlaylistReloadDelay, resolveLiveLatency };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=reload-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reload-policy.js","names":[],"sources":["../../../../src/media/hls/reload-policy.ts"],"sourcesContent":["import {\n getMediaPlaylistMetadata,\n isResolvedPresentation,\n isResolvedTrack,\n type MaybeResolvedPresentation,\n type ResolvedTrack,\n} from '../types';\nimport { findTrackById } from '../utils/tracks';\n\n/** Reload cadence when a playlist carries no usable target duration. */\nconst FALLBACK_TARGET_DURATION = 6;\n\n/**\n * Default `HOLD-BACK` as a multiple of the target duration when the playlist\n * declares none — the HLS spec default (RFC 8216bis `EXT-X-SERVER-CONTROL`).\n */\nconst HOLD_BACK_TARGET_MULTIPLIER = 3;\n\n/** Identity of a reload snapshot — window position + length. Changes when the window slid or grew. */\nfunction snapshotSignature(track: ResolvedTrack): string {\n return `${getMediaPlaylistMetadata(track)?.mediaSequence ?? 0}:${track.segments.length}`;\n}\n\nfunction targetDurationOf(track: ResolvedTrack): number {\n return getMediaPlaylistMetadata(track)?.targetDuration || FALLBACK_TARGET_DURATION;\n}\n\n/**\n * Live media-playlist reload cadence, per RFC 8216bis §6.3.4 — a\n * {@link RecurrencePolicy} for a `RecurringRunner` re-resolving the selected\n * track. Structurally matches `RecurrencePolicy<ResolvedTrack>` without\n * importing it (media stays core-free): `current` is the freshly resolved track,\n * `previous` the prior resolved snapshot.\n *\n * - Complete playlist (VoD, or live that hit `#EXT-X-ENDLIST`) → `null`: stop.\n * Keys off `Track.duration` (finite once complete), the single completeness\n * source of truth.\n * - Unchanged window (same media sequence + segment count as `previous`) → poll\n * at half the target duration; a moved/grown window (or the first reload) →\n * full target duration.\n *\n * A failed reload doesn't reach here — the rejection propagates through the\n * `RecurringRunner`; transient-failure recovery belongs at the fetch layer.\n *\n * Returned delays are milliseconds.\n */\nexport function mediaPlaylistReloadDelay(current: ResolvedTrack, previous: ResolvedTrack | undefined): number | null {\n if (Number.isFinite(current.duration)) return null;\n\n const target = targetDurationOf(current);\n const changed = !previous || snapshotSignature(current) !== snapshotSignature(previous);\n return (changed ? target : target / 2) * 1000;\n}\n\n/**\n * Target live latency (seconds) for a resolved track — how far behind the live\n * edge the playhead should sit. Prefers the server's declared\n * `EXT-X-SERVER-CONTROL` `HOLD-BACK`, falling back to\n * {@link HOLD_BACK_TARGET_MULTIPLIER}× the target duration when absent (the\n * spec default). This is the HLS side of the format-neutral\n * `resolveLiveLatency` seam consumed by `seek-to-live-edge`; a DASH engine\n * supplies its own (`suggestedPresentationDelay`).\n *\n * Only `HOLD-BACK` — never `PART-HOLD-BACK`, which assumes partial-segment\n * playback. See {@link MediaPlaylistMetadata.holdBack}.\n */\nexport function liveLatencyFor(track: ResolvedTrack): number {\n return getMediaPlaylistMetadata(track)?.holdBack ?? HOLD_BACK_TARGET_MULTIPLIER * targetDurationOf(track);\n}\n\n/**\n * Resolve the target live latency for a presentation's timeline-bearing track —\n * the HLS engine injects this as `seekToLiveEdge`'s format-neutral\n * `resolveLiveLatency` seam. `0` when there is no resolved track to read (the\n * behavior then seeks straight to the edge).\n */\nexport function resolveLiveLatency(\n presentation: MaybeResolvedPresentation | undefined,\n trackId: string | undefined\n): number {\n if (!isResolvedPresentation(presentation) || !trackId) return 0;\n const track = findTrackById(presentation, trackId);\n return track && isResolvedTrack(track) ? liveLatencyFor(track) : 0;\n}\n"],"mappings":";;;;AAUA,MAAM,2BAA2B;;;;;AAMjC,MAAM,8BAA8B;;AAGpC,SAAS,kBAAkB,OAA8B;CACvD,OAAO,GAAG,yBAAyB,KAAK,CAAC,EAAE,iBAAiB,EAAE,GAAG,MAAM,SAAS;AAClF;AAEA,SAAS,iBAAiB,OAA8B;CACtD,OAAO,yBAAyB,KAAK,CAAC,EAAE,kBAAkB;AAC5D;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,yBAAyB,SAAwB,UAAoD;CACnH,IAAI,OAAO,SAAS,QAAQ,QAAQ,GAAG,OAAO;CAE9C,MAAM,SAAS,iBAAiB,OAAO;CAEvC,QADgB,CAAC,YAAY,kBAAkB,OAAO,MAAM,kBAAkB,QAAQ,IACpE,SAAS,SAAS,KAAK;AAC3C;;;;;;;;;;;;;AAcA,SAAgB,eAAe,OAA8B;CAC3D,OAAO,yBAAyB,KAAK,CAAC,EAAE,YAAY,8BAA8B,iBAAiB,KAAK;AAC1G;;;;;;;AAQA,SAAgB,mBACd,cACA,SACQ;CACR,IAAI,CAAC,uBAAuB,YAAY,KAAK,CAAC,SAAS,OAAO;CAC9D,MAAM,QAAQ,cAAc,cAAc,OAAO;CACjD,OAAO,SAAS,gBAAgB,KAAK,IAAI,eAAe,KAAK,IAAI;AACnE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/media/hls/resolve-url.ts
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a potentially relative URL against a base URL using native URL API.
|
|
4
|
+
*/
|
|
5
|
+
function resolveUrl(url, baseUrl) {
|
|
6
|
+
return new URL(url, baseUrl).href;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { resolveUrl };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=resolve-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-url.js","names":[],"sources":["../../../../src/media/hls/resolve-url.ts"],"sourcesContent":["/**\n * Resolve a potentially relative URL against a base URL using native URL API.\n */\nexport function resolveUrl(url: string, baseUrl: string): string {\n return new URL(url, baseUrl).href;\n}\n"],"mappings":";;;;AAGA,SAAgB,WAAW,KAAa,SAAyB;CAC/D,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC;AAC/B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isResolvedPresentation, isResolvedTrack } from "./types/index.js";
|
|
2
|
+
import { findTrackById } from "./utils/tracks.js";
|
|
3
|
+
//#region src/media/live-window.ts
|
|
4
|
+
/**
|
|
5
|
+
* Derive the live window of the track with the given id — the single source of
|
|
6
|
+
* truth for "where is live," consumed (via `liveWindowFromState`) by the
|
|
7
|
+
* seek-to-live-edge and live-seekable-range behaviors so neither re-derives (or
|
|
8
|
+
* re-presumes) the window shape. Type-agnostic: the caller decides which track
|
|
9
|
+
* bears the timeline (video when present, else audio).
|
|
10
|
+
*
|
|
11
|
+
* The window is a **live read** over the current `segments` array — never
|
|
12
|
+
* stored on the track. The anchor triple is frozen per source; per-segment
|
|
13
|
+
* `startTime` values are re-derived against it on every reload, so the edge
|
|
14
|
+
* here slides while the origin stays fixed (see
|
|
15
|
+
* `internal/design/spf/live-presentation-timeline-model.md`).
|
|
16
|
+
*
|
|
17
|
+
* Returns `null` when there is no live edge to track: an unresolved
|
|
18
|
+
* presentation or track, a track with no segments, or a **complete** playlist
|
|
19
|
+
* (VoD, or live that has ended — a finite `Track.duration`).
|
|
20
|
+
*/
|
|
21
|
+
function liveWindowFor(presentation, trackId) {
|
|
22
|
+
if (!isResolvedPresentation(presentation) || !trackId) return null;
|
|
23
|
+
const track = findTrackById(presentation, trackId);
|
|
24
|
+
if (!track || !isResolvedTrack(track) || track.segments.length === 0) return null;
|
|
25
|
+
if (Number.isFinite(track.duration)) return null;
|
|
26
|
+
const { segments } = track;
|
|
27
|
+
const last = segments[segments.length - 1];
|
|
28
|
+
return {
|
|
29
|
+
start: segments[0].startTime,
|
|
30
|
+
end: last.startTime + last.duration
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { liveWindowFor };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=live-window.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-window.js","names":[],"sources":["../../../src/media/live-window.ts"],"sourcesContent":["/**\n * Derive the live window of the track with the given id — the single source of\n * truth for \"where is live,\" consumed (via `liveWindowFromState`) by the\n * seek-to-live-edge and live-seekable-range behaviors so neither re-derives (or\n * re-presumes) the window shape. Type-agnostic: the caller decides which track\n * bears the timeline (video when present, else audio).\n *\n * The window is a **live read** over the current `segments` array — never\n * stored on the track. The anchor triple is frozen per source; per-segment\n * `startTime` values are re-derived against it on every reload, so the edge\n * here slides while the origin stays fixed (see\n * `internal/design/spf/live-presentation-timeline-model.md`).\n *\n * Returns `null` when there is no live edge to track: an unresolved\n * presentation or track, a track with no segments, or a **complete** playlist\n * (VoD, or live that has ended — a finite `Track.duration`).\n */\nimport { isResolvedPresentation, isResolvedTrack, type MaybeResolvedPresentation } from './types';\nimport { findTrackById } from './utils/tracks';\n\nexport interface LiveWindow {\n /** Earliest time still in the window (seconds, presentation timeline). */\n start: number;\n /** The live edge — latest time in the window (seconds). */\n end: number;\n}\n\nexport function liveWindowFor(\n presentation: MaybeResolvedPresentation | undefined,\n trackId: string | undefined\n): LiveWindow | null {\n if (!isResolvedPresentation(presentation) || !trackId) return null;\n\n const track = findTrackById(presentation, trackId);\n if (!track || !isResolvedTrack(track) || track.segments.length === 0) return null;\n\n // Complete playlist (VoD, or live that has ended) → no live edge. `Track.duration`\n // is the parser's completeness signal (finite = complete, Infinity = still growing).\n if (Number.isFinite(track.duration)) return null;\n\n const { segments } = track;\n const last = segments[segments.length - 1]!;\n return {\n start: segments[0]!.startTime,\n end: last.startTime + last.duration,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,cACd,cACA,SACmB;CACnB,IAAI,CAAC,uBAAuB,YAAY,KAAK,CAAC,SAAS,OAAO;CAE9D,MAAM,QAAQ,cAAc,cAAc,OAAO;CACjD,IAAI,CAAC,SAAS,CAAC,gBAAgB,KAAK,KAAK,MAAM,SAAS,WAAW,GAAG,OAAO;CAI7E,IAAI,OAAO,SAAS,MAAM,QAAQ,GAAG,OAAO;CAE5C,MAAM,EAAE,aAAa;CACrB,MAAM,OAAO,SAAS,SAAS,SAAS;CACxC,OAAO;EACL,OAAO,SAAS,EAAE,CAAE;EACpB,KAAK,KAAK,YAAY,KAAK;CAC7B;AACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { AudioTrack, FrameRate, MaybeResolvedPresentation, VideoTrack } from "../types/index.js";
|
|
2
|
+
//#region src/media/media-tracks/media-tracks.d.ts
|
|
3
|
+
/** Properties that identify a distinct video rendition (multi-CDN copies share them). */
|
|
4
|
+
interface VideoDedupeKey {
|
|
5
|
+
width?: VideoTrack['width'];
|
|
6
|
+
height?: VideoTrack['height'];
|
|
7
|
+
bandwidth?: VideoTrack['bandwidth'];
|
|
8
|
+
}
|
|
9
|
+
/** Properties that identify a distinct audio track (multi-CDN copies share them). */
|
|
10
|
+
interface AudioDedupeKey {
|
|
11
|
+
language?: AudioTrack['language'];
|
|
12
|
+
name?: AudioTrack['name'];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The distinct video tracks of a presentation, deduped by {@link VideoDedupeKey} (first occurrence wins).
|
|
16
|
+
*
|
|
17
|
+
* Returns `[]` when the presentation is unresolved or has no video tracks.
|
|
18
|
+
*/
|
|
19
|
+
declare function dedupedVideoTracks(presentation: MaybeResolvedPresentation | undefined): VideoTrack[];
|
|
20
|
+
/**
|
|
21
|
+
* The distinct audio tracks of a presentation, deduped by `language` + `name`
|
|
22
|
+
* (first occurrence wins). Returns `[]` when the presentation is unresolved or has no audio tracks.
|
|
23
|
+
*/
|
|
24
|
+
declare function dedupedAudioTracks(presentation: MaybeResolvedPresentation | undefined): AudioTrack[];
|
|
25
|
+
/**
|
|
26
|
+
* Find a video track by id, searching the same candidate set the engine resolves
|
|
27
|
+
* against ({@link dedupedVideoTracks}'s pre-dedupe source). Returns `undefined`
|
|
28
|
+
* when absent. Maps the engine's resolved `selectedVideoTrackId` back to its
|
|
29
|
+
* properties for `active` reflection — the resolved id may be a per-CDN copy that
|
|
30
|
+
* isn't the representative {@link dedupedVideoTracks} kept.
|
|
31
|
+
*/
|
|
32
|
+
declare function findVideoTrackById(presentation: MaybeResolvedPresentation | undefined, id: string | undefined): VideoTrack | undefined;
|
|
33
|
+
/** Audio counterpart of {@link findVideoTrackById}, for `enabled` reflection. */
|
|
34
|
+
declare function findAudioTrackById(presentation: MaybeResolvedPresentation | undefined, id: string | undefined): AudioTrack | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Build a partial video track that can be used as `userVideoTrackSelection`.
|
|
37
|
+
*/
|
|
38
|
+
declare function toUserVideoTrackSelection<T extends VideoDedupeKey>(rendition?: T): Partial<VideoTrack> | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Build a partial audio track that can be used as a `userAudioTrackSelection`.
|
|
41
|
+
*/
|
|
42
|
+
declare function toUserAudioTrackSelection<T extends AudioDedupeKey>(track?: T): Partial<AudioTrack> | undefined;
|
|
43
|
+
/** Whether two video tracks are the same by dedupe key */
|
|
44
|
+
declare function isSameVideoTrack(a: VideoDedupeKey, b: VideoDedupeKey | undefined): boolean;
|
|
45
|
+
/** Whether two audio tracks are the same by dedupe key */
|
|
46
|
+
declare function isSameAudioTrack(a: AudioDedupeKey, b: AudioDedupeKey | undefined): boolean;
|
|
47
|
+
/** Collapse a rational frame rate (numerator/denominator) to frames per second. */
|
|
48
|
+
declare const frameRateToNumber: (frameRate: FrameRate) => number;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { AudioDedupeKey, type AudioTrack, VideoDedupeKey, type VideoTrack, dedupedAudioTracks, dedupedVideoTracks, findAudioTrackById, findVideoTrackById, frameRateToNumber, isSameAudioTrack, isSameVideoTrack, toUserAudioTrackSelection, toUserVideoTrackSelection };
|
|
51
|
+
//# sourceMappingURL=media-tracks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-tracks.d.ts","names":[],"sources":["../../../../src/media/media-tracks/media-tracks.ts"],"mappings":";;;UA0BiB;EACf,QAAQ;EACR,SAAS;EACT,YAAY;;;UAIG;EACf,WAAW;EACX,OAAO;;;;;;;iBAQO,mBAAmB,cAAc,wCAAwC;;;;;iBAazE,mBAAmB,cAAc,wCAAwC;;;;;;;;iBAgBzE,mBACd,cAAc,uCACd,yBACC;;iBAOa,mBACd,cAAc,uCACd,yBACC;;;;iBA2Ca,0BAA0B,UAAU,gBAAgB,YAAY,IAAI,QAAQ;;;;iBAO5E,0BAA0B,UAAU,gBAAgB,QAAQ,IAAI,QAAQ;;iBAKxE,iBAAiB,GAAG,gBAAgB,GAAG;;iBAKvC,iBAAiB,GAAG,gBAAgB,GAAG;;cAK1C,oBAAiB,WAAe"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { findTrackById, getTracksByType } from "../utils/tracks.js";
|
|
2
|
+
//#region src/media/media-tracks/media-tracks.ts
|
|
3
|
+
/**
|
|
4
|
+
* The distinct video tracks of a presentation, deduped by {@link VideoDedupeKey} (first occurrence wins).
|
|
5
|
+
*
|
|
6
|
+
* Returns `[]` when the presentation is unresolved or has no video tracks.
|
|
7
|
+
*/
|
|
8
|
+
function dedupedVideoTracks(presentation) {
|
|
9
|
+
if (!presentation) return [];
|
|
10
|
+
return dedupe({
|
|
11
|
+
tracks: getTracksByType(presentation, "video"),
|
|
12
|
+
keyFn: toUserVideoTrackSelection
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The distinct audio tracks of a presentation, deduped by `language` + `name`
|
|
17
|
+
* (first occurrence wins). Returns `[]` when the presentation is unresolved or has no audio tracks.
|
|
18
|
+
*/
|
|
19
|
+
function dedupedAudioTracks(presentation) {
|
|
20
|
+
if (!presentation) return [];
|
|
21
|
+
return dedupe({
|
|
22
|
+
tracks: getTracksByType(presentation, "audio"),
|
|
23
|
+
keyFn: toUserAudioTrackSelection
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Find a video track by id, searching the same candidate set the engine resolves
|
|
28
|
+
* against ({@link dedupedVideoTracks}'s pre-dedupe source). Returns `undefined`
|
|
29
|
+
* when absent. Maps the engine's resolved `selectedVideoTrackId` back to its
|
|
30
|
+
* properties for `active` reflection — the resolved id may be a per-CDN copy that
|
|
31
|
+
* isn't the representative {@link dedupedVideoTracks} kept.
|
|
32
|
+
*/
|
|
33
|
+
function findVideoTrackById(presentation, id) {
|
|
34
|
+
if (!presentation || !id) return void 0;
|
|
35
|
+
const track = findTrackById(presentation, id);
|
|
36
|
+
return track?.type === "video" ? track : void 0;
|
|
37
|
+
}
|
|
38
|
+
/** Audio counterpart of {@link findVideoTrackById}, for `enabled` reflection. */
|
|
39
|
+
function findAudioTrackById(presentation, id) {
|
|
40
|
+
if (!presentation || !id) return void 0;
|
|
41
|
+
const track = findTrackById(presentation, id);
|
|
42
|
+
return track?.type === "audio" ? track : void 0;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Shallow-equal two key objects by their own properties. Both come from the same
|
|
46
|
+
* key builder, so they carry the same keys — a one-directional scan suffices.
|
|
47
|
+
*/
|
|
48
|
+
function sameKey(a, b) {
|
|
49
|
+
for (const attr in a) if (a[attr] !== b[attr]) return false;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Dedupe tracks by a key function, keeping the first occurrence of each key.
|
|
54
|
+
* Keys are compared field-by-field ({@link sameKey}).
|
|
55
|
+
*/
|
|
56
|
+
function dedupe({ tracks, keyFn }) {
|
|
57
|
+
const seen = [];
|
|
58
|
+
const kept = [];
|
|
59
|
+
for (const track of tracks) {
|
|
60
|
+
const key = keyFn(track);
|
|
61
|
+
if (!key || seen.some((other) => sameKey(other, key))) continue;
|
|
62
|
+
seen.push(key);
|
|
63
|
+
kept.push(track);
|
|
64
|
+
}
|
|
65
|
+
return kept;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build a partial video track that can be used as `userVideoTrackSelection`.
|
|
69
|
+
*/
|
|
70
|
+
function toUserVideoTrackSelection(rendition) {
|
|
71
|
+
return rendition ? {
|
|
72
|
+
width: rendition.width,
|
|
73
|
+
height: rendition.height,
|
|
74
|
+
bandwidth: rendition.bandwidth
|
|
75
|
+
} : void 0;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build a partial audio track that can be used as a `userAudioTrackSelection`.
|
|
79
|
+
*/
|
|
80
|
+
function toUserAudioTrackSelection(track) {
|
|
81
|
+
return track ? {
|
|
82
|
+
language: track.language,
|
|
83
|
+
name: track.name
|
|
84
|
+
} : void 0;
|
|
85
|
+
}
|
|
86
|
+
/** Whether two video tracks are the same by dedupe key */
|
|
87
|
+
function isSameVideoTrack(a, b) {
|
|
88
|
+
return !!b && a.width === b.width && a.height === b.height && a.bandwidth === b.bandwidth;
|
|
89
|
+
}
|
|
90
|
+
/** Whether two audio tracks are the same by dedupe key */
|
|
91
|
+
function isSameAudioTrack(a, b) {
|
|
92
|
+
return !!b && (a.language ?? "") === (b.language ?? "") && a.name === b.name;
|
|
93
|
+
}
|
|
94
|
+
/** Collapse a rational frame rate (numerator/denominator) to frames per second. */
|
|
95
|
+
const frameRateToNumber = (frameRate) => {
|
|
96
|
+
return frameRate.frameRateNumerator / (frameRate.frameRateDenominator ?? 1);
|
|
97
|
+
};
|
|
98
|
+
//#endregion
|
|
99
|
+
export { dedupedAudioTracks, dedupedVideoTracks, findAudioTrackById, findVideoTrackById, frameRateToNumber, isSameAudioTrack, isSameVideoTrack, toUserAudioTrackSelection, toUserVideoTrackSelection };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=media-tracks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-tracks.js","names":[],"sources":["../../../../src/media/media-tracks/media-tracks.ts"],"sourcesContent":["/**\n * Media-track translation utilities.\n *\n * Pure, DOM-free transforms from SPF's CMAF-HAM track model onto the deduped\n * lists a media-element adapter exposes (video renditions, audio tracks), plus\n * the selection-criteria builders that turn a chosen rendition/track back into a\n * `user*TrackSelection` partial the engine's track-switching reads.\n *\n * These return SPF *model vocabulary* (`bandwidth`, `codecs: string[]`,\n * `frameRate` as a rational `FrameRate`); the consuming adapter owns the\n * mapping (e.g. for DOM `bandwidth` -> `bitrate`, `codecs.join(',')` -> `codec`,\n * `name` -> `label`).\n *\n * Deduplication is by *properties*, never URL, so a multi-CDN source that lists\n * the same rendition on several hosts collapses to one entry: video renditions\n * by `width` + `height` + `bandwidth`, audio tracks by `language` + `name`.\n * The selection builders emit those same properties as the match criteria, so\n * selecting a collapsed entry re-selects, for example, every underlying per-CDN track.\n */\n\nimport type { AudioTrack, FrameRate, MaybeResolvedPresentation, VideoTrack } from '../types';\nimport { findTrackById, getTracksByType } from '../utils/tracks';\n\nexport type { AudioTrack, VideoTrack };\n\n/** Properties that identify a distinct video rendition (multi-CDN copies share them). */\nexport interface VideoDedupeKey {\n width?: VideoTrack['width'];\n height?: VideoTrack['height'];\n bandwidth?: VideoTrack['bandwidth'];\n}\n\n/** Properties that identify a distinct audio track (multi-CDN copies share them). */\nexport interface AudioDedupeKey {\n language?: AudioTrack['language'];\n name?: AudioTrack['name'];\n}\n\n/**\n * The distinct video tracks of a presentation, deduped by {@link VideoDedupeKey} (first occurrence wins).\n *\n * Returns `[]` when the presentation is unresolved or has no video tracks.\n */\nexport function dedupedVideoTracks(presentation: MaybeResolvedPresentation | undefined): VideoTrack[] {\n if (!presentation) return [];\n\n return dedupe({\n tracks: getTracksByType(presentation, 'video') as readonly VideoTrack[],\n keyFn: toUserVideoTrackSelection,\n });\n}\n\n/**\n * The distinct audio tracks of a presentation, deduped by `language` + `name`\n * (first occurrence wins). Returns `[]` when the presentation is unresolved or has no audio tracks.\n */\nexport function dedupedAudioTracks(presentation: MaybeResolvedPresentation | undefined): AudioTrack[] {\n if (!presentation) return [];\n\n return dedupe({\n tracks: getTracksByType(presentation, 'audio') as readonly AudioTrack[],\n keyFn: toUserAudioTrackSelection,\n });\n}\n\n/**\n * Find a video track by id, searching the same candidate set the engine resolves\n * against ({@link dedupedVideoTracks}'s pre-dedupe source). Returns `undefined`\n * when absent. Maps the engine's resolved `selectedVideoTrackId` back to its\n * properties for `active` reflection — the resolved id may be a per-CDN copy that\n * isn't the representative {@link dedupedVideoTracks} kept.\n */\nexport function findVideoTrackById(\n presentation: MaybeResolvedPresentation | undefined,\n id: string | undefined\n): VideoTrack | undefined {\n if (!presentation || !id) return undefined;\n const track = findTrackById(presentation, id);\n return track?.type === 'video' ? (track as VideoTrack) : undefined;\n}\n\n/** Audio counterpart of {@link findVideoTrackById}, for `enabled` reflection. */\nexport function findAudioTrackById(\n presentation: MaybeResolvedPresentation | undefined,\n id: string | undefined\n): AudioTrack | undefined {\n if (!presentation || !id) return undefined;\n const track = findTrackById(presentation, id);\n return track?.type === 'audio' ? (track as AudioTrack) : undefined;\n}\n\n/**\n * Shallow-equal two key objects by their own properties. Both come from the same\n * key builder, so they carry the same keys — a one-directional scan suffices.\n */\nfunction sameKey<K extends object>(a: K, b: K): boolean {\n for (const attr in a) {\n if (a[attr] !== b[attr]) return false;\n }\n return true;\n}\n\n/**\n * Dedupe tracks by a key function, keeping the first occurrence of each key.\n * Keys are compared field-by-field ({@link sameKey}).\n */\nfunction dedupe<T, K extends object>({\n tracks,\n keyFn,\n}: {\n tracks: readonly T[];\n keyFn: (track: T) => K | undefined;\n}): T[] {\n const seen: K[] = [];\n const kept: T[] = [];\n for (const track of tracks) {\n const key = keyFn(track);\n if (!key || seen.some((other) => sameKey(other, key))) continue;\n seen.push(key);\n kept.push(track);\n }\n\n return kept;\n}\n\n/**\n * Build a partial video track that can be used as `userVideoTrackSelection`.\n */\nexport function toUserVideoTrackSelection<T extends VideoDedupeKey>(rendition?: T): Partial<VideoTrack> | undefined {\n return rendition ? { width: rendition.width, height: rendition.height, bandwidth: rendition.bandwidth } : undefined;\n}\n\n/**\n * Build a partial audio track that can be used as a `userAudioTrackSelection`.\n */\nexport function toUserAudioTrackSelection<T extends AudioDedupeKey>(track?: T): Partial<AudioTrack> | undefined {\n return track ? { language: track.language, name: track.name } : undefined;\n}\n\n/** Whether two video tracks are the same by dedupe key */\nexport function isSameVideoTrack(a: VideoDedupeKey, b: VideoDedupeKey | undefined): boolean {\n return !!b && a.width === b.width && a.height === b.height && a.bandwidth === b.bandwidth;\n}\n\n/** Whether two audio tracks are the same by dedupe key */\nexport function isSameAudioTrack(a: AudioDedupeKey, b: AudioDedupeKey | undefined): boolean {\n return !!b && (a.language ?? '') === (b.language ?? '') && a.name === b.name;\n}\n\n/** Collapse a rational frame rate (numerator/denominator) to frames per second. */\nexport const frameRateToNumber = (frameRate: FrameRate) => {\n return frameRate.frameRateNumerator / (frameRate.frameRateDenominator ?? 1);\n};\n"],"mappings":";;;;;;;AA2CA,SAAgB,mBAAmB,cAAmE;CACpG,IAAI,CAAC,cAAc,OAAO,CAAC;CAE3B,OAAO,OAAO;EACZ,QAAQ,gBAAgB,cAAc,OAAO;EAC7C,OAAO;CACT,CAAC;AACH;;;;;AAMA,SAAgB,mBAAmB,cAAmE;CACpG,IAAI,CAAC,cAAc,OAAO,CAAC;CAE3B,OAAO,OAAO;EACZ,QAAQ,gBAAgB,cAAc,OAAO;EAC7C,OAAO;CACT,CAAC;AACH;;;;;;;;AASA,SAAgB,mBACd,cACA,IACwB;CACxB,IAAI,CAAC,gBAAgB,CAAC,IAAI,OAAO,KAAA;CACjC,MAAM,QAAQ,cAAc,cAAc,EAAE;CAC5C,OAAO,OAAO,SAAS,UAAW,QAAuB,KAAA;AAC3D;;AAGA,SAAgB,mBACd,cACA,IACwB;CACxB,IAAI,CAAC,gBAAgB,CAAC,IAAI,OAAO,KAAA;CACjC,MAAM,QAAQ,cAAc,cAAc,EAAE;CAC5C,OAAO,OAAO,SAAS,UAAW,QAAuB,KAAA;AAC3D;;;;;AAMA,SAAS,QAA0B,GAAM,GAAe;CACtD,KAAK,MAAM,QAAQ,GACjB,IAAI,EAAE,UAAU,EAAE,OAAO,OAAO;CAElC,OAAO;AACT;;;;;AAMA,SAAS,OAA4B,EACnC,QACA,SAIM;CACN,MAAM,OAAY,CAAC;CACnB,MAAM,OAAY,CAAC;CACnB,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,MAAM,MAAM,KAAK;EACvB,IAAI,CAAC,OAAO,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG,CAAC,GAAG;EACvD,KAAK,KAAK,GAAG;EACb,KAAK,KAAK,KAAK;CACjB;CAEA,OAAO;AACT;;;;AAKA,SAAgB,0BAAoD,WAAgD;CAClH,OAAO,YAAY;EAAE,OAAO,UAAU;EAAO,QAAQ,UAAU;EAAQ,WAAW,UAAU;CAAU,IAAI,KAAA;AAC5G;;;;AAKA,SAAgB,0BAAoD,OAA4C;CAC9G,OAAO,QAAQ;EAAE,UAAU,MAAM;EAAU,MAAM,MAAM;CAAK,IAAI,KAAA;AAClE;;AAGA,SAAgB,iBAAiB,GAAmB,GAAwC;CAC1F,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE;AAClF;;AAGA,SAAgB,iBAAiB,GAAmB,GAAwC;CAC1F,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,SAAS,EAAE,YAAY,OAAO,EAAE,SAAS,EAAE;AAC1E;;AAGA,MAAa,qBAAqB,cAAyB;CACzD,OAAO,UAAU,sBAAsB,UAAU,wBAAwB;AAC3E"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/media/mp4/box.ts
|
|
2
|
+
function toDataView(data) {
|
|
3
|
+
return data instanceof Uint8Array ? new DataView(data.buffer, data.byteOffset, data.byteLength) : new DataView(data);
|
|
4
|
+
}
|
|
5
|
+
/** Read a 4-character box type / FourCC at `offset`. */
|
|
6
|
+
function readFourCC(view, offset) {
|
|
7
|
+
return String.fromCharCode(view.getUint8(offset), view.getUint8(offset + 1), view.getUint8(offset + 2), view.getUint8(offset + 3));
|
|
8
|
+
}
|
|
9
|
+
/** Iterate the boxes directly contained in `[start, end)`. */
|
|
10
|
+
function* iterateBoxes(view, start = 0, end = view.byteLength) {
|
|
11
|
+
let offset = start;
|
|
12
|
+
while (offset + 8 <= end) {
|
|
13
|
+
let size = view.getUint32(offset);
|
|
14
|
+
const type = readFourCC(view, offset + 4);
|
|
15
|
+
let dataStart = offset + 8;
|
|
16
|
+
if (size === 1) {
|
|
17
|
+
size = Number(view.getBigUint64(offset + 8));
|
|
18
|
+
dataStart = offset + 16;
|
|
19
|
+
} else if (size === 0) size = end - offset;
|
|
20
|
+
if (size < dataStart - offset) return;
|
|
21
|
+
yield {
|
|
22
|
+
type,
|
|
23
|
+
start: offset,
|
|
24
|
+
dataStart,
|
|
25
|
+
end: offset + size
|
|
26
|
+
};
|
|
27
|
+
offset += size;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Iterate the direct child boxes of a given `type` within `[start, end)`. */
|
|
31
|
+
function* iterateBoxesOfType(view, type, start = 0, end = view.byteLength) {
|
|
32
|
+
for (const box of iterateBoxes(view, start, end)) if (box.type === type) yield box;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Depth-first descent to the first box matching a nested path, e.g.
|
|
36
|
+
* `['moov', 'trak', 'mdia', 'mdhd']`. Returns `undefined` if any level is
|
|
37
|
+
* absent.
|
|
38
|
+
*/
|
|
39
|
+
function findBox(view, path, start = 0, end = view.byteLength) {
|
|
40
|
+
const [head, ...rest] = path;
|
|
41
|
+
for (const box of iterateBoxes(view, start, end)) {
|
|
42
|
+
if (box.type !== head) continue;
|
|
43
|
+
if (rest.length === 0) return box;
|
|
44
|
+
const found = findBox(view, rest, box.dataStart, box.end);
|
|
45
|
+
if (found) return found;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Read the version byte of a FullBox — the `version(1) + flags(3)` header at the
|
|
50
|
+
* start of the payload of `mdhd` / `tkhd` / `tfdt` / `hdlr` / `elst` / etc.
|
|
51
|
+
*/
|
|
52
|
+
function readFullBoxVersion(view, dataStart) {
|
|
53
|
+
return view.getUint8(dataStart);
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { findBox, iterateBoxes, iterateBoxesOfType, readFourCC, readFullBoxVersion, toDataView };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=box.js.map
|