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

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