hls.js 1.5.12-0.canary.10399 → 1.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/dist/hls-demo.js +38 -41
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +2671 -4220
- package/dist/hls.js.d.ts +108 -173
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +1955 -2892
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +3402 -4354
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +4445 -6009
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +38 -38
- package/src/config.ts +2 -5
- package/src/controller/abr-controller.ts +25 -39
- package/src/controller/audio-stream-controller.ts +137 -141
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +10 -27
- package/src/controller/base-stream-controller.ts +82 -215
- package/src/controller/buffer-controller.ts +97 -250
- package/src/controller/buffer-operation-queue.ts +19 -16
- package/src/controller/cap-level-controller.ts +2 -3
- package/src/controller/cmcd-controller.ts +14 -51
- package/src/controller/content-steering-controller.ts +15 -29
- package/src/controller/eme-controller.ts +23 -10
- package/src/controller/error-controller.ts +22 -28
- package/src/controller/fps-controller.ts +3 -8
- package/src/controller/fragment-finders.ts +16 -44
- package/src/controller/fragment-tracker.ts +25 -58
- package/src/controller/gap-controller.ts +16 -43
- package/src/controller/id3-track-controller.ts +35 -45
- package/src/controller/latency-controller.ts +13 -18
- package/src/controller/level-controller.ts +19 -37
- package/src/controller/stream-controller.ts +83 -100
- package/src/controller/subtitle-stream-controller.ts +47 -35
- package/src/controller/subtitle-track-controller.ts +3 -5
- package/src/controller/timeline-controller.ts +22 -20
- package/src/crypt/aes-crypto.ts +2 -21
- package/src/crypt/decrypter.ts +16 -32
- package/src/crypt/fast-aes-key.ts +5 -28
- package/src/demux/audio/aacdemuxer.ts +2 -2
- package/src/demux/audio/ac3-demuxer.ts +3 -4
- package/src/demux/audio/adts.ts +4 -9
- package/src/demux/audio/base-audio-demuxer.ts +14 -16
- package/src/demux/audio/mp3demuxer.ts +3 -4
- package/src/demux/audio/mpegaudio.ts +1 -1
- package/src/demux/id3.ts +411 -0
- package/src/demux/mp4demuxer.ts +7 -7
- package/src/demux/sample-aes.ts +0 -2
- package/src/demux/transmuxer-interface.ts +16 -8
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +3 -16
- package/src/demux/tsdemuxer.ts +38 -75
- package/src/demux/video/avc-video-parser.ts +121 -210
- package/src/demux/video/base-video-parser.ts +2 -135
- package/src/demux/video/exp-golomb.ts +208 -0
- package/src/events.ts +1 -8
- package/src/exports-named.ts +1 -1
- package/src/hls.ts +43 -73
- package/src/loader/date-range.ts +5 -71
- package/src/loader/fragment-loader.ts +21 -23
- package/src/loader/fragment.ts +4 -8
- package/src/loader/key-loader.ts +1 -3
- package/src/loader/level-details.ts +6 -6
- package/src/loader/level-key.ts +9 -10
- package/src/loader/m3u8-parser.ts +144 -138
- package/src/loader/playlist-loader.ts +7 -5
- package/src/remux/mp4-generator.ts +1 -196
- package/src/remux/mp4-remuxer.ts +16 -36
- package/src/remux/passthrough-remuxer.ts +1 -1
- package/src/task-loop.ts +2 -5
- package/src/types/component-api.ts +1 -3
- package/src/types/demuxer.ts +0 -3
- package/src/types/events.ts +6 -19
- package/src/types/fragment-tracker.ts +2 -2
- package/src/types/general.ts +6 -0
- package/src/types/media-playlist.ts +1 -9
- package/src/types/remuxer.ts +1 -1
- package/src/utils/attr-list.ts +9 -96
- package/src/utils/buffer-helper.ts +31 -12
- package/src/utils/cea-608-parser.ts +3 -1
- package/src/utils/codecs.ts +5 -34
- package/src/utils/fetch-loader.ts +1 -1
- package/src/utils/hdr.ts +7 -4
- package/src/utils/imsc1-ttml-parser.ts +1 -1
- package/src/utils/keysystem-util.ts +6 -1
- package/src/utils/level-helper.ts +44 -71
- package/src/utils/logger.ts +23 -58
- package/src/utils/mp4-tools.ts +3 -5
- package/src/utils/rendition-helper.ts +74 -100
- package/src/utils/variable-substitution.ts +19 -0
- package/src/utils/webvtt-parser.ts +12 -2
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/demux/video/hevc-video-parser.ts +0 -749
- package/src/utils/encryption-methods-util.ts +0 -21
- package/src/utils/hash.ts +0 -10
- package/src/utils/utf8-utils.ts +0 -18
@@ -13,7 +13,6 @@ export type CodecSetTier = {
|
|
13
13
|
minBitrate: number;
|
14
14
|
minHeight: number;
|
15
15
|
minFramerate: number;
|
16
|
-
minIndex: number;
|
17
16
|
maxScore: number;
|
18
17
|
videoRanges: Record<string, number>;
|
19
18
|
channels: Record<string, number>;
|
@@ -33,7 +32,6 @@ type StartParameters = {
|
|
33
32
|
preferHDR: boolean;
|
34
33
|
minFramerate: number;
|
35
34
|
minBitrate: number;
|
36
|
-
minIndex: number;
|
37
35
|
};
|
38
36
|
|
39
37
|
export function getStartCodecTier(
|
@@ -46,15 +44,13 @@ export function getStartCodecTier(
|
|
46
44
|
const codecSets = Object.keys(codecTiers);
|
47
45
|
const channelsPreference = audioPreference?.channels;
|
48
46
|
const audioCodecPreference = audioPreference?.audioCodec;
|
49
|
-
const videoCodecPreference = videoPreference?.videoCodec;
|
50
47
|
const preferStereo = channelsPreference && parseInt(channelsPreference) === 2;
|
51
48
|
// Use first level set to determine stereo, and minimum resolution and framerate
|
52
|
-
let hasStereo =
|
49
|
+
let hasStereo = true;
|
53
50
|
let hasCurrentVideoRange = false;
|
54
51
|
let minHeight = Infinity;
|
55
52
|
let minFramerate = Infinity;
|
56
53
|
let minBitrate = Infinity;
|
57
|
-
let minIndex = Infinity;
|
58
54
|
let selectedScore = 0;
|
59
55
|
let videoRanges: Array<VideoRange> = [];
|
60
56
|
|
@@ -65,7 +61,7 @@ export function getStartCodecTier(
|
|
65
61
|
|
66
62
|
for (let i = codecSets.length; i--; ) {
|
67
63
|
const tier = codecTiers[codecSets[i]];
|
68
|
-
hasStereo
|
64
|
+
hasStereo = tier.channels[2] > 0;
|
69
65
|
minHeight = Math.min(minHeight, tier.minHeight);
|
70
66
|
minFramerate = Math.min(minFramerate, tier.minFramerate);
|
71
67
|
minBitrate = Math.min(minBitrate, tier.minBitrate);
|
@@ -74,6 +70,7 @@ export function getStartCodecTier(
|
|
74
70
|
);
|
75
71
|
if (matchingVideoRanges.length > 0) {
|
76
72
|
hasCurrentVideoRange = true;
|
73
|
+
videoRanges = matchingVideoRanges;
|
77
74
|
}
|
78
75
|
}
|
79
76
|
minHeight = Number.isFinite(minHeight) ? minHeight : 0;
|
@@ -85,8 +82,8 @@ export function getStartCodecTier(
|
|
85
82
|
// If there are no variants with matching preference, set currentVideoRange to undefined
|
86
83
|
if (!hasCurrentVideoRange) {
|
87
84
|
currentVideoRange = undefined;
|
85
|
+
videoRanges = [];
|
88
86
|
}
|
89
|
-
const hasMultipleSets = codecSets.length > 1;
|
90
87
|
const codecSet = codecSets.reduce(
|
91
88
|
(selected: string | undefined, candidate: string) => {
|
92
89
|
// Remove candiates which do not meet bitrate, default audio, stereo or channels preference, 1080p or lower, 30fps or lower, or SDR/HDR selection if present
|
@@ -94,99 +91,80 @@ export function getStartCodecTier(
|
|
94
91
|
if (candidate === selected) {
|
95
92
|
return selected;
|
96
93
|
}
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
`audio codec preference "${audioCodecPreference}" not found`,
|
124
|
-
);
|
125
|
-
return selected;
|
126
|
-
}
|
127
|
-
if (channelsPreference && !preferStereo) {
|
128
|
-
if (!candidateTier.channels[channelsPreference]) {
|
129
|
-
logStartCodecCandidateIgnored(
|
130
|
-
candidate,
|
131
|
-
`no renditions with ${channelsPreference} channel sound found (channels options: ${Object.keys(
|
132
|
-
candidateTier.channels,
|
133
|
-
)})`,
|
134
|
-
);
|
135
|
-
return selected;
|
136
|
-
}
|
137
|
-
} else if (
|
138
|
-
(!audioCodecPreference || preferStereo) &&
|
139
|
-
hasStereo &&
|
140
|
-
candidateTier.channels['2'] === 0
|
141
|
-
) {
|
142
|
-
logStartCodecCandidateIgnored(
|
143
|
-
candidate,
|
144
|
-
`no renditions with stereo sound found`,
|
145
|
-
);
|
146
|
-
return selected;
|
147
|
-
}
|
148
|
-
if (candidateTier.minHeight > maxHeight) {
|
149
|
-
logStartCodecCandidateIgnored(
|
150
|
-
candidate,
|
151
|
-
`min resolution of ${candidateTier.minHeight} > maximum of ${maxHeight}`,
|
152
|
-
);
|
153
|
-
return selected;
|
154
|
-
}
|
155
|
-
if (candidateTier.minFramerate > maxFramerate) {
|
156
|
-
logStartCodecCandidateIgnored(
|
157
|
-
candidate,
|
158
|
-
`min framerate of ${candidateTier.minFramerate} > maximum of ${maxFramerate}`,
|
159
|
-
);
|
160
|
-
return selected;
|
161
|
-
}
|
162
|
-
if (
|
163
|
-
!videoRanges.some((range) => candidateTier.videoRanges[range] > 0)
|
164
|
-
) {
|
165
|
-
logStartCodecCandidateIgnored(
|
166
|
-
candidate,
|
167
|
-
`no variants with VIDEO-RANGE of ${JSON.stringify(
|
168
|
-
videoRanges,
|
169
|
-
)} found`,
|
170
|
-
);
|
171
|
-
return selected;
|
172
|
-
}
|
173
|
-
if (
|
174
|
-
videoCodecPreference &&
|
175
|
-
candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0
|
176
|
-
) {
|
177
|
-
logStartCodecCandidateIgnored(
|
178
|
-
candidate,
|
179
|
-
`video codec preference "${videoCodecPreference}" not found`,
|
180
|
-
);
|
181
|
-
return selected;
|
182
|
-
}
|
183
|
-
if (candidateTier.maxScore < selectedScore) {
|
94
|
+
if (candidateTier.minBitrate > currentBw) {
|
95
|
+
logStartCodecCandidateIgnored(
|
96
|
+
candidate,
|
97
|
+
`min bitrate of ${candidateTier.minBitrate} > current estimate of ${currentBw}`,
|
98
|
+
);
|
99
|
+
return selected;
|
100
|
+
}
|
101
|
+
if (!candidateTier.hasDefaultAudio) {
|
102
|
+
logStartCodecCandidateIgnored(
|
103
|
+
candidate,
|
104
|
+
`no renditions with default or auto-select sound found`,
|
105
|
+
);
|
106
|
+
return selected;
|
107
|
+
}
|
108
|
+
if (
|
109
|
+
audioCodecPreference &&
|
110
|
+
candidate.indexOf(audioCodecPreference.substring(0, 4)) % 5 !== 0
|
111
|
+
) {
|
112
|
+
logStartCodecCandidateIgnored(
|
113
|
+
candidate,
|
114
|
+
`audio codec preference "${audioCodecPreference}" not found`,
|
115
|
+
);
|
116
|
+
return selected;
|
117
|
+
}
|
118
|
+
if (channelsPreference && !preferStereo) {
|
119
|
+
if (!candidateTier.channels[channelsPreference]) {
|
184
120
|
logStartCodecCandidateIgnored(
|
185
121
|
candidate,
|
186
|
-
`
|
122
|
+
`no renditions with ${channelsPreference} channel sound found (channels options: ${Object.keys(
|
123
|
+
candidateTier.channels,
|
124
|
+
)})`,
|
187
125
|
);
|
188
126
|
return selected;
|
189
127
|
}
|
128
|
+
} else if (
|
129
|
+
(!audioCodecPreference || preferStereo) &&
|
130
|
+
hasStereo &&
|
131
|
+
candidateTier.channels['2'] === 0
|
132
|
+
) {
|
133
|
+
logStartCodecCandidateIgnored(
|
134
|
+
candidate,
|
135
|
+
`no renditions with stereo sound found`,
|
136
|
+
);
|
137
|
+
return selected;
|
138
|
+
}
|
139
|
+
if (candidateTier.minHeight > maxHeight) {
|
140
|
+
logStartCodecCandidateIgnored(
|
141
|
+
candidate,
|
142
|
+
`min resolution of ${candidateTier.minHeight} > maximum of ${maxHeight}`,
|
143
|
+
);
|
144
|
+
return selected;
|
145
|
+
}
|
146
|
+
if (candidateTier.minFramerate > maxFramerate) {
|
147
|
+
logStartCodecCandidateIgnored(
|
148
|
+
candidate,
|
149
|
+
`min framerate of ${candidateTier.minFramerate} > maximum of ${maxFramerate}`,
|
150
|
+
);
|
151
|
+
return selected;
|
152
|
+
}
|
153
|
+
if (!videoRanges.some((range) => candidateTier.videoRanges[range] > 0)) {
|
154
|
+
logStartCodecCandidateIgnored(
|
155
|
+
candidate,
|
156
|
+
`no variants with VIDEO-RANGE of ${JSON.stringify(
|
157
|
+
videoRanges,
|
158
|
+
)} found`,
|
159
|
+
);
|
160
|
+
return selected;
|
161
|
+
}
|
162
|
+
if (candidateTier.maxScore < selectedScore) {
|
163
|
+
logStartCodecCandidateIgnored(
|
164
|
+
candidate,
|
165
|
+
`max score of ${candidateTier.maxScore} < selected max of ${selectedScore}`,
|
166
|
+
);
|
167
|
+
return selected;
|
190
168
|
}
|
191
169
|
// Remove candiates with less preferred codecs or more errors
|
192
170
|
if (
|
@@ -197,7 +175,6 @@ export function getStartCodecTier(
|
|
197
175
|
) {
|
198
176
|
return selected;
|
199
177
|
}
|
200
|
-
minIndex = candidateTier.minIndex;
|
201
178
|
selectedScore = candidateTier.maxScore;
|
202
179
|
return candidate;
|
203
180
|
},
|
@@ -209,7 +186,6 @@ export function getStartCodecTier(
|
|
209
186
|
preferHDR,
|
210
187
|
minFramerate,
|
211
188
|
minBitrate,
|
212
|
-
minIndex,
|
213
189
|
};
|
214
190
|
}
|
215
191
|
|
@@ -267,7 +243,7 @@ export function getCodecTiers(
|
|
267
243
|
): Record<string, CodecSetTier> {
|
268
244
|
return levels
|
269
245
|
.slice(minAutoLevel, maxAutoLevel + 1)
|
270
|
-
.reduce((tiers: Record<string, CodecSetTier>, level
|
246
|
+
.reduce((tiers: Record<string, CodecSetTier>, level) => {
|
271
247
|
if (!level.codecSet) {
|
272
248
|
return tiers;
|
273
249
|
}
|
@@ -278,7 +254,6 @@ export function getCodecTiers(
|
|
278
254
|
minBitrate: Infinity,
|
279
255
|
minHeight: Infinity,
|
280
256
|
minFramerate: Infinity,
|
281
|
-
minIndex: index,
|
282
257
|
maxScore: 0,
|
283
258
|
videoRanges: { SDR: 0 },
|
284
259
|
channels: { '2': 0 },
|
@@ -290,7 +265,6 @@ export function getCodecTiers(
|
|
290
265
|
const lesserWidthOrHeight = Math.min(level.height, level.width);
|
291
266
|
tier.minHeight = Math.min(tier.minHeight, lesserWidthOrHeight);
|
292
267
|
tier.minFramerate = Math.min(tier.minFramerate, level.frameRate);
|
293
|
-
tier.minIndex = Math.min(tier.minIndex, index);
|
294
268
|
tier.maxScore = Math.max(tier.maxScore, level.score);
|
295
269
|
tier.fragmentError += level.fragmentError;
|
296
270
|
tier.videoRanges[level.videoRange] =
|
@@ -9,6 +9,25 @@ export function hasVariableReferences(str: string): boolean {
|
|
9
9
|
return VARIABLE_REPLACEMENT_REGEX.test(str);
|
10
10
|
}
|
11
11
|
|
12
|
+
export function substituteVariablesInAttributes(
|
13
|
+
parsed: Pick<
|
14
|
+
ParsedMultivariantPlaylist | LevelDetails,
|
15
|
+
'variableList' | 'hasVariableRefs' | 'playlistParsingError'
|
16
|
+
>,
|
17
|
+
attr: AttrList,
|
18
|
+
attributeNames: string[],
|
19
|
+
) {
|
20
|
+
if (parsed.variableList !== null || parsed.hasVariableRefs) {
|
21
|
+
for (let i = attributeNames.length; i--; ) {
|
22
|
+
const name = attributeNames[i];
|
23
|
+
const value = attr[name];
|
24
|
+
if (value) {
|
25
|
+
attr[name] = substituteVariables(parsed, value);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
12
31
|
export function substituteVariables(
|
13
32
|
parsed: Pick<
|
14
33
|
ParsedMultivariantPlaylist | LevelDetails,
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import { VTTParser } from './vttparser';
|
2
|
-
import { utf8ArrayToStr } from '
|
3
|
-
import { hash } from './hash';
|
2
|
+
import { utf8ArrayToStr } from '../demux/id3';
|
4
3
|
import {
|
5
4
|
RationalTimestamp,
|
6
5
|
toMpegTsClockFromTimescale,
|
@@ -46,6 +45,17 @@ const cueString2millis = function (timeString: string) {
|
|
46
45
|
return ts;
|
47
46
|
};
|
48
47
|
|
48
|
+
// From https://github.com/darkskyapp/string-hash
|
49
|
+
const hash = function (text: string) {
|
50
|
+
let hash = 5381;
|
51
|
+
let i = text.length;
|
52
|
+
while (i) {
|
53
|
+
hash = (hash * 33) ^ text.charCodeAt(--i);
|
54
|
+
}
|
55
|
+
|
56
|
+
return (hash >>> 0).toString();
|
57
|
+
};
|
58
|
+
|
49
59
|
// Create a unique hash id for a cue based on start/end times and text.
|
50
60
|
// This helps timeline-controller to avoid showing repeated captions.
|
51
61
|
export function generateCueId(
|