@remotion/media-parser 4.0.209 → 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 (213) 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 +2 -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/create/cluster-segment.js +0 -2
  39. package/dist/create/cluster.d.ts +10 -2
  40. package/dist/create/cluster.js +16 -10
  41. package/dist/create/create-media.d.ts +4 -2
  42. package/dist/create/create-media.js +76 -14
  43. package/dist/create/cues.d.ts +0 -0
  44. package/dist/create/cues.js +1 -0
  45. package/dist/create/make-duration-with-padding.d.ts +1 -1
  46. package/dist/create/make-duration-with-padding.js +3 -3
  47. package/dist/create/matroska-cues.d.ts +6 -0
  48. package/dist/create/matroska-cues.js +50 -0
  49. package/dist/create/matroska-info.js +1 -1
  50. package/dist/create/matroska-seek.d.ts +6 -0
  51. package/dist/create/matroska-seek.js +32 -0
  52. package/dist/create/matroska-segment.d.ts +1 -0
  53. package/dist/create/matroska-segment.js +3 -2
  54. package/dist/create/matroska-trackentry.d.ts +9 -14
  55. package/dist/create/matroska-trackentry.js +79 -94
  56. package/dist/emit-available-info.d.ts +12 -0
  57. package/dist/emit-available-info.js +133 -0
  58. package/dist/esm/buffer.mjs +57 -0
  59. package/dist/esm/from-fetch.mjs +72 -0
  60. package/dist/esm/from-node.mjs +48 -0
  61. package/dist/esm/from-web-file.mjs +48 -0
  62. package/dist/esm/index.mjs +6689 -0
  63. package/dist/esm/web-fs.mjs +67 -0
  64. package/dist/get-audio-codec.d.ts +5 -5
  65. package/dist/get-audio-codec.js +41 -57
  66. package/dist/get-container.d.ts +4 -0
  67. package/dist/get-container.js +26 -0
  68. package/dist/get-duration.js +1 -1
  69. package/dist/get-fps.js +1 -1
  70. package/dist/get-sample-aspect-ratio.d.ts +1 -1
  71. package/dist/get-sample-aspect-ratio.js +19 -19
  72. package/dist/get-tracks.d.ts +13 -0
  73. package/dist/get-tracks.js +8 -8
  74. package/dist/get-video-codec.d.ts +5 -2
  75. package/dist/get-video-codec.js +111 -21
  76. package/dist/has-all-info.d.ts +2 -2
  77. package/dist/has-all-info.js +23 -9
  78. package/dist/index.d.ts +3 -1
  79. package/dist/options.d.ts +97 -30
  80. package/dist/parse-media.js +43 -62
  81. package/dist/parse-video.d.ts +2 -1
  82. package/dist/parse-video.js +3 -1
  83. package/dist/parser-state.js +1 -2
  84. package/dist/readers/from-fetch.js +24 -4
  85. package/dist/readers/from-node.js +13 -3
  86. package/dist/readers/from-web-file.js +14 -2
  87. package/dist/readers/reader.d.ts +6 -1
  88. package/dist/samples-from-moof.js +1 -1
  89. package/dist/traversal.d.ts +0 -21
  90. package/dist/traversal.js +1 -158
  91. package/dist/truthy.d.ts +3 -0
  92. package/dist/truthy.js +7 -0
  93. package/dist/writers/buffer.d.ts +2 -0
  94. package/dist/writers/buffer.js +58 -0
  95. package/dist/writers/web-fs.d.ts +1 -0
  96. package/dist/writers/web-fs.js +42 -18
  97. package/dist/writers/writer.d.ts +4 -2
  98. package/fetch.js +2 -0
  99. package/node.js +2 -0
  100. package/package.json +43 -8
  101. package/web-file.js +2 -0
  102. package/web-fs.js +2 -0
  103. package/.eslintrc +0 -8
  104. package/input.webm +0 -0
  105. package/src/add-new-matroska-tracks.ts +0 -23
  106. package/src/boxes/iso-base-media/base-type.ts +0 -4
  107. package/src/boxes/iso-base-media/esds/decoder-specific-config.ts +0 -68
  108. package/src/boxes/iso-base-media/esds/esds-descriptors.ts +0 -135
  109. package/src/boxes/iso-base-media/esds/esds.ts +0 -49
  110. package/src/boxes/iso-base-media/ftyp.ts +0 -39
  111. package/src/boxes/iso-base-media/get-sample-positions-from-track.ts +0 -69
  112. package/src/boxes/iso-base-media/make-track.ts +0 -116
  113. package/src/boxes/iso-base-media/mdat/mdat.ts +0 -140
  114. package/src/boxes/iso-base-media/mdhd.ts +0 -59
  115. package/src/boxes/iso-base-media/moov/moov.ts +0 -43
  116. package/src/boxes/iso-base-media/mvhd.ts +0 -114
  117. package/src/boxes/iso-base-media/process-box.ts +0 -748
  118. package/src/boxes/iso-base-media/stsd/av1c.ts +0 -19
  119. package/src/boxes/iso-base-media/stsd/avcc.ts +0 -36
  120. package/src/boxes/iso-base-media/stsd/colr.ts +0 -49
  121. package/src/boxes/iso-base-media/stsd/ctts.ts +0 -64
  122. package/src/boxes/iso-base-media/stsd/hvcc.ts +0 -32
  123. package/src/boxes/iso-base-media/stsd/keys.ts +0 -27
  124. package/src/boxes/iso-base-media/stsd/mebx.ts +0 -54
  125. package/src/boxes/iso-base-media/stsd/pasp.ts +0 -32
  126. package/src/boxes/iso-base-media/stsd/samples.ts +0 -359
  127. package/src/boxes/iso-base-media/stsd/stco.ts +0 -52
  128. package/src/boxes/iso-base-media/stsd/stsc.ts +0 -61
  129. package/src/boxes/iso-base-media/stsd/stsd.ts +0 -55
  130. package/src/boxes/iso-base-media/stsd/stss.ts +0 -47
  131. package/src/boxes/iso-base-media/stsd/stsz.ts +0 -75
  132. package/src/boxes/iso-base-media/stsd/stts.ts +0 -62
  133. package/src/boxes/iso-base-media/tfdt.ts +0 -37
  134. package/src/boxes/iso-base-media/tfhd.ts +0 -66
  135. package/src/boxes/iso-base-media/tkhd.ts +0 -150
  136. package/src/boxes/iso-base-media/to-date.ts +0 -9
  137. package/src/boxes/iso-base-media/trak/trak.ts +0 -43
  138. package/src/boxes/iso-base-media/trun.ts +0 -74
  139. package/src/boxes/iso-base-media/void-box.ts +0 -4
  140. package/src/boxes/webm/allowed-partial-segments.ts +0 -1
  141. package/src/boxes/webm/av1-codec-private.ts +0 -113
  142. package/src/boxes/webm/description.ts +0 -104
  143. package/src/boxes/webm/ebml.ts +0 -98
  144. package/src/boxes/webm/get-ready-tracks.ts +0 -36
  145. package/src/boxes/webm/get-sample-from-block.ts +0 -125
  146. package/src/boxes/webm/get-track.ts +0 -257
  147. package/src/boxes/webm/make-header.ts +0 -253
  148. package/src/boxes/webm/parse-ebml.ts +0 -259
  149. package/src/boxes/webm/parse-webm-header.ts +0 -18
  150. package/src/boxes/webm/segments/all-segments.ts +0 -888
  151. package/src/boxes/webm/segments/block-simple-block-flags.ts +0 -52
  152. package/src/boxes/webm/segments/parse-children.ts +0 -144
  153. package/src/boxes/webm/segments/track-entry.ts +0 -38
  154. package/src/boxes/webm/segments.ts +0 -147
  155. package/src/boxes/webm/traversal.ts +0 -45
  156. package/src/buffer-iterator.ts +0 -555
  157. package/src/create/cluster-segment.ts +0 -62
  158. package/src/create/cluster.ts +0 -64
  159. package/src/create/create-media.ts +0 -136
  160. package/src/create/make-duration-with-padding.ts +0 -15
  161. package/src/create/matroska-header.ts +0 -63
  162. package/src/create/matroska-info.ts +0 -30
  163. package/src/create/matroska-segment.ts +0 -10
  164. package/src/create/matroska-trackentry.ts +0 -325
  165. package/src/create/timescale.ts +0 -1
  166. package/src/get-audio-codec.ts +0 -270
  167. package/src/get-dimensions.ts +0 -47
  168. package/src/get-duration.ts +0 -103
  169. package/src/get-fps.ts +0 -113
  170. package/src/get-sample-aspect-ratio.ts +0 -204
  171. package/src/get-sample-positions.ts +0 -93
  172. package/src/get-tracks.ts +0 -147
  173. package/src/get-video-codec.ts +0 -117
  174. package/src/has-all-info.ts +0 -81
  175. package/src/index.ts +0 -18
  176. package/src/make-hvc1-codec-strings.ts +0 -55
  177. package/src/options.ts +0 -118
  178. package/src/parse-media.ts +0 -183
  179. package/src/parse-result.ts +0 -79
  180. package/src/parse-video.ts +0 -83
  181. package/src/parser-context.ts +0 -10
  182. package/src/parser-state.ts +0 -178
  183. package/src/readers/from-fetch.ts +0 -90
  184. package/src/readers/from-node.ts +0 -51
  185. package/src/readers/from-web-file.ts +0 -49
  186. package/src/readers/reader.ts +0 -15
  187. package/src/samples-from-moof.ts +0 -102
  188. package/src/test/aspect-ratio.test.ts +0 -42
  189. package/src/test/av1.test.ts +0 -108
  190. package/src/test/create-matroska.test.ts +0 -287
  191. package/src/test/duration.test.ts +0 -18
  192. package/src/test/keys.test.ts +0 -47
  193. package/src/test/matroska.test.ts +0 -463
  194. package/src/test/mvhd.test.ts +0 -94
  195. package/src/test/parse-esds.test.ts +0 -98
  196. package/src/test/parse-stco.test.ts +0 -61
  197. package/src/test/parse-stsc.test.ts +0 -104
  198. package/src/test/parse-stsz.test.ts +0 -57
  199. package/src/test/parse-stts.test.ts +0 -38
  200. package/src/test/parse-video.test.ts +0 -101
  201. package/src/test/parse-webm.test.ts +0 -17
  202. package/src/test/samples-from-moof.test.ts +0 -2496
  203. package/src/test/stream-local.test.ts +0 -743
  204. package/src/test/stream-remote.test.ts +0 -59
  205. package/src/test/stream-samples.test.ts +0 -181
  206. package/src/test/stsd.test.ts +0 -265
  207. package/src/test/tkhd.test.ts +0 -87
  208. package/src/traversal.ts +0 -528
  209. package/src/webcodec-sample-types.ts +0 -29
  210. package/src/writers/web-fs.ts +0 -50
  211. package/src/writers/writer.ts +0 -12
  212. package/tsconfig.json +0 -14
  213. 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
- };