├── .nvmrc ├── src ├── util │ ├── noop.js │ ├── to-title-case.js │ ├── fn.js │ ├── logger.js │ ├── string-to-array-buffer.js │ ├── string.js │ ├── shallow-equal.js │ ├── segment.js │ ├── worker-callback.js │ ├── vjs-compat.js │ ├── container-request.js │ ├── date-ranges.js │ └── gops.js ├── config.js ├── resolve-url.js ├── decrypter-worker.js ├── error-codes.js ├── timeline-change-controller.js ├── ad-cue-tags.js ├── bin-utils.js ├── reload-source-on-error.js └── rendition-mixin.js ├── utils ├── bc0.ts ├── bipbop0.flv ├── bipbop0.ts ├── bipbop1.flv ├── bipbop1.ts ├── switcher │ ├── network_logs │ │ └── README.md │ ├── fn.js │ └── aggregate-simulations.js └── stats │ └── stats.css ├── test ├── segments │ ├── subtitles.vtt │ ├── id3.ts │ ├── audio.ts │ ├── muxed.ts │ ├── sidx.mp4 │ ├── video.ts │ ├── caption.ts │ ├── encrypted.ts │ ├── mp4Audio.mp4 │ ├── mp4Muxed.mp4 │ ├── mp4Video.mp4 │ ├── mp4WebVtt.mp4 │ ├── oneSecond.ts │ ├── zeroLength.ts │ ├── aacWithId3.aac │ ├── ac3WithId3.ac3 │ ├── mp4AudioInit.mp4 │ ├── mp4Captions.mp4 │ ├── mp4MuxedInit.mp4 │ ├── mp4VideoInit.mp4 │ ├── webmVideo.webm │ ├── aacWithoutId3.aac │ ├── ac3WithoutId3.ac3 │ ├── audioMaxOffset.ts │ ├── audioMinOffset.ts │ ├── encryptionKey.key │ ├── mp4WebVttInit.mp4 │ ├── videoDiffPtsDts.ts │ ├── videoMaxOffset.ts │ ├── videoMinOffset.ts │ ├── videoOneSecond.ts │ ├── videoOneSecond1.ts │ ├── videoOneSecond2.ts │ ├── videoOneSecond3.ts │ ├── videoOneSecond4.ts │ ├── webmVideoInit.webm │ ├── audioLargeOffset.ts │ ├── audioLargeOffset2.ts │ ├── videoLargeOffset.ts │ ├── videoLargeOffset2.ts │ └── subtitlesEncrypted.vtt ├── manifests │ ├── missingEndlist.m3u8 │ ├── multipleTargetDurations.m3u8 │ ├── manifestNoExtM3u.m3u8 │ ├── one-rendition.m3u8 │ ├── streamInfInvalid.m3u8 │ ├── manifestExtTTargetdurationNegative.m3u8 │ ├── zeroDuration.m3u8 │ ├── versionInvalid.m3u8 │ ├── zeroLength.m3u8 │ ├── two-renditions.m3u8 │ ├── disallowCache.m3u8 │ ├── emptyAllowCache.m3u8 │ ├── subtitles.m3u8 │ ├── invalidAllowCache.m3u8 │ ├── startVod.m3u8 │ ├── allowCacheInvalid.m3u8 │ ├── missingExtinf.m3u8 │ ├── startNegative.m3u8 │ ├── playlistMediaSequenceHigher.m3u8 │ ├── demuxed.m3u8 │ ├── domainUris.m3u8 │ ├── extXPlaylistTypeInvalidPlaylist.m3u8 │ ├── demuxed-two.m3u8 │ ├── media.m3u8 │ ├── media1.m3u8 │ ├── media2.m3u8 │ ├── media3.m3u8 │ ├── startLive.m3u8 │ ├── disc-sequence.m3u8 │ ├── absoluteUris.m3u8 │ ├── whiteSpace.m3u8 │ ├── liveStart30sBefore.m3u8 │ ├── liveMissingSegmentDuration.m3u8 │ ├── main.m3u8 │ ├── manifestExtXEndlistEarly.m3u8 │ ├── discontinuity.m3u8 │ ├── missingSegmentDuration.m3u8 │ ├── audioOnlyAlternateAudio.m3u8 │ ├── program-date-time.m3u8 │ ├── missingMediaSequence.m3u8 │ ├── mediaSequence.m3u8 │ ├── emptyMediaSequence.m3u8 │ ├── negativeMediaSequence.m3u8 │ ├── invalidMediaSequence.m3u8 │ ├── twoMediaSequences.m3u8 │ ├── playlist_target_duration_template.m3u8 │ ├── alternateVideo.m3u8 │ ├── alternateAudio.m3u8 │ ├── playlist_media_sequence_template.m3u8 │ ├── event.m3u8 │ ├── emptyPlaylistType.m3u8 │ ├── invalidPlaylistType.m3u8 │ ├── playlist_type_template.m3u8 │ ├── brightcove.m3u8 │ ├── alternate-audio-multiple-groups.m3u8 │ ├── emptyTargetDuration.m3u8 │ ├── encrypted.m3u8 │ ├── alternate-audio-accessibility.m3u8 │ ├── main-captions.m3u8 │ ├── main-subtitles.m3u8 │ ├── multipleVideo.m3u8 │ ├── multipleAudioGroups.m3u8 │ ├── multipleAudioGroupsCombinedMain.m3u8 │ ├── dash-sidx.mpd │ ├── byteRange.m3u8 │ ├── dash.mpd │ ├── extinf.m3u8 │ ├── playlist.m3u8 │ ├── allowCache.m3u8 │ ├── invalidTargetDuration.m3u8 │ ├── dash-live.mpd │ ├── location.mpd │ ├── playlist_allow_cache_template.m3u8 │ ├── playlist_byte_range_template.m3u8 │ ├── playlist_extinf_template.m3u8 │ ├── dash-many-codecs.mpd │ └── eventStream.mpd ├── util │ ├── string.test.js │ ├── logger.test.js │ ├── string-to-array-buffer.test.js │ ├── segment.test.js │ ├── media-sequence-sync.test.js │ └── text-tracks.test.js ├── custom-assertions.js ├── sanity.test.js └── resolve-url.test.js ├── docs ├── images │ ├── containers.png │ ├── hls-format.png │ ├── mp2t-structure.png │ ├── bitrate-switching-1.png │ ├── bitrate-switching-2.png │ ├── bitrate-switching-3.png │ ├── bitrate-switching-4.png │ ├── mp2t-packet-types.png │ ├── segment-loader-states.png │ ├── sources │ │ ├── containers.graffle │ │ ├── hls-format.graffle │ │ ├── mp2t-structure.graffle │ │ ├── mp2t-packet-types.graffle │ │ ├── bitrate-switching-1.graffle │ │ ├── bitrate-switching-2.graffle │ │ ├── bitrate-switching-3.graffle │ │ ├── bitrate-switching-4.graffle │ │ ├── dash-playlist-loader-states.nomnoml.txt │ │ ├── playlist-loader-states.nomnoml.txt │ │ ├── playlist-loader-pc-mg-sequence.puml │ │ └── dash-playlist-loader-pc-mg-sequence.puml │ ├── playlist-loader-pc-mg-sequence.puml.png │ ├── dash-playlist-loader-pc-mg-sequence.puml.png │ ├── dash-playlist-loader-states.nomnoml.svg │ └── playlist-loader-states.nomnoml.svg ├── lhls │ ├── current-flow.plantuml.png │ ├── expected-flow.plantuml.png │ ├── new-segment-loader-sequence.plantuml.png │ ├── current-transmux-and-append-flow.plantuml.png │ ├── current-flow.plantuml │ ├── expected-flow.plantuml │ ├── current-transmux-and-append-flow.plantuml │ └── transmux-before-append-changes.md ├── hlse.md ├── migration-2-3.md ├── player-time-to-program-time.md ├── media.md ├── reload-source-on-error.md ├── mse.md ├── glossary.md ├── bitrate-switching.md ├── content-steering.md ├── playlist-loader.md ├── arch.md └── troubleshooting.md ├── .npmignore ├── .editorconfig ├── .github ├── move.yml ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml ├── config.yml ├── ISSUE_TEMPLATE.md └── workflows │ ├── release.yml │ └── ci.yml ├── .gitignore ├── scripts ├── create-docs-images.js ├── karma.conf.js ├── netlify.js └── create-test-data.js ├── CONTRIBUTING.md ├── LICENSE ├── logo.svg ├── design └── media-groups.md ├── COLLABORATOR_GUIDE.md └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 2 | -------------------------------------------------------------------------------- /src/util/noop.js: -------------------------------------------------------------------------------- 1 | export default function noop() {} 2 | -------------------------------------------------------------------------------- /utils/bc0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/utils/bc0.ts -------------------------------------------------------------------------------- /test/segments/subtitles.vtt: -------------------------------------------------------------------------------- 1 | WEBVTT 2 | 3 | 00:01.466 --> 00:01.480 4 | Test subtitle 5 | -------------------------------------------------------------------------------- /utils/bipbop0.flv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/utils/bipbop0.flv -------------------------------------------------------------------------------- /utils/bipbop0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/utils/bipbop0.ts -------------------------------------------------------------------------------- /utils/bipbop1.flv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/utils/bipbop1.flv -------------------------------------------------------------------------------- /utils/bipbop1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/utils/bipbop1.ts -------------------------------------------------------------------------------- /test/segments/id3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/id3.ts -------------------------------------------------------------------------------- /test/segments/audio.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/audio.ts -------------------------------------------------------------------------------- /test/segments/muxed.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/muxed.ts -------------------------------------------------------------------------------- /test/segments/sidx.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/sidx.mp4 -------------------------------------------------------------------------------- /test/segments/video.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/video.ts -------------------------------------------------------------------------------- /test/segments/caption.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/caption.ts -------------------------------------------------------------------------------- /docs/images/containers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/containers.png -------------------------------------------------------------------------------- /docs/images/hls-format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/hls-format.png -------------------------------------------------------------------------------- /test/segments/encrypted.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/encrypted.ts -------------------------------------------------------------------------------- /test/segments/mp4Audio.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4Audio.mp4 -------------------------------------------------------------------------------- /test/segments/mp4Muxed.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4Muxed.mp4 -------------------------------------------------------------------------------- /test/segments/mp4Video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4Video.mp4 -------------------------------------------------------------------------------- /test/segments/mp4WebVtt.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4WebVtt.mp4 -------------------------------------------------------------------------------- /test/segments/oneSecond.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/oneSecond.ts -------------------------------------------------------------------------------- /test/segments/zeroLength.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/zeroLength.ts -------------------------------------------------------------------------------- /docs/images/mp2t-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/mp2t-structure.png -------------------------------------------------------------------------------- /test/segments/aacWithId3.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/aacWithId3.aac -------------------------------------------------------------------------------- /test/segments/ac3WithId3.ac3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/ac3WithId3.ac3 -------------------------------------------------------------------------------- /test/segments/mp4AudioInit.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4AudioInit.mp4 -------------------------------------------------------------------------------- /test/segments/mp4Captions.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4Captions.mp4 -------------------------------------------------------------------------------- /test/segments/mp4MuxedInit.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4MuxedInit.mp4 -------------------------------------------------------------------------------- /test/segments/mp4VideoInit.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4VideoInit.mp4 -------------------------------------------------------------------------------- /test/segments/webmVideo.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/webmVideo.webm -------------------------------------------------------------------------------- /test/segments/aacWithoutId3.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/aacWithoutId3.aac -------------------------------------------------------------------------------- /test/segments/ac3WithoutId3.ac3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/ac3WithoutId3.ac3 -------------------------------------------------------------------------------- /test/segments/audioMaxOffset.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/audioMaxOffset.ts -------------------------------------------------------------------------------- /test/segments/audioMinOffset.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/audioMinOffset.ts -------------------------------------------------------------------------------- /test/segments/encryptionKey.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/encryptionKey.key -------------------------------------------------------------------------------- /test/segments/mp4WebVttInit.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/mp4WebVttInit.mp4 -------------------------------------------------------------------------------- /test/segments/videoDiffPtsDts.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoDiffPtsDts.ts -------------------------------------------------------------------------------- /test/segments/videoMaxOffset.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoMaxOffset.ts -------------------------------------------------------------------------------- /test/segments/videoMinOffset.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoMinOffset.ts -------------------------------------------------------------------------------- /test/segments/videoOneSecond.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoOneSecond.ts -------------------------------------------------------------------------------- /test/segments/videoOneSecond1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoOneSecond1.ts -------------------------------------------------------------------------------- /test/segments/videoOneSecond2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoOneSecond2.ts -------------------------------------------------------------------------------- /test/segments/videoOneSecond3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoOneSecond3.ts -------------------------------------------------------------------------------- /test/segments/videoOneSecond4.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoOneSecond4.ts -------------------------------------------------------------------------------- /test/segments/webmVideoInit.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/webmVideoInit.webm -------------------------------------------------------------------------------- /docs/images/bitrate-switching-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/bitrate-switching-1.png -------------------------------------------------------------------------------- /docs/images/bitrate-switching-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/bitrate-switching-2.png -------------------------------------------------------------------------------- /docs/images/bitrate-switching-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/bitrate-switching-3.png -------------------------------------------------------------------------------- /docs/images/bitrate-switching-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/bitrate-switching-4.png -------------------------------------------------------------------------------- /docs/images/mp2t-packet-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/mp2t-packet-types.png -------------------------------------------------------------------------------- /docs/lhls/current-flow.plantuml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/lhls/current-flow.plantuml.png -------------------------------------------------------------------------------- /test/segments/audioLargeOffset.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/audioLargeOffset.ts -------------------------------------------------------------------------------- /test/segments/audioLargeOffset2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/audioLargeOffset2.ts -------------------------------------------------------------------------------- /test/segments/videoLargeOffset.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoLargeOffset.ts -------------------------------------------------------------------------------- /test/segments/videoLargeOffset2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/videoLargeOffset2.ts -------------------------------------------------------------------------------- /docs/images/segment-loader-states.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/segment-loader-states.png -------------------------------------------------------------------------------- /docs/lhls/expected-flow.plantuml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/lhls/expected-flow.plantuml.png -------------------------------------------------------------------------------- /test/manifests/missingEndlist.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:10 3 | #EXTINF:10, 4 | 00001.ts 5 | #EXTINF:10, 6 | 00002.ts 7 | -------------------------------------------------------------------------------- /test/segments/subtitlesEncrypted.vtt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/test/segments/subtitlesEncrypted.vtt -------------------------------------------------------------------------------- /docs/images/sources/containers.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/containers.graffle -------------------------------------------------------------------------------- /docs/images/sources/hls-format.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/hls-format.graffle -------------------------------------------------------------------------------- /docs/images/sources/mp2t-structure.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/mp2t-structure.graffle -------------------------------------------------------------------------------- /docs/images/sources/mp2t-packet-types.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/mp2t-packet-types.graffle -------------------------------------------------------------------------------- /docs/images/sources/bitrate-switching-1.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/bitrate-switching-1.graffle -------------------------------------------------------------------------------- /docs/images/sources/bitrate-switching-2.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/bitrate-switching-2.graffle -------------------------------------------------------------------------------- /docs/images/sources/bitrate-switching-3.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/bitrate-switching-3.graffle -------------------------------------------------------------------------------- /docs/images/sources/bitrate-switching-4.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/sources/bitrate-switching-4.graffle -------------------------------------------------------------------------------- /docs/lhls/new-segment-loader-sequence.plantuml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/lhls/new-segment-loader-sequence.plantuml.png -------------------------------------------------------------------------------- /docs/images/playlist-loader-pc-mg-sequence.puml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/playlist-loader-pc-mg-sequence.puml.png -------------------------------------------------------------------------------- /docs/lhls/current-transmux-and-append-flow.plantuml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/lhls/current-transmux-and-append-flow.plantuml.png -------------------------------------------------------------------------------- /test/manifests/multipleTargetDurations.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | 001.ts 3 | #EXT-X-TARGETDURATION:9 4 | 002.ts 5 | #EXTINF:7 6 | 003.ts 7 | #EXT-X-TARGETDURATION:10 8 | 004.ts -------------------------------------------------------------------------------- /docs/images/dash-playlist-loader-pc-mg-sequence.puml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/http-streaming/HEAD/docs/images/dash-playlist-loader-pc-mg-sequence.puml.png -------------------------------------------------------------------------------- /test/manifests/manifestNoExtM3u.m3u8: -------------------------------------------------------------------------------- 1 | #ZEN-TOTAL-DURATION:10 2 | #EXT-X-TARGETDURATION:10 3 | #EXTINF:10, 4 | /test/ts-files/zencoder/gogo/00001.ts 5 | #EXT-X-ENDLIST 6 | -------------------------------------------------------------------------------- /test/manifests/one-rendition.m3u8: -------------------------------------------------------------------------------- 1 | # A simple main playlist with a single media playlist 2 | #EXTM3U 3 | #EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=396x224 4 | media.m3u8 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Intentionally left blank, so that npm does not ignore anything by default, 2 | # but relies on the package.json "files" array to explicitly define what ends 3 | # up in the package. 4 | -------------------------------------------------------------------------------- /test/manifests/streamInfInvalid.m3u8: -------------------------------------------------------------------------------- 1 | # A simple main playlist with multiple variant streams 2 | #EXTM3U 3 | #EXT-X-STREAM-INF:PROGRAM-ID=1 4 | media.m3u8 5 | #EXT-X-STREAM-INF: 6 | media1.m3u8 7 | -------------------------------------------------------------------------------- /test/manifests/manifestExtTTargetdurationNegative.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #ZEN-TOTAL-DURATION:50 3 | #EXT-X-TARGETDURATION:-10 4 | #EXTINF:10, 5 | /test/ts-files/zencoder/gogo/00001.ts 6 | #EXT-X-ENDLIST 7 | -------------------------------------------------------------------------------- /test/manifests/zeroDuration.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | 5 | #EXTINF:0, 6 | http://example.com/00001.ts 7 | #ZEN-TOTAL-DURATION:57.9911 8 | #EXT-X-ENDLIST 9 | -------------------------------------------------------------------------------- /test/manifests/versionInvalid.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:10 3 | #EXT-X-VERSION:NaN 4 | #EXT-X-MEDIA-SEQUENCE:0 5 | #EXT-X-PLAYLIST-TYPE:VOD 6 | #EXTINF:10, 7 | hls_450k_video.ts 8 | #EXT-X-ENDLIST 9 | -------------------------------------------------------------------------------- /test/manifests/zeroLength.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | #EXT-X-DISCONTINUITY 5 | #EXTINF:0, 6 | ../segments/zeroLength.ts 7 | #EXTINF:10, 8 | ../segments/muxed.ts 9 | #EXT-X-ENDLIST 10 | -------------------------------------------------------------------------------- /test/manifests/two-renditions.m3u8: -------------------------------------------------------------------------------- 1 | # A simple main playlist with 2 media playlists 2 | #EXTM3U 3 | #EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=396x224 4 | media.m3u8 5 | #EXT-X-STREAM-INF:BANDWIDTH=40000,RESOLUTION=396x224 6 | media1.m3u8 7 | -------------------------------------------------------------------------------- /src/util/to-title-case.js: -------------------------------------------------------------------------------- 1 | const toTitleCase = function(string) { 2 | if (typeof string !== 'string') { 3 | return string; 4 | } 5 | 6 | return string.replace(/./, (w) => w.toUpperCase()); 7 | }; 8 | 9 | export default toTitleCase; 10 | -------------------------------------------------------------------------------- /test/manifests/disallowCache.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:10 3 | #EXT-X-VERSION:4 4 | #EXT-X-ALLOW-CACHE:NO 5 | #EXT-X-MEDIA-SEQUENCE:0 6 | #EXT-X-PLAYLIST-TYPE:VOD 7 | #EXTINF:10, 8 | #EXT-X-BYTERANGE:522828@0 9 | hls_450k_video.ts 10 | #EXT-X-ENDLIST -------------------------------------------------------------------------------- /test/manifests/emptyAllowCache.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:10 3 | #EXT-X-VERSION:4 4 | #EXT-X-ALLOW-CACHE: 5 | #EXT-X-MEDIA-SEQUENCE:0 6 | #EXT-X-PLAYLIST-TYPE:VOD 7 | #EXTINF:10, 8 | #EXT-X-BYTERANGE:522828@0 9 | hls_450k_video.ts 10 | #EXT-X-ENDLIST -------------------------------------------------------------------------------- /test/manifests/subtitles.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:11 3 | #EXT-X-VERSION:3 4 | #EXT-X-MEDIA-SEQUENCE:0 5 | #EXT-X-PLAYLIST-TYPE:VOD 6 | #EXTINF:11, 7 | ./0.webvtt 8 | #EXTINF:10, 9 | ./1.webvtt 10 | #EXTINF:9, 11 | ./2.webvtt 12 | #EXT-X-ENDLIST 13 | -------------------------------------------------------------------------------- /test/manifests/invalidAllowCache.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:10 3 | #EXT-X-VERSION:4 4 | #EXT-X-ALLOW-CACHE:MAYBE 5 | #EXT-X-MEDIA-SEQUENCE:0 6 | #EXT-X-PLAYLIST-TYPE:VOD 7 | #EXTINF:10, 8 | #EXT-X-BYTERANGE:522828@0 9 | hls_450k_video.ts 10 | #EXT-X-ENDLIST -------------------------------------------------------------------------------- /test/manifests/startVod.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-START:TIME-OFFSET=10.3 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | media-00001.ts 6 | #EXTINF:10, 7 | media-00002.ts 8 | #EXTINF:10, 9 | media-00003.ts 10 | #EXTINF:10, 11 | media-00004.ts 12 | #EXT-X-ENDLIST 13 | -------------------------------------------------------------------------------- /test/manifests/allowCacheInvalid.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:10 3 | #EXT-X-VERSION:4 4 | #EXT-X-ALLOW-CACHE:0 5 | #EXT-X-MEDIA-SEQUENCE:0 6 | #EXT-X-PLAYLIST-TYPE:VOD 7 | #EXTINF:10, 8 | #EXT-X-BYTERANGE:522828@0 9 | hls_450k_video.ts 10 | #EXT-X-ENDLIST 11 | -------------------------------------------------------------------------------- /test/manifests/missingExtinf.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-TARGETDURATION:10 3 | #EXT-X-VERSION:3 4 | #EXT-X-MEDIA-SEQUENCE:0 5 | #EXT-X-PLAYLIST-TYPE:VOD 6 | #EXTINF:10 7 | hls_450k_video.ts 8 | hls_450k_video.ts 9 | #EXTINF:10, 10 | hls_450k_video.ts 11 | #EXT-X-ENDLIST 12 | -------------------------------------------------------------------------------- /test/manifests/startNegative.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-START:TIME-OFFSET=-5.0 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | media-00001.ts 6 | #EXTINF:10, 7 | media-00002.ts 8 | #EXTINF:10, 9 | media-00003.ts 10 | #EXTINF:10, 11 | media-00004.ts 12 | #EXT-X-ENDLIST 13 | -------------------------------------------------------------------------------- /docs/lhls/current-flow.plantuml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | state "Download Segment" as DL 4 | state "Prepare for Append" as PfA 5 | 6 | [*] -> DL 7 | DL -> PfA 8 | PfA : transmux (if needed) 9 | PfA -> Append 10 | Append : MSE source buffer 11 | Append -> [*] 12 | 13 | @enduml 14 | -------------------------------------------------------------------------------- /src/util/fn.js: -------------------------------------------------------------------------------- 1 | export const debounce = (callback, wait) => { 2 | let timeoutId = null; 3 | 4 | return (...args) => { 5 | clearTimeout(timeoutId); 6 | 7 | timeoutId = setTimeout(() => { 8 | callback.apply(null, args); 9 | }, wait); 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/util/logger.js: -------------------------------------------------------------------------------- 1 | import videojs from 'video.js'; 2 | 3 | const logger = (source) => { 4 | if (videojs.log.debug) { 5 | return videojs.log.debug.bind(videojs, 'VHS:', `${source} >`); 6 | } 7 | 8 | return function() {}; 9 | }; 10 | 11 | export default logger; 12 | -------------------------------------------------------------------------------- /test/manifests/playlistMediaSequenceHigher.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:17 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | #EXT-X-ENDLIST 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /test/manifests/demuxed.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:4 3 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="en",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="en",URI="audio.m3u8" 4 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=564300,CODECS="mp4a.40.2,avc1.420015",AUDIO="audio" 5 | video.m3u8 6 | 7 | -------------------------------------------------------------------------------- /test/manifests/domainUris.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | /00001.ts 6 | #EXTINF:10, 7 | /subdir/00002.ts 8 | #EXTINF:10, 9 | /00003.ts 10 | #EXTINF:10, 11 | /00004.ts 12 | #ZEN-TOTAL-DURATION:57.9911 13 | #EXT-X-ENDLIST 14 | -------------------------------------------------------------------------------- /test/manifests/extXPlaylistTypeInvalidPlaylist.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:STRING 3 | #EXT-X-MEDIA-SEQUENCE:1 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | #EXT-X-ENDLIST 9 | -------------------------------------------------------------------------------- /test/manifests/demuxed-two.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:4 3 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="en",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="en",URI="media.m3u8" 4 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=564300,CODECS="mp4a.40.2,avc1.420015",AUDIO="audio" 5 | media1.m3u8 6 | 7 | -------------------------------------------------------------------------------- /src/util/string-to-array-buffer.js: -------------------------------------------------------------------------------- 1 | export const stringToArrayBuffer = (string) => { 2 | const view = new Uint8Array(new ArrayBuffer(string.length)); 3 | 4 | for (let i = 0; i < string.length; i++) { 5 | view[i] = string.charCodeAt(i); 6 | } 7 | 8 | return view.buffer; 9 | }; 10 | -------------------------------------------------------------------------------- /test/manifests/media.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | media-00001.ts 6 | #EXTINF:10, 7 | media-00002.ts 8 | #EXTINF:10, 9 | media-00003.ts 10 | #EXTINF:10, 11 | media-00004.ts 12 | #ZEN-TOTAL-DURATION:57.9911 13 | #EXT-X-ENDLIST 14 | -------------------------------------------------------------------------------- /test/manifests/media1.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | media1-00001.ts 6 | #EXTINF:10, 7 | media1-00002.ts 8 | #EXTINF:10, 9 | media1-00003.ts 10 | #EXTINF:10, 11 | media1-00004.ts 12 | #ZEN-TOTAL-DURATION:57.9911 13 | #EXT-X-ENDLIST 14 | -------------------------------------------------------------------------------- /test/manifests/media2.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | media2-00001.ts 6 | #EXTINF:10, 7 | media2-00002.ts 8 | #EXTINF:10, 9 | media2-00003.ts 10 | #EXTINF:10, 11 | media2-00004.ts 12 | #ZEN-TOTAL-DURATION:57.9911 13 | #EXT-X-ENDLIST 14 | -------------------------------------------------------------------------------- /test/manifests/media3.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | media3-00001.ts 6 | #EXTINF:10, 7 | media3-00002.ts 8 | #EXTINF:10, 9 | media3-00003.ts 10 | #EXTINF:10, 11 | media3-00004.ts 12 | #ZEN-TOTAL-DURATION:57.9911 13 | #EXT-X-ENDLIST 14 | -------------------------------------------------------------------------------- /test/manifests/startLive.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-START:TIME-OFFSET=0 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | media-00001.ts 6 | #EXTINF:10, 7 | media-00002.ts 8 | #EXTINF:10, 9 | media-00003.ts 10 | #EXTINF:10, 11 | media-00004.ts 12 | #EXTINF:10, 13 | media-00005.ts 14 | #EXTINF:10, 15 | media-00006.ts 16 | -------------------------------------------------------------------------------- /test/manifests/disc-sequence.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-TARGETDURATION:19 4 | #EXT-X-MEDIA-SEQUENCE:0 5 | #EXT-X-DISCONTINUITY-SEQUENCE:3 6 | #EXTINF:10,0 7 | 001.ts 8 | #EXTINF:19,0 9 | 002.ts 10 | #EXT-X-DISCONTINUITY 11 | #EXTINF:10,0 12 | 003.ts 13 | #EXTINF:11,0 14 | 004.ts 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /src/util/string.js: -------------------------------------------------------------------------------- 1 | export const uint8ToUtf8 = (uintArray) => 2 | decodeURIComponent(escape(String.fromCharCode.apply(null, uintArray))); 3 | 4 | export const bufferToHexString = (buffer) => { 5 | const uInt8Buffer = new Uint8Array(buffer); 6 | 7 | return Array.from(uInt8Buffer).map((byte) => byte.toString(16).padStart(2, '0')).join(''); 8 | }; 9 | -------------------------------------------------------------------------------- /test/manifests/absoluteUris.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | http://example.com/00001.ts 6 | #EXTINF:10, 7 | https://example.com/00002.ts 8 | #EXTINF:10, 9 | //example.com/00003.ts 10 | #EXTINF:10, 11 | http://example.com/00004.ts 12 | #ZEN-TOTAL-DURATION:57.9911 13 | #EXT-X-ENDLIST 14 | -------------------------------------------------------------------------------- /test/manifests/whiteSpace.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-TARGETDURATION:10 4 | 5 | #EXTINF:10, 6 | http://example.com/00001.ts 7 | #EXTINF:10, 8 | https://example.com/00002.ts 9 | #EXTINF:10, 10 | //example.com/00003.ts 11 | #EXTINF:10, 12 | http://example.com/00004.ts 13 | #ZEN-TOTAL-DURATION:57.9911 14 | #EXT-X-ENDLIST 15 | -------------------------------------------------------------------------------- /test/util/string.test.js: -------------------------------------------------------------------------------- 1 | import QUnit from 'qunit'; 2 | import { uint8ToUtf8 } from '../../src/util/string'; 3 | 4 | QUnit.module('uint8ToUtf8'); 5 | 6 | QUnit.test('converts beyond Latin-1 characters', function(assert) { 7 | const expected = 'シ'; 8 | const actual = uint8ToUtf8(new Uint8Array([227, 130, 183])); 9 | 10 | assert.deepEqual(actual, expected); 11 | }); 12 | -------------------------------------------------------------------------------- /test/manifests/liveStart30sBefore.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-MEDIA-SEQUENCE:0 3 | #EXT-X-ALLOW-CACHE:YES 4 | #EXT-X-TARGETDURATION:10 5 | #EXTINF:10,0 6 | 001.ts 7 | #EXTINF:19,0 8 | 002.ts 9 | #EXTINF:10,0 10 | 003.ts 11 | #EXTINF:11,0 12 | 004.ts 13 | #EXTINF:10,0 14 | 005.ts 15 | #EXTINF:10,0 16 | 006.ts 17 | #EXTINF:10,0 18 | 007.ts 19 | #EXTINF:10,0 20 | 008.ts 21 | #EXTINF:16,0 22 | 009.ts -------------------------------------------------------------------------------- /test/manifests/liveMissingSegmentDuration.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 9 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 10 | -------------------------------------------------------------------------------- /test/manifests/main.m3u8: -------------------------------------------------------------------------------- 1 | # A simple main playlist with multiple variant streams 2 | #EXTM3U 3 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=240000,RESOLUTION=396x224 4 | media.m3u8 5 | #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=40000 6 | media1.m3u8 7 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=440000,RESOLUTION=396x224 8 | media2.m3u8 9 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1928000,RESOLUTION=960x540 10 | media3.m3u8 11 | -------------------------------------------------------------------------------- /test/manifests/manifestExtXEndlistEarly.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #ZEN-TOTAL-DURATION:50 3 | #EXT-X-TARGETDURATION:10 4 | #EXTINF:10, 5 | /test/ts-files/zencoder/gogo/00001.ts 6 | #EXTINF:10, 7 | /test/ts-files/zencoder/gogo/00002.ts 8 | #EXTINF:10, 9 | /test/ts-files/zencoder/gogo/00003.ts 10 | #EXT-X-ENDLIST 11 | #EXTINF:10, 12 | /test/ts-files/zencoder/gogo/00004.ts 13 | #EXTINF:10, 14 | /test/ts-files/zencoder/gogo/00005.ts 15 | 16 | -------------------------------------------------------------------------------- /test/manifests/discontinuity.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-TARGETDURATION:19 4 | #EXT-X-MEDIA-SEQUENCE:0 5 | #EXTINF:10,0 6 | 001.ts 7 | #EXTINF:19,0 8 | 002.ts 9 | #EXT-X-DISCONTINUITY 10 | #EXTINF:10,0 11 | 003.ts 12 | #EXTINF:11,0 13 | 004.ts 14 | #EXT-X-DISCONTINUITY 15 | #EXTINF:10,0 16 | 005.ts 17 | #EXTINF:10,0 18 | 006.ts 19 | #EXTINF:10,0 20 | 007.ts 21 | #EXT-X-DISCONTINUITY 22 | #EXTINF:10,0 23 | 008.ts 24 | #EXTINF:16,0 25 | 009.ts 26 | #EXT-X-ENDLIST 27 | -------------------------------------------------------------------------------- /test/manifests/missingSegmentDuration.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 9 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 10 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 11 | #EXT-X-ENDLIST 12 | -------------------------------------------------------------------------------- /test/manifests/audioOnlyAlternateAudio.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="eng",NAME="English",AUTOSELECT=YES, DEFAULT=YES 3 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="fre",NAME="Français",AUTOSELECT=YES, DEFAULT=NO,URI="fre/prog_index.m3u8" 4 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="sp",NAME="Espanol",AUTOSELECT=YES, DEFAULT=NO,URI="sp/prog_index.m3u8" 5 | 6 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=195023,CODECS="mp4a.40.2",AUDIO="audio" 7 | eng/prog_index.m3u8 8 | -------------------------------------------------------------------------------- /test/manifests/program-date-time.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-TARGETDURATION:4 4 | #EXT-X-MEDIA-SEQUENCE:0 5 | 6 | #EXT-X-PROGRAM-DATE-TIME:2018-10-12T22:33:49.037+00:00 7 | #EXTINF:2.0, 8 | media-00001.ts 9 | #EXT-X-PROGRAM-DATE-TIME:2018-10-12T22:33:52.037+00:00 10 | #EXTINF:2.0, 11 | media-00002.ts 12 | #EXT-X-PROGRAM-DATE-TIME:2018-10-12T22:33:57.037+00:00 13 | #EXTINF:2.0, 14 | media-00003.ts 15 | #EXT-X-PROGRAM-DATE-TIME:2018-10-12T22:34:00.037+00:00 16 | #EXTINF:2.0, 17 | media-00004.ts 18 | -------------------------------------------------------------------------------- /docs/images/sources/dash-playlist-loader-states.nomnoml.txt: -------------------------------------------------------------------------------- 1 | #title: DASH Playlist Loader States 2 | #arrowSize: 0.5 3 | #bendSize: 1 4 | #direction: down 5 | #gutter: 10 6 | #edgeMargin: 1 7 | #edges: rounded 8 | #fillArrows: false 9 | #font: Arial 10 | #fontSize: 10 11 | #leading: 1 12 | #lineWidth: 2 13 | #padding: 20 14 | #spacing: 50 15 | #stroke: #33322E 16 | #zoom: 1 17 | 18 | #.label: align=center visual=none italic 19 | 20 | [HAVE_NOTHING] load()-> [HAVE_MAIN_MANIFEST] 21 | [HAVE_MAIN_MANIFEST] media()-> [HAVE_METADATA] 22 | -------------------------------------------------------------------------------- /test/manifests/missingMediaSequence.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-ALLOW-CACHE:YES 4 | #EXT-X-TARGETDURATION:8 5 | #EXTINF:6.640,{} 6 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 7 | #EXTINF:6.080,{} 8 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 9 | #EXTINF:6.600,{} 10 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 11 | #EXTINF:5.000,{} 12 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 13 | #EXT-X-ENDLIST 14 | -------------------------------------------------------------------------------- /test/manifests/mediaSequence.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | #EXTINF:6.080,{} 9 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 10 | #EXTINF:6.600,{} 11 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 12 | #EXTINF:5.000,{} 13 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 14 | #EXT-X-ENDLIST 15 | -------------------------------------------------------------------------------- /test/manifests/emptyMediaSequence.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE: 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | #EXTINF:6.080,{} 9 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 10 | #EXTINF:6.600,{} 11 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 12 | #EXTINF:5.000,{} 13 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 14 | #EXT-X-ENDLIST 15 | -------------------------------------------------------------------------------- /test/manifests/negativeMediaSequence.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:-11 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | #EXTINF:6.080,{} 9 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 10 | #EXTINF:6.600,{} 11 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 12 | #EXTINF:5.000,{} 13 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 14 | #EXT-X-ENDLIST 15 | -------------------------------------------------------------------------------- /test/manifests/invalidMediaSequence.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:gobblegobble 4 | #EXT-X-ALLOW-CACHE:YES 5 | #EXT-X-TARGETDURATION:8 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | #EXTINF:6.080,{} 9 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 10 | #EXTINF:6.600,{} 11 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 12 | #EXTINF:5.000,{} 13 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 14 | #EXT-X-ENDLIST 15 | -------------------------------------------------------------------------------- /.github/move.yml: -------------------------------------------------------------------------------- 1 | # Configuration for move-issues - https://github.com/dessant/move-issues 2 | 3 | # Delete the command comment when it contains no other content 4 | deleteCommand: true 5 | 6 | # Close the source issue after moving 7 | closeSourceIssue: true 8 | 9 | # Lock the source issue after moving 10 | lockSourceIssue: false 11 | 12 | # Mention issue and comment authors 13 | mentionAuthors: false 14 | 15 | # Preserve mentions in the issue content 16 | keepContentMentions: false 17 | 18 | # Set custom aliases for targets 19 | # aliases: 20 | # r: repo 21 | # or: owner/repo 22 | -------------------------------------------------------------------------------- /test/manifests/twoMediaSequences.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-MEDIA-SEQUENCE:11 5 | #EXT-X-ALLOW-CACHE:YES 6 | #EXT-X-TARGETDURATION:8 7 | #EXTINF:6.640,{} 8 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 9 | #EXTINF:6.080,{} 10 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 11 | #EXTINF:6.600,{} 12 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 13 | #EXTINF:5.000,{} 14 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /test/manifests/playlist_target_duration_template.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-ALLOW-CACHE:YES 5 | {{#if targetDuration}}#EXT-X-TARGETDURATION:{{{targetDuration}}}{{/if}} 6 | #EXTINF:6.640,{} 7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 8 | #EXTINF:6.080,{} 9 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 10 | #EXTINF:6.600,{} 11 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 12 | #EXTINF:5.000,{} 13 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 14 | #EXT-X-ENDLIST 15 | -------------------------------------------------------------------------------- /test/manifests/alternateVideo.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="500kbs",NAME="Angle1",AUTOSELECT=YES,DEFAULT=YES 3 | #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="500kbs",NAME="Angle2",AUTOSELECT=YES,DEFAULT=NO,URI="Angle2/500kbs/prog_index.m3u8" 4 | #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="500kbs",NAME="Angle3",AUTOSELECT=YES,DEFAULT=NO,URI="Angle3/500kbs/prog_index.m3u8" 5 | 6 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",LANGUAGE="eng",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="eng/prog_index.m3u8" 7 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=754857,CODECS="mp4a.40.2,avc1.4d401e",VIDEO="500kbs",AUDIO="aac" 8 | Angle1/500kbs/prog_index.m3u8 -------------------------------------------------------------------------------- /docs/lhls/expected-flow.plantuml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | state "Request Segment" as RS 4 | state "Partial Response (1)" as PR1 5 | state "..." as DDD 6 | state "Partial Response (n)" as PRN 7 | state "Prepare for Append (1)" as PfA1 8 | state "Prepare for Append (n)" as PfAN 9 | state "Append (1)" as A1 10 | state "Append (n)" as AN 11 | 12 | [*] -> RS 13 | 14 | RS --> PR1 15 | PR1 --> DDD 16 | DDD --> PRN 17 | 18 | PR1 -> PfA1 19 | PfA1 : transmux (if needed) 20 | PfA1 -> A1 21 | A1 : MSE source buffer 22 | PRN -> PfAN 23 | PfAN : transmux (if needed) 24 | PfAN -> AN 25 | AN : MSE source buffer 26 | 27 | AN --> [*] 28 | 29 | @enduml 30 | -------------------------------------------------------------------------------- /test/custom-assertions.js: -------------------------------------------------------------------------------- 1 | import QUnit from 'qunit'; 2 | import { timeRangesToArray } from '../src/ranges'; 3 | 4 | // 1% 5 | const BANDWIDTH_TOLERANCE = 0.01; 6 | 7 | export const timeRangesEqual = function(timeRange1, timeRange2, message) { 8 | QUnit.assert.deepEqual(timeRangesToArray(timeRange1), timeRangesToArray(timeRange2), message); 9 | }; 10 | 11 | export const bandwidthWithinTolerance = function(actual, expected, message) { 12 | QUnit.assert.ok( 13 | Math.abs(actual - expected) < (expected * BANDWIDTH_TOLERANCE), 14 | `${message}: expected ${actual} to be within ${BANDWIDTH_TOLERANCE} of ${expected}` 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /test/manifests/alternateAudio.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="eng",NAME="English",AUTOSELECT=YES, DEFAULT=YES,URI="eng/prog_index.m3u8" 3 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="fre",NAME="Français",AUTOSELECT=YES, DEFAULT=NO,URI="fre/prog_index.m3u8" 4 | #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="sp",NAME="Espanol",AUTOSELECT=YES, DEFAULT=NO,URI="sp/prog_index.m3u8" 5 | 6 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=195023,CODECS="avc1.42e00a,mp4a.40.2",AUDIO="audio" 7 | lo/prog_index.m3u8 8 | #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=591680,CODECS="avc1.42e01e,mp4a.40.2",AUDIO="audio" 9 | hi/prog_index.m3u8 -------------------------------------------------------------------------------- /utils/switcher/network_logs/README.md: -------------------------------------------------------------------------------- 1 | Sources from http://skuld.cs.umass.edu/traces/mmsys/2013/pathbandwidth/: 2 | - car.snaroya-smestad.txt - http://skuld.cs.umass.edu/traces/mmsys/2013/pathbandwidth/car.snaroya-smestad/report.2011-02-14_2139CET.log 3 | - bus.ljansbakken-oslo.txt - http://skuld.cs.umass.edu/traces/mmsys/2013/pathbandwidth/bus.ljansbakken-oslo/report.2011-01-31_1025CET.log 4 | - train.vestby-oslo.txt - http://skuld.cs.umass.edu/traces/mmsys/2013/pathbandwidth/train.vestby-oslo/report.2011-02-14_1728CET.log 5 | - ferry.nesoddtangen-oslo.txt - http://skuld.cs.umass.edu/traces/mmsys/2013/pathbandwidth/ferry.nesoddtangen-oslo/report.2011-02-01_1639CET.log -------------------------------------------------------------------------------- /test/util/logger.test.js: -------------------------------------------------------------------------------- 1 | import QUnit from 'qunit'; 2 | import videojs from 'video.js'; 3 | import logger from '../../src/util/logger'; 4 | 5 | QUnit.test('Logger includes source', function(assert) { 6 | const source = 'testsource'; 7 | const originalLogDebug = videojs.log.debug; 8 | let msg; 9 | 10 | videojs.log.debug = (...args) => { 11 | msg = args.join(' '); 12 | }; 13 | 14 | const logger_ = logger(source); 15 | 16 | logger_('test'); 17 | 18 | assert.strictEqual( 19 | msg, 20 | `VHS: ${source} > test`, 21 | 'log message includes the source' 22 | ); 23 | 24 | // Reset 25 | videojs.log.debug = originalLogDebug; 26 | }); 27 | -------------------------------------------------------------------------------- /test/manifests/playlist_media_sequence_template.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-PLAYLIST-TYPE:VOD 3 | {{#if mediaSequence}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence}}}{{/if}} 4 | {{#if mediaSequence1}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence2}}}{{/if}} 5 | #EXT-X-ALLOW-CACHE:YES 6 | #EXT-X-TARGETDURATION:8 7 | #EXTINF:6.640,{} 8 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts 9 | #EXTINF:6.080,{} 10 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts 11 | #EXTINF:6.600,{} 12 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts 13 | #EXTINF:5.000,{} 14 | /test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /docs/images/sources/playlist-loader-states.nomnoml.txt: -------------------------------------------------------------------------------- 1 | #title: Playlist Loader States 2 | #arrowSize: 0.5 3 | #bendSize: 1 4 | #direction: down 5 | #gutter: 10 6 | #edgeMargin: 1 7 | #edges: rounded 8 | #fillArrows: false 9 | #font: Arial 10 | #fontSize: 10 11 | #leading: 1 12 | #lineWidth: 2 13 | #padding: 20 14 | #spacing: 50 15 | #stroke: #33322E 16 | #zoom: 1 17 | 18 | #.label: align=center visual=none italic 19 | 20 | [HAVE_NOTHING] load()-> [HAVE_MAIN_MANIFEST] 21 | [HAVE_MAIN_MANIFEST] media()-> [SWITCHING_MEDIA] 22 | [SWITCHING_MEDIA] media()/ start()-> [HAVE_METADATA] 23 | 24 | [HAVE_METADATA] <--> [