hls.js 1.5.8-0.canary.10170 → 1.5.8

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 (87) hide show
  1. package/README.md +3 -4
  2. package/dist/hls-demo.js +3 -12
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +2366 -3626
  5. package/dist/hls.js.d.ts +84 -98
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1643 -2278
  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 +1258 -1903
  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 +1531 -2794
  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 +30 -30
  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 +10 -27
  25. package/src/controller/base-stream-controller.ts +38 -160
  26. package/src/controller/buffer-controller.ts +92 -230
  27. package/src/controller/buffer-operation-queue.ts +19 -16
  28. package/src/controller/cap-level-controller.ts +2 -3
  29. package/src/controller/cmcd-controller.ts +9 -30
  30. package/src/controller/content-steering-controller.ts +6 -8
  31. package/src/controller/eme-controller.ts +23 -10
  32. package/src/controller/error-controller.ts +8 -6
  33. package/src/controller/fps-controller.ts +3 -8
  34. package/src/controller/fragment-tracker.ts +11 -15
  35. package/src/controller/gap-controller.ts +16 -43
  36. package/src/controller/id3-track-controller.ts +7 -7
  37. package/src/controller/latency-controller.ts +11 -9
  38. package/src/controller/level-controller.ts +19 -13
  39. package/src/controller/stream-controller.ts +32 -37
  40. package/src/controller/subtitle-stream-controller.ts +40 -28
  41. package/src/controller/subtitle-track-controller.ts +3 -5
  42. package/src/controller/timeline-controller.ts +31 -25
  43. package/src/crypt/aes-crypto.ts +2 -21
  44. package/src/crypt/decrypter.ts +18 -32
  45. package/src/crypt/fast-aes-key.ts +5 -24
  46. package/src/demux/audio/aacdemuxer.ts +2 -2
  47. package/src/demux/audio/ac3-demuxer.ts +3 -4
  48. package/src/demux/audio/adts.ts +4 -9
  49. package/src/demux/audio/base-audio-demuxer.ts +14 -16
  50. package/src/demux/audio/mp3demuxer.ts +3 -4
  51. package/src/demux/audio/mpegaudio.ts +1 -1
  52. package/src/demux/id3.ts +411 -0
  53. package/src/demux/mp4demuxer.ts +7 -7
  54. package/src/demux/sample-aes.ts +0 -2
  55. package/src/demux/transmuxer-interface.ts +12 -4
  56. package/src/demux/transmuxer-worker.ts +4 -4
  57. package/src/demux/transmuxer.ts +3 -16
  58. package/src/demux/tsdemuxer.ts +37 -71
  59. package/src/demux/video/avc-video-parser.ts +119 -208
  60. package/src/demux/video/base-video-parser.ts +2 -134
  61. package/src/demux/video/exp-golomb.ts +208 -0
  62. package/src/events.ts +1 -8
  63. package/src/exports-named.ts +1 -1
  64. package/src/hls.ts +37 -49
  65. package/src/loader/fragment-loader.ts +3 -10
  66. package/src/loader/key-loader.ts +1 -3
  67. package/src/loader/level-key.ts +9 -10
  68. package/src/loader/playlist-loader.ts +5 -4
  69. package/src/remux/mp4-generator.ts +1 -196
  70. package/src/remux/mp4-remuxer.ts +8 -24
  71. package/src/task-loop.ts +2 -5
  72. package/src/types/component-api.ts +1 -3
  73. package/src/types/demuxer.ts +0 -3
  74. package/src/types/events.ts +0 -4
  75. package/src/types/remuxer.ts +1 -1
  76. package/src/utils/buffer-helper.ts +31 -12
  77. package/src/utils/codecs.ts +5 -34
  78. package/src/utils/fetch-loader.ts +1 -1
  79. package/src/utils/imsc1-ttml-parser.ts +1 -1
  80. package/src/utils/keysystem-util.ts +6 -1
  81. package/src/utils/logger.ts +23 -58
  82. package/src/utils/mp4-tools.ts +3 -5
  83. package/src/utils/webvtt-parser.ts +1 -1
  84. package/src/crypt/decrypter-aes-mode.ts +0 -4
  85. package/src/demux/video/hevc-video-parser.ts +0 -749
  86. package/src/utils/encryption-methods-util.ts +0 -21
  87. package/src/utils/utf8-utils.ts +0 -18
@@ -1,6 +1,6 @@
1
1
  import { ErrorTypes, ErrorDetails } from '../errors';
2
2
  import { Fragment } from './fragment';
3
- import type {
3
+ import {
4
4
  Loader,
5
5
  LoaderConfiguration,
6
6
  FragmentLoaderContext,
@@ -336,11 +336,8 @@ function createLoaderContext(
336
336
  if (Number.isFinite(start) && Number.isFinite(end)) {
337
337
  let byteRangeStart = start;
338
338
  let byteRangeEnd = end;
339
- if (
340
- frag.sn === 'initSegment' &&
341
- isMethodFullSegmentAesCbc(frag.decryptdata?.method)
342
- ) {
343
- // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
339
+ if (frag.sn === 'initSegment' && frag.decryptdata?.method === 'AES-128') {
340
+ // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
344
341
  // has the unencrypted size specified in the range.
345
342
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
346
343
  const fragmentLen = end - start;
@@ -375,10 +372,6 @@ function createGapLoadError(frag: Fragment, part?: Part): LoadError {
375
372
  return new LoadError(errorData);
376
373
  }
377
374
 
378
- function isMethodFullSegmentAesCbc(method) {
379
- return method === 'AES-128' || method === 'AES-256';
380
- }
381
-
382
375
  export class LoadError extends Error {
383
376
  public readonly data: FragLoadFailResult;
384
377
  constructor(data: FragLoadFailResult) {
@@ -1,5 +1,5 @@
1
1
  import { ErrorTypes, ErrorDetails } from '../errors';
2
- import type {
2
+ import {
3
3
  LoaderStats,
4
4
  LoaderResponse,
5
5
  LoaderConfiguration,
@@ -194,8 +194,6 @@ export default class KeyLoader implements ComponentAPI {
194
194
  }
195
195
  return this.loadKeyEME(keyInfo, frag);
196
196
  case 'AES-128':
197
- case 'AES-256':
198
- case 'AES-256-CTR':
199
197
  return this.loadKeyHTTP(keyInfo, frag);
200
198
  default:
201
199
  return Promise.reject(
@@ -2,7 +2,6 @@ import {
2
2
  changeEndianness,
3
3
  convertDataUriToArrayBytes,
4
4
  } from '../utils/keysystem-util';
5
- import { isFullSegmentEncryption } from '../utils/encryption-methods-util';
6
5
  import { KeySystemFormats } from '../utils/mediakeys-helper';
7
6
  import { mp4pssh } from '../utils/mp4-tools';
8
7
  import { logger } from '../utils/logger';
@@ -52,14 +51,13 @@ export class LevelKey implements DecryptData {
52
51
  this.keyFormatVersions = formatversions;
53
52
  this.iv = iv;
54
53
  this.encrypted = method ? method !== 'NONE' : false;
55
- this.isCommonEncryption =
56
- this.encrypted && !isFullSegmentEncryption(method);
54
+ this.isCommonEncryption = this.encrypted && method !== 'AES-128';
57
55
  }
58
56
 
59
57
  public isSupported(): boolean {
60
58
  // If it's Segment encryption or No encryption, just select that key system
61
59
  if (this.method) {
62
- if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
60
+ if (this.method === 'AES-128' || this.method === 'NONE') {
63
61
  return true;
64
62
  }
65
63
  if (this.keyFormat === 'identity') {
@@ -90,15 +88,16 @@ export class LevelKey implements DecryptData {
90
88
  return null;
91
89
  }
92
90
 
93
- if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
91
+ if (this.method === 'AES-128' && this.uri && !this.iv) {
94
92
  if (typeof sn !== 'number') {
95
93
  // We are fetching decryption data for a initialization segment
96
- // If the segment was encrypted with AES-128/256
94
+ // If the segment was encrypted with AES-128
97
95
  // It must have an IV defined. We cannot substitute the Segment Number in.
98
- logger.warn(
99
- `missing IV for initialization segment with method="${this.method}" - compliance issue`,
100
- );
101
-
96
+ if (this.method === 'AES-128' && !this.iv) {
97
+ logger.warn(
98
+ `missing IV for initialization segment with method="${this.method}" - compliance issue`,
99
+ );
100
+ }
102
101
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
103
102
  sn = 0;
104
103
  }
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { Events } from '../events';
10
10
  import { ErrorDetails, ErrorTypes } from '../errors';
11
+ import { logger } from '../utils/logger';
11
12
  import M3U8Parser from './m3u8-parser';
12
13
  import type { LevelParsed, VariableMap } from '../types/level';
13
14
  import type {
@@ -220,10 +221,10 @@ class PlaylistLoader implements NetworkComponentAPI {
220
221
  loaderContext.level === context.level
221
222
  ) {
222
223
  // same URL can't overlap
223
- this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
224
+ logger.trace('[playlist-loader]: playlist request ongoing');
224
225
  return;
225
226
  }
226
- this.hls.logger.log(
227
+ logger.log(
227
228
  `[playlist-loader]: aborting previous loader for type: ${context.type}`,
228
229
  );
229
230
  loader.abort();
@@ -407,7 +408,7 @@ class PlaylistLoader implements NetworkComponentAPI {
407
408
  levels[0].audioCodec &&
408
409
  !levels[0].attrs.AUDIO
409
410
  ) {
410
- this.hls.logger.log(
411
+ logger.log(
411
412
  '[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one',
412
413
  );
413
414
  audioTracks.unshift({
@@ -554,7 +555,7 @@ class PlaylistLoader implements NetworkComponentAPI {
554
555
  message += ` id: ${context.id} group-id: "${context.groupId}"`;
555
556
  }
556
557
  const error = new Error(message);
557
- this.hls.logger.warn(`[playlist-loader]: ${message}`);
558
+ logger.warn(`[playlist-loader]: ${message}`);
558
559
  let details = ErrorDetails.UNKNOWN;
559
560
  let fatal = false;
560
561
 
@@ -28,8 +28,6 @@ class MP4 {
28
28
  MP4.types = {
29
29
  avc1: [], // codingname
30
30
  avcC: [],
31
- hvc1: [],
32
- hvcC: [],
33
31
  btrt: [],
34
32
  dinf: [],
35
33
  dref: [],
@@ -841,10 +839,8 @@ class MP4 {
841
839
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
842
840
  }
843
841
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
844
- } else if (track.segmentCodec === 'avc') {
845
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
846
842
  } else {
847
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
843
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
848
844
  }
849
845
  }
850
846
 
@@ -1127,197 +1123,6 @@ class MP4 {
1127
1123
  const result = appendUint8Array(MP4.FTYP, movie);
1128
1124
  return result;
1129
1125
  }
1130
-
1131
- static hvc1(track) {
1132
- const ps = track.params;
1133
- const units = [track.vps, track.sps, track.pps];
1134
- const NALuLengthSize = 4;
1135
- const config = new Uint8Array([
1136
- 0x01,
1137
- (ps.general_profile_space << 6) |
1138
- (ps.general_tier_flag ? 32 : 0) |
1139
- ps.general_profile_idc,
1140
- ps.general_profile_compatibility_flags[0],
1141
- ps.general_profile_compatibility_flags[1],
1142
- ps.general_profile_compatibility_flags[2],
1143
- ps.general_profile_compatibility_flags[3],
1144
- ps.general_constraint_indicator_flags[0],
1145
- ps.general_constraint_indicator_flags[1],
1146
- ps.general_constraint_indicator_flags[2],
1147
- ps.general_constraint_indicator_flags[3],
1148
- ps.general_constraint_indicator_flags[4],
1149
- ps.general_constraint_indicator_flags[5],
1150
- ps.general_level_idc,
1151
- 240 | (ps.min_spatial_segmentation_idc >> 8),
1152
- 255 & ps.min_spatial_segmentation_idc,
1153
- 252 | ps.parallelismType,
1154
- 252 | ps.chroma_format_idc,
1155
- 248 | ps.bit_depth_luma_minus8,
1156
- 248 | ps.bit_depth_chroma_minus8,
1157
- 0x00,
1158
- parseInt(ps.frame_rate.fps),
1159
- (NALuLengthSize - 1) |
1160
- (ps.temporal_id_nested << 2) |
1161
- (ps.num_temporal_layers << 3) |
1162
- (ps.frame_rate.fixed ? 64 : 0),
1163
- units.length,
1164
- ]);
1165
-
1166
- // compute hvcC size in bytes
1167
- let length = config.length;
1168
- for (let i = 0; i < units.length; i += 1) {
1169
- length += 3;
1170
- for (let j = 0; j < units[i].length; j += 1) {
1171
- length += 2 + units[i][j].length;
1172
- }
1173
- }
1174
-
1175
- const hvcC = new Uint8Array(length);
1176
- hvcC.set(config, 0);
1177
- length = config.length;
1178
- // append parameter set units: one vps, one or more sps and pps
1179
- const iMax = units.length - 1;
1180
- for (let i = 0; i < units.length; i += 1) {
1181
- hvcC.set(
1182
- new Uint8Array([
1183
- (32 + i) | (i === iMax ? 128 : 0),
1184
- 0x00,
1185
- units[i].length,
1186
- ]),
1187
- length,
1188
- );
1189
- length += 3;
1190
- for (let j = 0; j < units[i].length; j += 1) {
1191
- hvcC.set(
1192
- new Uint8Array([units[i][j].length >> 8, units[i][j].length & 255]),
1193
- length,
1194
- );
1195
- length += 2;
1196
- hvcC.set(units[i][j], length);
1197
- length += units[i][j].length;
1198
- }
1199
- }
1200
- const hvcc = MP4.box(MP4.types.hvcC, hvcC);
1201
- const width = track.width;
1202
- const height = track.height;
1203
- const hSpacing = track.pixelRatio[0];
1204
- const vSpacing = track.pixelRatio[1];
1205
-
1206
- return MP4.box(
1207
- MP4.types.hvc1,
1208
- new Uint8Array([
1209
- 0x00,
1210
- 0x00,
1211
- 0x00, // reserved
1212
- 0x00,
1213
- 0x00,
1214
- 0x00, // reserved
1215
- 0x00,
1216
- 0x01, // data_reference_index
1217
- 0x00,
1218
- 0x00, // pre_defined
1219
- 0x00,
1220
- 0x00, // reserved
1221
- 0x00,
1222
- 0x00,
1223
- 0x00,
1224
- 0x00,
1225
- 0x00,
1226
- 0x00,
1227
- 0x00,
1228
- 0x00,
1229
- 0x00,
1230
- 0x00,
1231
- 0x00,
1232
- 0x00, // pre_defined
1233
- (width >> 8) & 0xff,
1234
- width & 0xff, // width
1235
- (height >> 8) & 0xff,
1236
- height & 0xff, // height
1237
- 0x00,
1238
- 0x48,
1239
- 0x00,
1240
- 0x00, // horizresolution
1241
- 0x00,
1242
- 0x48,
1243
- 0x00,
1244
- 0x00, // vertresolution
1245
- 0x00,
1246
- 0x00,
1247
- 0x00,
1248
- 0x00, // reserved
1249
- 0x00,
1250
- 0x01, // frame_count
1251
- 0x12,
1252
- 0x64,
1253
- 0x61,
1254
- 0x69,
1255
- 0x6c, // dailymotion/hls.js
1256
- 0x79,
1257
- 0x6d,
1258
- 0x6f,
1259
- 0x74,
1260
- 0x69,
1261
- 0x6f,
1262
- 0x6e,
1263
- 0x2f,
1264
- 0x68,
1265
- 0x6c,
1266
- 0x73,
1267
- 0x2e,
1268
- 0x6a,
1269
- 0x73,
1270
- 0x00,
1271
- 0x00,
1272
- 0x00,
1273
- 0x00,
1274
- 0x00,
1275
- 0x00,
1276
- 0x00,
1277
- 0x00,
1278
- 0x00,
1279
- 0x00,
1280
- 0x00,
1281
- 0x00,
1282
- 0x00, // compressorname
1283
- 0x00,
1284
- 0x18, // depth = 24
1285
- 0x11,
1286
- 0x11,
1287
- ]), // pre_defined = -1
1288
- hvcc,
1289
- MP4.box(
1290
- MP4.types.btrt,
1291
- new Uint8Array([
1292
- 0x00,
1293
- 0x1c,
1294
- 0x9c,
1295
- 0x80, // bufferSizeDB
1296
- 0x00,
1297
- 0x2d,
1298
- 0xc6,
1299
- 0xc0, // maxBitrate
1300
- 0x00,
1301
- 0x2d,
1302
- 0xc6,
1303
- 0xc0,
1304
- ]),
1305
- ), // avgBitrate
1306
- MP4.box(
1307
- MP4.types.pasp,
1308
- new Uint8Array([
1309
- hSpacing >> 24, // hSpacing
1310
- (hSpacing >> 16) & 0xff,
1311
- (hSpacing >> 8) & 0xff,
1312
- hSpacing & 0xff,
1313
- vSpacing >> 24, // vSpacing
1314
- (vSpacing >> 16) & 0xff,
1315
- (vSpacing >> 8) & 0xff,
1316
- vSpacing & 0xff,
1317
- ]),
1318
- ),
1319
- );
1320
- }
1321
1126
  }
1322
1127
 
1323
1128
  export default MP4;
@@ -4,7 +4,7 @@ import type { HlsEventEmitter } from '../events';
4
4
  import { Events } from '../events';
5
5
  import { ErrorTypes, ErrorDetails } from '../errors';
6
6
  import { logger } from '../utils/logger';
7
- import type {
7
+ import {
8
8
  InitSegmentData,
9
9
  Remuxer,
10
10
  RemuxerResult,
@@ -29,7 +29,6 @@ import type { TrackSet } from '../types/track';
29
29
  import type { SourceBufferName } from '../types/buffer';
30
30
  import type { Fragment } from '../loader/fragment';
31
31
  import type { HlsConfig } from '../config';
32
- import type { TypeSupported } from '../utils/codecs';
33
32
 
34
33
  const MAX_SILENT_FRAME_DURATION = 10 * 1000; // 10 seconds
35
34
  const AAC_SAMPLES_PER_FRAME = 1024;
@@ -42,7 +41,7 @@ let safariWebkitVersion: number | null = null;
42
41
  export default class MP4Remuxer implements Remuxer {
43
42
  private observer: HlsEventEmitter;
44
43
  private config: HlsConfig;
45
- private typeSupported: TypeSupported;
44
+ private typeSupported: any;
46
45
  private ISGenerated: boolean = false;
47
46
  private _initPTS: RationalTimestamp | null = null;
48
47
  private _initDTS: RationalTimestamp | null = null;
@@ -516,7 +515,7 @@ export default class MP4Remuxer implements Remuxer {
516
515
  if (foundHole || foundOverlap) {
517
516
  if (foundHole) {
518
517
  logger.warn(
519
- `${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
518
+ `AVC: ${toMsFromMpegTsClock(
520
519
  delta,
521
520
  true,
522
521
  )} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(
@@ -525,7 +524,7 @@ export default class MP4Remuxer implements Remuxer {
525
524
  );
526
525
  } else {
527
526
  logger.warn(
528
- `${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
527
+ `AVC: ${toMsFromMpegTsClock(
529
528
  -delta,
530
529
  true,
531
530
  )} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(
@@ -544,27 +543,12 @@ export default class MP4Remuxer implements Remuxer {
544
543
  inputSamples[0].dts = firstDTS;
545
544
  inputSamples[0].pts = firstPTS;
546
545
  } else {
547
- let isPTSOrderRetained = true;
548
546
  for (let i = 0; i < inputSamples.length; i++) {
549
- if (inputSamples[i].dts > firstPTS && isPTSOrderRetained) {
547
+ if (inputSamples[i].dts > firstPTS) {
550
548
  break;
551
549
  }
552
-
553
- const prevPTS = inputSamples[i].pts;
554
550
  inputSamples[i].dts -= delta;
555
551
  inputSamples[i].pts -= delta;
556
-
557
- // check to see if this sample's PTS order has changed
558
- // relative to the next one
559
- if (i < inputSamples.length - 1) {
560
- const nextSamplePTS = inputSamples[i + 1].pts;
561
- const currentSamplePTS = inputSamples[i].pts;
562
-
563
- const currentOrder = nextSamplePTS <= currentSamplePTS;
564
- const prevOrder = nextSamplePTS <= prevPTS;
565
-
566
- isPTSOrderRetained = currentOrder == prevOrder;
567
- }
568
552
  }
569
553
  }
570
554
  logger.log(
@@ -759,7 +743,7 @@ export default class MP4Remuxer implements Remuxer {
759
743
  }
760
744
  }
761
745
  }
762
- // next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
746
+ // next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
763
747
  mp4SampleDuration =
764
748
  stretchedLastFrame || !mp4SampleDuration
765
749
  ? averageSampleDuration
@@ -943,7 +927,7 @@ export default class MP4Remuxer implements Remuxer {
943
927
  for (let j = 0; j < missing; j++) {
944
928
  const newStamp = Math.max(nextPts as number, 0);
945
929
  let fillFrame = AAC.getSilentFrame(
946
- track.parsedCodec || track.manifestCodec || track.codec,
930
+ track.manifestCodec || track.codec,
947
931
  track.channelCount,
948
932
  );
949
933
  if (!fillFrame) {
@@ -1093,7 +1077,7 @@ export default class MP4Remuxer implements Remuxer {
1093
1077
  const nbSamples: number = Math.ceil((endDTS - startDTS) / frameDuration);
1094
1078
  // silent frame
1095
1079
  const silentFrame: Uint8Array | undefined = AAC.getSilentFrame(
1096
- track.parsedCodec || track.manifestCodec || track.codec,
1080
+ track.manifestCodec || track.codec,
1097
1081
  track.channelCount,
1098
1082
  );
1099
1083
 
package/src/task-loop.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { type ILogger, Logger } from './utils/logger';
2
-
3
1
  /**
4
2
  * @ignore
5
3
  * Sub-class specialization of EventHandler base class.
@@ -29,14 +27,13 @@ import { type ILogger, Logger } from './utils/logger';
29
27
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
30
28
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
31
29
  */
32
- export default class TaskLoop extends Logger {
30
+ export default class TaskLoop {
33
31
  private readonly _boundTick: () => void;
34
32
  private _tickTimer: number | null = null;
35
33
  private _tickInterval: number | null = null;
36
34
  private _tickCallCount = 0;
37
35
 
38
- constructor(label: string, logger: ILogger) {
39
- super(label, logger);
36
+ constructor() {
40
37
  this._boundTick = this.tick.bind(this);
41
38
  }
42
39
 
@@ -1,4 +1,4 @@
1
- import type EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator';
1
+ import EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator';
2
2
 
3
3
  export interface ComponentAPI {
4
4
  destroy(): void;
@@ -15,6 +15,4 @@ export interface AbrComponentAPI extends ComponentAPI {
15
15
  export interface NetworkComponentAPI extends ComponentAPI {
16
16
  startLoad(startPosition: number): void;
17
17
  stopLoad(): void;
18
- pauseBuffering?(): void;
19
- resumeBuffering?(): void;
20
18
  }
@@ -64,7 +64,6 @@ export interface DemuxedAudioTrack extends DemuxedTrack {
64
64
  segmentCodec?: string;
65
65
  channelCount?: number;
66
66
  manifestCodec?: string;
67
- parsedCodec?: string;
68
67
  samples: AudioSample[];
69
68
  }
70
69
 
@@ -73,14 +72,12 @@ export interface DemuxedVideoTrackBase extends DemuxedTrack {
73
72
  height?: number;
74
73
  pixelRatio?: [number, number];
75
74
  audFound?: boolean;
76
- vps?: Uint8Array[];
77
75
  pps?: Uint8Array[];
78
76
  sps?: Uint8Array[];
79
77
  naluState?: number;
80
78
  segmentCodec?: string;
81
79
  manifestCodec?: string;
82
80
  samples: VideoSample[] | Uint8Array;
83
- params?: object;
84
81
  }
85
82
 
86
83
  export interface DemuxedVideoTrack extends DemuxedVideoTrackBase {
@@ -42,10 +42,6 @@ export interface MediaAttachedData {
42
42
  mediaSource?: MediaSource;
43
43
  }
44
44
 
45
- export interface MediaEndedData {
46
- stalled: boolean;
47
- }
48
-
49
45
  export interface BufferCodecsData {
50
46
  video?: Track;
51
47
  audio?: Track;
@@ -1,5 +1,5 @@
1
1
  import type { TrackSet } from './track';
2
- import type {
2
+ import {
3
3
  DemuxedAudioTrack,
4
4
  DemuxedMetadataTrack,
5
5
  DemuxedUserdataTrack,
@@ -35,13 +35,19 @@ export class BufferHelper {
35
35
  * Return true if `media`'s buffered include `position`
36
36
  */
37
37
  static isBuffered(media: Bufferable, position: number): boolean {
38
- if (media) {
39
- const buffered = BufferHelper.getBuffered(media);
40
- for (let i = buffered.length; i--; ) {
41
- if (position >= buffered.start(i) && position <= buffered.end(i)) {
42
- return true;
38
+ try {
39
+ if (media) {
40
+ const buffered = BufferHelper.getBuffered(media);
41
+ for (let i = 0; i < buffered.length; i++) {
42
+ if (position >= buffered.start(i) && position <= buffered.end(i)) {
43
+ return true;
44
+ }
43
45
  }
44
46
  }
47
+ } catch (error) {
48
+ // this is to catch
49
+ // InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer':
50
+ // This SourceBuffer has been removed from the parent media source
45
51
  }
46
52
  return false;
47
53
  }
@@ -51,15 +57,21 @@ export class BufferHelper {
51
57
  pos: number,
52
58
  maxHoleDuration: number,
53
59
  ): BufferInfo {
54
- if (media) {
55
- const vbuffered = BufferHelper.getBuffered(media);
56
- if (vbuffered.length) {
60
+ try {
61
+ if (media) {
62
+ const vbuffered = BufferHelper.getBuffered(media);
57
63
  const buffered: BufferTimeRange[] = [];
58
- for (let i = 0; i < vbuffered.length; i++) {
64
+ let i: number;
65
+ for (i = 0; i < vbuffered.length; i++) {
59
66
  buffered.push({ start: vbuffered.start(i), end: vbuffered.end(i) });
60
67
  }
61
- return BufferHelper.bufferedInfo(buffered, pos, maxHoleDuration);
68
+
69
+ return this.bufferedInfo(buffered, pos, maxHoleDuration);
62
70
  }
71
+ } catch (error) {
72
+ // this is to catch
73
+ // InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer':
74
+ // This SourceBuffer has been removed from the parent media source
63
75
  }
64
76
  return { len: 0, start: pos, end: pos, nextStart: undefined };
65
77
  }
@@ -76,7 +88,14 @@ export class BufferHelper {
76
88
  } {
77
89
  pos = Math.max(0, pos);
78
90
  // sort on buffer.start/smaller end (IE does not always return sorted buffered range)
79
- buffered.sort((a, b) => a.start - b.start || b.end - a.end);
91
+ buffered.sort(function (a, b) {
92
+ const diff = a.start - b.start;
93
+ if (diff) {
94
+ return diff;
95
+ } else {
96
+ return b.end - a.end;
97
+ }
98
+ });
80
99
 
81
100
  let buffered2: BufferTimeRange[] = [];
82
101
  if (maxHoleDuration) {
@@ -145,7 +164,7 @@ export class BufferHelper {
145
164
  */
146
165
  static getBuffered(media: Bufferable): TimeRanges {
147
166
  try {
148
- return media.buffered || noopBuffered;
167
+ return media.buffered;
149
168
  } catch (e) {
150
169
  logger.log('failed to get media.buffered', e);
151
170
  return noopBuffered;
@@ -147,15 +147,12 @@ function getCodecCompatibleNameLower(
147
147
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec]!;
148
148
  }
149
149
 
150
+ // Idealy fLaC and Opus would be first (spec-compliant) but
151
+ // some browsers will report that fLaC is supported then fail.
152
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
150
153
  const codecsToCheck = {
151
- // Idealy fLaC and Opus would be first (spec-compliant) but
152
- // some browsers will report that fLaC is supported then fail.
153
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
154
154
  flac: ['flac', 'fLaC', 'FLAC'],
155
155
  opus: ['opus', 'Opus'],
156
- // Replace audio codec info if browser does not support mp4a.40.34,
157
- // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
158
- 'mp4a.40.34': ['mp3'],
159
156
  }[lowerCaseCodec];
160
157
 
161
158
  for (let i = 0; i < codecsToCheck.length; i++) {
@@ -168,18 +165,13 @@ function getCodecCompatibleNameLower(
168
165
  ) {
169
166
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
170
167
  return codecsToCheck[i];
171
- } else if (
172
- codecsToCheck[i] === 'mp3' &&
173
- getMediaSource(preferManagedMediaSource)?.isTypeSupported('audio/mpeg')
174
- ) {
175
- return '';
176
168
  }
177
169
  }
178
170
 
179
171
  return lowerCaseCodec;
180
172
  }
181
173
 
182
- const AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
174
+ const AUDIO_CODEC_REGEXP = /flac|opus/i;
183
175
  export function getCodecCompatibleName(
184
176
  codec: string,
185
177
  preferManagedMediaSource = true,
@@ -193,7 +185,7 @@ export function getCodecCompatibleName(
193
185
  }
194
186
 
195
187
  export function pickMostCompleteCodecName(
196
- parsedCodec: string | undefined,
188
+ parsedCodec: string,
197
189
  levelCodec: string | undefined,
198
190
  ): string | undefined {
199
191
  // Parsing of mp4a codecs strings in mp4-tools from media is incomplete as of d8c6c7a
@@ -217,24 +209,3 @@ export function convertAVC1ToAVCOTI(codec: string) {
217
209
  }
218
210
  return codec;
219
211
  }
220
-
221
- export interface TypeSupported {
222
- mpeg: boolean;
223
- mp3: boolean;
224
- ac3: boolean;
225
- }
226
-
227
- export function getM2TSSupportedAudioTypes(
228
- preferManagedMediaSource: boolean,
229
- ): TypeSupported {
230
- const MediaSource = getMediaSource(preferManagedMediaSource) || {
231
- isTypeSupported: () => false,
232
- };
233
- return {
234
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
235
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
236
- ac3: __USE_M2TS_ADVANCED_CODECS__
237
- ? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
238
- : false,
239
- };
240
- }
@@ -1,4 +1,4 @@
1
- import type {
1
+ import {
2
2
  LoaderCallbacks,
3
3
  LoaderContext,
4
4
  Loader,