@zenvor/hls.js 1.0.0

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 (159) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +472 -0
  3. package/dist/hls-demo.js +26995 -0
  4. package/dist/hls-demo.js.map +1 -0
  5. package/dist/hls.d.mts +4204 -0
  6. package/dist/hls.d.ts +4204 -0
  7. package/dist/hls.js +40050 -0
  8. package/dist/hls.js.d.ts +4204 -0
  9. package/dist/hls.js.map +1 -0
  10. package/dist/hls.light.js +27145 -0
  11. package/dist/hls.light.js.map +1 -0
  12. package/dist/hls.light.min.js +2 -0
  13. package/dist/hls.light.min.js.map +1 -0
  14. package/dist/hls.light.mjs +26392 -0
  15. package/dist/hls.light.mjs.map +1 -0
  16. package/dist/hls.min.js +2 -0
  17. package/dist/hls.min.js.map +1 -0
  18. package/dist/hls.mjs +38956 -0
  19. package/dist/hls.mjs.map +1 -0
  20. package/dist/hls.worker.js +2 -0
  21. package/dist/hls.worker.js.map +1 -0
  22. package/package.json +143 -0
  23. package/src/config.ts +794 -0
  24. package/src/controller/abr-controller.ts +1019 -0
  25. package/src/controller/algo-data-controller.ts +794 -0
  26. package/src/controller/audio-stream-controller.ts +1099 -0
  27. package/src/controller/audio-track-controller.ts +454 -0
  28. package/src/controller/base-playlist-controller.ts +438 -0
  29. package/src/controller/base-stream-controller.ts +2526 -0
  30. package/src/controller/buffer-controller.ts +2015 -0
  31. package/src/controller/buffer-operation-queue.ts +159 -0
  32. package/src/controller/cap-level-controller.ts +367 -0
  33. package/src/controller/cmcd-controller.ts +422 -0
  34. package/src/controller/content-steering-controller.ts +622 -0
  35. package/src/controller/eme-controller.ts +1617 -0
  36. package/src/controller/error-controller.ts +627 -0
  37. package/src/controller/fps-controller.ts +146 -0
  38. package/src/controller/fragment-finders.ts +256 -0
  39. package/src/controller/fragment-tracker.ts +567 -0
  40. package/src/controller/gap-controller.ts +719 -0
  41. package/src/controller/id3-track-controller.ts +488 -0
  42. package/src/controller/interstitial-player.ts +302 -0
  43. package/src/controller/interstitials-controller.ts +2895 -0
  44. package/src/controller/interstitials-schedule.ts +698 -0
  45. package/src/controller/latency-controller.ts +294 -0
  46. package/src/controller/level-controller.ts +776 -0
  47. package/src/controller/stream-controller.ts +1597 -0
  48. package/src/controller/subtitle-stream-controller.ts +508 -0
  49. package/src/controller/subtitle-track-controller.ts +617 -0
  50. package/src/controller/timeline-controller.ts +677 -0
  51. package/src/crypt/aes-crypto.ts +36 -0
  52. package/src/crypt/aes-decryptor.ts +339 -0
  53. package/src/crypt/decrypter-aes-mode.ts +4 -0
  54. package/src/crypt/decrypter.ts +225 -0
  55. package/src/crypt/fast-aes-key.ts +39 -0
  56. package/src/define-plugin.d.ts +17 -0
  57. package/src/demux/audio/aacdemuxer.ts +126 -0
  58. package/src/demux/audio/ac3-demuxer.ts +170 -0
  59. package/src/demux/audio/adts.ts +249 -0
  60. package/src/demux/audio/base-audio-demuxer.ts +205 -0
  61. package/src/demux/audio/dolby.ts +21 -0
  62. package/src/demux/audio/mp3demuxer.ts +85 -0
  63. package/src/demux/audio/mpegaudio.ts +177 -0
  64. package/src/demux/chunk-cache.ts +42 -0
  65. package/src/demux/dummy-demuxed-track.ts +13 -0
  66. package/src/demux/inject-worker.ts +75 -0
  67. package/src/demux/mp4demuxer.ts +234 -0
  68. package/src/demux/sample-aes.ts +198 -0
  69. package/src/demux/transmuxer-interface.ts +449 -0
  70. package/src/demux/transmuxer-worker.ts +221 -0
  71. package/src/demux/transmuxer.ts +560 -0
  72. package/src/demux/tsdemuxer.ts +1256 -0
  73. package/src/demux/video/avc-video-parser.ts +401 -0
  74. package/src/demux/video/base-video-parser.ts +198 -0
  75. package/src/demux/video/exp-golomb.ts +153 -0
  76. package/src/demux/video/hevc-video-parser.ts +736 -0
  77. package/src/empty-es.js +5 -0
  78. package/src/empty.js +3 -0
  79. package/src/errors.ts +107 -0
  80. package/src/events.ts +548 -0
  81. package/src/exports-default.ts +3 -0
  82. package/src/exports-named.ts +81 -0
  83. package/src/hls.ts +1613 -0
  84. package/src/is-supported.ts +54 -0
  85. package/src/loader/date-range.ts +207 -0
  86. package/src/loader/fragment-loader.ts +403 -0
  87. package/src/loader/fragment.ts +487 -0
  88. package/src/loader/interstitial-asset-list.ts +162 -0
  89. package/src/loader/interstitial-event.ts +337 -0
  90. package/src/loader/key-loader.ts +439 -0
  91. package/src/loader/level-details.ts +203 -0
  92. package/src/loader/level-key.ts +259 -0
  93. package/src/loader/load-stats.ts +17 -0
  94. package/src/loader/m3u8-parser.ts +1072 -0
  95. package/src/loader/playlist-loader.ts +839 -0
  96. package/src/polyfills/number.ts +15 -0
  97. package/src/remux/aac-helper.ts +81 -0
  98. package/src/remux/mp4-generator.ts +1380 -0
  99. package/src/remux/mp4-remuxer.ts +1261 -0
  100. package/src/remux/passthrough-remuxer.ts +434 -0
  101. package/src/task-loop.ts +130 -0
  102. package/src/types/algo.ts +44 -0
  103. package/src/types/buffer.ts +105 -0
  104. package/src/types/component-api.ts +20 -0
  105. package/src/types/demuxer.ts +208 -0
  106. package/src/types/events.ts +574 -0
  107. package/src/types/fragment-tracker.ts +23 -0
  108. package/src/types/level.ts +268 -0
  109. package/src/types/loader.ts +198 -0
  110. package/src/types/media-playlist.ts +92 -0
  111. package/src/types/network-details.ts +3 -0
  112. package/src/types/remuxer.ts +104 -0
  113. package/src/types/track.ts +12 -0
  114. package/src/types/transmuxer.ts +46 -0
  115. package/src/types/tuples.ts +6 -0
  116. package/src/types/vtt.ts +11 -0
  117. package/src/utils/arrays.ts +22 -0
  118. package/src/utils/attr-list.ts +192 -0
  119. package/src/utils/binary-search.ts +46 -0
  120. package/src/utils/buffer-helper.ts +173 -0
  121. package/src/utils/cea-608-parser.ts +1413 -0
  122. package/src/utils/chunker.ts +41 -0
  123. package/src/utils/codecs.ts +314 -0
  124. package/src/utils/cues.ts +96 -0
  125. package/src/utils/discontinuities.ts +174 -0
  126. package/src/utils/encryption-methods-util.ts +21 -0
  127. package/src/utils/error-helper.ts +95 -0
  128. package/src/utils/event-listener-helper.ts +16 -0
  129. package/src/utils/ewma-bandwidth-estimator.ts +97 -0
  130. package/src/utils/ewma.ts +43 -0
  131. package/src/utils/fetch-loader.ts +331 -0
  132. package/src/utils/global.ts +2 -0
  133. package/src/utils/hash.ts +10 -0
  134. package/src/utils/hdr.ts +67 -0
  135. package/src/utils/hex.ts +32 -0
  136. package/src/utils/imsc1-ttml-parser.ts +261 -0
  137. package/src/utils/keysystem-util.ts +45 -0
  138. package/src/utils/level-helper.ts +629 -0
  139. package/src/utils/logger.ts +120 -0
  140. package/src/utils/media-option-attributes.ts +49 -0
  141. package/src/utils/mediacapabilities-helper.ts +301 -0
  142. package/src/utils/mediakeys-helper.ts +210 -0
  143. package/src/utils/mediasource-helper.ts +37 -0
  144. package/src/utils/mp4-tools.ts +1473 -0
  145. package/src/utils/number.ts +3 -0
  146. package/src/utils/numeric-encoding-utils.ts +26 -0
  147. package/src/utils/output-filter.ts +46 -0
  148. package/src/utils/rendition-helper.ts +505 -0
  149. package/src/utils/safe-json-stringify.ts +22 -0
  150. package/src/utils/texttrack-utils.ts +164 -0
  151. package/src/utils/time-ranges.ts +17 -0
  152. package/src/utils/timescale-conversion.ts +46 -0
  153. package/src/utils/utf8-utils.ts +18 -0
  154. package/src/utils/variable-substitution.ts +105 -0
  155. package/src/utils/vttcue.ts +384 -0
  156. package/src/utils/vttparser.ts +497 -0
  157. package/src/utils/webvtt-parser.ts +166 -0
  158. package/src/utils/xhr-loader.ts +337 -0
  159. package/src/version.ts +1 -0
@@ -0,0 +1,234 @@
1
+ /**
2
+ * MP4 demuxer
3
+ */
4
+ import { dummyTrack } from './dummy-demuxed-track';
5
+ import {
6
+ type DemuxedAudioTrack,
7
+ type DemuxedMetadataTrack,
8
+ type DemuxedUserdataTrack,
9
+ type Demuxer,
10
+ type DemuxerResult,
11
+ type KeyData,
12
+ MetadataSchema,
13
+ type PassthroughTrack,
14
+ } from '../types/demuxer';
15
+ import {
16
+ appendUint8Array,
17
+ findBox,
18
+ hasMoofData,
19
+ parseEmsg,
20
+ parseInitSegment,
21
+ parseSamples,
22
+ RemuxerTrackIdConfig,
23
+ segmentValidRange,
24
+ } from '../utils/mp4-tools';
25
+ import type { HlsConfig } from '../config';
26
+ import type { HlsEventEmitter } from '../events';
27
+ import type { IEmsgParsingData } from '../utils/mp4-tools';
28
+
29
+ const emsgSchemePattern = /\/emsg[-/]ID3/i;
30
+
31
+ class MP4Demuxer implements Demuxer {
32
+ private remainderData: Uint8Array<ArrayBuffer> | null = null;
33
+ private timeOffset: number = 0;
34
+ private config: HlsConfig;
35
+ private videoTrack?: PassthroughTrack;
36
+ private audioTrack?: DemuxedAudioTrack;
37
+ private id3Track?: DemuxedMetadataTrack;
38
+ private txtTrack?: DemuxedUserdataTrack;
39
+
40
+ constructor(observer: HlsEventEmitter, config: HlsConfig) {
41
+ this.config = config;
42
+ }
43
+
44
+ public resetTimeStamp() {}
45
+
46
+ public resetInitSegment(
47
+ initSegment: Uint8Array | undefined,
48
+ audioCodec: string | undefined,
49
+ videoCodec: string | undefined,
50
+ trackDuration: number,
51
+ ) {
52
+ const videoTrack = (this.videoTrack = dummyTrack(
53
+ 'video',
54
+ 1,
55
+ ) as PassthroughTrack);
56
+ const audioTrack = (this.audioTrack = dummyTrack(
57
+ 'audio',
58
+ 1,
59
+ ) as DemuxedAudioTrack);
60
+ const captionTrack = (this.txtTrack = dummyTrack(
61
+ 'text',
62
+ 1,
63
+ ) as DemuxedUserdataTrack);
64
+
65
+ this.id3Track = dummyTrack('id3', 1) as DemuxedMetadataTrack;
66
+ this.timeOffset = 0;
67
+
68
+ if (!initSegment?.byteLength) {
69
+ return;
70
+ }
71
+ const initData = parseInitSegment(initSegment);
72
+
73
+ if (initData.video) {
74
+ const { id, timescale, codec, supplemental } = initData.video;
75
+ videoTrack.id = id;
76
+ videoTrack.timescale = captionTrack.timescale = timescale;
77
+ videoTrack.codec = codec;
78
+ videoTrack.supplemental = supplemental;
79
+ }
80
+
81
+ if (initData.audio) {
82
+ const { id, timescale, codec } = initData.audio;
83
+ audioTrack.id = id;
84
+ audioTrack.timescale = timescale;
85
+ audioTrack.codec = codec;
86
+ }
87
+
88
+ captionTrack.id = RemuxerTrackIdConfig.text;
89
+ videoTrack.sampleDuration = 0;
90
+ videoTrack.duration = audioTrack.duration = trackDuration;
91
+ }
92
+
93
+ public resetContiguity(): void {
94
+ this.remainderData = null;
95
+ }
96
+
97
+ static probe(data: Uint8Array) {
98
+ return hasMoofData(data);
99
+ }
100
+
101
+ public demux(
102
+ data: Uint8Array<ArrayBuffer>,
103
+ timeOffset: number,
104
+ ): DemuxerResult {
105
+ this.timeOffset = timeOffset;
106
+ // Load all data into the avc track. The CMAF remuxer will look for the data in the samples object; the rest of the fields do not matter
107
+ let videoSamples = data;
108
+ const videoTrack = this.videoTrack as PassthroughTrack;
109
+ const textTrack = this.txtTrack as DemuxedUserdataTrack;
110
+ if (this.config.progressive) {
111
+ // Split the bytestream into two ranges: one encompassing all data up until the start of the last moof, and everything else.
112
+ // This is done to guarantee that we're sending valid data to MSE - when demuxing progressively, we have no guarantee
113
+ // that the fetch loader gives us flush moof+mdat pairs. If we push jagged data to MSE, it will throw an exception.
114
+ if (this.remainderData) {
115
+ videoSamples = appendUint8Array(this.remainderData, data);
116
+ }
117
+ const segmentedData = segmentValidRange(videoSamples);
118
+ this.remainderData = segmentedData.remainder;
119
+ videoTrack.samples = segmentedData.valid || new Uint8Array();
120
+ } else {
121
+ videoTrack.samples = videoSamples;
122
+ }
123
+ const id3Track = this.extractID3Track(videoTrack, timeOffset);
124
+ textTrack.samples = parseSamples(timeOffset, videoTrack);
125
+
126
+ return {
127
+ videoTrack,
128
+ audioTrack: this.audioTrack as DemuxedAudioTrack,
129
+ id3Track,
130
+ textTrack: this.txtTrack as DemuxedUserdataTrack,
131
+ };
132
+ }
133
+
134
+ public flush() {
135
+ const timeOffset = this.timeOffset;
136
+ const videoTrack = this.videoTrack as PassthroughTrack;
137
+ const textTrack = this.txtTrack as DemuxedUserdataTrack;
138
+ videoTrack.samples = this.remainderData || new Uint8Array();
139
+ this.remainderData = null;
140
+
141
+ const id3Track = this.extractID3Track(videoTrack, this.timeOffset);
142
+ textTrack.samples = parseSamples(timeOffset, videoTrack);
143
+
144
+ return {
145
+ videoTrack,
146
+ audioTrack: dummyTrack() as DemuxedAudioTrack,
147
+ id3Track,
148
+ textTrack: dummyTrack() as DemuxedUserdataTrack,
149
+ };
150
+ }
151
+
152
+ private extractID3Track(
153
+ videoTrack: PassthroughTrack,
154
+ timeOffset: number,
155
+ ): DemuxedMetadataTrack {
156
+ const id3Track = this.id3Track as DemuxedMetadataTrack;
157
+ if (videoTrack.samples.length) {
158
+ const emsgs = findBox(videoTrack.samples, ['emsg']);
159
+ if (emsgs) {
160
+ emsgs.forEach((data: Uint8Array) => {
161
+ const emsgInfo = parseEmsg(data);
162
+ if (emsgSchemePattern.test(emsgInfo.schemeIdUri)) {
163
+ const pts = getEmsgStartTime(emsgInfo, timeOffset);
164
+ let duration =
165
+ emsgInfo.eventDuration === 0xffffffff
166
+ ? Number.POSITIVE_INFINITY
167
+ : emsgInfo.eventDuration / emsgInfo.timeScale;
168
+ // Safari takes anything <= 0.001 seconds and maps it to Infinity
169
+ if (duration <= 0.001) {
170
+ duration = Number.POSITIVE_INFINITY;
171
+ }
172
+ const payload = emsgInfo.payload;
173
+ id3Track.samples.push({
174
+ data: payload,
175
+ len: payload.byteLength,
176
+ dts: pts,
177
+ pts: pts,
178
+ type: MetadataSchema.emsg,
179
+ duration: duration,
180
+ });
181
+ } else if (this.config.enableEmsgKLVMetadata) {
182
+ const klvSchemaUri =
183
+ this.config.emsgKLVSchemaUri || MetadataSchema.misbklv;
184
+ if (emsgInfo.schemeIdUri.startsWith(klvSchemaUri)) {
185
+ const pts = getEmsgStartTime(emsgInfo, timeOffset);
186
+ id3Track.samples.push({
187
+ data: emsgInfo.payload,
188
+ len: emsgInfo.payload.byteLength,
189
+ dts: pts,
190
+ pts: pts,
191
+ type: MetadataSchema.misbklv,
192
+ duration: Number.POSITIVE_INFINITY,
193
+ });
194
+ }
195
+ }
196
+ });
197
+ }
198
+ }
199
+ return id3Track;
200
+ }
201
+
202
+ demuxSampleAes(
203
+ data: Uint8Array,
204
+ keyData: KeyData,
205
+ timeOffset: number,
206
+ ): Promise<DemuxerResult> {
207
+ return Promise.reject(
208
+ new Error('The MP4 demuxer does not support SAMPLE-AES decryption'),
209
+ );
210
+ }
211
+
212
+ destroy() {
213
+ // @ts-ignore
214
+ this.config = null;
215
+ this.remainderData = null;
216
+ this.videoTrack =
217
+ this.audioTrack =
218
+ this.id3Track =
219
+ this.txtTrack =
220
+ undefined;
221
+ }
222
+ }
223
+
224
+ function getEmsgStartTime(
225
+ emsgInfo: IEmsgParsingData,
226
+ timeOffset: number,
227
+ ): number {
228
+ return Number.isFinite(emsgInfo.presentationTime)
229
+ ? (emsgInfo.presentationTime as number) / emsgInfo.timeScale
230
+ : timeOffset +
231
+ (emsgInfo.presentationTimeDelta as number) / emsgInfo.timeScale;
232
+ }
233
+
234
+ export default MP4Demuxer;
@@ -0,0 +1,198 @@
1
+ /**
2
+ * SAMPLE-AES decrypter
3
+ */
4
+
5
+ import Decrypter from '../crypt/decrypter';
6
+ import { DecrypterAesMode } from '../crypt/decrypter-aes-mode';
7
+ import { discardEPB } from '../utils/mp4-tools';
8
+ import type { HlsConfig } from '../config';
9
+ import type { HlsEventEmitter } from '../events';
10
+ import type {
11
+ AACAudioSample,
12
+ DemuxedVideoTrackBase,
13
+ KeyData,
14
+ VideoSample,
15
+ VideoSampleUnit,
16
+ } from '../types/demuxer';
17
+
18
+ class SampleAesDecrypter {
19
+ private keyData: KeyData;
20
+ private decrypter: Decrypter;
21
+
22
+ constructor(observer: HlsEventEmitter, config: HlsConfig, keyData: KeyData) {
23
+ this.keyData = keyData;
24
+ this.decrypter = new Decrypter(config, {
25
+ removePKCS7Padding: false,
26
+ });
27
+ }
28
+
29
+ decryptBuffer(encryptedData: Uint8Array | ArrayBuffer): Promise<ArrayBuffer> {
30
+ return this.decrypter.decrypt(
31
+ encryptedData,
32
+ this.keyData.key.buffer,
33
+ this.keyData.iv.buffer,
34
+ DecrypterAesMode.cbc,
35
+ );
36
+ }
37
+
38
+ // AAC - encrypt all full 16 bytes blocks starting from offset 16
39
+ private decryptAacSample(
40
+ samples: AACAudioSample[],
41
+ sampleIndex: number,
42
+ callback: () => void,
43
+ ) {
44
+ const curUnit = samples[sampleIndex].unit;
45
+ if (curUnit.length <= 16) {
46
+ // No encrypted portion in this sample (first 16 bytes is not
47
+ // encrypted, see https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/HLS_Sample_Encryption/Encryption/Encryption.html),
48
+ return;
49
+ }
50
+ const encryptedData = curUnit.subarray(
51
+ 16,
52
+ curUnit.length - (curUnit.length % 16),
53
+ );
54
+ const encryptedBuffer = encryptedData.buffer.slice(
55
+ encryptedData.byteOffset,
56
+ encryptedData.byteOffset + encryptedData.length,
57
+ );
58
+
59
+ this.decryptBuffer(encryptedBuffer)
60
+ .then((decryptedBuffer: ArrayBuffer) => {
61
+ const decryptedData = new Uint8Array(decryptedBuffer);
62
+ curUnit.set(decryptedData, 16);
63
+
64
+ if (!this.decrypter.isSync()) {
65
+ this.decryptAacSamples(samples, sampleIndex + 1, callback);
66
+ }
67
+ })
68
+ .catch(callback);
69
+ }
70
+
71
+ decryptAacSamples(
72
+ samples: AACAudioSample[],
73
+ sampleIndex: number,
74
+ callback: () => void,
75
+ ) {
76
+ for (; ; sampleIndex++) {
77
+ if (sampleIndex >= samples.length) {
78
+ callback();
79
+ return;
80
+ }
81
+
82
+ if (samples[sampleIndex].unit.length < 32) {
83
+ continue;
84
+ }
85
+
86
+ this.decryptAacSample(samples, sampleIndex, callback);
87
+
88
+ if (!this.decrypter.isSync()) {
89
+ return;
90
+ }
91
+ }
92
+ }
93
+
94
+ // AVC - encrypt one 16 bytes block out of ten, starting from offset 32
95
+ getAvcEncryptedData(decodedData: Uint8Array) {
96
+ const encryptedDataLen =
97
+ Math.floor((decodedData.length - 48) / 160) * 16 + 16;
98
+ const encryptedData = new Int8Array(encryptedDataLen);
99
+ let outputPos = 0;
100
+ for (
101
+ let inputPos = 32;
102
+ inputPos < decodedData.length - 16;
103
+ inputPos += 160, outputPos += 16
104
+ ) {
105
+ encryptedData.set(
106
+ decodedData.subarray(inputPos, inputPos + 16),
107
+ outputPos,
108
+ );
109
+ }
110
+
111
+ return encryptedData;
112
+ }
113
+
114
+ getAvcDecryptedUnit(decodedData: Uint8Array, decryptedData: ArrayBufferLike) {
115
+ const uint8DecryptedData = new Uint8Array(decryptedData);
116
+ let inputPos = 0;
117
+ for (
118
+ let outputPos = 32;
119
+ outputPos < decodedData.length - 16;
120
+ outputPos += 160, inputPos += 16
121
+ ) {
122
+ decodedData.set(
123
+ uint8DecryptedData.subarray(inputPos, inputPos + 16),
124
+ outputPos,
125
+ );
126
+ }
127
+
128
+ return decodedData;
129
+ }
130
+
131
+ decryptAvcSample(
132
+ samples: VideoSample[],
133
+ sampleIndex: number,
134
+ unitIndex: number,
135
+ callback: () => void,
136
+ curUnit: VideoSampleUnit,
137
+ ) {
138
+ const decodedData = discardEPB(curUnit.data);
139
+ const encryptedData = this.getAvcEncryptedData(decodedData);
140
+
141
+ this.decryptBuffer(encryptedData.buffer)
142
+ .then((decryptedBuffer) => {
143
+ curUnit.data = this.getAvcDecryptedUnit(decodedData, decryptedBuffer);
144
+
145
+ if (!this.decrypter.isSync()) {
146
+ this.decryptAvcSamples(samples, sampleIndex, unitIndex + 1, callback);
147
+ }
148
+ })
149
+ .catch(callback);
150
+ }
151
+
152
+ decryptAvcSamples(
153
+ samples: DemuxedVideoTrackBase['samples'],
154
+ sampleIndex: number,
155
+ unitIndex: number,
156
+ callback: () => void,
157
+ ) {
158
+ if (samples instanceof Uint8Array) {
159
+ throw new Error('Cannot decrypt samples of type Uint8Array');
160
+ }
161
+
162
+ for (; ; sampleIndex++, unitIndex = 0) {
163
+ if (sampleIndex >= samples.length) {
164
+ callback();
165
+ return;
166
+ }
167
+
168
+ const curUnits = samples[sampleIndex].units;
169
+ for (; ; unitIndex++) {
170
+ if (unitIndex >= curUnits.length) {
171
+ break;
172
+ }
173
+
174
+ const curUnit = curUnits[unitIndex];
175
+ if (
176
+ curUnit.data.length <= 48 ||
177
+ (curUnit.type !== 1 && curUnit.type !== 5)
178
+ ) {
179
+ continue;
180
+ }
181
+
182
+ this.decryptAvcSample(
183
+ samples,
184
+ sampleIndex,
185
+ unitIndex,
186
+ callback,
187
+ curUnit,
188
+ );
189
+
190
+ if (!this.decrypter.isSync()) {
191
+ return;
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ export default SampleAesDecrypter;