@bendyline/squisq-video-react 2.0.2 → 2.2.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 (44) hide show
  1. package/COPYING.GPL-2.0.txt +339 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE.md +39 -0
  4. package/README.md +34 -7
  5. package/dist/chunk-KQG6DZ7G.js +549 -0
  6. package/dist/chunk-VI5AIVOQ.js +1951 -0
  7. package/dist/chunk-VILZP3GL.js +856 -0
  8. package/dist/chunk-YZN7D4IC.js +300 -0
  9. package/dist/components/index.d.ts +90 -0
  10. package/dist/components/index.js +11 -0
  11. package/dist/encoder/index.d.ts +95 -0
  12. package/dist/encoder/index.js +13 -0
  13. package/dist/hooks/index.d.ts +32 -0
  14. package/dist/hooks/index.js +10 -0
  15. package/dist/index.d.ts +8 -277
  16. package/dist/index.js +12 -1503
  17. package/dist/useVideoExport-NtqZVgaz.d.ts +115 -0
  18. package/dist/workers/encode.worker.js +37 -20
  19. package/dist/workers/ffmpeg.class-worker.js +0 -1
  20. package/package.json +26 -8
  21. package/dist/chunk-6DKLHXX3.js +0 -47
  22. package/dist/chunk-6DKLHXX3.js.map +0 -1
  23. package/dist/index.js.map +0 -1
  24. package/dist/workers/encode.worker.js.map +0 -1
  25. package/dist/workers/ffmpeg.class-worker.js.map +0 -1
  26. package/src/VideoExportButton.tsx +0 -87
  27. package/src/VideoExportModal.tsx +0 -553
  28. package/src/__tests__/audioTrack.test.ts +0 -108
  29. package/src/__tests__/gifTranscode.test.ts +0 -118
  30. package/src/__tests__/mp4MuxAudio.test.ts +0 -72
  31. package/src/__tests__/useVideoExportGif.test.ts +0 -155
  32. package/src/__tests__/videoExportProps.test.tsx +0 -148
  33. package/src/__tests__/workerEncoder.test.ts +0 -143
  34. package/src/audioTrack.ts +0 -332
  35. package/src/gifTranscode.ts +0 -75
  36. package/src/hooks/useFrameCapture.ts +0 -268
  37. package/src/hooks/useVideoExport.ts +0 -647
  38. package/src/index.ts +0 -40
  39. package/src/mainThreadEncoder.ts +0 -158
  40. package/src/mp4Mux.ts +0 -123
  41. package/src/workerEncoder.ts +0 -175
  42. package/src/workers/encode.worker.ts +0 -439
  43. package/src/workers/ffmpeg.class-worker.ts +0 -11
  44. package/src/workers/workerTypes.ts +0 -89
@@ -0,0 +1,1951 @@
1
+ // ../../node_modules/mp4-muxer/build/mp4-muxer.mjs
2
+ var __accessCheck = (obj, member, msg) => {
3
+ if (!member.has(obj))
4
+ throw TypeError("Cannot " + msg);
5
+ };
6
+ var __privateGet = (obj, member, getter) => {
7
+ __accessCheck(obj, member, "read from private field");
8
+ return getter ? getter.call(obj) : member.get(obj);
9
+ };
10
+ var __privateAdd = (obj, member, value) => {
11
+ if (member.has(obj))
12
+ throw TypeError("Cannot add the same private member more than once");
13
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
14
+ };
15
+ var __privateSet = (obj, member, value, setter) => {
16
+ __accessCheck(obj, member, "write to private field");
17
+ setter ? setter.call(obj, value) : member.set(obj, value);
18
+ return value;
19
+ };
20
+ var __privateWrapper = (obj, member, setter, getter) => ({
21
+ set _(value) {
22
+ __privateSet(obj, member, value, setter);
23
+ },
24
+ get _() {
25
+ return __privateGet(obj, member, getter);
26
+ }
27
+ });
28
+ var __privateMethod = (obj, member, method) => {
29
+ __accessCheck(obj, member, "access private method");
30
+ return method;
31
+ };
32
+ var bytes = new Uint8Array(8);
33
+ var view = new DataView(bytes.buffer);
34
+ var u8 = (value) => {
35
+ return [(value % 256 + 256) % 256];
36
+ };
37
+ var u16 = (value) => {
38
+ view.setUint16(0, value, false);
39
+ return [bytes[0], bytes[1]];
40
+ };
41
+ var i16 = (value) => {
42
+ view.setInt16(0, value, false);
43
+ return [bytes[0], bytes[1]];
44
+ };
45
+ var u24 = (value) => {
46
+ view.setUint32(0, value, false);
47
+ return [bytes[1], bytes[2], bytes[3]];
48
+ };
49
+ var u32 = (value) => {
50
+ view.setUint32(0, value, false);
51
+ return [bytes[0], bytes[1], bytes[2], bytes[3]];
52
+ };
53
+ var i32 = (value) => {
54
+ view.setInt32(0, value, false);
55
+ return [bytes[0], bytes[1], bytes[2], bytes[3]];
56
+ };
57
+ var u64 = (value) => {
58
+ view.setUint32(0, Math.floor(value / 2 ** 32), false);
59
+ view.setUint32(4, value, false);
60
+ return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];
61
+ };
62
+ var fixed_8_8 = (value) => {
63
+ view.setInt16(0, 2 ** 8 * value, false);
64
+ return [bytes[0], bytes[1]];
65
+ };
66
+ var fixed_16_16 = (value) => {
67
+ view.setInt32(0, 2 ** 16 * value, false);
68
+ return [bytes[0], bytes[1], bytes[2], bytes[3]];
69
+ };
70
+ var fixed_2_30 = (value) => {
71
+ view.setInt32(0, 2 ** 30 * value, false);
72
+ return [bytes[0], bytes[1], bytes[2], bytes[3]];
73
+ };
74
+ var ascii = (text, nullTerminated = false) => {
75
+ let bytes2 = Array(text.length).fill(null).map((_, i) => text.charCodeAt(i));
76
+ if (nullTerminated)
77
+ bytes2.push(0);
78
+ return bytes2;
79
+ };
80
+ var last = (arr) => {
81
+ return arr && arr[arr.length - 1];
82
+ };
83
+ var lastPresentedSample = (samples) => {
84
+ let result = void 0;
85
+ for (let sample of samples) {
86
+ if (!result || sample.presentationTimestamp > result.presentationTimestamp) {
87
+ result = sample;
88
+ }
89
+ }
90
+ return result;
91
+ };
92
+ var intoTimescale = (timeInSeconds, timescale, round = true) => {
93
+ let value = timeInSeconds * timescale;
94
+ return round ? Math.round(value) : value;
95
+ };
96
+ var rotationMatrix = (rotationInDegrees) => {
97
+ let theta = rotationInDegrees * (Math.PI / 180);
98
+ let cosTheta = Math.cos(theta);
99
+ let sinTheta = Math.sin(theta);
100
+ return [
101
+ cosTheta,
102
+ sinTheta,
103
+ 0,
104
+ -sinTheta,
105
+ cosTheta,
106
+ 0,
107
+ 0,
108
+ 0,
109
+ 1
110
+ ];
111
+ };
112
+ var IDENTITY_MATRIX = rotationMatrix(0);
113
+ var matrixToBytes = (matrix) => {
114
+ return [
115
+ fixed_16_16(matrix[0]),
116
+ fixed_16_16(matrix[1]),
117
+ fixed_2_30(matrix[2]),
118
+ fixed_16_16(matrix[3]),
119
+ fixed_16_16(matrix[4]),
120
+ fixed_2_30(matrix[5]),
121
+ fixed_16_16(matrix[6]),
122
+ fixed_16_16(matrix[7]),
123
+ fixed_2_30(matrix[8])
124
+ ];
125
+ };
126
+ var deepClone = (x) => {
127
+ if (!x)
128
+ return x;
129
+ if (typeof x !== "object")
130
+ return x;
131
+ if (Array.isArray(x))
132
+ return x.map(deepClone);
133
+ return Object.fromEntries(Object.entries(x).map(([key, value]) => [key, deepClone(value)]));
134
+ };
135
+ var isU32 = (value) => {
136
+ return value >= 0 && value < 2 ** 32;
137
+ };
138
+ var box = (type, contents, children) => ({
139
+ type,
140
+ contents: contents && new Uint8Array(contents.flat(10)),
141
+ children
142
+ });
143
+ var fullBox = (type, version, flags, contents, children) => box(
144
+ type,
145
+ [u8(version), u24(flags), contents ?? []],
146
+ children
147
+ );
148
+ var ftyp = (details) => {
149
+ let minorVersion = 512;
150
+ if (details.fragmented)
151
+ return box("ftyp", [
152
+ ascii("iso5"),
153
+ // Major brand
154
+ u32(minorVersion),
155
+ // Minor version
156
+ // Compatible brands
157
+ ascii("iso5"),
158
+ ascii("iso6"),
159
+ ascii("mp41")
160
+ ]);
161
+ return box("ftyp", [
162
+ ascii("isom"),
163
+ // Major brand
164
+ u32(minorVersion),
165
+ // Minor version
166
+ // Compatible brands
167
+ ascii("isom"),
168
+ details.holdsAvc ? ascii("avc1") : [],
169
+ ascii("mp41")
170
+ ]);
171
+ };
172
+ var mdat = (reserveLargeSize) => ({ type: "mdat", largeSize: reserveLargeSize });
173
+ var free = (size) => ({ type: "free", size });
174
+ var moov = (tracks, creationTime, fragmented = false) => box("moov", null, [
175
+ mvhd(creationTime, tracks),
176
+ ...tracks.map((x) => trak(x, creationTime)),
177
+ fragmented ? mvex(tracks) : null
178
+ ]);
179
+ var mvhd = (creationTime, tracks) => {
180
+ let duration = intoTimescale(Math.max(
181
+ 0,
182
+ ...tracks.filter((x) => x.samples.length > 0).map((x) => {
183
+ const lastSample = lastPresentedSample(x.samples);
184
+ return lastSample.presentationTimestamp + lastSample.duration;
185
+ })
186
+ ), GLOBAL_TIMESCALE);
187
+ let nextTrackId = Math.max(...tracks.map((x) => x.id)) + 1;
188
+ let needsU64 = !isU32(creationTime) || !isU32(duration);
189
+ let u32OrU64 = needsU64 ? u64 : u32;
190
+ return fullBox("mvhd", +needsU64, 0, [
191
+ u32OrU64(creationTime),
192
+ // Creation time
193
+ u32OrU64(creationTime),
194
+ // Modification time
195
+ u32(GLOBAL_TIMESCALE),
196
+ // Timescale
197
+ u32OrU64(duration),
198
+ // Duration
199
+ fixed_16_16(1),
200
+ // Preferred rate
201
+ fixed_8_8(1),
202
+ // Preferred volume
203
+ Array(10).fill(0),
204
+ // Reserved
205
+ matrixToBytes(IDENTITY_MATRIX),
206
+ // Matrix
207
+ Array(24).fill(0),
208
+ // Pre-defined
209
+ u32(nextTrackId)
210
+ // Next track ID
211
+ ]);
212
+ };
213
+ var trak = (track, creationTime) => box("trak", null, [
214
+ tkhd(track, creationTime),
215
+ mdia(track, creationTime)
216
+ ]);
217
+ var tkhd = (track, creationTime) => {
218
+ let lastSample = lastPresentedSample(track.samples);
219
+ let durationInGlobalTimescale = intoTimescale(
220
+ lastSample ? lastSample.presentationTimestamp + lastSample.duration : 0,
221
+ GLOBAL_TIMESCALE
222
+ );
223
+ let needsU64 = !isU32(creationTime) || !isU32(durationInGlobalTimescale);
224
+ let u32OrU64 = needsU64 ? u64 : u32;
225
+ let matrix;
226
+ if (track.info.type === "video") {
227
+ matrix = typeof track.info.rotation === "number" ? rotationMatrix(track.info.rotation) : track.info.rotation;
228
+ } else {
229
+ matrix = IDENTITY_MATRIX;
230
+ }
231
+ return fullBox("tkhd", +needsU64, 3, [
232
+ u32OrU64(creationTime),
233
+ // Creation time
234
+ u32OrU64(creationTime),
235
+ // Modification time
236
+ u32(track.id),
237
+ // Track ID
238
+ u32(0),
239
+ // Reserved
240
+ u32OrU64(durationInGlobalTimescale),
241
+ // Duration
242
+ Array(8).fill(0),
243
+ // Reserved
244
+ u16(0),
245
+ // Layer
246
+ u16(0),
247
+ // Alternate group
248
+ fixed_8_8(track.info.type === "audio" ? 1 : 0),
249
+ // Volume
250
+ u16(0),
251
+ // Reserved
252
+ matrixToBytes(matrix),
253
+ // Matrix
254
+ fixed_16_16(track.info.type === "video" ? track.info.width : 0),
255
+ // Track width
256
+ fixed_16_16(track.info.type === "video" ? track.info.height : 0)
257
+ // Track height
258
+ ]);
259
+ };
260
+ var mdia = (track, creationTime) => box("mdia", null, [
261
+ mdhd(track, creationTime),
262
+ hdlr(track.info.type === "video" ? "vide" : "soun"),
263
+ minf(track)
264
+ ]);
265
+ var mdhd = (track, creationTime) => {
266
+ let lastSample = lastPresentedSample(track.samples);
267
+ let localDuration = intoTimescale(
268
+ lastSample ? lastSample.presentationTimestamp + lastSample.duration : 0,
269
+ track.timescale
270
+ );
271
+ let needsU64 = !isU32(creationTime) || !isU32(localDuration);
272
+ let u32OrU64 = needsU64 ? u64 : u32;
273
+ return fullBox("mdhd", +needsU64, 0, [
274
+ u32OrU64(creationTime),
275
+ // Creation time
276
+ u32OrU64(creationTime),
277
+ // Modification time
278
+ u32(track.timescale),
279
+ // Timescale
280
+ u32OrU64(localDuration),
281
+ // Duration
282
+ u16(21956),
283
+ // Language ("und", undetermined)
284
+ u16(0)
285
+ // Quality
286
+ ]);
287
+ };
288
+ var hdlr = (componentSubtype) => fullBox("hdlr", 0, 0, [
289
+ ascii("mhlr"),
290
+ // Component type
291
+ ascii(componentSubtype),
292
+ // Component subtype
293
+ u32(0),
294
+ // Component manufacturer
295
+ u32(0),
296
+ // Component flags
297
+ u32(0),
298
+ // Component flags mask
299
+ ascii("mp4-muxer-hdlr", true)
300
+ // Component name
301
+ ]);
302
+ var minf = (track) => box("minf", null, [
303
+ track.info.type === "video" ? vmhd() : smhd(),
304
+ dinf(),
305
+ stbl(track)
306
+ ]);
307
+ var vmhd = () => fullBox("vmhd", 0, 1, [
308
+ u16(0),
309
+ // Graphics mode
310
+ u16(0),
311
+ // Opcolor R
312
+ u16(0),
313
+ // Opcolor G
314
+ u16(0)
315
+ // Opcolor B
316
+ ]);
317
+ var smhd = () => fullBox("smhd", 0, 0, [
318
+ u16(0),
319
+ // Balance
320
+ u16(0)
321
+ // Reserved
322
+ ]);
323
+ var dinf = () => box("dinf", null, [
324
+ dref()
325
+ ]);
326
+ var dref = () => fullBox("dref", 0, 0, [
327
+ u32(1)
328
+ // Entry count
329
+ ], [
330
+ url()
331
+ ]);
332
+ var url = () => fullBox("url ", 0, 1);
333
+ var stbl = (track) => {
334
+ const needsCtts = track.compositionTimeOffsetTable.length > 1 || track.compositionTimeOffsetTable.some((x) => x.sampleCompositionTimeOffset !== 0);
335
+ return box("stbl", null, [
336
+ stsd(track),
337
+ stts(track),
338
+ stss(track),
339
+ stsc(track),
340
+ stsz(track),
341
+ stco(track),
342
+ needsCtts ? ctts(track) : null
343
+ ]);
344
+ };
345
+ var stsd = (track) => fullBox("stsd", 0, 0, [
346
+ u32(1)
347
+ // Entry count
348
+ ], [
349
+ track.info.type === "video" ? videoSampleDescription(
350
+ VIDEO_CODEC_TO_BOX_NAME[track.info.codec],
351
+ track
352
+ ) : soundSampleDescription(
353
+ AUDIO_CODEC_TO_BOX_NAME[track.info.codec],
354
+ track
355
+ )
356
+ ]);
357
+ var videoSampleDescription = (compressionType, track) => box(compressionType, [
358
+ Array(6).fill(0),
359
+ // Reserved
360
+ u16(1),
361
+ // Data reference index
362
+ u16(0),
363
+ // Pre-defined
364
+ u16(0),
365
+ // Reserved
366
+ Array(12).fill(0),
367
+ // Pre-defined
368
+ u16(track.info.width),
369
+ // Width
370
+ u16(track.info.height),
371
+ // Height
372
+ u32(4718592),
373
+ // Horizontal resolution
374
+ u32(4718592),
375
+ // Vertical resolution
376
+ u32(0),
377
+ // Reserved
378
+ u16(1),
379
+ // Frame count
380
+ Array(32).fill(0),
381
+ // Compressor name
382
+ u16(24),
383
+ // Depth
384
+ i16(65535)
385
+ // Pre-defined
386
+ ], [
387
+ VIDEO_CODEC_TO_CONFIGURATION_BOX[track.info.codec](track),
388
+ track.info.decoderConfig.colorSpace ? colr(track) : null
389
+ ]);
390
+ var COLOR_PRIMARIES_MAP = {
391
+ "bt709": 1,
392
+ // ITU-R BT.709
393
+ "bt470bg": 5,
394
+ // ITU-R BT.470BG
395
+ "smpte170m": 6
396
+ // ITU-R BT.601 525 - SMPTE 170M
397
+ };
398
+ var TRANSFER_CHARACTERISTICS_MAP = {
399
+ "bt709": 1,
400
+ // ITU-R BT.709
401
+ "smpte170m": 6,
402
+ // SMPTE 170M
403
+ "iec61966-2-1": 13
404
+ // IEC 61966-2-1
405
+ };
406
+ var MATRIX_COEFFICIENTS_MAP = {
407
+ "rgb": 0,
408
+ // Identity
409
+ "bt709": 1,
410
+ // ITU-R BT.709
411
+ "bt470bg": 5,
412
+ // ITU-R BT.470BG
413
+ "smpte170m": 6
414
+ // SMPTE 170M
415
+ };
416
+ var colr = (track) => box("colr", [
417
+ ascii("nclx"),
418
+ // Colour type
419
+ u16(COLOR_PRIMARIES_MAP[track.info.decoderConfig.colorSpace.primaries]),
420
+ // Colour primaries
421
+ u16(TRANSFER_CHARACTERISTICS_MAP[track.info.decoderConfig.colorSpace.transfer]),
422
+ // Transfer characteristics
423
+ u16(MATRIX_COEFFICIENTS_MAP[track.info.decoderConfig.colorSpace.matrix]),
424
+ // Matrix coefficients
425
+ u8((track.info.decoderConfig.colorSpace.fullRange ? 1 : 0) << 7)
426
+ // Full range flag
427
+ ]);
428
+ var avcC = (track) => track.info.decoderConfig && box("avcC", [
429
+ // For AVC, description is an AVCDecoderConfigurationRecord, so nothing else to do here
430
+ ...new Uint8Array(track.info.decoderConfig.description)
431
+ ]);
432
+ var hvcC = (track) => track.info.decoderConfig && box("hvcC", [
433
+ // For HEVC, description is a HEVCDecoderConfigurationRecord, so nothing else to do here
434
+ ...new Uint8Array(track.info.decoderConfig.description)
435
+ ]);
436
+ var vpcC = (track) => {
437
+ if (!track.info.decoderConfig) {
438
+ return null;
439
+ }
440
+ let decoderConfig = track.info.decoderConfig;
441
+ if (!decoderConfig.colorSpace) {
442
+ throw new Error(`'colorSpace' is required in the decoder config for VP9.`);
443
+ }
444
+ let parts = decoderConfig.codec.split(".");
445
+ let profile = Number(parts[1]);
446
+ let level = Number(parts[2]);
447
+ let bitDepth = Number(parts[3]);
448
+ let chromaSubsampling = 0;
449
+ let thirdByte = (bitDepth << 4) + (chromaSubsampling << 1) + Number(decoderConfig.colorSpace.fullRange);
450
+ let colourPrimaries = 2;
451
+ let transferCharacteristics = 2;
452
+ let matrixCoefficients = 2;
453
+ return fullBox("vpcC", 1, 0, [
454
+ u8(profile),
455
+ // Profile
456
+ u8(level),
457
+ // Level
458
+ u8(thirdByte),
459
+ // Bit depth, chroma subsampling, full range
460
+ u8(colourPrimaries),
461
+ // Colour primaries
462
+ u8(transferCharacteristics),
463
+ // Transfer characteristics
464
+ u8(matrixCoefficients),
465
+ // Matrix coefficients
466
+ u16(0)
467
+ // Codec initialization data size
468
+ ]);
469
+ };
470
+ var av1C = () => {
471
+ let marker = 1;
472
+ let version = 1;
473
+ let firstByte = (marker << 7) + version;
474
+ return box("av1C", [
475
+ firstByte,
476
+ 0,
477
+ 0,
478
+ 0
479
+ ]);
480
+ };
481
+ var soundSampleDescription = (compressionType, track) => box(compressionType, [
482
+ Array(6).fill(0),
483
+ // Reserved
484
+ u16(1),
485
+ // Data reference index
486
+ u16(0),
487
+ // Version
488
+ u16(0),
489
+ // Revision level
490
+ u32(0),
491
+ // Vendor
492
+ u16(track.info.numberOfChannels),
493
+ // Number of channels
494
+ u16(16),
495
+ // Sample size (bits)
496
+ u16(0),
497
+ // Compression ID
498
+ u16(0),
499
+ // Packet size
500
+ fixed_16_16(track.info.sampleRate)
501
+ // Sample rate
502
+ ], [
503
+ AUDIO_CODEC_TO_CONFIGURATION_BOX[track.info.codec](track)
504
+ ]);
505
+ var esds = (track) => {
506
+ let description = new Uint8Array(track.info.decoderConfig.description);
507
+ return fullBox("esds", 0, 0, [
508
+ // https://stackoverflow.com/a/54803118
509
+ u32(58753152),
510
+ // TAG(3) = Object Descriptor ([2])
511
+ u8(32 + description.byteLength),
512
+ // length of this OD (which includes the next 2 tags)
513
+ u16(1),
514
+ // ES_ID = 1
515
+ u8(0),
516
+ // flags etc = 0
517
+ u32(75530368),
518
+ // TAG(4) = ES Descriptor ([2]) embedded in above OD
519
+ u8(18 + description.byteLength),
520
+ // length of this ESD
521
+ u8(64),
522
+ // MPEG-4 Audio
523
+ u8(21),
524
+ // stream type(6bits)=5 audio, flags(2bits)=1
525
+ u24(0),
526
+ // 24bit buffer size
527
+ u32(130071),
528
+ // max bitrate
529
+ u32(130071),
530
+ // avg bitrate
531
+ u32(92307584),
532
+ // TAG(5) = ASC ([2],[3]) embedded in above OD
533
+ u8(description.byteLength),
534
+ // length
535
+ ...description,
536
+ u32(109084800),
537
+ // TAG(6)
538
+ u8(1),
539
+ // length
540
+ u8(2)
541
+ // data
542
+ ]);
543
+ };
544
+ var dOps = (track) => {
545
+ let preskip = 3840;
546
+ let gain = 0;
547
+ const description = track.info.decoderConfig?.description;
548
+ if (description) {
549
+ if (description.byteLength < 18) {
550
+ throw new TypeError("Invalid decoder description provided for Opus; must be at least 18 bytes long.");
551
+ }
552
+ const view2 = ArrayBuffer.isView(description) ? new DataView(description.buffer, description.byteOffset, description.byteLength) : new DataView(description);
553
+ preskip = view2.getUint16(10, true);
554
+ gain = view2.getInt16(14, true);
555
+ }
556
+ return box("dOps", [
557
+ u8(0),
558
+ // Version
559
+ u8(track.info.numberOfChannels),
560
+ // OutputChannelCount
561
+ u16(preskip),
562
+ u32(track.info.sampleRate),
563
+ // InputSampleRate
564
+ fixed_8_8(gain),
565
+ // OutputGain
566
+ u8(0)
567
+ // ChannelMappingFamily
568
+ ]);
569
+ };
570
+ var stts = (track) => {
571
+ return fullBox("stts", 0, 0, [
572
+ u32(track.timeToSampleTable.length),
573
+ // Number of entries
574
+ track.timeToSampleTable.map((x) => [
575
+ // Time-to-sample table
576
+ u32(x.sampleCount),
577
+ // Sample count
578
+ u32(x.sampleDelta)
579
+ // Sample duration
580
+ ])
581
+ ]);
582
+ };
583
+ var stss = (track) => {
584
+ if (track.samples.every((x) => x.type === "key"))
585
+ return null;
586
+ let keySamples = [...track.samples.entries()].filter(([, sample]) => sample.type === "key");
587
+ return fullBox("stss", 0, 0, [
588
+ u32(keySamples.length),
589
+ // Number of entries
590
+ keySamples.map(([index]) => u32(index + 1))
591
+ // Sync sample table
592
+ ]);
593
+ };
594
+ var stsc = (track) => {
595
+ return fullBox("stsc", 0, 0, [
596
+ u32(track.compactlyCodedChunkTable.length),
597
+ // Number of entries
598
+ track.compactlyCodedChunkTable.map((x) => [
599
+ // Sample-to-chunk table
600
+ u32(x.firstChunk),
601
+ // First chunk
602
+ u32(x.samplesPerChunk),
603
+ // Samples per chunk
604
+ u32(1)
605
+ // Sample description index
606
+ ])
607
+ ]);
608
+ };
609
+ var stsz = (track) => fullBox("stsz", 0, 0, [
610
+ u32(0),
611
+ // Sample size (0 means non-constant size)
612
+ u32(track.samples.length),
613
+ // Number of entries
614
+ track.samples.map((x) => u32(x.size))
615
+ // Sample size table
616
+ ]);
617
+ var stco = (track) => {
618
+ if (track.finalizedChunks.length > 0 && last(track.finalizedChunks).offset >= 2 ** 32) {
619
+ return fullBox("co64", 0, 0, [
620
+ u32(track.finalizedChunks.length),
621
+ // Number of entries
622
+ track.finalizedChunks.map((x) => u64(x.offset))
623
+ // Chunk offset table
624
+ ]);
625
+ }
626
+ return fullBox("stco", 0, 0, [
627
+ u32(track.finalizedChunks.length),
628
+ // Number of entries
629
+ track.finalizedChunks.map((x) => u32(x.offset))
630
+ // Chunk offset table
631
+ ]);
632
+ };
633
+ var ctts = (track) => {
634
+ return fullBox("ctts", 0, 0, [
635
+ u32(track.compositionTimeOffsetTable.length),
636
+ // Number of entries
637
+ track.compositionTimeOffsetTable.map((x) => [
638
+ // Time-to-sample table
639
+ u32(x.sampleCount),
640
+ // Sample count
641
+ u32(x.sampleCompositionTimeOffset)
642
+ // Sample offset
643
+ ])
644
+ ]);
645
+ };
646
+ var mvex = (tracks) => {
647
+ return box("mvex", null, tracks.map(trex));
648
+ };
649
+ var trex = (track) => {
650
+ return fullBox("trex", 0, 0, [
651
+ u32(track.id),
652
+ // Track ID
653
+ u32(1),
654
+ // Default sample description index
655
+ u32(0),
656
+ // Default sample duration
657
+ u32(0),
658
+ // Default sample size
659
+ u32(0)
660
+ // Default sample flags
661
+ ]);
662
+ };
663
+ var moof = (sequenceNumber, tracks) => {
664
+ return box("moof", null, [
665
+ mfhd(sequenceNumber),
666
+ ...tracks.map(traf)
667
+ ]);
668
+ };
669
+ var mfhd = (sequenceNumber) => {
670
+ return fullBox("mfhd", 0, 0, [
671
+ u32(sequenceNumber)
672
+ // Sequence number
673
+ ]);
674
+ };
675
+ var fragmentSampleFlags = (sample) => {
676
+ let byte1 = 0;
677
+ let byte2 = 0;
678
+ let byte3 = 0;
679
+ let byte4 = 0;
680
+ let sampleIsDifferenceSample = sample.type === "delta";
681
+ byte2 |= +sampleIsDifferenceSample;
682
+ if (sampleIsDifferenceSample) {
683
+ byte1 |= 1;
684
+ } else {
685
+ byte1 |= 2;
686
+ }
687
+ return byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4;
688
+ };
689
+ var traf = (track) => {
690
+ return box("traf", null, [
691
+ tfhd(track),
692
+ tfdt(track),
693
+ trun(track)
694
+ ]);
695
+ };
696
+ var tfhd = (track) => {
697
+ let tfFlags = 0;
698
+ tfFlags |= 8;
699
+ tfFlags |= 16;
700
+ tfFlags |= 32;
701
+ tfFlags |= 131072;
702
+ let referenceSample = track.currentChunk.samples[1] ?? track.currentChunk.samples[0];
703
+ let referenceSampleInfo = {
704
+ duration: referenceSample.timescaleUnitsToNextSample,
705
+ size: referenceSample.size,
706
+ flags: fragmentSampleFlags(referenceSample)
707
+ };
708
+ return fullBox("tfhd", 0, tfFlags, [
709
+ u32(track.id),
710
+ // Track ID
711
+ u32(referenceSampleInfo.duration),
712
+ // Default sample duration
713
+ u32(referenceSampleInfo.size),
714
+ // Default sample size
715
+ u32(referenceSampleInfo.flags)
716
+ // Default sample flags
717
+ ]);
718
+ };
719
+ var tfdt = (track) => {
720
+ return fullBox("tfdt", 1, 0, [
721
+ u64(intoTimescale(track.currentChunk.startTimestamp, track.timescale))
722
+ // Base Media Decode Time
723
+ ]);
724
+ };
725
+ var trun = (track) => {
726
+ let allSampleDurations = track.currentChunk.samples.map((x) => x.timescaleUnitsToNextSample);
727
+ let allSampleSizes = track.currentChunk.samples.map((x) => x.size);
728
+ let allSampleFlags = track.currentChunk.samples.map(fragmentSampleFlags);
729
+ let allSampleCompositionTimeOffsets = track.currentChunk.samples.map((x) => intoTimescale(x.presentationTimestamp - x.decodeTimestamp, track.timescale));
730
+ let uniqueSampleDurations = new Set(allSampleDurations);
731
+ let uniqueSampleSizes = new Set(allSampleSizes);
732
+ let uniqueSampleFlags = new Set(allSampleFlags);
733
+ let uniqueSampleCompositionTimeOffsets = new Set(allSampleCompositionTimeOffsets);
734
+ let firstSampleFlagsPresent = uniqueSampleFlags.size === 2 && allSampleFlags[0] !== allSampleFlags[1];
735
+ let sampleDurationPresent = uniqueSampleDurations.size > 1;
736
+ let sampleSizePresent = uniqueSampleSizes.size > 1;
737
+ let sampleFlagsPresent = !firstSampleFlagsPresent && uniqueSampleFlags.size > 1;
738
+ let sampleCompositionTimeOffsetsPresent = uniqueSampleCompositionTimeOffsets.size > 1 || [...uniqueSampleCompositionTimeOffsets].some((x) => x !== 0);
739
+ let flags = 0;
740
+ flags |= 1;
741
+ flags |= 4 * +firstSampleFlagsPresent;
742
+ flags |= 256 * +sampleDurationPresent;
743
+ flags |= 512 * +sampleSizePresent;
744
+ flags |= 1024 * +sampleFlagsPresent;
745
+ flags |= 2048 * +sampleCompositionTimeOffsetsPresent;
746
+ return fullBox("trun", 1, flags, [
747
+ u32(track.currentChunk.samples.length),
748
+ // Sample count
749
+ u32(track.currentChunk.offset - track.currentChunk.moofOffset || 0),
750
+ // Data offset
751
+ firstSampleFlagsPresent ? u32(allSampleFlags[0]) : [],
752
+ track.currentChunk.samples.map((_, i) => [
753
+ sampleDurationPresent ? u32(allSampleDurations[i]) : [],
754
+ // Sample duration
755
+ sampleSizePresent ? u32(allSampleSizes[i]) : [],
756
+ // Sample size
757
+ sampleFlagsPresent ? u32(allSampleFlags[i]) : [],
758
+ // Sample flags
759
+ // Sample composition time offsets
760
+ sampleCompositionTimeOffsetsPresent ? i32(allSampleCompositionTimeOffsets[i]) : []
761
+ ])
762
+ ]);
763
+ };
764
+ var mfra = (tracks) => {
765
+ return box("mfra", null, [
766
+ ...tracks.map(tfra),
767
+ mfro()
768
+ ]);
769
+ };
770
+ var tfra = (track, trackIndex) => {
771
+ let version = 1;
772
+ return fullBox("tfra", version, 0, [
773
+ u32(track.id),
774
+ // Track ID
775
+ u32(63),
776
+ // This specifies that traf number, trun number and sample number are 32-bit ints
777
+ u32(track.finalizedChunks.length),
778
+ // Number of entries
779
+ track.finalizedChunks.map((chunk) => [
780
+ u64(intoTimescale(chunk.startTimestamp, track.timescale)),
781
+ // Time
782
+ u64(chunk.moofOffset),
783
+ // moof offset
784
+ u32(trackIndex + 1),
785
+ // traf number
786
+ u32(1),
787
+ // trun number
788
+ u32(1)
789
+ // Sample number
790
+ ])
791
+ ]);
792
+ };
793
+ var mfro = () => {
794
+ return fullBox("mfro", 0, 0, [
795
+ // This value needs to be overwritten manually from the outside, where the actual size of the enclosing mfra box
796
+ // is known
797
+ u32(0)
798
+ // Size
799
+ ]);
800
+ };
801
+ var VIDEO_CODEC_TO_BOX_NAME = {
802
+ "avc": "avc1",
803
+ "hevc": "hvc1",
804
+ "vp9": "vp09",
805
+ "av1": "av01"
806
+ };
807
+ var VIDEO_CODEC_TO_CONFIGURATION_BOX = {
808
+ "avc": avcC,
809
+ "hevc": hvcC,
810
+ "vp9": vpcC,
811
+ "av1": av1C
812
+ };
813
+ var AUDIO_CODEC_TO_BOX_NAME = {
814
+ "aac": "mp4a",
815
+ "opus": "Opus"
816
+ };
817
+ var AUDIO_CODEC_TO_CONFIGURATION_BOX = {
818
+ "aac": esds,
819
+ "opus": dOps
820
+ };
821
+ var Target = class {
822
+ };
823
+ var ArrayBufferTarget = class extends Target {
824
+ constructor() {
825
+ super(...arguments);
826
+ this.buffer = null;
827
+ }
828
+ };
829
+ var StreamTarget = class extends Target {
830
+ constructor(options) {
831
+ super();
832
+ this.options = options;
833
+ if (typeof options !== "object") {
834
+ throw new TypeError("StreamTarget requires an options object to be passed to its constructor.");
835
+ }
836
+ if (options.onData) {
837
+ if (typeof options.onData !== "function") {
838
+ throw new TypeError("options.onData, when provided, must be a function.");
839
+ }
840
+ if (options.onData.length < 2) {
841
+ throw new TypeError(
842
+ "options.onData, when provided, must be a function that takes in at least two arguments (data and position). Ignoring the position argument, which specifies the byte offset at which the data is to be written, can lead to broken outputs."
843
+ );
844
+ }
845
+ }
846
+ if (options.chunked !== void 0 && typeof options.chunked !== "boolean") {
847
+ throw new TypeError("options.chunked, when provided, must be a boolean.");
848
+ }
849
+ if (options.chunkSize !== void 0 && (!Number.isInteger(options.chunkSize) || options.chunkSize < 1024)) {
850
+ throw new TypeError("options.chunkSize, when provided, must be an integer and not smaller than 1024.");
851
+ }
852
+ }
853
+ };
854
+ var FileSystemWritableFileStreamTarget = class extends Target {
855
+ constructor(stream, options) {
856
+ super();
857
+ this.stream = stream;
858
+ this.options = options;
859
+ if (!(stream instanceof FileSystemWritableFileStream)) {
860
+ throw new TypeError("FileSystemWritableFileStreamTarget requires a FileSystemWritableFileStream instance.");
861
+ }
862
+ if (options !== void 0 && typeof options !== "object") {
863
+ throw new TypeError("FileSystemWritableFileStreamTarget's options, when provided, must be an object.");
864
+ }
865
+ if (options) {
866
+ if (options.chunkSize !== void 0 && (!Number.isInteger(options.chunkSize) || options.chunkSize <= 0)) {
867
+ throw new TypeError("options.chunkSize, when provided, must be a positive integer");
868
+ }
869
+ }
870
+ }
871
+ };
872
+ var _helper;
873
+ var _helperView;
874
+ var Writer = class {
875
+ constructor() {
876
+ this.pos = 0;
877
+ __privateAdd(this, _helper, new Uint8Array(8));
878
+ __privateAdd(this, _helperView, new DataView(__privateGet(this, _helper).buffer));
879
+ this.offsets = /* @__PURE__ */ new WeakMap();
880
+ }
881
+ /** Sets the current position for future writes to a new one. */
882
+ seek(newPos) {
883
+ this.pos = newPos;
884
+ }
885
+ writeU32(value) {
886
+ __privateGet(this, _helperView).setUint32(0, value, false);
887
+ this.write(__privateGet(this, _helper).subarray(0, 4));
888
+ }
889
+ writeU64(value) {
890
+ __privateGet(this, _helperView).setUint32(0, Math.floor(value / 2 ** 32), false);
891
+ __privateGet(this, _helperView).setUint32(4, value, false);
892
+ this.write(__privateGet(this, _helper).subarray(0, 8));
893
+ }
894
+ writeAscii(text) {
895
+ for (let i = 0; i < text.length; i++) {
896
+ __privateGet(this, _helperView).setUint8(i % 8, text.charCodeAt(i));
897
+ if (i % 8 === 7)
898
+ this.write(__privateGet(this, _helper));
899
+ }
900
+ if (text.length % 8 !== 0) {
901
+ this.write(__privateGet(this, _helper).subarray(0, text.length % 8));
902
+ }
903
+ }
904
+ writeBox(box2) {
905
+ this.offsets.set(box2, this.pos);
906
+ if (box2.contents && !box2.children) {
907
+ this.writeBoxHeader(box2, box2.size ?? box2.contents.byteLength + 8);
908
+ this.write(box2.contents);
909
+ } else {
910
+ let startPos = this.pos;
911
+ this.writeBoxHeader(box2, 0);
912
+ if (box2.contents)
913
+ this.write(box2.contents);
914
+ if (box2.children) {
915
+ for (let child of box2.children)
916
+ if (child)
917
+ this.writeBox(child);
918
+ }
919
+ let endPos = this.pos;
920
+ let size = box2.size ?? endPos - startPos;
921
+ this.seek(startPos);
922
+ this.writeBoxHeader(box2, size);
923
+ this.seek(endPos);
924
+ }
925
+ }
926
+ writeBoxHeader(box2, size) {
927
+ this.writeU32(box2.largeSize ? 1 : size);
928
+ this.writeAscii(box2.type);
929
+ if (box2.largeSize)
930
+ this.writeU64(size);
931
+ }
932
+ measureBoxHeader(box2) {
933
+ return 8 + (box2.largeSize ? 8 : 0);
934
+ }
935
+ patchBox(box2) {
936
+ let endPos = this.pos;
937
+ this.seek(this.offsets.get(box2));
938
+ this.writeBox(box2);
939
+ this.seek(endPos);
940
+ }
941
+ measureBox(box2) {
942
+ if (box2.contents && !box2.children) {
943
+ let headerSize = this.measureBoxHeader(box2);
944
+ return headerSize + box2.contents.byteLength;
945
+ } else {
946
+ let result = this.measureBoxHeader(box2);
947
+ if (box2.contents)
948
+ result += box2.contents.byteLength;
949
+ if (box2.children) {
950
+ for (let child of box2.children)
951
+ if (child)
952
+ result += this.measureBox(child);
953
+ }
954
+ return result;
955
+ }
956
+ }
957
+ };
958
+ _helper = /* @__PURE__ */ new WeakMap();
959
+ _helperView = /* @__PURE__ */ new WeakMap();
960
+ var _target;
961
+ var _buffer;
962
+ var _bytes;
963
+ var _maxPos;
964
+ var _ensureSize;
965
+ var ensureSize_fn;
966
+ var ArrayBufferTargetWriter = class extends Writer {
967
+ constructor(target) {
968
+ super();
969
+ __privateAdd(this, _ensureSize);
970
+ __privateAdd(this, _target, void 0);
971
+ __privateAdd(this, _buffer, new ArrayBuffer(2 ** 16));
972
+ __privateAdd(this, _bytes, new Uint8Array(__privateGet(this, _buffer)));
973
+ __privateAdd(this, _maxPos, 0);
974
+ __privateSet(this, _target, target);
975
+ }
976
+ write(data) {
977
+ __privateMethod(this, _ensureSize, ensureSize_fn).call(this, this.pos + data.byteLength);
978
+ __privateGet(this, _bytes).set(data, this.pos);
979
+ this.pos += data.byteLength;
980
+ __privateSet(this, _maxPos, Math.max(__privateGet(this, _maxPos), this.pos));
981
+ }
982
+ finalize() {
983
+ __privateMethod(this, _ensureSize, ensureSize_fn).call(this, this.pos);
984
+ __privateGet(this, _target).buffer = __privateGet(this, _buffer).slice(0, Math.max(__privateGet(this, _maxPos), this.pos));
985
+ }
986
+ };
987
+ _target = /* @__PURE__ */ new WeakMap();
988
+ _buffer = /* @__PURE__ */ new WeakMap();
989
+ _bytes = /* @__PURE__ */ new WeakMap();
990
+ _maxPos = /* @__PURE__ */ new WeakMap();
991
+ _ensureSize = /* @__PURE__ */ new WeakSet();
992
+ ensureSize_fn = function(size) {
993
+ let newLength = __privateGet(this, _buffer).byteLength;
994
+ while (newLength < size)
995
+ newLength *= 2;
996
+ if (newLength === __privateGet(this, _buffer).byteLength)
997
+ return;
998
+ let newBuffer = new ArrayBuffer(newLength);
999
+ let newBytes = new Uint8Array(newBuffer);
1000
+ newBytes.set(__privateGet(this, _bytes), 0);
1001
+ __privateSet(this, _buffer, newBuffer);
1002
+ __privateSet(this, _bytes, newBytes);
1003
+ };
1004
+ var DEFAULT_CHUNK_SIZE = 2 ** 24;
1005
+ var MAX_CHUNKS_AT_ONCE = 2;
1006
+ var _target2;
1007
+ var _sections;
1008
+ var _chunked;
1009
+ var _chunkSize;
1010
+ var _chunks;
1011
+ var _writeDataIntoChunks;
1012
+ var writeDataIntoChunks_fn;
1013
+ var _insertSectionIntoChunk;
1014
+ var insertSectionIntoChunk_fn;
1015
+ var _createChunk;
1016
+ var createChunk_fn;
1017
+ var _flushChunks;
1018
+ var flushChunks_fn;
1019
+ var StreamTargetWriter = class extends Writer {
1020
+ constructor(target) {
1021
+ super();
1022
+ __privateAdd(this, _writeDataIntoChunks);
1023
+ __privateAdd(this, _insertSectionIntoChunk);
1024
+ __privateAdd(this, _createChunk);
1025
+ __privateAdd(this, _flushChunks);
1026
+ __privateAdd(this, _target2, void 0);
1027
+ __privateAdd(this, _sections, []);
1028
+ __privateAdd(this, _chunked, void 0);
1029
+ __privateAdd(this, _chunkSize, void 0);
1030
+ __privateAdd(this, _chunks, []);
1031
+ __privateSet(this, _target2, target);
1032
+ __privateSet(this, _chunked, target.options?.chunked ?? false);
1033
+ __privateSet(this, _chunkSize, target.options?.chunkSize ?? DEFAULT_CHUNK_SIZE);
1034
+ }
1035
+ write(data) {
1036
+ __privateGet(this, _sections).push({
1037
+ data: data.slice(),
1038
+ start: this.pos
1039
+ });
1040
+ this.pos += data.byteLength;
1041
+ }
1042
+ flush() {
1043
+ if (__privateGet(this, _sections).length === 0)
1044
+ return;
1045
+ let chunks = [];
1046
+ let sorted = [...__privateGet(this, _sections)].sort((a, b) => a.start - b.start);
1047
+ chunks.push({
1048
+ start: sorted[0].start,
1049
+ size: sorted[0].data.byteLength
1050
+ });
1051
+ for (let i = 1; i < sorted.length; i++) {
1052
+ let lastChunk = chunks[chunks.length - 1];
1053
+ let section = sorted[i];
1054
+ if (section.start <= lastChunk.start + lastChunk.size) {
1055
+ lastChunk.size = Math.max(lastChunk.size, section.start + section.data.byteLength - lastChunk.start);
1056
+ } else {
1057
+ chunks.push({
1058
+ start: section.start,
1059
+ size: section.data.byteLength
1060
+ });
1061
+ }
1062
+ }
1063
+ for (let chunk of chunks) {
1064
+ chunk.data = new Uint8Array(chunk.size);
1065
+ for (let section of __privateGet(this, _sections)) {
1066
+ if (chunk.start <= section.start && section.start < chunk.start + chunk.size) {
1067
+ chunk.data.set(section.data, section.start - chunk.start);
1068
+ }
1069
+ }
1070
+ if (__privateGet(this, _chunked)) {
1071
+ __privateMethod(this, _writeDataIntoChunks, writeDataIntoChunks_fn).call(this, chunk.data, chunk.start);
1072
+ __privateMethod(this, _flushChunks, flushChunks_fn).call(this);
1073
+ } else {
1074
+ __privateGet(this, _target2).options.onData?.(chunk.data, chunk.start);
1075
+ }
1076
+ }
1077
+ __privateGet(this, _sections).length = 0;
1078
+ }
1079
+ finalize() {
1080
+ if (__privateGet(this, _chunked)) {
1081
+ __privateMethod(this, _flushChunks, flushChunks_fn).call(this, true);
1082
+ }
1083
+ }
1084
+ };
1085
+ _target2 = /* @__PURE__ */ new WeakMap();
1086
+ _sections = /* @__PURE__ */ new WeakMap();
1087
+ _chunked = /* @__PURE__ */ new WeakMap();
1088
+ _chunkSize = /* @__PURE__ */ new WeakMap();
1089
+ _chunks = /* @__PURE__ */ new WeakMap();
1090
+ _writeDataIntoChunks = /* @__PURE__ */ new WeakSet();
1091
+ writeDataIntoChunks_fn = function(data, position) {
1092
+ let chunkIndex = __privateGet(this, _chunks).findIndex((x) => x.start <= position && position < x.start + __privateGet(this, _chunkSize));
1093
+ if (chunkIndex === -1)
1094
+ chunkIndex = __privateMethod(this, _createChunk, createChunk_fn).call(this, position);
1095
+ let chunk = __privateGet(this, _chunks)[chunkIndex];
1096
+ let relativePosition = position - chunk.start;
1097
+ let toWrite = data.subarray(0, Math.min(__privateGet(this, _chunkSize) - relativePosition, data.byteLength));
1098
+ chunk.data.set(toWrite, relativePosition);
1099
+ let section = {
1100
+ start: relativePosition,
1101
+ end: relativePosition + toWrite.byteLength
1102
+ };
1103
+ __privateMethod(this, _insertSectionIntoChunk, insertSectionIntoChunk_fn).call(this, chunk, section);
1104
+ if (chunk.written[0].start === 0 && chunk.written[0].end === __privateGet(this, _chunkSize)) {
1105
+ chunk.shouldFlush = true;
1106
+ }
1107
+ if (__privateGet(this, _chunks).length > MAX_CHUNKS_AT_ONCE) {
1108
+ for (let i = 0; i < __privateGet(this, _chunks).length - 1; i++) {
1109
+ __privateGet(this, _chunks)[i].shouldFlush = true;
1110
+ }
1111
+ __privateMethod(this, _flushChunks, flushChunks_fn).call(this);
1112
+ }
1113
+ if (toWrite.byteLength < data.byteLength) {
1114
+ __privateMethod(this, _writeDataIntoChunks, writeDataIntoChunks_fn).call(this, data.subarray(toWrite.byteLength), position + toWrite.byteLength);
1115
+ }
1116
+ };
1117
+ _insertSectionIntoChunk = /* @__PURE__ */ new WeakSet();
1118
+ insertSectionIntoChunk_fn = function(chunk, section) {
1119
+ let low = 0;
1120
+ let high = chunk.written.length - 1;
1121
+ let index = -1;
1122
+ while (low <= high) {
1123
+ let mid = Math.floor(low + (high - low + 1) / 2);
1124
+ if (chunk.written[mid].start <= section.start) {
1125
+ low = mid + 1;
1126
+ index = mid;
1127
+ } else {
1128
+ high = mid - 1;
1129
+ }
1130
+ }
1131
+ chunk.written.splice(index + 1, 0, section);
1132
+ if (index === -1 || chunk.written[index].end < section.start)
1133
+ index++;
1134
+ while (index < chunk.written.length - 1 && chunk.written[index].end >= chunk.written[index + 1].start) {
1135
+ chunk.written[index].end = Math.max(chunk.written[index].end, chunk.written[index + 1].end);
1136
+ chunk.written.splice(index + 1, 1);
1137
+ }
1138
+ };
1139
+ _createChunk = /* @__PURE__ */ new WeakSet();
1140
+ createChunk_fn = function(includesPosition) {
1141
+ let start = Math.floor(includesPosition / __privateGet(this, _chunkSize)) * __privateGet(this, _chunkSize);
1142
+ let chunk = {
1143
+ start,
1144
+ data: new Uint8Array(__privateGet(this, _chunkSize)),
1145
+ written: [],
1146
+ shouldFlush: false
1147
+ };
1148
+ __privateGet(this, _chunks).push(chunk);
1149
+ __privateGet(this, _chunks).sort((a, b) => a.start - b.start);
1150
+ return __privateGet(this, _chunks).indexOf(chunk);
1151
+ };
1152
+ _flushChunks = /* @__PURE__ */ new WeakSet();
1153
+ flushChunks_fn = function(force = false) {
1154
+ for (let i = 0; i < __privateGet(this, _chunks).length; i++) {
1155
+ let chunk = __privateGet(this, _chunks)[i];
1156
+ if (!chunk.shouldFlush && !force)
1157
+ continue;
1158
+ for (let section of chunk.written) {
1159
+ __privateGet(this, _target2).options.onData?.(
1160
+ chunk.data.subarray(section.start, section.end),
1161
+ chunk.start + section.start
1162
+ );
1163
+ }
1164
+ __privateGet(this, _chunks).splice(i--, 1);
1165
+ }
1166
+ };
1167
+ var FileSystemWritableFileStreamTargetWriter = class extends StreamTargetWriter {
1168
+ constructor(target) {
1169
+ super(new StreamTarget({
1170
+ onData: (data, position) => target.stream.write({
1171
+ type: "write",
1172
+ data,
1173
+ position
1174
+ }),
1175
+ chunked: true,
1176
+ chunkSize: target.options?.chunkSize
1177
+ }));
1178
+ }
1179
+ };
1180
+ var GLOBAL_TIMESCALE = 1e3;
1181
+ var SUPPORTED_VIDEO_CODECS = ["avc", "hevc", "vp9", "av1"];
1182
+ var SUPPORTED_AUDIO_CODECS = ["aac", "opus"];
1183
+ var TIMESTAMP_OFFSET = 2082844800;
1184
+ var FIRST_TIMESTAMP_BEHAVIORS = ["strict", "offset", "cross-track-offset"];
1185
+ var _options;
1186
+ var _writer;
1187
+ var _ftypSize;
1188
+ var _mdat;
1189
+ var _videoTrack;
1190
+ var _audioTrack;
1191
+ var _creationTime;
1192
+ var _finalizedChunks;
1193
+ var _nextFragmentNumber;
1194
+ var _videoSampleQueue;
1195
+ var _audioSampleQueue;
1196
+ var _finalized;
1197
+ var _validateOptions;
1198
+ var validateOptions_fn;
1199
+ var _writeHeader;
1200
+ var writeHeader_fn;
1201
+ var _computeMoovSizeUpperBound;
1202
+ var computeMoovSizeUpperBound_fn;
1203
+ var _prepareTracks;
1204
+ var prepareTracks_fn;
1205
+ var _generateMpeg4AudioSpecificConfig;
1206
+ var generateMpeg4AudioSpecificConfig_fn;
1207
+ var _createSampleForTrack;
1208
+ var createSampleForTrack_fn;
1209
+ var _addSampleToTrack;
1210
+ var addSampleToTrack_fn;
1211
+ var _validateTimestamp;
1212
+ var validateTimestamp_fn;
1213
+ var _finalizeCurrentChunk;
1214
+ var finalizeCurrentChunk_fn;
1215
+ var _finalizeFragment;
1216
+ var finalizeFragment_fn;
1217
+ var _maybeFlushStreamingTargetWriter;
1218
+ var maybeFlushStreamingTargetWriter_fn;
1219
+ var _ensureNotFinalized;
1220
+ var ensureNotFinalized_fn;
1221
+ var Muxer = class {
1222
+ constructor(options) {
1223
+ __privateAdd(this, _validateOptions);
1224
+ __privateAdd(this, _writeHeader);
1225
+ __privateAdd(this, _computeMoovSizeUpperBound);
1226
+ __privateAdd(this, _prepareTracks);
1227
+ __privateAdd(this, _generateMpeg4AudioSpecificConfig);
1228
+ __privateAdd(this, _createSampleForTrack);
1229
+ __privateAdd(this, _addSampleToTrack);
1230
+ __privateAdd(this, _validateTimestamp);
1231
+ __privateAdd(this, _finalizeCurrentChunk);
1232
+ __privateAdd(this, _finalizeFragment);
1233
+ __privateAdd(this, _maybeFlushStreamingTargetWriter);
1234
+ __privateAdd(this, _ensureNotFinalized);
1235
+ __privateAdd(this, _options, void 0);
1236
+ __privateAdd(this, _writer, void 0);
1237
+ __privateAdd(this, _ftypSize, void 0);
1238
+ __privateAdd(this, _mdat, void 0);
1239
+ __privateAdd(this, _videoTrack, null);
1240
+ __privateAdd(this, _audioTrack, null);
1241
+ __privateAdd(this, _creationTime, Math.floor(Date.now() / 1e3) + TIMESTAMP_OFFSET);
1242
+ __privateAdd(this, _finalizedChunks, []);
1243
+ __privateAdd(this, _nextFragmentNumber, 1);
1244
+ __privateAdd(this, _videoSampleQueue, []);
1245
+ __privateAdd(this, _audioSampleQueue, []);
1246
+ __privateAdd(this, _finalized, false);
1247
+ __privateMethod(this, _validateOptions, validateOptions_fn).call(this, options);
1248
+ options.video = deepClone(options.video);
1249
+ options.audio = deepClone(options.audio);
1250
+ options.fastStart = deepClone(options.fastStart);
1251
+ this.target = options.target;
1252
+ __privateSet(this, _options, {
1253
+ firstTimestampBehavior: "strict",
1254
+ ...options
1255
+ });
1256
+ if (options.target instanceof ArrayBufferTarget) {
1257
+ __privateSet(this, _writer, new ArrayBufferTargetWriter(options.target));
1258
+ } else if (options.target instanceof StreamTarget) {
1259
+ __privateSet(this, _writer, new StreamTargetWriter(options.target));
1260
+ } else if (options.target instanceof FileSystemWritableFileStreamTarget) {
1261
+ __privateSet(this, _writer, new FileSystemWritableFileStreamTargetWriter(options.target));
1262
+ } else {
1263
+ throw new Error(`Invalid target: ${options.target}`);
1264
+ }
1265
+ __privateMethod(this, _prepareTracks, prepareTracks_fn).call(this);
1266
+ __privateMethod(this, _writeHeader, writeHeader_fn).call(this);
1267
+ }
1268
+ addVideoChunk(sample, meta, timestamp, compositionTimeOffset) {
1269
+ if (!(sample instanceof EncodedVideoChunk)) {
1270
+ throw new TypeError("addVideoChunk's first argument (sample) must be of type EncodedVideoChunk.");
1271
+ }
1272
+ if (meta && typeof meta !== "object") {
1273
+ throw new TypeError("addVideoChunk's second argument (meta), when provided, must be an object.");
1274
+ }
1275
+ if (timestamp !== void 0 && (!Number.isFinite(timestamp) || timestamp < 0)) {
1276
+ throw new TypeError(
1277
+ "addVideoChunk's third argument (timestamp), when provided, must be a non-negative real number."
1278
+ );
1279
+ }
1280
+ if (compositionTimeOffset !== void 0 && !Number.isFinite(compositionTimeOffset)) {
1281
+ throw new TypeError(
1282
+ "addVideoChunk's fourth argument (compositionTimeOffset), when provided, must be a real number."
1283
+ );
1284
+ }
1285
+ let data = new Uint8Array(sample.byteLength);
1286
+ sample.copyTo(data);
1287
+ this.addVideoChunkRaw(
1288
+ data,
1289
+ sample.type,
1290
+ timestamp ?? sample.timestamp,
1291
+ sample.duration,
1292
+ meta,
1293
+ compositionTimeOffset
1294
+ );
1295
+ }
1296
+ addVideoChunkRaw(data, type, timestamp, duration, meta, compositionTimeOffset) {
1297
+ if (!(data instanceof Uint8Array)) {
1298
+ throw new TypeError("addVideoChunkRaw's first argument (data) must be an instance of Uint8Array.");
1299
+ }
1300
+ if (type !== "key" && type !== "delta") {
1301
+ throw new TypeError("addVideoChunkRaw's second argument (type) must be either 'key' or 'delta'.");
1302
+ }
1303
+ if (!Number.isFinite(timestamp) || timestamp < 0) {
1304
+ throw new TypeError("addVideoChunkRaw's third argument (timestamp) must be a non-negative real number.");
1305
+ }
1306
+ if (!Number.isFinite(duration) || duration < 0) {
1307
+ throw new TypeError("addVideoChunkRaw's fourth argument (duration) must be a non-negative real number.");
1308
+ }
1309
+ if (meta && typeof meta !== "object") {
1310
+ throw new TypeError("addVideoChunkRaw's fifth argument (meta), when provided, must be an object.");
1311
+ }
1312
+ if (compositionTimeOffset !== void 0 && !Number.isFinite(compositionTimeOffset)) {
1313
+ throw new TypeError(
1314
+ "addVideoChunkRaw's sixth argument (compositionTimeOffset), when provided, must be a real number."
1315
+ );
1316
+ }
1317
+ __privateMethod(this, _ensureNotFinalized, ensureNotFinalized_fn).call(this);
1318
+ if (!__privateGet(this, _options).video)
1319
+ throw new Error("No video track declared.");
1320
+ if (typeof __privateGet(this, _options).fastStart === "object" && __privateGet(this, _videoTrack).samples.length === __privateGet(this, _options).fastStart.expectedVideoChunks) {
1321
+ throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${__privateGet(this, _options).fastStart.expectedVideoChunks}).`);
1322
+ }
1323
+ let videoSample = __privateMethod(this, _createSampleForTrack, createSampleForTrack_fn).call(this, __privateGet(this, _videoTrack), data, type, timestamp, duration, meta, compositionTimeOffset);
1324
+ if (__privateGet(this, _options).fastStart === "fragmented" && __privateGet(this, _audioTrack)) {
1325
+ while (__privateGet(this, _audioSampleQueue).length > 0 && __privateGet(this, _audioSampleQueue)[0].decodeTimestamp <= videoSample.decodeTimestamp) {
1326
+ let audioSample = __privateGet(this, _audioSampleQueue).shift();
1327
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _audioTrack), audioSample);
1328
+ }
1329
+ if (videoSample.decodeTimestamp <= __privateGet(this, _audioTrack).lastDecodeTimestamp) {
1330
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _videoTrack), videoSample);
1331
+ } else {
1332
+ __privateGet(this, _videoSampleQueue).push(videoSample);
1333
+ }
1334
+ } else {
1335
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _videoTrack), videoSample);
1336
+ }
1337
+ }
1338
+ addAudioChunk(sample, meta, timestamp) {
1339
+ if (!(sample instanceof EncodedAudioChunk)) {
1340
+ throw new TypeError("addAudioChunk's first argument (sample) must be of type EncodedAudioChunk.");
1341
+ }
1342
+ if (meta && typeof meta !== "object") {
1343
+ throw new TypeError("addAudioChunk's second argument (meta), when provided, must be an object.");
1344
+ }
1345
+ if (timestamp !== void 0 && (!Number.isFinite(timestamp) || timestamp < 0)) {
1346
+ throw new TypeError(
1347
+ "addAudioChunk's third argument (timestamp), when provided, must be a non-negative real number."
1348
+ );
1349
+ }
1350
+ let data = new Uint8Array(sample.byteLength);
1351
+ sample.copyTo(data);
1352
+ this.addAudioChunkRaw(data, sample.type, timestamp ?? sample.timestamp, sample.duration, meta);
1353
+ }
1354
+ addAudioChunkRaw(data, type, timestamp, duration, meta) {
1355
+ if (!(data instanceof Uint8Array)) {
1356
+ throw new TypeError("addAudioChunkRaw's first argument (data) must be an instance of Uint8Array.");
1357
+ }
1358
+ if (type !== "key" && type !== "delta") {
1359
+ throw new TypeError("addAudioChunkRaw's second argument (type) must be either 'key' or 'delta'.");
1360
+ }
1361
+ if (!Number.isFinite(timestamp) || timestamp < 0) {
1362
+ throw new TypeError("addAudioChunkRaw's third argument (timestamp) must be a non-negative real number.");
1363
+ }
1364
+ if (!Number.isFinite(duration) || duration < 0) {
1365
+ throw new TypeError("addAudioChunkRaw's fourth argument (duration) must be a non-negative real number.");
1366
+ }
1367
+ if (meta && typeof meta !== "object") {
1368
+ throw new TypeError("addAudioChunkRaw's fifth argument (meta), when provided, must be an object.");
1369
+ }
1370
+ __privateMethod(this, _ensureNotFinalized, ensureNotFinalized_fn).call(this);
1371
+ if (!__privateGet(this, _options).audio)
1372
+ throw new Error("No audio track declared.");
1373
+ if (typeof __privateGet(this, _options).fastStart === "object" && __privateGet(this, _audioTrack).samples.length === __privateGet(this, _options).fastStart.expectedAudioChunks) {
1374
+ throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${__privateGet(this, _options).fastStart.expectedAudioChunks}).`);
1375
+ }
1376
+ let audioSample = __privateMethod(this, _createSampleForTrack, createSampleForTrack_fn).call(this, __privateGet(this, _audioTrack), data, type, timestamp, duration, meta);
1377
+ if (__privateGet(this, _options).fastStart === "fragmented" && __privateGet(this, _videoTrack)) {
1378
+ while (__privateGet(this, _videoSampleQueue).length > 0 && __privateGet(this, _videoSampleQueue)[0].decodeTimestamp <= audioSample.decodeTimestamp) {
1379
+ let videoSample = __privateGet(this, _videoSampleQueue).shift();
1380
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _videoTrack), videoSample);
1381
+ }
1382
+ if (audioSample.decodeTimestamp <= __privateGet(this, _videoTrack).lastDecodeTimestamp) {
1383
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _audioTrack), audioSample);
1384
+ } else {
1385
+ __privateGet(this, _audioSampleQueue).push(audioSample);
1386
+ }
1387
+ } else {
1388
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _audioTrack), audioSample);
1389
+ }
1390
+ }
1391
+ /** Finalizes the file, making it ready for use. Must be called after all video and audio chunks have been added. */
1392
+ finalize() {
1393
+ if (__privateGet(this, _finalized)) {
1394
+ throw new Error("Cannot finalize a muxer more than once.");
1395
+ }
1396
+ if (__privateGet(this, _options).fastStart === "fragmented") {
1397
+ for (let videoSample of __privateGet(this, _videoSampleQueue))
1398
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _videoTrack), videoSample);
1399
+ for (let audioSample of __privateGet(this, _audioSampleQueue))
1400
+ __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _audioTrack), audioSample);
1401
+ __privateMethod(this, _finalizeFragment, finalizeFragment_fn).call(this, false);
1402
+ } else {
1403
+ if (__privateGet(this, _videoTrack))
1404
+ __privateMethod(this, _finalizeCurrentChunk, finalizeCurrentChunk_fn).call(this, __privateGet(this, _videoTrack));
1405
+ if (__privateGet(this, _audioTrack))
1406
+ __privateMethod(this, _finalizeCurrentChunk, finalizeCurrentChunk_fn).call(this, __privateGet(this, _audioTrack));
1407
+ }
1408
+ let tracks = [__privateGet(this, _videoTrack), __privateGet(this, _audioTrack)].filter(Boolean);
1409
+ if (__privateGet(this, _options).fastStart === "in-memory") {
1410
+ let mdatSize;
1411
+ for (let i = 0; i < 2; i++) {
1412
+ let movieBox2 = moov(tracks, __privateGet(this, _creationTime));
1413
+ let movieBoxSize = __privateGet(this, _writer).measureBox(movieBox2);
1414
+ mdatSize = __privateGet(this, _writer).measureBox(__privateGet(this, _mdat));
1415
+ let currentChunkPos = __privateGet(this, _writer).pos + movieBoxSize + mdatSize;
1416
+ for (let chunk of __privateGet(this, _finalizedChunks)) {
1417
+ chunk.offset = currentChunkPos;
1418
+ for (let { data } of chunk.samples) {
1419
+ currentChunkPos += data.byteLength;
1420
+ mdatSize += data.byteLength;
1421
+ }
1422
+ }
1423
+ if (currentChunkPos < 2 ** 32)
1424
+ break;
1425
+ if (mdatSize >= 2 ** 32)
1426
+ __privateGet(this, _mdat).largeSize = true;
1427
+ }
1428
+ let movieBox = moov(tracks, __privateGet(this, _creationTime));
1429
+ __privateGet(this, _writer).writeBox(movieBox);
1430
+ __privateGet(this, _mdat).size = mdatSize;
1431
+ __privateGet(this, _writer).writeBox(__privateGet(this, _mdat));
1432
+ for (let chunk of __privateGet(this, _finalizedChunks)) {
1433
+ for (let sample of chunk.samples) {
1434
+ __privateGet(this, _writer).write(sample.data);
1435
+ sample.data = null;
1436
+ }
1437
+ }
1438
+ } else if (__privateGet(this, _options).fastStart === "fragmented") {
1439
+ let startPos = __privateGet(this, _writer).pos;
1440
+ let mfraBox = mfra(tracks);
1441
+ __privateGet(this, _writer).writeBox(mfraBox);
1442
+ let mfraBoxSize = __privateGet(this, _writer).pos - startPos;
1443
+ __privateGet(this, _writer).seek(__privateGet(this, _writer).pos - 4);
1444
+ __privateGet(this, _writer).writeU32(mfraBoxSize);
1445
+ } else {
1446
+ let mdatPos = __privateGet(this, _writer).offsets.get(__privateGet(this, _mdat));
1447
+ let mdatSize = __privateGet(this, _writer).pos - mdatPos;
1448
+ __privateGet(this, _mdat).size = mdatSize;
1449
+ __privateGet(this, _mdat).largeSize = mdatSize >= 2 ** 32;
1450
+ __privateGet(this, _writer).patchBox(__privateGet(this, _mdat));
1451
+ let movieBox = moov(tracks, __privateGet(this, _creationTime));
1452
+ if (typeof __privateGet(this, _options).fastStart === "object") {
1453
+ __privateGet(this, _writer).seek(__privateGet(this, _ftypSize));
1454
+ __privateGet(this, _writer).writeBox(movieBox);
1455
+ let remainingBytes = mdatPos - __privateGet(this, _writer).pos;
1456
+ __privateGet(this, _writer).writeBox(free(remainingBytes));
1457
+ } else {
1458
+ __privateGet(this, _writer).writeBox(movieBox);
1459
+ }
1460
+ }
1461
+ __privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
1462
+ __privateGet(this, _writer).finalize();
1463
+ __privateSet(this, _finalized, true);
1464
+ }
1465
+ };
1466
+ _options = /* @__PURE__ */ new WeakMap();
1467
+ _writer = /* @__PURE__ */ new WeakMap();
1468
+ _ftypSize = /* @__PURE__ */ new WeakMap();
1469
+ _mdat = /* @__PURE__ */ new WeakMap();
1470
+ _videoTrack = /* @__PURE__ */ new WeakMap();
1471
+ _audioTrack = /* @__PURE__ */ new WeakMap();
1472
+ _creationTime = /* @__PURE__ */ new WeakMap();
1473
+ _finalizedChunks = /* @__PURE__ */ new WeakMap();
1474
+ _nextFragmentNumber = /* @__PURE__ */ new WeakMap();
1475
+ _videoSampleQueue = /* @__PURE__ */ new WeakMap();
1476
+ _audioSampleQueue = /* @__PURE__ */ new WeakMap();
1477
+ _finalized = /* @__PURE__ */ new WeakMap();
1478
+ _validateOptions = /* @__PURE__ */ new WeakSet();
1479
+ validateOptions_fn = function(options) {
1480
+ if (typeof options !== "object") {
1481
+ throw new TypeError("The muxer requires an options object to be passed to its constructor.");
1482
+ }
1483
+ if (!(options.target instanceof Target)) {
1484
+ throw new TypeError("The target must be provided and an instance of Target.");
1485
+ }
1486
+ if (options.video) {
1487
+ if (!SUPPORTED_VIDEO_CODECS.includes(options.video.codec)) {
1488
+ throw new TypeError(`Unsupported video codec: ${options.video.codec}`);
1489
+ }
1490
+ if (!Number.isInteger(options.video.width) || options.video.width <= 0) {
1491
+ throw new TypeError(`Invalid video width: ${options.video.width}. Must be a positive integer.`);
1492
+ }
1493
+ if (!Number.isInteger(options.video.height) || options.video.height <= 0) {
1494
+ throw new TypeError(`Invalid video height: ${options.video.height}. Must be a positive integer.`);
1495
+ }
1496
+ const videoRotation = options.video.rotation;
1497
+ if (typeof videoRotation === "number" && ![0, 90, 180, 270].includes(videoRotation)) {
1498
+ throw new TypeError(`Invalid video rotation: ${videoRotation}. Has to be 0, 90, 180 or 270.`);
1499
+ } else if (Array.isArray(videoRotation) && (videoRotation.length !== 9 || videoRotation.some((value) => typeof value !== "number"))) {
1500
+ throw new TypeError(`Invalid video transformation matrix: ${videoRotation.join()}`);
1501
+ }
1502
+ if (options.video.frameRate !== void 0 && (!Number.isInteger(options.video.frameRate) || options.video.frameRate <= 0)) {
1503
+ throw new TypeError(
1504
+ `Invalid video frame rate: ${options.video.frameRate}. Must be a positive integer.`
1505
+ );
1506
+ }
1507
+ }
1508
+ if (options.audio) {
1509
+ if (!SUPPORTED_AUDIO_CODECS.includes(options.audio.codec)) {
1510
+ throw new TypeError(`Unsupported audio codec: ${options.audio.codec}`);
1511
+ }
1512
+ if (!Number.isInteger(options.audio.numberOfChannels) || options.audio.numberOfChannels <= 0) {
1513
+ throw new TypeError(
1514
+ `Invalid number of audio channels: ${options.audio.numberOfChannels}. Must be a positive integer.`
1515
+ );
1516
+ }
1517
+ if (!Number.isInteger(options.audio.sampleRate) || options.audio.sampleRate <= 0) {
1518
+ throw new TypeError(
1519
+ `Invalid audio sample rate: ${options.audio.sampleRate}. Must be a positive integer.`
1520
+ );
1521
+ }
1522
+ }
1523
+ if (options.firstTimestampBehavior && !FIRST_TIMESTAMP_BEHAVIORS.includes(options.firstTimestampBehavior)) {
1524
+ throw new TypeError(`Invalid first timestamp behavior: ${options.firstTimestampBehavior}`);
1525
+ }
1526
+ if (typeof options.fastStart === "object") {
1527
+ if (options.video) {
1528
+ if (options.fastStart.expectedVideoChunks === void 0) {
1529
+ throw new TypeError(`'fastStart' is an object but is missing property 'expectedVideoChunks'.`);
1530
+ } else if (!Number.isInteger(options.fastStart.expectedVideoChunks) || options.fastStart.expectedVideoChunks < 0) {
1531
+ throw new TypeError(`'expectedVideoChunks' must be a non-negative integer.`);
1532
+ }
1533
+ }
1534
+ if (options.audio) {
1535
+ if (options.fastStart.expectedAudioChunks === void 0) {
1536
+ throw new TypeError(`'fastStart' is an object but is missing property 'expectedAudioChunks'.`);
1537
+ } else if (!Number.isInteger(options.fastStart.expectedAudioChunks) || options.fastStart.expectedAudioChunks < 0) {
1538
+ throw new TypeError(`'expectedAudioChunks' must be a non-negative integer.`);
1539
+ }
1540
+ }
1541
+ } else if (![false, "in-memory", "fragmented"].includes(options.fastStart)) {
1542
+ throw new TypeError(`'fastStart' option must be false, 'in-memory', 'fragmented' or an object.`);
1543
+ }
1544
+ if (options.minFragmentDuration !== void 0 && (!Number.isFinite(options.minFragmentDuration) || options.minFragmentDuration < 0)) {
1545
+ throw new TypeError(`'minFragmentDuration' must be a non-negative number.`);
1546
+ }
1547
+ };
1548
+ _writeHeader = /* @__PURE__ */ new WeakSet();
1549
+ writeHeader_fn = function() {
1550
+ __privateGet(this, _writer).writeBox(ftyp({
1551
+ holdsAvc: __privateGet(this, _options).video?.codec === "avc",
1552
+ fragmented: __privateGet(this, _options).fastStart === "fragmented"
1553
+ }));
1554
+ __privateSet(this, _ftypSize, __privateGet(this, _writer).pos);
1555
+ if (__privateGet(this, _options).fastStart === "in-memory") {
1556
+ __privateSet(this, _mdat, mdat(false));
1557
+ } else if (__privateGet(this, _options).fastStart === "fragmented") {
1558
+ } else {
1559
+ if (typeof __privateGet(this, _options).fastStart === "object") {
1560
+ let moovSizeUpperBound = __privateMethod(this, _computeMoovSizeUpperBound, computeMoovSizeUpperBound_fn).call(this);
1561
+ __privateGet(this, _writer).seek(__privateGet(this, _writer).pos + moovSizeUpperBound);
1562
+ }
1563
+ __privateSet(this, _mdat, mdat(true));
1564
+ __privateGet(this, _writer).writeBox(__privateGet(this, _mdat));
1565
+ }
1566
+ __privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
1567
+ };
1568
+ _computeMoovSizeUpperBound = /* @__PURE__ */ new WeakSet();
1569
+ computeMoovSizeUpperBound_fn = function() {
1570
+ if (typeof __privateGet(this, _options).fastStart !== "object")
1571
+ return;
1572
+ let upperBound = 0;
1573
+ let sampleCounts = [
1574
+ __privateGet(this, _options).fastStart.expectedVideoChunks,
1575
+ __privateGet(this, _options).fastStart.expectedAudioChunks
1576
+ ];
1577
+ for (let n of sampleCounts) {
1578
+ if (!n)
1579
+ continue;
1580
+ upperBound += (4 + 4) * Math.ceil(2 / 3 * n);
1581
+ upperBound += 4 * n;
1582
+ upperBound += (4 + 4 + 4) * Math.ceil(2 / 3 * n);
1583
+ upperBound += 4 * n;
1584
+ upperBound += 8 * n;
1585
+ }
1586
+ upperBound += 4096;
1587
+ return upperBound;
1588
+ };
1589
+ _prepareTracks = /* @__PURE__ */ new WeakSet();
1590
+ prepareTracks_fn = function() {
1591
+ if (__privateGet(this, _options).video) {
1592
+ __privateSet(this, _videoTrack, {
1593
+ id: 1,
1594
+ info: {
1595
+ type: "video",
1596
+ codec: __privateGet(this, _options).video.codec,
1597
+ width: __privateGet(this, _options).video.width,
1598
+ height: __privateGet(this, _options).video.height,
1599
+ rotation: __privateGet(this, _options).video.rotation ?? 0,
1600
+ decoderConfig: null
1601
+ },
1602
+ // The fallback contains many common frame rates as factors
1603
+ timescale: __privateGet(this, _options).video.frameRate ?? 57600,
1604
+ samples: [],
1605
+ finalizedChunks: [],
1606
+ currentChunk: null,
1607
+ firstDecodeTimestamp: void 0,
1608
+ lastDecodeTimestamp: -1,
1609
+ timeToSampleTable: [],
1610
+ compositionTimeOffsetTable: [],
1611
+ lastTimescaleUnits: null,
1612
+ lastSample: null,
1613
+ compactlyCodedChunkTable: []
1614
+ });
1615
+ }
1616
+ if (__privateGet(this, _options).audio) {
1617
+ __privateSet(this, _audioTrack, {
1618
+ id: __privateGet(this, _options).video ? 2 : 1,
1619
+ info: {
1620
+ type: "audio",
1621
+ codec: __privateGet(this, _options).audio.codec,
1622
+ numberOfChannels: __privateGet(this, _options).audio.numberOfChannels,
1623
+ sampleRate: __privateGet(this, _options).audio.sampleRate,
1624
+ decoderConfig: null
1625
+ },
1626
+ timescale: __privateGet(this, _options).audio.sampleRate,
1627
+ samples: [],
1628
+ finalizedChunks: [],
1629
+ currentChunk: null,
1630
+ firstDecodeTimestamp: void 0,
1631
+ lastDecodeTimestamp: -1,
1632
+ timeToSampleTable: [],
1633
+ compositionTimeOffsetTable: [],
1634
+ lastTimescaleUnits: null,
1635
+ lastSample: null,
1636
+ compactlyCodedChunkTable: []
1637
+ });
1638
+ if (__privateGet(this, _options).audio.codec === "aac") {
1639
+ let guessedCodecPrivate = __privateMethod(this, _generateMpeg4AudioSpecificConfig, generateMpeg4AudioSpecificConfig_fn).call(
1640
+ this,
1641
+ 2,
1642
+ // Object type for AAC-LC, since it's the most common
1643
+ __privateGet(this, _options).audio.sampleRate,
1644
+ __privateGet(this, _options).audio.numberOfChannels
1645
+ );
1646
+ __privateGet(this, _audioTrack).info.decoderConfig = {
1647
+ codec: __privateGet(this, _options).audio.codec,
1648
+ description: guessedCodecPrivate,
1649
+ numberOfChannels: __privateGet(this, _options).audio.numberOfChannels,
1650
+ sampleRate: __privateGet(this, _options).audio.sampleRate
1651
+ };
1652
+ }
1653
+ }
1654
+ };
1655
+ _generateMpeg4AudioSpecificConfig = /* @__PURE__ */ new WeakSet();
1656
+ generateMpeg4AudioSpecificConfig_fn = function(objectType, sampleRate, numberOfChannels) {
1657
+ let frequencyIndices = [96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350];
1658
+ let frequencyIndex = frequencyIndices.indexOf(sampleRate);
1659
+ let channelConfig = numberOfChannels;
1660
+ let configBits = "";
1661
+ configBits += objectType.toString(2).padStart(5, "0");
1662
+ configBits += frequencyIndex.toString(2).padStart(4, "0");
1663
+ if (frequencyIndex === 15)
1664
+ configBits += sampleRate.toString(2).padStart(24, "0");
1665
+ configBits += channelConfig.toString(2).padStart(4, "0");
1666
+ let paddingLength = Math.ceil(configBits.length / 8) * 8;
1667
+ configBits = configBits.padEnd(paddingLength, "0");
1668
+ let configBytes = new Uint8Array(configBits.length / 8);
1669
+ for (let i = 0; i < configBits.length; i += 8) {
1670
+ configBytes[i / 8] = parseInt(configBits.slice(i, i + 8), 2);
1671
+ }
1672
+ return configBytes;
1673
+ };
1674
+ _createSampleForTrack = /* @__PURE__ */ new WeakSet();
1675
+ createSampleForTrack_fn = function(track, data, type, timestamp, duration, meta, compositionTimeOffset) {
1676
+ let presentationTimestampInSeconds = timestamp / 1e6;
1677
+ let decodeTimestampInSeconds = (timestamp - (compositionTimeOffset ?? 0)) / 1e6;
1678
+ let durationInSeconds = duration / 1e6;
1679
+ let adjusted = __privateMethod(this, _validateTimestamp, validateTimestamp_fn).call(this, presentationTimestampInSeconds, decodeTimestampInSeconds, track);
1680
+ presentationTimestampInSeconds = adjusted.presentationTimestamp;
1681
+ decodeTimestampInSeconds = adjusted.decodeTimestamp;
1682
+ if (meta?.decoderConfig) {
1683
+ if (track.info.decoderConfig === null) {
1684
+ track.info.decoderConfig = meta.decoderConfig;
1685
+ } else {
1686
+ Object.assign(track.info.decoderConfig, meta.decoderConfig);
1687
+ }
1688
+ }
1689
+ let sample = {
1690
+ presentationTimestamp: presentationTimestampInSeconds,
1691
+ decodeTimestamp: decodeTimestampInSeconds,
1692
+ duration: durationInSeconds,
1693
+ data,
1694
+ size: data.byteLength,
1695
+ type,
1696
+ // Will be refined once the next sample comes in
1697
+ timescaleUnitsToNextSample: intoTimescale(durationInSeconds, track.timescale)
1698
+ };
1699
+ return sample;
1700
+ };
1701
+ _addSampleToTrack = /* @__PURE__ */ new WeakSet();
1702
+ addSampleToTrack_fn = function(track, sample) {
1703
+ if (__privateGet(this, _options).fastStart !== "fragmented") {
1704
+ track.samples.push(sample);
1705
+ }
1706
+ const sampleCompositionTimeOffset = intoTimescale(sample.presentationTimestamp - sample.decodeTimestamp, track.timescale);
1707
+ if (track.lastTimescaleUnits !== null) {
1708
+ let timescaleUnits = intoTimescale(sample.decodeTimestamp, track.timescale, false);
1709
+ let delta = Math.round(timescaleUnits - track.lastTimescaleUnits);
1710
+ track.lastTimescaleUnits += delta;
1711
+ track.lastSample.timescaleUnitsToNextSample = delta;
1712
+ if (__privateGet(this, _options).fastStart !== "fragmented") {
1713
+ let lastTableEntry = last(track.timeToSampleTable);
1714
+ if (lastTableEntry.sampleCount === 1) {
1715
+ lastTableEntry.sampleDelta = delta;
1716
+ lastTableEntry.sampleCount++;
1717
+ } else if (lastTableEntry.sampleDelta === delta) {
1718
+ lastTableEntry.sampleCount++;
1719
+ } else {
1720
+ lastTableEntry.sampleCount--;
1721
+ track.timeToSampleTable.push({
1722
+ sampleCount: 2,
1723
+ sampleDelta: delta
1724
+ });
1725
+ }
1726
+ const lastCompositionTimeOffsetTableEntry = last(track.compositionTimeOffsetTable);
1727
+ if (lastCompositionTimeOffsetTableEntry.sampleCompositionTimeOffset === sampleCompositionTimeOffset) {
1728
+ lastCompositionTimeOffsetTableEntry.sampleCount++;
1729
+ } else {
1730
+ track.compositionTimeOffsetTable.push({
1731
+ sampleCount: 1,
1732
+ sampleCompositionTimeOffset
1733
+ });
1734
+ }
1735
+ }
1736
+ } else {
1737
+ track.lastTimescaleUnits = 0;
1738
+ if (__privateGet(this, _options).fastStart !== "fragmented") {
1739
+ track.timeToSampleTable.push({
1740
+ sampleCount: 1,
1741
+ sampleDelta: intoTimescale(sample.duration, track.timescale)
1742
+ });
1743
+ track.compositionTimeOffsetTable.push({
1744
+ sampleCount: 1,
1745
+ sampleCompositionTimeOffset
1746
+ });
1747
+ }
1748
+ }
1749
+ track.lastSample = sample;
1750
+ let beginNewChunk = false;
1751
+ if (!track.currentChunk) {
1752
+ beginNewChunk = true;
1753
+ } else {
1754
+ let currentChunkDuration = sample.presentationTimestamp - track.currentChunk.startTimestamp;
1755
+ if (__privateGet(this, _options).fastStart === "fragmented") {
1756
+ let mostImportantTrack = __privateGet(this, _videoTrack) ?? __privateGet(this, _audioTrack);
1757
+ const chunkDuration = __privateGet(this, _options).minFragmentDuration ?? 1;
1758
+ if (track === mostImportantTrack && sample.type === "key" && currentChunkDuration >= chunkDuration) {
1759
+ beginNewChunk = true;
1760
+ __privateMethod(this, _finalizeFragment, finalizeFragment_fn).call(this);
1761
+ }
1762
+ } else {
1763
+ beginNewChunk = currentChunkDuration >= 0.5;
1764
+ }
1765
+ }
1766
+ if (beginNewChunk) {
1767
+ if (track.currentChunk) {
1768
+ __privateMethod(this, _finalizeCurrentChunk, finalizeCurrentChunk_fn).call(this, track);
1769
+ }
1770
+ track.currentChunk = {
1771
+ startTimestamp: sample.presentationTimestamp,
1772
+ samples: []
1773
+ };
1774
+ }
1775
+ track.currentChunk.samples.push(sample);
1776
+ };
1777
+ _validateTimestamp = /* @__PURE__ */ new WeakSet();
1778
+ validateTimestamp_fn = function(presentationTimestamp, decodeTimestamp, track) {
1779
+ const strictTimestampBehavior = __privateGet(this, _options).firstTimestampBehavior === "strict";
1780
+ const noLastDecodeTimestamp = track.lastDecodeTimestamp === -1;
1781
+ const timestampNonZero = decodeTimestamp !== 0;
1782
+ if (strictTimestampBehavior && noLastDecodeTimestamp && timestampNonZero) {
1783
+ throw new Error(
1784
+ `The first chunk for your media track must have a timestamp of 0 (received DTS=${decodeTimestamp}).Non-zero first timestamps are often caused by directly piping frames or audio data from a MediaStreamTrack into the encoder. Their timestamps are typically relative to the age of thedocument, which is probably what you want.
1785
+
1786
+ If you want to offset all timestamps of a track such that the first one is zero, set firstTimestampBehavior: 'offset' in the options.
1787
+ `
1788
+ );
1789
+ } else if (__privateGet(this, _options).firstTimestampBehavior === "offset" || __privateGet(this, _options).firstTimestampBehavior === "cross-track-offset") {
1790
+ if (track.firstDecodeTimestamp === void 0) {
1791
+ track.firstDecodeTimestamp = decodeTimestamp;
1792
+ }
1793
+ let baseDecodeTimestamp;
1794
+ if (__privateGet(this, _options).firstTimestampBehavior === "offset") {
1795
+ baseDecodeTimestamp = track.firstDecodeTimestamp;
1796
+ } else {
1797
+ baseDecodeTimestamp = Math.min(
1798
+ __privateGet(this, _videoTrack)?.firstDecodeTimestamp ?? Infinity,
1799
+ __privateGet(this, _audioTrack)?.firstDecodeTimestamp ?? Infinity
1800
+ );
1801
+ }
1802
+ decodeTimestamp -= baseDecodeTimestamp;
1803
+ presentationTimestamp -= baseDecodeTimestamp;
1804
+ }
1805
+ if (decodeTimestamp < track.lastDecodeTimestamp) {
1806
+ throw new Error(
1807
+ `Timestamps must be monotonically increasing (DTS went from ${track.lastDecodeTimestamp * 1e6} to ${decodeTimestamp * 1e6}).`
1808
+ );
1809
+ }
1810
+ track.lastDecodeTimestamp = decodeTimestamp;
1811
+ return { presentationTimestamp, decodeTimestamp };
1812
+ };
1813
+ _finalizeCurrentChunk = /* @__PURE__ */ new WeakSet();
1814
+ finalizeCurrentChunk_fn = function(track) {
1815
+ if (__privateGet(this, _options).fastStart === "fragmented") {
1816
+ throw new Error("Can't finalize individual chunks if 'fastStart' is set to 'fragmented'.");
1817
+ }
1818
+ if (!track.currentChunk)
1819
+ return;
1820
+ track.finalizedChunks.push(track.currentChunk);
1821
+ __privateGet(this, _finalizedChunks).push(track.currentChunk);
1822
+ if (track.compactlyCodedChunkTable.length === 0 || last(track.compactlyCodedChunkTable).samplesPerChunk !== track.currentChunk.samples.length) {
1823
+ track.compactlyCodedChunkTable.push({
1824
+ firstChunk: track.finalizedChunks.length,
1825
+ // 1-indexed
1826
+ samplesPerChunk: track.currentChunk.samples.length
1827
+ });
1828
+ }
1829
+ if (__privateGet(this, _options).fastStart === "in-memory") {
1830
+ track.currentChunk.offset = 0;
1831
+ return;
1832
+ }
1833
+ track.currentChunk.offset = __privateGet(this, _writer).pos;
1834
+ for (let sample of track.currentChunk.samples) {
1835
+ __privateGet(this, _writer).write(sample.data);
1836
+ sample.data = null;
1837
+ }
1838
+ __privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
1839
+ };
1840
+ _finalizeFragment = /* @__PURE__ */ new WeakSet();
1841
+ finalizeFragment_fn = function(flushStreamingWriter = true) {
1842
+ if (__privateGet(this, _options).fastStart !== "fragmented") {
1843
+ throw new Error("Can't finalize a fragment unless 'fastStart' is set to 'fragmented'.");
1844
+ }
1845
+ let tracks = [__privateGet(this, _videoTrack), __privateGet(this, _audioTrack)].filter((track) => track && track.currentChunk);
1846
+ if (tracks.length === 0)
1847
+ return;
1848
+ let fragmentNumber = __privateWrapper(this, _nextFragmentNumber)._++;
1849
+ if (fragmentNumber === 1) {
1850
+ let movieBox = moov(tracks, __privateGet(this, _creationTime), true);
1851
+ __privateGet(this, _writer).writeBox(movieBox);
1852
+ }
1853
+ let moofOffset = __privateGet(this, _writer).pos;
1854
+ let moofBox = moof(fragmentNumber, tracks);
1855
+ __privateGet(this, _writer).writeBox(moofBox);
1856
+ {
1857
+ let mdatBox = mdat(false);
1858
+ let totalTrackSampleSize = 0;
1859
+ for (let track of tracks) {
1860
+ for (let sample of track.currentChunk.samples) {
1861
+ totalTrackSampleSize += sample.size;
1862
+ }
1863
+ }
1864
+ let mdatSize = __privateGet(this, _writer).measureBox(mdatBox) + totalTrackSampleSize;
1865
+ if (mdatSize >= 2 ** 32) {
1866
+ mdatBox.largeSize = true;
1867
+ mdatSize = __privateGet(this, _writer).measureBox(mdatBox) + totalTrackSampleSize;
1868
+ }
1869
+ mdatBox.size = mdatSize;
1870
+ __privateGet(this, _writer).writeBox(mdatBox);
1871
+ }
1872
+ for (let track of tracks) {
1873
+ track.currentChunk.offset = __privateGet(this, _writer).pos;
1874
+ track.currentChunk.moofOffset = moofOffset;
1875
+ for (let sample of track.currentChunk.samples) {
1876
+ __privateGet(this, _writer).write(sample.data);
1877
+ sample.data = null;
1878
+ }
1879
+ }
1880
+ let endPos = __privateGet(this, _writer).pos;
1881
+ __privateGet(this, _writer).seek(__privateGet(this, _writer).offsets.get(moofBox));
1882
+ let newMoofBox = moof(fragmentNumber, tracks);
1883
+ __privateGet(this, _writer).writeBox(newMoofBox);
1884
+ __privateGet(this, _writer).seek(endPos);
1885
+ for (let track of tracks) {
1886
+ track.finalizedChunks.push(track.currentChunk);
1887
+ __privateGet(this, _finalizedChunks).push(track.currentChunk);
1888
+ track.currentChunk = null;
1889
+ }
1890
+ if (flushStreamingWriter) {
1891
+ __privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
1892
+ }
1893
+ };
1894
+ _maybeFlushStreamingTargetWriter = /* @__PURE__ */ new WeakSet();
1895
+ maybeFlushStreamingTargetWriter_fn = function() {
1896
+ if (__privateGet(this, _writer) instanceof StreamTargetWriter) {
1897
+ __privateGet(this, _writer).flush();
1898
+ }
1899
+ };
1900
+ _ensureNotFinalized = /* @__PURE__ */ new WeakSet();
1901
+ ensureNotFinalized_fn = function() {
1902
+ if (__privateGet(this, _finalized)) {
1903
+ throw new Error("Cannot add new video or audio chunks after the file has been finalized.");
1904
+ }
1905
+ };
1906
+
1907
+ // src/mp4Mux.ts
1908
+ function createMp4Muxer(options) {
1909
+ const target = new ArrayBufferTarget();
1910
+ const muxer = new Muxer({
1911
+ target,
1912
+ video: {
1913
+ codec: "avc",
1914
+ width: options.width,
1915
+ height: options.height
1916
+ },
1917
+ // Only declare the audio track when requested so the video-only
1918
+ // configuration stays byte-identical to the historical output.
1919
+ ...options.audio ? {
1920
+ audio: {
1921
+ codec: "aac",
1922
+ numberOfChannels: options.audio.numberOfChannels,
1923
+ sampleRate: options.audio.sampleRate
1924
+ }
1925
+ } : {},
1926
+ fastStart: "in-memory"
1927
+ });
1928
+ return {
1929
+ hasAudioTrack: options.audio !== void 0,
1930
+ addVideoChunk(chunk, meta) {
1931
+ muxer.addVideoChunk(chunk, meta);
1932
+ },
1933
+ addVideoChunkRaw(data, type, timestampMicros, durationMicros, meta) {
1934
+ muxer.addVideoChunkRaw(data, type, timestampMicros, durationMicros, meta);
1935
+ },
1936
+ addAudioChunk(chunk, meta) {
1937
+ muxer.addAudioChunk(chunk, meta);
1938
+ },
1939
+ addAudioChunkRaw(data, type, timestampMicros, durationMicros, meta) {
1940
+ muxer.addAudioChunkRaw(data, type, timestampMicros, durationMicros, meta);
1941
+ },
1942
+ finalize() {
1943
+ muxer.finalize();
1944
+ return target.buffer;
1945
+ }
1946
+ };
1947
+ }
1948
+
1949
+ export {
1950
+ createMp4Muxer
1951
+ };