@remotion/media-parser 4.0.191 → 4.0.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/boxes.json +1 -0
  2. package/dist/boxes/iso-base-media/esds/esds-descriptors.d.ts +21 -0
  3. package/dist/boxes/iso-base-media/esds/esds-descriptors.js +62 -0
  4. package/dist/boxes/iso-base-media/esds/esds.d.ts +15 -0
  5. package/dist/boxes/iso-base-media/esds/esds.js +27 -0
  6. package/dist/boxes/iso-base-media/ftype.d.ts +9 -0
  7. package/dist/boxes/iso-base-media/ftype.js +31 -0
  8. package/dist/boxes/iso-base-media/mdhd.d.ts +14 -0
  9. package/dist/boxes/iso-base-media/mdhd.js +33 -0
  10. package/dist/boxes/iso-base-media/process-box.js +30 -0
  11. package/dist/boxes/iso-base-media/stsd/samples.d.ts +2 -0
  12. package/dist/boxes/iso-base-media/stsd/samples.js +28 -8
  13. package/dist/boxes/webm/parse-webm-header.js +4 -4
  14. package/dist/boxes/webm/segments/track-entry.d.ts +30 -0
  15. package/dist/boxes/webm/segments/track-entry.js +59 -8
  16. package/dist/boxes/webm/segments.d.ts +2 -2
  17. package/dist/boxes/webm/segments.js +18 -0
  18. package/dist/buffer-iterator.d.ts +2 -1
  19. package/dist/buffer-iterator.js +29 -8
  20. package/dist/from-node.js +6 -2
  21. package/dist/from-web.js +6 -1
  22. package/dist/get-audio-codec.d.ts +4 -0
  23. package/dist/get-audio-codec.js +106 -0
  24. package/dist/get-dimensions.js +6 -2
  25. package/dist/get-fps.d.ts +8 -0
  26. package/dist/get-fps.js +117 -9
  27. package/dist/get-video-codec.d.ts +4 -0
  28. package/dist/get-video-codec.js +79 -0
  29. package/dist/get-video-metadata.d.ts +2 -0
  30. package/dist/get-video-metadata.js +44 -0
  31. package/dist/has-all-info.d.ts +1 -1
  32. package/dist/has-all-info.js +8 -0
  33. package/dist/options.d.ts +11 -3
  34. package/dist/parse-media.js +27 -6
  35. package/dist/parse-result.d.ts +3 -1
  36. package/dist/read-and-increment-offset.d.ts +28 -0
  37. package/dist/read-and-increment-offset.js +177 -0
  38. package/dist/reader.d.ts +5 -1
  39. package/package.json +2 -2
  40. package/src/boxes/iso-base-media/esds/esds-descriptors.ts +104 -0
  41. package/src/boxes/iso-base-media/esds/esds.ts +49 -0
  42. package/src/boxes/iso-base-media/mdhd.ts +56 -0
  43. package/src/boxes/iso-base-media/process-box.ts +35 -0
  44. package/src/boxes/iso-base-media/stsd/samples.ts +36 -8
  45. package/src/boxes/webm/parse-webm-header.ts +4 -4
  46. package/src/boxes/webm/segments/track-entry.ts +103 -11
  47. package/src/boxes/webm/segments.ts +43 -1
  48. package/src/buffer-iterator.ts +36 -10
  49. package/src/from-node.ts +6 -4
  50. package/src/from-web.ts +8 -1
  51. package/src/get-audio-codec.ts +143 -0
  52. package/src/get-dimensions.ts +11 -4
  53. package/src/get-fps.ts +175 -9
  54. package/src/get-video-codec.ts +104 -0
  55. package/src/has-all-info.ts +19 -2
  56. package/src/options.ts +43 -3
  57. package/src/parse-media.ts +35 -7
  58. package/src/parse-result.ts +5 -1
  59. package/src/reader.ts +5 -1
  60. package/src/test/matroska.test.ts +6 -7
  61. package/src/test/parse-esds.test.ts +75 -0
  62. package/src/test/parse-webm.test.ts +2 -0
  63. package/src/test/stream-local.test.ts +93 -5
  64. package/src/test/stream-remote.test.ts +41 -0
  65. package/src/test/stsd.test.ts +52 -5
  66. package/tsconfig.tsbuildinfo +1 -1
package/boxes.json ADDED
@@ -0,0 +1 @@
1
+ [{"type":"ftyp-box","majorBrand":"qt","minorVersion":0,"compatibleBrands":["qt"],"offset":0,"boxSize":20},{"type":"regular-box","boxType":"wide","boxSize":8,"children":[],"offset":20},{"type":"regular-box","boxType":"mdat","children":[],"boxSize":39048800,"offset":28},{"offset":39048828,"boxSize":14100,"type":"moov-box","children":[{"creationTime":1686832959000,"modificationTime":1686832973000,"timeScale":600,"durationInUnits":7541,"durationInSeconds":12.568333333333333,"rate":1,"volume":1,"matrix":[65536,0,0,0,65536,0,0,0,1073741824],"nextTrackId":6,"type":"mvhd-box","boxSize":108,"offset":39048836},{"offset":39048944,"boxSize":7341,"type":"trak-box","children":[{"offset":39048952,"boxSize":92,"type":"tkhd-box","creationTime":1686832959000,"modificationTime":1686832973000,"trackId":1,"duration":7541,"layer":0,"alternateGroup":0,"volume":0,"matrix":[0,65536,0,4294901760,0,0,141557760,0,1073741824],"width":3840,"height":2160,"version":0},{"type":"regular-box","boxType":"tapt","boxSize":68,"children":[],"offset":39049044},{"type":"regular-box","boxType":"edts","boxSize":36,"children":[],"offset":39049112},{"type":"regular-box","boxType":"mdia","boxSize":7137,"children":[{"type":"mdhd-box","duration":7541,"timescale":600,"version":0,"language":21956,"quality":0},{"type":"regular-box","boxType":"hdlr","boxSize":49,"children":[],"offset":39049188},{"type":"regular-box","boxType":"minf","boxSize":7048,"children":[{"type":"regular-box","boxType":"vmhd","boxSize":20,"children":[],"offset":39049245},{"type":"regular-box","boxType":"hdlr","boxSize":56,"children":[],"offset":39049265},{"type":"regular-box","boxType":"dinf","boxSize":36,"children":[],"offset":39049321},{"type":"regular-box","boxType":"stbl","boxSize":6928,"children":[{"type":"stsd-box","boxSize":309,"offset":39049365,"numberOfEntries":1,"samples":[{"format":"hvc1","offset":39049381,"dataReferenceIndex":1,"version":0,"revisionLevel":0,"vendor":[0,0,0,0],"size":293,"type":"video","width":3840,"height":2160,"horizontalResolutionPpi":72,"verticalResolutionPpi":72,"spacialQuality":512,"temporalQuality":512,"dataSize":0,"frameCountPerSample":1,"compressorName":[4,72,69,86,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"depth":24,"colorTableId":-1}]},{"type":"regular-box","boxType":"sgpd","boxSize":104,"children":[],"offset":39049674},{"type":"regular-box","boxType":"sgpd","boxSize":26,"children":[],"offset":39049778},{"type":"regular-box","boxType":"sgpd","boxSize":28,"children":[],"offset":39049804},{"type":"regular-box","boxType":"sbgp","boxSize":212,"children":[],"offset":39049832},{"type":"regular-box","boxType":"csgm","boxSize":71,"children":[],"offset":39050044},{"type":"regular-box","boxType":"csgm","boxSize":249,"children":[],"offset":39050115},{"type":"stts-box","sampleDistribution":[{"sampleCount":269,"sampleDelta":20},{"sampleCount":1,"sampleDelta":21},{"sampleCount":107,"sampleDelta":20}]},{"type":"regular-box","boxType":"ctts","boxSize":3032,"children":[],"offset":39050404},{"type":"regular-box","boxType":"cslg","boxSize":32,"children":[],"offset":39053436},{"type":"regular-box","boxType":"stss","boxSize":64,"children":[],"offset":39053468},{"type":"regular-box","boxType":"sdtp","boxSize":389,"children":[],"offset":39053532},{"type":"regular-box","boxType":"stsc","boxSize":616,"children":[],"offset":39053921},{"type":"regular-box","boxType":"stsz","boxSize":1528,"children":[],"offset":39054537},{"type":"regular-box","boxType":"stco","boxSize":220,"children":[],"offset":39056065}],"offset":39049357}],"offset":39049237}],"offset":39049148}]},{"offset":39056285,"boxSize":3190,"type":"trak-box","children":[{"offset":39056293,"boxSize":92,"type":"tkhd-box","creationTime":1686832959000,"modificationTime":1686832973000,"trackId":2,"duration":7540,"layer":0,"alternateGroup":0,"volume":256,"matrix":[65536,0,0,0,65536,0,0,0,1073741824],"width":0,"height":0,"version":0},{"type":"regular-box","boxType":"edts","boxSize":36,"children":[],"offset":39056385},{"type":"regular-box","boxType":"mdia","boxSize":3054,"children":[{"type":"mdhd-box","duration":557056,"timescale":44100,"version":0,"language":21956,"quality":0},{"type":"regular-box","boxType":"hdlr","boxSize":49,"children":[],"offset":39056461},{"type":"regular-box","boxType":"minf","boxSize":2965,"children":[{"type":"regular-box","boxType":"smhd","boxSize":16,"children":[],"offset":39056518},{"type":"regular-box","boxType":"hdlr","boxSize":56,"children":[],"offset":39056534},{"type":"regular-box","boxType":"dinf","boxSize":36,"children":[],"offset":39056590},{"type":"regular-box","boxType":"stbl","boxSize":2849,"children":[{"type":"stsd-box","boxSize":159,"offset":39056634,"numberOfEntries":1,"samples":[{"format":"mp4a","offset":39056650,"dataReferenceIndex":1,"version":1,"revisionLevel":0,"vendor":[0,0,0,0],"size":143,"type":"audio","numberOfChannels":2,"sampleSize":16,"compressionId":-2,"packetSize":0,"sampleRate":44100,"samplesPerPacket":1024,"bytesPerPacket":1,"bytesPerFrame":2,"bitsPerSample":2,"children":[{"type":"regular-box","boxType":"wave","boxSize":91,"children":[{"type":"regular-box","boxType":"frma","boxSize":12,"children":[],"offset":39056710},{"type":"regular-box","boxType":"mp4a","boxSize":12,"children":[],"offset":39056722},{"type":"esds-box","version":0,"tag":3,"sizeOfInstance":34,"esId":0,"descriptors":[{"type":"decoder-config-descriptor","objectTypeIndication":"aac"},{"type":"sl-config-descriptor"}]},{"type":"regular-box","boxType":"\u0000\u0000\u0000\u0000","boxSize":8,"children":[],"offset":39056785}],"offset":39056702}]}]},{"type":"regular-box","boxType":"sgpd","boxSize":26,"children":[],"offset":39056793},{"type":"regular-box","boxType":"sbgp","boxSize":28,"children":[],"offset":39056819},{"type":"stts-box","sampleDistribution":[{"sampleCount":544,"sampleDelta":1024}]},{"type":"regular-box","boxType":"stsc","boxSize":292,"children":[],"offset":39056871},{"type":"regular-box","boxType":"stsz","boxSize":2196,"children":[],"offset":39057163},{"type":"regular-box","boxType":"stco","boxSize":116,"children":[],"offset":39059359}],"offset":39056626}],"offset":39056510}],"offset":39056421}]},{"offset":39059475,"boxSize":629,"type":"trak-box","children":[{"offset":39059483,"boxSize":92,"type":"tkhd-box","creationTime":1686832959000,"modificationTime":1686832973000,"trackId":3,"duration":7541,"layer":0,"alternateGroup":0,"volume":0,"matrix":[65536,0,0,0,65536,0,0,0,1073741824],"width":0,"height":0,"version":0},{"type":"regular-box","boxType":"edts","boxSize":36,"children":[],"offset":39059575},{"type":"regular-box","boxType":"tref","boxSize":32,"children":[],"offset":39059611},{"type":"regular-box","boxType":"mdia","boxSize":461,"children":[{"type":"mdhd-box","duration":7541,"timescale":600,"version":0,"language":21956,"quality":0},{"type":"regular-box","boxType":"hdlr","boxSize":52,"children":[],"offset":39059683},{"type":"regular-box","boxType":"minf","boxSize":369,"children":[{"type":"regular-box","boxType":"gmhd","boxSize":32,"children":[],"offset":39059743},{"type":"regular-box","boxType":"hdlr","boxSize":56,"children":[],"offset":39059775},{"type":"regular-box","boxType":"dinf","boxSize":36,"children":[],"offset":39059831},{"type":"regular-box","boxType":"stbl","boxSize":237,"children":[{"type":"stsd-box","boxSize":133,"offset":39059875,"numberOfEntries":1,"samples":[{"type":"unknown","offset":39059891,"dataReferenceIndex":1,"version":0,"revisionLevel":101,"vendor":[107,101,121,115],"size":117,"format":"mebx"}]},{"type":"stts-box","sampleDistribution":[{"sampleCount":1,"sampleDelta":7541}]},{"type":"regular-box","boxType":"stsc","boxSize":28,"children":[],"offset":39060032},{"type":"regular-box","boxType":"stsz","boxSize":24,"children":[],"offset":39060060},{"type":"regular-box","boxType":"stco","boxSize":20,"children":[],"offset":39060084}],"offset":39059867}],"offset":39059735}],"offset":39059643}]},{"offset":39060104,"boxSize":1074,"type":"trak-box","children":[{"offset":39060112,"boxSize":92,"type":"tkhd-box","creationTime":1686832959000,"modificationTime":1686832973000,"trackId":4,"duration":7541,"layer":0,"alternateGroup":0,"volume":0,"matrix":[65536,0,0,0,65536,0,0,0,1073741824],"width":0,"height":0,"version":0},{"type":"regular-box","boxType":"edts","boxSize":36,"children":[],"offset":39060204},{"type":"regular-box","boxType":"tref","boxSize":32,"children":[],"offset":39060240},{"type":"regular-box","boxType":"mdia","boxSize":906,"children":[{"type":"mdhd-box","duration":7541,"timescale":600,"version":0,"language":21956,"quality":0},{"type":"regular-box","boxType":"hdlr","boxSize":52,"children":[],"offset":39060312},{"type":"regular-box","boxType":"minf","boxSize":814,"children":[{"type":"regular-box","boxType":"gmhd","boxSize":32,"children":[],"offset":39060372},{"type":"regular-box","boxType":"hdlr","boxSize":56,"children":[],"offset":39060404},{"type":"regular-box","boxType":"dinf","boxSize":36,"children":[],"offset":39060460},{"type":"regular-box","boxType":"stbl","boxSize":682,"children":[{"type":"stsd-box","boxSize":578,"offset":39060504,"numberOfEntries":1,"samples":[{"type":"unknown","offset":39060520,"dataReferenceIndex":1,"version":0,"revisionLevel":502,"vendor":[107,101,121,115],"size":562,"format":"mebx"}]},{"type":"stts-box","sampleDistribution":[{"sampleCount":1,"sampleDelta":7541}]},{"type":"regular-box","boxType":"stsc","boxSize":28,"children":[],"offset":39061106},{"type":"regular-box","boxType":"stsz","boxSize":24,"children":[],"offset":39061134},{"type":"regular-box","boxType":"stco","boxSize":20,"children":[],"offset":39061158}],"offset":39060496}],"offset":39060364}],"offset":39060272}]},{"offset":39061178,"boxSize":1218,"type":"trak-box","children":[{"offset":39061186,"boxSize":92,"type":"tkhd-box","creationTime":1686832959000,"modificationTime":1686832973000,"trackId":5,"duration":7541,"layer":0,"alternateGroup":0,"volume":0,"matrix":[65536,0,0,0,65536,0,0,0,1073741824],"width":0,"height":0,"version":0},{"type":"regular-box","boxType":"edts","boxSize":36,"children":[],"offset":39061278},{"type":"regular-box","boxType":"tref","boxSize":32,"children":[],"offset":39061314},{"type":"regular-box","boxType":"mdia","boxSize":1050,"children":[{"type":"mdhd-box","duration":7541,"timescale":600,"version":0,"language":21956,"quality":0},{"type":"regular-box","boxType":"hdlr","boxSize":52,"children":[],"offset":39061386},{"type":"regular-box","boxType":"minf","boxSize":958,"children":[{"type":"regular-box","boxType":"gmhd","boxSize":32,"children":[],"offset":39061446},{"type":"regular-box","boxType":"hdlr","boxSize":56,"children":[],"offset":39061478},{"type":"regular-box","boxType":"dinf","boxSize":36,"children":[],"offset":39061534},{"type":"regular-box","boxType":"stbl","boxSize":826,"children":[{"type":"stsd-box","boxSize":598,"offset":39061578,"numberOfEntries":1,"samples":[{"type":"unknown","offset":39061594,"dataReferenceIndex":1,"version":0,"revisionLevel":566,"vendor":[107,101,121,115],"size":582,"format":"mebx"}]},{"type":"stts-box","sampleDistribution":[{"sampleCount":269,"sampleDelta":20},{"sampleCount":1,"sampleDelta":21},{"sampleCount":107,"sampleDelta":20}]},{"type":"regular-box","boxType":"stsc","boxSize":40,"children":[],"offset":39062216},{"type":"regular-box","boxType":"stsz","boxSize":20,"children":[],"offset":39062256},{"type":"regular-box","boxType":"stco","boxSize":120,"children":[],"offset":39062276}],"offset":39061570}],"offset":39061438}],"offset":39061346}]},{"type":"regular-box","boxType":"meta","boxSize":532,"children":[],"offset":39062396}]}]
@@ -0,0 +1,21 @@
1
+ import type { BufferIterator } from '../../../buffer-iterator';
2
+ type AudioObjectType = 'aac' | 'mp3' | 'unknown';
3
+ type DecoderConfigDescriptor = {
4
+ type: 'decoder-config-descriptor';
5
+ objectTypeIndication: AudioObjectType;
6
+ };
7
+ type SlConfigDescriptor = {
8
+ type: 'sl-config-descriptor';
9
+ };
10
+ type UnknownDescriptor = {
11
+ type: 'unknown-descriptor';
12
+ };
13
+ export type Descriptor = DecoderConfigDescriptor | SlConfigDescriptor | UnknownDescriptor;
14
+ type DescriptorAndNext = {
15
+ descriptor: Descriptor | null;
16
+ };
17
+ export declare const processDescriptor: ({ iterator, }: {
18
+ iterator: BufferIterator;
19
+ }) => DescriptorAndNext;
20
+ export declare const parseDescriptors: (iterator: BufferIterator, maxBytes: number) => Descriptor[];
21
+ export {};
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDescriptors = exports.processDescriptor = void 0;
4
+ const mapToObjectAudioIndicator = (num) => {
5
+ // https://chromium.googlesource.com/chromium/src/media/+/master/formats/mp4/es_descriptor.h
6
+ // http://netmedia.zju.edu.cn/multimedia2013/mpeg-4/ISO%20IEC%2014496-1%20MPEG-4%20System%20Standard.pdf
7
+ // Page 42, table 8
8
+ if (num === 0x40) {
9
+ return 'aac';
10
+ }
11
+ if (num === 0x6b) {
12
+ return 'mp3';
13
+ }
14
+ return 'unknown';
15
+ };
16
+ const processDescriptor = ({ iterator, }) => {
17
+ const tag = iterator.getUint8();
18
+ if (tag === 4) {
19
+ const size = iterator.getPaddedFourByteNumber();
20
+ const initialOffset = iterator.counter.getOffset();
21
+ const objectTypeIndication = iterator.getUint8();
22
+ const remaining = size - (iterator.counter.getOffset() - initialOffset);
23
+ iterator.discard(remaining);
24
+ return {
25
+ descriptor: {
26
+ type: 'decoder-config-descriptor',
27
+ objectTypeIndication: mapToObjectAudioIndicator(objectTypeIndication),
28
+ },
29
+ };
30
+ }
31
+ if (tag === 6) {
32
+ const size = iterator.getPaddedFourByteNumber();
33
+ iterator.discard(size);
34
+ return {
35
+ descriptor: {
36
+ type: 'sl-config-descriptor',
37
+ },
38
+ };
39
+ }
40
+ return {
41
+ descriptor: null,
42
+ };
43
+ };
44
+ exports.processDescriptor = processDescriptor;
45
+ const parseDescriptors = (iterator, maxBytes) => {
46
+ const descriptors = [];
47
+ const initialOffset = iterator.counter.getOffset();
48
+ while (iterator.bytesRemaining() > 0 &&
49
+ iterator.counter.getOffset() - initialOffset < maxBytes) {
50
+ const { descriptor } = (0, exports.processDescriptor)({
51
+ iterator,
52
+ });
53
+ if (descriptor) {
54
+ descriptors.push(descriptor);
55
+ }
56
+ else {
57
+ break;
58
+ }
59
+ }
60
+ return descriptors;
61
+ };
62
+ exports.parseDescriptors = parseDescriptors;
@@ -0,0 +1,15 @@
1
+ import type { BufferIterator } from '../../../buffer-iterator';
2
+ import type { Descriptor } from './esds-descriptors';
3
+ export interface EsdsBox {
4
+ type: 'esds-box';
5
+ version: number;
6
+ tag: number;
7
+ sizeOfInstance: number;
8
+ esId: number;
9
+ descriptors: Descriptor[];
10
+ }
11
+ export declare const parseEsds: ({ data, size, fileOffset, }: {
12
+ data: BufferIterator;
13
+ size: number;
14
+ fileOffset: number;
15
+ }) => EsdsBox;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseEsds = void 0;
4
+ const esds_descriptors_1 = require("./esds-descriptors");
5
+ const parseEsds = ({ data, size, fileOffset, }) => {
6
+ const version = data.getUint8();
7
+ // Flags, we discard them
8
+ data.discard(3);
9
+ const tag = data.getUint8();
10
+ const sizeOfInstance = data.getPaddedFourByteNumber();
11
+ const esId = data.getUint16();
12
+ // disard 1 byte, currently unknown
13
+ data.discard(1);
14
+ const remaining = size - (data.counter.getOffset() - fileOffset);
15
+ const descriptors = (0, esds_descriptors_1.parseDescriptors)(data, remaining);
16
+ const remainingNow = size - (data.counter.getOffset() - fileOffset);
17
+ data.discard(remainingNow);
18
+ return {
19
+ type: 'esds-box',
20
+ version,
21
+ tag,
22
+ sizeOfInstance,
23
+ esId,
24
+ descriptors,
25
+ };
26
+ };
27
+ exports.parseEsds = parseEsds;
@@ -0,0 +1,9 @@
1
+ import type { BaseBox } from './base-type';
2
+ export interface FtypBox extends BaseBox {
3
+ type: 'ftyp-box';
4
+ majorBrand: string;
5
+ minorVersion: number;
6
+ compatibleBrands: string[];
7
+ }
8
+ export declare const fourByteToNumber: (data: ArrayBuffer, from: number) => number;
9
+ export declare const parseFtyp: (data: ArrayBuffer, offset: number) => FtypBox;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseFtyp = exports.fourByteToNumber = void 0;
4
+ const fourByteToNumber = (data, from) => {
5
+ const view = new DataView(data);
6
+ return ((view.getUint8(from + 0) << 24) |
7
+ (view.getUint8(from + 1) << 16) |
8
+ (view.getUint8(from + 2) << 8) |
9
+ view.getUint8(from + 3));
10
+ };
11
+ exports.fourByteToNumber = fourByteToNumber;
12
+ const parseFtyp = (data, offset) => {
13
+ const majorBrand = new TextDecoder().decode(data.slice(8, 12)).trim();
14
+ const minorVersion = (0, exports.fourByteToNumber)(data, 12);
15
+ const rest = data.slice(16);
16
+ const types = rest.byteLength / 4;
17
+ const compatibleBrands = [];
18
+ for (let i = 0; i < types; i++) {
19
+ const fourBytes = rest.slice(i * 4, i * 4 + 4);
20
+ compatibleBrands.push(new TextDecoder().decode(fourBytes).trim());
21
+ }
22
+ return {
23
+ type: 'ftyp-box',
24
+ majorBrand,
25
+ minorVersion,
26
+ compatibleBrands,
27
+ offset,
28
+ boxSize: data.byteLength,
29
+ };
30
+ };
31
+ exports.parseFtyp = parseFtyp;
@@ -0,0 +1,14 @@
1
+ import type { BufferIterator } from '../../buffer-iterator';
2
+ export interface MdhdBox {
3
+ type: 'mdhd-box';
4
+ version: number;
5
+ timescale: number;
6
+ duration: number;
7
+ language: number;
8
+ quality: number;
9
+ }
10
+ export declare const parseMdhd: ({ data, size, fileOffset, }: {
11
+ data: BufferIterator;
12
+ size: number;
13
+ fileOffset: number;
14
+ }) => MdhdBox;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseMdhd = void 0;
4
+ const parseMdhd = ({ data, size, fileOffset, }) => {
5
+ const version = data.getUint8();
6
+ if (version !== 0) {
7
+ throw new Error(`Unsupported MDHD version ${version}`);
8
+ }
9
+ // flags, we discard them
10
+ data.discard(3);
11
+ // creation time
12
+ data.discard(4);
13
+ // modification time
14
+ data.discard(4);
15
+ const timescale = data.getUint32();
16
+ const duration = data.getUint32();
17
+ const language = data.getUint16();
18
+ // quality
19
+ const quality = data.getUint16();
20
+ const remaining = size - (data.counter.getOffset() - fileOffset);
21
+ if (remaining !== 0) {
22
+ throw new Error(`Expected remaining bytes to be 0, got ${remaining}`);
23
+ }
24
+ return {
25
+ type: 'mdhd-box',
26
+ duration,
27
+ timescale,
28
+ version,
29
+ language,
30
+ quality,
31
+ };
32
+ };
33
+ exports.parseMdhd = parseMdhd;
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseBoxes = void 0;
4
+ const esds_1 = require("./esds/esds");
4
5
  const ftyp_1 = require("./ftyp");
6
+ const mdhd_1 = require("./mdhd");
5
7
  const moov_1 = require("./moov/moov");
6
8
  const mvhd_1 = require("./mvhd");
7
9
  const mebx_1 = require("./stsd/mebx");
@@ -14,6 +16,7 @@ const getChildren = ({ boxType, iterator, bytesRemainingInBox, }) => {
14
16
  boxType === 'minf' ||
15
17
  boxType === 'stbl' ||
16
18
  boxType === 'dims' ||
19
+ boxType === 'wave' ||
17
20
  boxType === 'stsb';
18
21
  if (parseChildren) {
19
22
  const parsed = (0, exports.parseBoxes)({
@@ -27,6 +30,9 @@ const getChildren = ({ boxType, iterator, bytesRemainingInBox, }) => {
27
30
  }
28
31
  return parsed.segments;
29
32
  }
33
+ if (bytesRemainingInBox < 0) {
34
+ throw new Error('Box size is too big ' + JSON.stringify({ boxType }));
35
+ }
30
36
  iterator.discard(bytesRemainingInBox);
31
37
  return [];
32
38
  };
@@ -119,6 +125,30 @@ const processBox = ({ iterator, allowIncompleteBoxes, }) => {
119
125
  size: boxSize,
120
126
  };
121
127
  }
128
+ if (boxType === 'mdhd') {
129
+ const box = (0, mdhd_1.parseMdhd)({
130
+ data: iterator,
131
+ size: boxSize,
132
+ fileOffset,
133
+ });
134
+ return {
135
+ type: 'complete',
136
+ box,
137
+ size: boxSize,
138
+ };
139
+ }
140
+ if (boxType === 'esds') {
141
+ const box = (0, esds_1.parseEsds)({
142
+ data: iterator,
143
+ size: boxSize,
144
+ fileOffset,
145
+ });
146
+ return {
147
+ type: 'complete',
148
+ box,
149
+ size: boxSize,
150
+ };
151
+ }
122
152
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
123
153
  const children = getChildren({
124
154
  boxType,
@@ -1,4 +1,5 @@
1
1
  import type { BufferIterator } from '../../../buffer-iterator';
2
+ import type { AnySegment } from '../../../parse-result';
2
3
  type SampleBase = {
3
4
  format: string;
4
5
  offset: number;
@@ -19,6 +20,7 @@ type AudioSample = SampleBase & {
19
20
  bytesPerPacket: number | null;
20
21
  bytesPerFrame: number | null;
21
22
  bitsPerSample: number | null;
23
+ children: AnySegment[];
22
24
  };
23
25
  type VideoSample = SampleBase & {
24
26
  type: 'video';
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseSamples = exports.processSample = void 0;
4
+ const process_box_1 = require("../process-box");
4
5
  // https://developer.apple.com/documentation/quicktime-file-format/video_sample_description
5
6
  const videoTags = [
6
7
  'cvid',
@@ -30,6 +31,7 @@ const videoTags = [
30
31
  'v410',
31
32
  'v210',
32
33
  'hvc1',
34
+ 'ap4h',
33
35
  ];
34
36
  // https://developer.apple.com/documentation/quicktime-file-format/sound_sample_descriptions
35
37
  const audioTags = [
@@ -98,7 +100,15 @@ const processSample = ({ iterator, }) => {
98
100
  const packetSize = iterator.getUint16();
99
101
  const sampleRate = iterator.getFixedPoint1616Number();
100
102
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
101
- iterator.discard(bytesRemainingInBox);
103
+ const children = (0, process_box_1.parseBoxes)({
104
+ iterator,
105
+ allowIncompleteBoxes: false,
106
+ maxBytes: bytesRemainingInBox,
107
+ initialBoxes: [],
108
+ });
109
+ if (children.status === 'incomplete') {
110
+ throw new Error('Incomplete boxes are not allowed');
111
+ }
102
112
  return {
103
113
  sample: {
104
114
  format: boxFormat,
@@ -118,21 +128,30 @@ const processSample = ({ iterator, }) => {
118
128
  bytesPerPacket: null,
119
129
  bytesPerFrame: null,
120
130
  bitsPerSample: null,
131
+ children: children.segments,
121
132
  },
122
133
  };
123
134
  }
124
135
  if (version === 1) {
125
136
  const numberOfChannels = iterator.getUint16();
126
137
  const sampleSize = iterator.getUint16();
127
- const compressionId = iterator.getUint16();
138
+ const compressionId = iterator.getInt16();
128
139
  const packetSize = iterator.getUint16();
129
140
  const sampleRate = iterator.getFixedPoint1616Number();
130
- const samplesPerPacket = iterator.getUint16();
131
- const bytesPerPacket = iterator.getUint16();
132
- const bytesPerFrame = iterator.getUint16();
133
- const bitsPerSample = iterator.getUint16();
141
+ const samplesPerPacket = iterator.getUint32();
142
+ const bytesPerPacket = iterator.getUint32();
143
+ const bytesPerFrame = iterator.getUint32();
144
+ const bytesPerSample = iterator.getUint32();
134
145
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
135
- iterator.discard(bytesRemainingInBox);
146
+ const children = (0, process_box_1.parseBoxes)({
147
+ iterator,
148
+ allowIncompleteBoxes: false,
149
+ maxBytes: bytesRemainingInBox,
150
+ initialBoxes: [],
151
+ });
152
+ if (children.status === 'incomplete') {
153
+ throw new Error('Incomplete boxes are not allowed');
154
+ }
136
155
  return {
137
156
  sample: {
138
157
  format: boxFormat,
@@ -151,7 +170,8 @@ const processSample = ({ iterator, }) => {
151
170
  samplesPerPacket,
152
171
  bytesPerPacket,
153
172
  bytesPerFrame,
154
- bitsPerSample,
173
+ bitsPerSample: bytesPerSample,
174
+ children: children.segments,
155
175
  },
156
176
  };
157
177
  }
@@ -5,12 +5,12 @@ const segments_1 = require("./segments");
5
5
  // Parsing according to https://darkcoding.net/software/reading-mediarecorders-webm-opus-output/
6
6
  const parseWebm = (counter) => {
7
7
  counter.discard(4);
8
- const length = counter.getEBML();
9
- if (length !== 31) {
10
- throw new Error(`Expected header length 31, got ${length}`);
8
+ const length = counter.getVint();
9
+ if (length !== 31 && length !== 35) {
10
+ throw new Error(`Expected header length 31 or 25, got ${length}`);
11
11
  }
12
12
  // Discard header for now
13
- counter.discard(31);
13
+ counter.discard(length);
14
14
  return { status: 'done', segments: [(0, segments_1.expectSegment)(counter)] };
15
15
  };
16
16
  exports.parseWebm = parseWebm;
@@ -69,3 +69,33 @@ export type ColorSegment = {
69
69
  type: 'color-segment';
70
70
  };
71
71
  export declare const parseColorSegment: (iterator: BufferIterator) => ColorSegment;
72
+ export type TitleSegment = {
73
+ type: 'title-segment';
74
+ title: string;
75
+ };
76
+ export declare const parseTitleSegment: (iterator: BufferIterator) => TitleSegment;
77
+ export type InterlacedSegment = {
78
+ type: 'interlaced-segment';
79
+ interlaced: boolean;
80
+ };
81
+ export declare const parseInterlacedSegment: (iterator: BufferIterator) => InterlacedSegment;
82
+ export type CodecPrivateSegment = {
83
+ type: 'codec-private-segment';
84
+ codecPrivateData: number[];
85
+ };
86
+ export declare const parseCodecPrivateSegment: (iterator: BufferIterator) => CodecPrivateSegment;
87
+ export type Crc32Segment = {
88
+ type: 'crc32-segment';
89
+ crc32: number[];
90
+ };
91
+ export declare const parseCrc32Segment: (iterator: BufferIterator) => Crc32Segment;
92
+ export type SegmentUUIDSegment = {
93
+ type: 'segment-uuid-segment';
94
+ segmentUUID: string;
95
+ };
96
+ export declare const parseSegmentUUIDSegment: (iterator: BufferIterator) => SegmentUUIDSegment;
97
+ export type DefaultFlagSegment = {
98
+ type: 'default-flag-segment';
99
+ defaultFlag: boolean;
100
+ };
101
+ export declare const parseDefaultFlagSegment: (iterator: BufferIterator) => DefaultFlagSegment;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseColorSegment = exports.parseMaxBlockAdditionId = exports.parseAlphaModeSegment = exports.parseHeightSegment = exports.parseWidthSegment = exports.parseVideoSegment = exports.parseDefaultDurationSegment = exports.parseTrackTypeSegment = exports.parseCodecSegment = exports.parseLanguageSegment = exports.parseFlagLacing = exports.parseTrackUID = exports.parseTrackNumber = exports.parseTrackEntry = void 0;
3
+ exports.parseDefaultFlagSegment = exports.parseSegmentUUIDSegment = exports.parseCrc32Segment = exports.parseCodecPrivateSegment = exports.parseInterlacedSegment = exports.parseTitleSegment = exports.parseColorSegment = exports.parseMaxBlockAdditionId = exports.parseAlphaModeSegment = exports.parseHeightSegment = exports.parseWidthSegment = exports.parseVideoSegment = exports.parseDefaultDurationSegment = exports.parseTrackTypeSegment = exports.parseCodecSegment = exports.parseLanguageSegment = exports.parseFlagLacing = exports.parseTrackUID = exports.parseTrackNumber = exports.parseTrackEntry = void 0;
4
4
  const parse_children_1 = require("./parse-children");
5
5
  const parseTrackEntry = (iterator) => {
6
6
  const offset = iterator.counter.getOffset();
@@ -25,10 +25,6 @@ const parseTrackNumber = (iterator) => {
25
25
  exports.parseTrackNumber = parseTrackNumber;
26
26
  const parseTrackUID = (iterator) => {
27
27
  const length = iterator.getVint();
28
- // Observation: AV1 has 8 bytes, WebM has 7
29
- if (length !== 8 && length !== 7) {
30
- throw new Error('Expected track number to be 8 byte');
31
- }
32
28
  const bytes = iterator.getSlice(length);
33
29
  const asString = [...bytes]
34
30
  .map((b) => b.toString(16).padStart(2, '0'))
@@ -109,11 +105,10 @@ const parseDefaultDurationSegment = (iterator) => {
109
105
  };
110
106
  exports.parseDefaultDurationSegment = parseDefaultDurationSegment;
111
107
  const parseVideoSegment = (iterator) => {
112
- const offset = iterator.counter.getOffset();
113
108
  const length = iterator.getVint();
114
109
  return {
115
110
  type: 'video-segment',
116
- children: (0, parse_children_1.expectChildren)(iterator, length - (iterator.counter.getOffset() - offset)),
111
+ children: (0, parse_children_1.expectChildren)(iterator, length),
117
112
  };
118
113
  };
119
114
  exports.parseVideoSegment = parseVideoSegment;
@@ -167,9 +162,65 @@ const parseMaxBlockAdditionId = (iterator) => {
167
162
  exports.parseMaxBlockAdditionId = parseMaxBlockAdditionId;
168
163
  const parseColorSegment = (iterator) => {
169
164
  const length = iterator.getVint();
170
- iterator.discard(length - 1);
165
+ iterator.discard(length);
171
166
  return {
172
167
  type: 'color-segment',
173
168
  };
174
169
  };
175
170
  exports.parseColorSegment = parseColorSegment;
171
+ const parseTitleSegment = (iterator) => {
172
+ const length = iterator.getVint();
173
+ const title = iterator.getByteString(length);
174
+ return {
175
+ type: 'title-segment',
176
+ title,
177
+ };
178
+ };
179
+ exports.parseTitleSegment = parseTitleSegment;
180
+ const parseInterlacedSegment = (iterator) => {
181
+ const length = iterator.getVint();
182
+ if (length !== 1) {
183
+ throw new Error('Expected interlaced segment to be 1 byte');
184
+ }
185
+ const interlaced = iterator.getUint8();
186
+ return {
187
+ type: 'interlaced-segment',
188
+ interlaced: Boolean(interlaced),
189
+ };
190
+ };
191
+ exports.parseInterlacedSegment = parseInterlacedSegment;
192
+ const parseCodecPrivateSegment = (iterator) => {
193
+ const length = iterator.getVint();
194
+ return {
195
+ type: 'codec-private-segment',
196
+ codecPrivateData: [...iterator.getSlice(length)],
197
+ };
198
+ };
199
+ exports.parseCodecPrivateSegment = parseCodecPrivateSegment;
200
+ const parseCrc32Segment = (iterator) => {
201
+ const length = iterator.getVint();
202
+ return {
203
+ type: 'crc32-segment',
204
+ crc32: [...iterator.getSlice(length)],
205
+ };
206
+ };
207
+ exports.parseCrc32Segment = parseCrc32Segment;
208
+ const parseSegmentUUIDSegment = (iterator) => {
209
+ const length = iterator.getVint();
210
+ return {
211
+ type: 'segment-uuid-segment',
212
+ segmentUUID: iterator.getSlice(length).toString(),
213
+ };
214
+ };
215
+ exports.parseSegmentUUIDSegment = parseSegmentUUIDSegment;
216
+ const parseDefaultFlagSegment = (iterator) => {
217
+ const length = iterator.getVint();
218
+ if (length !== 1) {
219
+ throw new Error('Expected default flag segment to be 1 byte');
220
+ }
221
+ return {
222
+ type: 'default-flag-segment',
223
+ defaultFlag: Boolean(iterator.getUint8()),
224
+ };
225
+ };
226
+ exports.parseDefaultFlagSegment = parseDefaultFlagSegment;
@@ -7,10 +7,10 @@ import { type SeekSegment } from './segments/seek';
7
7
  import type { SeekHeadSegment } from './segments/seek-head';
8
8
  import { type SeekPositionSegment } from './segments/seek-position';
9
9
  import type { TimestampScaleSegment } from './segments/timestamp-scale';
10
- import type { AlphaModeSegment, CodecSegment, ColorSegment, DefaultDurationSegment, FlagLacingSegment, HeightSegment, LanguageSegment, MaxBlockAdditionId, TrackEntrySegment, TrackNumberSegment, TrackTypeSegment, TrackUIDSegment, VideoSegment, WidthSegment } from './segments/track-entry';
10
+ import type { AlphaModeSegment, CodecPrivateSegment, CodecSegment, ColorSegment, Crc32Segment, DefaultDurationSegment, DefaultFlagSegment, FlagLacingSegment, HeightSegment, InterlacedSegment, LanguageSegment, MaxBlockAdditionId, SegmentUUIDSegment, TitleSegment, TrackEntrySegment, TrackNumberSegment, TrackTypeSegment, TrackUIDSegment, VideoSegment, WidthSegment } from './segments/track-entry';
11
11
  import type { TracksSegment } from './segments/tracks';
12
12
  import type { UnknownSegment } from './segments/unknown';
13
13
  import type { VoidSegment } from './segments/void';
14
14
  import type { WritingAppSegment } from './segments/writing';
15
- export type MatroskaSegment = MainSegment | UnknownSegment | SeekHeadSegment | SeekSegment | SeekPositionSegment | VoidSegment | InfoSegment | TimestampScaleSegment | MuxingAppSegment | WritingAppSegment | DurationSegment | TracksSegment | TrackEntrySegment | TrackNumberSegment | TrackUIDSegment | FlagLacingSegment | LanguageSegment | CodecSegment | TrackTypeSegment | DefaultDurationSegment | VideoSegment | WidthSegment | HeightSegment | AlphaModeSegment | MaxBlockAdditionId | ColorSegment;
15
+ export type MatroskaSegment = MainSegment | UnknownSegment | SeekHeadSegment | SeekSegment | SeekPositionSegment | VoidSegment | InfoSegment | TimestampScaleSegment | MuxingAppSegment | WritingAppSegment | DurationSegment | TracksSegment | TrackEntrySegment | TrackNumberSegment | TrackUIDSegment | FlagLacingSegment | LanguageSegment | CodecSegment | TrackTypeSegment | DefaultDurationSegment | VideoSegment | WidthSegment | HeightSegment | AlphaModeSegment | MaxBlockAdditionId | ColorSegment | TitleSegment | InterlacedSegment | CodecPrivateSegment | Crc32Segment | SegmentUUIDSegment | DefaultFlagSegment;
16
16
  export declare const expectSegment: (iterator: BufferIterator) => MatroskaSegment;
@@ -94,9 +94,27 @@ const expectSegment = (iterator) => {
94
94
  if (segmentId === '0xba') {
95
95
  return (0, track_entry_1.parseHeightSegment)(iterator);
96
96
  }
97
+ if (segmentId === '0x9a') {
98
+ return (0, track_entry_1.parseInterlacedSegment)(iterator);
99
+ }
97
100
  if (segmentId === '0x53c0') {
98
101
  return (0, track_entry_1.parseAlphaModeSegment)(iterator);
99
102
  }
103
+ if (segmentId === '0x63a2') {
104
+ return (0, track_entry_1.parseCodecPrivateSegment)(iterator);
105
+ }
106
+ if (segmentId === '0x7ba9') {
107
+ return (0, track_entry_1.parseTitleSegment)(iterator);
108
+ }
109
+ if (segmentId === '0xbf') {
110
+ return (0, track_entry_1.parseCrc32Segment)(iterator);
111
+ }
112
+ if (segmentId === '0x73a4') {
113
+ return (0, track_entry_1.parseSegmentUUIDSegment)(iterator);
114
+ }
115
+ if (segmentId === '0x88') {
116
+ return (0, track_entry_1.parseDefaultFlagSegment)(iterator);
117
+ }
100
118
  const length = iterator.getVint();
101
119
  const bytesRemaining = iterator.byteLength() - iterator.counter.getOffset();
102
120
  const toDiscard = Math.min(bytesRemaining, length > 0 ? length : bytesRemaining);
@@ -7,7 +7,7 @@ export declare class OffsetCounter {
7
7
  discardBytes(amount: number): void;
8
8
  decrement(amount: number): void;
9
9
  }
10
- export declare const getArrayBufferIterator: (initialData: Uint8Array) => {
10
+ export declare const getArrayBufferIterator: (initialData: Uint8Array, maxBytes?: number) => {
11
11
  addData: (newData: Uint8Array) => void;
12
12
  counter: OffsetCounter;
13
13
  byteLength: () => number;
@@ -19,6 +19,7 @@ export declare const getArrayBufferIterator: (initialData: Uint8Array) => {
19
19
  getFourByteNumber: () => number;
20
20
  getSlice: (amount: number) => Uint8Array;
21
21
  getAtom: () => string;
22
+ getPaddedFourByteNumber: () => number;
22
23
  getMatroskaSegmentId: () => string;
23
24
  getVint: () => number;
24
25
  getUint8: () => number;