hls.js 1.5.14-0.canary.10515 → 1.5.14
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 +2903 -4542
- package/dist/hls.js.d.ts +112 -186
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2284 -3295
- 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 +1804 -2817
- 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 +4652 -6293
- 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 +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 +98 -252
- 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 +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/inject-worker.ts +4 -38
- package/src/demux/mp4demuxer.ts +7 -7
- 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 +62 -122
- 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/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 +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/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/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
- 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,13 +48,18 @@ 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;
|
@@ -72,22 +74,20 @@ class TSDemuxer implements Demuxer {
|
|
72
74
|
private _txtTrack?: DemuxedUserdataTrack;
|
73
75
|
private aacOverFlow: AudioFrame | null = null;
|
74
76
|
private remainderData: Uint8Array | null = null;
|
75
|
-
private videoParser:
|
77
|
+
private videoParser: AvcVideoParser;
|
76
78
|
|
77
79
|
constructor(
|
78
80
|
observer: HlsEventEmitter,
|
79
81
|
config: HlsConfig,
|
80
82
|
typeSupported: TypeSupported,
|
81
|
-
logger: ILogger,
|
82
83
|
) {
|
83
84
|
this.observer = observer;
|
84
85
|
this.config = config;
|
85
86
|
this.typeSupported = typeSupported;
|
86
|
-
this.
|
87
|
-
this.videoParser = null;
|
87
|
+
this.videoParser = new AvcVideoParser();
|
88
88
|
}
|
89
89
|
|
90
|
-
static probe(data: Uint8Array
|
90
|
+
static probe(data: Uint8Array) {
|
91
91
|
const syncOffset = TSDemuxer.syncOffset(data);
|
92
92
|
if (syncOffset > 0) {
|
93
93
|
logger.warn(
|
@@ -291,28 +291,14 @@ class TSDemuxer implements Demuxer {
|
|
291
291
|
switch (pid) {
|
292
292
|
case videoPid:
|
293
293
|
if (stt) {
|
294
|
-
if (videoData && (pes = parsePES(videoData
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
this.videoParser = new HevcVideoParser();
|
303
|
-
}
|
304
|
-
break;
|
305
|
-
}
|
306
|
-
}
|
307
|
-
if (this.videoParser !== null) {
|
308
|
-
this.videoParser.parsePES(
|
309
|
-
videoTrack,
|
310
|
-
textTrack,
|
311
|
-
pes,
|
312
|
-
false,
|
313
|
-
this._duration,
|
314
|
-
);
|
315
|
-
}
|
294
|
+
if (videoData && (pes = parsePES(videoData))) {
|
295
|
+
this.videoParser.parseAVCPES(
|
296
|
+
videoTrack,
|
297
|
+
textTrack,
|
298
|
+
pes,
|
299
|
+
false,
|
300
|
+
this._duration,
|
301
|
+
);
|
316
302
|
}
|
317
303
|
|
318
304
|
videoData = { data: [], size: 0 };
|
@@ -324,7 +310,7 @@ class TSDemuxer implements Demuxer {
|
|
324
310
|
break;
|
325
311
|
case audioPid:
|
326
312
|
if (stt) {
|
327
|
-
if (audioData && (pes = parsePES(audioData
|
313
|
+
if (audioData && (pes = parsePES(audioData))) {
|
328
314
|
switch (audioTrack.segmentCodec) {
|
329
315
|
case 'aac':
|
330
316
|
this.parseAACPES(audioTrack, pes);
|
@@ -348,7 +334,7 @@ class TSDemuxer implements Demuxer {
|
|
348
334
|
break;
|
349
335
|
case id3Pid:
|
350
336
|
if (stt) {
|
351
|
-
if (id3Data && (pes = parsePES(id3Data
|
337
|
+
if (id3Data && (pes = parsePES(id3Data))) {
|
352
338
|
this.parseID3PES(id3Track, pes);
|
353
339
|
}
|
354
340
|
|
@@ -365,7 +351,7 @@ class TSDemuxer implements Demuxer {
|
|
365
351
|
}
|
366
352
|
|
367
353
|
pmtId = this._pmtId = parsePAT(data, offset);
|
368
|
-
//
|
354
|
+
// logger.log('PMT PID:' + this._pmtId);
|
369
355
|
break;
|
370
356
|
case pmtId: {
|
371
357
|
if (stt) {
|
@@ -378,7 +364,6 @@ class TSDemuxer implements Demuxer {
|
|
378
364
|
this.typeSupported,
|
379
365
|
isSampleAes,
|
380
366
|
this.observer,
|
381
|
-
this.logger,
|
382
367
|
);
|
383
368
|
|
384
369
|
// only update track id if track PID found while parsing PMT
|
@@ -404,7 +389,7 @@ class TSDemuxer implements Demuxer {
|
|
404
389
|
}
|
405
390
|
|
406
391
|
if (unknownPID !== null && !pmtParsed) {
|
407
|
-
|
392
|
+
logger.warn(
|
408
393
|
`MPEG-TS PMT found at ${start} after unknown PID '${unknownPID}'. Backtracking to sync byte @${syncOffset} to parse all TS packets.`,
|
409
394
|
);
|
410
395
|
unknownPID = null;
|
@@ -432,8 +417,6 @@ class TSDemuxer implements Demuxer {
|
|
432
417
|
new Error(
|
433
418
|
`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`,
|
434
419
|
),
|
435
|
-
undefined,
|
436
|
-
this.logger,
|
437
420
|
);
|
438
421
|
}
|
439
422
|
|
@@ -483,35 +466,21 @@ class TSDemuxer implements Demuxer {
|
|
483
466
|
const id3Data = id3Track.pesData;
|
484
467
|
// try to parse last PES packets
|
485
468
|
let pes: PES | null;
|
486
|
-
if (videoData && (pes = parsePES(videoData
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
}
|
496
|
-
break;
|
497
|
-
}
|
498
|
-
}
|
499
|
-
if (this.videoParser !== null) {
|
500
|
-
this.videoParser.parsePES(
|
501
|
-
videoTrack as DemuxedVideoTrack,
|
502
|
-
textTrack as DemuxedUserdataTrack,
|
503
|
-
pes,
|
504
|
-
true,
|
505
|
-
this._duration,
|
506
|
-
);
|
507
|
-
videoTrack.pesData = null;
|
508
|
-
}
|
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;
|
509
478
|
} else {
|
510
479
|
// either avcData null or PES truncated, keep it for next frag parsing
|
511
480
|
videoTrack.pesData = videoData;
|
512
481
|
}
|
513
482
|
|
514
|
-
if (audioData && (pes = parsePES(audioData
|
483
|
+
if (audioData && (pes = parsePES(audioData))) {
|
515
484
|
switch (audioTrack.segmentCodec) {
|
516
485
|
case 'aac':
|
517
486
|
this.parseAACPES(audioTrack, pes);
|
@@ -528,7 +497,7 @@ class TSDemuxer implements Demuxer {
|
|
528
497
|
audioTrack.pesData = null;
|
529
498
|
} else {
|
530
499
|
if (audioData?.size) {
|
531
|
-
|
500
|
+
logger.log(
|
532
501
|
'last AAC PES packet truncated,might overlap between fragments',
|
533
502
|
);
|
534
503
|
}
|
@@ -537,7 +506,7 @@ class TSDemuxer implements Demuxer {
|
|
537
506
|
audioTrack.pesData = audioData;
|
538
507
|
}
|
539
508
|
|
540
|
-
if (id3Data && (pes = parsePES(id3Data
|
509
|
+
if (id3Data && (pes = parsePES(id3Data))) {
|
541
510
|
this.parseID3PES(id3Track, pes);
|
542
511
|
id3Track.pesData = null;
|
543
512
|
} else {
|
@@ -631,12 +600,7 @@ class TSDemuxer implements Demuxer {
|
|
631
600
|
} else {
|
632
601
|
reason = 'No ADTS header found in AAC PES';
|
633
602
|
}
|
634
|
-
emitParsingError(
|
635
|
-
this.observer,
|
636
|
-
new Error(reason),
|
637
|
-
recoverable,
|
638
|
-
this.logger,
|
639
|
-
);
|
603
|
+
emitParsingError(this.observer, new Error(reason), recoverable);
|
640
604
|
if (!recoverable) {
|
641
605
|
return;
|
642
606
|
}
|
@@ -659,7 +623,7 @@ class TSDemuxer implements Demuxer {
|
|
659
623
|
const frameDuration = ADTS.getFrameDuration(track.samplerate as number);
|
660
624
|
pts = aacOverFlow.sample.pts + frameDuration;
|
661
625
|
} else {
|
662
|
-
|
626
|
+
logger.warn('[tsdemuxer]: AAC PES unknown PTS');
|
663
627
|
return;
|
664
628
|
}
|
665
629
|
|
@@ -690,7 +654,7 @@ class TSDemuxer implements Demuxer {
|
|
690
654
|
let offset = 0;
|
691
655
|
const pts = pes.pts;
|
692
656
|
if (pts === undefined) {
|
693
|
-
|
657
|
+
logger.warn('[tsdemuxer]: MPEG PES unknown PTS');
|
694
658
|
return;
|
695
659
|
}
|
696
660
|
|
@@ -722,7 +686,7 @@ class TSDemuxer implements Demuxer {
|
|
722
686
|
const data = pes.data;
|
723
687
|
const pts = pes.pts;
|
724
688
|
if (pts === undefined) {
|
725
|
-
|
689
|
+
logger.warn('[tsdemuxer]: AC3 PES unknown PTS');
|
726
690
|
return;
|
727
691
|
}
|
728
692
|
const length = data.length;
|
@@ -741,7 +705,7 @@ class TSDemuxer implements Demuxer {
|
|
741
705
|
|
742
706
|
private parseID3PES(id3Track: DemuxedMetadataTrack, pes: PES) {
|
743
707
|
if (pes.pts === undefined) {
|
744
|
-
|
708
|
+
logger.warn('[tsdemuxer]: ID3 PES unknown PTS');
|
745
709
|
return;
|
746
710
|
}
|
747
711
|
const id3Sample = Object.assign({}, pes as Required<PES>, {
|
@@ -768,7 +732,6 @@ function parsePMT(
|
|
768
732
|
typeSupported: TypeSupported,
|
769
733
|
isSampleAes: boolean,
|
770
734
|
observer: HlsEventEmitter,
|
771
|
-
logger: ILogger,
|
772
735
|
) {
|
773
736
|
const result = {
|
774
737
|
audioPid: -1,
|
@@ -791,7 +754,7 @@ function parsePMT(
|
|
791
754
|
switch (data[offset]) {
|
792
755
|
case 0xcf: // SAMPLE-AES AAC
|
793
756
|
if (!isSampleAes) {
|
794
|
-
logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC'
|
757
|
+
logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC');
|
795
758
|
break;
|
796
759
|
}
|
797
760
|
/* falls through */
|
@@ -814,7 +777,7 @@ function parsePMT(
|
|
814
777
|
|
815
778
|
case 0xdb: // SAMPLE-AES AVC
|
816
779
|
if (!isSampleAes) {
|
817
|
-
logEncryptedSamplesFoundInUnencryptedStream('H.264'
|
780
|
+
logEncryptedSamplesFoundInUnencryptedStream('H.264');
|
818
781
|
break;
|
819
782
|
}
|
820
783
|
/* falls through */
|
@@ -842,7 +805,7 @@ function parsePMT(
|
|
842
805
|
|
843
806
|
case 0xc1: // SAMPLE-AES AC3
|
844
807
|
if (!isSampleAes) {
|
845
|
-
logEncryptedSamplesFoundInUnencryptedStream('AC-3'
|
808
|
+
logEncryptedSamplesFoundInUnencryptedStream('AC-3');
|
846
809
|
break;
|
847
810
|
}
|
848
811
|
/* falls through */
|
@@ -898,31 +861,12 @@ function parsePMT(
|
|
898
861
|
case 0xc2: // SAMPLE-AES EC3
|
899
862
|
/* falls through */
|
900
863
|
case 0x87:
|
901
|
-
emitParsingError(
|
902
|
-
observer,
|
903
|
-
new Error('Unsupported EC-3 in M2TS found'),
|
904
|
-
undefined,
|
905
|
-
logger,
|
906
|
-
);
|
864
|
+
emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'));
|
907
865
|
return result;
|
908
866
|
|
909
|
-
case 0x24:
|
910
|
-
|
911
|
-
|
912
|
-
result.videoPid = pid;
|
913
|
-
result.segmentVideoCodec = 'hevc';
|
914
|
-
logger.log('HEVC in M2TS found');
|
915
|
-
}
|
916
|
-
} else {
|
917
|
-
emitParsingError(
|
918
|
-
observer,
|
919
|
-
new Error('Unsupported HEVC in M2TS found'),
|
920
|
-
undefined,
|
921
|
-
logger,
|
922
|
-
);
|
923
|
-
return result;
|
924
|
-
}
|
925
|
-
break;
|
867
|
+
case 0x24:
|
868
|
+
emitParsingError(observer, new Error('Unsupported HEVC in M2TS found'));
|
869
|
+
return result;
|
926
870
|
|
927
871
|
default:
|
928
872
|
// logger.log('unknown stream type:' + data[offset]);
|
@@ -938,8 +882,7 @@ function parsePMT(
|
|
938
882
|
function emitParsingError(
|
939
883
|
observer: HlsEventEmitter,
|
940
884
|
error: Error,
|
941
|
-
levelRetry
|
942
|
-
logger: ILogger,
|
885
|
+
levelRetry?: boolean,
|
943
886
|
) {
|
944
887
|
logger.warn(`parsing error: ${error.message}`);
|
945
888
|
observer.emit(Events.ERROR, Events.ERROR, {
|
@@ -952,14 +895,11 @@ function emitParsingError(
|
|
952
895
|
});
|
953
896
|
}
|
954
897
|
|
955
|
-
function logEncryptedSamplesFoundInUnencryptedStream(
|
956
|
-
type: string,
|
957
|
-
logger: ILogger,
|
958
|
-
) {
|
898
|
+
function logEncryptedSamplesFoundInUnencryptedStream(type: string) {
|
959
899
|
logger.log(`${type} with AES-128-CBC encryption found in unencrypted stream`);
|
960
900
|
}
|
961
901
|
|
962
|
-
function parsePES(stream: ElementaryStreamData
|
902
|
+
function parsePES(stream: ElementaryStreamData): PES | null {
|
963
903
|
let i = 0;
|
964
904
|
let frag: Uint8Array;
|
965
905
|
let pesLen: number;
|