hls.js 1.5.7-0.canary.10040 → 1.5.7

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.
Files changed (72) hide show
  1. package/README.md +1 -2
  2. package/dist/hls-demo.js +0 -10
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1283 -2293
  5. package/dist/hls.js.d.ts +84 -97
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1030 -1435
  8. package/dist/hls.light.js.map +1 -1
  9. package/dist/hls.light.min.js +1 -1
  10. package/dist/hls.light.min.js.map +1 -1
  11. package/dist/hls.light.mjs +809 -1209
  12. package/dist/hls.light.mjs.map +1 -1
  13. package/dist/hls.min.js +1 -1
  14. package/dist/hls.min.js.map +1 -1
  15. package/dist/hls.mjs +1039 -2030
  16. package/dist/hls.mjs.map +1 -1
  17. package/dist/hls.worker.js +1 -1
  18. package/dist/hls.worker.js.map +1 -1
  19. package/package.json +22 -22
  20. package/src/config.ts +2 -3
  21. package/src/controller/abr-controller.ts +20 -24
  22. package/src/controller/audio-stream-controller.ts +74 -68
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +8 -20
  25. package/src/controller/base-stream-controller.ts +36 -157
  26. package/src/controller/buffer-controller.ts +99 -226
  27. package/src/controller/buffer-operation-queue.ts +19 -16
  28. package/src/controller/cap-level-controller.ts +2 -2
  29. package/src/controller/cmcd-controller.ts +6 -27
  30. package/src/controller/content-steering-controller.ts +6 -8
  31. package/src/controller/eme-controller.ts +22 -9
  32. package/src/controller/error-controller.ts +8 -6
  33. package/src/controller/fps-controller.ts +3 -2
  34. package/src/controller/fragment-tracker.ts +11 -15
  35. package/src/controller/gap-controller.ts +16 -43
  36. package/src/controller/latency-controller.ts +11 -9
  37. package/src/controller/level-controller.ts +18 -12
  38. package/src/controller/stream-controller.ts +31 -36
  39. package/src/controller/subtitle-stream-controller.ts +40 -28
  40. package/src/controller/subtitle-track-controller.ts +3 -5
  41. package/src/controller/timeline-controller.ts +30 -23
  42. package/src/crypt/aes-crypto.ts +2 -21
  43. package/src/crypt/decrypter.ts +18 -32
  44. package/src/crypt/fast-aes-key.ts +5 -24
  45. package/src/demux/audio/adts.ts +4 -9
  46. package/src/demux/sample-aes.ts +0 -2
  47. package/src/demux/transmuxer-interface.ts +12 -4
  48. package/src/demux/transmuxer-worker.ts +4 -4
  49. package/src/demux/transmuxer.ts +3 -16
  50. package/src/demux/tsdemuxer.ts +37 -71
  51. package/src/demux/video/avc-video-parser.ts +119 -208
  52. package/src/demux/video/base-video-parser.ts +2 -134
  53. package/src/demux/video/exp-golomb.ts +208 -0
  54. package/src/events.ts +0 -7
  55. package/src/hls.ts +37 -49
  56. package/src/loader/fragment-loader.ts +2 -9
  57. package/src/loader/key-loader.ts +0 -2
  58. package/src/loader/level-key.ts +9 -10
  59. package/src/loader/playlist-loader.ts +5 -4
  60. package/src/remux/mp4-generator.ts +1 -196
  61. package/src/remux/mp4-remuxer.ts +7 -23
  62. package/src/task-loop.ts +2 -5
  63. package/src/types/component-api.ts +0 -2
  64. package/src/types/demuxer.ts +0 -3
  65. package/src/types/events.ts +0 -4
  66. package/src/utils/buffer-helper.ts +31 -12
  67. package/src/utils/codecs.ts +5 -34
  68. package/src/utils/logger.ts +24 -54
  69. package/src/utils/mp4-tools.ts +2 -4
  70. package/src/crypt/decrypter-aes-mode.ts +0 -4
  71. package/src/demux/video/hevc-video-parser.ts +0 -746
  72. package/src/utils/encryption-methods-util.ts +0 -21
@@ -1,35 +1,16 @@
1
- import { DecrypterAesMode } from './decrypter-aes-mode';
2
-
3
1
  export default class FastAESKey {
4
2
  private subtle: any;
5
3
  private key: ArrayBuffer;
6
- private aesMode: DecrypterAesMode;
7
4
 
8
- constructor(subtle, key, aesMode: DecrypterAesMode) {
5
+ constructor(subtle, key) {
9
6
  this.subtle = subtle;
10
7
  this.key = key;
11
- this.aesMode = aesMode;
12
8
  }
13
9
 
14
10
  expandKey() {
15
- const subtleAlgoName = getSubtleAlgoName(this.aesMode);
16
- return this.subtle.importKey(
17
- 'raw',
18
- this.key,
19
- { name: subtleAlgoName },
20
- false,
21
- ['encrypt', 'decrypt'],
22
- );
23
- }
24
- }
25
-
26
- function getSubtleAlgoName(aesMode: DecrypterAesMode) {
27
- switch (aesMode) {
28
- case DecrypterAesMode.cbc:
29
- return 'AES-CBC';
30
- case DecrypterAesMode.ctr:
31
- return 'AES-CTR';
32
- default:
33
- throw new Error(`[FastAESKey] invalid aes mode ${aesMode}`);
11
+ return this.subtle.importKey('raw', this.key, { name: 'AES-CBC' }, false, [
12
+ 'encrypt',
13
+ 'decrypt',
14
+ ]);
34
15
  }
35
16
  }
@@ -17,7 +17,6 @@ type AudioConfig = {
17
17
  samplerate: number;
18
18
  channelCount: number;
19
19
  codec: string;
20
- parsedCodec: string;
21
20
  manifestCodec: string;
22
21
  };
23
22
 
@@ -33,7 +32,6 @@ export function getAudioConfig(
33
32
  audioCodec: string,
34
33
  ): AudioConfig | void {
35
34
  let adtsObjectType: number;
36
- let originalAdtsObjectType: number;
37
35
  let adtsExtensionSamplingIndex: number;
38
36
  let adtsChannelConfig: number;
39
37
  let config: number[];
@@ -44,8 +42,7 @@ export function getAudioConfig(
44
42
  8000, 7350,
45
43
  ];
46
44
  // byte 2
47
- adtsObjectType = originalAdtsObjectType =
48
- ((data[offset + 2] & 0xc0) >>> 6) + 1;
45
+ adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
49
46
  const adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
50
47
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
51
48
  const error = new Error(`invalid ADTS sampling index:${adtsSamplingIndex}`);
@@ -64,8 +61,8 @@ export function getAudioConfig(
64
61
  logger.log(
65
62
  `manifest codec:${audioCodec}, ADTS type:${adtsObjectType}, samplingIndex:${adtsSamplingIndex}`,
66
63
  );
67
- // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
68
- if (/firefox|palemoon/i.test(userAgent)) {
64
+ // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
65
+ if (/firefox/i.test(userAgent)) {
69
66
  if (adtsSamplingIndex >= 6) {
70
67
  adtsObjectType = 5;
71
68
  config = new Array(4);
@@ -170,7 +167,6 @@ export function getAudioConfig(
170
167
  samplerate: adtsSamplingRates[adtsSamplingIndex],
171
168
  channelCount: adtsChannelConfig,
172
169
  codec: 'mp4a.40.' + adtsObjectType,
173
- parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
174
170
  manifestCodec,
175
171
  };
176
172
  }
@@ -248,9 +244,8 @@ export function initTrackConfig(
248
244
  track.channelCount = config.channelCount;
249
245
  track.codec = config.codec;
250
246
  track.manifestCodec = config.manifestCodec;
251
- track.parsedCodec = config.parsedCodec;
252
247
  logger.log(
253
- `parsed codec:${track.parsedCodec}, codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`,
248
+ `parsed codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`,
254
249
  );
255
250
  }
256
251
  }
@@ -4,7 +4,6 @@
4
4
 
5
5
  import { HlsConfig } from '../config';
6
6
  import Decrypter from '../crypt/decrypter';
7
- import { DecrypterAesMode } from '../crypt/decrypter-aes-mode';
8
7
  import { HlsEventEmitter } from '../events';
9
8
  import type {
10
9
  AudioSample,
@@ -31,7 +30,6 @@ class SampleAesDecrypter {
31
30
  encryptedData,
32
31
  this.keyData.key.buffer,
33
32
  this.keyData.iv.buffer,
34
- DecrypterAesMode.cbc,
35
33
  );
36
34
  }
37
35
 
@@ -12,13 +12,14 @@ import Transmuxer, {
12
12
  } from '../demux/transmuxer';
13
13
  import { logger } from '../utils/logger';
14
14
  import { ErrorTypes, ErrorDetails } from '../errors';
15
+ import { getMediaSource } from '../utils/mediasource-helper';
15
16
  import { EventEmitter } from 'eventemitter3';
16
17
  import { Fragment, Part } from '../loader/fragment';
17
- import { getM2TSSupportedAudioTypes } from '../utils/codecs';
18
18
  import type { ChunkMetadata, TransmuxerResult } from '../types/transmuxer';
19
19
  import type Hls from '../hls';
20
20
  import type { HlsEventEmitter } from '../events';
21
21
  import type { PlaylistLevelType } from '../types/loader';
22
+ import type { TypeSupported } from './tsdemuxer';
22
23
  import type { RationalTimestamp } from '../utils/timescale-conversion';
23
24
 
24
25
  export default class TransmuxerInterface {
@@ -63,9 +64,16 @@ export default class TransmuxerInterface {
63
64
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
64
65
  this.observer.on(Events.ERROR, forwardMessage);
65
66
 
66
- const m2tsTypeSupported = getM2TSSupportedAudioTypes(
67
- config.preferManagedMediaSource,
68
- );
67
+ const MediaSource = getMediaSource(config.preferManagedMediaSource) || {
68
+ isTypeSupported: () => false,
69
+ };
70
+ const m2tsTypeSupported: TypeSupported = {
71
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
72
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
73
+ ac3: __USE_M2TS_ADVANCED_CODECS__
74
+ ? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
75
+ : false,
76
+ };
69
77
 
70
78
  // navigator.vendor is not always available in Web Worker
71
79
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -1,6 +1,6 @@
1
1
  import Transmuxer, { isPromise } from '../demux/transmuxer';
2
2
  import { Events } from '../events';
3
- import { enableLogs, type ILogFunction, type ILogger } from '../utils/logger';
3
+ import { ILogFunction, enableLogs, logger } from '../utils/logger';
4
4
  import { EventEmitter } from 'eventemitter3';
5
5
  import { ErrorDetails, ErrorTypes } from '../errors';
6
6
  import type { RemuxedTrack, RemuxerResult } from '../types/remuxer';
@@ -21,7 +21,7 @@ function startWorker(self) {
21
21
  observer.on(Events.ERROR, forwardMessage);
22
22
 
23
23
  // forward logger events to main thread
24
- const forwardWorkerLogs = (logger: ILogger) => {
24
+ const forwardWorkerLogs = () => {
25
25
  for (const logFn in logger) {
26
26
  const func: ILogFunction = (message?) => {
27
27
  forwardMessage('workerLog', {
@@ -46,8 +46,8 @@ function startWorker(self) {
46
46
  data.vendor,
47
47
  data.id,
48
48
  );
49
- const logger = enableLogs(config.debug, data.id);
50
- forwardWorkerLogs(logger);
49
+ enableLogs(config.debug, data.id);
50
+ forwardWorkerLogs();
51
51
  forwardMessage('init', null);
52
52
  break;
53
53
  }
@@ -4,23 +4,18 @@ 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
12
  import { logger } from '../utils/logger';
13
- import {
14
- isFullSegmentEncryption,
15
- getAesModeFromFullSegmentMethod,
16
- } from '../utils/encryption-methods-util';
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
18
  import type { PlaylistLevelType } from '../types/loader';
23
- import type { TypeSupported } from '../utils/codecs';
24
19
  import type { RationalTimestamp } from '../utils/timescale-conversion';
25
20
  import { optionalSelf } from '../utils/global';
26
21
 
@@ -119,10 +114,8 @@ export default class Transmuxer {
119
114
  } = transmuxConfig;
120
115
 
121
116
  const keyData = getEncryptionType(uintData, decryptdata);
122
- if (keyData && isFullSegmentEncryption(keyData.method)) {
117
+ if (keyData && keyData.method === 'AES-128') {
123
118
  const decrypter = this.getDecrypter();
124
- const aesMode = getAesModeFromFullSegmentMethod(keyData.method);
125
-
126
119
  // Software decryption is synchronous; webCrypto is not
127
120
  if (decrypter.isSync()) {
128
121
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
@@ -131,7 +124,6 @@ export default class Transmuxer {
131
124
  uintData,
132
125
  keyData.key.buffer,
133
126
  keyData.iv.buffer,
134
- aesMode,
135
127
  );
136
128
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
137
129
  const loadingParts = chunkMeta.part > -1;
@@ -145,12 +137,7 @@ export default class Transmuxer {
145
137
  uintData = new Uint8Array(decryptedData);
146
138
  } else {
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
@@ -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 (or HEVC/H265) NAL units and AAC/ADTS samples from PES packet
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,9 +12,7 @@
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';
@@ -22,21 +20,20 @@ import { logger } from '../utils/logger';
22
20
  import { ErrorTypes, ErrorDetails } from '../errors';
23
21
  import type { HlsConfig } from '../config';
24
22
  import type { HlsEventEmitter } from '../events';
25
- import type { TypeSupported } from '../utils/codecs';
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 type { AudioFrame } from '../types/demuxer';
36
+ import { AudioFrame } from '../types/demuxer';
40
37
 
41
38
  export type ParsedTimestamp = {
42
39
  pts?: number;
@@ -51,6 +48,12 @@ 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 {
@@ -71,7 +74,7 @@ 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: BaseVideoParser | null;
77
+ private videoParser: AvcVideoParser;
75
78
 
76
79
  constructor(
77
80
  observer: HlsEventEmitter,
@@ -81,7 +84,7 @@ class TSDemuxer implements Demuxer {
81
84
  this.observer = observer;
82
85
  this.config = config;
83
86
  this.typeSupported = typeSupported;
84
- this.videoParser = null;
87
+ this.videoParser = new AvcVideoParser();
85
88
  }
86
89
 
87
90
  static probe(data: Uint8Array) {
@@ -289,27 +292,13 @@ class TSDemuxer implements Demuxer {
289
292
  case videoPid:
290
293
  if (stt) {
291
294
  if (videoData && (pes = parsePES(videoData))) {
292
- if (this.videoParser === null) {
293
- switch (videoTrack.segmentCodec) {
294
- case 'avc':
295
- this.videoParser = new AvcVideoParser();
296
- break;
297
- case 'hevc':
298
- if (__USE_M2TS_ADVANCED_CODECS__) {
299
- this.videoParser = new HevcVideoParser();
300
- }
301
- break;
302
- }
303
- }
304
- if (this.videoParser !== null) {
305
- this.videoParser.parsePES(
306
- videoTrack,
307
- textTrack,
308
- pes,
309
- false,
310
- this._duration,
311
- );
312
- }
295
+ this.videoParser.parseAVCPES(
296
+ videoTrack,
297
+ textTrack,
298
+ pes,
299
+ false,
300
+ this._duration,
301
+ );
313
302
  }
314
303
 
315
304
  videoData = { data: [], size: 0 };
@@ -481,28 +470,14 @@ class TSDemuxer implements Demuxer {
481
470
  // try to parse last PES packets
482
471
  let pes: PES | null;
483
472
  if (videoData && (pes = parsePES(videoData))) {
484
- if (this.videoParser === null) {
485
- switch (videoTrack.segmentCodec) {
486
- case 'avc':
487
- this.videoParser = new AvcVideoParser();
488
- break;
489
- case 'hevc':
490
- if (__USE_M2TS_ADVANCED_CODECS__) {
491
- this.videoParser = new HevcVideoParser();
492
- }
493
- break;
494
- }
495
- }
496
- if (this.videoParser !== null) {
497
- this.videoParser.parsePES(
498
- videoTrack as DemuxedVideoTrack,
499
- textTrack as DemuxedUserdataTrack,
500
- pes,
501
- true,
502
- this._duration,
503
- );
504
- videoTrack.pesData = null;
505
- }
473
+ this.videoParser.parseAVCPES(
474
+ videoTrack as DemuxedVideoTrack,
475
+ textTrack as DemuxedUserdataTrack,
476
+ pes,
477
+ true,
478
+ this._duration,
479
+ );
480
+ videoTrack.pesData = null;
506
481
  } else {
507
482
  // either avcData null or PES truncated, keep it for next frag parsing
508
483
  videoTrack.pesData = videoData;
@@ -899,17 +874,8 @@ function parsePMT(
899
874
  case 0x87:
900
875
  logger.warn('Unsupported EC-3 in M2TS found');
901
876
  break;
902
-
903
- case 0x24: // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
904
- if (__USE_M2TS_ADVANCED_CODECS__) {
905
- if (result.videoPid === -1) {
906
- result.videoPid = pid;
907
- result.segmentVideoCodec = 'hevc';
908
- logger.log('HEVC in M2TS found');
909
- }
910
- } else {
911
- logger.warn('Unsupported HEVC in M2TS found');
912
- }
877
+ case 0x24:
878
+ logger.warn('Unsupported HEVC in M2TS found');
913
879
  break;
914
880
 
915
881
  default: