hls.js 1.5.14-0.canary.10431 → 1.5.14-0.canary.10432
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 +316 -232
- package/dist/hls.js.d.ts +4 -2
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +316 -235
- 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 +244 -168
- 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 +244 -165
- 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/base-stream-controller.ts +5 -4
- package/src/demux/audio/aacdemuxer.ts +3 -3
- package/src/demux/audio/ac3-demuxer.ts +1 -1
- package/src/demux/inject-worker.ts +38 -4
- package/src/demux/transmuxer-interface.ts +98 -67
- package/src/demux/transmuxer-worker.ts +110 -76
- package/src/demux/transmuxer.ts +29 -16
- package/src/demux/tsdemuxer.ts +47 -24
- package/src/hls.ts +2 -1
- package/src/remux/mp4-remuxer.ts +24 -23
- package/src/remux/passthrough-remuxer.ts +22 -7
- package/src/version.ts +1 -0
package/src/hls.ts
CHANGED
@@ -13,6 +13,7 @@ import { enableStreamingMode, hlsDefaultConfig, mergeConfig } from './config';
|
|
13
13
|
import { EventEmitter } from 'eventemitter3';
|
14
14
|
import { Events } from './events';
|
15
15
|
import { ErrorTypes, ErrorDetails } from './errors';
|
16
|
+
import { version } from './version';
|
16
17
|
import { isHdcpLevel, type HdcpLevel, type Level } from './types/level';
|
17
18
|
import type { HlsEventEmitter, HlsListeners } from './events';
|
18
19
|
import type AudioTrackController from './controller/audio-track-controller';
|
@@ -87,7 +88,7 @@ export default class Hls implements HlsEventEmitter {
|
|
87
88
|
* Get the video-dev/hls.js package version.
|
88
89
|
*/
|
89
90
|
static get version(): string {
|
90
|
-
return
|
91
|
+
return version;
|
91
92
|
}
|
92
93
|
|
93
94
|
/**
|
package/src/remux/mp4-remuxer.ts
CHANGED
@@ -3,7 +3,6 @@ import MP4 from './mp4-generator';
|
|
3
3
|
import type { HlsEventEmitter } from '../events';
|
4
4
|
import { Events } from '../events';
|
5
5
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
6
|
-
import { logger } from '../utils/logger';
|
7
6
|
import type {
|
8
7
|
InitSegmentData,
|
9
8
|
Remuxer,
|
@@ -27,9 +26,9 @@ import type {
|
|
27
26
|
} from '../types/demuxer';
|
28
27
|
import type { TrackSet } from '../types/track';
|
29
28
|
import type { SourceBufferName } from '../types/buffer';
|
30
|
-
import type { Fragment } from '../loader/fragment';
|
31
29
|
import type { HlsConfig } from '../config';
|
32
30
|
import type { TypeSupported } from '../utils/codecs';
|
31
|
+
import type { ILogger } from '../utils/logger';
|
33
32
|
|
34
33
|
const MAX_SILENT_FRAME_DURATION = 10 * 1000; // 10 seconds
|
35
34
|
const AAC_SAMPLES_PER_FRAME = 1024;
|
@@ -40,9 +39,10 @@ let chromeVersion: number | null = null;
|
|
40
39
|
let safariWebkitVersion: number | null = null;
|
41
40
|
|
42
41
|
export default class MP4Remuxer implements Remuxer {
|
43
|
-
private
|
44
|
-
private
|
45
|
-
private
|
42
|
+
private readonly logger: ILogger;
|
43
|
+
private readonly observer: HlsEventEmitter;
|
44
|
+
private readonly config: HlsConfig;
|
45
|
+
private readonly typeSupported: TypeSupported;
|
46
46
|
private ISGenerated: boolean = false;
|
47
47
|
private _initPTS: RationalTimestamp | null = null;
|
48
48
|
private _initDTS: RationalTimestamp | null = null;
|
@@ -60,12 +60,13 @@ export default class MP4Remuxer implements Remuxer {
|
|
60
60
|
constructor(
|
61
61
|
observer: HlsEventEmitter,
|
62
62
|
config: HlsConfig,
|
63
|
-
typeSupported,
|
64
|
-
|
63
|
+
typeSupported: TypeSupported,
|
64
|
+
logger: ILogger,
|
65
65
|
) {
|
66
66
|
this.observer = observer;
|
67
67
|
this.config = config;
|
68
68
|
this.typeSupported = typeSupported;
|
69
|
+
this.logger = logger;
|
69
70
|
this.ISGenerated = false;
|
70
71
|
|
71
72
|
if (chromeVersion === null) {
|
@@ -85,18 +86,18 @@ export default class MP4Remuxer implements Remuxer {
|
|
85
86
|
}
|
86
87
|
|
87
88
|
resetTimeStamp(defaultTimeStamp: RationalTimestamp | null) {
|
88
|
-
logger.log('[mp4-remuxer]: initPTS & initDTS reset');
|
89
|
+
this.logger.log('[mp4-remuxer]: initPTS & initDTS reset');
|
89
90
|
this._initPTS = this._initDTS = defaultTimeStamp;
|
90
91
|
}
|
91
92
|
|
92
93
|
resetNextTimestamp() {
|
93
|
-
logger.log('[mp4-remuxer]: reset next timestamp');
|
94
|
+
this.logger.log('[mp4-remuxer]: reset next timestamp');
|
94
95
|
this.isVideoContiguous = false;
|
95
96
|
this.isAudioContiguous = false;
|
96
97
|
}
|
97
98
|
|
98
99
|
resetInitSegment() {
|
99
|
-
logger.log('[mp4-remuxer]: ISGenerated flag reset');
|
100
|
+
this.logger.log('[mp4-remuxer]: ISGenerated flag reset');
|
100
101
|
this.ISGenerated = false;
|
101
102
|
this.videoTrackConfig = undefined;
|
102
103
|
}
|
@@ -116,7 +117,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
116
117
|
}
|
117
118
|
}, videoSamples[0].pts);
|
118
119
|
if (rolloverDetected) {
|
119
|
-
logger.debug('PTS rollover detected');
|
120
|
+
this.logger.debug('PTS rollover detected');
|
120
121
|
}
|
121
122
|
return startPTS;
|
122
123
|
}
|
@@ -189,7 +190,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
189
190
|
if (!isVideoContiguous && this.config.forceKeyFrameOnDiscontinuity) {
|
190
191
|
independent = true;
|
191
192
|
if (firstKeyFrameIndex > 0) {
|
192
|
-
logger.warn(
|
193
|
+
this.logger.warn(
|
193
194
|
`[mp4-remuxer]: Dropped ${firstKeyFrameIndex} out of ${length} video samples due to a missing keyframe`,
|
194
195
|
);
|
195
196
|
const startPTS = this.getVideoStartPts(videoTrack.samples);
|
@@ -200,7 +201,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
200
201
|
videoTrack.inputTimeScale;
|
201
202
|
firstKeyFramePTS = videoTimeOffset;
|
202
203
|
} else if (firstKeyFrameIndex === -1) {
|
203
|
-
logger.warn(
|
204
|
+
this.logger.warn(
|
204
205
|
`[mp4-remuxer]: No keyframe found out of ${length} video samples`,
|
205
206
|
);
|
206
207
|
independent = false;
|
@@ -226,7 +227,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
226
227
|
if (enoughAudioSamples) {
|
227
228
|
// if initSegment was generated without audio samples, regenerate it again
|
228
229
|
if (!audioTrack.samplerate) {
|
229
|
-
logger.warn(
|
230
|
+
this.logger.warn(
|
230
231
|
'[mp4-remuxer]: regenerate InitSegment as audio detected',
|
231
232
|
);
|
232
233
|
initSegment = this.generateIS(
|
@@ -251,7 +252,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
251
252
|
const audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0;
|
252
253
|
// if initSegment was generated without video samples, regenerate it again
|
253
254
|
if (!videoTrack.inputTimeScale) {
|
254
|
-
logger.warn(
|
255
|
+
this.logger.warn(
|
255
256
|
'[mp4-remuxer]: regenerate InitSegment as video detected',
|
256
257
|
);
|
257
258
|
initSegment = this.generateIS(
|
@@ -518,7 +519,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
518
519
|
const foundOverlap = delta < -1;
|
519
520
|
if (foundHole || foundOverlap) {
|
520
521
|
if (foundHole) {
|
521
|
-
logger.warn(
|
522
|
+
this.logger.warn(
|
522
523
|
`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
|
523
524
|
delta,
|
524
525
|
true,
|
@@ -527,7 +528,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
527
528
|
)}`,
|
528
529
|
);
|
529
530
|
} else {
|
530
|
-
logger.warn(
|
531
|
+
this.logger.warn(
|
531
532
|
`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
|
532
533
|
-delta,
|
533
534
|
true,
|
@@ -570,7 +571,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
570
571
|
}
|
571
572
|
}
|
572
573
|
}
|
573
|
-
logger.log(
|
574
|
+
this.logger.log(
|
574
575
|
`Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(
|
575
576
|
firstPTS,
|
576
577
|
true,
|
@@ -692,7 +693,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
692
693
|
} else {
|
693
694
|
stretchedLastFrame = true;
|
694
695
|
}
|
695
|
-
logger.log(
|
696
|
+
this.logger.log(
|
696
697
|
`[mp4-remuxer]: It is approximately ${
|
697
698
|
deltaToFrameEnd / 90
|
698
699
|
} ms to the next segment; using duration ${
|
@@ -741,7 +742,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
741
742
|
averageSampleDuration / maxDtsDelta < 0.025 &&
|
742
743
|
outputSamples[0].cts === 0
|
743
744
|
) {
|
744
|
-
logger.warn(
|
745
|
+
this.logger.warn(
|
745
746
|
'Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration.',
|
746
747
|
);
|
747
748
|
let dts = firstDTS;
|
@@ -904,7 +905,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
904
905
|
alignedWithVideo
|
905
906
|
) {
|
906
907
|
if (i === 0) {
|
907
|
-
logger.warn(
|
908
|
+
this.logger.warn(
|
908
909
|
`Audio frame @ ${(pts / inputTimeScale).toFixed(
|
909
910
|
3,
|
910
911
|
)}s overlaps nextAudioPts by ${Math.round(
|
@@ -936,7 +937,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
936
937
|
if (i === 0) {
|
937
938
|
this.nextAudioPts = nextAudioPts = nextPts;
|
938
939
|
}
|
939
|
-
logger.warn(
|
940
|
+
this.logger.warn(
|
940
941
|
`[mp4-remuxer]: Injecting ${missing} audio frame @ ${(
|
941
942
|
nextPts / inputTimeScale
|
942
943
|
).toFixed(3)}s due to ${Math.round(
|
@@ -950,7 +951,7 @@ export default class MP4Remuxer implements Remuxer {
|
|
950
951
|
track.channelCount,
|
951
952
|
);
|
952
953
|
if (!fillFrame) {
|
953
|
-
logger.log(
|
954
|
+
this.logger.log(
|
954
955
|
'[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.',
|
955
956
|
);
|
956
957
|
fillFrame = sample.unit.subarray();
|
@@ -14,8 +14,9 @@ import {
|
|
14
14
|
parseInitSegment,
|
15
15
|
} from '../utils/mp4-tools';
|
16
16
|
import { ElementaryStreamTypes } from '../loader/fragment';
|
17
|
-
import { logger } from '../utils/logger';
|
18
17
|
import { getCodecCompatibleName } from '../utils/codecs';
|
18
|
+
import type { HlsEventEmitter } from '../events';
|
19
|
+
import type { HlsConfig } from '../config';
|
19
20
|
import type { TrackSet } from '../types/track';
|
20
21
|
import type {
|
21
22
|
InitSegmentData,
|
@@ -30,9 +31,12 @@ import type {
|
|
30
31
|
PassthroughTrack,
|
31
32
|
} from '../types/demuxer';
|
32
33
|
import type { DecryptData } from '../loader/level-key';
|
34
|
+
import type { TypeSupported } from '../utils/codecs';
|
35
|
+
import type { ILogger } from '../utils/logger';
|
33
36
|
import type { RationalTimestamp } from '../utils/timescale-conversion';
|
34
37
|
|
35
38
|
class PassThroughRemuxer implements Remuxer {
|
39
|
+
private readonly logger: ILogger;
|
36
40
|
private emitInitSegment: boolean = false;
|
37
41
|
private audioCodec?: string;
|
38
42
|
private videoCodec?: string;
|
@@ -41,6 +45,15 @@ class PassThroughRemuxer implements Remuxer {
|
|
41
45
|
private initTracks?: TrackSet;
|
42
46
|
private lastEndTime: number | null = null;
|
43
47
|
|
48
|
+
constructor(
|
49
|
+
observer: HlsEventEmitter,
|
50
|
+
config: HlsConfig,
|
51
|
+
typeSupported: TypeSupported,
|
52
|
+
logger: ILogger,
|
53
|
+
) {
|
54
|
+
this.logger = logger;
|
55
|
+
}
|
56
|
+
|
44
57
|
public destroy() {}
|
45
58
|
|
46
59
|
public resetTimeStamp(defaultInitPTS: RationalTimestamp | null) {
|
@@ -111,7 +124,7 @@ class PassThroughRemuxer implements Remuxer {
|
|
111
124
|
id: 'main',
|
112
125
|
};
|
113
126
|
} else {
|
114
|
-
logger.warn(
|
127
|
+
this.logger.warn(
|
115
128
|
'[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes.',
|
116
129
|
);
|
117
130
|
}
|
@@ -160,7 +173,9 @@ class PassThroughRemuxer implements Remuxer {
|
|
160
173
|
}
|
161
174
|
if (!initData?.length) {
|
162
175
|
// We can't remux if the initSegment could not be generated
|
163
|
-
logger.warn(
|
176
|
+
this.logger.warn(
|
177
|
+
'[passthrough-remuxer.ts]: Failed to generate initSegment.',
|
178
|
+
);
|
164
179
|
return result;
|
165
180
|
}
|
166
181
|
if (this.emitInitSegment) {
|
@@ -177,7 +192,7 @@ class PassThroughRemuxer implements Remuxer {
|
|
177
192
|
) {
|
178
193
|
initSegment.initPTS = decodeTime - timeOffset;
|
179
194
|
if (initPTS && initPTS.timescale === 1) {
|
180
|
-
logger.warn(
|
195
|
+
this.logger.warn(
|
181
196
|
`Adjusting initPTS @${timeOffset} from ${initPTS.baseTime / initPTS.timescale} to ${initSegment.initPTS}`,
|
182
197
|
);
|
183
198
|
}
|
@@ -196,7 +211,7 @@ class PassThroughRemuxer implements Remuxer {
|
|
196
211
|
if (duration > 0) {
|
197
212
|
this.lastEndTime = endTime;
|
198
213
|
} else {
|
199
|
-
logger.warn('Duration parsed from mp4 should be greater than zero');
|
214
|
+
this.logger.warn('Duration parsed from mp4 should be greater than zero');
|
200
215
|
this.resetNextTimestamp();
|
201
216
|
}
|
202
217
|
|
@@ -284,14 +299,14 @@ function getParsedTrackCodec(
|
|
284
299
|
return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
|
285
300
|
}
|
286
301
|
const result = 'mp4a.40.5';
|
287
|
-
logger.info(
|
302
|
+
this.logger.info(
|
288
303
|
`Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`,
|
289
304
|
);
|
290
305
|
return result;
|
291
306
|
}
|
292
307
|
// Provide defaults based on codec type
|
293
308
|
// This allows for some playback of some fmp4 playlists without CODECS defined in manifest
|
294
|
-
logger.warn(`Unhandled video codec "${parsedCodec}"`);
|
309
|
+
this.logger.warn(`Unhandled video codec "${parsedCodec}"`);
|
295
310
|
if (parsedCodec === 'hvc1' || parsedCodec === 'hev1') {
|
296
311
|
return 'hvc1.1.6.L120.90';
|
297
312
|
}
|
package/src/version.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export const version = __VERSION__;
|