hls.js 1.5.12-0.canary.10366 → 1.5.12-0.canary.10368
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/dist/hls.js +303 -204
- package/dist/hls.js.d.ts +14 -8
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +211 -131
- 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 +208 -129
- 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 +300 -202
- 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 +1 -1
- package/src/controller/abr-controller.ts +1 -1
- package/src/controller/audio-stream-controller.ts +86 -84
- package/src/controller/base-stream-controller.ts +50 -41
- package/src/controller/buffer-controller.ts +20 -5
- package/src/controller/error-controller.ts +22 -14
- package/src/controller/fragment-finders.ts +33 -3
- package/src/controller/fragment-tracker.ts +30 -1
- package/src/controller/stream-controller.ts +54 -47
- package/src/controller/subtitle-stream-controller.ts +4 -4
- package/src/controller/timeline-controller.ts +1 -1
- package/src/hls.ts +1 -1
- package/src/loader/fragment-loader.ts +14 -19
- package/src/loader/fragment.ts +2 -2
- package/src/loader/level-details.ts +1 -2
- package/src/loader/playlist-loader.ts +1 -2
- package/src/remux/mp4-remuxer.ts +12 -8
- package/src/remux/passthrough-remuxer.ts +1 -1
- package/src/types/events.ts +13 -1
- package/src/utils/hash.ts +10 -0
- package/src/utils/level-helper.ts +4 -5
- package/src/utils/rendition-helper.ts +84 -79
- package/src/utils/webvtt-parser.ts +1 -11
- package/src/types/general.ts +0 -6
@@ -461,11 +461,10 @@ export function computeReloadInterval(
|
|
461
461
|
}
|
462
462
|
|
463
463
|
export function getFragmentWithSN(
|
464
|
-
|
464
|
+
details: LevelDetails | undefined,
|
465
465
|
sn: number,
|
466
466
|
fragCurrent: Fragment | null,
|
467
467
|
): MediaFragment | null {
|
468
|
-
const details = level?.details;
|
469
468
|
if (!details) {
|
470
469
|
return null;
|
471
470
|
}
|
@@ -485,14 +484,14 @@ export function getFragmentWithSN(
|
|
485
484
|
}
|
486
485
|
|
487
486
|
export function getPartWith(
|
488
|
-
|
487
|
+
details: LevelDetails | undefined,
|
489
488
|
sn: number,
|
490
489
|
partIndex: number,
|
491
490
|
): Part | null {
|
492
|
-
if (!
|
491
|
+
if (!details) {
|
493
492
|
return null;
|
494
493
|
}
|
495
|
-
return findPart(
|
494
|
+
return findPart(details.partList, sn, partIndex);
|
496
495
|
}
|
497
496
|
|
498
497
|
export function findPart(
|
@@ -86,6 +86,7 @@ export function getStartCodecTier(
|
|
86
86
|
if (!hasCurrentVideoRange) {
|
87
87
|
currentVideoRange = undefined;
|
88
88
|
}
|
89
|
+
const hasMultipleSets = codecSets.length > 1;
|
89
90
|
const codecSet = codecSets.reduce(
|
90
91
|
(selected: string | undefined, candidate: string) => {
|
91
92
|
// 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
|
@@ -98,90 +99,94 @@ export function getStartCodecTier(
|
|
98
99
|
(range) => candidateTier.videoRanges[range] > 0,
|
99
100
|
)
|
100
101
|
: [];
|
101
|
-
if (
|
102
|
-
|
103
|
-
candidate,
|
104
|
-
`min bitrate of ${candidateTier.minBitrate} > current estimate of ${currentBw}`,
|
105
|
-
);
|
106
|
-
return selected;
|
107
|
-
}
|
108
|
-
if (!candidateTier.hasDefaultAudio) {
|
109
|
-
logStartCodecCandidateIgnored(
|
110
|
-
candidate,
|
111
|
-
`no renditions with default or auto-select sound found`,
|
112
|
-
);
|
113
|
-
return selected;
|
114
|
-
}
|
115
|
-
if (
|
116
|
-
audioCodecPreference &&
|
117
|
-
candidate.indexOf(audioCodecPreference.substring(0, 4)) % 5 !== 0
|
118
|
-
) {
|
119
|
-
logStartCodecCandidateIgnored(
|
120
|
-
candidate,
|
121
|
-
`audio codec preference "${audioCodecPreference}" not found`,
|
122
|
-
);
|
123
|
-
return selected;
|
124
|
-
}
|
125
|
-
if (channelsPreference && !preferStereo) {
|
126
|
-
if (!candidateTier.channels[channelsPreference]) {
|
102
|
+
if (hasMultipleSets) {
|
103
|
+
if (candidateTier.minBitrate > currentBw) {
|
127
104
|
logStartCodecCandidateIgnored(
|
128
105
|
candidate,
|
129
|
-
`
|
130
|
-
|
131
|
-
|
106
|
+
`min bitrate of ${candidateTier.minBitrate} > current estimate of ${currentBw}`,
|
107
|
+
);
|
108
|
+
return selected;
|
109
|
+
}
|
110
|
+
if (!candidateTier.hasDefaultAudio) {
|
111
|
+
logStartCodecCandidateIgnored(
|
112
|
+
candidate,
|
113
|
+
`no renditions with default or auto-select sound found`,
|
114
|
+
);
|
115
|
+
return selected;
|
116
|
+
}
|
117
|
+
if (
|
118
|
+
audioCodecPreference &&
|
119
|
+
candidate.indexOf(audioCodecPreference.substring(0, 4)) % 5 !== 0
|
120
|
+
) {
|
121
|
+
logStartCodecCandidateIgnored(
|
122
|
+
candidate,
|
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) {
|
184
|
+
logStartCodecCandidateIgnored(
|
185
|
+
candidate,
|
186
|
+
`max score of ${candidateTier.maxScore} < selected max of ${selectedScore}`,
|
132
187
|
);
|
133
188
|
return selected;
|
134
189
|
}
|
135
|
-
} else if (
|
136
|
-
(!audioCodecPreference || preferStereo) &&
|
137
|
-
hasStereo &&
|
138
|
-
candidateTier.channels['2'] === 0
|
139
|
-
) {
|
140
|
-
logStartCodecCandidateIgnored(
|
141
|
-
candidate,
|
142
|
-
`no renditions with stereo sound found`,
|
143
|
-
);
|
144
|
-
return selected;
|
145
|
-
}
|
146
|
-
if (candidateTier.minHeight > maxHeight) {
|
147
|
-
logStartCodecCandidateIgnored(
|
148
|
-
candidate,
|
149
|
-
`min resolution of ${candidateTier.minHeight} > maximum of ${maxHeight}`,
|
150
|
-
);
|
151
|
-
return selected;
|
152
|
-
}
|
153
|
-
if (candidateTier.minFramerate > maxFramerate) {
|
154
|
-
logStartCodecCandidateIgnored(
|
155
|
-
candidate,
|
156
|
-
`min framerate of ${candidateTier.minFramerate} > maximum of ${maxFramerate}`,
|
157
|
-
);
|
158
|
-
return selected;
|
159
|
-
}
|
160
|
-
if (!videoRanges.some((range) => candidateTier.videoRanges[range] > 0)) {
|
161
|
-
logStartCodecCandidateIgnored(
|
162
|
-
candidate,
|
163
|
-
`no variants with VIDEO-RANGE of ${JSON.stringify(
|
164
|
-
videoRanges,
|
165
|
-
)} found`,
|
166
|
-
);
|
167
|
-
return selected;
|
168
|
-
}
|
169
|
-
if (
|
170
|
-
videoCodecPreference &&
|
171
|
-
candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0
|
172
|
-
) {
|
173
|
-
logStartCodecCandidateIgnored(
|
174
|
-
candidate,
|
175
|
-
`video codec preference "${videoCodecPreference}" not found`,
|
176
|
-
);
|
177
|
-
return selected;
|
178
|
-
}
|
179
|
-
if (candidateTier.maxScore < selectedScore) {
|
180
|
-
logStartCodecCandidateIgnored(
|
181
|
-
candidate,
|
182
|
-
`max score of ${candidateTier.maxScore} < selected max of ${selectedScore}`,
|
183
|
-
);
|
184
|
-
return selected;
|
185
190
|
}
|
186
191
|
// Remove candiates with less preferred codecs or more errors
|
187
192
|
if (
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { VTTParser } from './vttparser';
|
2
2
|
import { utf8ArrayToStr } from '@svta/common-media-library/utils/utf8ArrayToStr';
|
3
|
+
import { hash } from './hash';
|
3
4
|
import {
|
4
5
|
RationalTimestamp,
|
5
6
|
toMpegTsClockFromTimescale,
|
@@ -45,17 +46,6 @@ const cueString2millis = function (timeString: string) {
|
|
45
46
|
return ts;
|
46
47
|
};
|
47
48
|
|
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
|
-
|
59
49
|
// Create a unique hash id for a cue based on start/end times and text.
|
60
50
|
// This helps timeline-controller to avoid showing repeated captions.
|
61
51
|
export function generateCueId(
|