hls.js 1.5.11 → 1.5.12-0.canary.10338
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 +4 -3
- package/dist/hls-demo.js +41 -38
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +3477 -2195
- package/dist/hls.js.d.ts +108 -85
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2401 -1754
- 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 +2148 -1476
- 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 +2863 -1558
- 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 +36 -36
- package/src/config.ts +3 -2
- package/src/controller/abr-controller.ts +24 -20
- package/src/controller/audio-stream-controller.ts +68 -74
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +27 -10
- package/src/controller/base-stream-controller.ts +160 -38
- package/src/controller/buffer-controller.ts +230 -92
- package/src/controller/buffer-operation-queue.ts +16 -19
- package/src/controller/cap-level-controller.ts +3 -2
- package/src/controller/cmcd-controller.ts +51 -14
- package/src/controller/content-steering-controller.ts +29 -15
- package/src/controller/eme-controller.ts +10 -23
- package/src/controller/error-controller.ts +6 -8
- package/src/controller/fps-controller.ts +8 -3
- package/src/controller/fragment-tracker.ts +15 -11
- package/src/controller/gap-controller.ts +43 -16
- package/src/controller/id3-track-controller.ts +7 -7
- package/src/controller/latency-controller.ts +9 -11
- package/src/controller/level-controller.ts +37 -19
- package/src/controller/stream-controller.ts +37 -32
- package/src/controller/subtitle-stream-controller.ts +28 -40
- package/src/controller/subtitle-track-controller.ts +5 -3
- package/src/controller/timeline-controller.ts +19 -21
- package/src/crypt/aes-crypto.ts +21 -2
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +32 -16
- package/src/crypt/fast-aes-key.ts +28 -5
- package/src/demux/audio/aacdemuxer.ts +2 -2
- package/src/demux/audio/ac3-demuxer.ts +4 -3
- package/src/demux/audio/adts.ts +9 -4
- package/src/demux/audio/base-audio-demuxer.ts +16 -14
- package/src/demux/audio/mp3demuxer.ts +4 -3
- package/src/demux/audio/mpegaudio.ts +1 -1
- package/src/demux/mp4demuxer.ts +7 -7
- package/src/demux/sample-aes.ts +2 -0
- package/src/demux/transmuxer-interface.ts +4 -12
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +16 -3
- package/src/demux/tsdemuxer.ts +75 -38
- package/src/demux/video/avc-video-parser.ts +208 -119
- package/src/demux/video/base-video-parser.ts +147 -18
- package/src/demux/video/exp-golomb.ts +0 -208
- package/src/demux/video/hevc-video-parser.ts +749 -0
- package/src/events.ts +8 -1
- package/src/exports-named.ts +1 -1
- package/src/hls.ts +61 -38
- package/src/loader/fragment-loader.ts +10 -3
- package/src/loader/key-loader.ts +3 -1
- package/src/loader/level-key.ts +10 -9
- package/src/loader/playlist-loader.ts +4 -5
- package/src/remux/mp4-generator.ts +196 -1
- package/src/remux/mp4-remuxer.ts +24 -8
- package/src/task-loop.ts +5 -2
- package/src/types/component-api.ts +3 -1
- package/src/types/demuxer.ts +4 -0
- package/src/types/events.ts +4 -0
- package/src/types/remuxer.ts +1 -1
- package/src/utils/buffer-helper.ts +12 -31
- package/src/utils/cea-608-parser.ts +1 -3
- package/src/utils/codecs.ts +34 -5
- package/src/utils/encryption-methods-util.ts +21 -0
- package/src/utils/fetch-loader.ts +1 -1
- package/src/utils/imsc1-ttml-parser.ts +1 -1
- package/src/utils/keysystem-util.ts +1 -6
- package/src/utils/logger.ts +58 -23
- package/src/utils/mp4-tools.ts +5 -3
- package/src/utils/utf8-utils.ts +18 -0
- package/src/utils/webvtt-parser.ts +1 -1
- package/src/demux/id3.ts +0 -411
package/src/remux/mp4-remuxer.ts
CHANGED
@@ -4,7 +4,7 @@ import type { HlsEventEmitter } from '../events';
|
|
4
4
|
import { Events } from '../events';
|
5
5
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
6
6
|
import { logger } from '../utils/logger';
|
7
|
-
import {
|
7
|
+
import type {
|
8
8
|
InitSegmentData,
|
9
9
|
Remuxer,
|
10
10
|
RemuxerResult,
|
@@ -29,6 +29,7 @@ import type { TrackSet } from '../types/track';
|
|
29
29
|
import type { SourceBufferName } from '../types/buffer';
|
30
30
|
import type { Fragment } from '../loader/fragment';
|
31
31
|
import type { HlsConfig } from '../config';
|
32
|
+
import type { TypeSupported } from '../utils/codecs';
|
32
33
|
|
33
34
|
const MAX_SILENT_FRAME_DURATION = 10 * 1000; // 10 seconds
|
34
35
|
const AAC_SAMPLES_PER_FRAME = 1024;
|
@@ -41,7 +42,7 @@ let safariWebkitVersion: number | null = null;
|
|
41
42
|
export default class MP4Remuxer implements Remuxer {
|
42
43
|
private observer: HlsEventEmitter;
|
43
44
|
private config: HlsConfig;
|
44
|
-
private typeSupported:
|
45
|
+
private typeSupported: TypeSupported;
|
45
46
|
private ISGenerated: boolean = false;
|
46
47
|
private _initPTS: RationalTimestamp | null = null;
|
47
48
|
private _initDTS: RationalTimestamp | null = null;
|
@@ -515,7 +516,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
515
516
|
if (foundHole || foundOverlap) {
|
516
517
|
if (foundHole) {
|
517
518
|
logger.warn(
|
518
|
-
|
519
|
+
`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
|
519
520
|
delta,
|
520
521
|
true,
|
521
522
|
)} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(
|
@@ -524,7 +525,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
524
525
|
);
|
525
526
|
} else {
|
526
527
|
logger.warn(
|
527
|
-
|
528
|
+
`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
|
528
529
|
-delta,
|
529
530
|
true,
|
530
531
|
)} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(
|
@@ -543,12 +544,27 @@ export default class MP4Remuxer implements Remuxer {
|
|
543
544
|
inputSamples[0].dts = firstDTS;
|
544
545
|
inputSamples[0].pts = firstPTS;
|
545
546
|
} else {
|
547
|
+
let isPTSOrderRetained = true;
|
546
548
|
for (let i = 0; i < inputSamples.length; i++) {
|
547
|
-
if (inputSamples[i].dts > firstPTS) {
|
549
|
+
if (inputSamples[i].dts > firstPTS && isPTSOrderRetained) {
|
548
550
|
break;
|
549
551
|
}
|
552
|
+
|
553
|
+
const prevPTS = inputSamples[i].pts;
|
550
554
|
inputSamples[i].dts -= delta;
|
551
555
|
inputSamples[i].pts -= delta;
|
556
|
+
|
557
|
+
// check to see if this sample's PTS order has changed
|
558
|
+
// relative to the next one
|
559
|
+
if (i < inputSamples.length - 1) {
|
560
|
+
const nextSamplePTS = inputSamples[i + 1].pts;
|
561
|
+
const currentSamplePTS = inputSamples[i].pts;
|
562
|
+
|
563
|
+
const currentOrder = nextSamplePTS <= currentSamplePTS;
|
564
|
+
const prevOrder = nextSamplePTS <= prevPTS;
|
565
|
+
|
566
|
+
isPTSOrderRetained = currentOrder == prevOrder;
|
567
|
+
}
|
552
568
|
}
|
553
569
|
}
|
554
570
|
logger.log(
|
@@ -743,7 +759,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
743
759
|
}
|
744
760
|
}
|
745
761
|
}
|
746
|
-
// next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
762
|
+
// next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
747
763
|
mp4SampleDuration =
|
748
764
|
stretchedLastFrame || !mp4SampleDuration
|
749
765
|
? averageSampleDuration
|
@@ -927,7 +943,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
927
943
|
for (let j = 0; j < missing; j++) {
|
928
944
|
const newStamp = Math.max(nextPts as number, 0);
|
929
945
|
let fillFrame = AAC.getSilentFrame(
|
930
|
-
track.manifestCodec || track.codec,
|
946
|
+
track.parsedCodec || track.manifestCodec || track.codec,
|
931
947
|
track.channelCount,
|
932
948
|
);
|
933
949
|
if (!fillFrame) {
|
@@ -1077,7 +1093,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
1077
1093
|
const nbSamples: number = Math.ceil((endDTS - startDTS) / frameDuration);
|
1078
1094
|
// silent frame
|
1079
1095
|
const silentFrame: Uint8Array | undefined = AAC.getSilentFrame(
|
1080
|
-
track.manifestCodec || track.codec,
|
1096
|
+
track.parsedCodec || track.manifestCodec || track.codec,
|
1081
1097
|
track.channelCount,
|
1082
1098
|
);
|
1083
1099
|
|
package/src/task-loop.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import { type ILogger, Logger } from './utils/logger';
|
2
|
+
|
1
3
|
/**
|
2
4
|
* @ignore
|
3
5
|
* Sub-class specialization of EventHandler base class.
|
@@ -27,13 +29,14 @@
|
|
27
29
|
* we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
|
28
30
|
* task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
|
29
31
|
*/
|
30
|
-
export default class TaskLoop {
|
32
|
+
export default class TaskLoop extends Logger {
|
31
33
|
private readonly _boundTick: () => void;
|
32
34
|
private _tickTimer: number | null = null;
|
33
35
|
private _tickInterval: number | null = null;
|
34
36
|
private _tickCallCount = 0;
|
35
37
|
|
36
|
-
constructor() {
|
38
|
+
constructor(label: string, logger: ILogger) {
|
39
|
+
super(label, logger);
|
37
40
|
this._boundTick = this.tick.bind(this);
|
38
41
|
}
|
39
42
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator';
|
1
|
+
import type EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator';
|
2
2
|
|
3
3
|
export interface ComponentAPI {
|
4
4
|
destroy(): void;
|
@@ -15,4 +15,6 @@ export interface AbrComponentAPI extends ComponentAPI {
|
|
15
15
|
export interface NetworkComponentAPI extends ComponentAPI {
|
16
16
|
startLoad(startPosition: number): void;
|
17
17
|
stopLoad(): void;
|
18
|
+
pauseBuffering?(): void;
|
19
|
+
resumeBuffering?(): void;
|
18
20
|
}
|
package/src/types/demuxer.ts
CHANGED
@@ -64,6 +64,7 @@ export interface DemuxedAudioTrack extends DemuxedTrack {
|
|
64
64
|
segmentCodec?: string;
|
65
65
|
channelCount?: number;
|
66
66
|
manifestCodec?: string;
|
67
|
+
parsedCodec?: string;
|
67
68
|
samples: AudioSample[];
|
68
69
|
}
|
69
70
|
|
@@ -72,12 +73,15 @@ export interface DemuxedVideoTrackBase extends DemuxedTrack {
|
|
72
73
|
height?: number;
|
73
74
|
pixelRatio?: [number, number];
|
74
75
|
audFound?: boolean;
|
76
|
+
vps?: Uint8Array[];
|
75
77
|
pps?: Uint8Array[];
|
76
78
|
sps?: Uint8Array[];
|
77
79
|
naluState?: number;
|
80
|
+
lastNalu?: VideoSampleUnit | null;
|
78
81
|
segmentCodec?: string;
|
79
82
|
manifestCodec?: string;
|
80
83
|
samples: VideoSample[] | Uint8Array;
|
84
|
+
params?: object;
|
81
85
|
}
|
82
86
|
|
83
87
|
export interface DemuxedVideoTrack extends DemuxedVideoTrackBase {
|
package/src/types/events.ts
CHANGED
package/src/types/remuxer.ts
CHANGED
@@ -35,19 +35,13 @@ export class BufferHelper {
|
|
35
35
|
* Return true if `media`'s buffered include `position`
|
36
36
|
*/
|
37
37
|
static isBuffered(media: Bufferable, position: number): boolean {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
return true;
|
44
|
-
}
|
38
|
+
if (media) {
|
39
|
+
const buffered = BufferHelper.getBuffered(media);
|
40
|
+
for (let i = buffered.length; i--; ) {
|
41
|
+
if (position >= buffered.start(i) && position <= buffered.end(i)) {
|
42
|
+
return true;
|
45
43
|
}
|
46
44
|
}
|
47
|
-
} catch (error) {
|
48
|
-
// this is to catch
|
49
|
-
// InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer':
|
50
|
-
// This SourceBuffer has been removed from the parent media source
|
51
45
|
}
|
52
46
|
return false;
|
53
47
|
}
|
@@ -57,21 +51,15 @@ export class BufferHelper {
|
|
57
51
|
pos: number,
|
58
52
|
maxHoleDuration: number,
|
59
53
|
): BufferInfo {
|
60
|
-
|
61
|
-
|
62
|
-
|
54
|
+
if (media) {
|
55
|
+
const vbuffered = BufferHelper.getBuffered(media);
|
56
|
+
if (vbuffered.length) {
|
63
57
|
const buffered: BufferTimeRange[] = [];
|
64
|
-
let i
|
65
|
-
for (i = 0; i < vbuffered.length; i++) {
|
58
|
+
for (let i = 0; i < vbuffered.length; i++) {
|
66
59
|
buffered.push({ start: vbuffered.start(i), end: vbuffered.end(i) });
|
67
60
|
}
|
68
|
-
|
69
|
-
return this.bufferedInfo(buffered, pos, maxHoleDuration);
|
61
|
+
return BufferHelper.bufferedInfo(buffered, pos, maxHoleDuration);
|
70
62
|
}
|
71
|
-
} catch (error) {
|
72
|
-
// this is to catch
|
73
|
-
// InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer':
|
74
|
-
// This SourceBuffer has been removed from the parent media source
|
75
63
|
}
|
76
64
|
return { len: 0, start: pos, end: pos, nextStart: undefined };
|
77
65
|
}
|
@@ -88,14 +76,7 @@ export class BufferHelper {
|
|
88
76
|
} {
|
89
77
|
pos = Math.max(0, pos);
|
90
78
|
// sort on buffer.start/smaller end (IE does not always return sorted buffered range)
|
91
|
-
buffered.sort(
|
92
|
-
const diff = a.start - b.start;
|
93
|
-
if (diff) {
|
94
|
-
return diff;
|
95
|
-
} else {
|
96
|
-
return b.end - a.end;
|
97
|
-
}
|
98
|
-
});
|
79
|
+
buffered.sort((a, b) => a.start - b.start || b.end - a.end);
|
99
80
|
|
100
81
|
let buffered2: BufferTimeRange[] = [];
|
101
82
|
if (maxHoleDuration) {
|
@@ -164,7 +145,7 @@ export class BufferHelper {
|
|
164
145
|
*/
|
165
146
|
static getBuffered(media: Bufferable): TimeRanges {
|
166
147
|
try {
|
167
|
-
return media.buffered;
|
148
|
+
return media.buffered || noopBuffered;
|
168
149
|
} catch (e) {
|
169
150
|
logger.log('failed to get media.buffered', e);
|
170
151
|
return noopBuffered;
|
@@ -1331,9 +1331,7 @@ class Cea608Parser {
|
|
1331
1331
|
if (charCodes) {
|
1332
1332
|
this.logger.log(
|
1333
1333
|
VerboseLevel.DEBUG,
|
1334
|
-
() =>
|
1335
|
-
'Char codes = ' +
|
1336
|
-
numArrayToHexArray(charCodes as number[]).join(','),
|
1334
|
+
() => 'Char codes = ' + numArrayToHexArray(charCodes).join(','),
|
1337
1335
|
);
|
1338
1336
|
}
|
1339
1337
|
return charCodes;
|
package/src/utils/codecs.ts
CHANGED
@@ -147,12 +147,15 @@ function getCodecCompatibleNameLower(
|
|
147
147
|
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec]!;
|
148
148
|
}
|
149
149
|
|
150
|
-
// Idealy fLaC and Opus would be first (spec-compliant) but
|
151
|
-
// some browsers will report that fLaC is supported then fail.
|
152
|
-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
153
150
|
const codecsToCheck = {
|
151
|
+
// Idealy fLaC and Opus would be first (spec-compliant) but
|
152
|
+
// some browsers will report that fLaC is supported then fail.
|
153
|
+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
154
154
|
flac: ['flac', 'fLaC', 'FLAC'],
|
155
155
|
opus: ['opus', 'Opus'],
|
156
|
+
// Replace audio codec info if browser does not support mp4a.40.34,
|
157
|
+
// and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
|
158
|
+
'mp4a.40.34': ['mp3'],
|
156
159
|
}[lowerCaseCodec];
|
157
160
|
|
158
161
|
for (let i = 0; i < codecsToCheck.length; i++) {
|
@@ -165,13 +168,18 @@ function getCodecCompatibleNameLower(
|
|
165
168
|
) {
|
166
169
|
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
|
167
170
|
return codecsToCheck[i];
|
171
|
+
} else if (
|
172
|
+
codecsToCheck[i] === 'mp3' &&
|
173
|
+
getMediaSource(preferManagedMediaSource)?.isTypeSupported('audio/mpeg')
|
174
|
+
) {
|
175
|
+
return '';
|
168
176
|
}
|
169
177
|
}
|
170
178
|
|
171
179
|
return lowerCaseCodec;
|
172
180
|
}
|
173
181
|
|
174
|
-
const AUDIO_CODEC_REGEXP = /flac|opus/i;
|
182
|
+
const AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
|
175
183
|
export function getCodecCompatibleName(
|
176
184
|
codec: string,
|
177
185
|
preferManagedMediaSource = true,
|
@@ -185,7 +193,7 @@ export function getCodecCompatibleName(
|
|
185
193
|
}
|
186
194
|
|
187
195
|
export function pickMostCompleteCodecName(
|
188
|
-
parsedCodec: string,
|
196
|
+
parsedCodec: string | undefined,
|
189
197
|
levelCodec: string | undefined,
|
190
198
|
): string | undefined {
|
191
199
|
// Parsing of mp4a codecs strings in mp4-tools from media is incomplete as of d8c6c7a
|
@@ -209,3 +217,24 @@ export function convertAVC1ToAVCOTI(codec: string) {
|
|
209
217
|
}
|
210
218
|
return codec;
|
211
219
|
}
|
220
|
+
|
221
|
+
export interface TypeSupported {
|
222
|
+
mpeg: boolean;
|
223
|
+
mp3: boolean;
|
224
|
+
ac3: boolean;
|
225
|
+
}
|
226
|
+
|
227
|
+
export function getM2TSSupportedAudioTypes(
|
228
|
+
preferManagedMediaSource: boolean,
|
229
|
+
): TypeSupported {
|
230
|
+
const MediaSource = getMediaSource(preferManagedMediaSource) || {
|
231
|
+
isTypeSupported: () => false,
|
232
|
+
};
|
233
|
+
return {
|
234
|
+
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
235
|
+
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
236
|
+
ac3: __USE_M2TS_ADVANCED_CODECS__
|
237
|
+
? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
|
238
|
+
: false,
|
239
|
+
};
|
240
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { DecrypterAesMode } from '../crypt/decrypter-aes-mode';
|
2
|
+
|
3
|
+
export function isFullSegmentEncryption(method: string): boolean {
|
4
|
+
return (
|
5
|
+
method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR'
|
6
|
+
);
|
7
|
+
}
|
8
|
+
|
9
|
+
export function getAesModeFromFullSegmentMethod(
|
10
|
+
method: string,
|
11
|
+
): DecrypterAesMode {
|
12
|
+
switch (method) {
|
13
|
+
case 'AES-128':
|
14
|
+
case 'AES-256':
|
15
|
+
return DecrypterAesMode.cbc;
|
16
|
+
case 'AES-256-CTR':
|
17
|
+
return DecrypterAesMode.ctr;
|
18
|
+
default:
|
19
|
+
throw new Error(`invalid full segment method ${method}`);
|
20
|
+
}
|
21
|
+
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { findBox } from './mp4-tools';
|
2
2
|
import { parseTimeStamp } from './vttparser';
|
3
3
|
import VTTCue from './vttcue';
|
4
|
-
import { utf8ArrayToStr } from '
|
4
|
+
import { utf8ArrayToStr } from '@svta/common-media-library/utils/utf8ArrayToStr';
|
5
5
|
import {
|
6
6
|
RationalTimestamp,
|
7
7
|
toTimescaleFromScale,
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { base64Decode } from './numeric-encoding-utils';
|
2
|
+
import { strToUtf8array } from './utf8-utils';
|
2
3
|
|
3
4
|
function getKeyIdBytes(str: string): Uint8Array {
|
4
5
|
const keyIdbytes = strToUtf8array(str).subarray(0, 16);
|
@@ -40,9 +41,3 @@ export function convertDataUriToArrayBytes(uri: string): Uint8Array | null {
|
|
40
41
|
}
|
41
42
|
return keydata;
|
42
43
|
}
|
43
|
-
|
44
|
-
export function strToUtf8array(str: string): Uint8Array {
|
45
|
-
return Uint8Array.from(unescape(encodeURIComponent(str)), (c) =>
|
46
|
-
c.charCodeAt(0),
|
47
|
-
);
|
48
|
-
}
|
package/src/utils/logger.ts
CHANGED
@@ -11,6 +11,25 @@ export interface ILogger {
|
|
11
11
|
error: ILogFunction;
|
12
12
|
}
|
13
13
|
|
14
|
+
export class Logger implements ILogger {
|
15
|
+
trace: ILogFunction;
|
16
|
+
debug: ILogFunction;
|
17
|
+
log: ILogFunction;
|
18
|
+
warn: ILogFunction;
|
19
|
+
info: ILogFunction;
|
20
|
+
error: ILogFunction;
|
21
|
+
|
22
|
+
constructor(label: string, logger: ILogger) {
|
23
|
+
const lb = `[${label}]:`;
|
24
|
+
this.trace = noop;
|
25
|
+
this.debug = logger.debug.bind(null, lb);
|
26
|
+
this.log = logger.log.bind(null, lb);
|
27
|
+
this.warn = logger.warn.bind(null, lb);
|
28
|
+
this.info = logger.info.bind(null, lb);
|
29
|
+
this.error = logger.error.bind(null, lb);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
14
33
|
const noop: ILogFunction = function () {};
|
15
34
|
|
16
35
|
const fakeLogger: ILogger = {
|
@@ -22,7 +41,9 @@ const fakeLogger: ILogger = {
|
|
22
41
|
error: noop,
|
23
42
|
};
|
24
43
|
|
25
|
-
|
44
|
+
function createLogger() {
|
45
|
+
return Object.assign({}, fakeLogger);
|
46
|
+
}
|
26
47
|
|
27
48
|
// let lastCallTime;
|
28
49
|
// function formatMsgWithTimeInfo(type, msg) {
|
@@ -33,33 +54,37 @@ let exportedLogger: ILogger = fakeLogger;
|
|
33
54
|
// return msg;
|
34
55
|
// }
|
35
56
|
|
36
|
-
function consolePrintFn(type: string): ILogFunction {
|
57
|
+
function consolePrintFn(type: string, id: string | undefined): ILogFunction {
|
37
58
|
const func: ILogFunction = self.console[type];
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
return noop;
|
59
|
+
return func
|
60
|
+
? func.bind(self.console, `${id ? '[' + id + '] ' : ''}[${type}] >`)
|
61
|
+
: noop;
|
42
62
|
}
|
43
63
|
|
44
|
-
function
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
});
|
64
|
+
function getLoggerFn(
|
65
|
+
key: string,
|
66
|
+
debugConfig: boolean | Partial<ILogger>,
|
67
|
+
id?: string,
|
68
|
+
): ILogFunction {
|
69
|
+
return debugConfig[key]
|
70
|
+
? debugConfig[key].bind(debugConfig)
|
71
|
+
: consolePrintFn(key, id);
|
53
72
|
}
|
54
73
|
|
55
|
-
|
74
|
+
const exportedLogger: ILogger = createLogger();
|
75
|
+
|
76
|
+
export function enableLogs(
|
77
|
+
debugConfig: boolean | ILogger,
|
78
|
+
context: string,
|
79
|
+
id?: string | undefined,
|
80
|
+
): ILogger {
|
56
81
|
// check that console is available
|
82
|
+
const newLogger = createLogger();
|
57
83
|
if (
|
58
84
|
(typeof console === 'object' && debugConfig === true) ||
|
59
85
|
typeof debugConfig === 'object'
|
60
86
|
) {
|
61
|
-
|
62
|
-
debugConfig,
|
87
|
+
const keys: (keyof ILogger)[] = [
|
63
88
|
// Remove out from list here to hard-disable a log-level
|
64
89
|
// 'trace',
|
65
90
|
'debug',
|
@@ -67,19 +92,29 @@ export function enableLogs(debugConfig: boolean | ILogger, id: string): void {
|
|
67
92
|
'info',
|
68
93
|
'warn',
|
69
94
|
'error',
|
70
|
-
|
95
|
+
];
|
96
|
+
keys.forEach((key) => {
|
97
|
+
newLogger[key] = getLoggerFn(key, debugConfig, id);
|
98
|
+
});
|
71
99
|
// Some browsers don't allow to use bind on console object anyway
|
72
100
|
// fallback to default if needed
|
73
101
|
try {
|
74
|
-
|
75
|
-
`Debug logs enabled for "${
|
102
|
+
newLogger.log(
|
103
|
+
`Debug logs enabled for "${context}" in hls.js version ${__VERSION__}`,
|
76
104
|
);
|
77
105
|
} catch (e) {
|
78
|
-
|
106
|
+
/* log fn threw an exception. All logger methods are no-ops. */
|
107
|
+
return createLogger();
|
79
108
|
}
|
109
|
+
// global exported logger uses the same functions as new logger without `id`
|
110
|
+
keys.forEach((key) => {
|
111
|
+
exportedLogger[key] = getLoggerFn(key, debugConfig);
|
112
|
+
});
|
80
113
|
} else {
|
81
|
-
|
114
|
+
// Reset global exported logger
|
115
|
+
Object.assign(exportedLogger, newLogger);
|
82
116
|
}
|
117
|
+
return newLogger;
|
83
118
|
}
|
84
119
|
|
85
120
|
export const logger: ILogger = exportedLogger;
|
package/src/utils/mp4-tools.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { ElementaryStreamTypes } from '../loader/fragment';
|
2
2
|
import { sliceUint8 } from './typed-array';
|
3
|
-
import { utf8ArrayToStr } from '
|
3
|
+
import { utf8ArrayToStr } from '@svta/common-media-library/utils/utf8ArrayToStr';
|
4
4
|
import { logger } from '../utils/logger';
|
5
5
|
import Hex from './hex';
|
6
6
|
import type { PassthroughTrack, UserdataSample } from '../types/demuxer';
|
@@ -327,7 +327,7 @@ function parseStsd(stsd: Uint8Array): { codec: string; encrypted: boolean } {
|
|
327
327
|
case 'mp4a': {
|
328
328
|
const codecBox = findBox(sampleEntries, [fourCC])[0];
|
329
329
|
const esdsBox = findBox(codecBox.subarray(28), ['esds'])[0];
|
330
|
-
if (esdsBox && esdsBox.length >
|
330
|
+
if (esdsBox && esdsBox.length > 7) {
|
331
331
|
let i = 4;
|
332
332
|
// ES Descriptor tag
|
333
333
|
if (esdsBox[i++] !== 0x03) {
|
@@ -478,7 +478,9 @@ function parseStsd(stsd: Uint8Array): { codec: string; encrypted: boolean } {
|
|
478
478
|
|
479
479
|
function skipBERInteger(bytes: Uint8Array, i: number): number {
|
480
480
|
const limit = i + 5;
|
481
|
-
while (bytes[i++] & 0x80 && i < limit) {
|
481
|
+
while (bytes[i++] & 0x80 && i < limit) {
|
482
|
+
/* do nothing */
|
483
|
+
}
|
482
484
|
return i;
|
483
485
|
}
|
484
486
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
// breaking up those two types in order to clarify what is happening in the decoding path.
|
2
|
+
type DecodedFrame<T> = { key: string; data: T; info?: any };
|
3
|
+
export type Frame = DecodedFrame<ArrayBuffer | string>;
|
4
|
+
// http://stackoverflow.com/questions/8936984/uint8array-to-string-in-javascript/22373197
|
5
|
+
// http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt
|
6
|
+
/* utf.js - UTF-8 <=> UTF-16 convertion
|
7
|
+
*
|
8
|
+
* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
|
9
|
+
* Version: 1.0
|
10
|
+
* LastModified: Dec 25 1999
|
11
|
+
* This library is free. You can redistribute it and/or modify it.
|
12
|
+
*/
|
13
|
+
|
14
|
+
export function strToUtf8array(str: string): Uint8Array {
|
15
|
+
return Uint8Array.from(unescape(encodeURIComponent(str)), (c) =>
|
16
|
+
c.charCodeAt(0),
|
17
|
+
);
|
18
|
+
}
|