hls.js 1.5.13 → 1.5.14-0.canary.10415

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 (103) hide show
  1. package/README.md +4 -3
  2. package/dist/hls-demo.js +41 -38
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +4211 -2666
  5. package/dist/hls.js.d.ts +179 -110
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +2841 -1921
  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 +2569 -1639
  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 +3572 -2017
  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 +38 -38
  20. package/src/config.ts +5 -2
  21. package/src/controller/abr-controller.ts +39 -25
  22. package/src/controller/audio-stream-controller.ts +156 -136
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +27 -10
  25. package/src/controller/base-stream-controller.ts +234 -89
  26. package/src/controller/buffer-controller.ts +250 -97
  27. package/src/controller/buffer-operation-queue.ts +16 -19
  28. package/src/controller/cap-level-controller.ts +3 -2
  29. package/src/controller/cmcd-controller.ts +51 -14
  30. package/src/controller/content-steering-controller.ts +29 -15
  31. package/src/controller/eme-controller.ts +10 -23
  32. package/src/controller/error-controller.ts +28 -22
  33. package/src/controller/fps-controller.ts +8 -3
  34. package/src/controller/fragment-finders.ts +44 -16
  35. package/src/controller/fragment-tracker.ts +58 -25
  36. package/src/controller/gap-controller.ts +43 -16
  37. package/src/controller/id3-track-controller.ts +45 -35
  38. package/src/controller/latency-controller.ts +18 -13
  39. package/src/controller/level-controller.ts +37 -19
  40. package/src/controller/stream-controller.ts +100 -83
  41. package/src/controller/subtitle-stream-controller.ts +35 -47
  42. package/src/controller/subtitle-track-controller.ts +5 -3
  43. package/src/controller/timeline-controller.ts +20 -22
  44. package/src/crypt/aes-crypto.ts +21 -2
  45. package/src/crypt/decrypter-aes-mode.ts +4 -0
  46. package/src/crypt/decrypter.ts +32 -16
  47. package/src/crypt/fast-aes-key.ts +28 -5
  48. package/src/demux/audio/aacdemuxer.ts +2 -2
  49. package/src/demux/audio/ac3-demuxer.ts +4 -3
  50. package/src/demux/audio/adts.ts +9 -4
  51. package/src/demux/audio/base-audio-demuxer.ts +16 -14
  52. package/src/demux/audio/mp3demuxer.ts +4 -3
  53. package/src/demux/audio/mpegaudio.ts +1 -1
  54. package/src/demux/mp4demuxer.ts +7 -7
  55. package/src/demux/sample-aes.ts +2 -0
  56. package/src/demux/transmuxer-interface.ts +8 -16
  57. package/src/demux/transmuxer-worker.ts +4 -4
  58. package/src/demux/transmuxer.ts +16 -3
  59. package/src/demux/tsdemuxer.ts +75 -38
  60. package/src/demux/video/avc-video-parser.ts +210 -121
  61. package/src/demux/video/base-video-parser.ts +135 -2
  62. package/src/demux/video/exp-golomb.ts +0 -208
  63. package/src/demux/video/hevc-video-parser.ts +749 -0
  64. package/src/events.ts +8 -1
  65. package/src/exports-named.ts +1 -1
  66. package/src/hls.ts +84 -47
  67. package/src/loader/date-range.ts +71 -5
  68. package/src/loader/fragment-loader.ts +23 -21
  69. package/src/loader/fragment.ts +8 -4
  70. package/src/loader/key-loader.ts +3 -1
  71. package/src/loader/level-details.ts +6 -6
  72. package/src/loader/level-key.ts +10 -9
  73. package/src/loader/m3u8-parser.ts +138 -144
  74. package/src/loader/playlist-loader.ts +5 -7
  75. package/src/remux/mp4-generator.ts +196 -1
  76. package/src/remux/mp4-remuxer.ts +32 -62
  77. package/src/remux/passthrough-remuxer.ts +1 -1
  78. package/src/task-loop.ts +5 -2
  79. package/src/types/component-api.ts +3 -1
  80. package/src/types/demuxer.ts +3 -0
  81. package/src/types/events.ts +19 -6
  82. package/src/types/fragment-tracker.ts +2 -2
  83. package/src/types/media-playlist.ts +9 -1
  84. package/src/types/remuxer.ts +1 -1
  85. package/src/utils/attr-list.ts +96 -9
  86. package/src/utils/buffer-helper.ts +12 -31
  87. package/src/utils/cea-608-parser.ts +1 -3
  88. package/src/utils/codecs.ts +34 -5
  89. package/src/utils/encryption-methods-util.ts +21 -0
  90. package/src/utils/fetch-loader.ts +1 -1
  91. package/src/utils/hash.ts +10 -0
  92. package/src/utils/hdr.ts +4 -7
  93. package/src/utils/imsc1-ttml-parser.ts +1 -1
  94. package/src/utils/keysystem-util.ts +1 -6
  95. package/src/utils/level-helper.ts +71 -44
  96. package/src/utils/logger.ts +58 -23
  97. package/src/utils/mp4-tools.ts +5 -3
  98. package/src/utils/rendition-helper.ts +100 -74
  99. package/src/utils/utf8-utils.ts +18 -0
  100. package/src/utils/variable-substitution.ts +0 -19
  101. package/src/utils/webvtt-parser.ts +2 -12
  102. package/src/demux/id3.ts +0 -411
  103. package/src/types/general.ts +0 -6
@@ -17,6 +17,7 @@ type AudioConfig = {
17
17
  samplerate: number;
18
18
  channelCount: number;
19
19
  codec: string;
20
+ parsedCodec: string;
20
21
  manifestCodec: string;
21
22
  };
22
23
 
@@ -32,6 +33,7 @@ export function getAudioConfig(
32
33
  audioCodec: string,
33
34
  ): AudioConfig | void {
34
35
  let adtsObjectType: number;
36
+ let originalAdtsObjectType: number;
35
37
  let adtsExtensionSamplingIndex: number;
36
38
  let adtsChannelConfig: number;
37
39
  let config: number[];
@@ -42,7 +44,8 @@ export function getAudioConfig(
42
44
  8000, 7350,
43
45
  ];
44
46
  // byte 2
45
- adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
47
+ adtsObjectType = originalAdtsObjectType =
48
+ ((data[offset + 2] & 0xc0) >>> 6) + 1;
46
49
  const adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
47
50
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
48
51
  const error = new Error(`invalid ADTS sampling index:${adtsSamplingIndex}`);
@@ -61,8 +64,8 @@ export function getAudioConfig(
61
64
  logger.log(
62
65
  `manifest codec:${audioCodec}, ADTS type:${adtsObjectType}, samplingIndex:${adtsSamplingIndex}`,
63
66
  );
64
- // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
65
- if (/firefox/i.test(userAgent)) {
67
+ // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
68
+ if (/firefox|palemoon/i.test(userAgent)) {
66
69
  if (adtsSamplingIndex >= 6) {
67
70
  adtsObjectType = 5;
68
71
  config = new Array(4);
@@ -167,6 +170,7 @@ export function getAudioConfig(
167
170
  samplerate: adtsSamplingRates[adtsSamplingIndex],
168
171
  channelCount: adtsChannelConfig,
169
172
  codec: 'mp4a.40.' + adtsObjectType,
173
+ parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
170
174
  manifestCodec,
171
175
  };
172
176
  }
@@ -244,8 +248,9 @@ export function initTrackConfig(
244
248
  track.channelCount = config.channelCount;
245
249
  track.codec = config.codec;
246
250
  track.manifestCodec = config.manifestCodec;
251
+ track.parsedCodec = config.parsedCodec;
247
252
  logger.log(
248
- `parsed codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`,
253
+ `parsed codec:${track.parsedCodec}, codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`,
249
254
  );
250
255
  }
251
256
  }
@@ -1,19 +1,21 @@
1
- import * as ID3 from '../id3';
2
1
  import {
3
- DemuxerResult,
4
- Demuxer,
5
- DemuxedAudioTrack,
6
- AudioFrame,
7
- DemuxedMetadataTrack,
8
- DemuxedVideoTrackBase,
9
- DemuxedUserdataTrack,
10
- KeyData,
2
+ type DemuxerResult,
3
+ type Demuxer,
4
+ type DemuxedAudioTrack,
5
+ type AudioFrame,
6
+ type DemuxedMetadataTrack,
7
+ type DemuxedVideoTrackBase,
8
+ type DemuxedUserdataTrack,
9
+ type KeyData,
11
10
  MetadataSchema,
12
11
  } from '../../types/demuxer';
13
12
  import { dummyTrack } from '../dummy-demuxed-track';
14
13
  import { appendUint8Array } from '../../utils/mp4-tools';
15
14
  import { sliceUint8 } from '../../utils/typed-array';
16
15
  import { RationalTimestamp } from '../../utils/timescale-conversion';
16
+ import { getId3Data } from '@svta/common-media-library/id3/getId3Data';
17
+ import { getId3Timestamp } from '@svta/common-media-library/id3/getId3Timestamp';
18
+ import { canParseId3 } from '@svta/common-media-library/id3/canParseId3';
17
19
 
18
20
  class BaseAudioDemuxer implements Demuxer {
19
21
  protected _audioTrack!: DemuxedAudioTrack;
@@ -69,12 +71,12 @@ class BaseAudioDemuxer implements Demuxer {
69
71
  this.cachedData = null;
70
72
  }
71
73
 
72
- let id3Data: Uint8Array | undefined = ID3.getID3Data(data, 0);
74
+ let id3Data: Uint8Array | undefined = getId3Data(data, 0);
73
75
  let offset = id3Data ? id3Data.length : 0;
74
76
  let lastDataIndex;
75
77
  const track = this._audioTrack;
76
78
  const id3Track = this._id3Track;
77
- const timestamp = id3Data ? ID3.getTimeStamp(id3Data) : undefined;
79
+ const timestamp = id3Data ? getId3Timestamp(id3Data) : undefined;
78
80
  const length = data.length;
79
81
 
80
82
  if (
@@ -111,9 +113,9 @@ class BaseAudioDemuxer implements Demuxer {
111
113
  } else {
112
114
  offset = length;
113
115
  }
114
- } else if (ID3.canParse(data, offset)) {
115
- // after a ID3.canParse, a call to ID3.getID3Data *should* always returns some data
116
- id3Data = ID3.getID3Data(data, offset)!;
116
+ } else if (canParseId3(data, offset)) {
117
+ // after a canParse, a call to getId3Data *should* always returns some data
118
+ id3Data = getId3Data(data, offset)!;
117
119
  id3Track.samples.push({
118
120
  pts: this.lastPTS,
119
121
  dts: this.lastPTS,
@@ -2,10 +2,11 @@
2
2
  * MP3 demuxer
3
3
  */
4
4
  import BaseAudioDemuxer from './base-audio-demuxer';
5
- import { getID3Data, getTimeStamp } from '../id3';
6
5
  import { getAudioBSID } from './dolby';
7
6
  import { logger } from '../../utils/logger';
8
7
  import * as MpegAudio from './mpegaudio';
8
+ import { getId3Data } from '@svta/common-media-library/id3/getId3Data';
9
+ import { getId3Timestamp } from '@svta/common-media-library/id3/getId3Timestamp';
9
10
 
10
11
  class MP3Demuxer extends BaseAudioDemuxer {
11
12
  resetInitSegment(
@@ -39,7 +40,7 @@ class MP3Demuxer extends BaseAudioDemuxer {
39
40
  // Look for MPEG header | 1111 1111 | 111X XYZX | where X can be either 0 or 1 and Y or Z should be 1
40
41
  // Layer bits (position 14 and 15) in header should be always different from 0 (Layer I or Layer II or Layer III)
41
42
  // More info http://www.mp3-tech.org/programmer/frame_header.html
42
- const id3Data = getID3Data(data, 0);
43
+ const id3Data = getId3Data(data, 0);
43
44
  let offset = id3Data?.length || 0;
44
45
 
45
46
  // Check for ac-3|ec-3 sync bytes and return false if present
@@ -47,7 +48,7 @@ class MP3Demuxer extends BaseAudioDemuxer {
47
48
  id3Data &&
48
49
  data[offset] === 0x0b &&
49
50
  data[offset + 1] === 0x77 &&
50
- getTimeStamp(id3Data) !== undefined &&
51
+ getId3Timestamp(id3Data) !== undefined &&
51
52
  // check the bsid to confirm ac-3 or ec-3 (not mp3)
52
53
  getAudioBSID(data, offset) <= 16
53
54
  ) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * MPEG parser helper
3
3
  */
4
- import { DemuxedAudioTrack } from '../../types/demuxer';
4
+ import type { DemuxedAudioTrack } from '../../types/demuxer';
5
5
 
6
6
  let chromeVersion: number | null = null;
7
7
 
@@ -2,13 +2,13 @@
2
2
  * MP4 demuxer
3
3
  */
4
4
  import {
5
- Demuxer,
6
- DemuxerResult,
7
- PassthroughTrack,
8
- DemuxedAudioTrack,
9
- DemuxedUserdataTrack,
10
- DemuxedMetadataTrack,
11
- KeyData,
5
+ type Demuxer,
6
+ type DemuxerResult,
7
+ type PassthroughTrack,
8
+ type DemuxedAudioTrack,
9
+ type DemuxedUserdataTrack,
10
+ type DemuxedMetadataTrack,
11
+ type KeyData,
12
12
  MetadataSchema,
13
13
  } from '../types/demuxer';
14
14
  import {
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { HlsConfig } from '../config';
6
6
  import Decrypter from '../crypt/decrypter';
7
+ import { DecrypterAesMode } from '../crypt/decrypter-aes-mode';
7
8
  import { HlsEventEmitter } from '../events';
8
9
  import type {
9
10
  AudioSample,
@@ -30,6 +31,7 @@ class SampleAesDecrypter {
30
31
  encryptedData,
31
32
  this.keyData.key.buffer,
32
33
  this.keyData.iv.buffer,
34
+ DecrypterAesMode.cbc,
33
35
  );
34
36
  }
35
37
 
@@ -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
- import { Fragment, Part } from '../loader/fragment';
16
+ import { MediaFragment, 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, HlsListeners } 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 {
@@ -27,7 +26,7 @@ export default class TransmuxerInterface {
27
26
  private hls: Hls;
28
27
  private id: PlaylistLevelType;
29
28
  private observer: HlsEventEmitter;
30
- private frag: Fragment | null = null;
29
+ private frag: MediaFragment | null = null;
31
30
  private part: Part | null = null;
32
31
  private useWorker: boolean;
33
32
  private workerContext: WorkerContext | null = null;
@@ -66,16 +65,9 @@ export default class TransmuxerInterface {
66
65
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
67
66
  this.observer.on(Events.ERROR, forwardMessage);
68
67
 
69
- const MediaSource = getMediaSource(config.preferManagedMediaSource) || {
70
- isTypeSupported: () => false,
71
- };
72
- const m2tsTypeSupported: TypeSupported = {
73
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
74
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
75
- ac3: __USE_M2TS_ADVANCED_CODECS__
76
- ? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
77
- : false,
78
- };
68
+ const m2tsTypeSupported = getM2TSSupportedAudioTypes(
69
+ config.preferManagedMediaSource,
70
+ );
79
71
 
80
72
  if (this.useWorker && typeof Worker !== 'undefined') {
81
73
  const canCreateWorker = config.workerPath || hasUMDWorker();
@@ -181,7 +173,7 @@ export default class TransmuxerInterface {
181
173
  initSegmentData: Uint8Array | undefined,
182
174
  audioCodec: string | undefined,
183
175
  videoCodec: string | undefined,
184
- frag: Fragment,
176
+ frag: MediaFragment,
185
177
  part: Part | null,
186
178
  duration: number,
187
179
  accurateTimeOffset: boolean,
@@ -197,7 +189,7 @@ export default class TransmuxerInterface {
197
189
 
198
190
  const discontinuity = !(lastFrag && frag.cc === lastFrag.cc);
199
191
  const trackSwitch = !(lastFrag && chunkMeta.level === lastFrag.level);
200
- const snDiff = lastFrag ? chunkMeta.sn - (lastFrag.sn as number) : -1;
192
+ const snDiff = lastFrag ? chunkMeta.sn - lastFrag.sn : -1;
201
193
  const partDiff = this.part ? chunkMeta.part - this.part.index : -1;
202
194
  const progressive =
203
195
  snDiff === 0 &&
@@ -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
  '',
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 };
@@ -467,14 +478,28 @@ class TSDemuxer implements Demuxer {
467
478
  // try to parse last PES packets
468
479
  let pes: PES | null;
469
480
  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;
481
+ if (this.videoParser === null) {
482
+ switch (videoTrack.segmentCodec) {
483
+ case 'avc':
484
+ this.videoParser = new AvcVideoParser();
485
+ break;
486
+ case 'hevc':
487
+ if (__USE_M2TS_ADVANCED_CODECS__) {
488
+ this.videoParser = new HevcVideoParser();
489
+ }
490
+ break;
491
+ }
492
+ }
493
+ if (this.videoParser !== null) {
494
+ this.videoParser.parsePES(
495
+ videoTrack as DemuxedVideoTrack,
496
+ textTrack as DemuxedUserdataTrack,
497
+ pes,
498
+ true,
499
+ this._duration,
500
+ );
501
+ videoTrack.pesData = null;
502
+ }
478
503
  } else {
479
504
  // either avcData null or PES truncated, keep it for next frag parsing
480
505
  videoTrack.pesData = videoData;
@@ -864,9 +889,21 @@ function parsePMT(
864
889
  emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'));
865
890
  return result;
866
891
 
867
- case 0x24:
868
- emitParsingError(observer, new Error('Unsupported HEVC in M2TS found'));
869
- return result;
892
+ case 0x24: // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
893
+ if (__USE_M2TS_ADVANCED_CODECS__) {
894
+ if (result.videoPid === -1) {
895
+ result.videoPid = pid;
896
+ result.segmentVideoCodec = 'hevc';
897
+ logger.log('HEVC in M2TS found');
898
+ }
899
+ } else {
900
+ emitParsingError(
901
+ observer,
902
+ new Error('Unsupported HEVC in M2TS found'),
903
+ );
904
+ return result;
905
+ }
906
+ break;
870
907
 
871
908
  default:
872
909
  // logger.log('unknown stream type:' + data[offset]);