@svta/cml-iso-bmff 0.23.2 → 1.0.0-alpha.2

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.
package/dist/index.js CHANGED
@@ -1,6 +1,17 @@
1
- import { UTF_8, decodeText } from "@svta/cml-utils";
1
+ import { UTF_8, decodeText, encodeText } from "@svta/cml-utils";
2
2
 
3
- //#region src/CONTAINERS.ts
3
+ //#region src/utils/createWriterConfig.ts
4
+ function createWriterConfig(config) {
5
+ return { writers: config?.writers ?? {} };
6
+ }
7
+
8
+ //#endregion
9
+ //#region src/utils/CONTAINERS.ts
10
+ /**
11
+ * List of container box types
12
+ *
13
+ * @public
14
+ */
4
15
  const CONTAINERS = [
5
16
  "dinf",
6
17
  "edts",
@@ -28,74 +39,1740 @@ const CONTAINERS = [
28
39
  ];
29
40
 
30
41
  //#endregion
31
- //#region src/fields/DATA.ts
42
+ //#region src/utils/isContainer.ts
43
+ /**
44
+ * Check if a box is a container
45
+ *
46
+ * @param box - The box to check
47
+ *
48
+ * @returns `true` if the box is a container, `false` otherwise
49
+ *
50
+ * @public
51
+ */
52
+ function isContainer(box) {
53
+ return "boxes" in box || CONTAINERS.includes(box.type);
54
+ }
55
+
56
+ //#endregion
57
+ //#region src/fields/TEMPLATE.ts
58
+ /**
59
+ * The template field type
60
+ *
61
+ * @public
62
+ */
63
+ const TEMPLATE = "template";
64
+
65
+ //#endregion
66
+ //#region src/fields/UINT.ts
67
+ /**
68
+ * The unsigned integer field type
69
+ *
70
+ * @public
71
+ */
72
+ const UINT = "uint";
73
+
74
+ //#endregion
75
+ //#region src/IsoBoxWriteView.ts
76
+ /**
77
+ * A view for writing ISO BMFF data.
78
+ *
79
+ * @public
80
+ */
81
+ var IsoBoxWriteView = class {
82
+ /**
83
+ * Constructs a new IsoBoxWriteView.
84
+ *
85
+ * @param size - The size of the data view.
86
+ */
87
+ constructor(type, size) {
88
+ this.writeUint = (value, size$1) => {
89
+ const { dataView, cursor } = this;
90
+ switch (size$1) {
91
+ case 1:
92
+ dataView.setUint8(cursor, value);
93
+ break;
94
+ case 2:
95
+ dataView.setUint16(cursor, value);
96
+ break;
97
+ case 3: {
98
+ const s1 = (value & 16776960) >> 8;
99
+ const s2 = value & 255;
100
+ dataView.setUint16(cursor, s1);
101
+ dataView.setUint8(cursor + 2, s2);
102
+ break;
103
+ }
104
+ case 4:
105
+ dataView.setUint32(cursor, value);
106
+ break;
107
+ case 8: {
108
+ const s1 = Math.floor(value / Math.pow(2, 32));
109
+ const s2 = value - s1 * Math.pow(2, 32);
110
+ dataView.setUint32(cursor, s1);
111
+ dataView.setUint32(cursor + 4, s2);
112
+ break;
113
+ }
114
+ }
115
+ this.cursor += size$1;
116
+ };
117
+ this.writeInt = (value, size$1) => {
118
+ const { dataView, cursor } = this;
119
+ switch (size$1) {
120
+ case 1:
121
+ dataView.setInt8(cursor, value);
122
+ break;
123
+ case 2:
124
+ dataView.setInt16(cursor, value);
125
+ break;
126
+ case 4:
127
+ dataView.setInt32(cursor, value);
128
+ break;
129
+ case 8:
130
+ const s1 = Math.floor(value / Math.pow(2, 32));
131
+ const s2 = value - s1 * Math.pow(2, 32);
132
+ dataView.setUint32(cursor, s1);
133
+ dataView.setUint32(cursor + 4, s2);
134
+ break;
135
+ }
136
+ this.cursor += size$1;
137
+ };
138
+ this.writeString = (value) => {
139
+ for (let c = 0, len = value.length; c < len; c++) this.writeUint(value.charCodeAt(c), 1);
140
+ };
141
+ this.writeTerminatedString = (value) => {
142
+ if (value.length === 0) return;
143
+ for (let c = 0, len = value.length; c < len; c++) this.writeUint(value.charCodeAt(c), 1);
144
+ this.writeUint(0, 1);
145
+ };
146
+ this.writeUtf8TerminatedString = (value) => {
147
+ const bytes = encodeText(value);
148
+ new Uint8Array(this.dataView.buffer).set(bytes, this.cursor);
149
+ this.cursor += bytes.length;
150
+ this.writeUint(0, 1);
151
+ };
152
+ this.writeBytes = (data) => {
153
+ new Uint8Array(this.dataView.buffer).set(data, this.cursor);
154
+ this.cursor += data.length;
155
+ };
156
+ this.writeArray = (data, type$1, size$1, length) => {
157
+ const write = type$1 === UINT ? this.writeUint : type$1 === TEMPLATE ? this.writeTemplate : this.writeInt;
158
+ for (let i = 0; i < length; i++) write(data[i] ?? 0, size$1);
159
+ };
160
+ this.writeTemplate = (value, size$1) => {
161
+ const shift = size$1 === 4 ? 16 : 8;
162
+ const fixedPoint = Math.round(value * Math.pow(2, shift));
163
+ this.writeUint(fixedPoint, size$1);
164
+ };
165
+ this.writeBoxHeader = (type$1, size$1) => {
166
+ if (size$1 > 4294967295) {
167
+ this.writeUint(1, 4);
168
+ this.writeString(type$1);
169
+ this.writeUint(size$1, 8);
170
+ } else {
171
+ this.writeUint(size$1, 4);
172
+ this.writeString(type$1);
173
+ }
174
+ };
175
+ this.dataView = new DataView(new ArrayBuffer(size));
176
+ this.cursor = 0;
177
+ this.writeBoxHeader(type, size);
178
+ }
179
+ /**
180
+ * The buffer of the data view.
181
+ *
182
+ * @returns The buffer of the data view.
183
+ */
184
+ get buffer() {
185
+ return this.dataView.buffer;
186
+ }
187
+ /**
188
+ * The length of the data view.
189
+ *
190
+ * @returns The length of the data view.
191
+ */
192
+ get byteLength() {
193
+ return this.dataView.byteLength;
194
+ }
195
+ /**
196
+ * The offset of the data view.
197
+ *
198
+ * @returns The offset of the data view.
199
+ */
200
+ get byteOffset() {
201
+ return this.dataView.byteOffset;
202
+ }
203
+ /**
204
+ * Writes a full box header to the data view.
205
+ *
206
+ * @param version - The version of the full box.
207
+ * @param flags - The flags of the full box.
208
+ */
209
+ writeFullBox(version, flags) {
210
+ this.writeUint(version, 1);
211
+ this.writeUint(flags, 3);
212
+ }
213
+ };
214
+
215
+ //#endregion
216
+ //#region src/writers/writeContainerBox.ts
217
+ /**
218
+ * Write a ContainerBox to an IsoBmffWriter.
219
+ *
220
+ * This function writes a container box with its child boxes. Child boxes are
221
+ * extracted from the container box's `boxes` array and encoded using their `view` property.
222
+ *
223
+ * @param box - The ContainerBox to write
224
+ *
225
+ * @returns An IsoBmffWriter containing the encoded box
226
+ */
227
+ function writeContainerBox(box, config) {
228
+ const children = [];
229
+ const headerSize = 8;
230
+ let childrenSize = 0;
231
+ for (const childBox of box.boxes) {
232
+ const view = writeIsoBox(childBox, config);
233
+ childrenSize += view.byteLength;
234
+ children.push(view);
235
+ }
236
+ const totalSize = headerSize + childrenSize;
237
+ const writer = new IsoBoxWriteView(box.type, totalSize);
238
+ for (const child of children) writer.writeBytes(child);
239
+ return writer;
240
+ }
241
+
242
+ //#endregion
243
+ //#region src/writers/writeBox.ts
244
+ /**
245
+ * Write a box to a Uint8Array.
246
+ *
247
+ * @param box - The box to write
248
+ * @param writers - The writers to use
249
+ * @returns The written box
250
+ *
251
+ * @internal
252
+ */
253
+ function writeBox(box, config) {
254
+ let view = null;
255
+ if ("type" in box) {
256
+ const { type } = box;
257
+ if (type !== "" && isContainer(box)) view = writeContainerBox(box, config);
258
+ else {
259
+ const writer = config.writers[type];
260
+ if (writer) view = writer(box, config);
261
+ else if ("view" in box) view = box.view;
262
+ }
263
+ if (!view) throw new Error(`No writer found for box type: ${type}`);
264
+ }
265
+ if ("buffer" in box) view = box;
266
+ if (!view) throw new Error("Invalid box");
267
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
268
+ }
269
+
270
+ //#endregion
271
+ //#region src/writeIsoBox.ts
272
+ /**
273
+ * Write an ISO box to a Uint8Array.
274
+ *
275
+ * @param box - The box to write
276
+ * @param writers - The writers to use
277
+ * @returns The written box
278
+ *
279
+ * @public
280
+ */
281
+ function writeIsoBox(box, config) {
282
+ return writeBox(box, createWriterConfig(config));
283
+ }
284
+
285
+ //#endregion
286
+ //#region src/IsoBoxReadableStream.ts
287
+ /**
288
+ * A readable stream of ISO BMFF boxes as Uint8Arrays.
289
+ *
290
+ * @public
291
+ */
292
+ var IsoBoxReadableStream = class extends ReadableStream {
293
+ /**
294
+ * Constructs a new IsoBoxReadableStream.
295
+ *
296
+ * @param boxes - The boxes to stream.
297
+ * @param config - The configuration for the stream.
298
+ */
299
+ constructor(boxes, config = {}) {
300
+ const iterator = boxes[Symbol.iterator]();
301
+ const cfg = createWriterConfig(config);
302
+ function pull(controller) {
303
+ const desiredSize = controller.desiredSize ?? 0;
304
+ for (let i = 0; i < desiredSize; i++) {
305
+ const { value, done } = iterator.next();
306
+ if (done) controller.close();
307
+ else controller.enqueue(writeIsoBox(value, cfg));
308
+ }
309
+ }
310
+ super({
311
+ start: pull,
312
+ pull
313
+ });
314
+ }
315
+ };
316
+
317
+ //#endregion
318
+ //#region src/createIsoBoxReadableStream.ts
319
+ /**
320
+ * Creates a ReadableStream of ISO BMFF boxes as Uint8Arrays.
321
+ *
322
+ * @param boxes - The boxes to stream.
323
+ * @param config - The configuration for the stream.
324
+ *
325
+ * @returns A new IsoBoxReadableStream.
326
+ *
327
+ * @example
328
+ * {@includeCode ../test/createIsoBoxReadableStream.test.ts#example}
329
+ *
330
+ * @public
331
+ */
332
+ function createIsoBoxReadableStream(boxes, config = {}) {
333
+ return new IsoBoxReadableStream(boxes, config);
334
+ }
335
+
336
+ //#endregion
337
+ //#region src/readers/readArdi.ts
338
+ /**
339
+ * Parse a AudioRenderingIndicationBox from an IsoView
340
+ *
341
+ * @param view - The IsoView to read data from
342
+ *
343
+ * @returns A parsed AudioRenderingIndicationBox
344
+ *
345
+ * @public
346
+ */
347
+ function readArdi(view) {
348
+ return {
349
+ type: "ardi",
350
+ ...view.readFullBox(),
351
+ audioRenderingIndication: view.readUint(1)
352
+ };
353
+ }
354
+
355
+ //#endregion
356
+ //#region src/readers/readAvc1.ts
357
+ /**
358
+ * Parse a VisualSampleEntryBox from an IsoView
359
+ *
360
+ * @param view - The IsoView to read data from
361
+ *
362
+ * @returns A parsed VisualSampleEntryBox
363
+ *
364
+ * @public
365
+ */
366
+ function readAvc1(view) {
367
+ const { readArray, readUint: readUint$1, readInt: readInt$1, readTemplate: readTemplate$1, readData: readData$1 } = view;
368
+ return {
369
+ type: "avc1",
370
+ reserved1: readArray(UINT, 1, 6),
371
+ dataReferenceIndex: readUint$1(2),
372
+ preDefined1: readUint$1(2),
373
+ reserved2: readUint$1(2),
374
+ preDefined2: readArray(UINT, 4, 3),
375
+ width: readUint$1(2),
376
+ height: readUint$1(2),
377
+ horizresolution: readTemplate$1(4),
378
+ vertresolution: readTemplate$1(4),
379
+ reserved3: readUint$1(4),
380
+ frameCount: readUint$1(2),
381
+ compressorName: readArray(UINT, 1, 32),
382
+ depth: readUint$1(2),
383
+ preDefined3: readInt$1(2),
384
+ config: readData$1(-1)
385
+ };
386
+ }
387
+
388
+ //#endregion
389
+ //#region src/readers/readAvc2.ts
390
+ /**
391
+ * Parse a VisualSampleEntryBox from an IsoView
392
+ *
393
+ * @param view - The IsoView to read data from
394
+ *
395
+ * @returns A parsed VisualSampleEntryBox
396
+ *
397
+ * @public
398
+ */
399
+ function readAvc2(view) {
400
+ return {
401
+ ...readAvc1(view),
402
+ type: "avc2"
403
+ };
404
+ }
405
+
406
+ //#endregion
407
+ //#region src/readers/readAvc3.ts
408
+ /**
409
+ * Parse a VisualSampleEntryBox from an IsoView
410
+ *
411
+ * @param view - The IsoView to read data from
412
+ *
413
+ * @returns A parsed VisualSampleEntryBox
414
+ *
415
+ * @public
416
+ */
417
+ function readAvc3(view) {
418
+ return {
419
+ ...readAvc1(view),
420
+ type: "avc3"
421
+ };
422
+ }
423
+
424
+ //#endregion
425
+ //#region src/readers/readAvc4.ts
426
+ /**
427
+ * Parse a VisualSampleEntryBox from an IsoView
428
+ *
429
+ * @param view - The IsoView to read data from
430
+ *
431
+ * @returns A parsed VisualSampleEntryBox
432
+ *
433
+ * @public
434
+ */
435
+ function readAvc4(view) {
436
+ return {
437
+ ...readAvc1(view),
438
+ type: "avc4"
439
+ };
440
+ }
441
+
442
+ //#endregion
443
+ //#region src/readers/readCtts.ts
444
+ /**
445
+ * Parse a CompositionTimeToSampleBox from an IsoView
446
+ *
447
+ * @param view - The IsoView to read data from
448
+ *
449
+ * @returns A parsed CompositionTimeToSampleBox
450
+ *
451
+ * @public
452
+ */
453
+ function readCtts(view) {
454
+ const { version, flags } = view.readFullBox();
455
+ const read = version === 1 ? view.readInt : view.readUint;
456
+ const entryCount = view.readUint(4);
457
+ return {
458
+ type: "ctts",
459
+ version,
460
+ flags,
461
+ entryCount,
462
+ entries: view.readEntries(entryCount, () => ({
463
+ sampleCount: view.readUint(4),
464
+ sampleOffset: read(4)
465
+ }))
466
+ };
467
+ }
468
+
469
+ //#endregion
470
+ //#region src/readers/readDref.ts
471
+ /**
472
+ * Parse a DataReferenceBox from an IsoView
473
+ *
474
+ * @param view - The IsoView to read data from
475
+ *
476
+ * @returns A parsed DataReferenceBox
477
+ *
478
+ * @public
479
+ */
480
+ function readDref(view) {
481
+ const { version, flags } = view.readFullBox();
482
+ const entryCount = view.readUint(4);
483
+ return {
484
+ type: "dref",
485
+ version,
486
+ flags,
487
+ entryCount,
488
+ entries: view.readBoxes(entryCount)
489
+ };
490
+ }
491
+
492
+ //#endregion
493
+ //#region src/readers/readElng.ts
494
+ /**
495
+ * Parse a ExtendedLanguageBox from an IsoView
496
+ *
497
+ * @param view - The IsoView to read data from
498
+ *
499
+ * @returns A parsed ExtendedLanguageBox
500
+ *
501
+ * @public
502
+ */
503
+ function readElng(view) {
504
+ return {
505
+ type: "elng",
506
+ ...view.readFullBox(),
507
+ extendedLanguage: view.readUtf8(-1)
508
+ };
509
+ }
510
+
511
+ //#endregion
512
+ //#region src/readers/readElst.ts
513
+ /**
514
+ * Parse a Box from an IsoView
515
+ *
516
+ * @param view - The IsoView to read data from
517
+ *
518
+ * @returns A parsed Box
519
+ *
520
+ * @public
521
+ */
522
+ function readElst(view) {
523
+ const { version, flags } = view.readFullBox();
524
+ const size = version === 1 ? 8 : 4;
525
+ const entryCount = view.readUint(4);
526
+ return {
527
+ type: "elst",
528
+ version,
529
+ flags,
530
+ entryCount,
531
+ entries: view.readEntries(entryCount, () => ({
532
+ segmentDuration: view.readUint(size),
533
+ mediaTime: view.readInt(size),
534
+ mediaRateInteger: view.readInt(2),
535
+ mediaRateFraction: view.readInt(2)
536
+ }))
537
+ };
538
+ }
539
+
540
+ //#endregion
541
+ //#region src/readers/readEmsg.ts
542
+ /**
543
+ * Parse an EventMessageBox from an IsoView
544
+ *
545
+ * @param view - The IsoView to read data from
546
+ *
547
+ * @returns A parsed EventMessageBox
548
+ *
549
+ * @public
550
+ */
551
+ function readEmsg(view) {
552
+ const { readUint: readUint$1, readString: readString$1, readData: readData$1 } = view;
553
+ const result = {
554
+ type: "emsg",
555
+ ...view.readFullBox()
556
+ };
557
+ if (result.version == 1) {
558
+ result.timescale = readUint$1(4);
559
+ result.presentationTime = readUint$1(8);
560
+ result.eventDuration = readUint$1(4);
561
+ result.id = readUint$1(4);
562
+ result.schemeIdUri = readString$1(-1);
563
+ result.value = readString$1(-1);
564
+ } else {
565
+ result.schemeIdUri = readString$1(-1);
566
+ result.value = readString$1(-1);
567
+ result.timescale = readUint$1(4);
568
+ result.presentationTimeDelta = readUint$1(4);
569
+ result.eventDuration = readUint$1(4);
570
+ result.id = readUint$1(4);
571
+ }
572
+ result.messageData = readData$1(-1);
573
+ return result;
574
+ }
575
+
576
+ //#endregion
577
+ //#region src/readers/readMp4a.ts
578
+ /**
579
+ * Parse an AudioSampleEntry from an IsoView
580
+ *
581
+ * @param view - The IsoView to read data from
582
+ *
583
+ * @returns A parsed AudioSampleEntry
584
+ *
585
+ * @public
586
+ */
587
+ function readMp4a(view) {
588
+ const { readArray, readUint: readUint$1, readTemplate: readTemplate$1, readData: readData$1 } = view;
589
+ return {
590
+ type: "mp4a",
591
+ reserved1: readArray(UINT, 1, 6),
592
+ dataReferenceIndex: readUint$1(2),
593
+ reserved2: readArray(UINT, 4, 2),
594
+ channelcount: readUint$1(2),
595
+ samplesize: readUint$1(2),
596
+ preDefined: readUint$1(2),
597
+ reserved3: readUint$1(2),
598
+ samplerate: readTemplate$1(4),
599
+ esds: readData$1(-1)
600
+ };
601
+ }
602
+
603
+ //#endregion
604
+ //#region src/readers/readEnca.ts
605
+ /**
606
+ * Parse an AudioSampleEntry from an IsoView
607
+ *
608
+ * @param view - The IsoView to read data from
609
+ *
610
+ * @returns A parsed AudioSampleEntry
611
+ *
612
+ * @public
613
+ */
614
+ function readEnca(view) {
615
+ return {
616
+ ...readMp4a(view),
617
+ type: "enca"
618
+ };
619
+ }
620
+
621
+ //#endregion
622
+ //#region src/readers/readEncv.ts
623
+ /**
624
+ * Parse a VisualSampleEntryBox from an IsoView
625
+ *
626
+ * @param view - The IsoView to read data from
627
+ *
628
+ * @returns A parsed VisualSampleEntryBox
629
+ *
630
+ * @public
631
+ */
632
+ function readEncv(view) {
633
+ return {
634
+ ...readAvc1(view),
635
+ type: "encv"
636
+ };
637
+ }
638
+
639
+ //#endregion
640
+ //#region src/readers/readFree.ts
641
+ /**
642
+ * Parse a Box from an IsoView
643
+ *
644
+ * @param view - The IsoView to read data from
645
+ *
646
+ * @returns A parsed Box
647
+ *
648
+ * @public
649
+ */
650
+ function readFree(view) {
651
+ return {
652
+ type: "free",
653
+ data: view.readData(-1)
654
+ };
655
+ }
656
+
657
+ //#endregion
658
+ //#region src/readers/readFrma.ts
659
+ /**
660
+ * Parse an OriginalFormatBox from an IsoView
661
+ *
662
+ * @param view - The IsoView to read data from
663
+ *
664
+ * @returns A parsed OriginalFormatBox
665
+ *
666
+ * @public
667
+ */
668
+ function readFrma(view) {
669
+ return {
670
+ type: "frma",
671
+ dataFormat: view.readUint(4)
672
+ };
673
+ }
674
+
675
+ //#endregion
676
+ //#region src/fields/STRING.ts
677
+ /**
678
+ * The string field type
679
+ *
680
+ * @public
681
+ */
682
+ const STRING = "string";
683
+
684
+ //#endregion
685
+ //#region src/readers/readFtyp.ts
686
+ /**
687
+ * Parse a FileTypeBox from an IsoView
688
+ *
689
+ * @param view - The IsoView to read data from
690
+ *
691
+ * @returns A parsed FileTypeBox
692
+ *
693
+ * @public
694
+ */
695
+ function readFtyp(view) {
696
+ const size = 4;
697
+ const majorBrand = view.readString(4);
698
+ const minorVersion = view.readUint(4);
699
+ const length = view.bytesRemaining / size;
700
+ return {
701
+ type: "ftyp",
702
+ majorBrand,
703
+ minorVersion,
704
+ compatibleBrands: view.readArray(STRING, size, length)
705
+ };
706
+ }
707
+
708
+ //#endregion
709
+ //#region src/readers/readHdlr.ts
710
+ /**
711
+ * Parse a HandlerReferenceBox from an IsoView
712
+ *
713
+ * @param view - The IsoView to read data from
714
+ *
715
+ * @returns A parsed HandlerReferenceBox
716
+ *
717
+ * @public
718
+ */
719
+ function readHdlr(view) {
720
+ return {
721
+ type: "hdlr",
722
+ ...view.readFullBox(),
723
+ preDefined: view.readUint(4),
724
+ handlerType: view.readString(4),
725
+ reserved: view.readArray(UINT, 4, 3),
726
+ name: view.readString(-1)
727
+ };
728
+ }
729
+
730
+ //#endregion
731
+ //#region src/readers/readHev1.ts
732
+ /**
733
+ * Parse a VisualSampleEntryBox from an IsoView
734
+ *
735
+ * @param view - The IsoView to read data from
736
+ *
737
+ * @returns A parsed VisualSampleEntryBox
738
+ *
739
+ * @public
740
+ */
741
+ function readHev1(view) {
742
+ return {
743
+ ...readAvc1(view),
744
+ type: "hev1"
745
+ };
746
+ }
747
+
748
+ //#endregion
749
+ //#region src/readers/readHvc1.ts
750
+ /**
751
+ * Parse a VisualSampleEntryBox from an IsoView
752
+ *
753
+ * @param view - The IsoView to read data from
754
+ *
755
+ * @returns A parsed VisualSampleEntryBox
756
+ *
757
+ * @public
758
+ */
759
+ function readHvc1(view) {
760
+ return {
761
+ ...readAvc1(view),
762
+ type: "hvc1"
763
+ };
764
+ }
765
+
766
+ //#endregion
767
+ //#region src/readers/readIden.ts
768
+ /**
769
+ * Parse a WebVTTCueIdBox from an IsoView
770
+ *
771
+ * @param view - The IsoView to read data from
772
+ *
773
+ * @returns A parsed WebVTTCueIdBox
774
+ *
775
+ * @public
776
+ */
777
+ function readIden(view) {
778
+ return {
779
+ type: "iden",
780
+ cueId: view.readUtf8(-1)
781
+ };
782
+ }
783
+
784
+ //#endregion
785
+ //#region src/readers/readImda.ts
786
+ /**
787
+ * Parse a IdentifiedMediaDataBox from an IsoView
788
+ *
789
+ * @param view - The IsoView to read data from
790
+ *
791
+ * @returns A parsed IdentifiedMediaDataBox
792
+ *
793
+ * @public
794
+ */
795
+ function readImda(view) {
796
+ return {
797
+ type: "imda",
798
+ imdaIdentifier: view.readUint(4),
799
+ data: view.readData(-1)
800
+ };
801
+ }
802
+
803
+ //#endregion
804
+ //#region src/readers/readKind.ts
805
+ /**
806
+ * Parse a TrackKinBox from an IsoView
807
+ *
808
+ * @param view - The IsoView to read data from
809
+ *
810
+ * @returns A parsed TrackKindBox
811
+ *
812
+ * @public
813
+ */
814
+ function readKind(view) {
815
+ return {
816
+ type: "kind",
817
+ ...view.readFullBox(),
818
+ schemeUri: view.readUtf8(-1),
819
+ value: view.readUtf8(-1)
820
+ };
821
+ }
822
+
823
+ //#endregion
824
+ //#region src/readers/readLabl.ts
825
+ /**
826
+ * Parse a LabelBox from an IsoView
827
+ *
828
+ * @param view - The IsoView to read data from
829
+ *
830
+ * @returns A parsed LabelBox
831
+ *
832
+ * @public
833
+ */
834
+ function readLabl(view) {
835
+ const { version, flags } = view.readFullBox();
836
+ return {
837
+ type: "labl",
838
+ version,
839
+ flags,
840
+ isGroupLabel: (flags & 1) !== 0,
841
+ labelId: view.readUint(2),
842
+ language: view.readUtf8(-1),
843
+ label: view.readUtf8(-1)
844
+ };
845
+ }
846
+
847
+ //#endregion
848
+ //#region src/readers/readMdat.ts
849
+ /**
850
+ * Parse a MediaDataBox from an IsoView
851
+ *
852
+ * @param view - The IsoView to read data from
853
+ *
854
+ * @returns A parsed MediaDataBox
855
+ *
856
+ * @public
857
+ */
858
+ function readMdat(view) {
859
+ return {
860
+ type: "mdat",
861
+ data: view.readData(-1)
862
+ };
863
+ }
864
+
865
+ //#endregion
866
+ //#region src/readers/readMdhd.ts
867
+ /**
868
+ * Parse a MediaHeaderBox from an IsoView
869
+ *
870
+ * @param view - The IsoView to read data from
871
+ *
872
+ * @returns A parsed MediaHeaderBox
873
+ *
874
+ * @public
875
+ */
876
+ function readMdhd(view) {
877
+ const { version, flags } = view.readFullBox();
878
+ const creationTime = view.readUint(version == 1 ? 8 : 4);
879
+ const modificationTime = view.readUint(version == 1 ? 8 : 4);
880
+ const timescale = view.readUint(4);
881
+ const duration = view.readUint(version == 1 ? 8 : 4);
882
+ const lang = view.readUint(2);
883
+ return {
884
+ type: "mdhd",
885
+ version,
886
+ flags,
887
+ creationTime,
888
+ modificationTime,
889
+ timescale,
890
+ duration,
891
+ language: String.fromCharCode((lang >> 10 & 31) + 96, (lang >> 5 & 31) + 96, (lang & 31) + 96),
892
+ preDefined: view.readUint(2)
893
+ };
894
+ }
895
+
896
+ //#endregion
897
+ //#region src/readers/readMehd.ts
898
+ /**
899
+ * Parse a MovieExtendsHeaderBox from an IsoView
900
+ *
901
+ * @param view - The IsoView to read data from
902
+ *
903
+ * @returns A parsed MovieExtendsHeaderBox
904
+ *
905
+ * @public
906
+ */
907
+ function readMehd(view) {
908
+ const { version, flags } = view.readFullBox();
909
+ return {
910
+ type: "mehd",
911
+ version,
912
+ flags,
913
+ fragmentDuration: view.readUint(version === 1 ? 8 : 4)
914
+ };
915
+ }
916
+
917
+ //#endregion
918
+ //#region src/readers/readMeta.ts
919
+ /**
920
+ * Parse a MetaBox from an IsoView
921
+ *
922
+ * @param view - The IsoView to read data from
923
+ *
924
+ * @returns A parsed MetaBox
925
+ *
926
+ * @public
927
+ */
928
+ function readMeta(view) {
929
+ return {
930
+ type: "meta",
931
+ ...view.readFullBox(),
932
+ boxes: view.readBoxes()
933
+ };
934
+ }
935
+
936
+ //#endregion
937
+ //#region src/readers/readMfhd.ts
938
+ /**
939
+ * Parse a MovieFragmentHeaderBox from an IsoView
940
+ *
941
+ * @param view - The IsoView to read data from
942
+ *
943
+ * @returns A parsed MovieFragmentHeaderBox
944
+ *
945
+ * @public
946
+ */
947
+ function readMfhd(view) {
948
+ return {
949
+ type: "mfhd",
950
+ ...view.readFullBox(),
951
+ sequenceNumber: view.readUint(4)
952
+ };
953
+ }
954
+
955
+ //#endregion
956
+ //#region src/readers/readMfro.ts
957
+ /**
958
+ * Parse a MovieFragmentRandomAccessBox from an IsoView
959
+ *
960
+ * @param view - The IsoView to read data from
961
+ *
962
+ * @returns A parsed MovieFragmentRandomAccessBox
963
+ *
964
+ * @public
965
+ */
966
+ function readMfro(view) {
967
+ return {
968
+ type: "mfro",
969
+ ...view.readFullBox(),
970
+ mfraSize: view.readUint(4)
971
+ };
972
+ }
973
+
974
+ //#endregion
975
+ //#region src/readers/readMvhd.ts
976
+ /**
977
+ * Parse a Box from an IsoView
978
+ *
979
+ * @param view - The IsoView to read data from
980
+ *
981
+ * @returns A parsed Box
982
+ *
983
+ * @public
984
+ */
985
+ function readMvhd(view) {
986
+ const { readUint: readUint$1, readTemplate: readTemplate$1, readArray } = view;
987
+ const { version, flags } = view.readFullBox();
988
+ const size = version == 1 ? 8 : 4;
989
+ return {
990
+ type: "mvhd",
991
+ version,
992
+ flags,
993
+ creationTime: readUint$1(size),
994
+ modificationTime: readUint$1(size),
995
+ timescale: readUint$1(4),
996
+ duration: readUint$1(size),
997
+ rate: readTemplate$1(4),
998
+ volume: readTemplate$1(2),
999
+ reserved1: readUint$1(2),
1000
+ reserved2: readArray(UINT, 4, 2),
1001
+ matrix: readArray(TEMPLATE, 4, 9),
1002
+ preDefined: readArray(UINT, 4, 6),
1003
+ nextTrackId: readUint$1(4)
1004
+ };
1005
+ }
1006
+
1007
+ //#endregion
1008
+ //#region src/readers/readPayl.ts
1009
+ /**
1010
+ * Parse a WebVTTCuePayloadBox from an IsoView
1011
+ *
1012
+ * @param view - The IsoView to read data from
1013
+ *
1014
+ * @returns A parsed WebVTTCuePayloadBox
1015
+ *
1016
+ * @public
1017
+ */
1018
+ function readPayl(view) {
1019
+ return {
1020
+ type: "payl",
1021
+ cueText: view.readUtf8(-1)
1022
+ };
1023
+ }
1024
+
1025
+ //#endregion
1026
+ //#region src/readers/readPrft.ts
1027
+ /**
1028
+ * Parse a ProducerReferenceTimeBox from an IsoView
1029
+ *
1030
+ * @param view - The IsoView to read data from
1031
+ *
1032
+ * @returns A parsed ProducerReferenceTimeBox
1033
+ *
1034
+ * @public
1035
+ */
1036
+ function readPrft(view) {
1037
+ const { version, flags } = view.readFullBox();
1038
+ return {
1039
+ type: "prft",
1040
+ version,
1041
+ flags,
1042
+ referenceTrackId: view.readUint(4),
1043
+ ntpTimestampSec: view.readUint(4),
1044
+ ntpTimestampFrac: view.readUint(4),
1045
+ mediaTime: view.readUint(version === 1 ? 8 : 4)
1046
+ };
1047
+ }
1048
+
1049
+ //#endregion
1050
+ //#region src/readers/readPrsl.ts
1051
+ /**
1052
+ * Parse a PreselectionGroupBox from an IsoView
1053
+ *
1054
+ * @param view - The IsoView to read data from
1055
+ *
1056
+ * @returns A parsed PreselectionGroupBox
1057
+ *
1058
+ * @public
1059
+ */
1060
+ function readPrsl(view) {
1061
+ const { version, flags } = view.readFullBox();
1062
+ const groupId = view.readUint(4);
1063
+ const numEntitiesInGroup = view.readUint(4);
1064
+ return {
1065
+ type: "prsl",
1066
+ version,
1067
+ flags,
1068
+ groupId,
1069
+ numEntitiesInGroup,
1070
+ entities: view.readEntries(numEntitiesInGroup, () => ({ entityId: view.readUint(4) })),
1071
+ preselectionTag: flags & 4096 ? view.readUtf8(-1) : void 0,
1072
+ selectionPriority: flags & 8192 ? view.readUint(1) : void 0,
1073
+ interleavingTag: flags & 16384 ? view.readUtf8(-1) : void 0
1074
+ };
1075
+ }
1076
+
1077
+ //#endregion
1078
+ //#region src/readers/readPssh.ts
1079
+ /**
1080
+ * Parse a ProtectionSystemSpecificHeaderBox from an IsoView
1081
+ *
1082
+ * @param view - The IsoView to read data from
1083
+ *
1084
+ * @returns A parsed ProtectionSystemSpecificHeaderBox
1085
+ *
1086
+ * @public
1087
+ */
1088
+ function readPssh(view) {
1089
+ const { readUint: readUint$1, readArray } = view;
1090
+ const { version, flags } = view.readFullBox();
1091
+ const systemId = readArray(UINT, 1, 16);
1092
+ let kidCount = 0;
1093
+ let kid = [];
1094
+ if (version > 0) {
1095
+ kidCount = readUint$1(4);
1096
+ kid = readArray(UINT, 1, kidCount);
1097
+ }
1098
+ const dataSize = readUint$1(4);
1099
+ const data = readArray(UINT, 1, dataSize);
1100
+ return {
1101
+ type: "pssh",
1102
+ version,
1103
+ flags,
1104
+ systemId,
1105
+ kidCount,
1106
+ kid,
1107
+ dataSize,
1108
+ data
1109
+ };
1110
+ }
1111
+
1112
+ //#endregion
1113
+ //#region src/readers/readSchm.ts
1114
+ /**
1115
+ * Parse a SchemeTypeBox from an IsoView
1116
+ *
1117
+ * @param view - The IsoView to read data from
1118
+ *
1119
+ * @returns A parsed SchemeTypeBox
1120
+ *
1121
+ * @public
1122
+ */
1123
+ function readSchm(view) {
1124
+ const { version, flags } = view.readFullBox();
1125
+ return {
1126
+ type: "schm",
1127
+ version,
1128
+ flags,
1129
+ schemeType: view.readUint(4),
1130
+ schemeVersion: view.readUint(4),
1131
+ schemeUri: flags & 1 ? view.readString(-1) : void 0
1132
+ };
1133
+ }
1134
+
1135
+ //#endregion
1136
+ //#region src/readers/readSdtp.ts
1137
+ /**
1138
+ * Parse a SampleDependencyTypeBox from an IsoView
1139
+ *
1140
+ * @param view - The IsoView to read data from
1141
+ *
1142
+ * @returns A parsed SampleDependencyTypeBox
1143
+ *
1144
+ * @public
1145
+ */
1146
+ function readSdtp(view) {
1147
+ return {
1148
+ type: "sdtp",
1149
+ ...view.readFullBox(),
1150
+ sampleDependencyTable: view.readArray(UINT, 1, view.bytesRemaining)
1151
+ };
1152
+ }
1153
+
1154
+ //#endregion
1155
+ //#region src/readers/readSidx.ts
1156
+ /**
1157
+ * Parse a SegmentIndexBox from an IsoView
1158
+ *
1159
+ * @param view - The IsoView to read data from
1160
+ *
1161
+ * @returns A parsed SegmentIndexBox
1162
+ *
1163
+ * @public
1164
+ */
1165
+ function readSidx(view) {
1166
+ const { readUint: readUint$1 } = view;
1167
+ const { version, flags } = view.readFullBox();
1168
+ const size = version === 1 ? 8 : 4;
1169
+ const referenceId = readUint$1(4);
1170
+ const timescale = readUint$1(4);
1171
+ const earliestPresentationTime = readUint$1(size);
1172
+ const firstOffset = readUint$1(size);
1173
+ const reserved = readUint$1(2);
1174
+ const referenceCount = readUint$1(2);
1175
+ return {
1176
+ type: "sidx",
1177
+ version,
1178
+ flags,
1179
+ referenceId,
1180
+ timescale,
1181
+ earliestPresentationTime,
1182
+ firstOffset,
1183
+ reserved,
1184
+ references: view.readEntries(referenceCount, () => {
1185
+ const entry = {};
1186
+ entry.reference = readUint$1(4);
1187
+ entry.subsegmentDuration = readUint$1(4);
1188
+ entry.sap = readUint$1(4);
1189
+ entry.referenceType = entry.reference >> 31 & 1;
1190
+ entry.referencedSize = entry.reference & 2147483647;
1191
+ entry.startsWithSap = entry.sap >> 31 & 1;
1192
+ entry.sapType = entry.sap >> 28 & 7;
1193
+ entry.sapDeltaTime = entry.sap & 268435455;
1194
+ return entry;
1195
+ })
1196
+ };
1197
+ }
1198
+
1199
+ //#endregion
1200
+ //#region src/readers/readSkip.ts
1201
+ /**
1202
+ * Parse a FreeSpaceBox from an IsoView
1203
+ *
1204
+ * @param view - The IsoView to read data from
1205
+ *
1206
+ * @returns A parsed FreeSpaceBox
1207
+ *
1208
+ * @public
1209
+ */
1210
+ function readSkip(view) {
1211
+ return {
1212
+ ...readFree(view),
1213
+ type: "skip"
1214
+ };
1215
+ }
1216
+
1217
+ //#endregion
1218
+ //#region src/readers/readSmhd.ts
1219
+ /**
1220
+ * Parse a SoundMediaHeaderBox from an IsoView
1221
+ *
1222
+ * @param view - The IsoView to read data from
1223
+ *
1224
+ * @returns A parsed SoundMediaHeaderBox
1225
+ *
1226
+ * @public
1227
+ */
1228
+ function readSmhd(view) {
1229
+ return {
1230
+ type: "smhd",
1231
+ ...view.readFullBox(),
1232
+ balance: view.readUint(2),
1233
+ reserved: view.readUint(2)
1234
+ };
1235
+ }
1236
+
1237
+ //#endregion
1238
+ //#region src/readers/readSsix.ts
1239
+ /**
1240
+ * Parse a SubsegmentIndexBox from an IsoView
1241
+ *
1242
+ * @param view - The IsoView to read data from
1243
+ *
1244
+ * @returns A parsed SubsegmentIndexBox
1245
+ *
1246
+ * @public
1247
+ */
1248
+ function readSsix(view) {
1249
+ const { version, flags } = view.readFullBox();
1250
+ const subsegmentCount = view.readUint(4);
1251
+ return {
1252
+ type: "ssix",
1253
+ version,
1254
+ flags,
1255
+ subsegmentCount,
1256
+ subsegments: view.readEntries(subsegmentCount, () => {
1257
+ const rangesCount = view.readUint(4);
1258
+ return {
1259
+ rangesCount,
1260
+ ranges: view.readEntries(rangesCount, () => ({
1261
+ level: view.readUint(1),
1262
+ rangeSize: view.readUint(3)
1263
+ }))
1264
+ };
1265
+ })
1266
+ };
1267
+ }
1268
+
1269
+ //#endregion
1270
+ //#region src/readers/readSthd.ts
1271
+ /**
1272
+ * Parse a SubtitleMediaHeaderBox from an IsoView
1273
+ *
1274
+ * @param view - The IsoView to read data from
1275
+ *
1276
+ * @returns A parsed SubtitleMediaHeaderBox
1277
+ *
1278
+ * @public
1279
+ */
1280
+ function readSthd(view) {
1281
+ return {
1282
+ type: "sthd",
1283
+ ...view.readFullBox()
1284
+ };
1285
+ }
1286
+
1287
+ //#endregion
1288
+ //#region src/readers/readStsd.ts
1289
+ /**
1290
+ * Parse a SampleDescriptionBox from an IsoView
1291
+ *
1292
+ * @param view - The IsoView to read data from
1293
+ *
1294
+ * @returns A parsed SampleDescriptionBox
1295
+ *
1296
+ * @public
1297
+ */
1298
+ function readStsd(view) {
1299
+ const { version, flags } = view.readFullBox();
1300
+ const entryCount = view.readUint(4);
1301
+ return {
1302
+ type: "stsd",
1303
+ version,
1304
+ flags,
1305
+ entryCount,
1306
+ entries: view.readBoxes(entryCount)
1307
+ };
1308
+ }
1309
+
1310
+ //#endregion
1311
+ //#region src/readers/readStss.ts
1312
+ /**
1313
+ * Parse a SyncSampleBox from an IsoView
1314
+ *
1315
+ * @param view - The IsoView to read data from
1316
+ *
1317
+ * @returns A parsed SyncSampleBox
1318
+ *
1319
+ * @public
1320
+ */
1321
+ function readStss(view) {
1322
+ const { version, flags } = view.readFullBox();
1323
+ const entryCount = view.readUint(4);
1324
+ return {
1325
+ type: "stss",
1326
+ version,
1327
+ flags,
1328
+ entryCount,
1329
+ entries: view.readEntries(entryCount, () => ({ sampleNumber: view.readUint(4) }))
1330
+ };
1331
+ }
1332
+
1333
+ //#endregion
1334
+ //#region src/readers/readSttg.ts
1335
+ /**
1336
+ * Parse a WebVTTSettingsBox from an IsoView
1337
+ *
1338
+ * @param view - The IsoView to read data from
1339
+ *
1340
+ * @returns A parsed WebVTTSettingsBox
1341
+ *
1342
+ * @public
1343
+ */
1344
+ function readSttg(view) {
1345
+ return {
1346
+ type: "sttg",
1347
+ settings: view.readUtf8(-1)
1348
+ };
1349
+ }
1350
+
1351
+ //#endregion
1352
+ //#region src/readers/readStts.ts
1353
+ /**
1354
+ * Parse a DecodingTimeToSampleBox from an IsoView
1355
+ *
1356
+ * @param view - The IsoView to read data from
1357
+ *
1358
+ * @returns A parsed DecodingTimeToSampleBox
1359
+ *
1360
+ * @public
1361
+ */
1362
+ function readStts(view) {
1363
+ const { version, flags } = view.readFullBox();
1364
+ const entryCount = view.readUint(4);
1365
+ return {
1366
+ type: "stts",
1367
+ version,
1368
+ flags,
1369
+ entryCount,
1370
+ entries: view.readEntries(entryCount, () => ({
1371
+ sampleCount: view.readUint(4),
1372
+ sampleDelta: view.readUint(4)
1373
+ }))
1374
+ };
1375
+ }
1376
+
1377
+ //#endregion
1378
+ //#region src/readers/readStyp.ts
1379
+ /**
1380
+ * Parse a SegmentTypeBox from an IsoView
1381
+ *
1382
+ * @param view - The IsoView to read data from
1383
+ *
1384
+ * @returns A parsed SegmentTypeBox
1385
+ *
1386
+ * @public
1387
+ */
1388
+ function readStyp(view) {
1389
+ return {
1390
+ ...readFtyp(view),
1391
+ type: "styp"
1392
+ };
1393
+ }
1394
+
1395
+ //#endregion
1396
+ //#region src/readers/readSubs.ts
1397
+ /**
1398
+ * Parse a SubSampleInformationBox from an IsoView
1399
+ *
1400
+ * @param view - The IsoView to read data from
1401
+ *
1402
+ * @returns A parsed SubSampleInformationBox
1403
+ *
1404
+ * @public
1405
+ */
1406
+ function readSubs(view) {
1407
+ const { version, flags } = view.readFullBox();
1408
+ const entryCount = view.readUint(4);
1409
+ return {
1410
+ type: "subs",
1411
+ version,
1412
+ flags,
1413
+ entryCount,
1414
+ entries: view.readEntries(entryCount, () => {
1415
+ const sampleDelta = view.readUint(4);
1416
+ const subsampleCount = view.readUint(2);
1417
+ return {
1418
+ sampleDelta,
1419
+ subsampleCount,
1420
+ subsamples: view.readEntries(subsampleCount, () => ({
1421
+ subsampleSize: view.readUint(version === 1 ? 4 : 2),
1422
+ subsamplePriority: view.readUint(1),
1423
+ discardable: view.readUint(1),
1424
+ codecSpecificParameters: view.readUint(4)
1425
+ }))
1426
+ };
1427
+ })
1428
+ };
1429
+ }
1430
+
1431
+ //#endregion
1432
+ //#region src/readers/readTenc.ts
1433
+ /**
1434
+ * Parse a TrackEncryptionBox from an IsoView
1435
+ *
1436
+ * @param view - The IsoView to read data from
1437
+ *
1438
+ * @returns A parsed TrackEncryptionBox
1439
+ *
1440
+ * @public
1441
+ */
1442
+ function readTenc(view) {
1443
+ return {
1444
+ type: "tenc",
1445
+ ...view.readFullBox(),
1446
+ defaultIsEncrypted: view.readUint(3),
1447
+ defaultIvSize: view.readUint(1),
1448
+ defaultKid: view.readArray(UINT, 1, 16)
1449
+ };
1450
+ }
1451
+
1452
+ //#endregion
1453
+ //#region src/readers/readTfdt.ts
1454
+ /**
1455
+ * Parse a TrackFragmentDecodeTimeBox from an IsoView
1456
+ *
1457
+ * @param view - The IsoView to read data from
1458
+ *
1459
+ * @returns A parsed TrackFragmentDecodeTimeBox
1460
+ *
1461
+ * @public
1462
+ */
1463
+ function readTfdt(view) {
1464
+ const { version, flags } = view.readFullBox();
1465
+ return {
1466
+ type: "tfdt",
1467
+ version,
1468
+ flags,
1469
+ baseMediaDecodeTime: view.readUint(version == 1 ? 8 : 4)
1470
+ };
1471
+ }
1472
+
1473
+ //#endregion
1474
+ //#region src/readers/readTfhd.ts
1475
+ /**
1476
+ * Parse a TrackFragmentHeaderBox from an IsoView
1477
+ *
1478
+ * @param view - The IsoView to read data from
1479
+ *
1480
+ * @returns A parsed TrackFragmentHeaderBox
1481
+ *
1482
+ * @public
1483
+ */
1484
+ function readTfhd(view) {
1485
+ const { version, flags } = view.readFullBox();
1486
+ return {
1487
+ type: "tfhd",
1488
+ version,
1489
+ flags,
1490
+ trackId: view.readUint(4),
1491
+ baseDataOffset: flags & 1 ? view.readUint(8) : void 0,
1492
+ sampleDescriptionIndex: flags & 2 ? view.readUint(4) : void 0,
1493
+ defaultSampleDuration: flags & 8 ? view.readUint(4) : void 0,
1494
+ defaultSampleSize: flags & 16 ? view.readUint(4) : void 0,
1495
+ defaultSampleFlags: flags & 32 ? view.readUint(4) : void 0
1496
+ };
1497
+ }
1498
+
1499
+ //#endregion
1500
+ //#region src/readers/readTfra.ts
1501
+ /**
1502
+ * Parse a TrackFragmentRandomAccessBox from an IsoView
1503
+ *
1504
+ * @param view - The IsoView to read data from
1505
+ *
1506
+ * @returns A parsed TrackFragmentRandomAccessBox
1507
+ *
1508
+ * @public
1509
+ */
1510
+ function readTfra(view) {
1511
+ const { version, flags } = view.readFullBox();
1512
+ const trackId = view.readUint(4);
1513
+ const reserved = view.readUint(4);
1514
+ const lengthSizeOfTrafNum = (reserved & 48) >> 4;
1515
+ const lengthSizeOfTrunNum = (reserved & 12) >> 2;
1516
+ const lengthSizeOfSampleNum = reserved & 3;
1517
+ const numberOfEntry = view.readUint(4);
1518
+ return {
1519
+ type: "tfra",
1520
+ version,
1521
+ flags,
1522
+ trackId,
1523
+ reserved,
1524
+ lengthSizeOfTrafNum,
1525
+ lengthSizeOfTrunNum,
1526
+ lengthSizeOfSampleNum,
1527
+ numberOfEntry,
1528
+ entries: view.readEntries(numberOfEntry, () => ({
1529
+ time: view.readUint(version === 1 ? 8 : 4),
1530
+ moofOffset: view.readUint(version === 1 ? 8 : 4),
1531
+ trafNumber: view.readUint(lengthSizeOfTrafNum + 1),
1532
+ trunNumber: view.readUint(lengthSizeOfTrunNum + 1),
1533
+ sampleNumber: view.readUint(lengthSizeOfSampleNum + 1)
1534
+ }))
1535
+ };
1536
+ }
1537
+
1538
+ //#endregion
1539
+ //#region src/readers/readTkhd.ts
1540
+ /**
1541
+ * Parse a TrackHeaderBox from an IsoView
1542
+ *
1543
+ * @param view - The IsoView to read data from
1544
+ *
1545
+ * @returns A parsed TrackHeaderBox
1546
+ *
1547
+ * @public
1548
+ */
1549
+ function readTkhd(view) {
1550
+ const { version, flags } = view.readFullBox();
1551
+ const size = version === 1 ? 8 : 4;
1552
+ return {
1553
+ type: "tkhd",
1554
+ version,
1555
+ flags,
1556
+ creationTime: view.readUint(size),
1557
+ modificationTime: view.readUint(size),
1558
+ trackId: view.readUint(4),
1559
+ reserved1: view.readUint(4),
1560
+ duration: view.readUint(size),
1561
+ reserved2: view.readArray(UINT, 4, 2),
1562
+ layer: view.readUint(2),
1563
+ alternateGroup: view.readUint(2),
1564
+ volume: view.readTemplate(2),
1565
+ reserved3: view.readUint(2),
1566
+ matrix: view.readArray(TEMPLATE, 4, 9),
1567
+ width: view.readTemplate(4),
1568
+ height: view.readTemplate(4)
1569
+ };
1570
+ }
1571
+
1572
+ //#endregion
1573
+ //#region src/readers/readTrex.ts
1574
+ /**
1575
+ * Parse a TrackExtendsBox from an IsoView
1576
+ *
1577
+ * @param view - The IsoView to read data from
1578
+ *
1579
+ * @returns A parsed TrackExtendsBox
1580
+ *
1581
+ * @public
1582
+ */
1583
+ function readTrex(view) {
1584
+ return {
1585
+ type: "trex",
1586
+ ...view.readFullBox(),
1587
+ trackId: view.readUint(4),
1588
+ defaultSampleDescriptionIndex: view.readUint(4),
1589
+ defaultSampleDuration: view.readUint(4),
1590
+ defaultSampleSize: view.readUint(4),
1591
+ defaultSampleFlags: view.readUint(4)
1592
+ };
1593
+ }
1594
+
1595
+ //#endregion
1596
+ //#region src/readers/readTrun.ts
1597
+ /**
1598
+ * Parse a TrackRunBox from an IsoView
1599
+ *
1600
+ * @param view - The IsoView to read data from
1601
+ *
1602
+ * @returns A parsed TrackRunBox
1603
+ *
1604
+ * @public
1605
+ */
1606
+ function readTrun(view) {
1607
+ const { version, flags } = view.readFullBox();
1608
+ const sampleCount = view.readUint(4);
1609
+ let dataOffset;
1610
+ let firstSampleFlags;
1611
+ if (flags & 1) dataOffset = view.readInt(4);
1612
+ if (flags & 4) firstSampleFlags = view.readUint(4);
1613
+ const samples = view.readEntries(sampleCount, () => {
1614
+ const sample = {};
1615
+ if (flags & 256) sample.sampleDuration = view.readUint(4);
1616
+ if (flags & 512) sample.sampleSize = view.readUint(4);
1617
+ if (flags & 1024) sample.sampleFlags = view.readUint(4);
1618
+ if (flags & 2048) sample.sampleCompositionTimeOffset = version === 1 ? view.readInt(4) : view.readUint(4);
1619
+ return sample;
1620
+ });
1621
+ return {
1622
+ type: "trun",
1623
+ version,
1624
+ flags,
1625
+ sampleCount,
1626
+ dataOffset,
1627
+ firstSampleFlags,
1628
+ samples
1629
+ };
1630
+ }
1631
+
1632
+ //#endregion
1633
+ //#region src/readers/readUrl.ts
1634
+ /**
1635
+ * Parse a UrlBox from an IsoView
1636
+ *
1637
+ * @param view - The IsoView to read data from
1638
+ *
1639
+ * @returns A parsed UrlBox
1640
+ *
1641
+ * @public
1642
+ */
1643
+ function readUrl(view) {
1644
+ return {
1645
+ type: "url ",
1646
+ ...view.readFullBox(),
1647
+ location: view.readString(-1)
1648
+ };
1649
+ }
1650
+
1651
+ //#endregion
1652
+ //#region src/readers/readUrn.ts
32
1653
  /**
33
- * The data field type
1654
+ * Parse a UrnBox from an IsoView
1655
+ *
1656
+ * @param view - The IsoView to read data from
34
1657
  *
1658
+ * @returns A parsed UrnBox
35
1659
  *
36
- * @beta
1660
+ * @public
37
1661
  */
38
- const DATA = "data";
1662
+ function readUrn(view) {
1663
+ return {
1664
+ type: "urn ",
1665
+ ...view.readFullBox(),
1666
+ name: view.readString(-1),
1667
+ location: view.readString(-1)
1668
+ };
1669
+ }
39
1670
 
40
1671
  //#endregion
41
- //#region src/fields/INT.ts
1672
+ //#region src/readers/readVlab.ts
42
1673
  /**
43
- * The integer field type
1674
+ * Parse a WebVTTSourceLabelBox from an IsoView
1675
+ *
1676
+ * @param view - The IsoView to read data from
44
1677
  *
1678
+ * @returns A parsed WebVTTSourceLabelBox
45
1679
  *
46
- * @beta
1680
+ * @public
47
1681
  */
48
- const INT = "int";
1682
+ function readVlab(view) {
1683
+ return {
1684
+ type: "vlab",
1685
+ sourceLabel: view.readUtf8(-1)
1686
+ };
1687
+ }
49
1688
 
50
1689
  //#endregion
51
- //#region src/fields/STRING.ts
1690
+ //#region src/readers/readVmhd.ts
52
1691
  /**
53
- * The string field type
1692
+ * Parse a VideoMediaHeaderBox from an IsoView
54
1693
  *
1694
+ * @param view - The IsoView to read data from
1695
+ *
1696
+ * @returns A parsed VideoMediaHeaderBox
55
1697
  *
56
- * @beta
1698
+ * @public
57
1699
  */
58
- const STRING = "string";
1700
+ function readVmhd(view) {
1701
+ return {
1702
+ type: "vmhd",
1703
+ ...view.readFullBox(),
1704
+ graphicsmode: view.readUint(2),
1705
+ opcolor: view.readArray(UINT, 2, 3)
1706
+ };
1707
+ }
59
1708
 
60
1709
  //#endregion
61
- //#region src/fields/TEMPLATE.ts
1710
+ //#region src/readers/readVttC.ts
62
1711
  /**
63
- * The template field type
1712
+ * Parse a WebVTTConfigurationBox from an IsoView
1713
+ *
1714
+ * @param view - The IsoView to read data from
64
1715
  *
1716
+ * @returns A parsed WebVttConfigurationBox
65
1717
  *
66
- * @beta
1718
+ * @public
67
1719
  */
68
- const TEMPLATE = "template";
1720
+ function readVttC(view) {
1721
+ return {
1722
+ type: "vttC",
1723
+ config: view.readUtf8()
1724
+ };
1725
+ }
69
1726
 
70
1727
  //#endregion
71
- //#region src/fields/UINT.ts
1728
+ //#region src/readers/readVtte.ts
72
1729
  /**
73
- * The unsigned integer field type
1730
+ * Parse a WebVTT Empty Sample Box from an IsoView
74
1731
  *
1732
+ * @returns A parsed WebVTT Empty Sample Box
75
1733
  *
76
- * @beta
1734
+ * @public
77
1735
  */
78
- const UINT = "uint";
1736
+ function readVtte(_) {
1737
+ return { type: "vtte" };
1738
+ }
1739
+
1740
+ //#endregion
1741
+ //#region src/fields/DATA.ts
1742
+ /**
1743
+ * The data field type
1744
+ *
1745
+ * @public
1746
+ */
1747
+ const DATA = "data";
1748
+
1749
+ //#endregion
1750
+ //#region src/fields/INT.ts
1751
+ /**
1752
+ * The integer field type
1753
+ *
1754
+ * @public
1755
+ */
1756
+ const INT = "int";
79
1757
 
80
1758
  //#endregion
81
1759
  //#region src/fields/UTF8.ts
82
1760
  /**
83
1761
  * The UTF8 field type
84
1762
  *
85
- *
86
- * @beta
1763
+ * @public
87
1764
  */
88
1765
  const UTF8 = "utf8";
89
1766
 
90
1767
  //#endregion
91
- //#region src/readers/readData.ts
1768
+ //#region src/utils/readData.ts
92
1769
  function readData(dataView, offset, size) {
93
1770
  const length = size > 0 ? size : dataView.byteLength - (offset - dataView.byteOffset);
94
1771
  return new Uint8Array(dataView.buffer, offset, Math.max(length, 0));
95
1772
  }
96
1773
 
97
1774
  //#endregion
98
- //#region src/readers/readInt.ts
1775
+ //#region src/utils/readInt.ts
99
1776
  function readInt(dataView, offset, size) {
100
1777
  let result = NaN;
101
1778
  const cursor = offset - dataView.byteOffset;
@@ -119,7 +1796,7 @@ function readInt(dataView, offset, size) {
119
1796
  }
120
1797
 
121
1798
  //#endregion
122
- //#region src/readers/readUint.ts
1799
+ //#region src/utils/readUint.ts
123
1800
  function readUint(dataView, offset, size) {
124
1801
  const cursor = offset - dataView.byteOffset;
125
1802
  let value = NaN;
@@ -150,7 +1827,7 @@ function readUint(dataView, offset, size) {
150
1827
  }
151
1828
 
152
1829
  //#endregion
153
- //#region src/readers/readString.ts
1830
+ //#region src/utils/readString.ts
154
1831
  function readString(dataView, offset, length) {
155
1832
  let str = "";
156
1833
  for (let c = 0; c < length; c++) {
@@ -161,14 +1838,14 @@ function readString(dataView, offset, length) {
161
1838
  }
162
1839
 
163
1840
  //#endregion
164
- //#region src/readers/readTemplate.ts
1841
+ //#region src/utils/readTemplate.ts
165
1842
  function readTemplate(dataView, offset, size) {
166
1843
  const half = size / 2;
167
1844
  return readUint(dataView, offset, half) + readUint(dataView, offset + half, half) / Math.pow(2, half);
168
1845
  }
169
1846
 
170
1847
  //#endregion
171
- //#region src/readers/readTerminatedString.ts
1848
+ //#region src/utils/readTerminatedString.ts
172
1849
  function readTerminatedString(dataView, offset) {
173
1850
  let str = "";
174
1851
  let cursor = offset;
@@ -182,7 +1859,7 @@ function readTerminatedString(dataView, offset) {
182
1859
  }
183
1860
 
184
1861
  //#endregion
185
- //#region src/readers/readUtf8String.ts
1862
+ //#region src/utils/readUtf8String.ts
186
1863
  /**
187
1864
  * Reads a UTF-8 string from a data view.
188
1865
  *
@@ -198,7 +1875,7 @@ function readUtf8String(dataView, offset) {
198
1875
  }
199
1876
 
200
1877
  //#endregion
201
- //#region src/readers/readUtf8TerminatedString.ts
1878
+ //#region src/utils/readUtf8TerminatedString.ts
202
1879
  /**
203
1880
  * Reads a UTF-8 terminated string from a data view.
204
1881
  *
@@ -221,15 +1898,14 @@ function readUtf8TerminatedString(dataView, offset) {
221
1898
  }
222
1899
 
223
1900
  //#endregion
224
- //#region src/IsoView.ts
1901
+ //#region src/IsoBoxReadView.ts
225
1902
  /**
226
1903
  * ISO BMFF data view. Similar to DataView, but with additional methods for reading ISO BMFF data.
227
1904
  * It implements the iterator protocol, so it can be used in a for...of loop.
228
1905
  *
229
- *
230
- * @beta
1906
+ * @public
231
1907
  */
232
- var IsoView = class IsoView {
1908
+ var IsoBoxReadView = class IsoBoxReadView {
233
1909
  /**
234
1910
  * Creates a new IsoView instance. Similar to DataView, but with additional
235
1911
  * methods for reading ISO BMFF data. It implements the iterator protocol,
@@ -240,10 +1916,13 @@ var IsoView = class IsoView {
240
1916
  */
241
1917
  constructor(raw, config) {
242
1918
  this.truncated = false;
243
- this.slice = (size) => {
244
- const dataView = new DataView(this.dataView.buffer, this.offset, size);
245
- this.offset += size;
246
- return new IsoView(dataView, this.config);
1919
+ this.slice = (offset, size) => {
1920
+ const isoView = new IsoBoxReadView(new DataView(this.dataView.buffer, offset, size), this.config);
1921
+ const headerSize = this.offset - offset;
1922
+ const bodySize = size - headerSize;
1923
+ this.offset += bodySize;
1924
+ isoView.jump(headerSize);
1925
+ return isoView;
247
1926
  };
248
1927
  this.read = (type, size = 0) => {
249
1928
  const { dataView, offset } = this;
@@ -309,30 +1988,34 @@ var IsoView = class IsoView {
309
1988
  for (let i = 0; i < length; i++) value.push(this.read(type, size));
310
1989
  return value;
311
1990
  };
1991
+ this.jump = (size) => {
1992
+ this.offset += size;
1993
+ };
312
1994
  this.readBox = () => {
313
1995
  const { dataView, offset } = this;
314
1996
  let cursor = 0;
1997
+ const size = readUint(dataView, offset, 4);
1998
+ const type = readString(dataView, offset + 4, 4);
315
1999
  const box = {
316
- size: readUint(dataView, offset, 4),
317
- type: readString(dataView, offset + 4, 4)
2000
+ size,
2001
+ type
318
2002
  };
319
2003
  cursor += 8;
320
2004
  if (box.size === 1) {
321
2005
  box.largesize = readUint(dataView, offset + cursor, 8);
322
2006
  cursor += 8;
323
2007
  }
324
- const actualSize = box.largesize || box.size;
2008
+ const actualSize = box.size === 0 ? this.bytesRemaining : box.largesize ?? box.size;
325
2009
  if (this.cursor + actualSize > dataView.byteLength) {
326
2010
  this.truncated = true;
327
2011
  throw new Error("Truncated box");
328
2012
  }
329
- this.offset += cursor;
330
- if (box.type === "uuid") box.usertype = this.readArray("uint", 1, 16);
331
- const viewSize = box.size === 0 ? this.bytesRemaining : actualSize - cursor;
332
- box.data = this.slice(viewSize);
2013
+ this.jump(cursor);
2014
+ if (type === "uuid") box.usertype = this.readArray("uint", 1, 16);
2015
+ box.view = this.slice(offset, actualSize);
333
2016
  return box;
334
2017
  };
335
- this.readBoxes = (length) => {
2018
+ this.readBoxes = (length = -1) => {
336
2019
  const result = [];
337
2020
  for (const box of this) {
338
2021
  result.push(box);
@@ -345,12 +2028,27 @@ var IsoView = class IsoView {
345
2028
  for (let i = 0; i < length; i++) result.push(map());
346
2029
  return result;
347
2030
  };
348
- this.dataView = raw instanceof ArrayBuffer ? new DataView(raw) : raw instanceof Uint8Array ? new DataView(raw.buffer, raw.byteOffset, raw.byteLength) : raw;
2031
+ this.dataView = raw instanceof ArrayBuffer ? new DataView(raw) : raw instanceof DataView ? raw : new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
349
2032
  this.offset = this.dataView.byteOffset;
350
- this.config = config || {
351
- recursive: false,
352
- parsers: {}
353
- };
2033
+ this.config = config || { readers: {} };
2034
+ }
2035
+ /**
2036
+ * The buffer of the data view.
2037
+ */
2038
+ get buffer() {
2039
+ return this.dataView.buffer;
2040
+ }
2041
+ /**
2042
+ * The byte offset of the data view.
2043
+ */
2044
+ get byteOffset() {
2045
+ return this.dataView.byteOffset;
2046
+ }
2047
+ /**
2048
+ * The byte length of the data view.
2049
+ */
2050
+ get byteLength() {
2051
+ return this.dataView.byteLength;
354
2052
  }
355
2053
  /**
356
2054
  * The current byteoffset in the data view.
@@ -376,1522 +2074,1643 @@ var IsoView = class IsoView {
376
2074
  * @returns A generator of boxes.
377
2075
  */
378
2076
  *[Symbol.iterator]() {
379
- const { parsers = {}, recursive = false } = this.config;
2077
+ const { readers = {} } = this.config;
380
2078
  while (!this.done) try {
381
- const { type, data,...rest } = this.readBox();
382
- const box = {
383
- type,
384
- ...rest
385
- };
386
- const parser = parsers[type] || parsers[type.trim()];
387
- if (parser) Object.assign(box, parser(data, this.config));
388
- box.view = data;
389
- if (CONTAINERS.includes(type)) {
2079
+ const box = this.readBox();
2080
+ const { type, view } = box;
2081
+ const parser = readers[type] || readers[type.trim()];
2082
+ if (parser) Object.assign(box, parser(view));
2083
+ if (isContainer(box) && !box.boxes) {
390
2084
  const boxes = [];
391
- for (const child of data) {
392
- if (recursive) yield child;
393
- boxes.push(child);
394
- }
2085
+ for (const child of view) boxes.push(child);
395
2086
  box.boxes = boxes;
396
2087
  }
397
2088
  yield box;
398
2089
  } catch (error) {
399
- break;
2090
+ if (error instanceof Error && error.message === "Truncated box") break;
2091
+ throw error;
400
2092
  }
401
2093
  }
402
2094
  };
403
2095
 
404
2096
  //#endregion
405
- //#region src/createIsoView.ts
2097
+ //#region src/readIsoBoxes.ts
406
2098
  /**
407
- * Create an IsoView from a raw ISO data.
2099
+ * Reads ISO boxes from a data source.
408
2100
  *
409
2101
  * @param raw - The raw ISO data
410
2102
  * @param config - The configuration for the IsoView
411
2103
  *
412
- * @returns The created IsoView
413
- *
414
- *
415
- * @beta
416
- */
417
- function createIsoView(raw, config) {
418
- return new IsoView(raw, config);
419
- }
420
-
421
- //#endregion
422
- //#region src/filterBoxes.ts
423
- function filter(iterator, fn, recursive, result) {
424
- for (const box of iterator) {
425
- if (fn(box)) result.push(box);
426
- const { boxes } = box;
427
- if (recursive && Array.isArray(boxes)) filter(boxes, fn, recursive, result);
428
- }
429
- return result;
430
- }
431
- /**
432
- * Filters boxes based on the given filter function.
2104
+ * @returns The parsed boxes
433
2105
  *
434
- * @param raw - The raw boxes to filter.
435
- * @param config - The box parser configuration.
436
- * @param fn - The filter function.
437
- * @returns The filtered boxes.
2106
+ * @example
2107
+ * {@includeCode ../test/readIsoBoxes.test.ts#example}
438
2108
  *
439
- * @beta
2109
+ * @public
440
2110
  */
441
- function filterBoxes(raw, fn, config) {
442
- if (raw instanceof DataView || raw instanceof Uint8Array || raw instanceof ArrayBuffer) raw = createIsoView(raw, {
443
- ...config,
444
- recursive: false
445
- });
446
- const recursive = config?.recursive ?? true;
447
- return filter(raw, fn, recursive, []);
2111
+ function readIsoBoxes(raw, config) {
2112
+ const boxes = [];
2113
+ for (const box of new IsoBoxReadView(raw, config)) boxes.push(box);
2114
+ return boxes;
448
2115
  }
449
2116
 
450
2117
  //#endregion
451
- //#region src/filterBoxesByType.ts
2118
+ //#region src/traverseIsoBoxes.ts
452
2119
  /**
453
- * Filter boxes by type from an IsoView
2120
+ * Traverse ISO boxes
454
2121
  *
455
- * @param type - The type(s) of boxes to filter
456
- * @param raw - The raw ISO data
457
- * @param config - The configuration for the IsoView
2122
+ * @param boxes - The boxes to traverse
2123
+ * @param depthFirst - Whether to traverse the boxes depth-first or breadth-first
2124
+ * @param maxDepth - The maximum depth to traverse. A value of 0 will only traverse the root boxes.
458
2125
  *
459
- * @returns The filtered boxes
2126
+ * @returns A generator of boxes
460
2127
  *
2128
+ * @example
2129
+ * {@includeCode ../test/traverseIsoBoxes.test.ts#example}
461
2130
  *
462
- * @beta
2131
+ * @public
463
2132
  */
464
- function filterBoxesByType(raw, type, config = {}) {
465
- if (!Array.isArray(type)) type = [type];
466
- return filterBoxes(raw, (box) => type.includes(box.type), config);
467
- }
468
-
469
- //#endregion
470
- //#region src/findBox.ts
471
- function find(iterator, recursive, fn) {
472
- for (const box of iterator) {
473
- if (fn(box)) return box;
474
- const { boxes } = box;
475
- if (recursive && Array.isArray(boxes)) {
476
- const result = find(boxes, recursive, fn);
477
- if (result) return result;
2133
+ function* traverseIsoBoxes(boxes, depthFirst = true, maxDepth = Infinity) {
2134
+ if (maxDepth < 0 || typeof maxDepth !== "number" || Number.isNaN(maxDepth)) return;
2135
+ const queue = [[boxes, 0]];
2136
+ while (queue.length > 0) {
2137
+ const item = queue.shift();
2138
+ if (!item) continue;
2139
+ const [children, depth] = item;
2140
+ for (const child of children) {
2141
+ yield child;
2142
+ if (depth >= maxDepth) continue;
2143
+ if (isContainer(child) && child.boxes) {
2144
+ const next = child.boxes;
2145
+ if (depthFirst) yield* traverseIsoBoxes(next, depthFirst, maxDepth - 1);
2146
+ else queue.push([next, depth + 1]);
2147
+ }
478
2148
  }
479
2149
  }
480
- return null;
481
2150
  }
2151
+
2152
+ //#endregion
2153
+ //#region src/utils/isFullBox.ts
482
2154
  /**
483
- * Find a box from an IsoView that matches a filter function
2155
+ * Check if a box is a full box
484
2156
  *
485
- * @param raw - The raw ISO data
486
- * @param config - The configuration for the IsoView
487
- * @param fn - The filter function
2157
+ * @param box - The box to check
488
2158
  *
489
- * @returns The first box that matches the filter function
2159
+ * @returns `true` if the box is a full box, `false` otherwise
490
2160
  *
491
- *
492
- * @beta
2161
+ * @public
493
2162
  */
494
- function findBox(raw, fn, config) {
495
- const recursive = config?.recursive ?? true;
496
- if (raw instanceof DataView || raw instanceof Uint8Array || raw instanceof ArrayBuffer) raw = createIsoView(raw, {
497
- ...config,
498
- recursive: false
499
- });
500
- return find(raw, recursive, fn);
2163
+ function isFullBox(box) {
2164
+ return "version" in box && "flags" in box;
501
2165
  }
502
2166
 
503
2167
  //#endregion
504
- //#region src/findBoxByType.ts
2168
+ //#region src/writeIsoBoxes.ts
505
2169
  /**
506
- * Find a box from an IsoView that matches a given type
2170
+ * Writes ISO boxes to a readable stream.
507
2171
  *
508
- * @param type - The type of box to find
509
- * @param raw - The raw ISO data
510
- * @param config - The configuration for the IsoView
2172
+ * @param boxes - The boxes to write
2173
+ * @param config - The configuration for the readable stream
511
2174
  *
512
- * @returns The first box that matches the type
2175
+ * @returns A readable stream of the written boxes
513
2176
  *
2177
+ * @example
2178
+ * {@includeCode ../test/writeIsoBoxes.test.ts#example}
514
2179
  *
515
- * @beta
2180
+ * @public
516
2181
  */
517
- function findBoxByType(raw, type, config = {}) {
518
- return findBox(raw, (box) => box.type === type, config);
2182
+ function writeIsoBoxes(boxes, config) {
2183
+ const cfg = createWriterConfig(config);
2184
+ return Array.from(boxes, (box) => writeBox(box, cfg));
519
2185
  }
520
2186
 
521
2187
  //#endregion
522
- //#region src/parseBoxes.ts
2188
+ //#region src/writers/writeArdi.ts
523
2189
  /**
524
- * Parse boxes from an IsoView
525
- *
526
- * @param raw - The raw ISO data
527
- * @param config - The configuration for the IsoView
2190
+ * Write an AudioRenderingIndicationBox to an IsoDataWriter.
528
2191
  *
529
- * @returns The parsed boxes
2192
+ * @param box - The AudioRenderingIndicationBox fields to write
530
2193
  *
2194
+ * @returns An IsoDataWriter containing the encoded box
531
2195
  *
532
- * @beta
2196
+ * @public
533
2197
  */
534
- function parseBoxes(raw, config) {
535
- const boxes = [];
536
- for (const box of createIsoView(raw, config)) boxes.push(box);
537
- return boxes;
2198
+ function writeArdi(box) {
2199
+ const writer = new IsoBoxWriteView("ardi", 13);
2200
+ writer.writeFullBox(box.version, box.flags);
2201
+ writer.writeUint(box.audioRenderingIndication, 1);
2202
+ return writer;
538
2203
  }
539
2204
 
540
2205
  //#endregion
541
- //#region src/parsers/ardi.ts
2206
+ //#region src/writers/writeVisualSampleEntryBox.ts
542
2207
  /**
543
- * Parse a AudioRenderingIndicationBox from an IsoView
2208
+ * Write a VisualSampleEntryBox to an IsoDataWriter.
544
2209
  *
545
- * @param view - The IsoView to read data from
2210
+ * ISO/IEC 14496-12:2012 - 12.1.3 Visual Sample Entry
546
2211
  *
547
- * @returns A parsed AudioRenderingIndicationBox
2212
+ * @param box - The VisualSampleEntryBox fields to write
2213
+ * @param type - The box type
548
2214
  *
2215
+ * @returns An IsoDataWriter containing the encoded box
549
2216
  *
550
- * @beta
2217
+ * @public
551
2218
  */
552
- function ardi(view) {
553
- return {
554
- ...view.readFullBox(),
555
- audioRenderingIndication: view.readUint(1)
556
- };
2219
+ function writeVisualSampleEntryBox(box, type) {
2220
+ const headerSize = 8;
2221
+ const reserved1Size = 6;
2222
+ const dataReferenceIndexSize = 2;
2223
+ const preDefined1Size = 2;
2224
+ const reserved2Size = 2;
2225
+ const preDefined2Size = 12;
2226
+ const widthSize = 2;
2227
+ const heightSize = 2;
2228
+ const horizresolutionSize = 4;
2229
+ const vertresolutionSize = 4;
2230
+ const reserved3Size = 4;
2231
+ const frameCountSize = 2;
2232
+ const compressorNameSize = 32;
2233
+ const depthSize = 2;
2234
+ const preDefined3Size = 2;
2235
+ const configSize = box.config.length;
2236
+ const writer = new IsoBoxWriteView(type, headerSize + reserved1Size + dataReferenceIndexSize + preDefined1Size + reserved2Size + preDefined2Size + widthSize + heightSize + horizresolutionSize + vertresolutionSize + reserved3Size + frameCountSize + compressorNameSize + depthSize + preDefined3Size + configSize);
2237
+ writer.writeArray(box.reserved1, UINT, 1, 6);
2238
+ writer.writeUint(box.dataReferenceIndex, 2);
2239
+ writer.writeUint(box.preDefined1, 2);
2240
+ writer.writeUint(box.reserved2, 2);
2241
+ writer.writeArray(box.preDefined2, UINT, 4, 3);
2242
+ writer.writeUint(box.width, 2);
2243
+ writer.writeUint(box.height, 2);
2244
+ writer.writeTemplate(box.horizresolution, 4);
2245
+ writer.writeTemplate(box.vertresolution, 4);
2246
+ writer.writeUint(box.reserved3, 4);
2247
+ writer.writeUint(box.frameCount, 2);
2248
+ writer.writeArray(box.compressorName, UINT, 1, 32);
2249
+ writer.writeUint(box.depth, 2);
2250
+ writer.writeUint(box.preDefined3 & 65535, 2);
2251
+ writer.writeBytes(box.config);
2252
+ return writer;
557
2253
  }
558
2254
 
559
2255
  //#endregion
560
- //#region src/parsers/avc1.ts
2256
+ //#region src/writers/writeAvc1.ts
561
2257
  /**
562
- * Parse a VisualSampleEntryBox from an IsoView
2258
+ * Write a VisualSampleEntryBox to an IsoDataWriter.
563
2259
  *
564
- * @param view - The IsoView to read data from
2260
+ * ISO/IEC 14496-12:2012 - 12.1.3 Visual Sample Entry
565
2261
  *
566
- * @returns A parsed VisualSampleEntryBox
2262
+ * @param box - The VisualSampleEntryBox fields to write
567
2263
  *
2264
+ * @returns An IsoDataWriter containing the encoded box
568
2265
  *
569
- * @beta
2266
+ * @public
570
2267
  */
571
- function avc1(view) {
572
- const { readArray, readUint: readUint$1, readInt: readInt$1, readTemplate: readTemplate$1, readData: readData$1 } = view;
573
- return {
574
- reserved1: readArray(UINT, 1, 6),
575
- dataReferenceIndex: readUint$1(2),
576
- preDefined1: readUint$1(2),
577
- reserved2: readUint$1(2),
578
- preDefined2: readArray(UINT, 4, 3),
579
- width: readUint$1(2),
580
- height: readUint$1(2),
581
- horizresolution: readTemplate$1(4),
582
- vertresolution: readTemplate$1(4),
583
- reserved3: readUint$1(4),
584
- frameCount: readUint$1(2),
585
- compressorName: readArray(UINT, 1, 32),
586
- depth: readUint$1(2),
587
- preDefined3: readInt$1(2),
588
- config: readData$1(-1)
589
- };
2268
+ function writeAvc1(box) {
2269
+ return writeVisualSampleEntryBox(box, "avc1");
590
2270
  }
591
2271
 
592
2272
  //#endregion
593
- //#region src/parsers/avc2.ts
2273
+ //#region src/writers/writeAvc2.ts
594
2274
  /**
595
- * Parse a VisualSampleEntryBox from an IsoView
596
- *
597
- * @param view - The IsoView to read data from
2275
+ * Write a VisualSampleEntryBox (avc2) to an IsoDataWriter.
598
2276
  *
599
- * @returns A parsed VisualSampleEntryBox
2277
+ * @param box - The VisualSampleEntryBox fields to write
600
2278
  *
2279
+ * @returns An IsoDataWriter containing the encoded box
601
2280
  *
602
- * @beta
2281
+ * @public
603
2282
  */
604
- function avc2(view) {
605
- return avc1(view);
2283
+ function writeAvc2(box) {
2284
+ return writeVisualSampleEntryBox(box, "avc2");
606
2285
  }
607
2286
 
608
2287
  //#endregion
609
- //#region src/parsers/avc3.ts
2288
+ //#region src/writers/writeAvc3.ts
610
2289
  /**
611
- * Parse a VisualSampleEntryBox from an IsoView
612
- *
613
- * @param view - The IsoView to read data from
2290
+ * Write a VisualSampleEntryBox (avc3) to an IsoDataWriter.
614
2291
  *
615
- * @returns A parsed VisualSampleEntryBox
2292
+ * @param box - The VisualSampleEntryBox fields to write
616
2293
  *
2294
+ * @returns An IsoDataWriter containing the encoded box
617
2295
  *
618
- * @beta
2296
+ * @public
619
2297
  */
620
- function avc3(view) {
621
- return avc1(view);
2298
+ function writeAvc3(box) {
2299
+ return writeVisualSampleEntryBox(box, "avc3");
622
2300
  }
623
2301
 
624
2302
  //#endregion
625
- //#region src/parsers/avc4.ts
2303
+ //#region src/writers/writeAvc4.ts
626
2304
  /**
627
- * Parse a VisualSampleEntryBox from an IsoView
628
- *
629
- * @param view - The IsoView to read data from
2305
+ * Write a VisualSampleEntryBox (avc4) to an IsoDataWriter.
630
2306
  *
631
- * @returns A parsed VisualSampleEntryBox
2307
+ * @param box - The VisualSampleEntryBox fields to write
632
2308
  *
2309
+ * @returns An IsoDataWriter containing the encoded box
633
2310
  *
634
- * @beta
2311
+ * @public
635
2312
  */
636
- function avc4(view) {
637
- return avc1(view);
2313
+ function writeAvc4(box) {
2314
+ return writeVisualSampleEntryBox(box, "avc4");
638
2315
  }
639
2316
 
640
2317
  //#endregion
641
- //#region src/parsers/ctts.ts
2318
+ //#region src/writers/writeCtts.ts
642
2319
  /**
643
- * Parse a CompositionTimeToSampleBox from an IsoView
2320
+ * Write a CompositionTimeToSampleBox to an IsoDataWriter.
644
2321
  *
645
- * @param view - The IsoView to read data from
2322
+ * ISO/IEC 14496-12:2012 - 8.6.1.3 Composition Time to Sample Box
646
2323
  *
647
- * @returns A parsed CompositionTimeToSampleBox
2324
+ * @param box - The CompositionTimeToSampleBox fields to write
648
2325
  *
2326
+ * @returns An IsoDataWriter containing the encoded box
649
2327
  *
650
- * @beta
2328
+ * @public
651
2329
  */
652
- function ctts(view) {
653
- const { version, flags } = view.readFullBox();
654
- const read = version === 1 ? view.readInt : view.readUint;
655
- const entryCount = view.readUint(4);
656
- return {
657
- version,
658
- flags,
659
- entryCount,
660
- entries: view.readEntries(entryCount, () => ({
661
- sampleCount: view.readUint(4),
662
- sampleOffset: read(4)
663
- }))
664
- };
2330
+ function writeCtts(box) {
2331
+ const headerSize = 8;
2332
+ const fullBoxSize = 4;
2333
+ const entryCountSize = 4;
2334
+ const entriesSize = box.entryCount * 8;
2335
+ const writer = new IsoBoxWriteView("ctts", headerSize + fullBoxSize + entryCountSize + entriesSize);
2336
+ writer.writeFullBox(box.version, box.flags);
2337
+ writer.writeUint(box.entryCount, 4);
2338
+ for (const entry of box.entries) {
2339
+ writer.writeUint(entry.sampleCount, 4);
2340
+ writer.writeUint(entry.sampleOffset, 4);
2341
+ }
2342
+ return writer;
665
2343
  }
666
2344
 
667
2345
  //#endregion
668
- //#region src/parsers/dref.ts
2346
+ //#region src/writers/writeDref.ts
669
2347
  /**
670
- * Parse a DataReferenceBox from an IsoView
671
- *
672
- * @param view - The IsoView to read data from
2348
+ * Write a DataReferenceBox to an IsoDataWriter.
673
2349
  *
674
- * @returns A parsed DataReferenceBox
2350
+ * @param box - The DataReferenceBox fields to write
675
2351
  *
2352
+ * @returns An IsoDataWriter containing the encoded box
676
2353
  *
677
- * @beta
2354
+ * @public
678
2355
  */
679
- function dref(view) {
680
- const { version, flags } = view.readFullBox();
681
- const entryCount = view.readUint(4);
682
- return {
683
- version,
684
- flags,
685
- entryCount,
686
- entries: view.readBoxes(entryCount)
687
- };
2356
+ function writeDref(box, config) {
2357
+ const headerSize = 8;
2358
+ const fullBoxSize = 4;
2359
+ const entryCountSize = 4;
2360
+ const entryCount = box.entries.length;
2361
+ const entries = writeIsoBoxes(box.entries, config);
2362
+ const entriesSize = entries.reduce((size, entry) => size + entry.byteLength, 0);
2363
+ const writer = new IsoBoxWriteView("dref", headerSize + fullBoxSize + entryCountSize + entriesSize);
2364
+ writer.writeFullBox(box.version, box.flags);
2365
+ writer.writeUint(entryCount, 4);
2366
+ for (const entry of entries) writer.writeBytes(entry);
2367
+ return writer;
688
2368
  }
689
2369
 
690
2370
  //#endregion
691
- //#region src/parsers/elng.ts
2371
+ //#region src/writers/writeElng.ts
692
2372
  /**
693
- * Parse a ExtendedLanguageBox from an IsoView
2373
+ * Write an ExtendedLanguageBox to an IsoDataWriter.
694
2374
  *
695
- * @param view - The IsoView to read data from
2375
+ * ISO/IEC 14496-12:2012 - 8.4.6 Extended Language Tag
696
2376
  *
697
- * @returns A parsed ExtendedLanguageBox
2377
+ * @param box - The ExtendedLanguageBox fields to write
698
2378
  *
2379
+ * @returns An IsoDataWriter containing the encoded box
699
2380
  *
700
- * @beta
2381
+ * @public
701
2382
  */
702
- function elng(view) {
703
- return {
704
- ...view.readFullBox(),
705
- extendedLanguage: view.readUtf8(-1)
706
- };
2383
+ function writeElng(box) {
2384
+ const extendedLanguageBytes = encodeText(box.extendedLanguage);
2385
+ const headerSize = 8;
2386
+ const fullBoxSize = 4;
2387
+ const extendedLanguageSize = extendedLanguageBytes.length + 1;
2388
+ const writer = new IsoBoxWriteView("elng", headerSize + fullBoxSize + extendedLanguageSize);
2389
+ writer.writeFullBox(box.version, box.flags);
2390
+ writer.writeUtf8TerminatedString(box.extendedLanguage);
2391
+ return writer;
707
2392
  }
708
2393
 
709
2394
  //#endregion
710
- //#region src/parsers/elst.ts
2395
+ //#region src/writers/writeElst.ts
711
2396
  /**
712
- * Parse a Box from an IsoView
2397
+ * Write an EditListBox to an IsoDataWriter.
713
2398
  *
714
- * @param view - The IsoView to read data from
2399
+ * ISO/IEC 14496-12:2012 - 8.6.6 Edit List Box
715
2400
  *
716
- * @returns A parsed Box
2401
+ * @param box - The EditListBox fields to write
717
2402
  *
2403
+ * @returns An IsoDataWriter containing the encoded box
718
2404
  *
719
- * @beta
2405
+ * @public
720
2406
  */
721
- function elst(view) {
722
- const { version, flags } = view.readFullBox();
723
- const size = version === 1 ? 8 : 4;
724
- const entryCount = view.readUint(4);
725
- return {
726
- version,
727
- flags,
728
- entryCount,
729
- entries: view.readEntries(entryCount, () => ({
730
- segmentDuration: view.readUint(size),
731
- mediaTime: view.readInt(size),
732
- mediaRateInteger: view.readInt(2),
733
- mediaRateFraction: view.readInt(2)
734
- }))
735
- };
2407
+ function writeElst(box) {
2408
+ const size = box.version === 1 ? 8 : 4;
2409
+ const headerSize = 8;
2410
+ const fullBoxSize = 4;
2411
+ const entryCountSize = 4;
2412
+ const entrySize = size + size + 2 + 2;
2413
+ const entriesSize = box.entryCount * entrySize;
2414
+ const writer = new IsoBoxWriteView("elst", headerSize + fullBoxSize + entryCountSize + entriesSize);
2415
+ writer.writeFullBox(box.version, box.flags);
2416
+ writer.writeUint(box.entryCount, 4);
2417
+ for (const entry of box.entries) {
2418
+ writer.writeUint(entry.segmentDuration, size);
2419
+ writer.writeInt(entry.mediaTime, size);
2420
+ writer.writeInt(entry.mediaRateInteger, 2);
2421
+ writer.writeInt(entry.mediaRateFraction, 2);
2422
+ }
2423
+ return writer;
736
2424
  }
737
2425
 
738
2426
  //#endregion
739
- //#region src/parsers/emsg.ts
2427
+ //#region src/writers/writeEmsg.ts
740
2428
  /**
741
- * Parse an EventMessageBox from an IsoView
2429
+ * Write an EventMessageBox to an IsoDataWriter.
742
2430
  *
743
- * @param view - The IsoView to read data from
2431
+ * ISO/IEC 23009-1 - 5.10.3.3 Event Message Box
744
2432
  *
745
- * @returns A parsed EventMessageBox
2433
+ * @param box - The EventMessageBox fields to write
746
2434
  *
2435
+ * @returns An IsoDataWriter containing the encoded box
747
2436
  *
748
- * @beta
2437
+ * @public
749
2438
  */
750
- function emsg(view) {
751
- const { readUint: readUint$1, readString: readString$1, readData: readData$1 } = view;
752
- const result = { ...view.readFullBox() };
753
- if (result.version == 1) {
754
- result.timescale = readUint$1(4);
755
- result.presentationTime = readUint$1(8);
756
- result.eventDuration = readUint$1(4);
757
- result.id = readUint$1(4);
758
- result.schemeIdUri = readString$1(-1);
759
- result.value = readString$1(-1);
2439
+ function writeEmsg(box) {
2440
+ const headerSize = 8;
2441
+ const fullBoxSize = 4;
2442
+ let contentSize;
2443
+ if (box.version === 0) contentSize = box.schemeIdUri.length + 1 + (box.value.length + 1) + 4 + 4 + 4 + 4 + box.messageData.length;
2444
+ else contentSize = 20 + (box.schemeIdUri.length + 1) + (box.value.length + 1) + box.messageData.length;
2445
+ const writer = new IsoBoxWriteView("emsg", headerSize + fullBoxSize + contentSize);
2446
+ writer.writeFullBox(box.version, box.flags);
2447
+ if (box.version === 0) {
2448
+ writer.writeTerminatedString(box.schemeIdUri);
2449
+ writer.writeTerminatedString(box.value);
2450
+ writer.writeUint(box.timescale, 4);
2451
+ writer.writeUint(box.presentationTimeDelta ?? 0, 4);
2452
+ writer.writeUint(box.eventDuration, 4);
2453
+ writer.writeUint(box.id, 4);
760
2454
  } else {
761
- result.schemeIdUri = readString$1(-1);
762
- result.value = readString$1(-1);
763
- result.timescale = readUint$1(4);
764
- result.presentationTimeDelta = readUint$1(4);
765
- result.eventDuration = readUint$1(4);
766
- result.id = readUint$1(4);
2455
+ writer.writeUint(box.timescale, 4);
2456
+ writer.writeUint(box.presentationTime ?? 0, 8);
2457
+ writer.writeUint(box.eventDuration, 4);
2458
+ writer.writeUint(box.id, 4);
2459
+ writer.writeTerminatedString(box.schemeIdUri);
2460
+ writer.writeTerminatedString(box.value);
767
2461
  }
768
- result.messageData = readData$1(-1);
769
- return result;
2462
+ writer.writeBytes(box.messageData);
2463
+ return writer;
770
2464
  }
771
2465
 
772
2466
  //#endregion
773
- //#region src/parsers/mp4a.ts
2467
+ //#region src/writers/writeEnca.ts
774
2468
  /**
775
- * Parse an AudioSampleEntry from an IsoView
776
- *
777
- * @param view - The IsoView to read data from
2469
+ * Write an AudioSampleEntryBox (enca) to an IsoDataWriter.
778
2470
  *
779
- * @returns A parsed AudioSampleEntry
2471
+ * @param box - The AudioSampleEntryBox fields to write
780
2472
  *
2473
+ * @returns An IsoDataWriter containing the encoded box
781
2474
  *
782
- * @beta
2475
+ * @public
783
2476
  */
784
- function mp4a(view) {
785
- const { readArray, readUint: readUint$1, readTemplate: readTemplate$1, readData: readData$1 } = view;
786
- return {
787
- reserved1: readArray(UINT, 1, 6),
788
- dataReferenceIndex: readUint$1(2),
789
- reserved2: readArray(UINT, 4, 2),
790
- channelcount: readUint$1(2),
791
- samplesize: readUint$1(2),
792
- preDefined: readUint$1(2),
793
- reserved3: readUint$1(2),
794
- samplerate: readTemplate$1(4),
795
- esds: readData$1(-1)
796
- };
2477
+ function writeEnca(box) {
2478
+ const headerSize = 8;
2479
+ const reserved1Size = 6;
2480
+ const dataReferenceIndexSize = 2;
2481
+ const reserved2Size = 8;
2482
+ const channelcountSize = 2;
2483
+ const samplesizeSize = 2;
2484
+ const preDefinedSize = 2;
2485
+ const reserved3Size = 2;
2486
+ const samplerateSize = 4;
2487
+ const esdsSize = box.esds.length;
2488
+ const writer = new IsoBoxWriteView("enca", headerSize + reserved1Size + dataReferenceIndexSize + reserved2Size + channelcountSize + samplesizeSize + preDefinedSize + reserved3Size + samplerateSize + esdsSize);
2489
+ writer.writeArray(box.reserved1, UINT, 1, 6);
2490
+ writer.writeUint(box.dataReferenceIndex, 2);
2491
+ writer.writeArray(box.reserved2, UINT, 4, 2);
2492
+ writer.writeUint(box.channelcount, 2);
2493
+ writer.writeUint(box.samplesize, 2);
2494
+ writer.writeUint(box.preDefined, 2);
2495
+ writer.writeUint(box.reserved3, 2);
2496
+ writer.writeTemplate(box.samplerate, 4);
2497
+ writer.writeBytes(box.esds);
2498
+ return writer;
797
2499
  }
798
2500
 
799
2501
  //#endregion
800
- //#region src/parsers/enca.ts
801
- /**
802
- * Parse an AudioSampleEntry from an IsoView
803
- *
804
- * @param view - The IsoView to read data from
2502
+ //#region src/writers/writeEncv.ts
2503
+ /**
2504
+ * Write a VisualSampleEntryBox (encv) to an IsoDataWriter.
805
2505
  *
806
- * @returns A parsed AudioSampleEntry
2506
+ * @param box - The VisualSampleEntryBox fields to write
807
2507
  *
2508
+ * @returns An IsoDataWriter containing the encoded box
808
2509
  *
809
- * @beta
2510
+ * @public
810
2511
  */
811
- function enca(view) {
812
- return mp4a(view);
2512
+ function writeEncv(box) {
2513
+ return writeVisualSampleEntryBox(box, "encv");
813
2514
  }
814
2515
 
815
2516
  //#endregion
816
- //#region src/parsers/encv.ts
2517
+ //#region src/writers/writeFree.ts
817
2518
  /**
818
- * Parse a VisualSampleEntryBox from an IsoView
2519
+ * Write a FreeSpaceBox to an IsoDataWriter.
819
2520
  *
820
- * @param view - The IsoView to read data from
2521
+ * ISO/IEC 14496-12:2012 - 8.1.2 Free Space Box
821
2522
  *
822
- * @returns A parsed VisualSampleEntryBox
2523
+ * @param box - The FreeSpaceBox fields to write
823
2524
  *
2525
+ * @returns An IsoDataWriter containing the encoded box
824
2526
  *
825
- * @beta
2527
+ * @public
826
2528
  */
827
- function encv(view) {
828
- return avc1(view);
2529
+ function writeFree(box) {
2530
+ const writer = new IsoBoxWriteView("free", 8 + box.data.length);
2531
+ writer.writeBytes(box.data);
2532
+ return writer;
829
2533
  }
830
2534
 
831
2535
  //#endregion
832
- //#region src/parsers/free.ts
2536
+ //#region src/writers/writeFrma.ts
833
2537
  /**
834
- * Parse a Box from an IsoView
2538
+ * Write an OriginalFormatBox to an IsoDataWriter.
835
2539
  *
836
- * @param view - The IsoView to read data from
2540
+ * ISO/IEC 14496-12:2012 - 8.12.2 Original Format Box
837
2541
  *
838
- * @returns A parsed Box
2542
+ * @param box - The OriginalFormatBox fields to write
839
2543
  *
2544
+ * @returns An IsoDataWriter containing the encoded box
840
2545
  *
841
- * @beta
2546
+ * @public
842
2547
  */
843
- function free(view) {
844
- return { data: view.readData(-1) };
2548
+ function writeFrma(box) {
2549
+ const writer = new IsoBoxWriteView("frma", 12);
2550
+ writer.writeUint(box.dataFormat, 4);
2551
+ return writer;
845
2552
  }
846
2553
 
847
2554
  //#endregion
848
- //#region src/parsers/frma.ts
2555
+ //#region src/writers/writeFtyp.ts
849
2556
  /**
850
- * Parse an OriginalFormatBox from an IsoView
2557
+ * Write a FileTypeBox to an IsoDataWriter.
851
2558
  *
852
- * @param view - The IsoView to read data from
2559
+ * ISO/IEC 14496-12:2012 - 4.3 File Type Box
853
2560
  *
854
- * @returns A parsed OriginalFormatBox
2561
+ * @param box - The FileTypeBox fields to write
855
2562
  *
2563
+ * @returns An IsoDataWriter containing the encoded box
856
2564
  *
857
- * @beta
2565
+ * @public
858
2566
  */
859
- function frma(view) {
860
- return { dataFormat: view.readUint(4) };
2567
+ function writeFtyp(box) {
2568
+ const headerSize = 8;
2569
+ const majorBrandSize = 4;
2570
+ const minorVersionSize = 4;
2571
+ const compatibleBrandsSize = box.compatibleBrands.length * 4;
2572
+ const writer = new IsoBoxWriteView("ftyp", headerSize + majorBrandSize + minorVersionSize + compatibleBrandsSize);
2573
+ writer.writeString(box.majorBrand);
2574
+ writer.writeUint(box.minorVersion, 4);
2575
+ for (const brand of box.compatibleBrands) writer.writeString(brand);
2576
+ return writer;
861
2577
  }
862
2578
 
863
2579
  //#endregion
864
- //#region src/parsers/ftyp.ts
2580
+ //#region src/writers/writeHdlr.ts
865
2581
  /**
866
- * Parse a FileTypeBox from an IsoView
2582
+ * Write a HandlerReferenceBox to an IsoDataWriter.
867
2583
  *
868
- * @param view - The IsoView to read data from
2584
+ * ISO/IEC 14496-12:2012 - 8.4.3 Handler Reference Box
869
2585
  *
870
- * @returns A parsed FileTypeBox
2586
+ * @param box - The HandlerReferenceBox fields to write
871
2587
  *
2588
+ * @returns An IsoDataWriter containing the encoded box
872
2589
  *
873
- * @beta
2590
+ * @public
874
2591
  */
875
- function ftyp(view) {
876
- const size = 4;
877
- const majorBrand = view.readString(4);
878
- const minorVersion = view.readUint(4);
879
- const length = view.bytesRemaining / size;
880
- return {
881
- majorBrand,
882
- minorVersion,
883
- compatibleBrands: view.readArray(STRING, size, length)
884
- };
2592
+ function writeHdlr(box) {
2593
+ const headerSize = 8;
2594
+ const fullBoxSize = 4;
2595
+ const preDefinedSize = 4;
2596
+ const handlerTypeSize = 4;
2597
+ const reservedSize = 12;
2598
+ const nameSize = box.name.length + 1;
2599
+ const writer = new IsoBoxWriteView("hdlr", headerSize + fullBoxSize + preDefinedSize + handlerTypeSize + reservedSize + nameSize);
2600
+ writer.writeFullBox(box.version, box.flags);
2601
+ writer.writeUint(box.preDefined, 4);
2602
+ writer.writeString(box.handlerType);
2603
+ writer.writeArray(box.reserved, UINT, 4, 3);
2604
+ writer.writeTerminatedString(box.name);
2605
+ return writer;
885
2606
  }
886
2607
 
887
2608
  //#endregion
888
- //#region src/parsers/hdlr.ts
2609
+ //#region src/writers/writeHev1.ts
889
2610
  /**
890
- * Parse a HandlerReferenceBox from an IsoView
2611
+ * Write a VisualSampleEntryBox (hev1) to an IsoDataWriter.
891
2612
  *
892
- * @param view - The IsoView to read data from
893
- *
894
- * @returns A parsed HandlerReferenceBox
2613
+ * @param box - The VisualSampleEntryBox fields to write
895
2614
  *
2615
+ * @returns An IsoDataWriter containing the encoded box
896
2616
  *
897
- * @beta
2617
+ * @public
898
2618
  */
899
- function hdlr(view) {
900
- return {
901
- ...view.readFullBox(),
902
- preDefined: view.readUint(4),
903
- handlerType: view.readString(4),
904
- reserved: view.readArray(UINT, 4, 3),
905
- name: view.readString(-1)
906
- };
2619
+ function writeHev1(box) {
2620
+ return writeVisualSampleEntryBox(box, "hev1");
907
2621
  }
908
2622
 
909
2623
  //#endregion
910
- //#region src/parsers/hev1.ts
2624
+ //#region src/writers/writeHvc1.ts
911
2625
  /**
912
- * Parse a VisualSampleEntryBox from an IsoView
913
- *
914
- * @param view - The IsoView to read data from
2626
+ * Write a VisualSampleEntryBox (hvc1) to an IsoDataWriter.
915
2627
  *
916
- * @returns A parsed VisualSampleEntryBox
2628
+ * @param box - The VisualSampleEntryBox fields to write
917
2629
  *
2630
+ * @returns An IsoDataWriter containing the encoded box
918
2631
  *
919
- * @beta
2632
+ * @public
920
2633
  */
921
- function hev1(view) {
922
- return avc1(view);
2634
+ function writeHvc1(box) {
2635
+ return writeVisualSampleEntryBox(box, "hvc1");
923
2636
  }
924
2637
 
925
2638
  //#endregion
926
- //#region src/parsers/hvc1.ts
2639
+ //#region src/writers/writeIden.ts
927
2640
  /**
928
- * Parse a VisualSampleEntryBox from an IsoView
929
- *
930
- * @param view - The IsoView to read data from
2641
+ * Write a WebVttCueIdBox to an IsoDataWriter.
931
2642
  *
932
- * @returns A parsed VisualSampleEntryBox
2643
+ * @param box - The WebVttCueIdBox fields to write
933
2644
  *
2645
+ * @returns An IsoDataWriter containing the encoded box
934
2646
  *
935
- * @beta
2647
+ * @public
936
2648
  */
937
- function hvc1(view) {
938
- return avc1(view);
2649
+ function writeIden(box) {
2650
+ const writer = new IsoBoxWriteView("iden", 8 + (encodeText(box.cueId).length + 1));
2651
+ writer.writeUtf8TerminatedString(box.cueId);
2652
+ return writer;
939
2653
  }
940
2654
 
941
2655
  //#endregion
942
- //#region src/parsers/iden.ts
2656
+ //#region src/writers/writeImda.ts
943
2657
  /**
944
- * Parse a WebVTTCueIdBox from an IsoView
945
- *
946
- * @param view - The IsoView to read data from
2658
+ * Write an IdentifiedMediaDataBox to an IsoDataWriter.
947
2659
  *
948
- * @returns A parsed WebVTTCueIdBox
2660
+ * @param box - The IdentifiedMediaDataBox fields to write
949
2661
  *
2662
+ * @returns An IsoDataWriter containing the encoded box
950
2663
  *
951
- * @beta
2664
+ * @public
952
2665
  */
953
- function iden(view) {
954
- return { cueId: view.readUtf8(-1) };
2666
+ function writeImda(box) {
2667
+ const headerSize = 8;
2668
+ const imdaIdentifierSize = 4;
2669
+ const dataSize = box.data.length;
2670
+ const writer = new IsoBoxWriteView("imda", headerSize + imdaIdentifierSize + dataSize);
2671
+ writer.writeUint(box.imdaIdentifier, 4);
2672
+ writer.writeBytes(box.data);
2673
+ return writer;
955
2674
  }
956
2675
 
957
2676
  //#endregion
958
- //#region src/parsers/imda.ts
2677
+ //#region src/writers/writeKind.ts
959
2678
  /**
960
- * Parse a IdentifiedMediaDataBox from an IsoView
961
- *
962
- * @param view - The IsoView to read data from
2679
+ * Write a TrackKindBox to an IsoDataWriter.
963
2680
  *
964
- * @returns A parsed IdentifiedMediaDataBox
2681
+ * @param box - The TrackKindBox fields to write
965
2682
  *
2683
+ * @returns An IsoDataWriter containing the encoded box
966
2684
  *
967
- * @beta
2685
+ * @public
968
2686
  */
969
- function imda(view) {
970
- return {
971
- imdaIdentifier: view.readUint(4),
972
- data: view.readData(-1)
973
- };
2687
+ function writeKind(box) {
2688
+ const schemeUriBytes = encodeText(box.schemeUri);
2689
+ const valueBytes = encodeText(box.value);
2690
+ const headerSize = 8;
2691
+ const fullBoxSize = 4;
2692
+ const schemeUriSize = schemeUriBytes.length + 1;
2693
+ const valueSize = valueBytes.length + 1;
2694
+ const writer = new IsoBoxWriteView("kind", headerSize + fullBoxSize + schemeUriSize + valueSize);
2695
+ writer.writeFullBox(box.version, box.flags);
2696
+ writer.writeUtf8TerminatedString(box.schemeUri);
2697
+ writer.writeUtf8TerminatedString(box.value);
2698
+ return writer;
974
2699
  }
975
2700
 
976
2701
  //#endregion
977
- //#region src/parsers/kind.ts
2702
+ //#region src/writers/writeLabl.ts
978
2703
  /**
979
- * Parse a TrackKinBox from an IsoView
980
- *
981
- * @param view - The IsoView to read data from
2704
+ * Write a LabelBox to an IsoDataWriter.
982
2705
  *
983
- * @returns A parsed TrackKindBox
2706
+ * @param box - The LabelBox fields to write
984
2707
  *
2708
+ * @returns An IsoDataWriter containing the encoded box
985
2709
  *
986
- * @beta
2710
+ * @public
987
2711
  */
988
- function kind(view) {
989
- return {
990
- ...view.readFullBox(),
991
- schemeUri: view.readUtf8(-1),
992
- value: view.readUtf8(-1)
993
- };
2712
+ function writeLabl(box) {
2713
+ const languageBytes = encodeText(box.language);
2714
+ const labelBytes = encodeText(box.label);
2715
+ const headerSize = 8;
2716
+ const fullBoxSize = 4;
2717
+ const labelIdSize = 2;
2718
+ const languageSize = languageBytes.length + 1;
2719
+ const labelSize = labelBytes.length + 1;
2720
+ const writer = new IsoBoxWriteView("labl", headerSize + fullBoxSize + labelIdSize + languageSize + labelSize);
2721
+ writer.writeFullBox(box.version, box.flags);
2722
+ writer.writeUint(box.labelId, 2);
2723
+ writer.writeUtf8TerminatedString(box.language);
2724
+ writer.writeUtf8TerminatedString(box.label);
2725
+ return writer;
994
2726
  }
995
2727
 
996
2728
  //#endregion
997
- //#region src/parsers/labl.ts
2729
+ //#region src/writers/writeMdat.ts
998
2730
  /**
999
- * Parse a LabelBox from an IsoView
2731
+ * Write a MediaDataBox to an IsoDataWriter.
1000
2732
  *
1001
- * @param view - The IsoView to read data from
2733
+ * ISO/IEC 14496-12:2012 - 8.1.1 Media Data Box
1002
2734
  *
1003
- * @returns A parsed LabelBox
2735
+ * @param box - The MediaDataBox fields to write
1004
2736
  *
2737
+ * @returns An IsoDataWriter containing the encoded box
1005
2738
  *
1006
- * @beta
2739
+ * @public
1007
2740
  */
1008
- function labl(view) {
1009
- const { version, flags } = view.readFullBox();
1010
- return {
1011
- version,
1012
- flags,
1013
- isGroupLabel: (flags & 1) !== 0,
1014
- labelId: view.readUint(2),
1015
- language: view.readUtf8(-1),
1016
- label: view.readUtf8(-1)
1017
- };
2741
+ function writeMdat(box) {
2742
+ const writer = new IsoBoxWriteView("mdat", 8 + box.data.length);
2743
+ writer.writeBytes(box.data);
2744
+ return writer;
1018
2745
  }
1019
2746
 
1020
2747
  //#endregion
1021
- //#region src/parsers/mdat.ts
2748
+ //#region src/writers/writeMdhd.ts
1022
2749
  /**
1023
- * Parse a MediaDataBox from an IsoView
2750
+ * Write a MediaHeaderBox to an IsoDataWriter.
1024
2751
  *
1025
- * @param view - The IsoView to read data from
2752
+ * ISO/IEC 14496-12:2012 - 8.4.2 Media Header Box
1026
2753
  *
1027
- * @returns A parsed MediaDataBox
2754
+ * @param box - The MediaHeaderBox fields to write
1028
2755
  *
2756
+ * @returns An IsoDataWriter containing the encoded box
1029
2757
  *
1030
- * @beta
2758
+ * @public
1031
2759
  */
1032
- function mdat(view) {
1033
- return { data: view.readData(-1) };
2760
+ function writeMdhd(box) {
2761
+ const size = box.version === 1 ? 8 : 4;
2762
+ const headerSize = 8;
2763
+ const fullBoxSize = 4;
2764
+ const timesSize = size * 3;
2765
+ const writer = new IsoBoxWriteView("mdhd", headerSize + fullBoxSize + timesSize + 4 + 2 + 2);
2766
+ writer.writeFullBox(box.version, box.flags);
2767
+ writer.writeUint(box.creationTime, size);
2768
+ writer.writeUint(box.modificationTime, size);
2769
+ writer.writeUint(box.timescale, 4);
2770
+ writer.writeUint(box.duration, size);
2771
+ const lang = box.language.length >= 3 ? (box.language.charCodeAt(0) - 96 & 31) << 10 | (box.language.charCodeAt(1) - 96 & 31) << 5 | box.language.charCodeAt(2) - 96 & 31 : 0;
2772
+ writer.writeUint(lang, 2);
2773
+ writer.writeUint(box.preDefined, 2);
2774
+ return writer;
1034
2775
  }
1035
2776
 
1036
2777
  //#endregion
1037
- //#region src/parsers/mdhd.ts
2778
+ //#region src/writers/writeMehd.ts
1038
2779
  /**
1039
- * Parse a MediaHeaderBox from an IsoView
2780
+ * Write a MovieExtendsHeaderBox to an IsoDataWriter.
1040
2781
  *
1041
- * @param view - The IsoView to read data from
2782
+ * ISO/IEC 14496-12:2012 - 8.8.2 Movie Extends Header Box
1042
2783
  *
1043
- * @returns A parsed MediaHeaderBox
2784
+ * @param box - The MovieExtendsHeaderBox fields to write
1044
2785
  *
2786
+ * @returns An IsoDataWriter containing the encoded box
1045
2787
  *
1046
- * @beta
2788
+ * @public
1047
2789
  */
1048
- function mdhd(view) {
1049
- const { version, flags } = view.readFullBox();
1050
- const creationTime = view.readUint(version == 1 ? 8 : 4);
1051
- const modificationTime = view.readUint(version == 1 ? 8 : 4);
1052
- const timescale = view.readUint(4);
1053
- const duration = view.readUint(version == 1 ? 8 : 4);
1054
- const lang = view.readUint(2);
1055
- return {
1056
- version,
1057
- flags,
1058
- creationTime,
1059
- modificationTime,
1060
- timescale,
1061
- duration,
1062
- language: String.fromCharCode((lang >> 10 & 31) + 96, (lang >> 5 & 31) + 96, (lang & 31) + 96),
1063
- preDefined: view.readUint(2)
1064
- };
2790
+ function writeMehd(box) {
2791
+ const size = box.version === 1 ? 8 : 4;
2792
+ const headerSize = 8;
2793
+ const fullBoxSize = 4;
2794
+ const fragmentDurationSize = size;
2795
+ const writer = new IsoBoxWriteView("mehd", headerSize + fullBoxSize + fragmentDurationSize);
2796
+ writer.writeFullBox(box.version, box.flags);
2797
+ writer.writeUint(box.fragmentDuration, size);
2798
+ return writer;
1065
2799
  }
1066
2800
 
1067
2801
  //#endregion
1068
- //#region src/parsers/mehd.ts
2802
+ //#region src/writers/writeMeta.ts
1069
2803
  /**
1070
- * Parse a MovieExtendsHeaderBox from an IsoView
2804
+ * Write a MetaBox to an IsoDataWriter.
1071
2805
  *
1072
- * @param view - The IsoView to read data from
2806
+ * ISO/IEC 14496-12:2012 - 8.11.1 Meta Box
1073
2807
  *
1074
- * @returns A parsed MovieExtendsHeaderBox
2808
+ * @param box - The MetaBox fields to write
1075
2809
  *
2810
+ * @returns An IsoDataWriter containing the encoded box
1076
2811
  *
1077
- * @beta
2812
+ * @public
1078
2813
  */
1079
- function mehd(view) {
1080
- const { version, flags } = view.readFullBox();
1081
- return {
1082
- version,
1083
- flags,
1084
- fragmentDuration: view.readUint(version === 1 ? 8 : 4)
1085
- };
2814
+ function writeMeta(box) {
2815
+ const writer = new IsoBoxWriteView("meta", 12);
2816
+ writer.writeFullBox(box.version, box.flags);
2817
+ return writer;
1086
2818
  }
1087
2819
 
1088
2820
  //#endregion
1089
- //#region src/parsers/meta.ts
2821
+ //#region src/writers/writeMfhd.ts
1090
2822
  /**
1091
- * Parse a MetaBox from an IsoView
2823
+ * Write a MovieFragmentHeaderBox to an IsoDataWriter.
1092
2824
  *
1093
- * @param view - The IsoView to read data from
2825
+ * ISO/IEC 14496-12:2012 - 8.8.5 Movie Fragment Header Box
1094
2826
  *
1095
- * @returns A parsed MetaBox
2827
+ * @param box - The MovieFragmentHeaderBox fields to write
1096
2828
  *
2829
+ * @returns An IsoDataWriter containing the encoded box
1097
2830
  *
1098
- * @beta
2831
+ * @public
1099
2832
  */
1100
- function meta(view) {
1101
- return view.readFullBox();
2833
+ function writeMfhd(box) {
2834
+ const writer = new IsoBoxWriteView("mfhd", 16);
2835
+ writer.writeFullBox(box.version, box.flags);
2836
+ writer.writeUint(box.sequenceNumber, 4);
2837
+ return writer;
1102
2838
  }
1103
2839
 
1104
2840
  //#endregion
1105
- //#region src/parsers/mfhd.ts
2841
+ //#region src/writers/writeMfro.ts
1106
2842
  /**
1107
- * Parse a MovieFragmentHeaderBox from an IsoView
2843
+ * Write a MovieFragmentRandomAccessOffsetBox to an IsoDataWriter.
1108
2844
  *
1109
- * @param view - The IsoView to read data from
2845
+ * ISO/IEC 14496-12:2012 - 8.8.11 Movie Fragment Random Access Offset Box
1110
2846
  *
1111
- * @returns A parsed MovieFragmentHeaderBox
2847
+ * @param box - The MovieFragmentRandomAccessOffsetBox fields to write
1112
2848
  *
2849
+ * @returns An IsoDataWriter containing the encoded box
1113
2850
  *
1114
- * @beta
2851
+ * @public
1115
2852
  */
1116
- function mfhd(view) {
1117
- return {
1118
- ...view.readFullBox(),
1119
- sequenceNumber: view.readUint(4)
1120
- };
2853
+ function writeMfro(box) {
2854
+ const writer = new IsoBoxWriteView("mfro", 16);
2855
+ writer.writeFullBox(box.version, box.flags);
2856
+ writer.writeUint(box.mfraSize, 4);
2857
+ return writer;
1121
2858
  }
1122
2859
 
1123
2860
  //#endregion
1124
- //#region src/parsers/mfro.ts
2861
+ //#region src/writers/writeMp4a.ts
1125
2862
  /**
1126
- * Parse a MovieFragmentRandomAccessBox from an IsoView
2863
+ * Write an AudioSampleEntryBox to an IsoDataWriter.
1127
2864
  *
1128
- * @param view - The IsoView to read data from
2865
+ * ISO/IEC 14496-12:2012 - 12.2.3 Audio Sample Entry
1129
2866
  *
1130
- * @returns A parsed MovieFragmentRandomAccessBox
2867
+ * @param box - The AudioSampleEntryBox fields to write
1131
2868
  *
2869
+ * @returns An IsoDataWriter containing the encoded box
1132
2870
  *
1133
- * @beta
2871
+ * @public
1134
2872
  */
1135
- function mfro(view) {
1136
- return {
1137
- ...view.readFullBox(),
1138
- mfraSize: view.readUint(4)
1139
- };
2873
+ function writeMp4a(box) {
2874
+ const headerSize = 8;
2875
+ const reserved1Size = 6;
2876
+ const dataReferenceIndexSize = 2;
2877
+ const reserved2Size = 8;
2878
+ const channelcountSize = 2;
2879
+ const samplesizeSize = 2;
2880
+ const preDefinedSize = 2;
2881
+ const reserved3Size = 2;
2882
+ const samplerateSize = 4;
2883
+ const esdsSize = box.esds.length;
2884
+ const writer = new IsoBoxWriteView("mp4a", headerSize + reserved1Size + dataReferenceIndexSize + reserved2Size + channelcountSize + samplesizeSize + preDefinedSize + reserved3Size + samplerateSize + esdsSize);
2885
+ writer.writeArray(box.reserved1, UINT, 1, 6);
2886
+ writer.writeUint(box.dataReferenceIndex, 2);
2887
+ writer.writeArray(box.reserved2, UINT, 4, 2);
2888
+ writer.writeUint(box.channelcount, 2);
2889
+ writer.writeUint(box.samplesize, 2);
2890
+ writer.writeUint(box.preDefined, 2);
2891
+ writer.writeUint(box.reserved3, 2);
2892
+ writer.writeTemplate(box.samplerate, 4);
2893
+ writer.writeBytes(box.esds);
2894
+ return writer;
1140
2895
  }
1141
2896
 
1142
2897
  //#endregion
1143
- //#region src/parsers/mvhd.ts
2898
+ //#region src/writers/writeMvhd.ts
1144
2899
  /**
1145
- * Parse a Box from an IsoView
2900
+ * Write a MovieHeaderBox to an IsoDataWriter.
1146
2901
  *
1147
- * @param view - The IsoView to read data from
2902
+ * ISO/IEC 14496-12:2012 - 8.2.2 Movie Header Box
1148
2903
  *
1149
- * @returns A parsed Box
2904
+ * @param box - The MovieHeaderBox fields to write
1150
2905
  *
2906
+ * @returns An IsoDataWriter containing the encoded box
1151
2907
  *
1152
- * @beta
2908
+ * @public
1153
2909
  */
1154
- function mvhd(view) {
1155
- const { readUint: readUint$1, readTemplate: readTemplate$1, readArray } = view;
1156
- const { version, flags } = view.readFullBox();
1157
- const size = version == 1 ? 8 : 4;
1158
- return {
1159
- version,
1160
- flags,
1161
- creationTime: readUint$1(size),
1162
- modificationTime: readUint$1(size),
1163
- timescale: readUint$1(4),
1164
- duration: readUint$1(size),
1165
- rate: readTemplate$1(4),
1166
- volume: readTemplate$1(2),
1167
- reserved1: readUint$1(2),
1168
- reserved2: readArray(UINT, 4, 2),
1169
- matrix: readArray(UINT, 4, 9),
1170
- preDefined: readArray(UINT, 4, 6),
1171
- nextTrackId: readUint$1(4)
1172
- };
2910
+ function writeMvhd(box) {
2911
+ const size = box.version === 1 ? 8 : 4;
2912
+ const headerSize = 8;
2913
+ const fullBoxSize = 4;
2914
+ const timesSize = size * 3;
2915
+ const writer = new IsoBoxWriteView("mvhd", headerSize + fullBoxSize + timesSize + 4 + 4 + 2 + 2 + 8 + 36 + 24 + 4);
2916
+ writer.writeFullBox(box.version, box.flags);
2917
+ writer.writeUint(box.creationTime, size);
2918
+ writer.writeUint(box.modificationTime, size);
2919
+ writer.writeUint(box.timescale, 4);
2920
+ writer.writeUint(box.duration, size);
2921
+ writer.writeTemplate(box.rate, 4);
2922
+ writer.writeTemplate(box.volume, 2);
2923
+ writer.writeUint(box.reserved1, 2);
2924
+ writer.writeArray(box.reserved2, UINT, 4, 2);
2925
+ writer.writeArray(box.matrix, TEMPLATE, 4, 9);
2926
+ writer.writeArray(box.preDefined, UINT, 4, 6);
2927
+ writer.writeUint(box.nextTrackId, 4);
2928
+ return writer;
1173
2929
  }
1174
2930
 
1175
2931
  //#endregion
1176
- //#region src/parsers/payl.ts
2932
+ //#region src/writers/writePayl.ts
1177
2933
  /**
1178
- * Parse a WebVTTCuePayloadBox from an IsoView
2934
+ * Write a WebVttCuePayloadBox to an IsoDataWriter.
1179
2935
  *
1180
- * @param view - The IsoView to read data from
1181
- *
1182
- * @returns A parsed WebVTTCuePayloadBox
2936
+ * @param box - The WebVttCuePayloadBox fields to write
1183
2937
  *
2938
+ * @returns An IsoDataWriter containing the encoded box
1184
2939
  *
1185
- * @beta
2940
+ * @public
1186
2941
  */
1187
- function payl(view) {
1188
- return { cueText: view.readUtf8(-1) };
2942
+ function writePayl(box) {
2943
+ const writer = new IsoBoxWriteView("payl", 8 + (encodeText(box.cueText).length + 1));
2944
+ writer.writeUtf8TerminatedString(box.cueText);
2945
+ return writer;
1189
2946
  }
1190
2947
 
1191
2948
  //#endregion
1192
- //#region src/parsers/prft.ts
2949
+ //#region src/writers/writePrft.ts
1193
2950
  /**
1194
- * Parse a ProducerReferenceTimeBox from an IsoView
2951
+ * Write a ProducerReferenceTimeBox to an IsoDataWriter.
1195
2952
  *
1196
- * @param view - The IsoView to read data from
2953
+ * ISO/IEC 14496-12:2012 - 8.16.5 Producer Reference Time Box
1197
2954
  *
1198
- * @returns A parsed ProducerReferenceTimeBox
2955
+ * @param box - The ProducerReferenceTimeBox fields to write
1199
2956
  *
2957
+ * @returns An IsoDataWriter containing the encoded box
1200
2958
  *
1201
- * @beta
2959
+ * @public
1202
2960
  */
1203
- function prft(view) {
1204
- const { version, flags } = view.readFullBox();
1205
- return {
1206
- version,
1207
- flags,
1208
- referenceTrackId: view.readUint(4),
1209
- ntpTimestampSec: view.readUint(4),
1210
- ntpTimestampFrac: view.readUint(4),
1211
- mediaTime: view.readUint(version === 1 ? 8 : 4)
1212
- };
2961
+ function writePrft(box) {
2962
+ const mediaTimeSize = box.version === 1 ? 8 : 4;
2963
+ const writer = new IsoBoxWriteView("prft", 24 + mediaTimeSize);
2964
+ writer.writeFullBox(box.version, box.flags);
2965
+ writer.writeUint(box.referenceTrackId, 4);
2966
+ writer.writeUint(box.ntpTimestampSec, 4);
2967
+ writer.writeUint(box.ntpTimestampFrac, 4);
2968
+ writer.writeUint(box.mediaTime, mediaTimeSize);
2969
+ return writer;
1213
2970
  }
1214
2971
 
1215
2972
  //#endregion
1216
- //#region src/parsers/prsl.ts
2973
+ //#region src/writers/writePrsl.ts
1217
2974
  /**
1218
- * Parse a PreselectionGroupBox from an IsoView
2975
+ * Write a PreselectionGroupBox to an IsoDataWriter.
1219
2976
  *
1220
- * @param view - The IsoView to read data from
1221
- *
1222
- * @returns A parsed PreselectionGroupBox
2977
+ * @param box - The PreselectionGroupBox fields to write
1223
2978
  *
2979
+ * @returns An IsoDataWriter containing the encoded box
1224
2980
  *
1225
- * @beta
2981
+ * @public
1226
2982
  */
1227
- function prsl(view) {
1228
- const { version, flags } = view.readFullBox();
1229
- const groupId = view.readUint(4);
1230
- const numEntitiesInGroup = view.readUint(4);
1231
- return {
1232
- version,
1233
- flags,
1234
- groupId,
1235
- numEntitiesInGroup,
1236
- entities: view.readEntries(numEntitiesInGroup, () => ({ entityId: view.readUint(4) })),
1237
- preselectionTag: flags & 4096 ? view.readUtf8(-1) : void 0,
1238
- selectionPriority: flags & 8192 ? view.readUint(1) : void 0,
1239
- interleavingTag: flags & 16384 ? view.readUtf8(-1) : void 0
1240
- };
2983
+ function writePrsl(box) {
2984
+ const preselectionTagBytes = box.flags & 4096 && box.preselectionTag ? encodeText(box.preselectionTag) : null;
2985
+ const interleavingTagBytes = box.flags & 16384 && box.interleavingTag ? encodeText(box.interleavingTag) : null;
2986
+ const headerSize = 8;
2987
+ const fullBoxSize = 4;
2988
+ const groupIdSize = 4;
2989
+ const numEntitiesInGroupSize = 4;
2990
+ const entitiesSize = box.numEntitiesInGroup * 4;
2991
+ const preselectionTagSize = preselectionTagBytes ? preselectionTagBytes.length + 1 : 0;
2992
+ const selectionPrioritySize = box.flags & 8192 ? 1 : 0;
2993
+ const interleavingTagSize = interleavingTagBytes ? interleavingTagBytes.length + 1 : 0;
2994
+ const writer = new IsoBoxWriteView("prsl", headerSize + fullBoxSize + groupIdSize + numEntitiesInGroupSize + entitiesSize + preselectionTagSize + selectionPrioritySize + interleavingTagSize);
2995
+ writer.writeFullBox(box.version, box.flags);
2996
+ writer.writeUint(box.groupId, 4);
2997
+ writer.writeUint(box.numEntitiesInGroup, 4);
2998
+ for (const entity of box.entities) writer.writeUint(entity.entityId, 4);
2999
+ if (preselectionTagBytes && box.preselectionTag) writer.writeUtf8TerminatedString(box.preselectionTag);
3000
+ if (box.flags & 8192) writer.writeUint(box.selectionPriority ?? 0, 1);
3001
+ if (interleavingTagBytes && box.interleavingTag) writer.writeUtf8TerminatedString(box.interleavingTag);
3002
+ return writer;
1241
3003
  }
1242
3004
 
1243
3005
  //#endregion
1244
- //#region src/parsers/pssh.ts
3006
+ //#region src/writers/writePssh.ts
1245
3007
  /**
1246
- * Parse a ProtectionSystemSpecificHeaderBox from an IsoView
3008
+ * Write a ProtectionSystemSpecificHeaderBox to an IsoDataWriter.
1247
3009
  *
1248
- * @param view - The IsoView to read data from
3010
+ * ISO/IEC 23001-7 - 8.1 Protection System Specific Header Box
1249
3011
  *
1250
- * @returns A parsed ProtectionSystemSpecificHeaderBox
3012
+ * @param box - The ProtectionSystemSpecificHeaderBox fields to write
1251
3013
  *
3014
+ * @returns An IsoDataWriter containing the encoded box
1252
3015
  *
1253
- * @beta
3016
+ * @public
1254
3017
  */
1255
- function pssh(view) {
1256
- const { readUint: readUint$1, readArray } = view;
1257
- const { version, flags } = view.readFullBox();
1258
- const systemId = readArray(UINT, 1, 16);
1259
- let kidCount = 0;
1260
- let kid = [];
1261
- if (version > 0) {
1262
- kidCount = readUint$1(4);
1263
- kid = readArray(UINT, 1, kidCount);
3018
+ function writePssh(box) {
3019
+ const headerSize = 8;
3020
+ const fullBoxSize = 4;
3021
+ const systemIdSize = 16;
3022
+ const kidCountSize = box.version > 0 ? 4 : 0;
3023
+ const kidSize = box.version > 0 ? box.kidCount * 16 : 0;
3024
+ const dataSizeField = 4;
3025
+ const dataSize = box.dataSize;
3026
+ const writer = new IsoBoxWriteView("pssh", headerSize + fullBoxSize + systemIdSize + kidCountSize + kidSize + dataSizeField + dataSize);
3027
+ writer.writeFullBox(box.version, box.flags);
3028
+ writer.writeArray(box.systemId, UINT, 1, 16);
3029
+ if (box.version > 0) {
3030
+ writer.writeUint(box.kidCount, 4);
3031
+ writer.writeArray(box.kid, UINT, 1, box.kidCount);
1264
3032
  }
1265
- const dataSize = readUint$1(4);
1266
- const data = readArray(UINT, 1, dataSize);
1267
- return {
1268
- version,
1269
- flags,
1270
- systemId,
1271
- kidCount,
1272
- kid,
1273
- dataSize,
1274
- data
1275
- };
3033
+ writer.writeUint(box.dataSize, 4);
3034
+ writer.writeArray(box.data, UINT, 1, box.dataSize);
3035
+ return writer;
1276
3036
  }
1277
3037
 
1278
3038
  //#endregion
1279
- //#region src/parsers/schm.ts
3039
+ //#region src/writers/writeSchm.ts
1280
3040
  /**
1281
- * Parse a SchemeTypeBox from an IsoView
3041
+ * Write a SchemeTypeBox to an IsoDataWriter.
1282
3042
  *
1283
- * @param view - The IsoView to read data from
3043
+ * ISO/IEC 14496-12:2012 - 8.12.5 Scheme Type Box
1284
3044
  *
1285
- * @returns A parsed SchemeTypeBox
3045
+ * @param box - The SchemeTypeBox fields to write
1286
3046
  *
3047
+ * @returns An IsoDataWriter containing the encoded box
1287
3048
  *
1288
- * @beta
3049
+ * @public
1289
3050
  */
1290
- function schm(view) {
1291
- const { version, flags } = view.readFullBox();
1292
- return {
1293
- version,
1294
- flags,
1295
- schemeType: view.readUint(4),
1296
- schemeVersion: view.readUint(4),
1297
- schemeUri: flags & 1 ? view.readString(-1) : void 0
1298
- };
3051
+ function writeSchm(box) {
3052
+ const headerSize = 8;
3053
+ const fullBoxSize = 4;
3054
+ const schemeTypeSize = 4;
3055
+ const schemeVersionSize = 4;
3056
+ const schemeUriSize = box.flags & 1 && box.schemeUri ? box.schemeUri.length + 1 : 0;
3057
+ const writer = new IsoBoxWriteView("schm", headerSize + fullBoxSize + schemeTypeSize + schemeVersionSize + schemeUriSize);
3058
+ writer.writeFullBox(box.version, box.flags);
3059
+ writer.writeUint(box.schemeType, 4);
3060
+ writer.writeUint(box.schemeVersion, 4);
3061
+ if (box.flags & 1 && box.schemeUri) writer.writeTerminatedString(box.schemeUri);
3062
+ return writer;
1299
3063
  }
1300
3064
 
1301
3065
  //#endregion
1302
- //#region src/parsers/sdtp.ts
3066
+ //#region src/writers/writeSdtp.ts
1303
3067
  /**
1304
- * Parse a SampleDependencyTypeBox from an IsoView
3068
+ * Write a SampleDependencyTypeBox to an IsoDataWriter.
1305
3069
  *
1306
- * @param view - The IsoView to read data from
3070
+ * ISO/IEC 14496-12:2012 - 8.6.4 Independent and Disposable Samples Box
1307
3071
  *
1308
- * @returns A parsed SampleDependencyTypeBox
3072
+ * @param box - The SampleDependencyTypeBox fields to write
1309
3073
  *
3074
+ * @returns An IsoDataWriter containing the encoded box
1310
3075
  *
1311
- * @beta
3076
+ * @public
1312
3077
  */
1313
- function sdtp(view) {
1314
- return {
1315
- ...view.readFullBox(),
1316
- sampleDependencyTable: view.readArray(UINT, 1, view.bytesRemaining)
1317
- };
3078
+ function writeSdtp(box) {
3079
+ const headerSize = 8;
3080
+ const fullBoxSize = 4;
3081
+ const sampleDependencyTableSize = box.sampleDependencyTable.length;
3082
+ const writer = new IsoBoxWriteView("sdtp", headerSize + fullBoxSize + sampleDependencyTableSize);
3083
+ writer.writeFullBox(box.version, box.flags);
3084
+ for (const entry of box.sampleDependencyTable) writer.writeUint(entry, 1);
3085
+ return writer;
1318
3086
  }
1319
3087
 
1320
3088
  //#endregion
1321
- //#region src/parsers/sidx.ts
3089
+ //#region src/writers/writeSidx.ts
1322
3090
  /**
1323
- * Parse a SegmentIndexBox from an IsoView
3091
+ * Write a SegmentIndexBox to an IsoDataWriter.
1324
3092
  *
1325
- * @param view - The IsoView to read data from
3093
+ * ISO/IEC 14496-12:2012 - 8.16.3 Segment Index Box
1326
3094
  *
1327
- * @returns A parsed SegmentIndexBox
3095
+ * @param box - The SegmentIndexBox fields to write
1328
3096
  *
3097
+ * @returns An IsoDataWriter containing the encoded box
1329
3098
  *
1330
- * @beta
3099
+ * @public
1331
3100
  */
1332
- function sidx(view) {
1333
- const { readUint: readUint$1 } = view;
1334
- const { version, flags } = view.readFullBox();
1335
- const size = version === 1 ? 8 : 4;
1336
- const referenceId = readUint$1(4);
1337
- const timescale = readUint$1(4);
1338
- const earliestPresentationTime = readUint$1(size);
1339
- const firstOffset = readUint$1(size);
1340
- const reserved = readUint$1(2);
1341
- const referenceCount = readUint$1(2);
1342
- return {
1343
- version,
1344
- flags,
1345
- referenceId,
1346
- timescale,
1347
- earliestPresentationTime,
1348
- firstOffset,
1349
- reserved,
1350
- references: view.readEntries(referenceCount, () => {
1351
- const entry = {};
1352
- entry.reference = readUint$1(4);
1353
- entry.subsegmentDuration = readUint$1(4);
1354
- entry.sap = readUint$1(4);
1355
- entry.referenceType = entry.reference >> 31 & 1;
1356
- entry.referencedSize = entry.reference & 2147483647;
1357
- entry.startsWithSap = entry.sap >> 31 & 1;
1358
- entry.sapType = entry.sap >> 28 & 7;
1359
- entry.sapDeltaTime = entry.sap & 268435455;
1360
- return entry;
1361
- })
1362
- };
3101
+ function writeSidx(box) {
3102
+ const size = box.version === 1 ? 8 : 4;
3103
+ const headerSize = 8;
3104
+ const fullBoxSize = 4;
3105
+ const referenceIdSize = 4;
3106
+ const timescaleSize = 4;
3107
+ const earliestPresentationTimeSize = size;
3108
+ const firstOffsetSize = size;
3109
+ const reservedSize = 2;
3110
+ const referenceCountSize = 2;
3111
+ const referencesSize = box.references.length * 12;
3112
+ const writer = new IsoBoxWriteView("sidx", headerSize + fullBoxSize + referenceIdSize + timescaleSize + earliestPresentationTimeSize + firstOffsetSize + reservedSize + referenceCountSize + referencesSize);
3113
+ writer.writeFullBox(box.version, box.flags);
3114
+ writer.writeUint(box.referenceId, 4);
3115
+ writer.writeUint(box.timescale, 4);
3116
+ writer.writeUint(box.earliestPresentationTime, size);
3117
+ writer.writeUint(box.firstOffset, size);
3118
+ writer.writeUint(box.reserved ?? 0, 2);
3119
+ writer.writeUint(box.references.length, 2);
3120
+ for (const ref of box.references) {
3121
+ const reference = (ref.referenceType & 1) << 31 | ref.referencedSize & 2147483647;
3122
+ writer.writeUint(reference, 4);
3123
+ writer.writeUint(ref.subsegmentDuration, 4);
3124
+ const sap = (ref.startsWithSap & 1) << 31 | (ref.sapType & 7) << 28 | ref.sapDeltaTime & 268435455;
3125
+ writer.writeUint(sap, 4);
3126
+ }
3127
+ return writer;
1363
3128
  }
1364
3129
 
1365
3130
  //#endregion
1366
- //#region src/parsers/skip.ts
3131
+ //#region src/writers/writeSkip.ts
1367
3132
  /**
1368
- * Parse a FreeSpaceBox from an IsoView
3133
+ * Write a FreeSpaceBox (skip variant) to an IsoDataWriter.
1369
3134
  *
1370
- * @param view - The IsoView to read data from
3135
+ * ISO/IEC 14496-12:2012 - 8.1.2 Free Space Box
1371
3136
  *
1372
- * @returns A parsed FreeSpaceBox
3137
+ * @param box - The FreeSpaceBox fields to write
1373
3138
  *
3139
+ * @returns An IsoDataWriter containing the encoded box
1374
3140
  *
1375
- * @beta
3141
+ * @public
1376
3142
  */
1377
- function skip(view) {
1378
- return free(view);
3143
+ function writeSkip(box) {
3144
+ const writer = new IsoBoxWriteView("skip", 8 + box.data.length);
3145
+ writer.writeBytes(box.data);
3146
+ return writer;
1379
3147
  }
1380
3148
 
1381
3149
  //#endregion
1382
- //#region src/parsers/smhd.ts
3150
+ //#region src/writers/writeSmhd.ts
1383
3151
  /**
1384
- * Parse a SoundMediaHeaderBox from an IsoView
3152
+ * Write a SoundMediaHeaderBox to an IsoDataWriter.
1385
3153
  *
1386
- * @param view - The IsoView to read data from
3154
+ * ISO/IEC 14496-12:2012 - 12.2.2 Sound Media Header Box
1387
3155
  *
1388
- * @returns A parsed SoundMediaHeaderBox
3156
+ * @param box - The SoundMediaHeaderBox fields to write
1389
3157
  *
3158
+ * @returns An IsoDataWriter containing the encoded box
1390
3159
  *
1391
- * @beta
3160
+ * @public
1392
3161
  */
1393
- function smhd(view) {
1394
- return {
1395
- ...view.readFullBox(),
1396
- balance: view.readUint(2),
1397
- reserved: view.readUint(2)
1398
- };
3162
+ function writeSmhd(box) {
3163
+ const writer = new IsoBoxWriteView("smhd", 16);
3164
+ writer.writeFullBox(box.version, box.flags);
3165
+ writer.writeUint(box.balance, 2);
3166
+ writer.writeUint(box.reserved, 2);
3167
+ return writer;
1399
3168
  }
1400
3169
 
1401
3170
  //#endregion
1402
- //#region src/parsers/ssix.ts
3171
+ //#region src/writers/writeSsix.ts
1403
3172
  /**
1404
- * Parse a SubsegmentIndexBox from an IsoView
3173
+ * Write a SubsegmentIndexBox to an IsoDataWriter.
1405
3174
  *
1406
- * @param view - The IsoView to read data from
3175
+ * ISO/IEC 14496-12:2012 - 8.16.4 Subsegment Index Box
1407
3176
  *
1408
- * @returns A parsed SubsegmentIndexBox
3177
+ * @param box - The SubsegmentIndexBox fields to write
1409
3178
  *
3179
+ * @returns An IsoDataWriter containing the encoded box
1410
3180
  *
1411
- * @beta
3181
+ * @public
1412
3182
  */
1413
- function ssix(view) {
1414
- const { version, flags } = view.readFullBox();
1415
- const subsegmentCount = view.readUint(4);
1416
- return {
1417
- version,
1418
- flags,
1419
- subsegmentCount,
1420
- subsegments: view.readEntries(subsegmentCount, () => {
1421
- const rangesCount = view.readUint(4);
1422
- return {
1423
- rangesCount,
1424
- ranges: view.readEntries(rangesCount, () => ({
1425
- level: view.readUint(1),
1426
- rangeSize: view.readUint(3)
1427
- }))
1428
- };
1429
- })
1430
- };
3183
+ function writeSsix(box) {
3184
+ const headerSize = 8;
3185
+ const fullBoxSize = 4;
3186
+ const subsegmentCountSize = 4;
3187
+ let rangesSize = 0;
3188
+ for (const subsegment of box.subsegments) {
3189
+ rangesSize += 4;
3190
+ rangesSize += subsegment.rangesCount * 4;
3191
+ }
3192
+ const writer = new IsoBoxWriteView("ssix", headerSize + fullBoxSize + subsegmentCountSize + rangesSize);
3193
+ writer.writeFullBox(box.version, box.flags);
3194
+ writer.writeUint(box.subsegmentCount, 4);
3195
+ for (const subsegment of box.subsegments) {
3196
+ writer.writeUint(subsegment.rangesCount, 4);
3197
+ for (const range of subsegment.ranges) {
3198
+ writer.writeUint(range.level, 1);
3199
+ writer.writeUint(range.rangeSize, 3);
3200
+ }
3201
+ }
3202
+ return writer;
1431
3203
  }
1432
3204
 
1433
3205
  //#endregion
1434
- //#region src/parsers/sthd.ts
3206
+ //#region src/writers/writeSthd.ts
1435
3207
  /**
1436
- * Parse a SubtitleMediaHeaderBox from an IsoView
3208
+ * Write a SubtitleMediaHeaderBox to an IsoDataWriter.
1437
3209
  *
1438
- * @param view - The IsoView to read data from
3210
+ * ISO/IEC 14496-12:2012 - 12.6.2 Subtitle Media Header Box
1439
3211
  *
1440
- * @returns A parsed SubtitleMediaHeaderBox
3212
+ * @param box - The SubtitleMediaHeaderBox fields to write
1441
3213
  *
3214
+ * @returns An IsoDataWriter containing the encoded box
1442
3215
  *
1443
- * @beta
3216
+ * @public
1444
3217
  */
1445
- function sthd(view) {
1446
- return view.readFullBox();
3218
+ function writeSthd(box) {
3219
+ const writer = new IsoBoxWriteView("sthd", 12);
3220
+ writer.writeFullBox(box.version, box.flags);
3221
+ return writer;
1447
3222
  }
1448
3223
 
1449
3224
  //#endregion
1450
- //#region src/parsers/stsd.ts
3225
+ //#region src/writers/writeStsd.ts
1451
3226
  /**
1452
- * Parse a SampleDescriptionBox from an IsoView
3227
+ * Write a SampleDescriptionBox to an IsoDataWriter.
1453
3228
  *
1454
- * @param view - The IsoView to read data from
1455
- *
1456
- * @returns A parsed SampleDescriptionBox
3229
+ * @param box - The SampleDescriptionBox fields to write
1457
3230
  *
3231
+ * @returns An IsoDataWriter containing the encoded box
1458
3232
  *
1459
- * @beta
3233
+ * @public
1460
3234
  */
1461
- function stsd(view) {
1462
- const { version, flags } = view.readFullBox();
1463
- const entryCount = view.readUint(4);
1464
- return {
1465
- version,
1466
- flags,
1467
- entryCount,
1468
- entries: view.readBoxes(entryCount)
1469
- };
3235
+ function writeStsd(box, config) {
3236
+ const headerSize = 8;
3237
+ const fullBoxSize = 4;
3238
+ const entryCountSize = 4;
3239
+ const entryCount = box.entries.length;
3240
+ const entries = writeIsoBoxes(box.entries, config);
3241
+ const entriesSize = entries.reduce((size, entry) => size + entry.byteLength, 0);
3242
+ const writer = new IsoBoxWriteView("stsd", headerSize + fullBoxSize + entryCountSize + entriesSize);
3243
+ writer.writeFullBox(box.version, box.flags);
3244
+ writer.writeUint(entryCount, 4);
3245
+ for (const entry of entries) writer.writeBytes(entry);
3246
+ return writer;
1470
3247
  }
1471
3248
 
1472
3249
  //#endregion
1473
- //#region src/parsers/stss.ts
3250
+ //#region src/writers/writeStss.ts
1474
3251
  /**
1475
- * Parse a SyncSampleBox from an IsoView
3252
+ * Write a SyncSampleBox to an IsoDataWriter.
1476
3253
  *
1477
- * @param view - The IsoView to read data from
3254
+ * ISO/IEC 14496-12:2012 - 8.6.2 Sync Sample Box
1478
3255
  *
1479
- * @returns A parsed SyncSampleBox
3256
+ * @param box - The SyncSampleBox fields to write
1480
3257
  *
3258
+ * @returns An IsoDataWriter containing the encoded box
1481
3259
  *
1482
- * @beta
3260
+ * @public
1483
3261
  */
1484
- function stss(view) {
1485
- const { version, flags } = view.readFullBox();
1486
- const entryCount = view.readUint(4);
1487
- return {
1488
- version,
1489
- flags,
1490
- entryCount,
1491
- entries: view.readEntries(entryCount, () => ({ sampleNumber: view.readUint(4) }))
1492
- };
3262
+ function writeStss(box) {
3263
+ const headerSize = 8;
3264
+ const fullBoxSize = 4;
3265
+ const entryCountSize = 4;
3266
+ const entriesSize = box.entryCount * 4;
3267
+ const writer = new IsoBoxWriteView("stss", headerSize + fullBoxSize + entryCountSize + entriesSize);
3268
+ writer.writeFullBox(box.version, box.flags);
3269
+ writer.writeUint(box.entryCount, 4);
3270
+ for (const entry of box.entries) writer.writeUint(entry.sampleNumber, 4);
3271
+ return writer;
1493
3272
  }
1494
3273
 
1495
3274
  //#endregion
1496
- //#region src/parsers/sttg.ts
3275
+ //#region src/writers/writeSttg.ts
1497
3276
  /**
1498
- * Parse a WebVTTSettingsBox from an IsoView
1499
- *
1500
- * @param view - The IsoView to read data from
3277
+ * Write a WebVttSettingsBox to an IsoDataWriter.
1501
3278
  *
1502
- * @returns A parsed WebVTTSettingsBox
3279
+ * @param box - The WebVttSettingsBox fields to write
1503
3280
  *
3281
+ * @returns An IsoDataWriter containing the encoded box
1504
3282
  *
1505
- * @beta
3283
+ * @public
1506
3284
  */
1507
- function sttg(view) {
1508
- return { settings: view.readUtf8(-1) };
3285
+ function writeSttg(box) {
3286
+ const writer = new IsoBoxWriteView("sttg", 8 + (encodeText(box.settings).length + 1));
3287
+ writer.writeUtf8TerminatedString(box.settings);
3288
+ return writer;
1509
3289
  }
1510
3290
 
1511
3291
  //#endregion
1512
- //#region src/parsers/stts.ts
3292
+ //#region src/writers/writeStts.ts
1513
3293
  /**
1514
- * Parse a DecodingTimeToSampleBox from an IsoView
3294
+ * Write a DecodingTimeToSampleBox to an IsoDataWriter.
1515
3295
  *
1516
- * @param view - The IsoView to read data from
3296
+ * ISO/IEC 14496-12:2012 - 8.6.1.2 Decoding Time to Sample Box
1517
3297
  *
1518
- * @returns A parsed DecodingTimeToSampleBox
3298
+ * @param box - The DecodingTimeToSampleBox fields to write
1519
3299
  *
3300
+ * @returns An IsoDataWriter containing the encoded box
1520
3301
  *
1521
- * @beta
3302
+ * @public
1522
3303
  */
1523
- function stts(view) {
1524
- const { version, flags } = view.readFullBox();
1525
- const entryCount = view.readUint(4);
1526
- return {
1527
- version,
1528
- flags,
1529
- entryCount,
1530
- entries: view.readEntries(entryCount, () => ({
1531
- sampleCount: view.readUint(4),
1532
- sampleDelta: view.readUint(4)
1533
- }))
1534
- };
3304
+ function writeStts(box) {
3305
+ const headerSize = 8;
3306
+ const fullBoxSize = 4;
3307
+ const entryCountSize = 4;
3308
+ const entriesSize = box.entryCount * 8;
3309
+ const writer = new IsoBoxWriteView("stts", headerSize + fullBoxSize + entryCountSize + entriesSize);
3310
+ writer.writeFullBox(box.version, box.flags);
3311
+ writer.writeUint(box.entryCount, 4);
3312
+ for (const entry of box.entries) {
3313
+ writer.writeUint(entry.sampleCount, 4);
3314
+ writer.writeUint(entry.sampleDelta, 4);
3315
+ }
3316
+ return writer;
1535
3317
  }
1536
3318
 
1537
3319
  //#endregion
1538
- //#region src/parsers/styp.ts
3320
+ //#region src/writers/writeStyp.ts
1539
3321
  /**
1540
- * Parse a SegmentTypeBox from an IsoView
3322
+ * Write a SegmentTypeBox to an IsoDataWriter.
1541
3323
  *
1542
- * @param view - The IsoView to read data from
3324
+ * ISO/IEC 14496-12:2012 - 8.16.2 Segment Type Box
1543
3325
  *
1544
- * @returns A parsed SegmentTypeBox
3326
+ * @param box - The SegmentTypeBox fields to write
1545
3327
  *
3328
+ * @returns An IsoDataWriter containing the encoded box
1546
3329
  *
1547
- * @beta
3330
+ * @public
1548
3331
  */
1549
- function styp(view) {
1550
- return ftyp(view);
3332
+ function writeStyp(box) {
3333
+ const headerSize = 8;
3334
+ const majorBrandSize = 4;
3335
+ const minorVersionSize = 4;
3336
+ const compatibleBrandsSize = box.compatibleBrands.length * 4;
3337
+ const writer = new IsoBoxWriteView("styp", headerSize + majorBrandSize + minorVersionSize + compatibleBrandsSize);
3338
+ writer.writeString(box.majorBrand);
3339
+ writer.writeUint(box.minorVersion, 4);
3340
+ for (const brand of box.compatibleBrands) writer.writeString(brand);
3341
+ return writer;
1551
3342
  }
1552
3343
 
1553
3344
  //#endregion
1554
- //#region src/parsers/subs.ts
3345
+ //#region src/writers/writeSubs.ts
1555
3346
  /**
1556
- * Parse a SubSampleInformationBox from an IsoView
3347
+ * Write a SubsampleInformationBox to an IsoDataWriter.
1557
3348
  *
1558
- * @param view - The IsoView to read data from
3349
+ * ISO/IEC 14496-12:2012 - 8.7.7 Sub-Sample Information Box
1559
3350
  *
1560
- * @returns A parsed SubSampleInformationBox
3351
+ * @param box - The SubsampleInformationBox fields to write
1561
3352
  *
3353
+ * @returns An IsoDataWriter containing the encoded box
1562
3354
  *
1563
- * @beta
3355
+ * @public
1564
3356
  */
1565
- function subs(view) {
1566
- const { version, flags } = view.readFullBox();
1567
- const entryCount = view.readUint(4);
1568
- return {
1569
- version,
1570
- flags,
1571
- entryCount,
1572
- entries: view.readEntries(entryCount, () => {
1573
- const sampleDelta = view.readUint(4);
1574
- const subsampleCount = view.readUint(2);
1575
- return {
1576
- sampleDelta,
1577
- subsampleCount,
1578
- subsamples: view.readEntries(subsampleCount, () => ({
1579
- subsampleSize: view.readUint(version === 1 ? 4 : 2),
1580
- subsamplePriority: view.readUint(1),
1581
- discardable: view.readUint(1),
1582
- codecSpecificParameters: view.readUint(4)
1583
- }))
1584
- };
1585
- })
1586
- };
3357
+ function writeSubs(box) {
3358
+ const subsampleSizeBytes = box.version === 1 ? 4 : 2;
3359
+ let entriesSize = 0;
3360
+ for (const entry of box.entries) {
3361
+ entriesSize += 4;
3362
+ entriesSize += 2;
3363
+ entriesSize += entry.subsampleCount * (subsampleSizeBytes + 1 + 1 + 4);
3364
+ }
3365
+ const writer = new IsoBoxWriteView("subs", 16 + entriesSize);
3366
+ writer.writeFullBox(box.version, box.flags);
3367
+ writer.writeUint(box.entryCount, 4);
3368
+ for (const entry of box.entries) {
3369
+ writer.writeUint(entry.sampleDelta, 4);
3370
+ writer.writeUint(entry.subsampleCount, 2);
3371
+ for (const subsample of entry.subsamples) {
3372
+ writer.writeUint(subsample.subsampleSize, subsampleSizeBytes);
3373
+ writer.writeUint(subsample.subsamplePriority, 1);
3374
+ writer.writeUint(subsample.discardable, 1);
3375
+ writer.writeUint(subsample.codecSpecificParameters, 4);
3376
+ }
3377
+ }
3378
+ return writer;
1587
3379
  }
1588
3380
 
1589
3381
  //#endregion
1590
- //#region src/parsers/tenc.ts
3382
+ //#region src/writers/writeTenc.ts
1591
3383
  /**
1592
- * Parse a TrackEncryptionBox from an IsoView
3384
+ * Write a TrackEncryptionBox to an IsoDataWriter.
1593
3385
  *
1594
- * @param view - The IsoView to read data from
3386
+ * ISO/IEC 23001-7 - 8.2 Track Encryption Box
1595
3387
  *
1596
- * @returns A parsed TrackEncryptionBox
3388
+ * @param box - The TrackEncryptionBox fields to write
1597
3389
  *
3390
+ * @returns An IsoDataWriter containing the encoded box
1598
3391
  *
1599
- * @beta
3392
+ * @public
1600
3393
  */
1601
- function tenc(view) {
1602
- return {
1603
- ...view.readFullBox(),
1604
- defaultIsEncrypted: view.readUint(3),
1605
- defaultIvSize: view.readUint(1),
1606
- defaultKid: view.readArray(UINT, 1, 16)
1607
- };
3394
+ function writeTenc(box) {
3395
+ const writer = new IsoBoxWriteView("tenc", 32);
3396
+ writer.writeFullBox(box.version, box.flags);
3397
+ writer.writeUint(box.defaultIsEncrypted, 3);
3398
+ writer.writeUint(box.defaultIvSize, 1);
3399
+ writer.writeArray(box.defaultKid, UINT, 1, 16);
3400
+ return writer;
1608
3401
  }
1609
3402
 
1610
3403
  //#endregion
1611
- //#region src/parsers/tfdt.ts
3404
+ //#region src/writers/writeTfdt.ts
1612
3405
  /**
1613
- * Parse a TrackFragmentDecodeTimeBox from an IsoView
3406
+ * Write a TrackFragmentBaseMediaDecodeTimeBox to an IsoDataWriter.
1614
3407
  *
1615
- * @param view - The IsoView to read data from
3408
+ * ISO/IEC 14496-12:2012 - 8.8.12 Track Fragment Base Media Decode Time Box
1616
3409
  *
1617
- * @returns A parsed TrackFragmentDecodeTimeBox
3410
+ * @param box - The TrackFragmentBaseMediaDecodeTimeBox fields to write
1618
3411
  *
3412
+ * @returns An IsoDataWriter containing the encoded box
1619
3413
  *
1620
- * @beta
3414
+ * @public
1621
3415
  */
1622
- function tfdt(view) {
1623
- const { version, flags } = view.readFullBox();
1624
- return {
1625
- version,
1626
- flags,
1627
- baseMediaDecodeTime: view.readUint(version == 1 ? 8 : 4)
1628
- };
3416
+ function writeTfdt(box) {
3417
+ const size = box.version === 1 ? 8 : 4;
3418
+ const headerSize = 8;
3419
+ const fullBoxSize = 4;
3420
+ const baseMediaDecodeTimeSize = size;
3421
+ const writer = new IsoBoxWriteView("tfdt", headerSize + fullBoxSize + baseMediaDecodeTimeSize);
3422
+ writer.writeFullBox(box.version, box.flags);
3423
+ writer.writeUint(box.baseMediaDecodeTime, size);
3424
+ return writer;
1629
3425
  }
1630
3426
 
1631
3427
  //#endregion
1632
- //#region src/parsers/tfhd.ts
3428
+ //#region src/writers/writeTfhd.ts
1633
3429
  /**
1634
- * Parse a TrackFragmentHeaderBox from an IsoView
3430
+ * Write a TrackFragmentHeaderBox to an IsoDataWriter.
1635
3431
  *
1636
- * @param view - The IsoView to read data from
3432
+ * ISO/IEC 14496-12:2012 - 8.8.7 Track Fragment Header Box
1637
3433
  *
1638
- * @returns A parsed TrackFragmentHeaderBox
3434
+ * @param box - The TrackFragmentHeaderBox fields to write
1639
3435
  *
3436
+ * @returns An IsoDataWriter containing the encoded box
1640
3437
  *
1641
- * @beta
3438
+ * @public
1642
3439
  */
1643
- function tfhd(view) {
1644
- const { version, flags } = view.readFullBox();
1645
- return {
1646
- version,
1647
- flags,
1648
- trackId: view.readUint(4),
1649
- baseDataOffset: flags & 1 ? view.readUint(8) : void 0,
1650
- sampleDescriptionIndex: flags & 2 ? view.readUint(4) : void 0,
1651
- defaultSampleDuration: flags & 8 ? view.readUint(4) : void 0,
1652
- defaultSampleSize: flags & 16 ? view.readUint(4) : void 0,
1653
- defaultSampleFlags: flags & 32 ? view.readUint(4) : void 0
1654
- };
3440
+ function writeTfhd(box) {
3441
+ const headerSize = 8;
3442
+ const fullBoxSize = 4;
3443
+ const trackIdSize = 4;
3444
+ const baseDataOffsetSize = box.flags & 1 ? 8 : 0;
3445
+ const sampleDescriptionIndexSize = box.flags & 2 ? 4 : 0;
3446
+ const defaultSampleDurationSize = box.flags & 8 ? 4 : 0;
3447
+ const defaultSampleSizeSize = box.flags & 16 ? 4 : 0;
3448
+ const defaultSampleFlagsSize = box.flags & 32 ? 4 : 0;
3449
+ const writer = new IsoBoxWriteView("tfhd", headerSize + fullBoxSize + trackIdSize + baseDataOffsetSize + sampleDescriptionIndexSize + defaultSampleDurationSize + defaultSampleSizeSize + defaultSampleFlagsSize);
3450
+ writer.writeFullBox(box.version, box.flags);
3451
+ writer.writeUint(box.trackId, 4);
3452
+ if (box.flags & 1) writer.writeUint(box.baseDataOffset ?? 0, 8);
3453
+ if (box.flags & 2) writer.writeUint(box.sampleDescriptionIndex ?? 0, 4);
3454
+ if (box.flags & 8) writer.writeUint(box.defaultSampleDuration ?? 0, 4);
3455
+ if (box.flags & 16) writer.writeUint(box.defaultSampleSize ?? 0, 4);
3456
+ if (box.flags & 32) writer.writeUint(box.defaultSampleFlags ?? 0, 4);
3457
+ return writer;
1655
3458
  }
1656
3459
 
1657
3460
  //#endregion
1658
- //#region src/parsers/tfra.ts
3461
+ //#region src/writers/writeTfra.ts
1659
3462
  /**
1660
- * Parse a TrackFragmentRandomAccessBox from an IsoView
3463
+ * Write a TrackFragmentRandomAccessBox to an IsoDataWriter.
1661
3464
  *
1662
- * @param view - The IsoView to read data from
3465
+ * ISO/IEC 14496-12:2012 - 8.8.10 Track Fragment Random Access Box
1663
3466
  *
1664
- * @returns A parsed TrackFragmentRandomAccessBox
3467
+ * @param box - The TrackFragmentRandomAccessBox fields to write
1665
3468
  *
3469
+ * @returns An IsoDataWriter containing the encoded box
1666
3470
  *
1667
- * @beta
3471
+ * @public
1668
3472
  */
1669
- function tfra(view) {
1670
- const { version, flags } = view.readFullBox();
1671
- const trackId = view.readUint(4);
1672
- const reserved = view.readUint(4);
1673
- const lengthSizeOfTrafNum = (reserved & 48) >> 4;
1674
- const lengthSizeOfTrunNum = (reserved & 12) >> 2;
1675
- const lengthSizeOfSampleNum = reserved & 3;
1676
- const numberOfEntry = view.readUint(4);
1677
- return {
1678
- version,
1679
- flags,
1680
- trackId,
1681
- reserved,
1682
- lengthSizeOfTrafNum,
1683
- lengthSizeOfTrunNum,
1684
- lengthSizeOfSampleNum,
1685
- numberOfEntry,
1686
- entries: view.readEntries(numberOfEntry, () => ({
1687
- time: view.readUint(version === 1 ? 8 : 4),
1688
- moofOffset: view.readUint(version === 1 ? 8 : 4),
1689
- trafNumber: view.readUint(lengthSizeOfTrafNum + 1),
1690
- trunNumber: view.readUint(lengthSizeOfTrunNum + 1),
1691
- sampleNumber: view.readUint(lengthSizeOfSampleNum + 1)
1692
- }))
1693
- };
3473
+ function writeTfra(box) {
3474
+ const timeSize = box.version === 1 ? 8 : 4;
3475
+ const entrySize = timeSize + timeSize + (box.lengthSizeOfTrafNum + 1) + (box.lengthSizeOfTrunNum + 1) + (box.lengthSizeOfSampleNum + 1);
3476
+ const headerSize = 8;
3477
+ const fullBoxSize = 4;
3478
+ const trackIdSize = 4;
3479
+ const reservedSize = 4;
3480
+ const numberOfEntrySize = 4;
3481
+ const entriesSize = box.numberOfEntry * entrySize;
3482
+ const writer = new IsoBoxWriteView("tfra", headerSize + fullBoxSize + trackIdSize + reservedSize + numberOfEntrySize + entriesSize);
3483
+ writer.writeFullBox(box.version, box.flags);
3484
+ writer.writeUint(box.trackId, 4);
3485
+ const reserved = box.lengthSizeOfTrafNum << 4 | box.lengthSizeOfTrunNum << 2 | box.lengthSizeOfSampleNum;
3486
+ writer.writeUint(reserved, 4);
3487
+ writer.writeUint(box.numberOfEntry, 4);
3488
+ for (const entry of box.entries) {
3489
+ writer.writeUint(entry.time, timeSize);
3490
+ writer.writeUint(entry.moofOffset, timeSize);
3491
+ writer.writeUint(entry.trafNumber, box.lengthSizeOfTrafNum + 1);
3492
+ writer.writeUint(entry.trunNumber, box.lengthSizeOfTrunNum + 1);
3493
+ writer.writeUint(entry.sampleNumber, box.lengthSizeOfSampleNum + 1);
3494
+ }
3495
+ return writer;
1694
3496
  }
1695
3497
 
1696
3498
  //#endregion
1697
- //#region src/parsers/tkhd.ts
3499
+ //#region src/writers/writeTkhd.ts
1698
3500
  /**
1699
- * Parse a TrackHeaderBox from an IsoView
3501
+ * Write a TrackHeaderBox to an IsoDataWriter.
1700
3502
  *
1701
- * @param view - The IsoView to read data from
3503
+ * ISO/IEC 14496-12:2012 - 8.3.2 Track Header Box
1702
3504
  *
1703
- * @returns A parsed TrackHeaderBox
3505
+ * @param box - The TrackHeaderBox fields to write
1704
3506
  *
3507
+ * @returns An IsoDataWriter containing the encoded box
1705
3508
  *
1706
- * @beta
3509
+ * @public
1707
3510
  */
1708
- function tkhd(view) {
1709
- const { version, flags } = view.readFullBox();
1710
- const size = version === 1 ? 8 : 4;
1711
- return {
1712
- version,
1713
- flags,
1714
- creationTime: view.readUint(size),
1715
- modificationTime: view.readUint(size),
1716
- trackId: view.readUint(4),
1717
- reserved1: view.readUint(4),
1718
- duration: view.readUint(size),
1719
- reserved2: view.readArray(UINT, 4, 2),
1720
- layer: view.readUint(2),
1721
- alternateGroup: view.readUint(2),
1722
- volume: view.readTemplate(2),
1723
- reserved3: view.readUint(2),
1724
- matrix: view.readArray(TEMPLATE, 4, 9),
1725
- width: view.readTemplate(4),
1726
- height: view.readTemplate(4)
1727
- };
3511
+ function writeTkhd(box) {
3512
+ const size = box.version === 1 ? 8 : 4;
3513
+ const headerSize = 8;
3514
+ const fullBoxSize = 4;
3515
+ const timesSize = size * 3;
3516
+ const writer = new IsoBoxWriteView("tkhd", headerSize + fullBoxSize + timesSize + 4 + 4 + 8 + 2 + 2 + 2 + 2 + 36 + 4 + 4);
3517
+ writer.writeFullBox(box.version, box.flags);
3518
+ writer.writeUint(box.creationTime, size);
3519
+ writer.writeUint(box.modificationTime, size);
3520
+ writer.writeUint(box.trackId, 4);
3521
+ writer.writeUint(box.reserved1, 4);
3522
+ writer.writeUint(box.duration, size);
3523
+ writer.writeArray(box.reserved2, UINT, 4, 2);
3524
+ writer.writeUint(box.layer, 2);
3525
+ writer.writeUint(box.alternateGroup, 2);
3526
+ writer.writeTemplate(box.volume, 2);
3527
+ writer.writeUint(box.reserved3, 2);
3528
+ writer.writeArray(box.matrix, TEMPLATE, 4, 9);
3529
+ writer.writeTemplate(box.width, 4);
3530
+ writer.writeTemplate(box.height, 4);
3531
+ return writer;
1728
3532
  }
1729
3533
 
1730
3534
  //#endregion
1731
- //#region src/parsers/trex.ts
3535
+ //#region src/writers/writeTrex.ts
1732
3536
  /**
1733
- * Parse a TrackExtendsBox from an IsoView
3537
+ * Write a TrackExtendsBox to an IsoDataWriter.
1734
3538
  *
1735
- * @param view - The IsoView to read data from
3539
+ * ISO/IEC 14496-12:2012 - 8.8.3 Track Extends Box
1736
3540
  *
1737
- * @returns A parsed TrackExtendsBox
3541
+ * @param box - The TrackExtendsBox fields to write
1738
3542
  *
3543
+ * @returns An IsoDataWriter containing the encoded box
1739
3544
  *
1740
- * @beta
3545
+ * @public
1741
3546
  */
1742
- function trex(view) {
1743
- return {
1744
- ...view.readFullBox(),
1745
- trackId: view.readUint(4),
1746
- defaultSampleDescriptionIndex: view.readUint(4),
1747
- defaultSampleDuration: view.readUint(4),
1748
- defaultSampleSize: view.readUint(4),
1749
- defaultSampleFlags: view.readUint(4)
1750
- };
3547
+ function writeTrex(box) {
3548
+ const writer = new IsoBoxWriteView("trex", 32);
3549
+ writer.writeFullBox(box.version, box.flags);
3550
+ writer.writeUint(box.trackId, 4);
3551
+ writer.writeUint(box.defaultSampleDescriptionIndex, 4);
3552
+ writer.writeUint(box.defaultSampleDuration, 4);
3553
+ writer.writeUint(box.defaultSampleSize, 4);
3554
+ writer.writeUint(box.defaultSampleFlags, 4);
3555
+ return writer;
1751
3556
  }
1752
3557
 
1753
3558
  //#endregion
1754
- //#region src/parsers/trun.ts
3559
+ //#region src/writers/writeTrun.ts
1755
3560
  /**
1756
- * Parse a TrackRunBox from an IsoView
3561
+ * Write a TrackRunBox to an IsoDataWriter.
1757
3562
  *
1758
- * @param view - The IsoView to read data from
3563
+ * ISO/IEC 14496-12:2012 - 8.8.8 Track Run Box
1759
3564
  *
1760
- * @returns A parsed TrackRunBox
3565
+ * @param box - The TrackRunBox fields to write
1761
3566
  *
3567
+ * @returns An IsoDataWriter containing the encoded box
1762
3568
  *
1763
- * @beta
3569
+ * @public
1764
3570
  */
1765
- function trun(view) {
1766
- const { version, flags } = view.readFullBox();
1767
- const sampleCount = view.readUint(4);
1768
- let dataOffset;
1769
- let firstSampleFlags;
1770
- if (flags & 1) dataOffset = view.readInt(4);
1771
- if (flags & 4) firstSampleFlags = view.readUint(4);
1772
- const samples = view.readEntries(sampleCount, () => {
1773
- const sample = {};
1774
- if (flags & 256) sample.sampleDuration = view.readUint(4);
1775
- if (flags & 512) sample.sampleSize = view.readUint(4);
1776
- if (flags & 1024) sample.sampleFlags = view.readUint(4);
1777
- if (flags & 2048) sample.sampleCompositionTimeOffset = version === 1 ? view.readInt(4) : view.readUint(4);
1778
- return sample;
1779
- });
1780
- return {
1781
- version,
1782
- flags,
1783
- sampleCount,
1784
- dataOffset,
1785
- firstSampleFlags,
1786
- samples
1787
- };
3571
+ function writeTrun(box) {
3572
+ const headerSize = 8;
3573
+ const fullBoxSize = 4;
3574
+ const sampleCountSize = 4;
3575
+ const dataOffsetSize = box.flags & 1 ? 4 : 0;
3576
+ const firstSampleFlagsSize = box.flags & 4 ? 4 : 0;
3577
+ let sampleSize = 0;
3578
+ if (box.flags & 256) sampleSize += 4;
3579
+ if (box.flags & 512) sampleSize += 4;
3580
+ if (box.flags & 1024) sampleSize += 4;
3581
+ if (box.flags & 2048) sampleSize += 4;
3582
+ const samplesSize = sampleSize * box.sampleCount;
3583
+ const writer = new IsoBoxWriteView("trun", headerSize + fullBoxSize + sampleCountSize + dataOffsetSize + firstSampleFlagsSize + samplesSize);
3584
+ writer.writeFullBox(box.version, box.flags);
3585
+ writer.writeUint(box.sampleCount, 4);
3586
+ if (box.flags & 1) writer.writeUint(box.dataOffset ?? 0, 4);
3587
+ if (box.flags & 4) writer.writeUint(box.firstSampleFlags ?? 0, 4);
3588
+ for (const sample of box.samples) {
3589
+ if (box.flags & 256) writer.writeUint(sample.sampleDuration ?? 0, 4);
3590
+ if (box.flags & 512) writer.writeUint(sample.sampleSize ?? 0, 4);
3591
+ if (box.flags & 1024) writer.writeUint(sample.sampleFlags ?? 0, 4);
3592
+ if (box.flags & 2048) writer.writeUint(sample.sampleCompositionTimeOffset ?? 0, 4);
3593
+ }
3594
+ return writer;
1788
3595
  }
1789
3596
 
1790
3597
  //#endregion
1791
- //#region src/parsers/url.ts
3598
+ //#region src/writers/writeUrl.ts
1792
3599
  /**
1793
- * Parse a UrlBox from an IsoView
3600
+ * Write a UrlBox to an IsoDataWriter.
1794
3601
  *
1795
- * @param view - The IsoView to read data from
3602
+ * ISO/IEC 14496-12:2012 - 8.7.2 Data Reference Box
1796
3603
  *
1797
- * @returns A parsed UrlBox
3604
+ * @param box - The UrlBox fields to write
1798
3605
  *
3606
+ * @returns An IsoDataWriter containing the encoded box
1799
3607
  *
1800
- * @beta
3608
+ * @public
1801
3609
  */
1802
- function url(view) {
1803
- return {
1804
- ...view.readFullBox(),
1805
- location: view.readString(-1)
1806
- };
3610
+ function writeUrl(box) {
3611
+ const headerSize = 8;
3612
+ const fullBoxSize = 4;
3613
+ const locationSize = box.location.length + 1;
3614
+ const writer = new IsoBoxWriteView("url ", headerSize + fullBoxSize + locationSize);
3615
+ writer.writeFullBox(box.version, box.flags);
3616
+ writer.writeTerminatedString(box.location);
3617
+ return writer;
1807
3618
  }
1808
3619
 
1809
3620
  //#endregion
1810
- //#region src/parsers/urn.ts
3621
+ //#region src/writers/writeUrn.ts
1811
3622
  /**
1812
- * Parse a UrnBox from an IsoView
3623
+ * Write a UrnBox to an IsoDataWriter.
1813
3624
  *
1814
- * @param view - The IsoView to read data from
3625
+ * ISO/IEC 14496-12:2012 - 8.7.2 Data Reference Box
1815
3626
  *
1816
- * @returns A parsed UrnBox
3627
+ * @param box - The UrnBox fields to write
1817
3628
  *
3629
+ * @returns An IsoDataWriter containing the encoded box
1818
3630
  *
1819
- * @beta
3631
+ * @public
1820
3632
  */
1821
- function urn(view) {
1822
- return {
1823
- ...view.readFullBox(),
1824
- name: view.readString(-1),
1825
- location: view.readString(-1)
1826
- };
3633
+ function writeUrn(box) {
3634
+ const headerSize = 8;
3635
+ const fullBoxSize = 4;
3636
+ const nameSize = box.name.length + 1;
3637
+ const locationSize = box.location.length + 1;
3638
+ const writer = new IsoBoxWriteView("urn ", headerSize + fullBoxSize + nameSize + locationSize);
3639
+ writer.writeFullBox(box.version, box.flags);
3640
+ writer.writeTerminatedString(box.name);
3641
+ writer.writeTerminatedString(box.location);
3642
+ return writer;
1827
3643
  }
1828
3644
 
1829
3645
  //#endregion
1830
- //#region src/parsers/vlab.ts
3646
+ //#region src/writers/writeVlab.ts
1831
3647
  /**
1832
- * Parse a WebVTTSourceLabelBox from an IsoView
1833
- *
1834
- * @param view - The IsoView to read data from
3648
+ * Write a WebVttSourceLabelBox to an IsoDataWriter.
1835
3649
  *
1836
- * @returns A parsed WebVTTSourceLabelBox
3650
+ * @param box - The WebVttSourceLabelBox fields to write
1837
3651
  *
3652
+ * @returns An IsoDataWriter containing the encoded box
1838
3653
  *
1839
- * @beta
3654
+ * @public
1840
3655
  */
1841
- function vlab(view) {
1842
- return { sourceLabel: view.readUtf8(-1) };
3656
+ function writeVlab(box) {
3657
+ const writer = new IsoBoxWriteView("vlab", 8 + (encodeText(box.sourceLabel).length + 1));
3658
+ writer.writeUtf8TerminatedString(box.sourceLabel);
3659
+ return writer;
1843
3660
  }
1844
3661
 
1845
3662
  //#endregion
1846
- //#region src/parsers/vmhd.ts
3663
+ //#region src/writers/writeVmhd.ts
1847
3664
  /**
1848
- * Parse a VideoMediaHeaderBox from an IsoView
3665
+ * Write a VideoMediaHeaderBox to an IsoDataWriter.
1849
3666
  *
1850
- * @param view - The IsoView to read data from
3667
+ * ISO/IEC 14496-12:2012 - 12.1.2 Video Media Header Box
1851
3668
  *
1852
- * @returns A parsed VideoMediaHeaderBox
3669
+ * @param box - The VideoMediaHeaderBox fields to write
1853
3670
  *
3671
+ * @returns An IsoDataWriter containing the encoded box
1854
3672
  *
1855
- * @beta
3673
+ * @public
1856
3674
  */
1857
- function vmhd(view) {
1858
- return {
1859
- ...view.readFullBox(),
1860
- graphicsmode: view.readUint(2),
1861
- opcolor: view.readArray(UINT, 2, 3)
1862
- };
3675
+ function writeVmhd(box) {
3676
+ const writer = new IsoBoxWriteView("vmhd", 20);
3677
+ writer.writeFullBox(box.version, box.flags);
3678
+ writer.writeUint(box.graphicsmode, 2);
3679
+ writer.writeArray(box.opcolor, UINT, 2, 3);
3680
+ return writer;
1863
3681
  }
1864
3682
 
1865
3683
  //#endregion
1866
- //#region src/parsers/vttC.ts
3684
+ //#region src/writers/writeVttC.ts
1867
3685
  /**
1868
- * Parse a WebVTTConfigurationBox from an IsoView
1869
- *
1870
- * @param view - The IsoView to read data from
3686
+ * Write a WebVttConfigurationBox to an IsoDataWriter.
1871
3687
  *
1872
- * @returns A parsed WebVttConfigurationBox
3688
+ * @param box - The WebVttConfigurationBox fields to write
1873
3689
  *
3690
+ * @returns An IsoDataWriter containing the encoded box
1874
3691
  *
1875
- * @beta
3692
+ * @public
1876
3693
  */
1877
- function vttC(view) {
1878
- return { config: view.readUtf8() };
3694
+ function writeVttC(box) {
3695
+ const configBytes = encodeText(box.config);
3696
+ const writer = new IsoBoxWriteView("vttC", 8 + configBytes.length);
3697
+ writer.writeBytes(configBytes);
3698
+ return writer;
1879
3699
  }
1880
3700
 
1881
3701
  //#endregion
1882
- //#region src/parsers/vtte.ts
3702
+ //#region src/writers/writeVtte.ts
1883
3703
  /**
1884
- * Parse a WebVTT Empty Sample Box from an IsoView
1885
- *
1886
- * @returns A parsed WebVTT Empty Sample Box
3704
+ * Write a WebVttEmptySampleBox to an IsoDataWriter.
1887
3705
  *
3706
+ * @returns An IsoDataWriter containing the encoded box
1888
3707
  *
1889
- * @beta
3708
+ * @public
1890
3709
  */
1891
- function vtte() {
1892
- return {};
3710
+ function writeVtte(_) {
3711
+ return new IsoBoxWriteView("vtte", 8);
1893
3712
  }
1894
3713
 
1895
3714
  //#endregion
1896
- export { ardi, avc1, avc2, avc3, avc4, createIsoView, ctts, dref, elng, elst, emsg, enca, encv, filterBoxes, filterBoxesByType, findBox, findBoxByType, free, frma, ftyp, hdlr, hev1, hvc1, iden, imda, kind, labl, mdat, mdhd, mehd, meta, mfhd, mfro, mp4a, mvhd, parseBoxes, payl, prft, prsl, pssh, schm, sdtp, sidx, skip, smhd, ssix, sthd, stsd, stss, sttg, stts, styp, subs, tenc, tfdt, tfhd, tfra, tkhd, trex, trun, url, urn, vlab, vmhd, vttC, vtte };
3715
+ export { CONTAINERS, IsoBoxReadableStream, createIsoBoxReadableStream, isContainer, isFullBox, readArdi, readAvc1, readAvc2, readAvc3, readAvc4, readCtts, readDref, readElng, readElst, readEmsg, readEnca, readEncv, readFree, readFrma, readFtyp, readHdlr, readHev1, readHvc1, readIden, readImda, readIsoBoxes, readKind, readLabl, readMdat, readMdhd, readMehd, readMeta, readMfhd, readMfro, readMp4a, readMvhd, readPayl, readPrft, readPrsl, readPssh, readSchm, readSdtp, readSidx, readSkip, readSmhd, readSsix, readSthd, readStsd, readStss, readSttg, readStts, readStyp, readSubs, readTenc, readTfdt, readTfhd, readTfra, readTkhd, readTrex, readTrun, readUrl, readUrn, readVlab, readVmhd, readVttC, readVtte, traverseIsoBoxes, writeArdi, writeAvc1, writeAvc2, writeAvc3, writeAvc4, writeCtts, writeDref, writeElng, writeElst, writeEmsg, writeEnca, writeEncv, writeFree, writeFrma, writeFtyp, writeHdlr, writeHev1, writeHvc1, writeIden, writeImda, writeIsoBox, writeIsoBoxes, writeKind, writeLabl, writeMdat, writeMdhd, writeMehd, writeMeta, writeMfhd, writeMfro, writeMp4a, writeMvhd, writePayl, writePrft, writePrsl, writePssh, writeSchm, writeSdtp, writeSidx, writeSkip, writeSmhd, writeSsix, writeSthd, writeStsd, writeStss, writeSttg, writeStts, writeStyp, writeSubs, writeTenc, writeTfdt, writeTfhd, writeTfra, writeTkhd, writeTrex, writeTrun, writeUrl, writeUrn, writeVlab, writeVmhd, writeVttC, writeVtte };
1897
3716
  //# sourceMappingURL=index.js.map