hls.js 1.5.14-0.canary.10559 → 1.5.15

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 (109) hide show
  1. package/README.md +3 -4
  2. package/dist/hls-demo.js +38 -41
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +2911 -4558
  5. package/dist/hls.js.d.ts +112 -186
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +2291 -3311
  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 +1813 -2835
  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 +4707 -6356
  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 +42 -42
  20. package/src/config.ts +2 -5
  21. package/src/controller/abr-controller.ts +25 -39
  22. package/src/controller/audio-stream-controller.ts +136 -156
  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 +107 -263
  26. package/src/controller/buffer-controller.ts +97 -250
  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 +14 -51
  30. package/src/controller/content-steering-controller.ts +15 -29
  31. package/src/controller/eme-controller.ts +23 -10
  32. package/src/controller/error-controller.ts +22 -28
  33. package/src/controller/fps-controller.ts +3 -8
  34. package/src/controller/fragment-finders.ts +16 -44
  35. package/src/controller/fragment-tracker.ts +25 -58
  36. package/src/controller/gap-controller.ts +16 -43
  37. package/src/controller/id3-track-controller.ts +35 -45
  38. package/src/controller/latency-controller.ts +13 -18
  39. package/src/controller/level-controller.ts +19 -37
  40. package/src/controller/stream-controller.ts +83 -100
  41. package/src/controller/subtitle-stream-controller.ts +47 -35
  42. package/src/controller/subtitle-track-controller.ts +3 -5
  43. package/src/controller/timeline-controller.ts +22 -20
  44. package/src/crypt/aes-crypto.ts +2 -21
  45. package/src/crypt/decrypter.ts +16 -32
  46. package/src/crypt/fast-aes-key.ts +5 -28
  47. package/src/demux/audio/aacdemuxer.ts +5 -5
  48. package/src/demux/audio/ac3-demuxer.ts +4 -5
  49. package/src/demux/audio/adts.ts +4 -9
  50. package/src/demux/audio/base-audio-demuxer.ts +15 -21
  51. package/src/demux/audio/mp3demuxer.ts +3 -4
  52. package/src/demux/audio/mpegaudio.ts +1 -1
  53. package/src/demux/id3.ts +411 -0
  54. package/src/demux/inject-worker.ts +4 -38
  55. package/src/demux/mp4demuxer.ts +8 -17
  56. package/src/demux/sample-aes.ts +0 -2
  57. package/src/demux/transmuxer-interface.ts +83 -106
  58. package/src/demux/transmuxer-worker.ts +77 -111
  59. package/src/demux/transmuxer.ts +22 -46
  60. package/src/demux/tsdemuxer.ts +65 -131
  61. package/src/demux/video/avc-video-parser.ts +156 -219
  62. package/src/demux/video/base-video-parser.ts +9 -133
  63. package/src/demux/video/exp-golomb.ts +208 -0
  64. package/src/errors.ts +0 -2
  65. package/src/events.ts +1 -8
  66. package/src/exports-named.ts +1 -1
  67. package/src/hls.ts +48 -97
  68. package/src/loader/date-range.ts +5 -71
  69. package/src/loader/fragment-loader.ts +21 -23
  70. package/src/loader/fragment.ts +4 -8
  71. package/src/loader/key-loader.ts +1 -3
  72. package/src/loader/level-details.ts +6 -6
  73. package/src/loader/level-key.ts +9 -10
  74. package/src/loader/m3u8-parser.ts +144 -138
  75. package/src/loader/playlist-loader.ts +7 -5
  76. package/src/remux/mp4-generator.ts +1 -196
  77. package/src/remux/mp4-remuxer.ts +84 -55
  78. package/src/remux/passthrough-remuxer.ts +8 -23
  79. package/src/task-loop.ts +2 -5
  80. package/src/types/component-api.ts +1 -3
  81. package/src/types/demuxer.ts +1 -3
  82. package/src/types/events.ts +6 -19
  83. package/src/types/fragment-tracker.ts +2 -2
  84. package/src/types/general.ts +6 -0
  85. package/src/types/media-playlist.ts +1 -9
  86. package/src/types/remuxer.ts +1 -1
  87. package/src/utils/attr-list.ts +9 -96
  88. package/src/utils/buffer-helper.ts +31 -12
  89. package/src/utils/cea-608-parser.ts +3 -1
  90. package/src/utils/codecs.ts +5 -34
  91. package/src/utils/discontinuities.ts +47 -21
  92. package/src/utils/fetch-loader.ts +1 -1
  93. package/src/utils/hdr.ts +7 -4
  94. package/src/utils/imsc1-ttml-parser.ts +1 -1
  95. package/src/utils/keysystem-util.ts +6 -1
  96. package/src/utils/level-helper.ts +44 -71
  97. package/src/utils/logger.ts +23 -58
  98. package/src/utils/mp4-tools.ts +3 -5
  99. package/src/utils/rendition-helper.ts +74 -100
  100. package/src/utils/variable-substitution.ts +19 -0
  101. package/src/utils/webvtt-parser.ts +12 -2
  102. package/dist/hls.d.mts +0 -3179
  103. package/dist/hls.d.ts +0 -3179
  104. package/src/crypt/decrypter-aes-mode.ts +0 -4
  105. package/src/demux/video/hevc-video-parser.ts +0 -718
  106. package/src/utils/encryption-methods-util.ts +0 -21
  107. package/src/utils/hash.ts +0 -10
  108. package/src/utils/utf8-utils.ts +0 -18
  109. package/src/version.ts +0 -1
@@ -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;
@@ -3,7 +3,8 @@ import MP4 from './mp4-generator';
3
3
  import type { HlsEventEmitter } from '../events';
4
4
  import { Events } from '../events';
5
5
  import { ErrorTypes, ErrorDetails } from '../errors';
6
- import type {
6
+ import { logger } from '../utils/logger';
7
+ import {
7
8
  InitSegmentData,
8
9
  Remuxer,
9
10
  RemuxerResult,
@@ -26,9 +27,8 @@ import type {
26
27
  } from '../types/demuxer';
27
28
  import type { TrackSet } from '../types/track';
28
29
  import type { SourceBufferName } from '../types/buffer';
30
+ import type { Fragment } from '../loader/fragment';
29
31
  import type { HlsConfig } from '../config';
30
- import type { TypeSupported } from '../utils/codecs';
31
- import type { ILogger } from '../utils/logger';
32
32
 
33
33
  const MAX_SILENT_FRAME_DURATION = 10 * 1000; // 10 seconds
34
34
  const AAC_SAMPLES_PER_FRAME = 1024;
@@ -39,10 +39,9 @@ let chromeVersion: number | null = null;
39
39
  let safariWebkitVersion: number | null = null;
40
40
 
41
41
  export default class MP4Remuxer implements Remuxer {
42
- private readonly logger: ILogger;
43
- private readonly observer: HlsEventEmitter;
44
- private readonly config: HlsConfig;
45
- private readonly typeSupported: TypeSupported;
42
+ private observer: HlsEventEmitter;
43
+ private config: HlsConfig;
44
+ private typeSupported: any;
46
45
  private ISGenerated: boolean = false;
47
46
  private _initPTS: RationalTimestamp | null = null;
48
47
  private _initDTS: RationalTimestamp | null = null;
@@ -60,13 +59,12 @@ export default class MP4Remuxer implements Remuxer {
60
59
  constructor(
61
60
  observer: HlsEventEmitter,
62
61
  config: HlsConfig,
63
- typeSupported: TypeSupported,
64
- logger: ILogger,
62
+ typeSupported,
63
+ vendor = '',
65
64
  ) {
66
65
  this.observer = observer;
67
66
  this.config = config;
68
67
  this.typeSupported = typeSupported;
69
- this.logger = logger;
70
68
  this.ISGenerated = false;
71
69
 
72
70
  if (chromeVersion === null) {
@@ -86,18 +84,18 @@ export default class MP4Remuxer implements Remuxer {
86
84
  }
87
85
 
88
86
  resetTimeStamp(defaultTimeStamp: RationalTimestamp | null) {
89
- this.logger.log('[mp4-remuxer]: initPTS & initDTS reset');
87
+ logger.log('[mp4-remuxer]: initPTS & initDTS reset');
90
88
  this._initPTS = this._initDTS = defaultTimeStamp;
91
89
  }
92
90
 
93
91
  resetNextTimestamp() {
94
- this.logger.log('[mp4-remuxer]: reset next timestamp');
92
+ logger.log('[mp4-remuxer]: reset next timestamp');
95
93
  this.isVideoContiguous = false;
96
94
  this.isAudioContiguous = false;
97
95
  }
98
96
 
99
97
  resetInitSegment() {
100
- this.logger.log('[mp4-remuxer]: ISGenerated flag reset');
98
+ logger.log('[mp4-remuxer]: ISGenerated flag reset');
101
99
  this.ISGenerated = false;
102
100
  this.videoTrackConfig = undefined;
103
101
  }
@@ -117,7 +115,7 @@ export default class MP4Remuxer implements Remuxer {
117
115
  }
118
116
  }, videoSamples[0].pts);
119
117
  if (rolloverDetected) {
120
- this.logger.debug('PTS rollover detected');
118
+ logger.debug('PTS rollover detected');
121
119
  }
122
120
  return startPTS;
123
121
  }
@@ -161,18 +159,15 @@ export default class MP4Remuxer implements Remuxer {
161
159
  if (this.ISGenerated) {
162
160
  const config = this.videoTrackConfig;
163
161
  if (
164
- (config &&
165
- (videoTrack.width !== config.width ||
166
- videoTrack.height !== config.height ||
167
- videoTrack.pixelRatio?.[0] !== config.pixelRatio?.[0] ||
168
- videoTrack.pixelRatio?.[1] !== config.pixelRatio?.[1])) ||
169
- (!config && enoughVideoSamples) ||
170
- (this.nextAudioPts === null && enoughAudioSamples)
162
+ config &&
163
+ (videoTrack.width !== config.width ||
164
+ videoTrack.height !== config.height ||
165
+ videoTrack.pixelRatio?.[0] !== config.pixelRatio?.[0] ||
166
+ videoTrack.pixelRatio?.[1] !== config.pixelRatio?.[1])
171
167
  ) {
172
168
  this.resetInitSegment();
173
169
  }
174
- }
175
- if (!this.ISGenerated) {
170
+ } else {
176
171
  initSegment = this.generateIS(
177
172
  audioTrack,
178
173
  videoTrack,
@@ -190,7 +185,7 @@ export default class MP4Remuxer implements Remuxer {
190
185
  if (!isVideoContiguous && this.config.forceKeyFrameOnDiscontinuity) {
191
186
  independent = true;
192
187
  if (firstKeyFrameIndex > 0) {
193
- this.logger.warn(
188
+ logger.warn(
194
189
  `[mp4-remuxer]: Dropped ${firstKeyFrameIndex} out of ${length} video samples due to a missing keyframe`,
195
190
  );
196
191
  const startPTS = this.getVideoStartPts(videoTrack.samples);
@@ -201,7 +196,7 @@ export default class MP4Remuxer implements Remuxer {
201
196
  videoTrack.inputTimeScale;
202
197
  firstKeyFramePTS = videoTimeOffset;
203
198
  } else if (firstKeyFrameIndex === -1) {
204
- this.logger.warn(
199
+ logger.warn(
205
200
  `[mp4-remuxer]: No keyframe found out of ${length} video samples`,
206
201
  );
207
202
  independent = false;
@@ -227,7 +222,7 @@ export default class MP4Remuxer implements Remuxer {
227
222
  if (enoughAudioSamples) {
228
223
  // if initSegment was generated without audio samples, regenerate it again
229
224
  if (!audioTrack.samplerate) {
230
- this.logger.warn(
225
+ logger.warn(
231
226
  '[mp4-remuxer]: regenerate InitSegment as audio detected',
232
227
  );
233
228
  initSegment = this.generateIS(
@@ -252,7 +247,7 @@ export default class MP4Remuxer implements Remuxer {
252
247
  const audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0;
253
248
  // if initSegment was generated without video samples, regenerate it again
254
249
  if (!videoTrack.inputTimeScale) {
255
- this.logger.warn(
250
+ logger.warn(
256
251
  '[mp4-remuxer]: regenerate InitSegment as video detected',
257
252
  );
258
253
  initSegment = this.generateIS(
@@ -519,8 +514,8 @@ export default class MP4Remuxer implements Remuxer {
519
514
  const foundOverlap = delta < -1;
520
515
  if (foundHole || foundOverlap) {
521
516
  if (foundHole) {
522
- this.logger.warn(
523
- `${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
517
+ logger.warn(
518
+ `AVC: ${toMsFromMpegTsClock(
524
519
  delta,
525
520
  true,
526
521
  )} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(
@@ -528,8 +523,8 @@ export default class MP4Remuxer implements Remuxer {
528
523
  )}`,
529
524
  );
530
525
  } else {
531
- this.logger.warn(
532
- `${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(
526
+ logger.warn(
527
+ `AVC: ${toMsFromMpegTsClock(
533
528
  -delta,
534
529
  true,
535
530
  )} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(
@@ -548,30 +543,15 @@ export default class MP4Remuxer implements Remuxer {
548
543
  inputSamples[0].dts = firstDTS;
549
544
  inputSamples[0].pts = firstPTS;
550
545
  } else {
551
- let isPTSOrderRetained = true;
552
546
  for (let i = 0; i < inputSamples.length; i++) {
553
- if (inputSamples[i].dts > firstPTS && isPTSOrderRetained) {
547
+ if (inputSamples[i].dts > firstPTS) {
554
548
  break;
555
549
  }
556
-
557
- const prevPTS = inputSamples[i].pts;
558
550
  inputSamples[i].dts -= delta;
559
551
  inputSamples[i].pts -= delta;
560
-
561
- // check to see if this sample's PTS order has changed
562
- // relative to the next one
563
- if (i < inputSamples.length - 1) {
564
- const nextSamplePTS = inputSamples[i + 1].pts;
565
- const currentSamplePTS = inputSamples[i].pts;
566
-
567
- const currentOrder = nextSamplePTS <= currentSamplePTS;
568
- const prevOrder = nextSamplePTS <= prevPTS;
569
-
570
- isPTSOrderRetained = currentOrder == prevOrder;
571
- }
572
552
  }
573
553
  }
574
- this.logger.log(
554
+ logger.log(
575
555
  `Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(
576
556
  firstPTS,
577
557
  true,
@@ -693,7 +673,7 @@ export default class MP4Remuxer implements Remuxer {
693
673
  } else {
694
674
  stretchedLastFrame = true;
695
675
  }
696
- this.logger.log(
676
+ logger.log(
697
677
  `[mp4-remuxer]: It is approximately ${
698
678
  deltaToFrameEnd / 90
699
679
  } ms to the next segment; using duration ${
@@ -742,7 +722,7 @@ export default class MP4Remuxer implements Remuxer {
742
722
  averageSampleDuration / maxDtsDelta < 0.025 &&
743
723
  outputSamples[0].cts === 0
744
724
  ) {
745
- this.logger.warn(
725
+ logger.warn(
746
726
  'Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration.',
747
727
  );
748
728
  let dts = firstDTS;
@@ -763,7 +743,7 @@ export default class MP4Remuxer implements Remuxer {
763
743
  }
764
744
  }
765
745
  }
766
- // 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)
767
747
  mp4SampleDuration =
768
748
  stretchedLastFrame || !mp4SampleDuration
769
749
  ? averageSampleDuration
@@ -905,7 +885,7 @@ export default class MP4Remuxer implements Remuxer {
905
885
  alignedWithVideo
906
886
  ) {
907
887
  if (i === 0) {
908
- this.logger.warn(
888
+ logger.warn(
909
889
  `Audio frame @ ${(pts / inputTimeScale).toFixed(
910
890
  3,
911
891
  )}s overlaps nextAudioPts by ${Math.round(
@@ -937,7 +917,7 @@ export default class MP4Remuxer implements Remuxer {
937
917
  if (i === 0) {
938
918
  this.nextAudioPts = nextAudioPts = nextPts;
939
919
  }
940
- this.logger.warn(
920
+ logger.warn(
941
921
  `[mp4-remuxer]: Injecting ${missing} audio frame @ ${(
942
922
  nextPts / inputTimeScale
943
923
  ).toFixed(3)}s due to ${Math.round(
@@ -947,11 +927,11 @@ export default class MP4Remuxer implements Remuxer {
947
927
  for (let j = 0; j < missing; j++) {
948
928
  const newStamp = Math.max(nextPts as number, 0);
949
929
  let fillFrame = AAC.getSilentFrame(
950
- track.parsedCodec || track.manifestCodec || track.codec,
930
+ track.manifestCodec || track.codec,
951
931
  track.channelCount,
952
932
  );
953
933
  if (!fillFrame) {
954
- this.logger.log(
934
+ logger.log(
955
935
  '[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.',
956
936
  );
957
937
  fillFrame = sample.unit.subarray();
@@ -1070,6 +1050,55 @@ export default class MP4Remuxer implements Remuxer {
1070
1050
  this.isAudioContiguous = true;
1071
1051
  return audioData;
1072
1052
  }
1053
+
1054
+ remuxEmptyAudio(
1055
+ track: DemuxedAudioTrack,
1056
+ timeOffset: number,
1057
+ contiguous: boolean,
1058
+ videoData: Fragment,
1059
+ ): RemuxedTrack | undefined {
1060
+ const inputTimeScale: number = track.inputTimeScale;
1061
+ const mp4timeScale: number = track.samplerate
1062
+ ? track.samplerate
1063
+ : inputTimeScale;
1064
+ const scaleFactor: number = inputTimeScale / mp4timeScale;
1065
+ const nextAudioPts: number | null = this.nextAudioPts;
1066
+ // sync with video's timestamp
1067
+ const initDTS = this._initDTS as RationalTimestamp;
1068
+ const init90kHz = (initDTS.baseTime * 90000) / initDTS.timescale;
1069
+ const startDTS: number =
1070
+ (nextAudioPts !== null
1071
+ ? nextAudioPts
1072
+ : videoData.startDTS * inputTimeScale) + init90kHz;
1073
+ const endDTS: number = videoData.endDTS * inputTimeScale + init90kHz;
1074
+ // one sample's duration value
1075
+ const frameDuration: number = scaleFactor * AAC_SAMPLES_PER_FRAME;
1076
+ // samples count of this segment's duration
1077
+ const nbSamples: number = Math.ceil((endDTS - startDTS) / frameDuration);
1078
+ // silent frame
1079
+ const silentFrame: Uint8Array | undefined = AAC.getSilentFrame(
1080
+ track.manifestCodec || track.codec,
1081
+ track.channelCount,
1082
+ );
1083
+
1084
+ logger.warn('[mp4-remuxer]: remux empty Audio');
1085
+ // Can't remux if we can't generate a silent frame...
1086
+ if (!silentFrame) {
1087
+ logger.trace(
1088
+ '[mp4-remuxer]: Unable to remuxEmptyAudio since we were unable to get a silent frame for given audio codec',
1089
+ );
1090
+ return;
1091
+ }
1092
+
1093
+ const samples: Array<any> = [];
1094
+ for (let i = 0; i < nbSamples; i++) {
1095
+ const stamp = startDTS + i * frameDuration;
1096
+ samples.push({ unit: silentFrame, pts: stamp, dts: stamp });
1097
+ }
1098
+ track.samples = samples;
1099
+
1100
+ return this.remuxAudio(track, timeOffset, contiguous, false);
1101
+ }
1073
1102
  }
1074
1103
 
1075
1104
  export function normalizePts(value: number, reference: number | null): number {
@@ -14,9 +14,8 @@ import {
14
14
  parseInitSegment,
15
15
  } from '../utils/mp4-tools';
16
16
  import { ElementaryStreamTypes } from '../loader/fragment';
17
+ import { logger } from '../utils/logger';
17
18
  import { getCodecCompatibleName } from '../utils/codecs';
18
- import type { HlsEventEmitter } from '../events';
19
- import type { HlsConfig } from '../config';
20
19
  import type { TrackSet } from '../types/track';
21
20
  import type {
22
21
  InitSegmentData,
@@ -31,12 +30,9 @@ import type {
31
30
  PassthroughTrack,
32
31
  } from '../types/demuxer';
33
32
  import type { DecryptData } from '../loader/level-key';
34
- import type { TypeSupported } from '../utils/codecs';
35
- import type { ILogger } from '../utils/logger';
36
33
  import type { RationalTimestamp } from '../utils/timescale-conversion';
37
34
 
38
35
  class PassThroughRemuxer implements Remuxer {
39
- private readonly logger: ILogger;
40
36
  private emitInitSegment: boolean = false;
41
37
  private audioCodec?: string;
42
38
  private videoCodec?: string;
@@ -45,15 +41,6 @@ class PassThroughRemuxer implements Remuxer {
45
41
  private initTracks?: TrackSet;
46
42
  private lastEndTime: number | null = null;
47
43
 
48
- constructor(
49
- observer: HlsEventEmitter,
50
- config: HlsConfig,
51
- typeSupported: TypeSupported,
52
- logger: ILogger,
53
- ) {
54
- this.logger = logger;
55
- }
56
-
57
44
  public destroy() {}
58
45
 
59
46
  public resetTimeStamp(defaultInitPTS: RationalTimestamp | null) {
@@ -124,7 +111,7 @@ class PassThroughRemuxer implements Remuxer {
124
111
  id: 'main',
125
112
  };
126
113
  } else {
127
- this.logger.warn(
114
+ logger.warn(
128
115
  '[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes.',
129
116
  );
130
117
  }
@@ -173,9 +160,7 @@ class PassThroughRemuxer implements Remuxer {
173
160
  }
174
161
  if (!initData?.length) {
175
162
  // We can't remux if the initSegment could not be generated
176
- this.logger.warn(
177
- '[passthrough-remuxer.ts]: Failed to generate initSegment.',
178
- );
163
+ logger.warn('[passthrough-remuxer.ts]: Failed to generate initSegment.');
179
164
  return result;
180
165
  }
181
166
  if (this.emitInitSegment) {
@@ -192,8 +177,8 @@ class PassThroughRemuxer implements Remuxer {
192
177
  ) {
193
178
  initSegment.initPTS = decodeTime - timeOffset;
194
179
  if (initPTS && initPTS.timescale === 1) {
195
- this.logger.warn(
196
- `Adjusting initPTS @${timeOffset} from ${initPTS.baseTime / initPTS.timescale} to ${initSegment.initPTS}`,
180
+ logger.warn(
181
+ `Adjusting initPTS by ${initSegment.initPTS - initPTS.baseTime}`,
197
182
  );
198
183
  }
199
184
  this.initPTS = initPTS = {
@@ -211,7 +196,7 @@ class PassThroughRemuxer implements Remuxer {
211
196
  if (duration > 0) {
212
197
  this.lastEndTime = endTime;
213
198
  } else {
214
- this.logger.warn('Duration parsed from mp4 should be greater than zero');
199
+ logger.warn('Duration parsed from mp4 should be greater than zero');
215
200
  this.resetNextTimestamp();
216
201
  }
217
202
 
@@ -299,14 +284,14 @@ function getParsedTrackCodec(
299
284
  return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
300
285
  }
301
286
  const result = 'mp4a.40.5';
302
- this.logger.info(
287
+ logger.info(
303
288
  `Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`,
304
289
  );
305
290
  return result;
306
291
  }
307
292
  // Provide defaults based on codec type
308
293
  // This allows for some playback of some fmp4 playlists without CODECS defined in manifest
309
- this.logger.warn(`Unhandled video codec "${parsedCodec}"`);
294
+ logger.warn(`Unhandled video codec "${parsedCodec}"`);
310
295
  if (parsedCodec === 'hvc1' || parsedCodec === 'hev1') {
311
296
  return 'hvc1.1.6.L120.90';
312
297
  }
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 {
@@ -125,6 +122,7 @@ export interface VideoSample {
125
122
  key: boolean;
126
123
  frame: boolean;
127
124
  units: VideoSampleUnit[];
125
+ debug: string;
128
126
  length: number;
129
127
  }
130
128