@remotion/media-parser 4.0.208 → 4.0.210

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 (215) hide show
  1. package/buffer.js +2 -0
  2. package/dist/boxes/iso-base-media/get-sample-positions-from-track.js +1 -1
  3. package/dist/boxes/iso-base-media/make-track.js +14 -2
  4. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +2 -1
  5. package/dist/boxes/iso-base-media/mdat/mdat.js +8 -3
  6. package/dist/boxes/iso-base-media/moov/moov.d.ts +2 -1
  7. package/dist/boxes/iso-base-media/moov/moov.js +2 -1
  8. package/dist/boxes/iso-base-media/process-box.d.ts +6 -3
  9. package/dist/boxes/iso-base-media/process-box.js +20 -5
  10. package/dist/boxes/iso-base-media/stsd/avcc.d.ts +1 -1
  11. package/dist/boxes/iso-base-media/stsd/avcc.js +2 -2
  12. package/dist/boxes/iso-base-media/stsd/ctts.js +2 -5
  13. package/dist/boxes/iso-base-media/stsd/hvcc.d.ts +1 -1
  14. package/dist/boxes/iso-base-media/stsd/hvcc.js +2 -2
  15. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
  16. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
  17. package/dist/boxes/iso-base-media/stsd/samples.d.ts +4 -2
  18. package/dist/boxes/iso-base-media/stsd/samples.js +69 -11
  19. package/dist/boxes/iso-base-media/stsd/stsd.d.ts +2 -1
  20. package/dist/boxes/iso-base-media/stsd/stsd.js +2 -1
  21. package/dist/boxes/iso-base-media/trak/trak.d.ts +2 -1
  22. package/dist/boxes/iso-base-media/trak/trak.js +2 -1
  23. package/dist/boxes/iso-base-media/traversal.d.ts +44 -0
  24. package/dist/boxes/iso-base-media/traversal.js +211 -0
  25. package/dist/boxes/webm/color.d.ts +4 -0
  26. package/dist/boxes/webm/color.js +120 -0
  27. package/dist/boxes/webm/description.js +1 -1
  28. package/dist/boxes/webm/get-ready-tracks.js +3 -3
  29. package/dist/boxes/webm/get-sample-from-block.js +1 -1
  30. package/dist/boxes/webm/get-track.js +16 -1
  31. package/dist/boxes/webm/make-track.d.ts +9 -0
  32. package/dist/boxes/webm/make-track.js +260 -0
  33. package/dist/boxes/webm/parse-ebml.js +5 -2
  34. package/dist/boxes/webm/segments/all-segments.d.ts +36 -3
  35. package/dist/boxes/webm/segments/all-segments.js +34 -6
  36. package/dist/boxes/webm/traversal.d.ts +26 -1
  37. package/dist/boxes/webm/traversal.js +214 -1
  38. package/dist/buffer-iterator.js +6 -0
  39. package/dist/create/cluster-segment.d.ts +1 -1
  40. package/dist/create/cluster-segment.js +3 -5
  41. package/dist/create/cluster.d.ts +13 -0
  42. package/dist/create/cluster.js +54 -0
  43. package/dist/create/create-media.d.ts +4 -2
  44. package/dist/create/create-media.js +87 -47
  45. package/dist/create/cues.d.ts +0 -0
  46. package/dist/create/cues.js +1 -0
  47. package/dist/create/make-duration-with-padding.d.ts +1 -0
  48. package/dist/create/make-duration-with-padding.js +15 -0
  49. package/dist/create/matroska-cues.d.ts +6 -0
  50. package/dist/create/matroska-cues.js +50 -0
  51. package/dist/create/matroska-info.d.ts +1 -2
  52. package/dist/create/matroska-info.js +3 -11
  53. package/dist/create/matroska-seek.d.ts +6 -0
  54. package/dist/create/matroska-seek.js +32 -0
  55. package/dist/create/matroska-segment.d.ts +1 -0
  56. package/dist/create/matroska-segment.js +3 -2
  57. package/dist/create/matroska-trackentry.d.ts +9 -14
  58. package/dist/create/matroska-trackentry.js +79 -94
  59. package/dist/create/timescale.d.ts +1 -0
  60. package/dist/create/timescale.js +4 -0
  61. package/dist/emit-available-info.d.ts +12 -0
  62. package/dist/emit-available-info.js +133 -0
  63. package/dist/esm/buffer.mjs +57 -0
  64. package/dist/esm/from-fetch.mjs +72 -0
  65. package/dist/esm/from-node.mjs +48 -0
  66. package/dist/esm/from-web-file.mjs +48 -0
  67. package/dist/esm/index.mjs +6689 -0
  68. package/dist/esm/web-fs.mjs +67 -0
  69. package/dist/get-audio-codec.d.ts +5 -5
  70. package/dist/get-audio-codec.js +41 -57
  71. package/dist/get-container.d.ts +4 -0
  72. package/dist/get-container.js +26 -0
  73. package/dist/get-duration.js +1 -1
  74. package/dist/get-fps.js +1 -1
  75. package/dist/get-sample-aspect-ratio.d.ts +1 -1
  76. package/dist/get-sample-aspect-ratio.js +19 -19
  77. package/dist/get-tracks.d.ts +13 -0
  78. package/dist/get-tracks.js +8 -8
  79. package/dist/get-video-codec.d.ts +5 -2
  80. package/dist/get-video-codec.js +111 -21
  81. package/dist/has-all-info.d.ts +2 -2
  82. package/dist/has-all-info.js +23 -9
  83. package/dist/index.d.ts +3 -1
  84. package/dist/options.d.ts +97 -30
  85. package/dist/parse-media.js +43 -62
  86. package/dist/parse-video.d.ts +2 -1
  87. package/dist/parse-video.js +3 -1
  88. package/dist/parser-state.js +1 -2
  89. package/dist/readers/from-fetch.js +24 -4
  90. package/dist/readers/from-node.js +13 -3
  91. package/dist/readers/from-web-file.js +14 -2
  92. package/dist/readers/reader.d.ts +6 -1
  93. package/dist/samples-from-moof.js +1 -1
  94. package/dist/traversal.d.ts +0 -21
  95. package/dist/traversal.js +1 -158
  96. package/dist/truthy.d.ts +3 -0
  97. package/dist/truthy.js +7 -0
  98. package/dist/writers/buffer.d.ts +2 -0
  99. package/dist/writers/buffer.js +58 -0
  100. package/dist/writers/web-fs.d.ts +1 -0
  101. package/dist/writers/web-fs.js +42 -18
  102. package/dist/writers/writer.d.ts +4 -2
  103. package/fetch.js +2 -0
  104. package/node.js +2 -0
  105. package/package.json +43 -8
  106. package/web-file.js +2 -0
  107. package/web-fs.js +2 -0
  108. package/.eslintrc +0 -8
  109. package/input.webm +0 -0
  110. package/src/add-new-matroska-tracks.ts +0 -23
  111. package/src/boxes/iso-base-media/base-type.ts +0 -4
  112. package/src/boxes/iso-base-media/esds/decoder-specific-config.ts +0 -68
  113. package/src/boxes/iso-base-media/esds/esds-descriptors.ts +0 -135
  114. package/src/boxes/iso-base-media/esds/esds.ts +0 -49
  115. package/src/boxes/iso-base-media/ftyp.ts +0 -39
  116. package/src/boxes/iso-base-media/get-sample-positions-from-track.ts +0 -69
  117. package/src/boxes/iso-base-media/make-track.ts +0 -116
  118. package/src/boxes/iso-base-media/mdat/mdat.ts +0 -140
  119. package/src/boxes/iso-base-media/mdhd.ts +0 -59
  120. package/src/boxes/iso-base-media/moov/moov.ts +0 -43
  121. package/src/boxes/iso-base-media/mvhd.ts +0 -114
  122. package/src/boxes/iso-base-media/process-box.ts +0 -748
  123. package/src/boxes/iso-base-media/stsd/av1c.ts +0 -19
  124. package/src/boxes/iso-base-media/stsd/avcc.ts +0 -36
  125. package/src/boxes/iso-base-media/stsd/colr.ts +0 -49
  126. package/src/boxes/iso-base-media/stsd/ctts.ts +0 -64
  127. package/src/boxes/iso-base-media/stsd/hvcc.ts +0 -32
  128. package/src/boxes/iso-base-media/stsd/keys.ts +0 -27
  129. package/src/boxes/iso-base-media/stsd/mebx.ts +0 -54
  130. package/src/boxes/iso-base-media/stsd/pasp.ts +0 -32
  131. package/src/boxes/iso-base-media/stsd/samples.ts +0 -359
  132. package/src/boxes/iso-base-media/stsd/stco.ts +0 -52
  133. package/src/boxes/iso-base-media/stsd/stsc.ts +0 -61
  134. package/src/boxes/iso-base-media/stsd/stsd.ts +0 -55
  135. package/src/boxes/iso-base-media/stsd/stss.ts +0 -47
  136. package/src/boxes/iso-base-media/stsd/stsz.ts +0 -75
  137. package/src/boxes/iso-base-media/stsd/stts.ts +0 -62
  138. package/src/boxes/iso-base-media/tfdt.ts +0 -37
  139. package/src/boxes/iso-base-media/tfhd.ts +0 -66
  140. package/src/boxes/iso-base-media/tkhd.ts +0 -150
  141. package/src/boxes/iso-base-media/to-date.ts +0 -9
  142. package/src/boxes/iso-base-media/trak/trak.ts +0 -43
  143. package/src/boxes/iso-base-media/trun.ts +0 -74
  144. package/src/boxes/iso-base-media/void-box.ts +0 -4
  145. package/src/boxes/webm/allowed-partial-segments.ts +0 -1
  146. package/src/boxes/webm/av1-codec-private.ts +0 -113
  147. package/src/boxes/webm/description.ts +0 -104
  148. package/src/boxes/webm/ebml.ts +0 -98
  149. package/src/boxes/webm/get-ready-tracks.ts +0 -36
  150. package/src/boxes/webm/get-sample-from-block.ts +0 -125
  151. package/src/boxes/webm/get-track.ts +0 -257
  152. package/src/boxes/webm/make-header.ts +0 -253
  153. package/src/boxes/webm/parse-ebml.ts +0 -255
  154. package/src/boxes/webm/parse-webm-header.ts +0 -18
  155. package/src/boxes/webm/segments/all-segments.ts +0 -888
  156. package/src/boxes/webm/segments/block-simple-block-flags.ts +0 -52
  157. package/src/boxes/webm/segments/parse-children.ts +0 -144
  158. package/src/boxes/webm/segments/track-entry.ts +0 -38
  159. package/src/boxes/webm/segments.ts +0 -147
  160. package/src/boxes/webm/traversal.ts +0 -45
  161. package/src/buffer-iterator.ts +0 -548
  162. package/src/create/cluster-segment.ts +0 -62
  163. package/src/create/create-media.ts +0 -172
  164. package/src/create/matroska-header.ts +0 -63
  165. package/src/create/matroska-info.ts +0 -46
  166. package/src/create/matroska-segment.ts +0 -10
  167. package/src/create/matroska-trackentry.ts +0 -325
  168. package/src/get-audio-codec.ts +0 -270
  169. package/src/get-dimensions.ts +0 -47
  170. package/src/get-duration.ts +0 -103
  171. package/src/get-fps.ts +0 -113
  172. package/src/get-sample-aspect-ratio.ts +0 -204
  173. package/src/get-sample-positions.ts +0 -93
  174. package/src/get-tracks.ts +0 -147
  175. package/src/get-video-codec.ts +0 -117
  176. package/src/has-all-info.ts +0 -81
  177. package/src/index.ts +0 -18
  178. package/src/make-hvc1-codec-strings.ts +0 -55
  179. package/src/options.ts +0 -118
  180. package/src/parse-media.ts +0 -183
  181. package/src/parse-result.ts +0 -79
  182. package/src/parse-video.ts +0 -83
  183. package/src/parser-context.ts +0 -10
  184. package/src/parser-state.ts +0 -178
  185. package/src/readers/from-fetch.ts +0 -90
  186. package/src/readers/from-node.ts +0 -51
  187. package/src/readers/from-web-file.ts +0 -49
  188. package/src/readers/reader.ts +0 -15
  189. package/src/samples-from-moof.ts +0 -102
  190. package/src/test/aspect-ratio.test.ts +0 -42
  191. package/src/test/av1.test.ts +0 -108
  192. package/src/test/create-matroska.test.ts +0 -287
  193. package/src/test/duration.test.ts +0 -18
  194. package/src/test/keys.test.ts +0 -47
  195. package/src/test/matroska.test.ts +0 -463
  196. package/src/test/mvhd.test.ts +0 -94
  197. package/src/test/parse-esds.test.ts +0 -98
  198. package/src/test/parse-stco.test.ts +0 -61
  199. package/src/test/parse-stsc.test.ts +0 -104
  200. package/src/test/parse-stsz.test.ts +0 -57
  201. package/src/test/parse-stts.test.ts +0 -38
  202. package/src/test/parse-video.test.ts +0 -101
  203. package/src/test/parse-webm.test.ts +0 -17
  204. package/src/test/samples-from-moof.test.ts +0 -2496
  205. package/src/test/stream-local.test.ts +0 -743
  206. package/src/test/stream-remote.test.ts +0 -59
  207. package/src/test/stream-samples.test.ts +0 -181
  208. package/src/test/stsd.test.ts +0 -265
  209. package/src/test/tkhd.test.ts +0 -87
  210. package/src/traversal.ts +0 -528
  211. package/src/webcodec-sample-types.ts +0 -29
  212. package/src/writers/web-fs.ts +0 -50
  213. package/src/writers/writer.ts +0 -12
  214. package/tsconfig.json +0 -14
  215. package/tsconfig.tsbuildinfo +0 -1
@@ -1,19 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
-
3
- export interface Av1CBox {
4
- type: 'av1C-box';
5
- privateData: Uint8Array;
6
- }
7
-
8
- export const parseAv1C = ({
9
- data,
10
- size,
11
- }: {
12
- data: BufferIterator;
13
- size: number;
14
- }): Av1CBox => {
15
- return {
16
- type: 'av1C-box',
17
- privateData: data.getSlice(size - 8),
18
- };
19
- };
@@ -1,36 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
-
3
- export interface AvccBox {
4
- type: 'avcc-box';
5
- description: Uint8Array;
6
- configurationString: string;
7
- }
8
-
9
- export const parseAvcc = ({
10
- data,
11
- size,
12
- }: {
13
- data: BufferIterator;
14
- size: number;
15
- }): AvccBox => {
16
- const confVersion = data.getUint8();
17
- if (confVersion !== 1) {
18
- throw new Error(`Unsupported AVCC version ${confVersion}`);
19
- }
20
-
21
- const profile = data.getUint8();
22
- const profileCompatibility = data.getUint8();
23
- const level = data.getUint8();
24
-
25
- const str = `${profile.toString(16).padStart(2, '0')}${profileCompatibility.toString(16).padStart(2, '0')}${level.toString(16).padStart(2, '0')}`;
26
-
27
- data.counter.decrement(4);
28
-
29
- const description = data.getSlice(size - 8);
30
-
31
- return {
32
- type: 'avcc-box',
33
- description,
34
- configurationString: str,
35
- };
36
- };
@@ -1,49 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
-
3
- export interface ColorParameterBox {
4
- type: 'colr-box';
5
- primaries: number;
6
- transfer: number;
7
- matrixIndex: number;
8
- fullRangeFlag: boolean;
9
- }
10
-
11
- export const parseColorParameterBox = ({
12
- iterator,
13
- }: {
14
- iterator: BufferIterator;
15
- }): ColorParameterBox => {
16
- const byteString = iterator.getByteString(4);
17
- if (byteString === 'nclx') {
18
- const primaries = iterator.getUint16();
19
- const transfer = iterator.getUint16();
20
- const matrixIndex = iterator.getUint16();
21
- iterator.startReadingBits();
22
- const fullRangeFlag = Boolean(iterator.getBits(1));
23
- iterator.stopReadingBits();
24
-
25
- return {
26
- type: 'colr-box',
27
- fullRangeFlag,
28
- matrixIndex,
29
- primaries,
30
- transfer,
31
- };
32
- }
33
-
34
- if (byteString === 'nclc') {
35
- const primaries = iterator.getUint16();
36
- const transfer = iterator.getUint16();
37
- const matrixIndex = iterator.getUint16();
38
-
39
- return {
40
- type: 'colr-box',
41
- fullRangeFlag: false,
42
- matrixIndex,
43
- primaries,
44
- transfer,
45
- };
46
- }
47
-
48
- throw new Error('Unexpected box type ' + byteString);
49
- };
@@ -1,64 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
- import type {BaseBox} from '../base-type';
3
-
4
- type CttsEntry = {
5
- sampleCount: number;
6
- sampleOffset: number;
7
- };
8
-
9
- export interface CttsBox extends BaseBox {
10
- type: 'ctts-box';
11
- version: number;
12
- flags: number[];
13
- entryCount: number;
14
- entries: CttsEntry[];
15
- }
16
-
17
- export const parseCtts = ({
18
- iterator,
19
- offset,
20
- size,
21
- }: {
22
- iterator: BufferIterator;
23
- offset: number;
24
- size: number;
25
- }): CttsBox => {
26
- const version = iterator.getUint8();
27
- if (version !== 0 && version !== 1) {
28
- throw new Error(`Unsupported CTTS version ${version}`);
29
- }
30
-
31
- const flags = iterator.getSlice(3);
32
- const entryCount = iterator.getUint32();
33
-
34
- const entries: CttsEntry[] = [];
35
-
36
- for (let i = 0; i < entryCount; i++) {
37
- const sampleCount = iterator.getUint32();
38
-
39
- // V1 = signed, V0 = unsigned
40
- // however some files are buggy
41
-
42
- // Let's do the same thing as mp4box but uint32, based on our test set of videos
43
- // https://github.com/gpac/mp4box.js/blob/c6cc468145bc5b031b866446111f29c8b620dbe6/src/parsing/ctts.js#L2
44
- const sampleOffset = iterator.getUint32();
45
- if (sampleOffset < 0) {
46
- throw new Error('ctts box uses negative values without using version 1');
47
- }
48
-
49
- entries.push({
50
- sampleCount,
51
- sampleOffset,
52
- });
53
- }
54
-
55
- return {
56
- type: 'ctts-box',
57
- boxSize: size,
58
- offset,
59
- version,
60
- flags: [...flags],
61
- entryCount,
62
- entries,
63
- };
64
- };
@@ -1,32 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
- import {getHvc1CodecString} from '../../../make-hvc1-codec-strings';
3
-
4
- export interface HvccBox {
5
- type: 'hvcc-box';
6
- data: Uint8Array;
7
- configurationString: string;
8
- }
9
-
10
- export const parseHvcc = ({
11
- data,
12
- size,
13
- offset,
14
- }: {
15
- data: BufferIterator;
16
- size: number;
17
- offset: number;
18
- }): HvccBox => {
19
- const raw = data.getSlice(size - 8);
20
- data.counter.decrement(size - 8);
21
-
22
- const constraintString = getHvc1CodecString(data);
23
-
24
- const remaining = size - (data.counter.getOffset() - offset);
25
- data.discard(remaining);
26
-
27
- return {
28
- type: 'hvcc-box',
29
- data: raw,
30
- configurationString: constraintString,
31
- };
32
- };
@@ -1,27 +0,0 @@
1
- import {getArrayBufferIterator} from '../../../buffer-iterator';
2
- import type {BaseBox} from '../base-type';
3
-
4
- export interface KeysBox extends BaseBox {
5
- type: 'keys-box';
6
- }
7
-
8
- export const parseKeys = (data: Uint8Array, offset: number): KeysBox => {
9
- const iterator = getArrayBufferIterator(data, data.byteLength);
10
- const size = iterator.getUint32();
11
- if (size !== data.byteLength) {
12
- throw new Error(`Expected keys size of ${data.byteLength}, got ${size}`);
13
- }
14
-
15
- const atom = iterator.getAtom();
16
- if (atom !== 'keys') {
17
- throw new Error(`Expected keys type of keys, got ${atom}`);
18
- }
19
-
20
- iterator.destroy();
21
-
22
- return {
23
- type: 'keys-box',
24
- boxSize: data.byteLength,
25
- offset,
26
- };
27
- };
@@ -1,54 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
- import type {AnySegment} from '../../../parse-result';
3
- import type {ParserContext} from '../../../parser-context';
4
- import type {BaseBox} from '../base-type';
5
- import {parseBoxes} from '../process-box';
6
-
7
- export interface MebxBox extends BaseBox {
8
- type: 'mebx-box';
9
- dataReferenceIndex: number;
10
- format: string;
11
- children: AnySegment[];
12
- }
13
-
14
- export const parseMebx = async ({
15
- iterator,
16
- offset,
17
- size,
18
- options,
19
- littleEndian,
20
- }: {
21
- iterator: BufferIterator;
22
- offset: number;
23
- size: number;
24
- options: ParserContext;
25
- littleEndian: boolean;
26
- }): Promise<MebxBox> => {
27
- // reserved, 6 bit
28
- iterator.discard(6);
29
-
30
- const dataReferenceIndex = iterator.getUint16();
31
-
32
- const children = await parseBoxes({
33
- iterator,
34
- maxBytes: iterator.counter.getOffset() - offset,
35
- allowIncompleteBoxes: false,
36
- initialBoxes: [],
37
- options,
38
- continueMdat: false,
39
- littleEndian,
40
- });
41
-
42
- if (children.status === 'incomplete') {
43
- throw new Error('Incomplete boxes are not allowed');
44
- }
45
-
46
- return {
47
- type: 'mebx-box',
48
- boxSize: size,
49
- offset,
50
- dataReferenceIndex,
51
- format: 'mebx',
52
- children: children.segments,
53
- };
54
- };
@@ -1,32 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
- import type {BaseBox} from '../base-type';
3
-
4
- export interface PaspBox extends BaseBox {
5
- type: 'pasp-box';
6
- hSpacing: number;
7
- vSpacing: number;
8
- }
9
-
10
- export const parsePasp = ({
11
- iterator,
12
- offset,
13
- size,
14
- }: {
15
- iterator: BufferIterator;
16
- offset: number;
17
- size: number;
18
- }): PaspBox => {
19
- const hSpacing = iterator.getUint32();
20
- const vSpacing = iterator.getUint32();
21
-
22
- const bytesRemainingInBox = size - (iterator.counter.getOffset() - offset);
23
- iterator.discard(bytesRemainingInBox);
24
-
25
- return {
26
- type: 'pasp-box',
27
- boxSize: size,
28
- offset,
29
- hSpacing,
30
- vSpacing,
31
- };
32
- };
@@ -1,359 +0,0 @@
1
- import type {BufferIterator} from '../../../buffer-iterator';
2
- import type {AnySegment} from '../../../parse-result';
3
- import type {ParserContext} from '../../../parser-context';
4
- import {parseBoxes} from '../process-box';
5
-
6
- type SampleBase = {
7
- format: string;
8
- offset: number;
9
- dataReferenceIndex: number;
10
- size: number;
11
- };
12
-
13
- export type AudioSample = SampleBase & {
14
- type: 'audio';
15
- numberOfChannels: number;
16
- sampleSize: number;
17
- compressionId: number;
18
- packetSize: number;
19
- sampleRate: number;
20
- samplesPerPacket: number | null;
21
- bytesPerPacket: number | null;
22
- bytesPerFrame: number | null;
23
- bitsPerSample: number | null;
24
- children: AnySegment[];
25
- version: number;
26
- revisionLevel: number;
27
- vendor: number[];
28
- };
29
-
30
- export type VideoSample = SampleBase & {
31
- type: 'video';
32
- temporalQuality: number;
33
- spacialQuality: number;
34
- width: number;
35
- height: number;
36
- compressorName: number[];
37
- horizontalResolutionPpi: number;
38
- verticalResolutionPpi: number;
39
- dataSize: number;
40
- frameCountPerSample: number;
41
- depth: number;
42
- colorTableId: number;
43
- descriptors: AnySegment[];
44
- version: number;
45
- revisionLevel: number;
46
- vendor: number[];
47
- };
48
-
49
- type UnknownSample = SampleBase & {
50
- type: 'unknown';
51
- };
52
-
53
- export type Sample = AudioSample | VideoSample | UnknownSample;
54
-
55
- type SampleAndNext = {
56
- sample: Sample | null;
57
- };
58
-
59
- // https://developer.apple.com/documentation/quicktime-file-format/video_sample_description
60
- const videoTags = [
61
- 'cvid',
62
- 'jpeg',
63
- 'smc ',
64
- 'rle ',
65
- 'rpza',
66
- 'kpcd',
67
- 'png ',
68
- 'mjpa',
69
- 'mjpb',
70
- 'SVQ1',
71
- 'SVQ3',
72
- 'mp4v',
73
- 'avc1',
74
- 'dvc ',
75
- 'dvcp',
76
- 'gif ',
77
- 'h263',
78
- 'tiff',
79
- 'raw ',
80
- '2vuY',
81
- 'yuv2',
82
- 'v308',
83
- 'v408',
84
- 'v216',
85
- 'v410',
86
- 'v210',
87
- 'hvc1',
88
- 'ap4h',
89
- 'av01',
90
- ];
91
-
92
- // https://developer.apple.com/documentation/quicktime-file-format/sound_sample_descriptions
93
- const audioTags = [
94
- 0x00000000,
95
- 'NONE',
96
- 'raw ',
97
- 'twos',
98
- 'sowt',
99
- 'MAC3 ',
100
- 'MAC6 ',
101
- 'ima4',
102
- 'fl32',
103
- 'fl64',
104
- 'in24',
105
- 'in32',
106
- 'ulaw',
107
- 'alaw',
108
- 0x6d730002,
109
- 0x6d730011,
110
- 'dvca',
111
- 'QDMC',
112
- 'QDM2',
113
- 'Qclp',
114
- 0x6d730055,
115
- '.mp3',
116
- 'mp4a',
117
- 'ac-3',
118
- ];
119
-
120
- export const processSample = async ({
121
- iterator,
122
- options,
123
- }: {
124
- iterator: BufferIterator;
125
- options: ParserContext;
126
- }): Promise<SampleAndNext> => {
127
- const fileOffset = iterator.counter.getOffset();
128
- const bytesRemaining = iterator.bytesRemaining();
129
- const boxSize = iterator.getUint32();
130
-
131
- if (bytesRemaining < boxSize) {
132
- throw new Error(`Expected box size of ${bytesRemaining}, got ${boxSize}`);
133
- }
134
-
135
- const boxFormat = iterator.getAtom();
136
-
137
- const isVideo = videoTags.includes(boxFormat);
138
- const isAudio =
139
- audioTags.includes(boxFormat) || audioTags.includes(Number(boxFormat));
140
-
141
- // 6 reserved bytes
142
- iterator.discard(6);
143
-
144
- const dataReferenceIndex = iterator.getUint16();
145
-
146
- if (!isVideo && !isAudio) {
147
- const bytesRemainingInBox =
148
- boxSize - (iterator.counter.getOffset() - fileOffset);
149
- iterator.discard(bytesRemainingInBox);
150
-
151
- return {
152
- sample: {
153
- type: 'unknown',
154
- offset: fileOffset,
155
- dataReferenceIndex,
156
- size: boxSize,
157
- format: boxFormat,
158
- },
159
- };
160
- }
161
-
162
- if (isAudio) {
163
- const version = iterator.getUint16();
164
- const revisionLevel = iterator.getUint16();
165
- const vendor = iterator.getSlice(4);
166
- if (version === 0) {
167
- const numberOfChannels = iterator.getUint16();
168
- const sampleSize = iterator.getUint16();
169
- const compressionId = iterator.getUint16();
170
- const packetSize = iterator.getUint16();
171
- const sampleRate = iterator.getFixedPointUnsigned1616Number();
172
-
173
- const bytesRemainingInBox =
174
- boxSize - (iterator.counter.getOffset() - fileOffset);
175
- const children = await parseBoxes({
176
- iterator,
177
- allowIncompleteBoxes: false,
178
- maxBytes: bytesRemainingInBox,
179
- initialBoxes: [],
180
- options,
181
- continueMdat: false,
182
- littleEndian: false,
183
- });
184
-
185
- if (children.status === 'incomplete') {
186
- throw new Error('Incomplete boxes are not allowed');
187
- }
188
-
189
- return {
190
- sample: {
191
- format: boxFormat,
192
- offset: fileOffset,
193
- dataReferenceIndex,
194
- version,
195
- revisionLevel,
196
- vendor: [...Array.from(new Uint8Array(vendor))],
197
- size: boxSize,
198
- type: 'audio',
199
- numberOfChannels,
200
- sampleSize,
201
- compressionId,
202
- packetSize,
203
- sampleRate,
204
- samplesPerPacket: null,
205
- bytesPerPacket: null,
206
- bytesPerFrame: null,
207
- bitsPerSample: null,
208
- children: children.segments,
209
- },
210
- };
211
- }
212
-
213
- if (version === 1) {
214
- const numberOfChannels = iterator.getUint16();
215
- const sampleSize = iterator.getUint16();
216
- const compressionId = iterator.getInt16();
217
- const packetSize = iterator.getUint16();
218
- const sampleRate = iterator.getFixedPointUnsigned1616Number();
219
-
220
- const samplesPerPacket = iterator.getUint32();
221
-
222
- const bytesPerPacket = iterator.getUint32();
223
- const bytesPerFrame = iterator.getUint32();
224
- const bytesPerSample = iterator.getUint32();
225
-
226
- const bytesRemainingInBox =
227
- boxSize - (iterator.counter.getOffset() - fileOffset);
228
-
229
- const children = await parseBoxes({
230
- iterator,
231
- allowIncompleteBoxes: false,
232
- maxBytes: bytesRemainingInBox,
233
- initialBoxes: [],
234
- options,
235
- continueMdat: false,
236
- littleEndian: false,
237
- });
238
-
239
- if (children.status === 'incomplete') {
240
- throw new Error('Incomplete boxes are not allowed');
241
- }
242
-
243
- return {
244
- sample: {
245
- format: boxFormat,
246
- offset: fileOffset,
247
- dataReferenceIndex,
248
- version,
249
- revisionLevel,
250
- vendor: [...Array.from(new Uint8Array(vendor))],
251
- size: boxSize,
252
- type: 'audio',
253
- numberOfChannels,
254
- sampleSize,
255
- compressionId,
256
- packetSize,
257
- sampleRate,
258
- samplesPerPacket,
259
- bytesPerPacket,
260
- bytesPerFrame,
261
- bitsPerSample: bytesPerSample,
262
- children: children.segments,
263
- },
264
- };
265
- }
266
-
267
- throw new Error(`Unsupported version ${version}`);
268
- }
269
-
270
- if (isVideo) {
271
- const version = iterator.getUint16();
272
- const revisionLevel = iterator.getUint16();
273
- const vendor = iterator.getSlice(4);
274
- const temporalQuality = iterator.getUint32();
275
- const spacialQuality = iterator.getUint32();
276
- const width = iterator.getUint16();
277
- const height = iterator.getUint16();
278
- const horizontalResolution = iterator.getFixedPointUnsigned1616Number();
279
- const verticalResolution = iterator.getFixedPointUnsigned1616Number();
280
- const dataSize = iterator.getUint32();
281
- const frameCountPerSample = iterator.getUint16();
282
- const compressorName = iterator.getPascalString();
283
- const depth = iterator.getUint16();
284
- const colorTableId = iterator.getInt16();
285
-
286
- const bytesRemainingInBox =
287
- boxSize - (iterator.counter.getOffset() - fileOffset);
288
-
289
- const children = await parseBoxes({
290
- iterator,
291
- allowIncompleteBoxes: false,
292
- maxBytes: bytesRemainingInBox,
293
- initialBoxes: [],
294
- options,
295
- continueMdat: false,
296
- littleEndian: false,
297
- });
298
-
299
- if (children.status === 'incomplete') {
300
- throw new Error('Incomplete boxes are not allowed');
301
- }
302
-
303
- return {
304
- sample: {
305
- format: boxFormat,
306
- offset: fileOffset,
307
- dataReferenceIndex,
308
- version,
309
- revisionLevel,
310
- vendor: [...Array.from(new Uint8Array(vendor))],
311
- size: boxSize,
312
- type: 'video',
313
- width,
314
- height,
315
- horizontalResolutionPpi: horizontalResolution,
316
- verticalResolutionPpi: verticalResolution,
317
- spacialQuality,
318
- temporalQuality,
319
- dataSize,
320
- frameCountPerSample,
321
- compressorName,
322
- depth,
323
- colorTableId,
324
- descriptors: children.segments,
325
- },
326
- };
327
- }
328
-
329
- throw new Error(`Unknown sample format ${boxFormat}`);
330
- };
331
-
332
- export const parseSamples = async ({
333
- iterator,
334
- maxBytes,
335
- options,
336
- }: {
337
- iterator: BufferIterator;
338
- maxBytes: number;
339
- options: ParserContext;
340
- }): Promise<Sample[]> => {
341
- const samples: Sample[] = [];
342
- const initialOffset = iterator.counter.getOffset();
343
-
344
- while (
345
- iterator.bytesRemaining() > 0 &&
346
- iterator.counter.getOffset() - initialOffset < maxBytes
347
- ) {
348
- const {sample} = await processSample({
349
- iterator,
350
- options,
351
- });
352
-
353
- if (sample) {
354
- samples.push(sample);
355
- }
356
- }
357
-
358
- return samples;
359
- };