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

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