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

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
@@ -15,18 +15,14 @@ function createWriterConfig(config) {
15
15
  const CONTAINERS = [
16
16
  "dinf",
17
17
  "edts",
18
- "enca",
19
- "encv",
20
18
  "grpl",
21
19
  "mdia",
22
20
  "meco",
23
- "meta",
24
21
  "mfra",
25
22
  "minf",
26
23
  "moof",
27
24
  "moov",
28
25
  "mvex",
29
- "prsl",
30
26
  "schi",
31
27
  "sinf",
32
28
  "stbl",
@@ -150,8 +146,11 @@ var IsoBoxWriteView = class {
150
146
  this.writeUint(0, 1);
151
147
  };
152
148
  this.writeBytes = (data) => {
153
- new Uint8Array(this.dataView.buffer).set(data, this.cursor);
154
- this.cursor += data.length;
149
+ if (!Array.isArray(data)) data = [data];
150
+ for (const bytes of data) {
151
+ new Uint8Array(this.dataView.buffer).set(bytes, this.cursor);
152
+ this.cursor += bytes.length;
153
+ }
155
154
  };
156
155
  this.writeArray = (data, type$1, size$1, length) => {
157
156
  const write = type$1 === UINT ? this.writeUint : type$1 === TEMPLATE ? this.writeTemplate : this.writeInt;
@@ -213,7 +212,43 @@ var IsoBoxWriteView = class {
213
212
  };
214
213
 
215
214
  //#endregion
216
- //#region src/writers/writeContainerBox.ts
215
+ //#region src/utils/writeBoxes.ts
216
+ /**
217
+ * Write boxes to an array of Uint8Arrays.
218
+ *
219
+ * @param boxes - The boxes to write
220
+ * @param config - The configuration for the writer
221
+ *
222
+ * @returns The written boxes
223
+ *
224
+ * @internal
225
+ */
226
+ function writeBoxes(boxes, config) {
227
+ return Array.from(boxes, (box) => writeBox(box, config));
228
+ }
229
+
230
+ //#endregion
231
+ //#region src/utils/writeChildBoxes.ts
232
+ /**
233
+ * Write child boxes
234
+ *
235
+ * @param boxes - The boxes to write
236
+ * @param config - The configuration for the writer
237
+ *
238
+ * @returns The byte arrays and total size of the written boxes
239
+ *
240
+ * @internal
241
+ */
242
+ function writeChildBoxes(boxes, config) {
243
+ const bytes = writeBoxes(boxes, config);
244
+ return {
245
+ bytes,
246
+ size: bytes.reduce((size, byte) => size + byte.byteLength, 0)
247
+ };
248
+ }
249
+
250
+ //#endregion
251
+ //#region src/utils/writeContainerBox.ts
217
252
  /**
218
253
  * Write a ContainerBox to an IsoBmffWriter.
219
254
  *
@@ -223,24 +258,20 @@ var IsoBoxWriteView = class {
223
258
  * @param box - The ContainerBox to write
224
259
  *
225
260
  * @returns An IsoBmffWriter containing the encoded box
261
+ *
262
+ * @internal
226
263
  */
227
264
  function writeContainerBox(box, config) {
228
- const children = [];
229
265
  const headerSize = 8;
230
- let childrenSize = 0;
231
- for (const childBox of box.boxes) {
232
- const view = writeIsoBox(childBox, config);
233
- childrenSize += view.byteLength;
234
- children.push(view);
235
- }
236
- const totalSize = headerSize + childrenSize;
266
+ const { bytes, size } = writeChildBoxes(box.boxes, config);
267
+ const totalSize = headerSize + size;
237
268
  const writer = new IsoBoxWriteView(box.type, totalSize);
238
- for (const child of children) writer.writeBytes(child);
269
+ writer.writeBytes(bytes);
239
270
  return writer;
240
271
  }
241
272
 
242
273
  //#endregion
243
- //#region src/writers/writeBox.ts
274
+ //#region src/utils/writeBox.ts
244
275
  /**
245
276
  * Write a box to a Uint8Array.
246
277
  *
@@ -254,12 +285,10 @@ function writeBox(box, config) {
254
285
  let view = null;
255
286
  if ("type" in box) {
256
287
  const { type } = box;
257
- if (type !== "" && isContainer(box)) view = writeContainerBox(box, config);
258
- else {
259
- const writer = config.writers[type];
260
- if (writer) view = writer(box, config);
261
- else if ("view" in box) view = box.view;
262
- }
288
+ const writer = config.writers?.[type];
289
+ if (writer) view = writer(box, config);
290
+ else if (isContainer(box)) view = writeContainerBox(box, config);
291
+ else if ("view" in box) view = box.view;
263
292
  if (!view) throw new Error(`No writer found for box type: ${type}`);
264
293
  }
265
294
  if ("buffer" in box) view = box;
@@ -273,7 +302,8 @@ function writeBox(box, config) {
273
302
  * Write an ISO box to a Uint8Array.
274
303
  *
275
304
  * @param box - The box to write
276
- * @param writers - The writers to use
305
+ * @param config - The configuration for the writer
306
+ *
277
307
  * @returns The written box
278
308
  *
279
309
  * @public
@@ -334,401 +364,558 @@ function createIsoBoxReadableStream(boxes, config = {}) {
334
364
  }
335
365
 
336
366
  //#endregion
337
- //#region src/readers/readArdi.ts
367
+ //#region src/fields/DATA.ts
338
368
  /**
339
- * Parse a AudioRenderingIndicationBox from an IsoView
340
- *
341
- * @param view - The IsoView to read data from
342
- *
343
- * @returns A parsed AudioRenderingIndicationBox
369
+ * The data field type
344
370
  *
345
371
  * @public
346
372
  */
347
- function readArdi(view) {
348
- return {
349
- type: "ardi",
350
- ...view.readFullBox(),
351
- audioRenderingIndication: view.readUint(1)
352
- };
353
- }
373
+ const DATA = "data";
354
374
 
355
375
  //#endregion
356
- //#region src/readers/readAvc1.ts
376
+ //#region src/fields/INT.ts
357
377
  /**
358
- * Parse a VisualSampleEntryBox from an IsoView
359
- *
360
- * @param view - The IsoView to read data from
361
- *
362
- * @returns A parsed VisualSampleEntryBox
378
+ * The integer field type
363
379
  *
364
380
  * @public
365
381
  */
366
- function readAvc1(view) {
367
- const { readArray, readUint: readUint$1, readInt: readInt$1, readTemplate: readTemplate$1, readData: readData$1 } = view;
368
- return {
369
- type: "avc1",
370
- reserved1: readArray(UINT, 1, 6),
371
- dataReferenceIndex: readUint$1(2),
372
- preDefined1: readUint$1(2),
373
- reserved2: readUint$1(2),
374
- preDefined2: readArray(UINT, 4, 3),
375
- width: readUint$1(2),
376
- height: readUint$1(2),
377
- horizresolution: readTemplate$1(4),
378
- vertresolution: readTemplate$1(4),
379
- reserved3: readUint$1(4),
380
- frameCount: readUint$1(2),
381
- compressorName: readArray(UINT, 1, 32),
382
- depth: readUint$1(2),
383
- preDefined3: readInt$1(2),
384
- config: readData$1(-1)
385
- };
386
- }
382
+ const INT = "int";
387
383
 
388
384
  //#endregion
389
- //#region src/readers/readAvc2.ts
385
+ //#region src/fields/STRING.ts
390
386
  /**
391
- * Parse a VisualSampleEntryBox from an IsoView
392
- *
393
- * @param view - The IsoView to read data from
394
- *
395
- * @returns A parsed VisualSampleEntryBox
387
+ * The string field type
396
388
  *
397
389
  * @public
398
390
  */
399
- function readAvc2(view) {
400
- return {
401
- ...readAvc1(view),
402
- type: "avc2"
403
- };
404
- }
391
+ const STRING = "string";
405
392
 
406
393
  //#endregion
407
- //#region src/readers/readAvc3.ts
394
+ //#region src/fields/UTF8.ts
408
395
  /**
409
- * Parse a VisualSampleEntryBox from an IsoView
410
- *
411
- * @param view - The IsoView to read data from
412
- *
413
- * @returns A parsed VisualSampleEntryBox
396
+ * The UTF8 field type
414
397
  *
415
398
  * @public
416
399
  */
417
- function readAvc3(view) {
418
- return {
419
- ...readAvc1(view),
420
- type: "avc3"
421
- };
400
+ const UTF8 = "utf8";
401
+
402
+ //#endregion
403
+ //#region src/utils/readData.ts
404
+ function readData(dataView, offset, size) {
405
+ const length = size > 0 ? size : dataView.byteLength - (offset - dataView.byteOffset);
406
+ return new Uint8Array(dataView.buffer, offset, Math.max(length, 0));
422
407
  }
423
408
 
424
409
  //#endregion
425
- //#region src/readers/readAvc4.ts
410
+ //#region src/utils/readInt.ts
411
+ function readInt(dataView, offset, size) {
412
+ let result = NaN;
413
+ const cursor = offset - dataView.byteOffset;
414
+ switch (size) {
415
+ case 1:
416
+ result = dataView.getInt8(cursor);
417
+ break;
418
+ case 2:
419
+ result = dataView.getInt16(cursor);
420
+ break;
421
+ case 4:
422
+ result = dataView.getInt32(cursor);
423
+ break;
424
+ case 8:
425
+ const s1 = dataView.getInt32(cursor);
426
+ const s2 = dataView.getInt32(cursor + 4);
427
+ result = s1 * Math.pow(2, 32) + s2;
428
+ break;
429
+ }
430
+ return result;
431
+ }
432
+
433
+ //#endregion
434
+ //#region src/utils/readUint.ts
435
+ function readUint(dataView, offset, size) {
436
+ const cursor = offset - dataView.byteOffset;
437
+ let value = NaN;
438
+ let s1;
439
+ let s2;
440
+ switch (size) {
441
+ case 1:
442
+ value = dataView.getUint8(cursor);
443
+ break;
444
+ case 2:
445
+ value = dataView.getUint16(cursor);
446
+ break;
447
+ case 3:
448
+ s1 = dataView.getUint16(cursor);
449
+ s2 = dataView.getUint8(cursor + 2);
450
+ value = (s1 << 8) + s2;
451
+ break;
452
+ case 4:
453
+ value = dataView.getUint32(cursor);
454
+ break;
455
+ case 8:
456
+ s1 = dataView.getUint32(cursor);
457
+ s2 = dataView.getUint32(cursor + 4);
458
+ value = s1 * Math.pow(2, 32) + s2;
459
+ break;
460
+ }
461
+ return value;
462
+ }
463
+
464
+ //#endregion
465
+ //#region src/utils/readString.ts
466
+ function readString(dataView, offset, length) {
467
+ let str = "";
468
+ for (let c = 0; c < length; c++) {
469
+ const char = readUint(dataView, offset + c, 1);
470
+ str += String.fromCharCode(char);
471
+ }
472
+ return str;
473
+ }
474
+
475
+ //#endregion
476
+ //#region src/utils/readTemplate.ts
477
+ function readTemplate(dataView, offset, size) {
478
+ const half = size / 2;
479
+ return readUint(dataView, offset, half) + readUint(dataView, offset + half, half) / Math.pow(2, half);
480
+ }
481
+
482
+ //#endregion
483
+ //#region src/utils/readTerminatedString.ts
484
+ function readTerminatedString(dataView, offset) {
485
+ let str = "";
486
+ let cursor = offset;
487
+ while (cursor - dataView.byteOffset < dataView.byteLength) {
488
+ const char = readUint(dataView, cursor, 1);
489
+ if (char === 0) break;
490
+ str += String.fromCharCode(char);
491
+ cursor++;
492
+ }
493
+ return str;
494
+ }
495
+
496
+ //#endregion
497
+ //#region src/utils/readUtf8String.ts
426
498
  /**
427
- * Parse a VisualSampleEntryBox from an IsoView
428
- *
429
- * @param view - The IsoView to read data from
499
+ * Reads a UTF-8 string from a data view.
430
500
  *
431
- * @returns A parsed VisualSampleEntryBox
501
+ * @param dataView - The data view to read from.
502
+ * @param offset - The offset to start reading from.
503
+ * @returns The UTF-8 string.
432
504
  *
433
- * @public
505
+ * @internal
434
506
  */
435
- function readAvc4(view) {
436
- return {
437
- ...readAvc1(view),
438
- type: "avc4"
439
- };
507
+ function readUtf8String(dataView, offset) {
508
+ const length = dataView.byteLength - (offset - dataView.byteOffset);
509
+ return length > 0 ? decodeText(new DataView(dataView.buffer, offset, length), { encoding: UTF_8 }) : "";
440
510
  }
441
511
 
442
512
  //#endregion
443
- //#region src/readers/readCtts.ts
513
+ //#region src/utils/readUtf8TerminatedString.ts
444
514
  /**
445
- * Parse a CompositionTimeToSampleBox from an IsoView
446
- *
447
- * @param view - The IsoView to read data from
515
+ * Reads a UTF-8 terminated string from a data view.
448
516
  *
449
- * @returns A parsed CompositionTimeToSampleBox
517
+ * @param dataView - The data view to read from.
518
+ * @param offset - The offset to start reading from.
519
+ * @returns The UTF-8 terminated string.
450
520
  *
451
- * @public
521
+ * @internal
452
522
  */
453
- function readCtts(view) {
454
- const { version, flags } = view.readFullBox();
455
- const read = version === 1 ? view.readInt : view.readUint;
456
- const entryCount = view.readUint(4);
457
- return {
458
- type: "ctts",
459
- version,
460
- flags,
461
- entryCount,
462
- entries: view.readEntries(entryCount, () => ({
463
- sampleCount: view.readUint(4),
464
- sampleOffset: read(4)
465
- }))
466
- };
523
+ function readUtf8TerminatedString(dataView, offset) {
524
+ const length = dataView.byteLength - (offset - dataView.byteOffset);
525
+ let data = "";
526
+ if (length > 0) {
527
+ const view = new DataView(dataView.buffer, offset, length);
528
+ let l = 0;
529
+ for (; l < length; l++) if (view.getUint8(l) === 0) break;
530
+ data = decodeText(new DataView(dataView.buffer, offset, l), { encoding: UTF_8 });
531
+ }
532
+ return data;
467
533
  }
468
534
 
469
535
  //#endregion
470
- //#region src/readers/readDref.ts
536
+ //#region src/IsoBoxReadView.ts
471
537
  /**
472
- * Parse a DataReferenceBox from an IsoView
473
- *
474
- * @param view - The IsoView to read data from
475
- *
476
- * @returns A parsed DataReferenceBox
538
+ * ISO BMFF data view. Similar to DataView, but with additional methods for reading ISO BMFF data.
539
+ * It implements the iterator protocol, so it can be used in a for...of loop.
477
540
  *
478
541
  * @public
479
542
  */
480
- function readDref(view) {
481
- const { version, flags } = view.readFullBox();
482
- const entryCount = view.readUint(4);
483
- return {
484
- type: "dref",
485
- version,
486
- flags,
487
- entryCount,
488
- entries: view.readBoxes(entryCount)
489
- };
490
- }
543
+ var IsoBoxReadView = class IsoBoxReadView {
544
+ /**
545
+ * Creates a new IsoView instance. Similar to DataView, but with additional
546
+ * methods for reading ISO BMFF data. It implements the iterator protocol,
547
+ * so it can be used in a for...of loop.
548
+ *
549
+ * @param raw - The raw data to view.
550
+ * @param config - The configuration for the IsoView.
551
+ */
552
+ constructor(raw, config) {
553
+ this.truncated = false;
554
+ this.slice = (offset, size) => {
555
+ const isoView = new IsoBoxReadView(new DataView(this.dataView.buffer, offset, size), this.config);
556
+ const headerSize = this.offset - offset;
557
+ const bodySize = size - headerSize;
558
+ this.offset += bodySize;
559
+ isoView.jump(headerSize);
560
+ return isoView;
561
+ };
562
+ this.read = (type, size = 0) => {
563
+ const { dataView, offset } = this;
564
+ let result;
565
+ let cursor = size;
566
+ switch (type) {
567
+ case UINT:
568
+ result = readUint(dataView, offset, size);
569
+ break;
570
+ case INT:
571
+ result = readInt(dataView, offset, size);
572
+ break;
573
+ case TEMPLATE:
574
+ result = readTemplate(dataView, offset, size);
575
+ break;
576
+ case STRING:
577
+ if (size === -1) {
578
+ result = readTerminatedString(dataView, offset);
579
+ cursor = result.length + 1;
580
+ } else result = readString(dataView, offset, size);
581
+ break;
582
+ case DATA:
583
+ result = readData(dataView, offset, size);
584
+ cursor = result.length;
585
+ break;
586
+ case UTF8:
587
+ if (size === -1) {
588
+ result = readUtf8TerminatedString(dataView, offset);
589
+ cursor = result.length + 1;
590
+ } else result = readUtf8String(dataView, offset);
591
+ break;
592
+ default: result = -1;
593
+ }
594
+ this.offset += cursor;
595
+ return result;
596
+ };
597
+ this.readUint = (size) => {
598
+ return this.read(UINT, size);
599
+ };
600
+ this.readInt = (size) => {
601
+ return this.read(INT, size);
602
+ };
603
+ this.readString = (size) => {
604
+ return this.read(STRING, size);
605
+ };
606
+ this.readTemplate = (size) => {
607
+ return this.read(TEMPLATE, size);
608
+ };
609
+ this.readData = (size) => {
610
+ return this.read(DATA, size);
611
+ };
612
+ this.readUtf8 = (size) => {
613
+ return this.read(UTF8, size);
614
+ };
615
+ this.readFullBox = () => {
616
+ return {
617
+ version: this.readUint(1),
618
+ flags: this.readUint(3)
619
+ };
620
+ };
621
+ this.readArray = (type, size, length) => {
622
+ const value = [];
623
+ for (let i = 0; i < length; i++) value.push(this.read(type, size));
624
+ return value;
625
+ };
626
+ this.jump = (size) => {
627
+ this.offset += size;
628
+ };
629
+ this.readBox = () => {
630
+ const { dataView, offset } = this;
631
+ let cursor = 0;
632
+ const size = readUint(dataView, offset, 4);
633
+ const type = readString(dataView, offset + 4, 4);
634
+ const box = {
635
+ size,
636
+ type
637
+ };
638
+ cursor += 8;
639
+ if (box.size === 1) {
640
+ box.largesize = readUint(dataView, offset + cursor, 8);
641
+ cursor += 8;
642
+ }
643
+ const actualSize = box.size === 0 ? this.bytesRemaining : box.largesize ?? box.size;
644
+ if (this.cursor + actualSize > dataView.byteLength) {
645
+ this.truncated = true;
646
+ throw new Error("Truncated box");
647
+ }
648
+ this.jump(cursor);
649
+ if (type === "uuid") box.usertype = this.readArray("uint", 1, 16);
650
+ box.view = this.slice(offset, actualSize);
651
+ return box;
652
+ };
653
+ this.readBoxes = (length = -1) => {
654
+ const result = [];
655
+ for (const box of this) {
656
+ result.push(box);
657
+ if (length > 0 && result.length >= length) break;
658
+ }
659
+ return result;
660
+ };
661
+ this.readEntries = (length, map) => {
662
+ const result = [];
663
+ for (let i = 0; i < length; i++) result.push(map());
664
+ return result;
665
+ };
666
+ this.dataView = raw instanceof ArrayBuffer ? new DataView(raw) : raw instanceof DataView ? raw : new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
667
+ this.offset = this.dataView.byteOffset;
668
+ this.config = config || { readers: {} };
669
+ }
670
+ /**
671
+ * The buffer of the data view.
672
+ */
673
+ get buffer() {
674
+ return this.dataView.buffer;
675
+ }
676
+ /**
677
+ * The byte offset of the data view.
678
+ */
679
+ get byteOffset() {
680
+ return this.dataView.byteOffset;
681
+ }
682
+ /**
683
+ * The byte length of the data view.
684
+ */
685
+ get byteLength() {
686
+ return this.dataView.byteLength;
687
+ }
688
+ /**
689
+ * The current byteoffset in the data view.
690
+ */
691
+ get cursor() {
692
+ return this.offset - this.dataView.byteOffset;
693
+ }
694
+ /**
695
+ * Whether the end of the data view has been reached.
696
+ */
697
+ get done() {
698
+ return this.cursor >= this.dataView.byteLength || this.truncated;
699
+ }
700
+ /**
701
+ * The number of bytes remaining in the data view.
702
+ */
703
+ get bytesRemaining() {
704
+ return this.dataView.byteLength - this.cursor;
705
+ }
706
+ /**
707
+ * Iterates over the boxes in the data view.
708
+ *
709
+ * @returns A generator of boxes.
710
+ */
711
+ *[Symbol.iterator]() {
712
+ const { readers = {} } = this.config;
713
+ while (!this.done) try {
714
+ const box = this.readBox();
715
+ const { type, view } = box;
716
+ const parser = readers[type] || readers[type.trim()];
717
+ if (parser) Object.assign(box, parser(view));
718
+ if (isContainer(box) && !box.boxes) {
719
+ const boxes = [];
720
+ for (const child of view) boxes.push(child);
721
+ box.boxes = boxes;
722
+ }
723
+ yield box;
724
+ } catch (error) {
725
+ if (error instanceof Error && error.message === "Truncated box") break;
726
+ throw error;
727
+ }
728
+ }
729
+ };
491
730
 
492
731
  //#endregion
493
- //#region src/readers/readElng.ts
732
+ //#region src/readIsoBoxes.ts
494
733
  /**
495
- * Parse a ExtendedLanguageBox from an IsoView
734
+ * Reads ISO boxes from a data source.
496
735
  *
497
- * @param view - The IsoView to read data from
736
+ * @param raw - The raw ISO data
737
+ * @param config - The configuration for the IsoView
498
738
  *
499
- * @returns A parsed ExtendedLanguageBox
739
+ * @returns The parsed boxes
740
+ *
741
+ * @example
742
+ * {@includeCode ../test/readIsoBoxes.test.ts#example}
500
743
  *
501
744
  * @public
502
745
  */
503
- function readElng(view) {
504
- return {
505
- type: "elng",
506
- ...view.readFullBox(),
507
- extendedLanguage: view.readUtf8(-1)
508
- };
746
+ function readIsoBoxes(raw, config) {
747
+ const boxes = [];
748
+ for (const box of new IsoBoxReadView(raw, config)) boxes.push(box);
749
+ return boxes;
509
750
  }
510
751
 
511
752
  //#endregion
512
- //#region src/readers/readElst.ts
753
+ //#region src/traverseIsoBoxes.ts
513
754
  /**
514
- * Parse a Box from an IsoView
755
+ * Traverse ISO boxes
515
756
  *
516
- * @param view - The IsoView to read data from
757
+ * @param boxes - The boxes to traverse
758
+ * @param depthFirst - Whether to traverse the boxes depth-first or breadth-first
759
+ * @param maxDepth - The maximum depth to traverse. A value of 0 will only traverse the root boxes.
517
760
  *
518
- * @returns A parsed Box
761
+ * @returns A generator of boxes
762
+ *
763
+ * @example
764
+ * {@includeCode ../test/traverseIsoBoxes.test.ts#example}
519
765
  *
520
766
  * @public
521
767
  */
522
- function readElst(view) {
523
- const { version, flags } = view.readFullBox();
524
- const size = version === 1 ? 8 : 4;
525
- const entryCount = view.readUint(4);
526
- return {
527
- type: "elst",
528
- version,
529
- flags,
530
- entryCount,
531
- entries: view.readEntries(entryCount, () => ({
532
- segmentDuration: view.readUint(size),
533
- mediaTime: view.readInt(size),
534
- mediaRateInteger: view.readInt(2),
535
- mediaRateFraction: view.readInt(2)
536
- }))
537
- };
538
- }
539
-
540
- //#endregion
541
- //#region src/readers/readEmsg.ts
542
- /**
543
- * Parse an EventMessageBox from an IsoView
544
- *
545
- * @param view - The IsoView to read data from
546
- *
547
- * @returns A parsed EventMessageBox
548
- *
549
- * @public
550
- */
551
- function readEmsg(view) {
552
- const { readUint: readUint$1, readString: readString$1, readData: readData$1 } = view;
553
- const result = {
554
- type: "emsg",
555
- ...view.readFullBox()
556
- };
557
- if (result.version == 1) {
558
- result.timescale = readUint$1(4);
559
- result.presentationTime = readUint$1(8);
560
- result.eventDuration = readUint$1(4);
561
- result.id = readUint$1(4);
562
- result.schemeIdUri = readString$1(-1);
563
- result.value = readString$1(-1);
564
- } else {
565
- result.schemeIdUri = readString$1(-1);
566
- result.value = readString$1(-1);
567
- result.timescale = readUint$1(4);
568
- result.presentationTimeDelta = readUint$1(4);
569
- result.eventDuration = readUint$1(4);
570
- result.id = readUint$1(4);
768
+ function* traverseIsoBoxes(boxes, depthFirst = true, maxDepth = Infinity) {
769
+ if (maxDepth < 0 || typeof maxDepth !== "number" || Number.isNaN(maxDepth)) return;
770
+ const queue = [[boxes, 0]];
771
+ while (queue.length > 0) {
772
+ const item = queue.shift();
773
+ if (!item) continue;
774
+ const [children, depth] = item;
775
+ for (const child of children) {
776
+ yield child;
777
+ if (depth >= maxDepth) continue;
778
+ if (isContainer(child) && child.boxes) {
779
+ const next = child.boxes;
780
+ if (depthFirst) yield* traverseIsoBoxes(next, depthFirst, maxDepth - 1);
781
+ else queue.push([next, depth + 1]);
782
+ }
783
+ }
571
784
  }
572
- result.messageData = readData$1(-1);
573
- return result;
574
785
  }
575
786
 
576
787
  //#endregion
577
- //#region src/readers/readMp4a.ts
788
+ //#region src/writeIsoBoxes.ts
578
789
  /**
579
- * Parse an AudioSampleEntry from an IsoView
580
- *
581
- * @param view - The IsoView to read data from
582
- *
583
- * @returns A parsed AudioSampleEntry
790
+ * Writes ISO boxes to a readable stream.
584
791
  *
585
- * @public
586
- */
587
- function readMp4a(view) {
588
- const { readArray, readUint: readUint$1, readTemplate: readTemplate$1, readData: readData$1 } = view;
589
- return {
590
- type: "mp4a",
591
- reserved1: readArray(UINT, 1, 6),
592
- dataReferenceIndex: readUint$1(2),
593
- reserved2: readArray(UINT, 4, 2),
594
- channelcount: readUint$1(2),
595
- samplesize: readUint$1(2),
596
- preDefined: readUint$1(2),
597
- reserved3: readUint$1(2),
598
- samplerate: readTemplate$1(4),
599
- esds: readData$1(-1)
600
- };
601
- }
602
-
603
- //#endregion
604
- //#region src/readers/readEnca.ts
605
- /**
606
- * Parse an AudioSampleEntry from an IsoView
792
+ * @param boxes - The boxes to write
793
+ * @param config - The configuration for the readable stream
607
794
  *
608
- * @param view - The IsoView to read data from
795
+ * @returns A readable stream of the written boxes
609
796
  *
610
- * @returns A parsed AudioSampleEntry
797
+ * @example
798
+ * {@includeCode ../test/writeIsoBoxes.test.ts#example}
611
799
  *
612
800
  * @public
613
801
  */
614
- function readEnca(view) {
615
- return {
616
- ...readMp4a(view),
617
- type: "enca"
618
- };
802
+ function writeIsoBoxes(boxes, config) {
803
+ return writeBoxes(boxes, createWriterConfig(config));
619
804
  }
620
805
 
621
806
  //#endregion
622
- //#region src/readers/readEncv.ts
807
+ //#region src/readers/readArdi.ts
623
808
  /**
624
- * Parse a VisualSampleEntryBox from an IsoView
809
+ * Parse a AudioRenderingIndicationBox from an IsoView
625
810
  *
626
811
  * @param view - The IsoView to read data from
627
812
  *
628
- * @returns A parsed VisualSampleEntryBox
813
+ * @returns A parsed AudioRenderingIndicationBox
629
814
  *
630
815
  * @public
631
816
  */
632
- function readEncv(view) {
817
+ function readArdi(view) {
633
818
  return {
634
- ...readAvc1(view),
635
- type: "encv"
819
+ type: "ardi",
820
+ ...view.readFullBox(),
821
+ audioRenderingIndication: view.readUint(1)
636
822
  };
637
823
  }
638
824
 
639
825
  //#endregion
640
- //#region src/readers/readFree.ts
826
+ //#region src/readers/readAudioSampleEntryBox.ts
641
827
  /**
642
- * Parse a Box from an IsoView
828
+ * Parse a AudioSampleEntryBox from an IsoView
643
829
  *
830
+ * @param type - The type of AudioSampleEntryBox to read
644
831
  * @param view - The IsoView to read data from
645
832
  *
646
- * @returns A parsed Box
833
+ * @returns A parsed AudioSampleEntryBox
647
834
  *
648
835
  * @public
649
836
  */
650
- function readFree(view) {
837
+ function readAudioSampleEntryBox(type, view) {
838
+ const { readArray, readUint: readUint$1, readTemplate: readTemplate$1, readBoxes } = view;
651
839
  return {
652
- type: "free",
653
- data: view.readData(-1)
840
+ type,
841
+ reserved1: readArray(UINT, 1, 6),
842
+ dataReferenceIndex: readUint$1(2),
843
+ reserved2: readArray(UINT, 4, 2),
844
+ channelcount: readUint$1(2),
845
+ samplesize: readUint$1(2),
846
+ preDefined: readUint$1(2),
847
+ reserved3: readUint$1(2),
848
+ samplerate: readTemplate$1(4),
849
+ boxes: readBoxes()
654
850
  };
655
851
  }
656
852
 
657
853
  //#endregion
658
- //#region src/readers/readFrma.ts
854
+ //#region src/readers/readVisualSampleEntryBox.ts
659
855
  /**
660
- * Parse an OriginalFormatBox from an IsoView
856
+ * Parse a VisualSampleEntryBox from an IsoView
661
857
  *
858
+ * @param type - The type of VisualSampleEntryBox to read
662
859
  * @param view - The IsoView to read data from
663
860
  *
664
- * @returns A parsed OriginalFormatBox
861
+ * @returns A parsed VisualSampleEntryBox
665
862
  *
666
863
  * @public
667
864
  */
668
- function readFrma(view) {
865
+ function readVisualSampleEntryBox(type, view) {
866
+ const { readArray, readUint: readUint$1, readInt: readInt$1, readTemplate: readTemplate$1, readBoxes } = view;
669
867
  return {
670
- type: "frma",
671
- dataFormat: view.readUint(4)
868
+ type,
869
+ reserved1: readArray(UINT, 1, 6),
870
+ dataReferenceIndex: readUint$1(2),
871
+ preDefined1: readUint$1(2),
872
+ reserved2: readUint$1(2),
873
+ preDefined2: readArray(UINT, 4, 3),
874
+ width: readUint$1(2),
875
+ height: readUint$1(2),
876
+ horizresolution: readTemplate$1(4),
877
+ vertresolution: readTemplate$1(4),
878
+ reserved3: readUint$1(4),
879
+ frameCount: readUint$1(2),
880
+ compressorName: readArray(UINT, 1, 32),
881
+ depth: readUint$1(2),
882
+ preDefined3: readInt$1(2),
883
+ boxes: readBoxes()
672
884
  };
673
885
  }
674
886
 
675
887
  //#endregion
676
- //#region src/fields/STRING.ts
677
- /**
678
- * The string field type
679
- *
680
- * @public
681
- */
682
- const STRING = "string";
683
-
684
- //#endregion
685
- //#region src/readers/readFtyp.ts
888
+ //#region src/readers/readAvc1.ts
686
889
  /**
687
- * Parse a FileTypeBox from an IsoView
890
+ * Parse a VisualSampleEntryBox from an IsoView
688
891
  *
689
892
  * @param view - The IsoView to read data from
690
893
  *
691
- * @returns A parsed FileTypeBox
894
+ * @returns A parsed VisualSampleEntryBox
692
895
  *
693
896
  * @public
694
897
  */
695
- function readFtyp(view) {
696
- const size = 4;
697
- const majorBrand = view.readString(4);
698
- const minorVersion = view.readUint(4);
699
- const length = view.bytesRemaining / size;
700
- return {
701
- type: "ftyp",
702
- majorBrand,
703
- minorVersion,
704
- compatibleBrands: view.readArray(STRING, size, length)
705
- };
898
+ function readAvc1(view) {
899
+ return readVisualSampleEntryBox("avc1", view);
706
900
  }
707
901
 
708
902
  //#endregion
709
- //#region src/readers/readHdlr.ts
903
+ //#region src/readers/readAvc2.ts
710
904
  /**
711
- * Parse a HandlerReferenceBox from an IsoView
905
+ * Parse a VisualSampleEntryBox from an IsoView
712
906
  *
713
907
  * @param view - The IsoView to read data from
714
908
  *
715
- * @returns A parsed HandlerReferenceBox
909
+ * @returns A parsed VisualSampleEntryBox
716
910
  *
717
911
  * @public
718
912
  */
719
- function readHdlr(view) {
720
- return {
721
- type: "hdlr",
722
- ...view.readFullBox(),
723
- preDefined: view.readUint(4),
724
- handlerType: view.readString(4),
725
- reserved: view.readArray(UINT, 4, 3),
726
- name: view.readString(-1)
727
- };
913
+ function readAvc2(view) {
914
+ return readVisualSampleEntryBox("avc2", view);
728
915
  }
729
916
 
730
917
  //#endregion
731
- //#region src/readers/readHev1.ts
918
+ //#region src/readers/readAvc3.ts
732
919
  /**
733
920
  * Parse a VisualSampleEntryBox from an IsoView
734
921
  *
@@ -738,15 +925,12 @@ function readHdlr(view) {
738
925
  *
739
926
  * @public
740
927
  */
741
- function readHev1(view) {
742
- return {
743
- ...readAvc1(view),
744
- type: "hev1"
745
- };
928
+ function readAvc3(view) {
929
+ return readVisualSampleEntryBox("avc3", view);
746
930
  }
747
931
 
748
932
  //#endregion
749
- //#region src/readers/readHvc1.ts
933
+ //#region src/readers/readAvc4.ts
750
934
  /**
751
935
  * Parse a VisualSampleEntryBox from an IsoView
752
936
  *
@@ -756,1432 +940,1289 @@ function readHev1(view) {
756
940
  *
757
941
  * @public
758
942
  */
759
- function readHvc1(view) {
760
- return {
761
- ...readAvc1(view),
762
- type: "hvc1"
763
- };
943
+ function readAvc4(view) {
944
+ return readVisualSampleEntryBox("avc4", view);
764
945
  }
765
946
 
766
947
  //#endregion
767
- //#region src/readers/readIden.ts
948
+ //#region src/readers/readCtts.ts
768
949
  /**
769
- * Parse a WebVTTCueIdBox from an IsoView
950
+ * Parse a CompositionTimeToSampleBox from an IsoView
770
951
  *
771
952
  * @param view - The IsoView to read data from
772
953
  *
773
- * @returns A parsed WebVTTCueIdBox
954
+ * @returns A parsed CompositionTimeToSampleBox
774
955
  *
775
956
  * @public
776
957
  */
777
- function readIden(view) {
958
+ function readCtts(view) {
959
+ const { version, flags } = view.readFullBox();
960
+ const read = version === 1 ? view.readInt : view.readUint;
961
+ const entryCount = view.readUint(4);
778
962
  return {
779
- type: "iden",
780
- cueId: view.readUtf8(-1)
963
+ type: "ctts",
964
+ version,
965
+ flags,
966
+ entryCount,
967
+ entries: view.readEntries(entryCount, () => ({
968
+ sampleCount: view.readUint(4),
969
+ sampleOffset: read(4)
970
+ }))
781
971
  };
782
972
  }
783
973
 
784
974
  //#endregion
785
- //#region src/readers/readImda.ts
975
+ //#region src/readers/readDref.ts
786
976
  /**
787
- * Parse a IdentifiedMediaDataBox from an IsoView
977
+ * Parse a DataReferenceBox from an IsoView
788
978
  *
789
979
  * @param view - The IsoView to read data from
790
980
  *
791
- * @returns A parsed IdentifiedMediaDataBox
981
+ * @returns A parsed DataReferenceBox
792
982
  *
793
983
  * @public
794
984
  */
795
- function readImda(view) {
985
+ function readDref(view) {
986
+ const { version, flags } = view.readFullBox();
987
+ const entryCount = view.readUint(4);
796
988
  return {
797
- type: "imda",
798
- imdaIdentifier: view.readUint(4),
799
- data: view.readData(-1)
989
+ type: "dref",
990
+ version,
991
+ flags,
992
+ entryCount,
993
+ entries: view.readBoxes(entryCount)
800
994
  };
801
995
  }
802
996
 
803
997
  //#endregion
804
- //#region src/readers/readKind.ts
998
+ //#region src/readers/readElng.ts
805
999
  /**
806
- * Parse a TrackKinBox from an IsoView
1000
+ * Parse a ExtendedLanguageBox from an IsoView
807
1001
  *
808
1002
  * @param view - The IsoView to read data from
809
1003
  *
810
- * @returns A parsed TrackKindBox
1004
+ * @returns A parsed ExtendedLanguageBox
811
1005
  *
812
1006
  * @public
813
1007
  */
814
- function readKind(view) {
1008
+ function readElng(view) {
815
1009
  return {
816
- type: "kind",
1010
+ type: "elng",
817
1011
  ...view.readFullBox(),
818
- schemeUri: view.readUtf8(-1),
819
- value: view.readUtf8(-1)
1012
+ extendedLanguage: view.readUtf8(-1)
820
1013
  };
821
1014
  }
822
1015
 
823
1016
  //#endregion
824
- //#region src/readers/readLabl.ts
1017
+ //#region src/readers/readElst.ts
825
1018
  /**
826
- * Parse a LabelBox from an IsoView
1019
+ * Parse a Box from an IsoView
827
1020
  *
828
1021
  * @param view - The IsoView to read data from
829
1022
  *
830
- * @returns A parsed LabelBox
1023
+ * @returns A parsed Box
831
1024
  *
832
1025
  * @public
833
1026
  */
834
- function readLabl(view) {
1027
+ function readElst(view) {
835
1028
  const { version, flags } = view.readFullBox();
1029
+ const size = version === 1 ? 8 : 4;
1030
+ const entryCount = view.readUint(4);
836
1031
  return {
837
- type: "labl",
1032
+ type: "elst",
838
1033
  version,
839
1034
  flags,
840
- isGroupLabel: (flags & 1) !== 0,
841
- labelId: view.readUint(2),
842
- language: view.readUtf8(-1),
843
- label: view.readUtf8(-1)
1035
+ entryCount,
1036
+ entries: view.readEntries(entryCount, () => ({
1037
+ segmentDuration: view.readUint(size),
1038
+ mediaTime: view.readInt(size),
1039
+ mediaRateInteger: view.readInt(2),
1040
+ mediaRateFraction: view.readInt(2)
1041
+ }))
844
1042
  };
845
1043
  }
846
1044
 
847
1045
  //#endregion
848
- //#region src/readers/readMdat.ts
1046
+ //#region src/readers/readEmsg.ts
849
1047
  /**
850
- * Parse a MediaDataBox from an IsoView
1048
+ * Parse an EventMessageBox from an IsoView
851
1049
  *
852
1050
  * @param view - The IsoView to read data from
853
1051
  *
854
- * @returns A parsed MediaDataBox
1052
+ * @returns A parsed EventMessageBox
855
1053
  *
856
1054
  * @public
857
1055
  */
858
- function readMdat(view) {
859
- return {
860
- type: "mdat",
861
- data: view.readData(-1)
1056
+ function readEmsg(view) {
1057
+ const { readUint: readUint$1, readString: readString$1, readData: readData$1 } = view;
1058
+ const result = {
1059
+ type: "emsg",
1060
+ ...view.readFullBox()
862
1061
  };
1062
+ if (result.version == 1) {
1063
+ result.timescale = readUint$1(4);
1064
+ result.presentationTime = readUint$1(8);
1065
+ result.eventDuration = readUint$1(4);
1066
+ result.id = readUint$1(4);
1067
+ result.schemeIdUri = readString$1(-1);
1068
+ result.value = readString$1(-1);
1069
+ } else {
1070
+ result.schemeIdUri = readString$1(-1);
1071
+ result.value = readString$1(-1);
1072
+ result.timescale = readUint$1(4);
1073
+ result.presentationTimeDelta = readUint$1(4);
1074
+ result.eventDuration = readUint$1(4);
1075
+ result.id = readUint$1(4);
1076
+ }
1077
+ result.messageData = readData$1(-1);
1078
+ return result;
863
1079
  }
864
1080
 
865
1081
  //#endregion
866
- //#region src/readers/readMdhd.ts
1082
+ //#region src/readers/readEnca.ts
867
1083
  /**
868
- * Parse a MediaHeaderBox from an IsoView
1084
+ * Parse an AudioSampleEntry from an IsoView
869
1085
  *
870
1086
  * @param view - The IsoView to read data from
871
1087
  *
872
- * @returns A parsed MediaHeaderBox
1088
+ * @returns A parsed AudioSampleEntry
873
1089
  *
874
1090
  * @public
875
1091
  */
876
- function readMdhd(view) {
877
- const { version, flags } = view.readFullBox();
878
- const creationTime = view.readUint(version == 1 ? 8 : 4);
879
- const modificationTime = view.readUint(version == 1 ? 8 : 4);
880
- const timescale = view.readUint(4);
881
- const duration = view.readUint(version == 1 ? 8 : 4);
882
- const lang = view.readUint(2);
883
- return {
884
- type: "mdhd",
885
- version,
886
- flags,
887
- creationTime,
888
- modificationTime,
889
- timescale,
890
- duration,
891
- language: String.fromCharCode((lang >> 10 & 31) + 96, (lang >> 5 & 31) + 96, (lang & 31) + 96),
892
- preDefined: view.readUint(2)
893
- };
1092
+ function readEnca(view) {
1093
+ return readAudioSampleEntryBox("enca", view);
894
1094
  }
895
1095
 
896
1096
  //#endregion
897
- //#region src/readers/readMehd.ts
1097
+ //#region src/readers/readEncv.ts
898
1098
  /**
899
- * Parse a MovieExtendsHeaderBox from an IsoView
1099
+ * Parse a VisualSampleEntryBox from an IsoView
900
1100
  *
901
1101
  * @param view - The IsoView to read data from
902
1102
  *
903
- * @returns A parsed MovieExtendsHeaderBox
1103
+ * @returns A parsed VisualSampleEntryBox
904
1104
  *
905
1105
  * @public
906
1106
  */
907
- function readMehd(view) {
908
- const { version, flags } = view.readFullBox();
909
- return {
910
- type: "mehd",
911
- version,
912
- flags,
913
- fragmentDuration: view.readUint(version === 1 ? 8 : 4)
914
- };
1107
+ function readEncv(view) {
1108
+ return readVisualSampleEntryBox("encv", view);
915
1109
  }
916
1110
 
917
1111
  //#endregion
918
- //#region src/readers/readMeta.ts
1112
+ //#region src/readers/readFree.ts
919
1113
  /**
920
- * Parse a MetaBox from an IsoView
1114
+ * Parse a Box from an IsoView
921
1115
  *
922
1116
  * @param view - The IsoView to read data from
923
1117
  *
924
- * @returns A parsed MetaBox
1118
+ * @returns A parsed Box
925
1119
  *
926
1120
  * @public
927
1121
  */
928
- function readMeta(view) {
1122
+ function readFree(view) {
929
1123
  return {
930
- type: "meta",
931
- ...view.readFullBox(),
932
- boxes: view.readBoxes()
1124
+ type: "free",
1125
+ data: view.readData(-1)
933
1126
  };
934
1127
  }
935
1128
 
936
1129
  //#endregion
937
- //#region src/readers/readMfhd.ts
1130
+ //#region src/readers/readFrma.ts
938
1131
  /**
939
- * Parse a MovieFragmentHeaderBox from an IsoView
1132
+ * Parse an OriginalFormatBox from an IsoView
940
1133
  *
941
1134
  * @param view - The IsoView to read data from
942
1135
  *
943
- * @returns A parsed MovieFragmentHeaderBox
1136
+ * @returns A parsed OriginalFormatBox
944
1137
  *
945
1138
  * @public
946
1139
  */
947
- function readMfhd(view) {
1140
+ function readFrma(view) {
948
1141
  return {
949
- type: "mfhd",
950
- ...view.readFullBox(),
951
- sequenceNumber: view.readUint(4)
1142
+ type: "frma",
1143
+ dataFormat: view.readUint(4)
952
1144
  };
953
1145
  }
954
1146
 
955
1147
  //#endregion
956
- //#region src/readers/readMfro.ts
1148
+ //#region src/readers/readFtyp.ts
957
1149
  /**
958
- * Parse a MovieFragmentRandomAccessBox from an IsoView
1150
+ * Parse a FileTypeBox from an IsoView
959
1151
  *
960
1152
  * @param view - The IsoView to read data from
961
1153
  *
962
- * @returns A parsed MovieFragmentRandomAccessBox
1154
+ * @returns A parsed FileTypeBox
963
1155
  *
964
1156
  * @public
965
1157
  */
966
- function readMfro(view) {
1158
+ function readFtyp(view) {
1159
+ const size = 4;
1160
+ const majorBrand = view.readString(4);
1161
+ const minorVersion = view.readUint(4);
1162
+ const length = view.bytesRemaining / size;
967
1163
  return {
968
- type: "mfro",
969
- ...view.readFullBox(),
970
- mfraSize: view.readUint(4)
1164
+ type: "ftyp",
1165
+ majorBrand,
1166
+ minorVersion,
1167
+ compatibleBrands: view.readArray(STRING, size, length)
971
1168
  };
972
1169
  }
973
1170
 
974
1171
  //#endregion
975
- //#region src/readers/readMvhd.ts
1172
+ //#region src/readers/readHdlr.ts
976
1173
  /**
977
- * Parse a Box from an IsoView
1174
+ * Parse a HandlerReferenceBox from an IsoView
978
1175
  *
979
1176
  * @param view - The IsoView to read data from
980
1177
  *
981
- * @returns A parsed Box
1178
+ * @returns A parsed HandlerReferenceBox
982
1179
  *
983
1180
  * @public
984
1181
  */
985
- function readMvhd(view) {
986
- const { readUint: readUint$1, readTemplate: readTemplate$1, readArray } = view;
987
- const { version, flags } = view.readFullBox();
988
- const size = version == 1 ? 8 : 4;
1182
+ function readHdlr(view) {
989
1183
  return {
990
- type: "mvhd",
991
- version,
992
- flags,
993
- creationTime: readUint$1(size),
994
- modificationTime: readUint$1(size),
995
- timescale: readUint$1(4),
996
- duration: readUint$1(size),
997
- rate: readTemplate$1(4),
998
- volume: readTemplate$1(2),
999
- reserved1: readUint$1(2),
1000
- reserved2: readArray(UINT, 4, 2),
1001
- matrix: readArray(TEMPLATE, 4, 9),
1002
- preDefined: readArray(UINT, 4, 6),
1003
- nextTrackId: readUint$1(4)
1184
+ type: "hdlr",
1185
+ ...view.readFullBox(),
1186
+ preDefined: view.readUint(4),
1187
+ handlerType: view.readString(4),
1188
+ reserved: view.readArray(UINT, 4, 3),
1189
+ name: view.readString(-1)
1004
1190
  };
1005
1191
  }
1006
1192
 
1007
1193
  //#endregion
1008
- //#region src/readers/readPayl.ts
1194
+ //#region src/readers/readHev1.ts
1009
1195
  /**
1010
- * Parse a WebVTTCuePayloadBox from an IsoView
1196
+ * Parse a VisualSampleEntryBox from an IsoView
1011
1197
  *
1012
1198
  * @param view - The IsoView to read data from
1013
1199
  *
1014
- * @returns A parsed WebVTTCuePayloadBox
1200
+ * @returns A parsed VisualSampleEntryBox
1015
1201
  *
1016
1202
  * @public
1017
1203
  */
1018
- function readPayl(view) {
1019
- return {
1020
- type: "payl",
1021
- cueText: view.readUtf8(-1)
1022
- };
1204
+ function readHev1(view) {
1205
+ return readVisualSampleEntryBox("hev1", view);
1023
1206
  }
1024
1207
 
1025
1208
  //#endregion
1026
- //#region src/readers/readPrft.ts
1209
+ //#region src/readers/readHvc1.ts
1027
1210
  /**
1028
- * Parse a ProducerReferenceTimeBox from an IsoView
1211
+ * Parse a VisualSampleEntryBox from an IsoView
1029
1212
  *
1030
1213
  * @param view - The IsoView to read data from
1031
1214
  *
1032
- * @returns A parsed ProducerReferenceTimeBox
1215
+ * @returns A parsed VisualSampleEntryBox
1033
1216
  *
1034
1217
  * @public
1035
1218
  */
1036
- function readPrft(view) {
1037
- const { version, flags } = view.readFullBox();
1038
- return {
1039
- type: "prft",
1040
- version,
1041
- flags,
1042
- referenceTrackId: view.readUint(4),
1043
- ntpTimestampSec: view.readUint(4),
1044
- ntpTimestampFrac: view.readUint(4),
1045
- mediaTime: view.readUint(version === 1 ? 8 : 4)
1046
- };
1219
+ function readHvc1(view) {
1220
+ return readVisualSampleEntryBox("hvc1", view);
1047
1221
  }
1048
1222
 
1049
1223
  //#endregion
1050
- //#region src/readers/readPrsl.ts
1224
+ //#region src/readers/readIden.ts
1051
1225
  /**
1052
- * Parse a PreselectionGroupBox from an IsoView
1226
+ * Parse a WebVTTCueIdBox from an IsoView
1053
1227
  *
1054
1228
  * @param view - The IsoView to read data from
1055
1229
  *
1056
- * @returns A parsed PreselectionGroupBox
1230
+ * @returns A parsed WebVTTCueIdBox
1057
1231
  *
1058
1232
  * @public
1059
1233
  */
1060
- function readPrsl(view) {
1061
- const { version, flags } = view.readFullBox();
1062
- const groupId = view.readUint(4);
1063
- const numEntitiesInGroup = view.readUint(4);
1234
+ function readIden(view) {
1064
1235
  return {
1065
- type: "prsl",
1066
- version,
1067
- flags,
1068
- groupId,
1069
- numEntitiesInGroup,
1070
- entities: view.readEntries(numEntitiesInGroup, () => ({ entityId: view.readUint(4) })),
1071
- preselectionTag: flags & 4096 ? view.readUtf8(-1) : void 0,
1072
- selectionPriority: flags & 8192 ? view.readUint(1) : void 0,
1073
- interleavingTag: flags & 16384 ? view.readUtf8(-1) : void 0
1236
+ type: "iden",
1237
+ cueId: view.readUtf8(-1)
1074
1238
  };
1075
1239
  }
1076
1240
 
1077
1241
  //#endregion
1078
- //#region src/readers/readPssh.ts
1242
+ //#region src/readers/readImda.ts
1079
1243
  /**
1080
- * Parse a ProtectionSystemSpecificHeaderBox from an IsoView
1244
+ * Parse a IdentifiedMediaDataBox from an IsoView
1081
1245
  *
1082
1246
  * @param view - The IsoView to read data from
1083
1247
  *
1084
- * @returns A parsed ProtectionSystemSpecificHeaderBox
1248
+ * @returns A parsed IdentifiedMediaDataBox
1085
1249
  *
1086
1250
  * @public
1087
1251
  */
1088
- function readPssh(view) {
1089
- const { readUint: readUint$1, readArray } = view;
1090
- const { version, flags } = view.readFullBox();
1091
- const systemId = readArray(UINT, 1, 16);
1092
- let kidCount = 0;
1093
- let kid = [];
1094
- if (version > 0) {
1095
- kidCount = readUint$1(4);
1096
- kid = readArray(UINT, 1, kidCount);
1097
- }
1098
- const dataSize = readUint$1(4);
1099
- const data = readArray(UINT, 1, dataSize);
1252
+ function readImda(view) {
1100
1253
  return {
1101
- type: "pssh",
1102
- version,
1103
- flags,
1104
- systemId,
1105
- kidCount,
1106
- kid,
1107
- dataSize,
1108
- data
1254
+ type: "imda",
1255
+ imdaIdentifier: view.readUint(4),
1256
+ data: view.readData(-1)
1109
1257
  };
1110
1258
  }
1111
1259
 
1112
1260
  //#endregion
1113
- //#region src/readers/readSchm.ts
1261
+ //#region src/readers/readKind.ts
1114
1262
  /**
1115
- * Parse a SchemeTypeBox from an IsoView
1263
+ * Parse a TrackKinBox from an IsoView
1116
1264
  *
1117
1265
  * @param view - The IsoView to read data from
1118
1266
  *
1119
- * @returns A parsed SchemeTypeBox
1267
+ * @returns A parsed TrackKindBox
1120
1268
  *
1121
1269
  * @public
1122
1270
  */
1123
- function readSchm(view) {
1124
- const { version, flags } = view.readFullBox();
1271
+ function readKind(view) {
1125
1272
  return {
1126
- type: "schm",
1127
- version,
1128
- flags,
1129
- schemeType: view.readUint(4),
1130
- schemeVersion: view.readUint(4),
1131
- schemeUri: flags & 1 ? view.readString(-1) : void 0
1273
+ type: "kind",
1274
+ ...view.readFullBox(),
1275
+ schemeUri: view.readUtf8(-1),
1276
+ value: view.readUtf8(-1)
1132
1277
  };
1133
1278
  }
1134
1279
 
1135
1280
  //#endregion
1136
- //#region src/readers/readSdtp.ts
1281
+ //#region src/readers/readLabl.ts
1137
1282
  /**
1138
- * Parse a SampleDependencyTypeBox from an IsoView
1283
+ * Parse a LabelBox from an IsoView
1139
1284
  *
1140
1285
  * @param view - The IsoView to read data from
1141
1286
  *
1142
- * @returns A parsed SampleDependencyTypeBox
1287
+ * @returns A parsed LabelBox
1143
1288
  *
1144
1289
  * @public
1145
1290
  */
1146
- function readSdtp(view) {
1147
- return {
1148
- type: "sdtp",
1149
- ...view.readFullBox(),
1150
- sampleDependencyTable: view.readArray(UINT, 1, view.bytesRemaining)
1151
- };
1152
- }
1153
-
1154
- //#endregion
1155
- //#region src/readers/readSidx.ts
1156
- /**
1157
- * Parse a SegmentIndexBox from an IsoView
1158
- *
1159
- * @param view - The IsoView to read data from
1160
- *
1161
- * @returns A parsed SegmentIndexBox
1162
- *
1163
- * @public
1164
- */
1165
- function readSidx(view) {
1166
- const { readUint: readUint$1 } = view;
1291
+ function readLabl(view) {
1167
1292
  const { version, flags } = view.readFullBox();
1168
- const size = version === 1 ? 8 : 4;
1169
- const referenceId = readUint$1(4);
1170
- const timescale = readUint$1(4);
1171
- const earliestPresentationTime = readUint$1(size);
1172
- const firstOffset = readUint$1(size);
1173
- const reserved = readUint$1(2);
1174
- const referenceCount = readUint$1(2);
1175
1293
  return {
1176
- type: "sidx",
1294
+ type: "labl",
1177
1295
  version,
1178
1296
  flags,
1179
- referenceId,
1180
- timescale,
1181
- earliestPresentationTime,
1182
- firstOffset,
1183
- reserved,
1184
- references: view.readEntries(referenceCount, () => {
1185
- const entry = {};
1186
- entry.reference = readUint$1(4);
1187
- entry.subsegmentDuration = readUint$1(4);
1188
- entry.sap = readUint$1(4);
1189
- entry.referenceType = entry.reference >> 31 & 1;
1190
- entry.referencedSize = entry.reference & 2147483647;
1191
- entry.startsWithSap = entry.sap >> 31 & 1;
1192
- entry.sapType = entry.sap >> 28 & 7;
1193
- entry.sapDeltaTime = entry.sap & 268435455;
1194
- return entry;
1195
- })
1297
+ isGroupLabel: (flags & 1) !== 0,
1298
+ labelId: view.readUint(2),
1299
+ language: view.readUtf8(-1),
1300
+ label: view.readUtf8(-1)
1196
1301
  };
1197
1302
  }
1198
1303
 
1199
1304
  //#endregion
1200
- //#region src/readers/readSkip.ts
1305
+ //#region src/readers/readMdat.ts
1201
1306
  /**
1202
- * Parse a FreeSpaceBox from an IsoView
1307
+ * Parse a MediaDataBox from an IsoView
1203
1308
  *
1204
1309
  * @param view - The IsoView to read data from
1205
1310
  *
1206
- * @returns A parsed FreeSpaceBox
1311
+ * @returns A parsed MediaDataBox
1207
1312
  *
1208
1313
  * @public
1209
1314
  */
1210
- function readSkip(view) {
1315
+ function readMdat(view) {
1211
1316
  return {
1212
- ...readFree(view),
1213
- type: "skip"
1317
+ type: "mdat",
1318
+ data: view.readData(-1)
1214
1319
  };
1215
1320
  }
1216
1321
 
1217
1322
  //#endregion
1218
- //#region src/readers/readSmhd.ts
1323
+ //#region src/readers/readMdhd.ts
1219
1324
  /**
1220
- * Parse a SoundMediaHeaderBox from an IsoView
1325
+ * Parse a MediaHeaderBox from an IsoView
1221
1326
  *
1222
1327
  * @param view - The IsoView to read data from
1223
1328
  *
1224
- * @returns A parsed SoundMediaHeaderBox
1329
+ * @returns A parsed MediaHeaderBox
1225
1330
  *
1226
1331
  * @public
1227
1332
  */
1228
- function readSmhd(view) {
1333
+ function readMdhd(view) {
1334
+ const { version, flags } = view.readFullBox();
1335
+ const creationTime = view.readUint(version == 1 ? 8 : 4);
1336
+ const modificationTime = view.readUint(version == 1 ? 8 : 4);
1337
+ const timescale = view.readUint(4);
1338
+ const duration = view.readUint(version == 1 ? 8 : 4);
1339
+ const lang = view.readUint(2);
1229
1340
  return {
1230
- type: "smhd",
1231
- ...view.readFullBox(),
1232
- balance: view.readUint(2),
1233
- reserved: view.readUint(2)
1341
+ type: "mdhd",
1342
+ version,
1343
+ flags,
1344
+ creationTime,
1345
+ modificationTime,
1346
+ timescale,
1347
+ duration,
1348
+ language: String.fromCharCode((lang >> 10 & 31) + 96, (lang >> 5 & 31) + 96, (lang & 31) + 96),
1349
+ preDefined: view.readUint(2)
1234
1350
  };
1235
1351
  }
1236
1352
 
1237
1353
  //#endregion
1238
- //#region src/readers/readSsix.ts
1354
+ //#region src/readers/readMehd.ts
1239
1355
  /**
1240
- * Parse a SubsegmentIndexBox from an IsoView
1356
+ * Parse a MovieExtendsHeaderBox from an IsoView
1241
1357
  *
1242
1358
  * @param view - The IsoView to read data from
1243
1359
  *
1244
- * @returns A parsed SubsegmentIndexBox
1360
+ * @returns A parsed MovieExtendsHeaderBox
1245
1361
  *
1246
1362
  * @public
1247
1363
  */
1248
- function readSsix(view) {
1364
+ function readMehd(view) {
1249
1365
  const { version, flags } = view.readFullBox();
1250
- const subsegmentCount = view.readUint(4);
1251
1366
  return {
1252
- type: "ssix",
1367
+ type: "mehd",
1253
1368
  version,
1254
1369
  flags,
1255
- subsegmentCount,
1256
- subsegments: view.readEntries(subsegmentCount, () => {
1257
- const rangesCount = view.readUint(4);
1258
- return {
1259
- rangesCount,
1260
- ranges: view.readEntries(rangesCount, () => ({
1261
- level: view.readUint(1),
1262
- rangeSize: view.readUint(3)
1263
- }))
1264
- };
1265
- })
1370
+ fragmentDuration: view.readUint(version === 1 ? 8 : 4)
1266
1371
  };
1267
1372
  }
1268
1373
 
1269
1374
  //#endregion
1270
- //#region src/readers/readSthd.ts
1375
+ //#region src/readers/readMeta.ts
1271
1376
  /**
1272
- * Parse a SubtitleMediaHeaderBox from an IsoView
1377
+ * Parse a MetaBox from an IsoView
1273
1378
  *
1274
1379
  * @param view - The IsoView to read data from
1275
1380
  *
1276
- * @returns A parsed SubtitleMediaHeaderBox
1381
+ * @returns A parsed MetaBox
1277
1382
  *
1278
1383
  * @public
1279
1384
  */
1280
- function readSthd(view) {
1385
+ function readMeta(view) {
1281
1386
  return {
1282
- type: "sthd",
1283
- ...view.readFullBox()
1387
+ type: "meta",
1388
+ ...view.readFullBox(),
1389
+ boxes: view.readBoxes()
1284
1390
  };
1285
1391
  }
1286
1392
 
1287
1393
  //#endregion
1288
- //#region src/readers/readStsd.ts
1394
+ //#region src/readers/readMfhd.ts
1289
1395
  /**
1290
- * Parse a SampleDescriptionBox from an IsoView
1396
+ * Parse a MovieFragmentHeaderBox from an IsoView
1291
1397
  *
1292
1398
  * @param view - The IsoView to read data from
1293
1399
  *
1294
- * @returns A parsed SampleDescriptionBox
1400
+ * @returns A parsed MovieFragmentHeaderBox
1295
1401
  *
1296
1402
  * @public
1297
1403
  */
1298
- function readStsd(view) {
1299
- const { version, flags } = view.readFullBox();
1300
- const entryCount = view.readUint(4);
1404
+ function readMfhd(view) {
1301
1405
  return {
1302
- type: "stsd",
1303
- version,
1304
- flags,
1305
- entryCount,
1306
- entries: view.readBoxes(entryCount)
1406
+ type: "mfhd",
1407
+ ...view.readFullBox(),
1408
+ sequenceNumber: view.readUint(4)
1307
1409
  };
1308
1410
  }
1309
1411
 
1310
1412
  //#endregion
1311
- //#region src/readers/readStss.ts
1413
+ //#region src/readers/readMfro.ts
1312
1414
  /**
1313
- * Parse a SyncSampleBox from an IsoView
1415
+ * Parse a MovieFragmentRandomAccessBox from an IsoView
1314
1416
  *
1315
1417
  * @param view - The IsoView to read data from
1316
1418
  *
1317
- * @returns A parsed SyncSampleBox
1419
+ * @returns A parsed MovieFragmentRandomAccessBox
1318
1420
  *
1319
1421
  * @public
1320
1422
  */
1321
- function readStss(view) {
1322
- const { version, flags } = view.readFullBox();
1323
- const entryCount = view.readUint(4);
1423
+ function readMfro(view) {
1324
1424
  return {
1325
- type: "stss",
1326
- version,
1327
- flags,
1328
- entryCount,
1329
- entries: view.readEntries(entryCount, () => ({ sampleNumber: view.readUint(4) }))
1425
+ type: "mfro",
1426
+ ...view.readFullBox(),
1427
+ mfraSize: view.readUint(4)
1330
1428
  };
1331
1429
  }
1332
1430
 
1333
1431
  //#endregion
1334
- //#region src/readers/readSttg.ts
1432
+ //#region src/readers/readMp4a.ts
1335
1433
  /**
1336
- * Parse a WebVTTSettingsBox from an IsoView
1434
+ * Parse an AudioSampleEntry from an IsoView
1337
1435
  *
1338
1436
  * @param view - The IsoView to read data from
1339
1437
  *
1340
- * @returns A parsed WebVTTSettingsBox
1438
+ * @returns A parsed AudioSampleEntry
1341
1439
  *
1342
1440
  * @public
1343
1441
  */
1344
- function readSttg(view) {
1345
- return {
1346
- type: "sttg",
1347
- settings: view.readUtf8(-1)
1348
- };
1442
+ function readMp4a(view) {
1443
+ return readAudioSampleEntryBox("mp4a", view);
1349
1444
  }
1350
1445
 
1351
1446
  //#endregion
1352
- //#region src/readers/readStts.ts
1447
+ //#region src/readers/readMvhd.ts
1353
1448
  /**
1354
- * Parse a DecodingTimeToSampleBox from an IsoView
1449
+ * Parse a Box from an IsoView
1355
1450
  *
1356
1451
  * @param view - The IsoView to read data from
1357
1452
  *
1358
- * @returns A parsed DecodingTimeToSampleBox
1453
+ * @returns A parsed Box
1359
1454
  *
1360
1455
  * @public
1361
1456
  */
1362
- function readStts(view) {
1457
+ function readMvhd(view) {
1458
+ const { readUint: readUint$1, readTemplate: readTemplate$1, readArray } = view;
1363
1459
  const { version, flags } = view.readFullBox();
1364
- const entryCount = view.readUint(4);
1460
+ const size = version == 1 ? 8 : 4;
1365
1461
  return {
1366
- type: "stts",
1462
+ type: "mvhd",
1367
1463
  version,
1368
1464
  flags,
1369
- entryCount,
1370
- entries: view.readEntries(entryCount, () => ({
1371
- sampleCount: view.readUint(4),
1372
- sampleDelta: view.readUint(4)
1373
- }))
1465
+ creationTime: readUint$1(size),
1466
+ modificationTime: readUint$1(size),
1467
+ timescale: readUint$1(4),
1468
+ duration: readUint$1(size),
1469
+ rate: readTemplate$1(4),
1470
+ volume: readTemplate$1(2),
1471
+ reserved1: readUint$1(2),
1472
+ reserved2: readArray(UINT, 4, 2),
1473
+ matrix: readArray(TEMPLATE, 4, 9),
1474
+ preDefined: readArray(UINT, 4, 6),
1475
+ nextTrackId: readUint$1(4)
1374
1476
  };
1375
1477
  }
1376
1478
 
1377
1479
  //#endregion
1378
- //#region src/readers/readStyp.ts
1480
+ //#region src/readers/readPayl.ts
1379
1481
  /**
1380
- * Parse a SegmentTypeBox from an IsoView
1482
+ * Parse a WebVTTCuePayloadBox from an IsoView
1381
1483
  *
1382
1484
  * @param view - The IsoView to read data from
1383
1485
  *
1384
- * @returns A parsed SegmentTypeBox
1486
+ * @returns A parsed WebVTTCuePayloadBox
1385
1487
  *
1386
1488
  * @public
1387
1489
  */
1388
- function readStyp(view) {
1490
+ function readPayl(view) {
1389
1491
  return {
1390
- ...readFtyp(view),
1391
- type: "styp"
1492
+ type: "payl",
1493
+ cueText: view.readUtf8(-1)
1392
1494
  };
1393
1495
  }
1394
1496
 
1395
1497
  //#endregion
1396
- //#region src/readers/readSubs.ts
1498
+ //#region src/readers/readPrft.ts
1397
1499
  /**
1398
- * Parse a SubSampleInformationBox from an IsoView
1500
+ * Parse a ProducerReferenceTimeBox from an IsoView
1399
1501
  *
1400
1502
  * @param view - The IsoView to read data from
1401
1503
  *
1402
- * @returns A parsed SubSampleInformationBox
1504
+ * @returns A parsed ProducerReferenceTimeBox
1403
1505
  *
1404
1506
  * @public
1405
1507
  */
1406
- function readSubs(view) {
1508
+ function readPrft(view) {
1407
1509
  const { version, flags } = view.readFullBox();
1408
- const entryCount = view.readUint(4);
1409
1510
  return {
1410
- type: "subs",
1511
+ type: "prft",
1411
1512
  version,
1412
1513
  flags,
1413
- entryCount,
1414
- entries: view.readEntries(entryCount, () => {
1415
- const sampleDelta = view.readUint(4);
1416
- const subsampleCount = view.readUint(2);
1417
- return {
1418
- sampleDelta,
1419
- subsampleCount,
1420
- subsamples: view.readEntries(subsampleCount, () => ({
1421
- subsampleSize: view.readUint(version === 1 ? 4 : 2),
1422
- subsamplePriority: view.readUint(1),
1423
- discardable: view.readUint(1),
1424
- codecSpecificParameters: view.readUint(4)
1425
- }))
1426
- };
1427
- })
1514
+ referenceTrackId: view.readUint(4),
1515
+ ntpTimestampSec: view.readUint(4),
1516
+ ntpTimestampFrac: view.readUint(4),
1517
+ mediaTime: view.readUint(version === 1 ? 8 : 4)
1428
1518
  };
1429
1519
  }
1430
1520
 
1431
1521
  //#endregion
1432
- //#region src/readers/readTenc.ts
1522
+ //#region src/readers/readPrsl.ts
1433
1523
  /**
1434
- * Parse a TrackEncryptionBox from an IsoView
1524
+ * Parse a PreselectionGroupBox from an IsoView
1435
1525
  *
1436
1526
  * @param view - The IsoView to read data from
1437
1527
  *
1438
- * @returns A parsed TrackEncryptionBox
1528
+ * @returns A parsed PreselectionGroupBox
1439
1529
  *
1440
1530
  * @public
1441
1531
  */
1442
- function readTenc(view) {
1532
+ function readPrsl(view) {
1533
+ const { version, flags } = view.readFullBox();
1534
+ const groupId = view.readUint(4);
1535
+ const numEntitiesInGroup = view.readUint(4);
1443
1536
  return {
1444
- type: "tenc",
1445
- ...view.readFullBox(),
1446
- defaultIsEncrypted: view.readUint(3),
1447
- defaultIvSize: view.readUint(1),
1448
- defaultKid: view.readArray(UINT, 1, 16)
1537
+ type: "prsl",
1538
+ version,
1539
+ flags,
1540
+ groupId,
1541
+ numEntitiesInGroup,
1542
+ entities: view.readEntries(numEntitiesInGroup, () => ({ entityId: view.readUint(4) })),
1543
+ preselectionTag: flags & 4096 ? view.readUtf8(-1) : void 0,
1544
+ selectionPriority: flags & 8192 ? view.readUint(1) : void 0,
1545
+ interleavingTag: flags & 16384 ? view.readUtf8(-1) : void 0,
1546
+ boxes: view.readBoxes()
1449
1547
  };
1450
1548
  }
1451
1549
 
1452
1550
  //#endregion
1453
- //#region src/readers/readTfdt.ts
1551
+ //#region src/readers/readPssh.ts
1454
1552
  /**
1455
- * Parse a TrackFragmentDecodeTimeBox from an IsoView
1553
+ * Parse a ProtectionSystemSpecificHeaderBox from an IsoView
1456
1554
  *
1457
1555
  * @param view - The IsoView to read data from
1458
1556
  *
1459
- * @returns A parsed TrackFragmentDecodeTimeBox
1557
+ * @returns A parsed ProtectionSystemSpecificHeaderBox
1460
1558
  *
1461
1559
  * @public
1462
1560
  */
1463
- function readTfdt(view) {
1561
+ function readPssh(view) {
1562
+ const { readUint: readUint$1, readArray } = view;
1464
1563
  const { version, flags } = view.readFullBox();
1564
+ const systemId = readArray(UINT, 1, 16);
1565
+ let kidCount = 0;
1566
+ let kid = [];
1567
+ if (version > 0) {
1568
+ kidCount = readUint$1(4);
1569
+ kid = readArray(UINT, 1, kidCount);
1570
+ }
1571
+ const dataSize = readUint$1(4);
1572
+ const data = readArray(UINT, 1, dataSize);
1465
1573
  return {
1466
- type: "tfdt",
1574
+ type: "pssh",
1467
1575
  version,
1468
1576
  flags,
1469
- baseMediaDecodeTime: view.readUint(version == 1 ? 8 : 4)
1577
+ systemId,
1578
+ kidCount,
1579
+ kid,
1580
+ dataSize,
1581
+ data
1470
1582
  };
1471
1583
  }
1472
1584
 
1473
1585
  //#endregion
1474
- //#region src/readers/readTfhd.ts
1586
+ //#region src/readers/readSchm.ts
1475
1587
  /**
1476
- * Parse a TrackFragmentHeaderBox from an IsoView
1588
+ * Parse a SchemeTypeBox from an IsoView
1477
1589
  *
1478
1590
  * @param view - The IsoView to read data from
1479
1591
  *
1480
- * @returns A parsed TrackFragmentHeaderBox
1592
+ * @returns A parsed SchemeTypeBox
1481
1593
  *
1482
1594
  * @public
1483
1595
  */
1484
- function readTfhd(view) {
1596
+ function readSchm(view) {
1485
1597
  const { version, flags } = view.readFullBox();
1486
1598
  return {
1487
- type: "tfhd",
1599
+ type: "schm",
1488
1600
  version,
1489
1601
  flags,
1490
- trackId: view.readUint(4),
1491
- baseDataOffset: flags & 1 ? view.readUint(8) : void 0,
1492
- sampleDescriptionIndex: flags & 2 ? view.readUint(4) : void 0,
1493
- defaultSampleDuration: flags & 8 ? view.readUint(4) : void 0,
1494
- defaultSampleSize: flags & 16 ? view.readUint(4) : void 0,
1495
- defaultSampleFlags: flags & 32 ? view.readUint(4) : void 0
1602
+ schemeType: view.readUint(4),
1603
+ schemeVersion: view.readUint(4),
1604
+ schemeUri: flags & 1 ? view.readString(-1) : void 0
1496
1605
  };
1497
1606
  }
1498
1607
 
1499
1608
  //#endregion
1500
- //#region src/readers/readTfra.ts
1609
+ //#region src/readers/readSdtp.ts
1501
1610
  /**
1502
- * Parse a TrackFragmentRandomAccessBox from an IsoView
1611
+ * Parse a SampleDependencyTypeBox from an IsoView
1503
1612
  *
1504
1613
  * @param view - The IsoView to read data from
1505
1614
  *
1506
- * @returns A parsed TrackFragmentRandomAccessBox
1615
+ * @returns A parsed SampleDependencyTypeBox
1507
1616
  *
1508
1617
  * @public
1509
1618
  */
1510
- function readTfra(view) {
1511
- const { version, flags } = view.readFullBox();
1512
- const trackId = view.readUint(4);
1513
- const reserved = view.readUint(4);
1514
- const lengthSizeOfTrafNum = (reserved & 48) >> 4;
1515
- const lengthSizeOfTrunNum = (reserved & 12) >> 2;
1516
- const lengthSizeOfSampleNum = reserved & 3;
1517
- const numberOfEntry = view.readUint(4);
1619
+ function readSdtp(view) {
1518
1620
  return {
1519
- type: "tfra",
1520
- version,
1521
- flags,
1522
- trackId,
1523
- reserved,
1524
- lengthSizeOfTrafNum,
1525
- lengthSizeOfTrunNum,
1526
- lengthSizeOfSampleNum,
1527
- numberOfEntry,
1528
- entries: view.readEntries(numberOfEntry, () => ({
1529
- time: view.readUint(version === 1 ? 8 : 4),
1530
- moofOffset: view.readUint(version === 1 ? 8 : 4),
1531
- trafNumber: view.readUint(lengthSizeOfTrafNum + 1),
1532
- trunNumber: view.readUint(lengthSizeOfTrunNum + 1),
1533
- sampleNumber: view.readUint(lengthSizeOfSampleNum + 1)
1534
- }))
1621
+ type: "sdtp",
1622
+ ...view.readFullBox(),
1623
+ sampleDependencyTable: view.readArray(UINT, 1, view.bytesRemaining)
1535
1624
  };
1536
1625
  }
1537
1626
 
1538
1627
  //#endregion
1539
- //#region src/readers/readTkhd.ts
1628
+ //#region src/readers/readSidx.ts
1540
1629
  /**
1541
- * Parse a TrackHeaderBox from an IsoView
1630
+ * Parse a SegmentIndexBox from an IsoView
1542
1631
  *
1543
1632
  * @param view - The IsoView to read data from
1544
1633
  *
1545
- * @returns A parsed TrackHeaderBox
1634
+ * @returns A parsed SegmentIndexBox
1546
1635
  *
1547
1636
  * @public
1548
1637
  */
1549
- function readTkhd(view) {
1638
+ function readSidx(view) {
1639
+ const { readUint: readUint$1 } = view;
1550
1640
  const { version, flags } = view.readFullBox();
1551
1641
  const size = version === 1 ? 8 : 4;
1642
+ const referenceId = readUint$1(4);
1643
+ const timescale = readUint$1(4);
1644
+ const earliestPresentationTime = readUint$1(size);
1645
+ const firstOffset = readUint$1(size);
1646
+ const reserved = readUint$1(2);
1647
+ const referenceCount = readUint$1(2);
1552
1648
  return {
1553
- type: "tkhd",
1649
+ type: "sidx",
1554
1650
  version,
1555
1651
  flags,
1556
- creationTime: view.readUint(size),
1557
- modificationTime: view.readUint(size),
1558
- trackId: view.readUint(4),
1559
- reserved1: view.readUint(4),
1560
- duration: view.readUint(size),
1561
- reserved2: view.readArray(UINT, 4, 2),
1562
- layer: view.readUint(2),
1563
- alternateGroup: view.readUint(2),
1564
- volume: view.readTemplate(2),
1565
- reserved3: view.readUint(2),
1566
- matrix: view.readArray(TEMPLATE, 4, 9),
1567
- width: view.readTemplate(4),
1568
- height: view.readTemplate(4)
1652
+ referenceId,
1653
+ timescale,
1654
+ earliestPresentationTime,
1655
+ firstOffset,
1656
+ reserved,
1657
+ references: view.readEntries(referenceCount, () => {
1658
+ const entry = {};
1659
+ entry.reference = readUint$1(4);
1660
+ entry.subsegmentDuration = readUint$1(4);
1661
+ entry.sap = readUint$1(4);
1662
+ entry.referenceType = entry.reference >> 31 & 1;
1663
+ entry.referencedSize = entry.reference & 2147483647;
1664
+ entry.startsWithSap = entry.sap >> 31 & 1;
1665
+ entry.sapType = entry.sap >> 28 & 7;
1666
+ entry.sapDeltaTime = entry.sap & 268435455;
1667
+ return entry;
1668
+ })
1569
1669
  };
1570
1670
  }
1571
1671
 
1572
1672
  //#endregion
1573
- //#region src/readers/readTrex.ts
1673
+ //#region src/readers/readSkip.ts
1574
1674
  /**
1575
- * Parse a TrackExtendsBox from an IsoView
1675
+ * Parse a FreeSpaceBox from an IsoView
1576
1676
  *
1577
1677
  * @param view - The IsoView to read data from
1578
1678
  *
1579
- * @returns A parsed TrackExtendsBox
1679
+ * @returns A parsed FreeSpaceBox
1580
1680
  *
1581
1681
  * @public
1582
1682
  */
1583
- function readTrex(view) {
1683
+ function readSkip(view) {
1584
1684
  return {
1585
- type: "trex",
1586
- ...view.readFullBox(),
1587
- trackId: view.readUint(4),
1588
- defaultSampleDescriptionIndex: view.readUint(4),
1589
- defaultSampleDuration: view.readUint(4),
1590
- defaultSampleSize: view.readUint(4),
1591
- defaultSampleFlags: view.readUint(4)
1685
+ ...readFree(view),
1686
+ type: "skip"
1592
1687
  };
1593
1688
  }
1594
1689
 
1595
1690
  //#endregion
1596
- //#region src/readers/readTrun.ts
1691
+ //#region src/readers/readSmhd.ts
1597
1692
  /**
1598
- * Parse a TrackRunBox from an IsoView
1693
+ * Parse a SoundMediaHeaderBox from an IsoView
1599
1694
  *
1600
1695
  * @param view - The IsoView to read data from
1601
1696
  *
1602
- * @returns A parsed TrackRunBox
1697
+ * @returns A parsed SoundMediaHeaderBox
1603
1698
  *
1604
1699
  * @public
1605
1700
  */
1606
- function readTrun(view) {
1607
- const { version, flags } = view.readFullBox();
1608
- const sampleCount = view.readUint(4);
1609
- let dataOffset;
1610
- let firstSampleFlags;
1611
- if (flags & 1) dataOffset = view.readInt(4);
1612
- if (flags & 4) firstSampleFlags = view.readUint(4);
1613
- const samples = view.readEntries(sampleCount, () => {
1614
- const sample = {};
1615
- if (flags & 256) sample.sampleDuration = view.readUint(4);
1616
- if (flags & 512) sample.sampleSize = view.readUint(4);
1617
- if (flags & 1024) sample.sampleFlags = view.readUint(4);
1618
- if (flags & 2048) sample.sampleCompositionTimeOffset = version === 1 ? view.readInt(4) : view.readUint(4);
1619
- return sample;
1620
- });
1701
+ function readSmhd(view) {
1621
1702
  return {
1622
- type: "trun",
1623
- version,
1624
- flags,
1625
- sampleCount,
1626
- dataOffset,
1627
- firstSampleFlags,
1628
- samples
1703
+ type: "smhd",
1704
+ ...view.readFullBox(),
1705
+ balance: view.readUint(2),
1706
+ reserved: view.readUint(2)
1629
1707
  };
1630
1708
  }
1631
1709
 
1632
1710
  //#endregion
1633
- //#region src/readers/readUrl.ts
1711
+ //#region src/readers/readSsix.ts
1634
1712
  /**
1635
- * Parse a UrlBox from an IsoView
1713
+ * Parse a SubsegmentIndexBox from an IsoView
1636
1714
  *
1637
1715
  * @param view - The IsoView to read data from
1638
1716
  *
1639
- * @returns A parsed UrlBox
1717
+ * @returns A parsed SubsegmentIndexBox
1640
1718
  *
1641
1719
  * @public
1642
1720
  */
1643
- function readUrl(view) {
1721
+ function readSsix(view) {
1722
+ const { version, flags } = view.readFullBox();
1723
+ const subsegmentCount = view.readUint(4);
1644
1724
  return {
1645
- type: "url ",
1646
- ...view.readFullBox(),
1647
- location: view.readString(-1)
1725
+ type: "ssix",
1726
+ version,
1727
+ flags,
1728
+ subsegmentCount,
1729
+ subsegments: view.readEntries(subsegmentCount, () => {
1730
+ const rangesCount = view.readUint(4);
1731
+ return {
1732
+ rangesCount,
1733
+ ranges: view.readEntries(rangesCount, () => ({
1734
+ level: view.readUint(1),
1735
+ rangeSize: view.readUint(3)
1736
+ }))
1737
+ };
1738
+ })
1648
1739
  };
1649
1740
  }
1650
1741
 
1651
1742
  //#endregion
1652
- //#region src/readers/readUrn.ts
1743
+ //#region src/readers/readSthd.ts
1653
1744
  /**
1654
- * Parse a UrnBox from an IsoView
1745
+ * Parse a SubtitleMediaHeaderBox from an IsoView
1655
1746
  *
1656
1747
  * @param view - The IsoView to read data from
1657
1748
  *
1658
- * @returns A parsed UrnBox
1749
+ * @returns A parsed SubtitleMediaHeaderBox
1659
1750
  *
1660
1751
  * @public
1661
1752
  */
1662
- function readUrn(view) {
1753
+ function readSthd(view) {
1663
1754
  return {
1664
- type: "urn ",
1665
- ...view.readFullBox(),
1666
- name: view.readString(-1),
1667
- location: view.readString(-1)
1755
+ type: "sthd",
1756
+ ...view.readFullBox()
1668
1757
  };
1669
1758
  }
1670
1759
 
1671
1760
  //#endregion
1672
- //#region src/readers/readVlab.ts
1761
+ //#region src/readers/readStsd.ts
1673
1762
  /**
1674
- * Parse a WebVTTSourceLabelBox from an IsoView
1763
+ * Parse a SampleDescriptionBox from an IsoView
1675
1764
  *
1676
1765
  * @param view - The IsoView to read data from
1677
1766
  *
1678
- * @returns A parsed WebVTTSourceLabelBox
1767
+ * @returns A parsed SampleDescriptionBox
1679
1768
  *
1680
1769
  * @public
1681
1770
  */
1682
- function readVlab(view) {
1771
+ function readStsd(view) {
1772
+ const { version, flags } = view.readFullBox();
1773
+ const entryCount = view.readUint(4);
1683
1774
  return {
1684
- type: "vlab",
1685
- sourceLabel: view.readUtf8(-1)
1775
+ type: "stsd",
1776
+ version,
1777
+ flags,
1778
+ entryCount,
1779
+ entries: view.readBoxes(entryCount)
1686
1780
  };
1687
1781
  }
1688
1782
 
1689
1783
  //#endregion
1690
- //#region src/readers/readVmhd.ts
1784
+ //#region src/readers/readStss.ts
1691
1785
  /**
1692
- * Parse a VideoMediaHeaderBox from an IsoView
1786
+ * Parse a SyncSampleBox from an IsoView
1693
1787
  *
1694
1788
  * @param view - The IsoView to read data from
1695
1789
  *
1696
- * @returns A parsed VideoMediaHeaderBox
1790
+ * @returns A parsed SyncSampleBox
1697
1791
  *
1698
1792
  * @public
1699
1793
  */
1700
- function readVmhd(view) {
1701
- return {
1702
- type: "vmhd",
1703
- ...view.readFullBox(),
1704
- graphicsmode: view.readUint(2),
1705
- opcolor: view.readArray(UINT, 2, 3)
1794
+ function readStss(view) {
1795
+ const { version, flags } = view.readFullBox();
1796
+ const entryCount = view.readUint(4);
1797
+ return {
1798
+ type: "stss",
1799
+ version,
1800
+ flags,
1801
+ entryCount,
1802
+ entries: view.readEntries(entryCount, () => ({ sampleNumber: view.readUint(4) }))
1706
1803
  };
1707
1804
  }
1708
1805
 
1709
1806
  //#endregion
1710
- //#region src/readers/readVttC.ts
1807
+ //#region src/readers/readSttg.ts
1711
1808
  /**
1712
- * Parse a WebVTTConfigurationBox from an IsoView
1809
+ * Parse a WebVTTSettingsBox from an IsoView
1713
1810
  *
1714
1811
  * @param view - The IsoView to read data from
1715
1812
  *
1716
- * @returns A parsed WebVttConfigurationBox
1813
+ * @returns A parsed WebVTTSettingsBox
1717
1814
  *
1718
1815
  * @public
1719
1816
  */
1720
- function readVttC(view) {
1817
+ function readSttg(view) {
1721
1818
  return {
1722
- type: "vttC",
1723
- config: view.readUtf8()
1819
+ type: "sttg",
1820
+ settings: view.readUtf8(-1)
1724
1821
  };
1725
1822
  }
1726
1823
 
1727
1824
  //#endregion
1728
- //#region src/readers/readVtte.ts
1825
+ //#region src/readers/readStts.ts
1729
1826
  /**
1730
- * Parse a WebVTT Empty Sample Box from an IsoView
1827
+ * Parse a DecodingTimeToSampleBox from an IsoView
1731
1828
  *
1732
- * @returns A parsed WebVTT Empty Sample Box
1829
+ * @param view - The IsoView to read data from
1830
+ *
1831
+ * @returns A parsed DecodingTimeToSampleBox
1733
1832
  *
1734
1833
  * @public
1735
1834
  */
1736
- function readVtte(_) {
1737
- return { type: "vtte" };
1835
+ function readStts(view) {
1836
+ const { version, flags } = view.readFullBox();
1837
+ const entryCount = view.readUint(4);
1838
+ return {
1839
+ type: "stts",
1840
+ version,
1841
+ flags,
1842
+ entryCount,
1843
+ entries: view.readEntries(entryCount, () => ({
1844
+ sampleCount: view.readUint(4),
1845
+ sampleDelta: view.readUint(4)
1846
+ }))
1847
+ };
1738
1848
  }
1739
1849
 
1740
1850
  //#endregion
1741
- //#region src/fields/DATA.ts
1851
+ //#region src/readers/readStyp.ts
1742
1852
  /**
1743
- * The data field type
1853
+ * Parse a SegmentTypeBox from an IsoView
1744
1854
  *
1745
- * @public
1746
- */
1747
- const DATA = "data";
1748
-
1749
- //#endregion
1750
- //#region src/fields/INT.ts
1751
- /**
1752
- * The integer field type
1855
+ * @param view - The IsoView to read data from
1856
+ *
1857
+ * @returns A parsed SegmentTypeBox
1753
1858
  *
1754
1859
  * @public
1755
1860
  */
1756
- const INT = "int";
1861
+ function readStyp(view) {
1862
+ return {
1863
+ ...readFtyp(view),
1864
+ type: "styp"
1865
+ };
1866
+ }
1757
1867
 
1758
1868
  //#endregion
1759
- //#region src/fields/UTF8.ts
1869
+ //#region src/readers/readSubs.ts
1760
1870
  /**
1761
- * The UTF8 field type
1871
+ * Parse a SubSampleInformationBox from an IsoView
1872
+ *
1873
+ * @param view - The IsoView to read data from
1874
+ *
1875
+ * @returns A parsed SubSampleInformationBox
1762
1876
  *
1763
1877
  * @public
1764
1878
  */
1765
- const UTF8 = "utf8";
1766
-
1767
- //#endregion
1768
- //#region src/utils/readData.ts
1769
- function readData(dataView, offset, size) {
1770
- const length = size > 0 ? size : dataView.byteLength - (offset - dataView.byteOffset);
1771
- return new Uint8Array(dataView.buffer, offset, Math.max(length, 0));
1772
- }
1773
-
1774
- //#endregion
1775
- //#region src/utils/readInt.ts
1776
- function readInt(dataView, offset, size) {
1777
- let result = NaN;
1778
- const cursor = offset - dataView.byteOffset;
1779
- switch (size) {
1780
- case 1:
1781
- result = dataView.getInt8(cursor);
1782
- break;
1783
- case 2:
1784
- result = dataView.getInt16(cursor);
1785
- break;
1786
- case 4:
1787
- result = dataView.getInt32(cursor);
1788
- break;
1789
- case 8:
1790
- const s1 = dataView.getInt32(cursor);
1791
- const s2 = dataView.getInt32(cursor + 4);
1792
- result = s1 * Math.pow(2, 32) + s2;
1793
- break;
1794
- }
1795
- return result;
1796
- }
1797
-
1798
- //#endregion
1799
- //#region src/utils/readUint.ts
1800
- function readUint(dataView, offset, size) {
1801
- const cursor = offset - dataView.byteOffset;
1802
- let value = NaN;
1803
- let s1;
1804
- let s2;
1805
- switch (size) {
1806
- case 1:
1807
- value = dataView.getUint8(cursor);
1808
- break;
1809
- case 2:
1810
- value = dataView.getUint16(cursor);
1811
- break;
1812
- case 3:
1813
- s1 = dataView.getUint16(cursor);
1814
- s2 = dataView.getUint8(cursor + 2);
1815
- value = (s1 << 8) + s2;
1816
- break;
1817
- case 4:
1818
- value = dataView.getUint32(cursor);
1819
- break;
1820
- case 8:
1821
- s1 = dataView.getUint32(cursor);
1822
- s2 = dataView.getUint32(cursor + 4);
1823
- value = s1 * Math.pow(2, 32) + s2;
1824
- break;
1825
- }
1826
- return value;
1827
- }
1828
-
1829
- //#endregion
1830
- //#region src/utils/readString.ts
1831
- function readString(dataView, offset, length) {
1832
- let str = "";
1833
- for (let c = 0; c < length; c++) {
1834
- const char = readUint(dataView, offset + c, 1);
1835
- str += String.fromCharCode(char);
1836
- }
1837
- return str;
1838
- }
1839
-
1840
- //#endregion
1841
- //#region src/utils/readTemplate.ts
1842
- function readTemplate(dataView, offset, size) {
1843
- const half = size / 2;
1844
- return readUint(dataView, offset, half) + readUint(dataView, offset + half, half) / Math.pow(2, half);
1845
- }
1846
-
1847
- //#endregion
1848
- //#region src/utils/readTerminatedString.ts
1849
- function readTerminatedString(dataView, offset) {
1850
- let str = "";
1851
- let cursor = offset;
1852
- while (cursor - dataView.byteOffset < dataView.byteLength) {
1853
- const char = readUint(dataView, cursor, 1);
1854
- if (char === 0) break;
1855
- str += String.fromCharCode(char);
1856
- cursor++;
1857
- }
1858
- return str;
1879
+ function readSubs(view) {
1880
+ const { version, flags } = view.readFullBox();
1881
+ const entryCount = view.readUint(4);
1882
+ return {
1883
+ type: "subs",
1884
+ version,
1885
+ flags,
1886
+ entryCount,
1887
+ entries: view.readEntries(entryCount, () => {
1888
+ const sampleDelta = view.readUint(4);
1889
+ const subsampleCount = view.readUint(2);
1890
+ return {
1891
+ sampleDelta,
1892
+ subsampleCount,
1893
+ subsamples: view.readEntries(subsampleCount, () => ({
1894
+ subsampleSize: view.readUint(version === 1 ? 4 : 2),
1895
+ subsamplePriority: view.readUint(1),
1896
+ discardable: view.readUint(1),
1897
+ codecSpecificParameters: view.readUint(4)
1898
+ }))
1899
+ };
1900
+ })
1901
+ };
1859
1902
  }
1860
1903
 
1861
1904
  //#endregion
1862
- //#region src/utils/readUtf8String.ts
1905
+ //#region src/readers/readTenc.ts
1863
1906
  /**
1864
- * Reads a UTF-8 string from a data view.
1907
+ * Parse a TrackEncryptionBox from an IsoView
1865
1908
  *
1866
- * @param dataView - The data view to read from.
1867
- * @param offset - The offset to start reading from.
1868
- * @returns The UTF-8 string.
1909
+ * @param view - The IsoView to read data from
1869
1910
  *
1870
- * @internal
1911
+ * @returns A parsed TrackEncryptionBox
1912
+ *
1913
+ * @public
1871
1914
  */
1872
- function readUtf8String(dataView, offset) {
1873
- const length = dataView.byteLength - (offset - dataView.byteOffset);
1874
- return length > 0 ? decodeText(new DataView(dataView.buffer, offset, length), { encoding: UTF_8 }) : "";
1915
+ function readTenc(view) {
1916
+ return {
1917
+ type: "tenc",
1918
+ ...view.readFullBox(),
1919
+ defaultIsEncrypted: view.readUint(3),
1920
+ defaultIvSize: view.readUint(1),
1921
+ defaultKid: view.readArray(UINT, 1, 16)
1922
+ };
1875
1923
  }
1876
1924
 
1877
1925
  //#endregion
1878
- //#region src/utils/readUtf8TerminatedString.ts
1926
+ //#region src/readers/readTfdt.ts
1879
1927
  /**
1880
- * Reads a UTF-8 terminated string from a data view.
1928
+ * Parse a TrackFragmentDecodeTimeBox from an IsoView
1881
1929
  *
1882
- * @param dataView - The data view to read from.
1883
- * @param offset - The offset to start reading from.
1884
- * @returns The UTF-8 terminated string.
1930
+ * @param view - The IsoView to read data from
1885
1931
  *
1886
- * @internal
1932
+ * @returns A parsed TrackFragmentDecodeTimeBox
1933
+ *
1934
+ * @public
1887
1935
  */
1888
- function readUtf8TerminatedString(dataView, offset) {
1889
- const length = dataView.byteLength - (offset - dataView.byteOffset);
1890
- let data = "";
1891
- if (length > 0) {
1892
- const view = new DataView(dataView.buffer, offset, length);
1893
- let l = 0;
1894
- for (; l < length; l++) if (view.getUint8(l) === 0) break;
1895
- data = decodeText(new DataView(dataView.buffer, offset, l), { encoding: UTF_8 });
1896
- }
1897
- return data;
1936
+ function readTfdt(view) {
1937
+ const { version, flags } = view.readFullBox();
1938
+ return {
1939
+ type: "tfdt",
1940
+ version,
1941
+ flags,
1942
+ baseMediaDecodeTime: view.readUint(version == 1 ? 8 : 4)
1943
+ };
1898
1944
  }
1899
1945
 
1900
1946
  //#endregion
1901
- //#region src/IsoBoxReadView.ts
1947
+ //#region src/readers/readTfhd.ts
1902
1948
  /**
1903
- * ISO BMFF data view. Similar to DataView, but with additional methods for reading ISO BMFF data.
1904
- * It implements the iterator protocol, so it can be used in a for...of loop.
1949
+ * Parse a TrackFragmentHeaderBox from an IsoView
1950
+ *
1951
+ * @param view - The IsoView to read data from
1952
+ *
1953
+ * @returns A parsed TrackFragmentHeaderBox
1905
1954
  *
1906
1955
  * @public
1907
1956
  */
1908
- var IsoBoxReadView = class IsoBoxReadView {
1909
- /**
1910
- * Creates a new IsoView instance. Similar to DataView, but with additional
1911
- * methods for reading ISO BMFF data. It implements the iterator protocol,
1912
- * so it can be used in a for...of loop.
1913
- *
1914
- * @param raw - The raw data to view.
1915
- * @param config - The configuration for the IsoView.
1916
- */
1917
- constructor(raw, config) {
1918
- this.truncated = false;
1919
- this.slice = (offset, size) => {
1920
- const isoView = new IsoBoxReadView(new DataView(this.dataView.buffer, offset, size), this.config);
1921
- const headerSize = this.offset - offset;
1922
- const bodySize = size - headerSize;
1923
- this.offset += bodySize;
1924
- isoView.jump(headerSize);
1925
- return isoView;
1926
- };
1927
- this.read = (type, size = 0) => {
1928
- const { dataView, offset } = this;
1929
- let result;
1930
- let cursor = size;
1931
- switch (type) {
1932
- case UINT:
1933
- result = readUint(dataView, offset, size);
1934
- break;
1935
- case INT:
1936
- result = readInt(dataView, offset, size);
1937
- break;
1938
- case TEMPLATE:
1939
- result = readTemplate(dataView, offset, size);
1940
- break;
1941
- case STRING:
1942
- if (size === -1) {
1943
- result = readTerminatedString(dataView, offset);
1944
- cursor = result.length + 1;
1945
- } else result = readString(dataView, offset, size);
1946
- break;
1947
- case DATA:
1948
- result = readData(dataView, offset, size);
1949
- cursor = result.length;
1950
- break;
1951
- case UTF8:
1952
- if (size === -1) {
1953
- result = readUtf8TerminatedString(dataView, offset);
1954
- cursor = result.length + 1;
1955
- } else result = readUtf8String(dataView, offset);
1956
- break;
1957
- default: result = -1;
1958
- }
1959
- this.offset += cursor;
1960
- return result;
1961
- };
1962
- this.readUint = (size) => {
1963
- return this.read(UINT, size);
1964
- };
1965
- this.readInt = (size) => {
1966
- return this.read(INT, size);
1967
- };
1968
- this.readString = (size) => {
1969
- return this.read(STRING, size);
1970
- };
1971
- this.readTemplate = (size) => {
1972
- return this.read(TEMPLATE, size);
1973
- };
1974
- this.readData = (size) => {
1975
- return this.read(DATA, size);
1976
- };
1977
- this.readUtf8 = (size) => {
1978
- return this.read(UTF8, size);
1979
- };
1980
- this.readFullBox = () => {
1981
- return {
1982
- version: this.readUint(1),
1983
- flags: this.readUint(3)
1984
- };
1985
- };
1986
- this.readArray = (type, size, length) => {
1987
- const value = [];
1988
- for (let i = 0; i < length; i++) value.push(this.read(type, size));
1989
- return value;
1990
- };
1991
- this.jump = (size) => {
1992
- this.offset += size;
1993
- };
1994
- this.readBox = () => {
1995
- const { dataView, offset } = this;
1996
- let cursor = 0;
1997
- const size = readUint(dataView, offset, 4);
1998
- const type = readString(dataView, offset + 4, 4);
1999
- const box = {
2000
- size,
2001
- type
2002
- };
2003
- cursor += 8;
2004
- if (box.size === 1) {
2005
- box.largesize = readUint(dataView, offset + cursor, 8);
2006
- cursor += 8;
2007
- }
2008
- const actualSize = box.size === 0 ? this.bytesRemaining : box.largesize ?? box.size;
2009
- if (this.cursor + actualSize > dataView.byteLength) {
2010
- this.truncated = true;
2011
- throw new Error("Truncated box");
2012
- }
2013
- this.jump(cursor);
2014
- if (type === "uuid") box.usertype = this.readArray("uint", 1, 16);
2015
- box.view = this.slice(offset, actualSize);
2016
- return box;
2017
- };
2018
- this.readBoxes = (length = -1) => {
2019
- const result = [];
2020
- for (const box of this) {
2021
- result.push(box);
2022
- if (length > 0 && result.length >= length) break;
2023
- }
2024
- return result;
2025
- };
2026
- this.readEntries = (length, map) => {
2027
- const result = [];
2028
- for (let i = 0; i < length; i++) result.push(map());
2029
- return result;
2030
- };
2031
- this.dataView = raw instanceof ArrayBuffer ? new DataView(raw) : raw instanceof DataView ? raw : new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
2032
- this.offset = this.dataView.byteOffset;
2033
- this.config = config || { readers: {} };
2034
- }
2035
- /**
2036
- * The buffer of the data view.
2037
- */
2038
- get buffer() {
2039
- return this.dataView.buffer;
2040
- }
2041
- /**
2042
- * The byte offset of the data view.
2043
- */
2044
- get byteOffset() {
2045
- return this.dataView.byteOffset;
2046
- }
2047
- /**
2048
- * The byte length of the data view.
2049
- */
2050
- get byteLength() {
2051
- return this.dataView.byteLength;
2052
- }
2053
- /**
2054
- * The current byteoffset in the data view.
2055
- */
2056
- get cursor() {
2057
- return this.offset - this.dataView.byteOffset;
2058
- }
2059
- /**
2060
- * Whether the end of the data view has been reached.
2061
- */
2062
- get done() {
2063
- return this.cursor >= this.dataView.byteLength || this.truncated;
2064
- }
2065
- /**
2066
- * The number of bytes remaining in the data view.
2067
- */
2068
- get bytesRemaining() {
2069
- return this.dataView.byteLength - this.cursor;
2070
- }
2071
- /**
2072
- * Iterates over the boxes in the data view.
2073
- *
2074
- * @returns A generator of boxes.
2075
- */
2076
- *[Symbol.iterator]() {
2077
- const { readers = {} } = this.config;
2078
- while (!this.done) try {
2079
- const box = this.readBox();
2080
- const { type, view } = box;
2081
- const parser = readers[type] || readers[type.trim()];
2082
- if (parser) Object.assign(box, parser(view));
2083
- if (isContainer(box) && !box.boxes) {
2084
- const boxes = [];
2085
- for (const child of view) boxes.push(child);
2086
- box.boxes = boxes;
2087
- }
2088
- yield box;
2089
- } catch (error) {
2090
- if (error instanceof Error && error.message === "Truncated box") break;
2091
- throw error;
2092
- }
2093
- }
2094
- };
1957
+ function readTfhd(view) {
1958
+ const { version, flags } = view.readFullBox();
1959
+ return {
1960
+ type: "tfhd",
1961
+ version,
1962
+ flags,
1963
+ trackId: view.readUint(4),
1964
+ baseDataOffset: flags & 1 ? view.readUint(8) : void 0,
1965
+ sampleDescriptionIndex: flags & 2 ? view.readUint(4) : void 0,
1966
+ defaultSampleDuration: flags & 8 ? view.readUint(4) : void 0,
1967
+ defaultSampleSize: flags & 16 ? view.readUint(4) : void 0,
1968
+ defaultSampleFlags: flags & 32 ? view.readUint(4) : void 0
1969
+ };
1970
+ }
1971
+
1972
+ //#endregion
1973
+ //#region src/readers/readTfra.ts
1974
+ /**
1975
+ * Parse a TrackFragmentRandomAccessBox from an IsoView
1976
+ *
1977
+ * @param view - The IsoView to read data from
1978
+ *
1979
+ * @returns A parsed TrackFragmentRandomAccessBox
1980
+ *
1981
+ * @public
1982
+ */
1983
+ function readTfra(view) {
1984
+ const { version, flags } = view.readFullBox();
1985
+ const trackId = view.readUint(4);
1986
+ const reserved = view.readUint(4);
1987
+ const lengthSizeOfTrafNum = (reserved & 48) >> 4;
1988
+ const lengthSizeOfTrunNum = (reserved & 12) >> 2;
1989
+ const lengthSizeOfSampleNum = reserved & 3;
1990
+ const numberOfEntry = view.readUint(4);
1991
+ return {
1992
+ type: "tfra",
1993
+ version,
1994
+ flags,
1995
+ trackId,
1996
+ reserved,
1997
+ lengthSizeOfTrafNum,
1998
+ lengthSizeOfTrunNum,
1999
+ lengthSizeOfSampleNum,
2000
+ numberOfEntry,
2001
+ entries: view.readEntries(numberOfEntry, () => ({
2002
+ time: view.readUint(version === 1 ? 8 : 4),
2003
+ moofOffset: view.readUint(version === 1 ? 8 : 4),
2004
+ trafNumber: view.readUint(lengthSizeOfTrafNum + 1),
2005
+ trunNumber: view.readUint(lengthSizeOfTrunNum + 1),
2006
+ sampleNumber: view.readUint(lengthSizeOfSampleNum + 1)
2007
+ }))
2008
+ };
2009
+ }
2010
+
2011
+ //#endregion
2012
+ //#region src/readers/readTkhd.ts
2013
+ /**
2014
+ * Parse a TrackHeaderBox from an IsoView
2015
+ *
2016
+ * @param view - The IsoView to read data from
2017
+ *
2018
+ * @returns A parsed TrackHeaderBox
2019
+ *
2020
+ * @public
2021
+ */
2022
+ function readTkhd(view) {
2023
+ const { version, flags } = view.readFullBox();
2024
+ const size = version === 1 ? 8 : 4;
2025
+ return {
2026
+ type: "tkhd",
2027
+ version,
2028
+ flags,
2029
+ creationTime: view.readUint(size),
2030
+ modificationTime: view.readUint(size),
2031
+ trackId: view.readUint(4),
2032
+ reserved1: view.readUint(4),
2033
+ duration: view.readUint(size),
2034
+ reserved2: view.readArray(UINT, 4, 2),
2035
+ layer: view.readUint(2),
2036
+ alternateGroup: view.readUint(2),
2037
+ volume: view.readTemplate(2),
2038
+ reserved3: view.readUint(2),
2039
+ matrix: view.readArray(TEMPLATE, 4, 9),
2040
+ width: view.readTemplate(4),
2041
+ height: view.readTemplate(4)
2042
+ };
2043
+ }
2044
+
2045
+ //#endregion
2046
+ //#region src/readers/readTrex.ts
2047
+ /**
2048
+ * Parse a TrackExtendsBox from an IsoView
2049
+ *
2050
+ * @param view - The IsoView to read data from
2051
+ *
2052
+ * @returns A parsed TrackExtendsBox
2053
+ *
2054
+ * @public
2055
+ */
2056
+ function readTrex(view) {
2057
+ return {
2058
+ type: "trex",
2059
+ ...view.readFullBox(),
2060
+ trackId: view.readUint(4),
2061
+ defaultSampleDescriptionIndex: view.readUint(4),
2062
+ defaultSampleDuration: view.readUint(4),
2063
+ defaultSampleSize: view.readUint(4),
2064
+ defaultSampleFlags: view.readUint(4)
2065
+ };
2066
+ }
2095
2067
 
2096
2068
  //#endregion
2097
- //#region src/readIsoBoxes.ts
2069
+ //#region src/readers/readTrun.ts
2098
2070
  /**
2099
- * Reads ISO boxes from a data source.
2071
+ * Parse a TrackRunBox from an IsoView
2100
2072
  *
2101
- * @param raw - The raw ISO data
2102
- * @param config - The configuration for the IsoView
2073
+ * @param view - The IsoView to read data from
2103
2074
  *
2104
- * @returns The parsed boxes
2075
+ * @returns A parsed TrackRunBox
2105
2076
  *
2106
- * @example
2107
- * {@includeCode ../test/readIsoBoxes.test.ts#example}
2077
+ * @public
2078
+ */
2079
+ function readTrun(view) {
2080
+ const { version, flags } = view.readFullBox();
2081
+ const sampleCount = view.readUint(4);
2082
+ let dataOffset;
2083
+ let firstSampleFlags;
2084
+ if (flags & 1) dataOffset = view.readInt(4);
2085
+ if (flags & 4) firstSampleFlags = view.readUint(4);
2086
+ const samples = view.readEntries(sampleCount, () => {
2087
+ const sample = {};
2088
+ if (flags & 256) sample.sampleDuration = view.readUint(4);
2089
+ if (flags & 512) sample.sampleSize = view.readUint(4);
2090
+ if (flags & 1024) sample.sampleFlags = view.readUint(4);
2091
+ if (flags & 2048) sample.sampleCompositionTimeOffset = version === 1 ? view.readInt(4) : view.readUint(4);
2092
+ return sample;
2093
+ });
2094
+ return {
2095
+ type: "trun",
2096
+ version,
2097
+ flags,
2098
+ sampleCount,
2099
+ dataOffset,
2100
+ firstSampleFlags,
2101
+ samples
2102
+ };
2103
+ }
2104
+
2105
+ //#endregion
2106
+ //#region src/readers/readUrl.ts
2107
+ /**
2108
+ * Parse a UrlBox from an IsoView
2109
+ *
2110
+ * @param view - The IsoView to read data from
2111
+ *
2112
+ * @returns A parsed UrlBox
2108
2113
  *
2109
2114
  * @public
2110
2115
  */
2111
- function readIsoBoxes(raw, config) {
2112
- const boxes = [];
2113
- for (const box of new IsoBoxReadView(raw, config)) boxes.push(box);
2114
- return boxes;
2116
+ function readUrl(view) {
2117
+ return {
2118
+ type: "url ",
2119
+ ...view.readFullBox(),
2120
+ location: view.readString(-1)
2121
+ };
2115
2122
  }
2116
2123
 
2117
2124
  //#endregion
2118
- //#region src/traverseIsoBoxes.ts
2125
+ //#region src/readers/readUrn.ts
2119
2126
  /**
2120
- * Traverse ISO boxes
2127
+ * Parse a UrnBox from an IsoView
2121
2128
  *
2122
- * @param boxes - The boxes to traverse
2123
- * @param depthFirst - Whether to traverse the boxes depth-first or breadth-first
2124
- * @param maxDepth - The maximum depth to traverse. A value of 0 will only traverse the root boxes.
2129
+ * @param view - The IsoView to read data from
2125
2130
  *
2126
- * @returns A generator of boxes
2131
+ * @returns A parsed UrnBox
2127
2132
  *
2128
- * @example
2129
- * {@includeCode ../test/traverseIsoBoxes.test.ts#example}
2133
+ * @public
2134
+ */
2135
+ function readUrn(view) {
2136
+ return {
2137
+ type: "urn ",
2138
+ ...view.readFullBox(),
2139
+ name: view.readString(-1),
2140
+ location: view.readString(-1)
2141
+ };
2142
+ }
2143
+
2144
+ //#endregion
2145
+ //#region src/readers/readVlab.ts
2146
+ /**
2147
+ * Parse a WebVTTSourceLabelBox from an IsoView
2148
+ *
2149
+ * @param view - The IsoView to read data from
2150
+ *
2151
+ * @returns A parsed WebVTTSourceLabelBox
2130
2152
  *
2131
2153
  * @public
2132
2154
  */
2133
- function* traverseIsoBoxes(boxes, depthFirst = true, maxDepth = Infinity) {
2134
- if (maxDepth < 0 || typeof maxDepth !== "number" || Number.isNaN(maxDepth)) return;
2135
- const queue = [[boxes, 0]];
2136
- while (queue.length > 0) {
2137
- const item = queue.shift();
2138
- if (!item) continue;
2139
- const [children, depth] = item;
2140
- for (const child of children) {
2141
- yield child;
2142
- if (depth >= maxDepth) continue;
2143
- if (isContainer(child) && child.boxes) {
2144
- const next = child.boxes;
2145
- if (depthFirst) yield* traverseIsoBoxes(next, depthFirst, maxDepth - 1);
2146
- else queue.push([next, depth + 1]);
2147
- }
2148
- }
2149
- }
2155
+ function readVlab(view) {
2156
+ return {
2157
+ type: "vlab",
2158
+ sourceLabel: view.readUtf8(-1)
2159
+ };
2150
2160
  }
2151
2161
 
2152
2162
  //#endregion
2153
- //#region src/utils/isFullBox.ts
2163
+ //#region src/readers/readVmhd.ts
2154
2164
  /**
2155
- * Check if a box is a full box
2165
+ * Parse a VideoMediaHeaderBox from an IsoView
2156
2166
  *
2157
- * @param box - The box to check
2167
+ * @param view - The IsoView to read data from
2158
2168
  *
2159
- * @returns `true` if the box is a full box, `false` otherwise
2169
+ * @returns A parsed VideoMediaHeaderBox
2160
2170
  *
2161
2171
  * @public
2162
2172
  */
2163
- function isFullBox(box) {
2164
- return "version" in box && "flags" in box;
2173
+ function readVmhd(view) {
2174
+ return {
2175
+ type: "vmhd",
2176
+ ...view.readFullBox(),
2177
+ graphicsmode: view.readUint(2),
2178
+ opcolor: view.readArray(UINT, 2, 3)
2179
+ };
2165
2180
  }
2166
2181
 
2167
2182
  //#endregion
2168
- //#region src/writeIsoBoxes.ts
2183
+ //#region src/readers/readVttC.ts
2169
2184
  /**
2170
- * Writes ISO boxes to a readable stream.
2185
+ * Parse a WebVTTConfigurationBox from an IsoView
2171
2186
  *
2172
- * @param boxes - The boxes to write
2173
- * @param config - The configuration for the readable stream
2187
+ * @param view - The IsoView to read data from
2174
2188
  *
2175
- * @returns A readable stream of the written boxes
2189
+ * @returns A parsed WebVttConfigurationBox
2176
2190
  *
2177
- * @example
2178
- * {@includeCode ../test/writeIsoBoxes.test.ts#example}
2191
+ * @public
2192
+ */
2193
+ function readVttC(view) {
2194
+ return {
2195
+ type: "vttC",
2196
+ config: view.readUtf8()
2197
+ };
2198
+ }
2199
+
2200
+ //#endregion
2201
+ //#region src/readers/readVtte.ts
2202
+ /**
2203
+ * Parse a WebVTT Empty Sample Box from an IsoView
2204
+ *
2205
+ * @returns A parsed WebVTT Empty Sample Box
2179
2206
  *
2180
2207
  * @public
2181
2208
  */
2182
- function writeIsoBoxes(boxes, config) {
2183
- const cfg = createWriterConfig(config);
2184
- return Array.from(boxes, (box) => writeBox(box, cfg));
2209
+ function readVtte(_) {
2210
+ return { type: "vtte" };
2211
+ }
2212
+
2213
+ //#endregion
2214
+ //#region src/utils/isFullBox.ts
2215
+ /**
2216
+ * Check if a box is a full box
2217
+ *
2218
+ * @param box - The box to check
2219
+ *
2220
+ * @returns `true` if the box is a full box, `false` otherwise
2221
+ *
2222
+ * @public
2223
+ */
2224
+ function isFullBox(box) {
2225
+ return "version" in box && "flags" in box;
2185
2226
  }
2186
2227
 
2187
2228
  //#endregion
@@ -2202,6 +2243,45 @@ function writeArdi(box) {
2202
2243
  return writer;
2203
2244
  }
2204
2245
 
2246
+ //#endregion
2247
+ //#region src/writers/writeAudioSampleEntryBox.ts
2248
+ /**
2249
+ * Write an AudioSampleEntryBox to an IsoDataWriter.
2250
+ *
2251
+ * ISO/IEC 14496-12:2012 - 12.2.3 Audio Sample Entry
2252
+ *
2253
+ * @param box - The AudioSampleEntryBox fields to write
2254
+ * @param config - The IsoBoxWriteViewConfig to use
2255
+ *
2256
+ * @returns An IsoDataWriter containing the encoded box
2257
+ *
2258
+ * @public
2259
+ */
2260
+ function writeAudioSampleEntryBox(box, config) {
2261
+ const headerSize = 8;
2262
+ const reserved1Size = 6;
2263
+ const dataReferenceIndexSize = 2;
2264
+ const reserved2Size = 8;
2265
+ const channelcountSize = 2;
2266
+ const samplesizeSize = 2;
2267
+ const preDefinedSize = 2;
2268
+ const reserved3Size = 2;
2269
+ const samplerateSize = 4;
2270
+ const { bytes, size } = writeChildBoxes(box.boxes, config);
2271
+ const totalSize = headerSize + reserved1Size + dataReferenceIndexSize + reserved2Size + channelcountSize + samplesizeSize + preDefinedSize + reserved3Size + samplerateSize + size;
2272
+ const writer = new IsoBoxWriteView(box.type, totalSize);
2273
+ writer.writeArray(box.reserved1, UINT, 1, 6);
2274
+ writer.writeUint(box.dataReferenceIndex, 2);
2275
+ writer.writeArray(box.reserved2, UINT, 4, 2);
2276
+ writer.writeUint(box.channelcount, 2);
2277
+ writer.writeUint(box.samplesize, 2);
2278
+ writer.writeUint(box.preDefined, 2);
2279
+ writer.writeUint(box.reserved3, 2);
2280
+ writer.writeTemplate(box.samplerate, 4);
2281
+ writer.writeBytes(bytes);
2282
+ return writer;
2283
+ }
2284
+
2205
2285
  //#endregion
2206
2286
  //#region src/writers/writeVisualSampleEntryBox.ts
2207
2287
  /**
@@ -2210,13 +2290,13 @@ function writeArdi(box) {
2210
2290
  * ISO/IEC 14496-12:2012 - 12.1.3 Visual Sample Entry
2211
2291
  *
2212
2292
  * @param box - The VisualSampleEntryBox fields to write
2213
- * @param type - The box type
2293
+ * @param config - The configuration for the writer
2214
2294
  *
2215
2295
  * @returns An IsoDataWriter containing the encoded box
2216
2296
  *
2217
2297
  * @public
2218
2298
  */
2219
- function writeVisualSampleEntryBox(box, type) {
2299
+ function writeVisualSampleEntryBox(box, config) {
2220
2300
  const headerSize = 8;
2221
2301
  const reserved1Size = 6;
2222
2302
  const dataReferenceIndexSize = 2;
@@ -2232,8 +2312,9 @@ function writeVisualSampleEntryBox(box, type) {
2232
2312
  const compressorNameSize = 32;
2233
2313
  const depthSize = 2;
2234
2314
  const preDefined3Size = 2;
2235
- const configSize = box.config.length;
2236
- const writer = new IsoBoxWriteView(type, headerSize + reserved1Size + dataReferenceIndexSize + preDefined1Size + reserved2Size + preDefined2Size + widthSize + heightSize + horizresolutionSize + vertresolutionSize + reserved3Size + frameCountSize + compressorNameSize + depthSize + preDefined3Size + configSize);
2315
+ const { bytes, size } = writeChildBoxes(box.boxes, config);
2316
+ const totalSize = headerSize + reserved1Size + dataReferenceIndexSize + preDefined1Size + reserved2Size + preDefined2Size + widthSize + heightSize + horizresolutionSize + vertresolutionSize + reserved3Size + frameCountSize + compressorNameSize + depthSize + preDefined3Size + size;
2317
+ const writer = new IsoBoxWriteView(box.type, totalSize);
2237
2318
  writer.writeArray(box.reserved1, UINT, 1, 6);
2238
2319
  writer.writeUint(box.dataReferenceIndex, 2);
2239
2320
  writer.writeUint(box.preDefined1, 2);
@@ -2248,7 +2329,7 @@ function writeVisualSampleEntryBox(box, type) {
2248
2329
  writer.writeArray(box.compressorName, UINT, 1, 32);
2249
2330
  writer.writeUint(box.depth, 2);
2250
2331
  writer.writeUint(box.preDefined3 & 65535, 2);
2251
- writer.writeBytes(box.config);
2332
+ writer.writeBytes(bytes);
2252
2333
  return writer;
2253
2334
  }
2254
2335
 
@@ -2260,13 +2341,14 @@ function writeVisualSampleEntryBox(box, type) {
2260
2341
  * ISO/IEC 14496-12:2012 - 12.1.3 Visual Sample Entry
2261
2342
  *
2262
2343
  * @param box - The VisualSampleEntryBox fields to write
2344
+ * @param config - The IsoBoxWriteViewConfig to use
2263
2345
  *
2264
2346
  * @returns An IsoDataWriter containing the encoded box
2265
2347
  *
2266
2348
  * @public
2267
2349
  */
2268
- function writeAvc1(box) {
2269
- return writeVisualSampleEntryBox(box, "avc1");
2350
+ function writeAvc1(box, config) {
2351
+ return writeVisualSampleEntryBox(box, config);
2270
2352
  }
2271
2353
 
2272
2354
  //#endregion
@@ -2275,13 +2357,14 @@ function writeAvc1(box) {
2275
2357
  * Write a VisualSampleEntryBox (avc2) to an IsoDataWriter.
2276
2358
  *
2277
2359
  * @param box - The VisualSampleEntryBox fields to write
2360
+ * @param config - The IsoBoxWriteViewConfig to use
2278
2361
  *
2279
2362
  * @returns An IsoDataWriter containing the encoded box
2280
2363
  *
2281
2364
  * @public
2282
2365
  */
2283
- function writeAvc2(box) {
2284
- return writeVisualSampleEntryBox(box, "avc2");
2366
+ function writeAvc2(box, config) {
2367
+ return writeVisualSampleEntryBox(box, config);
2285
2368
  }
2286
2369
 
2287
2370
  //#endregion
@@ -2290,13 +2373,14 @@ function writeAvc2(box) {
2290
2373
  * Write a VisualSampleEntryBox (avc3) to an IsoDataWriter.
2291
2374
  *
2292
2375
  * @param box - The VisualSampleEntryBox fields to write
2376
+ * @param config - The IsoBoxWriteViewConfig to use
2293
2377
  *
2294
2378
  * @returns An IsoDataWriter containing the encoded box
2295
2379
  *
2296
2380
  * @public
2297
2381
  */
2298
- function writeAvc3(box) {
2299
- return writeVisualSampleEntryBox(box, "avc3");
2382
+ function writeAvc3(box, config) {
2383
+ return writeVisualSampleEntryBox(box, config);
2300
2384
  }
2301
2385
 
2302
2386
  //#endregion
@@ -2305,13 +2389,14 @@ function writeAvc3(box) {
2305
2389
  * Write a VisualSampleEntryBox (avc4) to an IsoDataWriter.
2306
2390
  *
2307
2391
  * @param box - The VisualSampleEntryBox fields to write
2392
+ * @param config - The IsoBoxWriteViewConfig to use
2308
2393
  *
2309
2394
  * @returns An IsoDataWriter containing the encoded box
2310
2395
  *
2311
2396
  * @public
2312
2397
  */
2313
- function writeAvc4(box) {
2314
- return writeVisualSampleEntryBox(box, "avc4");
2398
+ function writeAvc4(box, config) {
2399
+ return writeVisualSampleEntryBox(box, config);
2315
2400
  }
2316
2401
 
2317
2402
  //#endregion
@@ -2348,6 +2433,7 @@ function writeCtts(box) {
2348
2433
  * Write a DataReferenceBox to an IsoDataWriter.
2349
2434
  *
2350
2435
  * @param box - The DataReferenceBox fields to write
2436
+ * @param config - The IsoBoxWriteViewConfig to use
2351
2437
  *
2352
2438
  * @returns An IsoDataWriter containing the encoded box
2353
2439
  *
@@ -2358,12 +2444,11 @@ function writeDref(box, config) {
2358
2444
  const fullBoxSize = 4;
2359
2445
  const entryCountSize = 4;
2360
2446
  const entryCount = box.entries.length;
2361
- const entries = writeIsoBoxes(box.entries, config);
2362
- const entriesSize = entries.reduce((size, entry) => size + entry.byteLength, 0);
2363
- const writer = new IsoBoxWriteView("dref", headerSize + fullBoxSize + entryCountSize + entriesSize);
2447
+ const { bytes, size } = writeChildBoxes(box.entries, config);
2448
+ const writer = new IsoBoxWriteView("dref", headerSize + fullBoxSize + entryCountSize + size);
2364
2449
  writer.writeFullBox(box.version, box.flags);
2365
2450
  writer.writeUint(entryCount, 4);
2366
- for (const entry of entries) writer.writeBytes(entry);
2451
+ writer.writeBytes(bytes);
2367
2452
  return writer;
2368
2453
  }
2369
2454
 
@@ -2469,33 +2554,14 @@ function writeEmsg(box) {
2469
2554
  * Write an AudioSampleEntryBox (enca) to an IsoDataWriter.
2470
2555
  *
2471
2556
  * @param box - The AudioSampleEntryBox fields to write
2557
+ * @param config - The IsoBoxWriteViewConfig to use
2472
2558
  *
2473
2559
  * @returns An IsoDataWriter containing the encoded box
2474
2560
  *
2475
2561
  * @public
2476
2562
  */
2477
- function writeEnca(box) {
2478
- const headerSize = 8;
2479
- const reserved1Size = 6;
2480
- const dataReferenceIndexSize = 2;
2481
- const reserved2Size = 8;
2482
- const channelcountSize = 2;
2483
- const samplesizeSize = 2;
2484
- const preDefinedSize = 2;
2485
- const reserved3Size = 2;
2486
- const samplerateSize = 4;
2487
- const esdsSize = box.esds.length;
2488
- const writer = new IsoBoxWriteView("enca", headerSize + reserved1Size + dataReferenceIndexSize + reserved2Size + channelcountSize + samplesizeSize + preDefinedSize + reserved3Size + samplerateSize + esdsSize);
2489
- writer.writeArray(box.reserved1, UINT, 1, 6);
2490
- writer.writeUint(box.dataReferenceIndex, 2);
2491
- writer.writeArray(box.reserved2, UINT, 4, 2);
2492
- writer.writeUint(box.channelcount, 2);
2493
- writer.writeUint(box.samplesize, 2);
2494
- writer.writeUint(box.preDefined, 2);
2495
- writer.writeUint(box.reserved3, 2);
2496
- writer.writeTemplate(box.samplerate, 4);
2497
- writer.writeBytes(box.esds);
2498
- return writer;
2563
+ function writeEnca(box, config) {
2564
+ return writeAudioSampleEntryBox(box, config);
2499
2565
  }
2500
2566
 
2501
2567
  //#endregion
@@ -2504,13 +2570,14 @@ function writeEnca(box) {
2504
2570
  * Write a VisualSampleEntryBox (encv) to an IsoDataWriter.
2505
2571
  *
2506
2572
  * @param box - The VisualSampleEntryBox fields to write
2573
+ * @param config - The IsoBoxWriteViewConfig to use
2507
2574
  *
2508
2575
  * @returns An IsoDataWriter containing the encoded box
2509
2576
  *
2510
2577
  * @public
2511
2578
  */
2512
- function writeEncv(box) {
2513
- return writeVisualSampleEntryBox(box, "encv");
2579
+ function writeEncv(box, config) {
2580
+ return writeVisualSampleEntryBox(box, config);
2514
2581
  }
2515
2582
 
2516
2583
  //#endregion
@@ -2611,13 +2678,14 @@ function writeHdlr(box) {
2611
2678
  * Write a VisualSampleEntryBox (hev1) to an IsoDataWriter.
2612
2679
  *
2613
2680
  * @param box - The VisualSampleEntryBox fields to write
2681
+ * @param config - The IsoBoxWriteViewConfig to use
2614
2682
  *
2615
2683
  * @returns An IsoDataWriter containing the encoded box
2616
2684
  *
2617
2685
  * @public
2618
2686
  */
2619
- function writeHev1(box) {
2620
- return writeVisualSampleEntryBox(box, "hev1");
2687
+ function writeHev1(box, config) {
2688
+ return writeVisualSampleEntryBox(box, config);
2621
2689
  }
2622
2690
 
2623
2691
  //#endregion
@@ -2626,13 +2694,14 @@ function writeHev1(box) {
2626
2694
  * Write a VisualSampleEntryBox (hvc1) to an IsoDataWriter.
2627
2695
  *
2628
2696
  * @param box - The VisualSampleEntryBox fields to write
2697
+ * @param config - The IsoBoxWriteViewConfig to use
2629
2698
  *
2630
2699
  * @returns An IsoDataWriter containing the encoded box
2631
2700
  *
2632
2701
  * @public
2633
2702
  */
2634
- function writeHvc1(box) {
2635
- return writeVisualSampleEntryBox(box, "hvc1");
2703
+ function writeHvc1(box, config) {
2704
+ return writeVisualSampleEntryBox(box, config);
2636
2705
  }
2637
2706
 
2638
2707
  //#endregion
@@ -2806,14 +2875,19 @@ function writeMehd(box) {
2806
2875
  * ISO/IEC 14496-12:2012 - 8.11.1 Meta Box
2807
2876
  *
2808
2877
  * @param box - The MetaBox fields to write
2878
+ * @param config - The IsoBoxWriteViewConfig to use
2809
2879
  *
2810
2880
  * @returns An IsoDataWriter containing the encoded box
2811
2881
  *
2812
2882
  * @public
2813
2883
  */
2814
- function writeMeta(box) {
2815
- const writer = new IsoBoxWriteView("meta", 12);
2884
+ function writeMeta(box, config) {
2885
+ const headerSize = 8;
2886
+ const fullBoxSize = 4;
2887
+ const { bytes, size } = writeChildBoxes(box.boxes, config);
2888
+ const writer = new IsoBoxWriteView("meta", headerSize + fullBoxSize + size);
2816
2889
  writer.writeFullBox(box.version, box.flags);
2890
+ writer.writeBytes(bytes);
2817
2891
  return writer;
2818
2892
  }
2819
2893
 
@@ -2870,28 +2944,8 @@ function writeMfro(box) {
2870
2944
  *
2871
2945
  * @public
2872
2946
  */
2873
- function writeMp4a(box) {
2874
- const headerSize = 8;
2875
- const reserved1Size = 6;
2876
- const dataReferenceIndexSize = 2;
2877
- const reserved2Size = 8;
2878
- const channelcountSize = 2;
2879
- const samplesizeSize = 2;
2880
- const preDefinedSize = 2;
2881
- const reserved3Size = 2;
2882
- const samplerateSize = 4;
2883
- const esdsSize = box.esds.length;
2884
- const writer = new IsoBoxWriteView("mp4a", headerSize + reserved1Size + dataReferenceIndexSize + reserved2Size + channelcountSize + samplesizeSize + preDefinedSize + reserved3Size + samplerateSize + esdsSize);
2885
- writer.writeArray(box.reserved1, UINT, 1, 6);
2886
- writer.writeUint(box.dataReferenceIndex, 2);
2887
- writer.writeArray(box.reserved2, UINT, 4, 2);
2888
- writer.writeUint(box.channelcount, 2);
2889
- writer.writeUint(box.samplesize, 2);
2890
- writer.writeUint(box.preDefined, 2);
2891
- writer.writeUint(box.reserved3, 2);
2892
- writer.writeTemplate(box.samplerate, 4);
2893
- writer.writeBytes(box.esds);
2894
- return writer;
2947
+ function writeMp4a(box, config) {
2948
+ return writeAudioSampleEntryBox(box, config);
2895
2949
  }
2896
2950
 
2897
2951
  //#endregion
@@ -2975,12 +3029,13 @@ function writePrft(box) {
2975
3029
  * Write a PreselectionGroupBox to an IsoDataWriter.
2976
3030
  *
2977
3031
  * @param box - The PreselectionGroupBox fields to write
3032
+ * @param config - The IsoBoxWriteViewConfig to use
2978
3033
  *
2979
3034
  * @returns An IsoDataWriter containing the encoded box
2980
3035
  *
2981
3036
  * @public
2982
3037
  */
2983
- function writePrsl(box) {
3038
+ function writePrsl(box, config) {
2984
3039
  const preselectionTagBytes = box.flags & 4096 && box.preselectionTag ? encodeText(box.preselectionTag) : null;
2985
3040
  const interleavingTagBytes = box.flags & 16384 && box.interleavingTag ? encodeText(box.interleavingTag) : null;
2986
3041
  const headerSize = 8;
@@ -2991,7 +3046,8 @@ function writePrsl(box) {
2991
3046
  const preselectionTagSize = preselectionTagBytes ? preselectionTagBytes.length + 1 : 0;
2992
3047
  const selectionPrioritySize = box.flags & 8192 ? 1 : 0;
2993
3048
  const interleavingTagSize = interleavingTagBytes ? interleavingTagBytes.length + 1 : 0;
2994
- const writer = new IsoBoxWriteView("prsl", headerSize + fullBoxSize + groupIdSize + numEntitiesInGroupSize + entitiesSize + preselectionTagSize + selectionPrioritySize + interleavingTagSize);
3049
+ const { bytes, size } = writeChildBoxes(box.boxes, config);
3050
+ const writer = new IsoBoxWriteView("prsl", headerSize + fullBoxSize + groupIdSize + numEntitiesInGroupSize + entitiesSize + preselectionTagSize + selectionPrioritySize + interleavingTagSize + size);
2995
3051
  writer.writeFullBox(box.version, box.flags);
2996
3052
  writer.writeUint(box.groupId, 4);
2997
3053
  writer.writeUint(box.numEntitiesInGroup, 4);
@@ -2999,6 +3055,7 @@ function writePrsl(box) {
2999
3055
  if (preselectionTagBytes && box.preselectionTag) writer.writeUtf8TerminatedString(box.preselectionTag);
3000
3056
  if (box.flags & 8192) writer.writeUint(box.selectionPriority ?? 0, 1);
3001
3057
  if (interleavingTagBytes && box.interleavingTag) writer.writeUtf8TerminatedString(box.interleavingTag);
3058
+ writer.writeBytes(bytes);
3002
3059
  return writer;
3003
3060
  }
3004
3061
 
@@ -3227,6 +3284,7 @@ function writeSthd(box) {
3227
3284
  * Write a SampleDescriptionBox to an IsoDataWriter.
3228
3285
  *
3229
3286
  * @param box - The SampleDescriptionBox fields to write
3287
+ * @param config - The IsoBoxWriteViewConfig to use
3230
3288
  *
3231
3289
  * @returns An IsoDataWriter containing the encoded box
3232
3290
  *
@@ -3237,12 +3295,11 @@ function writeStsd(box, config) {
3237
3295
  const fullBoxSize = 4;
3238
3296
  const entryCountSize = 4;
3239
3297
  const entryCount = box.entries.length;
3240
- const entries = writeIsoBoxes(box.entries, config);
3241
- const entriesSize = entries.reduce((size, entry) => size + entry.byteLength, 0);
3242
- const writer = new IsoBoxWriteView("stsd", headerSize + fullBoxSize + entryCountSize + entriesSize);
3298
+ const { bytes, size } = writeChildBoxes(box.entries, config);
3299
+ const writer = new IsoBoxWriteView("stsd", headerSize + fullBoxSize + entryCountSize + size);
3243
3300
  writer.writeFullBox(box.version, box.flags);
3244
3301
  writer.writeUint(entryCount, 4);
3245
- for (const entry of entries) writer.writeBytes(entry);
3302
+ writer.writeBytes(bytes);
3246
3303
  return writer;
3247
3304
  }
3248
3305
 
@@ -3712,5 +3769,5 @@ function writeVtte(_) {
3712
3769
  }
3713
3770
 
3714
3771
  //#endregion
3715
- export { CONTAINERS, IsoBoxReadableStream, createIsoBoxReadableStream, isContainer, isFullBox, readArdi, readAvc1, readAvc2, readAvc3, readAvc4, readCtts, readDref, readElng, readElst, readEmsg, readEnca, readEncv, readFree, readFrma, readFtyp, readHdlr, readHev1, readHvc1, readIden, readImda, readIsoBoxes, readKind, readLabl, readMdat, readMdhd, readMehd, readMeta, readMfhd, readMfro, readMp4a, readMvhd, readPayl, readPrft, readPrsl, readPssh, readSchm, readSdtp, readSidx, readSkip, readSmhd, readSsix, readSthd, readStsd, readStss, readSttg, readStts, readStyp, readSubs, readTenc, readTfdt, readTfhd, readTfra, readTkhd, readTrex, readTrun, readUrl, readUrn, readVlab, readVmhd, readVttC, readVtte, traverseIsoBoxes, writeArdi, writeAvc1, writeAvc2, writeAvc3, writeAvc4, writeCtts, writeDref, writeElng, writeElst, writeEmsg, writeEnca, writeEncv, writeFree, writeFrma, writeFtyp, writeHdlr, writeHev1, writeHvc1, writeIden, writeImda, writeIsoBox, writeIsoBoxes, writeKind, writeLabl, writeMdat, writeMdhd, writeMehd, writeMeta, writeMfhd, writeMfro, writeMp4a, writeMvhd, writePayl, writePrft, writePrsl, writePssh, writeSchm, writeSdtp, writeSidx, writeSkip, writeSmhd, writeSsix, writeSthd, writeStsd, writeStss, writeSttg, writeStts, writeStyp, writeSubs, writeTenc, writeTfdt, writeTfhd, writeTfra, writeTkhd, writeTrex, writeTrun, writeUrl, writeUrn, writeVlab, writeVmhd, writeVttC, writeVtte };
3772
+ export { CONTAINERS, IsoBoxReadableStream, createIsoBoxReadableStream, isContainer, isFullBox, readArdi, readAudioSampleEntryBox, 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, readVisualSampleEntryBox, readVlab, readVmhd, readVttC, readVtte, traverseIsoBoxes, writeArdi, writeAudioSampleEntryBox, writeAvc1, writeAvc2, writeAvc3, writeAvc4, writeCtts, writeDref, writeElng, writeElst, writeEmsg, writeEnca, writeEncv, writeFree, writeFrma, writeFtyp, writeHdlr, writeHev1, writeHvc1, writeIden, writeImda, writeIsoBox, writeIsoBoxes, writeKind, writeLabl, writeMdat, writeMdhd, writeMehd, writeMeta, writeMfhd, writeMfro, writeMp4a, writeMvhd, writePayl, writePrft, writePrsl, writePssh, writeSchm, writeSdtp, writeSidx, writeSkip, writeSmhd, writeSsix, writeSthd, writeStsd, writeStss, writeSttg, writeStts, writeStyp, writeSubs, writeTenc, writeTfdt, writeTfhd, writeTfra, writeTkhd, writeTrex, writeTrun, writeUrl, writeUrn, writeVisualSampleEntryBox, writeVlab, writeVmhd, writeVttC, writeVtte };
3716
3773
  //# sourceMappingURL=index.js.map