hls.js 1.5.14-0.canary.10559 → 1.5.15
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 +2911 -4558
- package/dist/hls.js.d.ts +112 -186
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2291 -3311
- 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 +1813 -2835
- 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 +4707 -6356
- 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 +42 -42
- package/src/config.ts +2 -5
- package/src/controller/abr-controller.ts +25 -39
- package/src/controller/audio-stream-controller.ts +136 -156
- 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 +107 -263
- 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 +5 -5
- package/src/demux/audio/ac3-demuxer.ts +4 -5
- package/src/demux/audio/adts.ts +4 -9
- package/src/demux/audio/base-audio-demuxer.ts +15 -21
- 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/inject-worker.ts +4 -38
- package/src/demux/mp4demuxer.ts +8 -17
- package/src/demux/sample-aes.ts +0 -2
- package/src/demux/transmuxer-interface.ts +83 -106
- package/src/demux/transmuxer-worker.ts +77 -111
- package/src/demux/transmuxer.ts +22 -46
- package/src/demux/tsdemuxer.ts +65 -131
- package/src/demux/video/avc-video-parser.ts +156 -219
- package/src/demux/video/base-video-parser.ts +9 -133
- package/src/demux/video/exp-golomb.ts +208 -0
- package/src/errors.ts +0 -2
- package/src/events.ts +1 -8
- package/src/exports-named.ts +1 -1
- package/src/hls.ts +48 -97
- 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 +84 -55
- package/src/remux/passthrough-remuxer.ts +8 -23
- package/src/task-loop.ts +2 -5
- package/src/types/component-api.ts +1 -3
- package/src/types/demuxer.ts +1 -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/discontinuities.ts +47 -21
- 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/dist/hls.d.mts +0 -3179
- package/dist/hls.d.ts +0 -3179
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/demux/video/hevc-video-parser.ts +0 -718
- package/src/utils/encryption-methods-util.ts +0 -21
- package/src/utils/hash.ts +0 -10
- package/src/utils/utf8-utils.ts +0 -18
- package/src/version.ts +0 -1
package/src/demux/transmuxer.ts
CHANGED
@@ -4,31 +4,28 @@ import { ErrorTypes, ErrorDetails } from '../errors';
|
|
4
4
|
import Decrypter from '../crypt/decrypter';
|
5
5
|
import AACDemuxer from './audio/aacdemuxer';
|
6
6
|
import MP4Demuxer from '../demux/mp4demuxer';
|
7
|
-
import TSDemuxer from '../demux/tsdemuxer';
|
7
|
+
import TSDemuxer, { TypeSupported } from '../demux/tsdemuxer';
|
8
8
|
import MP3Demuxer from './audio/mp3demuxer';
|
9
9
|
import { AC3Demuxer } from './audio/ac3-demuxer';
|
10
10
|
import MP4Remuxer from '../remux/mp4-remuxer';
|
11
11
|
import PassThroughRemuxer from '../remux/passthrough-remuxer';
|
12
|
-
import {
|
13
|
-
import {
|
14
|
-
isFullSegmentEncryption,
|
15
|
-
getAesModeFromFullSegmentMethod,
|
16
|
-
} from '../utils/encryption-methods-util';
|
12
|
+
import { logger } from '../utils/logger';
|
17
13
|
import type { Demuxer, DemuxerResult, KeyData } from '../types/demuxer';
|
18
14
|
import type { Remuxer } from '../types/remuxer';
|
19
15
|
import type { TransmuxerResult, ChunkMetadata } from '../types/transmuxer';
|
20
16
|
import type { HlsConfig } from '../config';
|
21
17
|
import type { DecryptData } from '../loader/level-key';
|
22
|
-
import type {
|
23
|
-
import type { ILogger } from '../utils/logger';
|
18
|
+
import type { PlaylistLevelType } from '../types/loader';
|
24
19
|
import type { RationalTimestamp } from '../utils/timescale-conversion';
|
20
|
+
import { optionalSelf } from '../utils/global';
|
25
21
|
|
26
|
-
let now
|
22
|
+
let now;
|
27
23
|
// performance.now() not available on WebWorker, at least on Safari Desktop
|
28
24
|
try {
|
29
25
|
now = self.performance.now.bind(self.performance);
|
30
26
|
} catch (err) {
|
31
|
-
|
27
|
+
logger.debug('Unable to use Performance API on this environment');
|
28
|
+
now = optionalSelf?.Date.now;
|
32
29
|
}
|
33
30
|
|
34
31
|
type MuxConfig =
|
@@ -50,11 +47,11 @@ if (__USE_M2TS_ADVANCED_CODECS__) {
|
|
50
47
|
}
|
51
48
|
|
52
49
|
export default class Transmuxer {
|
53
|
-
|
54
|
-
private logger: ILogger;
|
50
|
+
public async: boolean = false;
|
55
51
|
private observer: HlsEventEmitter;
|
56
52
|
private typeSupported: TypeSupported;
|
57
53
|
private config: HlsConfig;
|
54
|
+
private vendor: string;
|
58
55
|
private id: PlaylistLevelType;
|
59
56
|
private demuxer?: Demuxer;
|
60
57
|
private remuxer?: Remuxer;
|
@@ -70,13 +67,12 @@ export default class Transmuxer {
|
|
70
67
|
config: HlsConfig,
|
71
68
|
vendor: string,
|
72
69
|
id: PlaylistLevelType,
|
73
|
-
logger: ILogger,
|
74
70
|
) {
|
75
71
|
this.observer = observer;
|
76
72
|
this.typeSupported = typeSupported;
|
77
73
|
this.config = config;
|
74
|
+
this.vendor = vendor;
|
78
75
|
this.id = id;
|
79
|
-
this.logger = logger;
|
80
76
|
}
|
81
77
|
|
82
78
|
configure(transmuxConfig: TransmuxConfig) {
|
@@ -118,10 +114,8 @@ export default class Transmuxer {
|
|
118
114
|
} = transmuxConfig;
|
119
115
|
|
120
116
|
const keyData = getEncryptionType(uintData, decryptdata);
|
121
|
-
if (keyData &&
|
117
|
+
if (keyData && keyData.method === 'AES-128') {
|
122
118
|
const decrypter = this.getDecrypter();
|
123
|
-
const aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
124
|
-
|
125
119
|
// Software decryption is synchronous; webCrypto is not
|
126
120
|
if (decrypter.isSync()) {
|
127
121
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
@@ -130,7 +124,6 @@ export default class Transmuxer {
|
|
130
124
|
uintData,
|
131
125
|
keyData.key.buffer,
|
132
126
|
keyData.iv.buffer,
|
133
|
-
aesMode,
|
134
127
|
);
|
135
128
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
136
129
|
const loadingParts = chunkMeta.part > -1;
|
@@ -143,14 +136,8 @@ export default class Transmuxer {
|
|
143
136
|
}
|
144
137
|
uintData = new Uint8Array(decryptedData);
|
145
138
|
} else {
|
146
|
-
this.asyncResult = true;
|
147
139
|
this.decryptionPromise = decrypter
|
148
|
-
.webCryptoDecrypt(
|
149
|
-
uintData,
|
150
|
-
keyData.key.buffer,
|
151
|
-
keyData.iv.buffer,
|
152
|
-
aesMode,
|
153
|
-
)
|
140
|
+
.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer)
|
154
141
|
.then((decryptedData): TransmuxerResult => {
|
155
142
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
156
143
|
// the decrypted data has been transmuxed
|
@@ -162,7 +149,7 @@ export default class Transmuxer {
|
|
162
149
|
this.decryptionPromise = null;
|
163
150
|
return result;
|
164
151
|
});
|
165
|
-
return this.decryptionPromise
|
152
|
+
return this.decryptionPromise!;
|
166
153
|
}
|
167
154
|
}
|
168
155
|
|
@@ -170,7 +157,7 @@ export default class Transmuxer {
|
|
170
157
|
if (resetMuxers) {
|
171
158
|
const error = this.configureTransmuxer(uintData);
|
172
159
|
if (error) {
|
173
|
-
|
160
|
+
logger.warn(`[transmuxer] ${error.message}`);
|
174
161
|
this.observer.emit(Events.ERROR, Events.ERROR, {
|
175
162
|
type: ErrorTypes.MEDIA_ERROR,
|
176
163
|
details: ErrorDetails.FRAG_PARSING_ERROR,
|
@@ -208,8 +195,6 @@ export default class Transmuxer {
|
|
208
195
|
accurateTimeOffset,
|
209
196
|
chunkMeta,
|
210
197
|
);
|
211
|
-
this.asyncResult = isPromise(result);
|
212
|
-
|
213
198
|
const currentState = this.currentTransmuxState;
|
214
199
|
|
215
200
|
currentState.contiguous = true;
|
@@ -230,7 +215,6 @@ export default class Transmuxer {
|
|
230
215
|
const { decrypter, currentTransmuxState, decryptionPromise } = this;
|
231
216
|
|
232
217
|
if (decryptionPromise) {
|
233
|
-
this.asyncResult = true;
|
234
218
|
// Upon resolution, the decryption promise calls push() and returns its TransmuxerResult up the stack. Therefore
|
235
219
|
// only flushing is required for async decryption
|
236
220
|
return decryptionPromise.then(() => {
|
@@ -257,16 +241,11 @@ export default class Transmuxer {
|
|
257
241
|
if (!demuxer || !remuxer) {
|
258
242
|
// If probing failed, then Hls.js has been given content its not able to handle
|
259
243
|
stats.executeEnd = now();
|
260
|
-
|
261
|
-
if (this.asyncResult) {
|
262
|
-
return Promise.resolve(emptyResults);
|
263
|
-
}
|
264
|
-
return emptyResults;
|
244
|
+
return [emptyResult(chunkMeta)];
|
265
245
|
}
|
266
246
|
|
267
247
|
const demuxResultOrPromise = demuxer.flush(timeOffset);
|
268
248
|
if (isPromise(demuxResultOrPromise)) {
|
269
|
-
this.asyncResult = true;
|
270
249
|
// Decrypt final SAMPLE-AES samples
|
271
250
|
return demuxResultOrPromise.then((demuxResult) => {
|
272
251
|
this.flushRemux(transmuxResults, demuxResult, chunkMeta);
|
@@ -275,9 +254,6 @@ export default class Transmuxer {
|
|
275
254
|
}
|
276
255
|
|
277
256
|
this.flushRemux(transmuxResults, demuxResultOrPromise, chunkMeta);
|
278
|
-
if (this.asyncResult) {
|
279
|
-
return Promise.resolve(transmuxResults);
|
280
|
-
}
|
281
257
|
return transmuxResults;
|
282
258
|
}
|
283
259
|
|
@@ -288,10 +264,10 @@ export default class Transmuxer {
|
|
288
264
|
) {
|
289
265
|
const { audioTrack, videoTrack, id3Track, textTrack } = demuxResult;
|
290
266
|
const { accurateTimeOffset, timeOffset } = this.currentTransmuxState;
|
291
|
-
|
292
|
-
`[transmuxer.ts]: Flushed
|
267
|
+
logger.log(
|
268
|
+
`[transmuxer.ts]: Flushed fragment ${chunkMeta.sn}${
|
293
269
|
chunkMeta.part > -1 ? ' p: ' + chunkMeta.part : ''
|
294
|
-
} of
|
270
|
+
} of level ${chunkMeta.level}`,
|
295
271
|
);
|
296
272
|
const remuxResult = this.remuxer!.remux(
|
297
273
|
audioTrack,
|
@@ -445,11 +421,11 @@ export default class Transmuxer {
|
|
445
421
|
}
|
446
422
|
|
447
423
|
private configureTransmuxer(data: Uint8Array): void | Error {
|
448
|
-
const { config, observer, typeSupported } = this;
|
424
|
+
const { config, observer, typeSupported, vendor } = this;
|
449
425
|
// probe for content type
|
450
426
|
let mux;
|
451
427
|
for (let i = 0, len = muxConfig.length; i < len; i++) {
|
452
|
-
if (muxConfig[i].demux?.probe(data
|
428
|
+
if (muxConfig[i].demux?.probe(data)) {
|
453
429
|
mux = muxConfig[i];
|
454
430
|
break;
|
455
431
|
}
|
@@ -463,10 +439,10 @@ export default class Transmuxer {
|
|
463
439
|
const Remuxer: MuxConfig['remux'] = mux.remux;
|
464
440
|
const Demuxer: MuxConfig['demux'] = mux.demux;
|
465
441
|
if (!remuxer || !(remuxer instanceof Remuxer)) {
|
466
|
-
this.remuxer = new Remuxer(observer, config, typeSupported,
|
442
|
+
this.remuxer = new Remuxer(observer, config, typeSupported, vendor);
|
467
443
|
}
|
468
444
|
if (!demuxer || !(demuxer instanceof Demuxer)) {
|
469
|
-
this.demuxer = new Demuxer(observer, config, typeSupported
|
445
|
+
this.demuxer = new Demuxer(observer, config, typeSupported);
|
470
446
|
this.probe = Demuxer.probe;
|
471
447
|
}
|
472
448
|
}
|
package/src/demux/tsdemuxer.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* highly optimized TS demuxer:
|
3
3
|
* parse PAT, PMT
|
4
4
|
* extract PES packet from audio and video PIDs
|
5
|
-
* extract AVC/H264
|
5
|
+
* extract AVC/H264 NAL units and AAC/ADTS samples from PES packet
|
6
6
|
* trigger the remuxer upon parsing completion
|
7
7
|
* it also tries to workaround as best as it can audio codec switch (HE-AAC to AAC and vice versa), without having to restart the MediaSource.
|
8
8
|
* it also controls the remuxing process :
|
@@ -12,31 +12,28 @@
|
|
12
12
|
import * as ADTS from './audio/adts';
|
13
13
|
import * as MpegAudio from './audio/mpegaudio';
|
14
14
|
import * as AC3 from './audio/ac3-demuxer';
|
15
|
-
import BaseVideoParser from './video/base-video-parser';
|
16
15
|
import AvcVideoParser from './video/avc-video-parser';
|
17
|
-
import HevcVideoParser from './video/hevc-video-parser';
|
18
16
|
import SampleAesDecrypter from './sample-aes';
|
19
17
|
import { Events } from '../events';
|
20
18
|
import { appendUint8Array, RemuxerTrackIdConfig } from '../utils/mp4-tools';
|
19
|
+
import { logger } from '../utils/logger';
|
21
20
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
22
21
|
import type { HlsConfig } from '../config';
|
23
22
|
import type { HlsEventEmitter } from '../events';
|
24
|
-
import type { TypeSupported } from '../utils/codecs';
|
25
|
-
import type { ILogger } from '../utils/logger';
|
26
23
|
import {
|
24
|
+
DemuxedVideoTrack,
|
25
|
+
DemuxedAudioTrack,
|
26
|
+
DemuxedTrack,
|
27
|
+
Demuxer,
|
28
|
+
DemuxerResult,
|
29
|
+
VideoSample,
|
30
|
+
DemuxedMetadataTrack,
|
31
|
+
DemuxedUserdataTrack,
|
32
|
+
ElementaryStreamData,
|
33
|
+
KeyData,
|
27
34
|
MetadataSchema,
|
28
|
-
type DemuxedVideoTrack,
|
29
|
-
type DemuxedAudioTrack,
|
30
|
-
type DemuxedTrack,
|
31
|
-
type Demuxer,
|
32
|
-
type DemuxerResult,
|
33
|
-
type VideoSample,
|
34
|
-
type DemuxedMetadataTrack,
|
35
|
-
type DemuxedUserdataTrack,
|
36
|
-
type ElementaryStreamData,
|
37
|
-
type KeyData,
|
38
35
|
} from '../types/demuxer';
|
39
|
-
import
|
36
|
+
import { AudioFrame } from '../types/demuxer';
|
40
37
|
|
41
38
|
export type ParsedTimestamp = {
|
42
39
|
pts?: number;
|
@@ -51,18 +48,24 @@ export type PES = ParsedTimestamp & {
|
|
51
48
|
export type ParsedVideoSample = ParsedTimestamp &
|
52
49
|
Omit<VideoSample, 'pts' | 'dts'>;
|
53
50
|
|
51
|
+
export interface TypeSupported {
|
52
|
+
mpeg: boolean;
|
53
|
+
mp3: boolean;
|
54
|
+
ac3: boolean;
|
55
|
+
}
|
56
|
+
|
54
57
|
const PACKET_LENGTH = 188;
|
55
58
|
|
56
59
|
class TSDemuxer implements Demuxer {
|
57
|
-
private readonly logger: ILogger;
|
58
60
|
private readonly observer: HlsEventEmitter;
|
59
61
|
private readonly config: HlsConfig;
|
60
|
-
private
|
62
|
+
private typeSupported: TypeSupported;
|
61
63
|
|
62
64
|
private sampleAes: SampleAesDecrypter | null = null;
|
63
65
|
private pmtParsed: boolean = false;
|
64
66
|
private audioCodec?: string;
|
65
67
|
private videoCodec?: string;
|
68
|
+
private _duration: number = 0;
|
66
69
|
private _pmtId: number = -1;
|
67
70
|
|
68
71
|
private _videoTrack?: DemuxedVideoTrack;
|
@@ -71,22 +74,20 @@ class TSDemuxer implements Demuxer {
|
|
71
74
|
private _txtTrack?: DemuxedUserdataTrack;
|
72
75
|
private aacOverFlow: AudioFrame | null = null;
|
73
76
|
private remainderData: Uint8Array | null = null;
|
74
|
-
private videoParser:
|
77
|
+
private videoParser: AvcVideoParser;
|
75
78
|
|
76
79
|
constructor(
|
77
80
|
observer: HlsEventEmitter,
|
78
81
|
config: HlsConfig,
|
79
82
|
typeSupported: TypeSupported,
|
80
|
-
logger: ILogger,
|
81
83
|
) {
|
82
84
|
this.observer = observer;
|
83
85
|
this.config = config;
|
84
86
|
this.typeSupported = typeSupported;
|
85
|
-
this.
|
86
|
-
this.videoParser = null;
|
87
|
+
this.videoParser = new AvcVideoParser();
|
87
88
|
}
|
88
89
|
|
89
|
-
static probe(data: Uint8Array
|
90
|
+
static probe(data: Uint8Array) {
|
90
91
|
const syncOffset = TSDemuxer.syncOffset(data);
|
91
92
|
if (syncOffset > 0) {
|
92
93
|
logger.warn(
|
@@ -181,7 +182,6 @@ class TSDemuxer implements Demuxer {
|
|
181
182
|
this._pmtId = -1;
|
182
183
|
|
183
184
|
this._videoTrack = TSDemuxer.createTrack('video') as DemuxedVideoTrack;
|
184
|
-
this._videoTrack.duration = trackDuration;
|
185
185
|
this._audioTrack = TSDemuxer.createTrack(
|
186
186
|
'audio',
|
187
187
|
trackDuration,
|
@@ -195,6 +195,7 @@ class TSDemuxer implements Demuxer {
|
|
195
195
|
this.remainderData = null;
|
196
196
|
this.audioCodec = audioCodec;
|
197
197
|
this.videoCodec = videoCodec;
|
198
|
+
this._duration = trackDuration;
|
198
199
|
}
|
199
200
|
|
200
201
|
public resetTimeStamp() {}
|
@@ -290,22 +291,14 @@ class TSDemuxer implements Demuxer {
|
|
290
291
|
switch (pid) {
|
291
292
|
case videoPid:
|
292
293
|
if (stt) {
|
293
|
-
if (videoData && (pes = parsePES(videoData
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
this.videoParser = new HevcVideoParser();
|
302
|
-
}
|
303
|
-
break;
|
304
|
-
}
|
305
|
-
}
|
306
|
-
if (this.videoParser !== null) {
|
307
|
-
this.videoParser.parsePES(videoTrack, textTrack, pes, false);
|
308
|
-
}
|
294
|
+
if (videoData && (pes = parsePES(videoData))) {
|
295
|
+
this.videoParser.parseAVCPES(
|
296
|
+
videoTrack,
|
297
|
+
textTrack,
|
298
|
+
pes,
|
299
|
+
false,
|
300
|
+
this._duration,
|
301
|
+
);
|
309
302
|
}
|
310
303
|
|
311
304
|
videoData = { data: [], size: 0 };
|
@@ -317,7 +310,7 @@ class TSDemuxer implements Demuxer {
|
|
317
310
|
break;
|
318
311
|
case audioPid:
|
319
312
|
if (stt) {
|
320
|
-
if (audioData && (pes = parsePES(audioData
|
313
|
+
if (audioData && (pes = parsePES(audioData))) {
|
321
314
|
switch (audioTrack.segmentCodec) {
|
322
315
|
case 'aac':
|
323
316
|
this.parseAACPES(audioTrack, pes);
|
@@ -341,7 +334,7 @@ class TSDemuxer implements Demuxer {
|
|
341
334
|
break;
|
342
335
|
case id3Pid:
|
343
336
|
if (stt) {
|
344
|
-
if (id3Data && (pes = parsePES(id3Data
|
337
|
+
if (id3Data && (pes = parsePES(id3Data))) {
|
345
338
|
this.parseID3PES(id3Track, pes);
|
346
339
|
}
|
347
340
|
|
@@ -358,7 +351,7 @@ class TSDemuxer implements Demuxer {
|
|
358
351
|
}
|
359
352
|
|
360
353
|
pmtId = this._pmtId = parsePAT(data, offset);
|
361
|
-
//
|
354
|
+
// logger.log('PMT PID:' + this._pmtId);
|
362
355
|
break;
|
363
356
|
case pmtId: {
|
364
357
|
if (stt) {
|
@@ -371,7 +364,6 @@ class TSDemuxer implements Demuxer {
|
|
371
364
|
this.typeSupported,
|
372
365
|
isSampleAes,
|
373
366
|
this.observer,
|
374
|
-
this.logger,
|
375
367
|
);
|
376
368
|
|
377
369
|
// only update track id if track PID found while parsing PMT
|
@@ -397,7 +389,7 @@ class TSDemuxer implements Demuxer {
|
|
397
389
|
}
|
398
390
|
|
399
391
|
if (unknownPID !== null && !pmtParsed) {
|
400
|
-
|
392
|
+
logger.warn(
|
401
393
|
`MPEG-TS PMT found at ${start} after unknown PID '${unknownPID}'. Backtracking to sync byte @${syncOffset} to parse all TS packets.`,
|
402
394
|
);
|
403
395
|
unknownPID = null;
|
@@ -425,8 +417,6 @@ class TSDemuxer implements Demuxer {
|
|
425
417
|
new Error(
|
426
418
|
`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`,
|
427
419
|
),
|
428
|
-
undefined,
|
429
|
-
this.logger,
|
430
420
|
);
|
431
421
|
}
|
432
422
|
|
@@ -476,34 +466,21 @@ class TSDemuxer implements Demuxer {
|
|
476
466
|
const id3Data = id3Track.pesData;
|
477
467
|
// try to parse last PES packets
|
478
468
|
let pes: PES | null;
|
479
|
-
if (videoData && (pes = parsePES(videoData
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
}
|
489
|
-
break;
|
490
|
-
}
|
491
|
-
}
|
492
|
-
if (this.videoParser !== null) {
|
493
|
-
this.videoParser.parsePES(
|
494
|
-
videoTrack as DemuxedVideoTrack,
|
495
|
-
textTrack as DemuxedUserdataTrack,
|
496
|
-
pes,
|
497
|
-
true,
|
498
|
-
);
|
499
|
-
videoTrack.pesData = null;
|
500
|
-
}
|
469
|
+
if (videoData && (pes = parsePES(videoData))) {
|
470
|
+
this.videoParser.parseAVCPES(
|
471
|
+
videoTrack as DemuxedVideoTrack,
|
472
|
+
textTrack as DemuxedUserdataTrack,
|
473
|
+
pes,
|
474
|
+
true,
|
475
|
+
this._duration,
|
476
|
+
);
|
477
|
+
videoTrack.pesData = null;
|
501
478
|
} else {
|
502
479
|
// either avcData null or PES truncated, keep it for next frag parsing
|
503
480
|
videoTrack.pesData = videoData;
|
504
481
|
}
|
505
482
|
|
506
|
-
if (audioData && (pes = parsePES(audioData
|
483
|
+
if (audioData && (pes = parsePES(audioData))) {
|
507
484
|
switch (audioTrack.segmentCodec) {
|
508
485
|
case 'aac':
|
509
486
|
this.parseAACPES(audioTrack, pes);
|
@@ -520,7 +497,7 @@ class TSDemuxer implements Demuxer {
|
|
520
497
|
audioTrack.pesData = null;
|
521
498
|
} else {
|
522
499
|
if (audioData?.size) {
|
523
|
-
|
500
|
+
logger.log(
|
524
501
|
'last AAC PES packet truncated,might overlap between fragments',
|
525
502
|
);
|
526
503
|
}
|
@@ -529,7 +506,7 @@ class TSDemuxer implements Demuxer {
|
|
529
506
|
audioTrack.pesData = audioData;
|
530
507
|
}
|
531
508
|
|
532
|
-
if (id3Data && (pes = parsePES(id3Data
|
509
|
+
if (id3Data && (pes = parsePES(id3Data))) {
|
533
510
|
this.parseID3PES(id3Track, pes);
|
534
511
|
id3Track.pesData = null;
|
535
512
|
} else {
|
@@ -582,21 +559,7 @@ class TSDemuxer implements Demuxer {
|
|
582
559
|
}
|
583
560
|
|
584
561
|
public destroy() {
|
585
|
-
|
586
|
-
this.observer.removeAllListeners();
|
587
|
-
}
|
588
|
-
// @ts-ignore
|
589
|
-
this.config = this.logger = this.observer = null;
|
590
|
-
this.aacOverFlow =
|
591
|
-
this.videoParser =
|
592
|
-
this.remainderData =
|
593
|
-
this.sampleAes =
|
594
|
-
null;
|
595
|
-
this._videoTrack =
|
596
|
-
this._audioTrack =
|
597
|
-
this._id3Track =
|
598
|
-
this._txtTrack =
|
599
|
-
undefined;
|
562
|
+
this._duration = 0;
|
600
563
|
}
|
601
564
|
|
602
565
|
private parseAACPES(track: DemuxedAudioTrack, pes: PES) {
|
@@ -637,12 +600,7 @@ class TSDemuxer implements Demuxer {
|
|
637
600
|
} else {
|
638
601
|
reason = 'No ADTS header found in AAC PES';
|
639
602
|
}
|
640
|
-
emitParsingError(
|
641
|
-
this.observer,
|
642
|
-
new Error(reason),
|
643
|
-
recoverable,
|
644
|
-
this.logger,
|
645
|
-
);
|
603
|
+
emitParsingError(this.observer, new Error(reason), recoverable);
|
646
604
|
if (!recoverable) {
|
647
605
|
return;
|
648
606
|
}
|
@@ -665,7 +623,7 @@ class TSDemuxer implements Demuxer {
|
|
665
623
|
const frameDuration = ADTS.getFrameDuration(track.samplerate as number);
|
666
624
|
pts = aacOverFlow.sample.pts + frameDuration;
|
667
625
|
} else {
|
668
|
-
|
626
|
+
logger.warn('[tsdemuxer]: AAC PES unknown PTS');
|
669
627
|
return;
|
670
628
|
}
|
671
629
|
|
@@ -696,7 +654,7 @@ class TSDemuxer implements Demuxer {
|
|
696
654
|
let offset = 0;
|
697
655
|
const pts = pes.pts;
|
698
656
|
if (pts === undefined) {
|
699
|
-
|
657
|
+
logger.warn('[tsdemuxer]: MPEG PES unknown PTS');
|
700
658
|
return;
|
701
659
|
}
|
702
660
|
|
@@ -728,7 +686,7 @@ class TSDemuxer implements Demuxer {
|
|
728
686
|
const data = pes.data;
|
729
687
|
const pts = pes.pts;
|
730
688
|
if (pts === undefined) {
|
731
|
-
|
689
|
+
logger.warn('[tsdemuxer]: AC3 PES unknown PTS');
|
732
690
|
return;
|
733
691
|
}
|
734
692
|
const length = data.length;
|
@@ -747,7 +705,7 @@ class TSDemuxer implements Demuxer {
|
|
747
705
|
|
748
706
|
private parseID3PES(id3Track: DemuxedMetadataTrack, pes: PES) {
|
749
707
|
if (pes.pts === undefined) {
|
750
|
-
|
708
|
+
logger.warn('[tsdemuxer]: ID3 PES unknown PTS');
|
751
709
|
return;
|
752
710
|
}
|
753
711
|
const id3Sample = Object.assign({}, pes as Required<PES>, {
|
@@ -774,7 +732,6 @@ function parsePMT(
|
|
774
732
|
typeSupported: TypeSupported,
|
775
733
|
isSampleAes: boolean,
|
776
734
|
observer: HlsEventEmitter,
|
777
|
-
logger: ILogger,
|
778
735
|
) {
|
779
736
|
const result = {
|
780
737
|
audioPid: -1,
|
@@ -797,7 +754,7 @@ function parsePMT(
|
|
797
754
|
switch (data[offset]) {
|
798
755
|
case 0xcf: // SAMPLE-AES AAC
|
799
756
|
if (!isSampleAes) {
|
800
|
-
logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC'
|
757
|
+
logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC');
|
801
758
|
break;
|
802
759
|
}
|
803
760
|
/* falls through */
|
@@ -820,7 +777,7 @@ function parsePMT(
|
|
820
777
|
|
821
778
|
case 0xdb: // SAMPLE-AES AVC
|
822
779
|
if (!isSampleAes) {
|
823
|
-
logEncryptedSamplesFoundInUnencryptedStream('H.264'
|
780
|
+
logEncryptedSamplesFoundInUnencryptedStream('H.264');
|
824
781
|
break;
|
825
782
|
}
|
826
783
|
/* falls through */
|
@@ -848,7 +805,7 @@ function parsePMT(
|
|
848
805
|
|
849
806
|
case 0xc1: // SAMPLE-AES AC3
|
850
807
|
if (!isSampleAes) {
|
851
|
-
logEncryptedSamplesFoundInUnencryptedStream('AC-3'
|
808
|
+
logEncryptedSamplesFoundInUnencryptedStream('AC-3');
|
852
809
|
break;
|
853
810
|
}
|
854
811
|
/* falls through */
|
@@ -904,31 +861,12 @@ function parsePMT(
|
|
904
861
|
case 0xc2: // SAMPLE-AES EC3
|
905
862
|
/* falls through */
|
906
863
|
case 0x87:
|
907
|
-
emitParsingError(
|
908
|
-
observer,
|
909
|
-
new Error('Unsupported EC-3 in M2TS found'),
|
910
|
-
undefined,
|
911
|
-
logger,
|
912
|
-
);
|
864
|
+
emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'));
|
913
865
|
return result;
|
914
866
|
|
915
|
-
case 0x24:
|
916
|
-
|
917
|
-
|
918
|
-
result.videoPid = pid;
|
919
|
-
result.segmentVideoCodec = 'hevc';
|
920
|
-
logger.log('HEVC in M2TS found');
|
921
|
-
}
|
922
|
-
} else {
|
923
|
-
emitParsingError(
|
924
|
-
observer,
|
925
|
-
new Error('Unsupported HEVC in M2TS found'),
|
926
|
-
undefined,
|
927
|
-
logger,
|
928
|
-
);
|
929
|
-
return result;
|
930
|
-
}
|
931
|
-
break;
|
867
|
+
case 0x24:
|
868
|
+
emitParsingError(observer, new Error('Unsupported HEVC in M2TS found'));
|
869
|
+
return result;
|
932
870
|
|
933
871
|
default:
|
934
872
|
// logger.log('unknown stream type:' + data[offset]);
|
@@ -944,8 +882,7 @@ function parsePMT(
|
|
944
882
|
function emitParsingError(
|
945
883
|
observer: HlsEventEmitter,
|
946
884
|
error: Error,
|
947
|
-
levelRetry
|
948
|
-
logger: ILogger,
|
885
|
+
levelRetry?: boolean,
|
949
886
|
) {
|
950
887
|
logger.warn(`parsing error: ${error.message}`);
|
951
888
|
observer.emit(Events.ERROR, Events.ERROR, {
|
@@ -958,14 +895,11 @@ function emitParsingError(
|
|
958
895
|
});
|
959
896
|
}
|
960
897
|
|
961
|
-
function logEncryptedSamplesFoundInUnencryptedStream(
|
962
|
-
type: string,
|
963
|
-
logger: ILogger,
|
964
|
-
) {
|
898
|
+
function logEncryptedSamplesFoundInUnencryptedStream(type: string) {
|
965
899
|
logger.log(`${type} with AES-128-CBC encryption found in unencrypted stream`);
|
966
900
|
}
|
967
901
|
|
968
|
-
function parsePES(stream: ElementaryStreamData
|
902
|
+
function parsePES(stream: ElementaryStreamData): PES | null {
|
969
903
|
let i = 0;
|
970
904
|
let frag: Uint8Array;
|
971
905
|
let pesLen: number;
|