hls.js 1.5.4 → 1.5.5-0.canary.9978

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 (67) hide show
  1. package/README.md +1 -0
  2. package/dist/hls-demo.js +10 -0
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1935 -1094
  5. package/dist/hls.js.d.ts +63 -50
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1059 -838
  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 +846 -626
  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 +1640 -814
  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 +18 -18
  20. package/src/config.ts +3 -2
  21. package/src/controller/abr-controller.ts +21 -20
  22. package/src/controller/audio-stream-controller.ts +15 -16
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +7 -7
  25. package/src/controller/base-stream-controller.ts +56 -29
  26. package/src/controller/buffer-controller.ts +11 -11
  27. package/src/controller/cap-level-controller.ts +1 -2
  28. package/src/controller/cmcd-controller.ts +25 -3
  29. package/src/controller/content-steering-controller.ts +8 -6
  30. package/src/controller/eme-controller.ts +9 -22
  31. package/src/controller/error-controller.ts +6 -8
  32. package/src/controller/fps-controller.ts +2 -3
  33. package/src/controller/gap-controller.ts +43 -16
  34. package/src/controller/latency-controller.ts +9 -11
  35. package/src/controller/level-controller.ts +5 -17
  36. package/src/controller/stream-controller.ts +25 -32
  37. package/src/controller/subtitle-stream-controller.ts +13 -14
  38. package/src/controller/subtitle-track-controller.ts +5 -3
  39. package/src/controller/timeline-controller.ts +23 -30
  40. package/src/crypt/aes-crypto.ts +21 -2
  41. package/src/crypt/decrypter-aes-mode.ts +4 -0
  42. package/src/crypt/decrypter.ts +32 -18
  43. package/src/crypt/fast-aes-key.ts +24 -5
  44. package/src/demux/audio/adts.ts +9 -4
  45. package/src/demux/sample-aes.ts +2 -0
  46. package/src/demux/transmuxer-interface.ts +4 -12
  47. package/src/demux/transmuxer-worker.ts +4 -4
  48. package/src/demux/transmuxer.ts +16 -3
  49. package/src/demux/tsdemuxer.ts +71 -37
  50. package/src/demux/video/avc-video-parser.ts +208 -119
  51. package/src/demux/video/base-video-parser.ts +134 -2
  52. package/src/demux/video/exp-golomb.ts +0 -208
  53. package/src/demux/video/hevc-video-parser.ts +746 -0
  54. package/src/events.ts +7 -0
  55. package/src/hls.ts +42 -34
  56. package/src/loader/fragment-loader.ts +9 -2
  57. package/src/loader/key-loader.ts +2 -0
  58. package/src/loader/level-key.ts +10 -9
  59. package/src/remux/mp4-generator.ts +196 -1
  60. package/src/remux/mp4-remuxer.ts +23 -7
  61. package/src/task-loop.ts +5 -2
  62. package/src/types/component-api.ts +2 -0
  63. package/src/types/demuxer.ts +3 -0
  64. package/src/types/events.ts +4 -0
  65. package/src/utils/codecs.ts +33 -4
  66. package/src/utils/encryption-methods-util.ts +21 -0
  67. package/src/utils/logger.ts +53 -24
@@ -12,14 +12,13 @@ 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';
16
15
  import { EventEmitter } from 'eventemitter3';
17
16
  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';
23
22
  import type { RationalTimestamp } from '../utils/timescale-conversion';
24
23
 
25
24
  export default class TransmuxerInterface {
@@ -64,16 +63,9 @@ export default class TransmuxerInterface {
64
63
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
65
64
  this.observer.on(Events.ERROR, forwardMessage);
66
65
 
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
- };
66
+ const m2tsTypeSupported = getM2TSSupportedAudioTypes(
67
+ config.preferManagedMediaSource,
68
+ );
77
69
 
78
70
  // navigator.vendor is not always available in Web Worker
79
71
  // 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 { ILogFunction, enableLogs, logger } from '../utils/logger';
3
+ import { enableLogs, type ILogFunction, type ILogger } 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 = () => {
24
+ const forwardWorkerLogs = (logger: ILogger) => {
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
- enableLogs(config.debug, data.id);
50
- forwardWorkerLogs();
49
+ const logger = enableLogs(config.debug, data.id);
50
+ forwardWorkerLogs(logger);
51
51
  forwardMessage('init', null);
52
52
  break;
53
53
  }
@@ -4,18 +4,23 @@ 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, { TypeSupported } from '../demux/tsdemuxer';
7
+ import TSDemuxer 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';
13
17
  import type { Demuxer, DemuxerResult, KeyData } from '../types/demuxer';
14
18
  import type { Remuxer } from '../types/remuxer';
15
19
  import type { TransmuxerResult, ChunkMetadata } from '../types/transmuxer';
16
20
  import type { HlsConfig } from '../config';
17
21
  import type { DecryptData } from '../loader/level-key';
18
22
  import type { PlaylistLevelType } from '../types/loader';
23
+ import type { TypeSupported } from '../utils/codecs';
19
24
  import type { RationalTimestamp } from '../utils/timescale-conversion';
20
25
  import { optionalSelf } from '../utils/global';
21
26
 
@@ -114,8 +119,10 @@ export default class Transmuxer {
114
119
  } = transmuxConfig;
115
120
 
116
121
  const keyData = getEncryptionType(uintData, decryptdata);
117
- if (keyData && keyData.method === 'AES-128') {
122
+ if (keyData && isFullSegmentEncryption(keyData.method)) {
118
123
  const decrypter = this.getDecrypter();
124
+ const aesMode = getAesModeFromFullSegmentMethod(keyData.method);
125
+
119
126
  // Software decryption is synchronous; webCrypto is not
120
127
  if (decrypter.isSync()) {
121
128
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
@@ -124,6 +131,7 @@ export default class Transmuxer {
124
131
  uintData,
125
132
  keyData.key.buffer,
126
133
  keyData.iv.buffer,
134
+ aesMode,
127
135
  );
128
136
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
129
137
  const loadingParts = chunkMeta.part > -1;
@@ -137,7 +145,12 @@ export default class Transmuxer {
137
145
  uintData = new Uint8Array(decryptedData);
138
146
  } else {
139
147
  this.decryptionPromise = decrypter
140
- .webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer)
148
+ .webCryptoDecrypt(
149
+ uintData,
150
+ keyData.key.buffer,
151
+ keyData.iv.buffer,
152
+ aesMode,
153
+ )
141
154
  .then((decryptedData): TransmuxerResult => {
142
155
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
143
156
  // 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 NAL units and AAC/ADTS samples from PES packet
5
+ * extract AVC/H264 (or HEVC/H265) 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,7 +12,9 @@
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';
15
16
  import AvcVideoParser from './video/avc-video-parser';
17
+ import HevcVideoParser from './video/hevc-video-parser';
16
18
  import SampleAesDecrypter from './sample-aes';
17
19
  import { Events } from '../events';
18
20
  import { appendUint8Array, RemuxerTrackIdConfig } from '../utils/mp4-tools';
@@ -20,20 +22,21 @@ import { logger } from '../utils/logger';
20
22
  import { ErrorTypes, ErrorDetails } from '../errors';
21
23
  import type { HlsConfig } from '../config';
22
24
  import type { HlsEventEmitter } from '../events';
25
+ import type { TypeSupported } from '../utils/codecs';
23
26
  import {
24
- DemuxedVideoTrack,
25
- DemuxedAudioTrack,
26
- DemuxedTrack,
27
- Demuxer,
28
- DemuxerResult,
29
- VideoSample,
30
- DemuxedMetadataTrack,
31
- DemuxedUserdataTrack,
32
- ElementaryStreamData,
33
- KeyData,
34
27
  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,
35
38
  } from '../types/demuxer';
36
- import { AudioFrame } from '../types/demuxer';
39
+ import type { AudioFrame } from '../types/demuxer';
37
40
 
38
41
  export type ParsedTimestamp = {
39
42
  pts?: number;
@@ -48,12 +51,6 @@ export type PES = ParsedTimestamp & {
48
51
  export type ParsedVideoSample = ParsedTimestamp &
49
52
  Omit<VideoSample, 'pts' | 'dts'>;
50
53
 
51
- export interface TypeSupported {
52
- mpeg: boolean;
53
- mp3: boolean;
54
- ac3: boolean;
55
- }
56
-
57
54
  const PACKET_LENGTH = 188;
58
55
 
59
56
  class TSDemuxer implements Demuxer {
@@ -74,7 +71,7 @@ class TSDemuxer implements Demuxer {
74
71
  private _txtTrack?: DemuxedUserdataTrack;
75
72
  private aacOverFlow: AudioFrame | null = null;
76
73
  private remainderData: Uint8Array | null = null;
77
- private videoParser: AvcVideoParser;
74
+ private videoParser: BaseVideoParser | null;
78
75
 
79
76
  constructor(
80
77
  observer: HlsEventEmitter,
@@ -84,7 +81,7 @@ class TSDemuxer implements Demuxer {
84
81
  this.observer = observer;
85
82
  this.config = config;
86
83
  this.typeSupported = typeSupported;
87
- this.videoParser = new AvcVideoParser();
84
+ this.videoParser = null;
88
85
  }
89
86
 
90
87
  static probe(data: Uint8Array) {
@@ -292,13 +289,27 @@ class TSDemuxer implements Demuxer {
292
289
  case videoPid:
293
290
  if (stt) {
294
291
  if (videoData && (pes = parsePES(videoData))) {
295
- this.videoParser.parseAVCPES(
296
- videoTrack,
297
- textTrack,
298
- pes,
299
- false,
300
- this._duration,
301
- );
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
+ }
302
313
  }
303
314
 
304
315
  videoData = { data: [], size: 0 };
@@ -470,14 +481,28 @@ class TSDemuxer implements Demuxer {
470
481
  // try to parse last PES packets
471
482
  let pes: PES | null;
472
483
  if (videoData && (pes = parsePES(videoData))) {
473
- this.videoParser.parseAVCPES(
474
- videoTrack as DemuxedVideoTrack,
475
- textTrack as DemuxedUserdataTrack,
476
- pes,
477
- true,
478
- this._duration,
479
- );
480
- videoTrack.pesData = null;
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
+ }
481
506
  } else {
482
507
  // either avcData null or PES truncated, keep it for next frag parsing
483
508
  videoTrack.pesData = videoData;
@@ -874,8 +899,17 @@ function parsePMT(
874
899
  case 0x87:
875
900
  logger.warn('Unsupported EC-3 in M2TS found');
876
901
  break;
877
- case 0x24:
878
- logger.warn('Unsupported HEVC in M2TS found');
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
+ }
879
913
  break;
880
914
 
881
915
  default: