hls.js 1.5.9 → 1.5.10-0.canary.10321

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 (90) 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 +3479 -2197
  5. package/dist/hls.js.d.ts +108 -85
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +2407 -1761
  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 +1994 -1321
  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 +2868 -1563
  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 +35 -35
  20. package/src/config.ts +3 -2
  21. package/src/controller/abr-controller.ts +24 -20
  22. package/src/controller/audio-stream-controller.ts +68 -74
  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 +160 -38
  26. package/src/controller/buffer-controller.ts +230 -92
  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 +6 -8
  33. package/src/controller/fps-controller.ts +8 -3
  34. package/src/controller/fragment-tracker.ts +15 -11
  35. package/src/controller/gap-controller.ts +43 -16
  36. package/src/controller/id3-track-controller.ts +7 -7
  37. package/src/controller/latency-controller.ts +9 -11
  38. package/src/controller/level-controller.ts +37 -19
  39. package/src/controller/stream-controller.ts +37 -32
  40. package/src/controller/subtitle-stream-controller.ts +28 -40
  41. package/src/controller/subtitle-track-controller.ts +5 -3
  42. package/src/controller/timeline-controller.ts +19 -21
  43. package/src/crypt/aes-crypto.ts +21 -2
  44. package/src/crypt/decrypter-aes-mode.ts +4 -0
  45. package/src/crypt/decrypter.ts +32 -16
  46. package/src/crypt/fast-aes-key.ts +28 -5
  47. package/src/demux/audio/aacdemuxer.ts +2 -2
  48. package/src/demux/audio/ac3-demuxer.ts +4 -3
  49. package/src/demux/audio/adts.ts +9 -4
  50. package/src/demux/audio/base-audio-demuxer.ts +16 -14
  51. package/src/demux/audio/mp3demuxer.ts +4 -3
  52. package/src/demux/audio/mpegaudio.ts +1 -1
  53. package/src/demux/mp4demuxer.ts +7 -7
  54. package/src/demux/sample-aes.ts +2 -0
  55. package/src/demux/transmuxer-interface.ts +4 -12
  56. package/src/demux/transmuxer-worker.ts +4 -4
  57. package/src/demux/transmuxer.ts +16 -3
  58. package/src/demux/tsdemuxer.ts +71 -37
  59. package/src/demux/video/avc-video-parser.ts +208 -119
  60. package/src/demux/video/base-video-parser.ts +147 -18
  61. package/src/demux/video/exp-golomb.ts +0 -208
  62. package/src/demux/video/hevc-video-parser.ts +749 -0
  63. package/src/empty-es.js +5 -0
  64. package/src/events.ts +8 -1
  65. package/src/exports-named.ts +1 -1
  66. package/src/hls.ts +61 -38
  67. package/src/loader/fragment-loader.ts +10 -3
  68. package/src/loader/key-loader.ts +3 -1
  69. package/src/loader/level-key.ts +10 -9
  70. package/src/loader/playlist-loader.ts +4 -5
  71. package/src/remux/mp4-generator.ts +196 -1
  72. package/src/remux/mp4-remuxer.ts +24 -8
  73. package/src/task-loop.ts +5 -2
  74. package/src/types/component-api.ts +3 -1
  75. package/src/types/demuxer.ts +4 -0
  76. package/src/types/events.ts +4 -0
  77. package/src/types/remuxer.ts +1 -1
  78. package/src/utils/buffer-helper.ts +12 -31
  79. package/src/utils/cea-608-parser.ts +1 -3
  80. package/src/utils/codecs.ts +34 -5
  81. package/src/utils/encryption-methods-util.ts +21 -0
  82. package/src/utils/fetch-loader.ts +1 -1
  83. package/src/utils/imsc1-ttml-parser.ts +1 -1
  84. package/src/utils/keysystem-util.ts +1 -6
  85. package/src/utils/logger.ts +58 -23
  86. package/src/utils/mp4-tools.ts +5 -3
  87. package/src/utils/utf8-utils.ts +18 -0
  88. package/src/utils/webvtt-parser.ts +1 -1
  89. package/src/utils/xhr-loader.ts +5 -5
  90. package/src/demux/id3.ts +0 -411
@@ -1,12 +1,15 @@
1
1
  import type { ParsedVideoSample } from '../tsdemuxer';
2
- import {
2
+ import type {
3
3
  DemuxedVideoTrack,
4
+ DemuxedUserdataTrack,
4
5
  VideoSample,
5
6
  VideoSampleUnit,
6
7
  } from '../../types/demuxer';
8
+ import type { PES } from '../tsdemuxer';
7
9
  import { logger } from '../../utils/logger';
10
+ import { appendUint8Array } from '../../utils/mp4-tools';
8
11
 
9
- class BaseVideoParser {
12
+ abstract class BaseVideoParser {
10
13
  protected VideoSample: ParsedVideoSample | null = null;
11
14
 
12
15
  protected createVideoSample(
@@ -26,22 +29,6 @@ class BaseVideoParser {
26
29
  };
27
30
  }
28
31
 
29
- protected getLastNalUnit(
30
- samples: VideoSample[],
31
- ): VideoSampleUnit | undefined {
32
- let VideoSample = this.VideoSample;
33
- let lastUnit: VideoSampleUnit | undefined;
34
- // try to fallback to previous sample if current one is empty
35
- if (!VideoSample || VideoSample.units.length === 0) {
36
- VideoSample = samples[samples.length - 1];
37
- }
38
- if (VideoSample?.units) {
39
- const units = VideoSample.units;
40
- lastUnit = units[units.length - 1];
41
- }
42
- return lastUnit;
43
- }
44
-
45
32
  protected pushAccessUnit(
46
33
  VideoSample: ParsedVideoSample,
47
34
  videoTrack: DemuxedVideoTrack,
@@ -69,6 +56,148 @@ class BaseVideoParser {
69
56
  );
70
57
  }
71
58
  }
59
+
60
+ abstract parsePES(
61
+ track: DemuxedVideoTrack,
62
+ textTrack: DemuxedUserdataTrack,
63
+ pes: PES,
64
+ last: boolean,
65
+ duration: number,
66
+ );
67
+
68
+ protected abstract getNALuType(data: Uint8Array, offset: number): number;
69
+
70
+ protected parseNALu(
71
+ track: DemuxedVideoTrack,
72
+ array: Uint8Array,
73
+ last: boolean,
74
+ ): Array<{
75
+ data: Uint8Array;
76
+ type: number;
77
+ state?: number;
78
+ }> {
79
+ const len = array.byteLength;
80
+ let state = track.naluState || 0;
81
+ const lastState = state;
82
+ const units: VideoSampleUnit[] = [];
83
+ let i = 0;
84
+ let value: number;
85
+ let overflow: number;
86
+ let unitType: number;
87
+ let lastUnitStart = -1;
88
+ let lastUnitType: number = 0;
89
+ // logger.log('PES:' + Hex.hexDump(array));
90
+
91
+ if (state === -1) {
92
+ // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
93
+ lastUnitStart = 0;
94
+ // NALu type is value read from offset 0
95
+ lastUnitType = this.getNALuType(array, 0);
96
+ state = 0;
97
+ i = 1;
98
+ }
99
+
100
+ while (i < len) {
101
+ value = array[i++];
102
+ // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
103
+ if (!state) {
104
+ state = value ? 0 : 1;
105
+ continue;
106
+ }
107
+ if (state === 1) {
108
+ state = value ? 0 : 2;
109
+ continue;
110
+ }
111
+ // here we have state either equal to 2 or 3
112
+ if (!value) {
113
+ state = 3;
114
+ } else if (value === 1) {
115
+ overflow = i - state - 1;
116
+ if (lastUnitStart >= 0) {
117
+ const unit: VideoSampleUnit = {
118
+ data: array.subarray(lastUnitStart, overflow),
119
+ type: lastUnitType,
120
+ };
121
+ if (track.lastNalu) {
122
+ units.push(track.lastNalu);
123
+ track.lastNalu = null;
124
+ }
125
+ // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
126
+ units.push(unit);
127
+ } else {
128
+ // lastUnitStart is undefined => this is the first start code found in this PES packet
129
+ // first check if start code delimiter is overlapping between 2 PES packets,
130
+ // ie it started in last packet (lastState not zero)
131
+ // and ended at the beginning of this PES packet (i <= 4 - lastState)
132
+ const lastUnit = track.lastNalu;
133
+ if (lastUnit) {
134
+ if (lastState && i <= 4 - lastState) {
135
+ // start delimiter overlapping between PES packets
136
+ // strip start delimiter bytes from the end of last NAL unit
137
+ // check if lastUnit had a state different from zero
138
+ if (lastUnit.state) {
139
+ // strip last bytes
140
+ lastUnit.data = lastUnit.data.subarray(
141
+ 0,
142
+ lastUnit.data.byteLength - lastState,
143
+ );
144
+ }
145
+ }
146
+ // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
147
+
148
+ if (overflow > 0) {
149
+ // logger.log('first NALU found with overflow:' + overflow);
150
+ lastUnit.data = appendUint8Array(
151
+ lastUnit.data,
152
+ array.subarray(0, overflow),
153
+ );
154
+ lastUnit.state = 0;
155
+ units.push(lastUnit);
156
+ track.lastNalu = null;
157
+ }
158
+ }
159
+ }
160
+ // check if we can read unit type
161
+ if (i < len) {
162
+ unitType = this.getNALuType(array, i);
163
+ // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
164
+ lastUnitStart = i;
165
+ lastUnitType = unitType;
166
+ state = 0;
167
+ } else {
168
+ // not enough byte to read unit type. let's read it on next PES parsing
169
+ state = -1;
170
+ }
171
+ } else {
172
+ state = 0;
173
+ }
174
+ }
175
+ if (lastUnitStart >= 0 && state >= 0) {
176
+ const unit: VideoSampleUnit = {
177
+ data: array.subarray(lastUnitStart, len),
178
+ type: lastUnitType,
179
+ state: state,
180
+ };
181
+ if (!last) {
182
+ track.lastNalu = unit;
183
+ // logger.log('store NALu to push it on next PES');
184
+ } else {
185
+ units.push(unit);
186
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
187
+ }
188
+ } else if (units.length === 0) {
189
+ // no NALu found
190
+ // append pes.data to previous NAL unit
191
+ const lastUnit = track.lastNalu;
192
+ if (lastUnit) {
193
+ lastUnit.data = appendUint8Array(lastUnit.data, array);
194
+ units.push(lastUnit);
195
+ track.lastNalu = null;
196
+ }
197
+ }
198
+ track.naluState = state;
199
+ return units;
200
+ }
72
201
  }
73
202
 
74
203
  export default BaseVideoParser;
@@ -148,214 +148,6 @@ class ExpGolomb {
148
148
  readUInt(): number {
149
149
  return this.readBits(32);
150
150
  }
151
-
152
- /**
153
- * Advance the ExpGolomb decoder past a scaling list. The scaling
154
- * list is optionally transmitted as part of a sequence parameter
155
- * set and is not relevant to transmuxing.
156
- * @param count the number of entries in this scaling list
157
- * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
158
- */
159
- skipScalingList(count: number): void {
160
- let lastScale = 8;
161
- let nextScale = 8;
162
- let deltaScale;
163
- for (let j = 0; j < count; j++) {
164
- if (nextScale !== 0) {
165
- deltaScale = this.readEG();
166
- nextScale = (lastScale + deltaScale + 256) % 256;
167
- }
168
- lastScale = nextScale === 0 ? lastScale : nextScale;
169
- }
170
- }
171
-
172
- /**
173
- * Read a sequence parameter set and return some interesting video
174
- * properties. A sequence parameter set is the H264 metadata that
175
- * describes the properties of upcoming video frames.
176
- * @returns an object with configuration parsed from the
177
- * sequence parameter set, including the dimensions of the
178
- * associated video frames.
179
- */
180
- readSPS(): {
181
- width: number;
182
- height: number;
183
- pixelRatio: [number, number];
184
- } {
185
- let frameCropLeftOffset = 0;
186
- let frameCropRightOffset = 0;
187
- let frameCropTopOffset = 0;
188
- let frameCropBottomOffset = 0;
189
- let numRefFramesInPicOrderCntCycle;
190
- let scalingListCount;
191
- let i;
192
- const readUByte = this.readUByte.bind(this);
193
- const readBits = this.readBits.bind(this);
194
- const readUEG = this.readUEG.bind(this);
195
- const readBoolean = this.readBoolean.bind(this);
196
- const skipBits = this.skipBits.bind(this);
197
- const skipEG = this.skipEG.bind(this);
198
- const skipUEG = this.skipUEG.bind(this);
199
- const skipScalingList = this.skipScalingList.bind(this);
200
-
201
- readUByte();
202
- const profileIdc = readUByte(); // profile_idc
203
- readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
204
- skipBits(3); // reserved_zero_3bits u(3),
205
- readUByte(); // level_idc u(8)
206
- skipUEG(); // seq_parameter_set_id
207
- // some profiles have more optional data we don't need
208
- if (
209
- profileIdc === 100 ||
210
- profileIdc === 110 ||
211
- profileIdc === 122 ||
212
- profileIdc === 244 ||
213
- profileIdc === 44 ||
214
- profileIdc === 83 ||
215
- profileIdc === 86 ||
216
- profileIdc === 118 ||
217
- profileIdc === 128
218
- ) {
219
- const chromaFormatIdc = readUEG();
220
- if (chromaFormatIdc === 3) {
221
- skipBits(1);
222
- } // separate_colour_plane_flag
223
-
224
- skipUEG(); // bit_depth_luma_minus8
225
- skipUEG(); // bit_depth_chroma_minus8
226
- skipBits(1); // qpprime_y_zero_transform_bypass_flag
227
- if (readBoolean()) {
228
- // seq_scaling_matrix_present_flag
229
- scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
230
- for (i = 0; i < scalingListCount; i++) {
231
- if (readBoolean()) {
232
- // seq_scaling_list_present_flag[ i ]
233
- if (i < 6) {
234
- skipScalingList(16);
235
- } else {
236
- skipScalingList(64);
237
- }
238
- }
239
- }
240
- }
241
- }
242
- skipUEG(); // log2_max_frame_num_minus4
243
- const picOrderCntType = readUEG();
244
- if (picOrderCntType === 0) {
245
- readUEG(); // log2_max_pic_order_cnt_lsb_minus4
246
- } else if (picOrderCntType === 1) {
247
- skipBits(1); // delta_pic_order_always_zero_flag
248
- skipEG(); // offset_for_non_ref_pic
249
- skipEG(); // offset_for_top_to_bottom_field
250
- numRefFramesInPicOrderCntCycle = readUEG();
251
- for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
252
- skipEG();
253
- } // offset_for_ref_frame[ i ]
254
- }
255
- skipUEG(); // max_num_ref_frames
256
- skipBits(1); // gaps_in_frame_num_value_allowed_flag
257
- const picWidthInMbsMinus1 = readUEG();
258
- const picHeightInMapUnitsMinus1 = readUEG();
259
- const frameMbsOnlyFlag = readBits(1);
260
- if (frameMbsOnlyFlag === 0) {
261
- skipBits(1);
262
- } // mb_adaptive_frame_field_flag
263
-
264
- skipBits(1); // direct_8x8_inference_flag
265
- if (readBoolean()) {
266
- // frame_cropping_flag
267
- frameCropLeftOffset = readUEG();
268
- frameCropRightOffset = readUEG();
269
- frameCropTopOffset = readUEG();
270
- frameCropBottomOffset = readUEG();
271
- }
272
- let pixelRatio: [number, number] = [1, 1];
273
- if (readBoolean()) {
274
- // vui_parameters_present_flag
275
- if (readBoolean()) {
276
- // aspect_ratio_info_present_flag
277
- const aspectRatioIdc = readUByte();
278
- switch (aspectRatioIdc) {
279
- case 1:
280
- pixelRatio = [1, 1];
281
- break;
282
- case 2:
283
- pixelRatio = [12, 11];
284
- break;
285
- case 3:
286
- pixelRatio = [10, 11];
287
- break;
288
- case 4:
289
- pixelRatio = [16, 11];
290
- break;
291
- case 5:
292
- pixelRatio = [40, 33];
293
- break;
294
- case 6:
295
- pixelRatio = [24, 11];
296
- break;
297
- case 7:
298
- pixelRatio = [20, 11];
299
- break;
300
- case 8:
301
- pixelRatio = [32, 11];
302
- break;
303
- case 9:
304
- pixelRatio = [80, 33];
305
- break;
306
- case 10:
307
- pixelRatio = [18, 11];
308
- break;
309
- case 11:
310
- pixelRatio = [15, 11];
311
- break;
312
- case 12:
313
- pixelRatio = [64, 33];
314
- break;
315
- case 13:
316
- pixelRatio = [160, 99];
317
- break;
318
- case 14:
319
- pixelRatio = [4, 3];
320
- break;
321
- case 15:
322
- pixelRatio = [3, 2];
323
- break;
324
- case 16:
325
- pixelRatio = [2, 1];
326
- break;
327
- case 255: {
328
- pixelRatio = [
329
- (readUByte() << 8) | readUByte(),
330
- (readUByte() << 8) | readUByte(),
331
- ];
332
- break;
333
- }
334
- }
335
- }
336
- }
337
- return {
338
- width: Math.ceil(
339
- (picWidthInMbsMinus1 + 1) * 16 -
340
- frameCropLeftOffset * 2 -
341
- frameCropRightOffset * 2,
342
- ),
343
- height:
344
- (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 -
345
- (frameMbsOnlyFlag ? 2 : 4) *
346
- (frameCropTopOffset + frameCropBottomOffset),
347
- pixelRatio: pixelRatio,
348
- };
349
- }
350
-
351
- readSliceType() {
352
- // skip NALu type
353
- this.readUByte();
354
- // discard first_mb_in_slice
355
- this.readUEG();
356
- // return slice_type
357
- return this.readUEG();
358
- }
359
151
  }
360
152
 
361
153
  export default ExpGolomb;