@zenvor/hls.js 1.0.0
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/LICENSE +28 -0
- package/README.md +472 -0
- package/dist/hls-demo.js +26995 -0
- package/dist/hls-demo.js.map +1 -0
- package/dist/hls.d.mts +4204 -0
- package/dist/hls.d.ts +4204 -0
- package/dist/hls.js +40050 -0
- package/dist/hls.js.d.ts +4204 -0
- package/dist/hls.js.map +1 -0
- package/dist/hls.light.js +27145 -0
- package/dist/hls.light.js.map +1 -0
- package/dist/hls.light.min.js +2 -0
- package/dist/hls.light.min.js.map +1 -0
- package/dist/hls.light.mjs +26392 -0
- package/dist/hls.light.mjs.map +1 -0
- package/dist/hls.min.js +2 -0
- package/dist/hls.min.js.map +1 -0
- package/dist/hls.mjs +38956 -0
- package/dist/hls.mjs.map +1 -0
- package/dist/hls.worker.js +2 -0
- package/dist/hls.worker.js.map +1 -0
- package/package.json +143 -0
- package/src/config.ts +794 -0
- package/src/controller/abr-controller.ts +1019 -0
- package/src/controller/algo-data-controller.ts +794 -0
- package/src/controller/audio-stream-controller.ts +1099 -0
- package/src/controller/audio-track-controller.ts +454 -0
- package/src/controller/base-playlist-controller.ts +438 -0
- package/src/controller/base-stream-controller.ts +2526 -0
- package/src/controller/buffer-controller.ts +2015 -0
- package/src/controller/buffer-operation-queue.ts +159 -0
- package/src/controller/cap-level-controller.ts +367 -0
- package/src/controller/cmcd-controller.ts +422 -0
- package/src/controller/content-steering-controller.ts +622 -0
- package/src/controller/eme-controller.ts +1617 -0
- package/src/controller/error-controller.ts +627 -0
- package/src/controller/fps-controller.ts +146 -0
- package/src/controller/fragment-finders.ts +256 -0
- package/src/controller/fragment-tracker.ts +567 -0
- package/src/controller/gap-controller.ts +719 -0
- package/src/controller/id3-track-controller.ts +488 -0
- package/src/controller/interstitial-player.ts +302 -0
- package/src/controller/interstitials-controller.ts +2895 -0
- package/src/controller/interstitials-schedule.ts +698 -0
- package/src/controller/latency-controller.ts +294 -0
- package/src/controller/level-controller.ts +776 -0
- package/src/controller/stream-controller.ts +1597 -0
- package/src/controller/subtitle-stream-controller.ts +508 -0
- package/src/controller/subtitle-track-controller.ts +617 -0
- package/src/controller/timeline-controller.ts +677 -0
- package/src/crypt/aes-crypto.ts +36 -0
- package/src/crypt/aes-decryptor.ts +339 -0
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +225 -0
- package/src/crypt/fast-aes-key.ts +39 -0
- package/src/define-plugin.d.ts +17 -0
- package/src/demux/audio/aacdemuxer.ts +126 -0
- package/src/demux/audio/ac3-demuxer.ts +170 -0
- package/src/demux/audio/adts.ts +249 -0
- package/src/demux/audio/base-audio-demuxer.ts +205 -0
- package/src/demux/audio/dolby.ts +21 -0
- package/src/demux/audio/mp3demuxer.ts +85 -0
- package/src/demux/audio/mpegaudio.ts +177 -0
- package/src/demux/chunk-cache.ts +42 -0
- package/src/demux/dummy-demuxed-track.ts +13 -0
- package/src/demux/inject-worker.ts +75 -0
- package/src/demux/mp4demuxer.ts +234 -0
- package/src/demux/sample-aes.ts +198 -0
- package/src/demux/transmuxer-interface.ts +449 -0
- package/src/demux/transmuxer-worker.ts +221 -0
- package/src/demux/transmuxer.ts +560 -0
- package/src/demux/tsdemuxer.ts +1256 -0
- package/src/demux/video/avc-video-parser.ts +401 -0
- package/src/demux/video/base-video-parser.ts +198 -0
- package/src/demux/video/exp-golomb.ts +153 -0
- package/src/demux/video/hevc-video-parser.ts +736 -0
- package/src/empty-es.js +5 -0
- package/src/empty.js +3 -0
- package/src/errors.ts +107 -0
- package/src/events.ts +548 -0
- package/src/exports-default.ts +3 -0
- package/src/exports-named.ts +81 -0
- package/src/hls.ts +1613 -0
- package/src/is-supported.ts +54 -0
- package/src/loader/date-range.ts +207 -0
- package/src/loader/fragment-loader.ts +403 -0
- package/src/loader/fragment.ts +487 -0
- package/src/loader/interstitial-asset-list.ts +162 -0
- package/src/loader/interstitial-event.ts +337 -0
- package/src/loader/key-loader.ts +439 -0
- package/src/loader/level-details.ts +203 -0
- package/src/loader/level-key.ts +259 -0
- package/src/loader/load-stats.ts +17 -0
- package/src/loader/m3u8-parser.ts +1072 -0
- package/src/loader/playlist-loader.ts +839 -0
- package/src/polyfills/number.ts +15 -0
- package/src/remux/aac-helper.ts +81 -0
- package/src/remux/mp4-generator.ts +1380 -0
- package/src/remux/mp4-remuxer.ts +1261 -0
- package/src/remux/passthrough-remuxer.ts +434 -0
- package/src/task-loop.ts +130 -0
- package/src/types/algo.ts +44 -0
- package/src/types/buffer.ts +105 -0
- package/src/types/component-api.ts +20 -0
- package/src/types/demuxer.ts +208 -0
- package/src/types/events.ts +574 -0
- package/src/types/fragment-tracker.ts +23 -0
- package/src/types/level.ts +268 -0
- package/src/types/loader.ts +198 -0
- package/src/types/media-playlist.ts +92 -0
- package/src/types/network-details.ts +3 -0
- package/src/types/remuxer.ts +104 -0
- package/src/types/track.ts +12 -0
- package/src/types/transmuxer.ts +46 -0
- package/src/types/tuples.ts +6 -0
- package/src/types/vtt.ts +11 -0
- package/src/utils/arrays.ts +22 -0
- package/src/utils/attr-list.ts +192 -0
- package/src/utils/binary-search.ts +46 -0
- package/src/utils/buffer-helper.ts +173 -0
- package/src/utils/cea-608-parser.ts +1413 -0
- package/src/utils/chunker.ts +41 -0
- package/src/utils/codecs.ts +314 -0
- package/src/utils/cues.ts +96 -0
- package/src/utils/discontinuities.ts +174 -0
- package/src/utils/encryption-methods-util.ts +21 -0
- package/src/utils/error-helper.ts +95 -0
- package/src/utils/event-listener-helper.ts +16 -0
- package/src/utils/ewma-bandwidth-estimator.ts +97 -0
- package/src/utils/ewma.ts +43 -0
- package/src/utils/fetch-loader.ts +331 -0
- package/src/utils/global.ts +2 -0
- package/src/utils/hash.ts +10 -0
- package/src/utils/hdr.ts +67 -0
- package/src/utils/hex.ts +32 -0
- package/src/utils/imsc1-ttml-parser.ts +261 -0
- package/src/utils/keysystem-util.ts +45 -0
- package/src/utils/level-helper.ts +629 -0
- package/src/utils/logger.ts +120 -0
- package/src/utils/media-option-attributes.ts +49 -0
- package/src/utils/mediacapabilities-helper.ts +301 -0
- package/src/utils/mediakeys-helper.ts +210 -0
- package/src/utils/mediasource-helper.ts +37 -0
- package/src/utils/mp4-tools.ts +1473 -0
- package/src/utils/number.ts +3 -0
- package/src/utils/numeric-encoding-utils.ts +26 -0
- package/src/utils/output-filter.ts +46 -0
- package/src/utils/rendition-helper.ts +505 -0
- package/src/utils/safe-json-stringify.ts +22 -0
- package/src/utils/texttrack-utils.ts +164 -0
- package/src/utils/time-ranges.ts +17 -0
- package/src/utils/timescale-conversion.ts +46 -0
- package/src/utils/utf8-utils.ts +18 -0
- package/src/utils/variable-substitution.ts +105 -0
- package/src/utils/vttcue.ts +384 -0
- package/src/utils/vttparser.ts +497 -0
- package/src/utils/webvtt-parser.ts +166 -0
- package/src/utils/xhr-loader.ts +337 -0
- package/src/version.ts +1 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type { MediaPlaylist } from './media-playlist';
|
|
2
|
+
import type { LevelDetails } from '../loader/level-details';
|
|
3
|
+
import type { AttrList } from '../utils/attr-list';
|
|
4
|
+
import type { MediaDecodingInfo } from '../utils/mediacapabilities-helper';
|
|
5
|
+
|
|
6
|
+
export interface LevelParsed extends CodecsParsed {
|
|
7
|
+
attrs: LevelAttributes;
|
|
8
|
+
bitrate: number;
|
|
9
|
+
details?: LevelDetails;
|
|
10
|
+
height?: number;
|
|
11
|
+
id?: number;
|
|
12
|
+
name: string;
|
|
13
|
+
supplemental?: CodecsParsed;
|
|
14
|
+
url: string;
|
|
15
|
+
width?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CodecsParsed {
|
|
19
|
+
audioCodec?: string;
|
|
20
|
+
videoCodec?: string;
|
|
21
|
+
textCodec?: string;
|
|
22
|
+
unknownCodecs?: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface LevelAttributes extends AttrList {
|
|
26
|
+
'ALLOWED-CPC'?: string;
|
|
27
|
+
AUDIO?: string;
|
|
28
|
+
'AVERAGE-BANDWIDTH'?: string;
|
|
29
|
+
BANDWIDTH?: string;
|
|
30
|
+
'CLOSED-CAPTIONS'?: string;
|
|
31
|
+
CODECS?: string;
|
|
32
|
+
'FRAME-RATE'?: string;
|
|
33
|
+
'HDCP-LEVEL'?: 'TYPE-0' | 'TYPE-1' | 'NONE';
|
|
34
|
+
'PATHWAY-ID'?: string;
|
|
35
|
+
RESOLUTION?: string;
|
|
36
|
+
SCORE?: string;
|
|
37
|
+
'STABLE-VARIANT-ID'?: string;
|
|
38
|
+
SUBTITLES?: string;
|
|
39
|
+
'SUPPLEMENTAL-CODECS'?: string;
|
|
40
|
+
VIDEO?: string;
|
|
41
|
+
'VIDEO-RANGE'?: VideoRange;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const HdcpLevels = ['NONE', 'TYPE-0', 'TYPE-1', null] as const;
|
|
45
|
+
export type HdcpLevel = (typeof HdcpLevels)[number];
|
|
46
|
+
|
|
47
|
+
export function isHdcpLevel(value: any): value is HdcpLevel {
|
|
48
|
+
return HdcpLevels.indexOf(value) > -1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const VideoRangeValues = ['SDR', 'PQ', 'HLG'] as const;
|
|
52
|
+
export type VideoRange = (typeof VideoRangeValues)[number];
|
|
53
|
+
|
|
54
|
+
export function isVideoRange(value: any): value is VideoRange {
|
|
55
|
+
return !!value && VideoRangeValues.indexOf(value) > -1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type VariableMap = Record<string, string>;
|
|
59
|
+
|
|
60
|
+
export const enum HlsSkip {
|
|
61
|
+
No = '',
|
|
62
|
+
Yes = 'YES',
|
|
63
|
+
v2 = 'v2',
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getSkipValue(details: LevelDetails): HlsSkip {
|
|
67
|
+
const { canSkipUntil, canSkipDateRanges, age } = details;
|
|
68
|
+
// A Client SHOULD NOT request a Playlist Delta Update unless it already
|
|
69
|
+
// has a version of the Playlist that is no older than one-half of the Skip Boundary.
|
|
70
|
+
// @see: https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.3.7
|
|
71
|
+
const playlistRecentEnough = age < canSkipUntil / 2;
|
|
72
|
+
if (canSkipUntil && playlistRecentEnough) {
|
|
73
|
+
if (canSkipDateRanges) {
|
|
74
|
+
return HlsSkip.v2;
|
|
75
|
+
}
|
|
76
|
+
return HlsSkip.Yes;
|
|
77
|
+
}
|
|
78
|
+
return HlsSkip.No;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export class HlsUrlParameters {
|
|
82
|
+
msn?: number;
|
|
83
|
+
part?: number;
|
|
84
|
+
skip?: HlsSkip;
|
|
85
|
+
|
|
86
|
+
constructor(msn?: number, part?: number, skip?: HlsSkip) {
|
|
87
|
+
this.msn = msn;
|
|
88
|
+
this.part = part;
|
|
89
|
+
this.skip = skip;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
addDirectives(uri: string): string | never {
|
|
93
|
+
const url: URL = new self.URL(uri);
|
|
94
|
+
if (this.msn !== undefined) {
|
|
95
|
+
url.searchParams.set('_HLS_msn', this.msn.toString());
|
|
96
|
+
}
|
|
97
|
+
if (this.part !== undefined) {
|
|
98
|
+
url.searchParams.set('_HLS_part', this.part.toString());
|
|
99
|
+
}
|
|
100
|
+
if (this.skip) {
|
|
101
|
+
url.searchParams.set('_HLS_skip', this.skip);
|
|
102
|
+
}
|
|
103
|
+
return url.href;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export class Level {
|
|
108
|
+
public readonly _attrs: LevelAttributes[];
|
|
109
|
+
public readonly audioCodec: string | undefined;
|
|
110
|
+
public readonly bitrate: number;
|
|
111
|
+
public readonly codecSet: string;
|
|
112
|
+
public readonly url: string[];
|
|
113
|
+
public readonly frameRate: number;
|
|
114
|
+
public readonly height: number;
|
|
115
|
+
public readonly id: number;
|
|
116
|
+
public readonly name: string;
|
|
117
|
+
public readonly supplemental: CodecsParsed | undefined;
|
|
118
|
+
public readonly videoCodec: string | undefined;
|
|
119
|
+
public readonly width: number;
|
|
120
|
+
public details?: LevelDetails;
|
|
121
|
+
public fragmentError: number = 0;
|
|
122
|
+
public loadError: number = 0;
|
|
123
|
+
public loaded?: { bytes: number; duration: number };
|
|
124
|
+
public realBitrate: number = 0;
|
|
125
|
+
public supportedPromise?: Promise<MediaDecodingInfo>;
|
|
126
|
+
public supportedResult?: MediaDecodingInfo;
|
|
127
|
+
private _avgBitrate: number = 0;
|
|
128
|
+
private _audioGroups?: (string | undefined)[];
|
|
129
|
+
private _subtitleGroups?: (string | undefined)[];
|
|
130
|
+
// Deprecated (retained for backwards compatibility)
|
|
131
|
+
private readonly _urlId: number = 0;
|
|
132
|
+
|
|
133
|
+
constructor(data: LevelParsed | MediaPlaylist) {
|
|
134
|
+
this.url = [data.url];
|
|
135
|
+
this._attrs = [data.attrs];
|
|
136
|
+
this.bitrate = data.bitrate;
|
|
137
|
+
if (data.details) {
|
|
138
|
+
this.details = data.details;
|
|
139
|
+
}
|
|
140
|
+
this.id = data.id || 0;
|
|
141
|
+
this.name = data.name;
|
|
142
|
+
this.width = data.width || 0;
|
|
143
|
+
this.height = data.height || 0;
|
|
144
|
+
this.frameRate = data.attrs.optionalFloat('FRAME-RATE', 0);
|
|
145
|
+
this._avgBitrate = data.attrs.decimalInteger('AVERAGE-BANDWIDTH');
|
|
146
|
+
this.audioCodec = data.audioCodec;
|
|
147
|
+
this.videoCodec = data.videoCodec;
|
|
148
|
+
this.codecSet = [data.videoCodec, data.audioCodec]
|
|
149
|
+
.filter((c) => !!c)
|
|
150
|
+
.map((s: string) => s.substring(0, 4))
|
|
151
|
+
.join(',');
|
|
152
|
+
if ('supplemental' in data) {
|
|
153
|
+
this.supplemental = data.supplemental;
|
|
154
|
+
const supplementalVideo = data.supplemental?.videoCodec;
|
|
155
|
+
if (supplementalVideo && supplementalVideo !== data.videoCodec) {
|
|
156
|
+
this.codecSet += `,${supplementalVideo.substring(0, 4)}`;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
this.addGroupId('audio', data.attrs.AUDIO);
|
|
160
|
+
this.addGroupId('text', data.attrs.SUBTITLES);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
get maxBitrate(): number {
|
|
164
|
+
return Math.max(this.realBitrate, this.bitrate);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
get averageBitrate(): number {
|
|
168
|
+
return this._avgBitrate || this.realBitrate || this.bitrate;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
get attrs(): LevelAttributes {
|
|
172
|
+
return this._attrs[0];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get codecs(): string {
|
|
176
|
+
return this.attrs.CODECS || '';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
get pathwayId(): string {
|
|
180
|
+
return this.attrs['PATHWAY-ID'] || '.';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
get videoRange(): VideoRange {
|
|
184
|
+
return this.attrs['VIDEO-RANGE'] || 'SDR';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
get score(): number {
|
|
188
|
+
return this.attrs.optionalFloat('SCORE', 0);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
get uri(): string {
|
|
192
|
+
return this.url[0] || '';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
hasAudioGroup(groupId: string | undefined): boolean {
|
|
196
|
+
return hasGroup(this._audioGroups, groupId);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
hasSubtitleGroup(groupId: string | undefined): boolean {
|
|
200
|
+
return hasGroup(this._subtitleGroups, groupId);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
get audioGroups(): (string | undefined)[] | undefined {
|
|
204
|
+
return this._audioGroups;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
get subtitleGroups(): (string | undefined)[] | undefined {
|
|
208
|
+
return this._subtitleGroups;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
addGroupId(type: string, groupId: string | undefined) {
|
|
212
|
+
if (!groupId) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (type === 'audio') {
|
|
216
|
+
let audioGroups = this._audioGroups;
|
|
217
|
+
if (!audioGroups) {
|
|
218
|
+
audioGroups = this._audioGroups = [];
|
|
219
|
+
}
|
|
220
|
+
if (audioGroups.indexOf(groupId) === -1) {
|
|
221
|
+
audioGroups.push(groupId);
|
|
222
|
+
}
|
|
223
|
+
} else if (type === 'text') {
|
|
224
|
+
let subtitleGroups = this._subtitleGroups;
|
|
225
|
+
if (!subtitleGroups) {
|
|
226
|
+
subtitleGroups = this._subtitleGroups = [];
|
|
227
|
+
}
|
|
228
|
+
if (subtitleGroups.indexOf(groupId) === -1) {
|
|
229
|
+
subtitleGroups.push(groupId);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Deprecated methods (retained for backwards compatibility)
|
|
235
|
+
get urlId(): number {
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
set urlId(value: number) {}
|
|
240
|
+
|
|
241
|
+
get audioGroupIds(): (string | undefined)[] | undefined {
|
|
242
|
+
return this.audioGroups ? [this.audioGroupId] : undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
get textGroupIds(): (string | undefined)[] | undefined {
|
|
246
|
+
return this.subtitleGroups ? [this.textGroupId] : undefined;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
get audioGroupId(): string | undefined {
|
|
250
|
+
return this.audioGroups?.[0];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
get textGroupId(): string | undefined {
|
|
254
|
+
return this.subtitleGroups?.[0];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
addFallback() {}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function hasGroup(
|
|
261
|
+
groups: (string | undefined)[] | undefined,
|
|
262
|
+
groupId: string | undefined,
|
|
263
|
+
): boolean {
|
|
264
|
+
if (!groupId || !groups) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
return groups.indexOf(groupId) !== -1;
|
|
268
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type { LoaderConfig } from '../config';
|
|
2
|
+
import type { HlsUrlParameters, Level } from './level';
|
|
3
|
+
import type { MediaPlaylist } from './media-playlist';
|
|
4
|
+
import type { NullableNetworkDetails } from './network-details';
|
|
5
|
+
import type { Fragment } from '../loader/fragment';
|
|
6
|
+
import type { Part } from '../loader/fragment';
|
|
7
|
+
import type { KeyLoaderInfo } from '../loader/key-loader';
|
|
8
|
+
import type { LevelDetails } from '../loader/level-details';
|
|
9
|
+
|
|
10
|
+
export interface LoaderContext {
|
|
11
|
+
// target URL
|
|
12
|
+
url: string;
|
|
13
|
+
// loader response type (arraybuffer or default response type for playlist)
|
|
14
|
+
responseType: string;
|
|
15
|
+
// headers
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
// start byte range offset
|
|
18
|
+
rangeStart?: number;
|
|
19
|
+
// end byte range offset
|
|
20
|
+
rangeEnd?: number;
|
|
21
|
+
// true if onProgress should report partial chunk of loaded content
|
|
22
|
+
progressData?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface FragmentLoaderContext extends LoaderContext {
|
|
26
|
+
frag: Fragment;
|
|
27
|
+
part: Part | null;
|
|
28
|
+
resetIV?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface KeyLoaderContext extends LoaderContext {
|
|
32
|
+
keyInfo: KeyLoaderInfo;
|
|
33
|
+
frag: Fragment;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface LoaderConfiguration {
|
|
37
|
+
// LoaderConfig policy that overrides required settings
|
|
38
|
+
loadPolicy: LoaderConfig;
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated use LoaderConfig timeoutRetry and errorRetry maxNumRetry
|
|
41
|
+
*/
|
|
42
|
+
// Max number of load retries
|
|
43
|
+
maxRetry: number;
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated use LoaderConfig maxTimeToFirstByteMs and maxLoadTimeMs
|
|
46
|
+
*/
|
|
47
|
+
// Timeout after which `onTimeOut` callback will be triggered
|
|
48
|
+
// when loading has not finished after that delay
|
|
49
|
+
timeout: number;
|
|
50
|
+
/**
|
|
51
|
+
* @deprecated use LoaderConfig timeoutRetry and errorRetry retryDelayMs
|
|
52
|
+
*/
|
|
53
|
+
// Delay between an I/O error and following connection retry (ms).
|
|
54
|
+
// This to avoid spamming the server
|
|
55
|
+
retryDelay: number;
|
|
56
|
+
/**
|
|
57
|
+
* @deprecated use LoaderConfig timeoutRetry and errorRetry maxRetryDelayMs
|
|
58
|
+
*/
|
|
59
|
+
// max connection retry delay (ms)
|
|
60
|
+
maxRetryDelay: number;
|
|
61
|
+
// When streaming progressively, this is the minimum chunk size required to emit a PROGRESS event
|
|
62
|
+
highWaterMark?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface LoaderResponse {
|
|
66
|
+
url: string;
|
|
67
|
+
data?: string | ArrayBuffer | Object;
|
|
68
|
+
// Errors can include HTTP status code and error message
|
|
69
|
+
// Successful responses should include status code 200
|
|
70
|
+
code?: number;
|
|
71
|
+
text?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface LoaderStats {
|
|
75
|
+
aborted: boolean;
|
|
76
|
+
loaded: number;
|
|
77
|
+
retry: number;
|
|
78
|
+
total: number;
|
|
79
|
+
chunkCount: number;
|
|
80
|
+
bwEstimate: number;
|
|
81
|
+
loading: HlsProgressivePerformanceTiming;
|
|
82
|
+
parsing: HlsPerformanceTiming;
|
|
83
|
+
buffering: HlsProgressivePerformanceTiming;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface HlsPerformanceTiming {
|
|
87
|
+
start: number;
|
|
88
|
+
end: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface HlsChunkPerformanceTiming extends HlsPerformanceTiming {
|
|
92
|
+
executeStart: number;
|
|
93
|
+
executeEnd: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface HlsProgressivePerformanceTiming extends HlsPerformanceTiming {
|
|
97
|
+
first: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type LoaderOnSuccess<T extends LoaderContext> = (
|
|
101
|
+
response: LoaderResponse,
|
|
102
|
+
stats: LoaderStats,
|
|
103
|
+
context: T,
|
|
104
|
+
networkDetails: NullableNetworkDetails,
|
|
105
|
+
) => void;
|
|
106
|
+
|
|
107
|
+
export type LoaderOnProgress<T extends LoaderContext> = (
|
|
108
|
+
stats: LoaderStats,
|
|
109
|
+
context: T,
|
|
110
|
+
data: string | ArrayBuffer,
|
|
111
|
+
networkDetails: NullableNetworkDetails,
|
|
112
|
+
) => void;
|
|
113
|
+
|
|
114
|
+
export type LoaderOnError<T extends LoaderContext> = (
|
|
115
|
+
error: {
|
|
116
|
+
// error status code
|
|
117
|
+
code: number;
|
|
118
|
+
// error description
|
|
119
|
+
text: string;
|
|
120
|
+
},
|
|
121
|
+
context: T,
|
|
122
|
+
networkDetails: NullableNetworkDetails,
|
|
123
|
+
stats: LoaderStats,
|
|
124
|
+
) => void;
|
|
125
|
+
|
|
126
|
+
export type LoaderOnTimeout<T extends LoaderContext> = (
|
|
127
|
+
stats: LoaderStats,
|
|
128
|
+
context: T,
|
|
129
|
+
networkDetails: NullableNetworkDetails,
|
|
130
|
+
) => void;
|
|
131
|
+
|
|
132
|
+
export type LoaderOnAbort<T extends LoaderContext> = (
|
|
133
|
+
stats: LoaderStats,
|
|
134
|
+
context: T,
|
|
135
|
+
networkDetails: NullableNetworkDetails,
|
|
136
|
+
) => void;
|
|
137
|
+
|
|
138
|
+
export interface LoaderCallbacks<T extends LoaderContext> {
|
|
139
|
+
onSuccess: LoaderOnSuccess<T>;
|
|
140
|
+
onError: LoaderOnError<T>;
|
|
141
|
+
onTimeout: LoaderOnTimeout<T>;
|
|
142
|
+
onAbort?: LoaderOnAbort<T>;
|
|
143
|
+
onProgress?: LoaderOnProgress<T>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface Loader<T extends LoaderContext> {
|
|
147
|
+
destroy(): void;
|
|
148
|
+
abort(): void;
|
|
149
|
+
load(
|
|
150
|
+
context: T,
|
|
151
|
+
config: LoaderConfiguration,
|
|
152
|
+
callbacks: LoaderCallbacks<T>,
|
|
153
|
+
): void;
|
|
154
|
+
/**
|
|
155
|
+
* `getCacheAge()` is called by hls.js to get the duration that a given object
|
|
156
|
+
* has been sitting in a cache proxy when playing live. If implemented,
|
|
157
|
+
* this should return a value in seconds.
|
|
158
|
+
*
|
|
159
|
+
* For HTTP based loaders, this should return the contents of the "age" header.
|
|
160
|
+
*
|
|
161
|
+
* @returns time object being lodaded
|
|
162
|
+
*/
|
|
163
|
+
getCacheAge?: () => number | null;
|
|
164
|
+
getResponseHeader?: (name: string) => string | null;
|
|
165
|
+
context: T | null;
|
|
166
|
+
stats: LoaderStats;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const enum PlaylistContextType {
|
|
170
|
+
MANIFEST = 'manifest',
|
|
171
|
+
LEVEL = 'level',
|
|
172
|
+
AUDIO_TRACK = 'audioTrack',
|
|
173
|
+
SUBTITLE_TRACK = 'subtitleTrack',
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const enum PlaylistLevelType {
|
|
177
|
+
MAIN = 'main',
|
|
178
|
+
AUDIO = 'audio',
|
|
179
|
+
SUBTITLE = 'subtitle',
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface PlaylistLoaderContext extends LoaderContext {
|
|
183
|
+
type: PlaylistContextType;
|
|
184
|
+
// the level index to load
|
|
185
|
+
level: number | null;
|
|
186
|
+
// level or track id from LevelLoadingData / TrackLoadingData
|
|
187
|
+
id: number | null;
|
|
188
|
+
// Media Playlist Group ID
|
|
189
|
+
groupId?: string;
|
|
190
|
+
// Content Steering Pathway ID (or undefined for default Pathway ".")
|
|
191
|
+
pathwayId?: string;
|
|
192
|
+
// internal representation of a parsed m3u8 level playlist
|
|
193
|
+
levelDetails?: LevelDetails;
|
|
194
|
+
// Blocking playlist request delivery directives (or null id none were added to playlist url
|
|
195
|
+
deliveryDirectives: HlsUrlParameters | null;
|
|
196
|
+
// Reference to level or track object in hls.levels, hls.allAudioTracks, or hls.allSubtitleTracks (null when loading MVP)
|
|
197
|
+
levelOrTrack: Level | MediaPlaylist | null;
|
|
198
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Level, VideoRange } from './level';
|
|
2
|
+
import type { PlaylistLevelType } from './loader';
|
|
3
|
+
import type { LevelDetails } from '../loader/level-details';
|
|
4
|
+
import type { AttrList } from '../utils/attr-list';
|
|
5
|
+
|
|
6
|
+
export type AudioPlaylistType = 'AUDIO';
|
|
7
|
+
|
|
8
|
+
export type MainPlaylistType = AudioPlaylistType | 'VIDEO';
|
|
9
|
+
|
|
10
|
+
export type SubtitlePlaylistType = 'SUBTITLES' | 'CLOSED-CAPTIONS';
|
|
11
|
+
|
|
12
|
+
export type MediaPlaylistType = MainPlaylistType | SubtitlePlaylistType;
|
|
13
|
+
|
|
14
|
+
export type MediaSelection = {
|
|
15
|
+
[PlaylistLevelType.MAIN]: Level;
|
|
16
|
+
[PlaylistLevelType.AUDIO]?: MediaPlaylist;
|
|
17
|
+
[PlaylistLevelType.SUBTITLE]?: MediaPlaylist;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type VideoSelectionOption = {
|
|
21
|
+
preferHDR?: boolean;
|
|
22
|
+
allowedVideoRanges?: Array<VideoRange>;
|
|
23
|
+
videoCodec?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type AudioSelectionOption = {
|
|
27
|
+
lang?: string;
|
|
28
|
+
assocLang?: string;
|
|
29
|
+
characteristics?: string;
|
|
30
|
+
channels?: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
audioCodec?: string;
|
|
33
|
+
groupId?: string;
|
|
34
|
+
default?: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type SubtitleSelectionOption = {
|
|
38
|
+
id?: number;
|
|
39
|
+
lang?: string;
|
|
40
|
+
assocLang?: string;
|
|
41
|
+
characteristics?: string;
|
|
42
|
+
name?: string;
|
|
43
|
+
groupId?: string;
|
|
44
|
+
default?: boolean;
|
|
45
|
+
forced?: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// audioTracks, captions and subtitles returned by `M3U8Parser.parseMasterPlaylistMedia`
|
|
49
|
+
export interface MediaPlaylist {
|
|
50
|
+
attrs: MediaAttributes;
|
|
51
|
+
audioCodec?: string;
|
|
52
|
+
autoselect: boolean; // implicit false if not present
|
|
53
|
+
bitrate: number;
|
|
54
|
+
channels?: string;
|
|
55
|
+
characteristics?: string;
|
|
56
|
+
details?: LevelDetails;
|
|
57
|
+
height?: number;
|
|
58
|
+
default: boolean; // implicit false if not present
|
|
59
|
+
forced: boolean; // implicit false if not present
|
|
60
|
+
groupId: string; // required in HLS playlists
|
|
61
|
+
id: number; // incrementing number to track media playlists
|
|
62
|
+
instreamId?: string;
|
|
63
|
+
lang?: string;
|
|
64
|
+
assocLang?: string;
|
|
65
|
+
name: string;
|
|
66
|
+
textCodec?: string;
|
|
67
|
+
unknownCodecs?: string[];
|
|
68
|
+
// 'main' is a custom type added to signal a audioCodec in main track?; see playlist-loader~L310
|
|
69
|
+
type: MediaPlaylistType | 'main';
|
|
70
|
+
url: string;
|
|
71
|
+
videoCodec?: string;
|
|
72
|
+
width?: number;
|
|
73
|
+
// keep a reference to the track node that is associated with this MediaPlaylist
|
|
74
|
+
trackNode?: HTMLTrackElement;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface MediaAttributes extends AttrList {
|
|
78
|
+
'ASSOC-LANGUAGE'?: string;
|
|
79
|
+
AUTOSELECT?: 'YES' | 'NO';
|
|
80
|
+
CHANNELS?: string;
|
|
81
|
+
CHARACTERISTICS?: string;
|
|
82
|
+
DEFAULT?: 'YES' | 'NO';
|
|
83
|
+
FORCED?: 'YES' | 'NO';
|
|
84
|
+
'GROUP-ID': string;
|
|
85
|
+
'INSTREAM-ID'?: string;
|
|
86
|
+
LANGUAGE?: string;
|
|
87
|
+
NAME: string;
|
|
88
|
+
'PATHWAY-ID'?: string;
|
|
89
|
+
'STABLE-RENDITION-ID'?: string;
|
|
90
|
+
TYPE?: 'AUDIO' | 'VIDEO' | 'SUBTITLES' | 'CLOSED-CAPTIONS';
|
|
91
|
+
URI?: string;
|
|
92
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { SourceBufferName } from './buffer';
|
|
2
|
+
import type {
|
|
3
|
+
DemuxedAudioTrack,
|
|
4
|
+
DemuxedMetadataTrack,
|
|
5
|
+
DemuxedUserdataTrack,
|
|
6
|
+
DemuxedVideoTrack,
|
|
7
|
+
DemuxedVideoTrackBase,
|
|
8
|
+
MetadataSample,
|
|
9
|
+
UserdataSample,
|
|
10
|
+
} from './demuxer';
|
|
11
|
+
import type { PlaylistLevelType } from './loader';
|
|
12
|
+
import type { TrackSet } from './track';
|
|
13
|
+
import type { DecryptData } from '../loader/level-key';
|
|
14
|
+
import type { TimestampOffset } from '../utils/timescale-conversion';
|
|
15
|
+
|
|
16
|
+
export interface Remuxer {
|
|
17
|
+
remux(
|
|
18
|
+
audioTrack: DemuxedAudioTrack,
|
|
19
|
+
videoTrack: DemuxedVideoTrackBase,
|
|
20
|
+
id3Track: DemuxedMetadataTrack,
|
|
21
|
+
textTrack: DemuxedUserdataTrack,
|
|
22
|
+
timeOffset: number,
|
|
23
|
+
accurateTimeOffset: boolean,
|
|
24
|
+
flush: boolean,
|
|
25
|
+
playlistType: PlaylistLevelType,
|
|
26
|
+
): RemuxerResult;
|
|
27
|
+
resetInitSegment(
|
|
28
|
+
initSegment: Uint8Array | undefined,
|
|
29
|
+
audioCodec: string | undefined,
|
|
30
|
+
videoCodec: string | undefined,
|
|
31
|
+
decryptdata: DecryptData | null,
|
|
32
|
+
): void;
|
|
33
|
+
resetTimeStamp(defaultInitPTS: TimestampOffset | null): void;
|
|
34
|
+
resetNextTimestamp(): void;
|
|
35
|
+
destroy(): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface RemuxedTrack {
|
|
39
|
+
data1: Uint8Array<ArrayBuffer>;
|
|
40
|
+
data2?: Uint8Array<ArrayBuffer>;
|
|
41
|
+
startPTS: number;
|
|
42
|
+
endPTS: number;
|
|
43
|
+
startDTS: number;
|
|
44
|
+
endDTS: number;
|
|
45
|
+
type: SourceBufferName;
|
|
46
|
+
hasAudio: boolean;
|
|
47
|
+
hasVideo: boolean;
|
|
48
|
+
independent?: boolean;
|
|
49
|
+
firstKeyFrame?: number;
|
|
50
|
+
firstKeyFramePTS?: number;
|
|
51
|
+
nb: number;
|
|
52
|
+
transferredData1?: ArrayBuffer;
|
|
53
|
+
transferredData2?: ArrayBuffer;
|
|
54
|
+
dropped?: number;
|
|
55
|
+
encrypted?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface RemuxedMetadata {
|
|
59
|
+
samples: MetadataSample[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface RemuxedUserdata {
|
|
63
|
+
samples: UserdataSample[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type Mp4SampleFlags = {
|
|
67
|
+
isLeading: 0;
|
|
68
|
+
isDependedOn: 0;
|
|
69
|
+
hasRedundancy: 0;
|
|
70
|
+
degradPrio: 0;
|
|
71
|
+
dependsOn: 1 | 2;
|
|
72
|
+
isNonSync: 0 | 1;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type Mp4Sample = {
|
|
76
|
+
size: number;
|
|
77
|
+
duration: number;
|
|
78
|
+
cts: number;
|
|
79
|
+
flags: Mp4SampleFlags;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type RemuxedAudioTrackSamples = DemuxedAudioTrack & {
|
|
83
|
+
samples: Mp4Sample[];
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type RemuxedVideoTrackSamples = DemuxedVideoTrack & {
|
|
87
|
+
samples: Mp4Sample[];
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export interface RemuxerResult {
|
|
91
|
+
audio?: RemuxedTrack;
|
|
92
|
+
video?: RemuxedTrack;
|
|
93
|
+
text?: RemuxedUserdata;
|
|
94
|
+
id3?: RemuxedMetadata;
|
|
95
|
+
initSegment?: InitSegmentData;
|
|
96
|
+
independent?: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface InitSegmentData {
|
|
100
|
+
tracks?: TrackSet;
|
|
101
|
+
initPTS: number | undefined;
|
|
102
|
+
timescale: number | undefined;
|
|
103
|
+
trackId: number | undefined;
|
|
104
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BaseTrack } from './buffer';
|
|
2
|
+
|
|
3
|
+
export interface TrackSet {
|
|
4
|
+
audio?: Track;
|
|
5
|
+
video?: Track;
|
|
6
|
+
audiovideo?: Track;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Track extends BaseTrack {
|
|
10
|
+
buffer?: SourceBuffer; // eslint-disable-line no-restricted-globals
|
|
11
|
+
initSegment?: Uint8Array<ArrayBuffer>;
|
|
12
|
+
}
|