@remotion/media-parser 4.0.194 → 4.0.196

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 (275) hide show
  1. package/dist/add-new-matroska-tracks.d.ts +8 -0
  2. package/dist/add-new-matroska-tracks.js +14 -0
  3. package/dist/av1-codec-string.d.ts +3 -0
  4. package/dist/av1-codec-string.js +91 -0
  5. package/dist/boxes/iso-base-media/esds/decoder-specific-config.d.ts +14 -0
  6. package/dist/boxes/iso-base-media/esds/decoder-specific-config.js +38 -0
  7. package/dist/boxes/iso-base-media/esds/esds-descriptors.d.ts +8 -0
  8. package/dist/boxes/iso-base-media/esds/esds-descriptors.js +22 -2
  9. package/dist/boxes/iso-base-media/ftype.d.ts +9 -0
  10. package/dist/boxes/iso-base-media/ftype.js +31 -0
  11. package/dist/boxes/iso-base-media/make-track.d.ts +3 -0
  12. package/dist/boxes/iso-base-media/make-track.js +112 -0
  13. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +6 -2
  14. package/dist/boxes/iso-base-media/mdat/mdat.js +90 -6
  15. package/dist/boxes/iso-base-media/moov/moov.d.ts +4 -2
  16. package/dist/boxes/iso-base-media/moov/moov.js +4 -2
  17. package/dist/boxes/iso-base-media/mvhd.js +7 -1
  18. package/dist/boxes/iso-base-media/process-box.d.ts +20 -3
  19. package/dist/boxes/iso-base-media/process-box.js +322 -34
  20. package/dist/boxes/iso-base-media/stsd/av1c.d.ts +9 -0
  21. package/dist/boxes/iso-base-media/stsd/av1c.js +10 -0
  22. package/dist/boxes/iso-base-media/stsd/avcc-hvcc.d.ts +20 -0
  23. package/dist/boxes/iso-base-media/stsd/avcc-hvcc.js +73 -0
  24. package/dist/boxes/iso-base-media/stsd/avcc.d.ts +10 -0
  25. package/dist/boxes/iso-base-media/stsd/avcc.js +21 -0
  26. package/dist/boxes/iso-base-media/stsd/colr.d.ts +11 -0
  27. package/dist/boxes/iso-base-media/stsd/colr.js +35 -0
  28. package/dist/boxes/iso-base-media/stsd/ctts.d.ts +19 -0
  29. package/dist/boxes/iso-base-media/stsd/ctts.js +30 -0
  30. package/dist/boxes/iso-base-media/stsd/hvcc.d.ts +11 -0
  31. package/dist/boxes/iso-base-media/stsd/hvcc.js +17 -0
  32. package/dist/boxes/iso-base-media/stsd/keys.js +1 -0
  33. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +4 -2
  34. package/dist/boxes/iso-base-media/stsd/mebx.js +4 -2
  35. package/dist/boxes/iso-base-media/stsd/pasp.d.ts +12 -0
  36. package/dist/boxes/iso-base-media/stsd/pasp.js +17 -0
  37. package/dist/boxes/iso-base-media/stsd/samples.d.ts +12 -5
  38. package/dist/boxes/iso-base-media/stsd/samples.js +27 -10
  39. package/dist/boxes/iso-base-media/stsd/stsd.d.ts +4 -2
  40. package/dist/boxes/iso-base-media/stsd/stsd.js +6 -2
  41. package/dist/boxes/iso-base-media/stsd/stss.d.ts +13 -0
  42. package/dist/boxes/iso-base-media/stsd/stss.js +28 -0
  43. package/dist/boxes/iso-base-media/stsd/stsz.d.ts +9 -3
  44. package/dist/boxes/iso-base-media/stsd/stsz.js +14 -2
  45. package/dist/boxes/iso-base-media/stsd/stts.d.ts +15 -0
  46. package/dist/boxes/iso-base-media/stsd/stts.js +35 -0
  47. package/dist/boxes/iso-base-media/tkhd.d.ts +3 -0
  48. package/dist/boxes/iso-base-media/tkhd.js +41 -14
  49. package/dist/boxes/iso-base-media/trak/trak.d.ts +4 -2
  50. package/dist/boxes/iso-base-media/trak/trak.js +4 -2
  51. package/dist/boxes/iso-base-media/void-box.d.ts +4 -0
  52. package/dist/boxes/iso-base-media/void-box.js +2 -0
  53. package/dist/boxes/webm/allowed-partial-segments.d.ts +1 -0
  54. package/dist/boxes/webm/allowed-partial-segments.js +4 -0
  55. package/dist/boxes/webm/av1-codec-private.d.ts +2 -0
  56. package/dist/boxes/webm/av1-codec-private.js +95 -0
  57. package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.d.ts +14 -0
  58. package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.js +67 -0
  59. package/dist/boxes/webm/bitstream/av1/bitstream-frame.d.ts +11 -0
  60. package/dist/boxes/webm/bitstream/av1/bitstream-frame.js +14 -0
  61. package/dist/boxes/webm/bitstream/av1/chroma-sample-position.d.ts +6 -0
  62. package/dist/boxes/webm/bitstream/av1/chroma-sample-position.js +9 -0
  63. package/dist/boxes/webm/bitstream/av1/color-config.d.ts +16 -0
  64. package/dist/boxes/webm/bitstream/av1/color-config.js +103 -0
  65. package/dist/boxes/webm/bitstream/av1/color-primaries.d.ts +14 -0
  66. package/dist/boxes/webm/bitstream/av1/color-primaries.js +17 -0
  67. package/dist/boxes/webm/bitstream/av1/decoder-model-info.d.ts +9 -0
  68. package/dist/boxes/webm/bitstream/av1/decoder-model-info.js +17 -0
  69. package/dist/boxes/webm/bitstream/av1/header-segment.d.ts +51 -0
  70. package/dist/boxes/webm/bitstream/av1/header-segment.js +183 -0
  71. package/dist/boxes/webm/bitstream/av1/matrix-coefficients.d.ts +17 -0
  72. package/dist/boxes/webm/bitstream/av1/matrix-coefficients.js +20 -0
  73. package/dist/boxes/webm/bitstream/av1/operating-parameters-info.d.ts +10 -0
  74. package/dist/boxes/webm/bitstream/av1/operating-parameters-info.js +15 -0
  75. package/dist/boxes/webm/bitstream/av1/temporal-point-info.d.ts +5 -0
  76. package/dist/boxes/webm/bitstream/av1/temporal-point-info.js +8 -0
  77. package/dist/boxes/webm/bitstream/av1/timing-info.d.ts +8 -0
  78. package/dist/boxes/webm/bitstream/av1/timing-info.js +20 -0
  79. package/dist/boxes/webm/bitstream/av1/transfer-characteristics.d.ts +21 -0
  80. package/dist/boxes/webm/bitstream/av1/transfer-characteristics.js +24 -0
  81. package/dist/boxes/webm/bitstream/av1/uvlc.d.ts +2 -0
  82. package/dist/boxes/webm/bitstream/av1/uvlc.js +20 -0
  83. package/dist/boxes/webm/bitstream/av1.d.ts +20 -0
  84. package/dist/boxes/webm/bitstream/av1.js +118 -0
  85. package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.d.ts +0 -0
  86. package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.js +1 -0
  87. package/dist/boxes/webm/description.d.ts +2 -0
  88. package/dist/boxes/webm/description.js +83 -0
  89. package/dist/boxes/webm/get-ready-tracks.d.ts +3 -0
  90. package/dist/boxes/webm/get-ready-tracks.js +29 -0
  91. package/dist/boxes/webm/get-track.d.ts +6 -0
  92. package/dist/boxes/webm/get-track.js +183 -0
  93. package/dist/boxes/webm/parse-webm-header.d.ts +2 -1
  94. package/dist/boxes/webm/parse-webm-header.js +2 -2
  95. package/dist/boxes/webm/segments/all-segments.d.ts +269 -0
  96. package/dist/boxes/webm/segments/all-segments.js +277 -0
  97. package/dist/boxes/webm/segments/duration.d.ts +1 -1
  98. package/dist/boxes/webm/segments/duration.js +13 -9
  99. package/dist/boxes/webm/segments/info.d.ts +2 -1
  100. package/dist/boxes/webm/segments/info.js +12 -4
  101. package/dist/boxes/webm/segments/main.d.ts +0 -2
  102. package/dist/boxes/webm/segments/main.js +0 -11
  103. package/dist/boxes/webm/segments/muxing.d.ts +1 -1
  104. package/dist/boxes/webm/segments/muxing.js +1 -2
  105. package/dist/boxes/webm/segments/parse-children.d.ts +11 -1
  106. package/dist/boxes/webm/segments/parse-children.js +82 -6
  107. package/dist/boxes/webm/segments/seek-head.d.ts +2 -1
  108. package/dist/boxes/webm/segments/seek-head.js +12 -3
  109. package/dist/boxes/webm/segments/seek-position.d.ts +1 -1
  110. package/dist/boxes/webm/segments/seek-position.js +1 -2
  111. package/dist/boxes/webm/segments/seek.d.ts +7 -2
  112. package/dist/boxes/webm/segments/seek.js +22 -9
  113. package/dist/boxes/webm/segments/track-entry.d.ts +102 -22
  114. package/dist/boxes/webm/segments/track-entry.js +269 -57
  115. package/dist/boxes/webm/segments/tracks.d.ts +2 -1
  116. package/dist/boxes/webm/segments/tracks.js +12 -4
  117. package/dist/boxes/webm/segments/void.d.ts +1 -1
  118. package/dist/boxes/webm/segments/void.js +1 -2
  119. package/dist/boxes/webm/segments/writing.d.ts +1 -1
  120. package/dist/boxes/webm/segments/writing.js +1 -2
  121. package/dist/boxes/webm/segments.d.ts +8 -4
  122. package/dist/boxes/webm/segments.js +176 -40
  123. package/dist/boxes/webm/traversal.d.ts +7 -0
  124. package/dist/boxes/webm/traversal.js +25 -0
  125. package/dist/buffer-iterator.d.ts +15 -1
  126. package/dist/buffer-iterator.js +115 -46
  127. package/dist/combine-uint8array.d.ts +1 -0
  128. package/dist/combine-uint8array.js +13 -0
  129. package/dist/from-fetch.d.ts +2 -0
  130. package/dist/from-fetch.js +54 -0
  131. package/dist/from-node.js +6 -0
  132. package/dist/from-web-file.d.ts +2 -0
  133. package/dist/from-web-file.js +34 -0
  134. package/dist/from-web.js +6 -9
  135. package/dist/get-audio-codec.d.ts +19 -0
  136. package/dist/get-audio-codec.js +153 -60
  137. package/dist/get-dimensions.d.ts +8 -2
  138. package/dist/get-dimensions.js +13 -91
  139. package/dist/get-duration.js +4 -7
  140. package/dist/get-fps.d.ts +4 -3
  141. package/dist/get-fps.js +17 -116
  142. package/dist/get-sample-aspect-ratio.d.ts +37 -0
  143. package/dist/get-sample-aspect-ratio.js +137 -0
  144. package/dist/get-sample-positions.d.ts +11 -1
  145. package/dist/get-sample-positions.js +31 -2
  146. package/dist/get-tracks.d.ts +44 -5
  147. package/dist/get-tracks.js +66 -48
  148. package/dist/get-video-codec.d.ts +2 -0
  149. package/dist/get-video-codec.js +47 -31
  150. package/dist/get-video-metadata.d.ts +2 -0
  151. package/dist/get-video-metadata.js +44 -0
  152. package/dist/has-all-info.d.ts +2 -1
  153. package/dist/has-all-info.js +14 -5
  154. package/dist/index.d.ts +1 -0
  155. package/dist/make-hvc1-codec-strings.d.ts +2 -0
  156. package/dist/make-hvc1-codec-strings.js +47 -0
  157. package/dist/options.d.ts +26 -4
  158. package/dist/parse-media.js +62 -17
  159. package/dist/parse-result.d.ts +16 -5
  160. package/dist/parse-video.d.ts +11 -2
  161. package/dist/parse-video.js +14 -6
  162. package/dist/parser-context.d.ts +8 -0
  163. package/dist/parser-context.js +2 -0
  164. package/dist/parser-state.d.ts +23 -0
  165. package/dist/parser-state.js +112 -0
  166. package/dist/read-and-increment-offset.d.ts +28 -0
  167. package/dist/read-and-increment-offset.js +177 -0
  168. package/dist/reader.d.ts +2 -2
  169. package/dist/traversal.d.ts +37 -0
  170. package/dist/traversal.js +244 -1
  171. package/dist/understand-vorbis.d.ts +1 -0
  172. package/dist/understand-vorbis.js +12 -0
  173. package/dist/webcodec-sample-types.d.ts +21 -0
  174. package/dist/webcodec-sample-types.js +2 -0
  175. package/package.json +10 -2
  176. package/src/add-new-matroska-tracks.ts +23 -0
  177. package/src/boxes/iso-base-media/esds/decoder-specific-config.ts +61 -0
  178. package/src/boxes/iso-base-media/esds/esds-descriptors.ts +33 -2
  179. package/src/boxes/iso-base-media/make-track.ts +157 -0
  180. package/src/boxes/iso-base-media/mdat/mdat.ts +131 -0
  181. package/src/boxes/iso-base-media/moov/moov.ts +8 -3
  182. package/src/boxes/iso-base-media/mvhd.ts +7 -1
  183. package/src/boxes/iso-base-media/process-box.ts +388 -38
  184. package/src/boxes/iso-base-media/stsd/av1c.ts +19 -0
  185. package/src/boxes/iso-base-media/stsd/avcc.ts +36 -0
  186. package/src/boxes/iso-base-media/stsd/colr.ts +49 -0
  187. package/src/boxes/iso-base-media/stsd/ctts.ts +55 -0
  188. package/src/boxes/iso-base-media/stsd/hvcc.ts +32 -0
  189. package/src/boxes/iso-base-media/stsd/keys.ts +2 -0
  190. package/src/boxes/iso-base-media/stsd/mebx.ts +8 -3
  191. package/src/boxes/iso-base-media/stsd/pasp.ts +32 -0
  192. package/src/boxes/iso-base-media/stsd/samples.ts +43 -16
  193. package/src/boxes/iso-base-media/stsd/stco.ts +50 -0
  194. package/src/boxes/iso-base-media/stsd/stsc.ts +61 -0
  195. package/src/boxes/iso-base-media/stsd/stsd.ts +10 -3
  196. package/src/boxes/iso-base-media/stsd/stss.ts +47 -0
  197. package/src/boxes/iso-base-media/stsd/stsz.ts +75 -0
  198. package/src/boxes/iso-base-media/tkhd.ts +63 -16
  199. package/src/boxes/iso-base-media/trak/trak.ts +8 -3
  200. package/src/boxes/iso-base-media/void-box.ts +4 -0
  201. package/src/boxes/webm/allowed-partial-segments.ts +1 -0
  202. package/src/boxes/webm/av1-codec-private.ts +113 -0
  203. package/src/boxes/webm/description.ts +101 -0
  204. package/src/boxes/webm/get-ready-tracks.ts +36 -0
  205. package/src/boxes/webm/get-track.ts +250 -0
  206. package/src/boxes/webm/parse-webm-header.ts +6 -2
  207. package/src/boxes/webm/segments/all-segments.ts +285 -0
  208. package/src/boxes/webm/segments/duration.ts +15 -8
  209. package/src/boxes/webm/segments/info.ts +18 -4
  210. package/src/boxes/webm/segments/main.ts +0 -13
  211. package/src/boxes/webm/segments/muxing.ts +1 -1
  212. package/src/boxes/webm/segments/parse-children.ts +132 -9
  213. package/src/boxes/webm/segments/seek-head.ts +17 -4
  214. package/src/boxes/webm/segments/seek-position.ts +1 -2
  215. package/src/boxes/webm/segments/seek.ts +31 -9
  216. package/src/boxes/webm/segments/track-entry.ts +475 -65
  217. package/src/boxes/webm/segments/tracks.ts +17 -7
  218. package/src/boxes/webm/segments/void.ts +4 -2
  219. package/src/boxes/webm/segments/writing.ts +1 -1
  220. package/src/boxes/webm/segments.ts +266 -42
  221. package/src/boxes/webm/traversal.ts +32 -0
  222. package/src/buffer-iterator.ts +140 -45
  223. package/src/combine-uint8array.ts +13 -0
  224. package/src/{from-web.ts → from-fetch.ts} +9 -1
  225. package/src/from-node.ts +8 -0
  226. package/src/from-web-file.ts +39 -0
  227. package/src/get-audio-codec.ts +213 -84
  228. package/src/get-dimensions.ts +25 -132
  229. package/src/get-duration.ts +4 -8
  230. package/src/get-fps.ts +27 -172
  231. package/src/get-sample-aspect-ratio.ts +204 -0
  232. package/src/get-sample-positions.ts +93 -0
  233. package/src/get-tracks.ts +147 -0
  234. package/src/get-video-codec.ts +62 -47
  235. package/src/has-all-info.ts +35 -5
  236. package/src/index.ts +8 -0
  237. package/src/make-hvc1-codec-strings.ts +55 -0
  238. package/src/options.ts +48 -9
  239. package/src/parse-media.ts +90 -21
  240. package/src/parse-result.ts +28 -4
  241. package/src/parse-video.ts +30 -7
  242. package/src/parser-context.ts +9 -0
  243. package/src/parser-state.ts +151 -0
  244. package/src/reader.ts +2 -2
  245. package/src/test/aspect-ratio.test.ts +42 -0
  246. package/src/test/av1.test.ts +108 -0
  247. package/src/test/duration.test.ts +5 -21
  248. package/src/test/matroska.test.ts +350 -31
  249. package/src/test/mvhd.test.ts +6 -1
  250. package/src/test/parse-esds.test.ts +29 -6
  251. package/src/test/parse-stco.test.ts +59 -0
  252. package/src/test/parse-stsc.test.ts +104 -0
  253. package/src/test/parse-stsz.test.ts +57 -0
  254. package/src/test/parse-stts.test.ts +1 -1
  255. package/src/test/parse-video.test.ts +23 -35
  256. package/src/test/parse-webm.test.ts +5 -5
  257. package/src/test/stream-local.test.ts +542 -46
  258. package/src/test/stream-remote.test.ts +15 -13
  259. package/src/test/stream-samples.test.ts +259 -0
  260. package/src/test/stsd.test.ts +60 -8
  261. package/src/test/tkhd.test.ts +4 -1
  262. package/src/traversal.ts +496 -0
  263. package/src/webcodec-sample-types.ts +30 -0
  264. package/tsconfig.json +5 -1
  265. package/tsconfig.tsbuildinfo +1 -1
  266. package/boxes.json +0 -1
  267. package/dist/boxes/iso-base-media/esds-descriptors.d.ts +0 -21
  268. package/dist/boxes/iso-base-media/esds-descriptors.js +0 -62
  269. package/dist/boxes/iso-base-media/esds.d.ts +0 -15
  270. package/dist/boxes/iso-base-media/esds.js +0 -27
  271. package/dist/get-codec.d.ts +0 -4
  272. package/dist/get-codec.js +0 -22
  273. /package/dist/{get-samples.d.ts → boxes/webm/bitstream/av1/frame.d.ts} +0 -0
  274. /package/dist/{get-samples.js → boxes/webm/bitstream/av1/frame.js} +0 -0
  275. /package/src/boxes/iso-base-media/{stts → stsd}/stts.ts +0 -0
@@ -1,8 +1,13 @@
1
1
  /* eslint-disable max-depth */
2
- import type {Sample} from './boxes/iso-base-media/stsd/samples';
2
+ import type {EsdsBox} from './boxes/iso-base-media/esds/esds';
3
+ import type {MoovBox} from './boxes/iso-base-media/moov/moov';
4
+ import type {AudioSample} from './boxes/iso-base-media/stsd/samples';
5
+ import type {TrakBox} from './boxes/iso-base-media/trak/trak';
6
+ import type {MainSegment} from './boxes/webm/segments/main';
3
7
  import {trakBoxContainsAudio} from './get-fps';
4
8
  import type {KnownAudioCodecs} from './options';
5
9
  import type {AnySegment} from './parse-result';
10
+ import {getMoovBox, getStsdBox, getTraks} from './traversal';
6
11
 
7
12
  export const hasAudioCodec = (boxes: AnySegment[]): boolean => {
8
13
  try {
@@ -12,111 +17,152 @@ export const hasAudioCodec = (boxes: AnySegment[]): boolean => {
12
17
  }
13
18
  };
14
19
 
15
- const onEsdsBox = (child: AnySegment): KnownAudioCodecs | null => {
20
+ const getCodecSpecificatorFromEsdsBox = ({
21
+ child,
22
+ }: {
23
+ child: EsdsBox;
24
+ }): {
25
+ primary: number;
26
+ secondary: number | null;
27
+ description: Uint8Array | undefined;
28
+ } => {
29
+ const descriptor = child.descriptors.find(
30
+ (d) => d.type === 'decoder-config-descriptor',
31
+ );
32
+ if (!descriptor) {
33
+ throw new Error('No decoder-config-descriptor');
34
+ }
35
+
36
+ if (descriptor.type !== 'decoder-config-descriptor') {
37
+ throw new Error('Expected decoder-config-descriptor');
38
+ }
39
+
40
+ if (descriptor.asNumber !== 0x40) {
41
+ return {
42
+ primary: descriptor.asNumber,
43
+ secondary: null,
44
+ description: undefined,
45
+ };
46
+ }
47
+
48
+ const audioSpecificConfig = descriptor.decoderSpecificConfigs.find((d) => {
49
+ return d.type === 'audio-specific-config' ? d : null;
50
+ });
51
+ if (
52
+ !audioSpecificConfig ||
53
+ audioSpecificConfig.type !== 'audio-specific-config'
54
+ ) {
55
+ throw new Error('No audio-specific-config');
56
+ }
57
+
58
+ return {
59
+ primary: descriptor.asNumber,
60
+ secondary: audioSpecificConfig.audioObjectType,
61
+ description: audioSpecificConfig.asBytes,
62
+ };
63
+ };
64
+
65
+ type AudioCodecInfo = {
66
+ format: string;
67
+ primarySpecificator: number | null;
68
+ secondarySpecificator: number | null;
69
+ description: Uint8Array | undefined;
70
+ };
71
+
72
+ const onSample = (
73
+ sample: AudioSample,
74
+ children: AnySegment[],
75
+ ): AudioCodecInfo | null => {
76
+ const child = children.find((c) => c.type === 'esds-box');
77
+
16
78
  if (child && child.type === 'esds-box') {
17
- const descriptor = child.descriptors.find(
18
- (d) => d.type === 'decoder-config-descriptor',
19
- );
20
- if (descriptor && descriptor.type === 'decoder-config-descriptor') {
21
- return descriptor.objectTypeIndication;
22
- }
79
+ const ret = getCodecSpecificatorFromEsdsBox({child});
80
+ return {
81
+ format: sample.format,
82
+ primarySpecificator: ret.primary,
83
+ secondarySpecificator: ret.secondary,
84
+ description: ret.description,
85
+ };
23
86
  }
24
87
 
25
- return null;
88
+ return {
89
+ format: sample.format,
90
+ primarySpecificator: null,
91
+ secondarySpecificator: null,
92
+ description: undefined,
93
+ };
26
94
  };
27
95
 
28
- const onSample = (sample: Sample): KnownAudioCodecs | null | undefined => {
29
- if (!sample) {
96
+ export const getNumberOfChannelsFromTrak = (trak: TrakBox): number | null => {
97
+ const stsdBox = getStsdBox(trak);
98
+ if (!stsdBox) {
30
99
  return null;
31
100
  }
32
101
 
33
- if (sample.type !== 'audio') {
102
+ const sample = stsdBox.samples.find((s) => s.type === 'audio');
103
+ if (!sample || sample.type !== 'audio') {
34
104
  return null;
35
105
  }
36
106
 
37
- if (sample.format === 'sowt') {
38
- return 'aiff';
39
- }
107
+ return sample.numberOfChannels;
108
+ };
40
109
 
41
- const child = sample.children.find((c) => c.type === 'esds-box');
110
+ export const getSampleRate = (trak: TrakBox): number | null => {
111
+ const stsdBox = getStsdBox(trak);
112
+ if (!stsdBox) {
113
+ return null;
114
+ }
42
115
 
43
- if (child && child.type === 'esds-box') {
44
- const ret = onEsdsBox(child);
45
- if (ret) {
46
- return ret;
47
- }
116
+ const sample = stsdBox.samples.find((s) => s.type === 'audio');
117
+ if (!sample || sample.type !== 'audio') {
118
+ return null;
48
119
  }
120
+
121
+ return sample.sampleRate;
49
122
  };
50
123
 
51
- export const getAudioCodec = (boxes: AnySegment[]): KnownAudioCodecs | null => {
52
- const moovBox = boxes.find((b) => b.type === 'moov-box');
53
- if (moovBox && moovBox.type === 'moov-box') {
54
- const trakBox = moovBox.children.find(
55
- (b) => b.type === 'trak-box' && trakBoxContainsAudio(b),
56
- );
57
- if (trakBox && trakBox.type === 'trak-box') {
58
- const mdiaBox = trakBox.children.find(
59
- (b) => b.type === 'regular-box' && b.boxType === 'mdia',
60
- );
61
- if (
62
- mdiaBox &&
63
- mdiaBox.type === 'regular-box' &&
64
- mdiaBox.boxType === 'mdia'
65
- ) {
66
- const minfBox = mdiaBox?.children.find(
67
- (b) => b.type === 'regular-box' && b.boxType === 'minf',
68
- );
69
- if (
70
- minfBox &&
71
- minfBox.type === 'regular-box' &&
72
- minfBox.boxType === 'minf'
73
- ) {
74
- const stblBox = minfBox?.children.find(
75
- (b) => b.type === 'regular-box' && b.boxType === 'stbl',
76
- );
77
- if (stblBox && stblBox.type === 'regular-box') {
78
- const stsdBox = stblBox?.children.find(
79
- (b) => b.type === 'stsd-box',
80
- );
81
- if (stsdBox && stsdBox.type === 'stsd-box') {
82
- const sample = stsdBox.samples.find((s) => s.type === 'audio');
83
- if (sample && sample.type === 'audio') {
84
- const ret = onSample(sample);
85
- if (ret) {
86
- return ret;
87
- }
88
-
89
- const waveBox = sample.children.find(
90
- (b) => b.type === 'regular-box' && b.boxType === 'wave',
91
- );
92
- if (
93
- waveBox &&
94
- waveBox.type === 'regular-box' &&
95
- waveBox.boxType === 'wave'
96
- ) {
97
- const esdsBox = waveBox.children.find(
98
- (b) => b.type === 'esds-box',
99
- );
100
- if (esdsBox && esdsBox.type === 'esds-box') {
101
- const ret2 = onEsdsBox(esdsBox);
102
- if (ret2) {
103
- return ret2;
104
- }
105
- }
106
- }
107
- }
108
- }
109
- }
110
- }
111
- }
124
+ export const getAudioCodecFromTrak = (trak: TrakBox): AudioCodecInfo | null => {
125
+ const stsdBox = getStsdBox(trak);
126
+ if (!stsdBox) {
127
+ return null;
128
+ }
129
+
130
+ const sample = stsdBox.samples.find((s) => s.type === 'audio');
131
+ if (!sample || sample.type !== 'audio') {
132
+ return null;
133
+ }
134
+
135
+ const waveBox = sample.children.find(
136
+ (b) => b.type === 'regular-box' && b.boxType === 'wave',
137
+ );
138
+ if (waveBox && waveBox.type === 'regular-box' && waveBox.boxType === 'wave') {
139
+ const esdsSample = onSample(sample, waveBox.children);
140
+ if (esdsSample) {
141
+ return esdsSample;
112
142
  }
113
143
  }
114
144
 
115
- const mainSegment = boxes.find((b) => b.type === 'main-segment');
116
- if (!mainSegment || mainSegment.type !== 'main-segment') {
145
+ const ret = onSample(sample, sample.children);
146
+ if (ret) {
147
+ return ret;
148
+ }
149
+
150
+ return null;
151
+ };
152
+
153
+ export const getAudioCodecFromIso = (moov: MoovBox) => {
154
+ const traks = getTraks(moov);
155
+ const trakBox = traks.find(
156
+ (b) => b.type === 'trak-box' && trakBoxContainsAudio(b),
157
+ );
158
+ if (!trakBox) {
117
159
  return null;
118
160
  }
119
161
 
162
+ return getAudioCodecFromTrak(trakBox);
163
+ };
164
+
165
+ export const getAudioCodecFromMatroska = (mainSegment: MainSegment) => {
120
166
  const tracksSegment = mainSegment.children.find(
121
167
  (b) => b.type === 'tracks-segment',
122
168
  );
@@ -132,12 +178,95 @@ export const getAudioCodec = (boxes: AnySegment[]): KnownAudioCodecs | null => {
132
178
  return 'opus';
133
179
  }
134
180
 
181
+ if (trackType.codec === 'A_VORBIS') {
182
+ return 'vorbis';
183
+ }
184
+
135
185
  if (trackType.codec === 'A_PCM/INT/LIT') {
136
186
  return 'pcm';
137
187
  }
188
+
189
+ if (trackType.codec === 'A_AAC') {
190
+ return 'aac';
191
+ }
192
+
193
+ if (trackType.codec === 'A_MPEG/L3') {
194
+ return 'mp3';
195
+ }
138
196
  }
139
197
  }
140
198
  }
141
199
 
142
200
  return null;
143
201
  };
202
+
203
+ export const getAudioCodecStringFromTrak = (
204
+ trak: TrakBox,
205
+ ): {codecString: string; description: Uint8Array | undefined} => {
206
+ const codec = getAudioCodecFromTrak(trak);
207
+ if (!codec) {
208
+ throw new Error('Expected codec');
209
+ }
210
+
211
+ const codecStringWithoutMp3Exception = (
212
+ [
213
+ codec.format,
214
+ codec.primarySpecificator ? codec.primarySpecificator.toString(16) : null,
215
+ codec.secondarySpecificator
216
+ ? codec.secondarySpecificator.toString().padStart(2, '0')
217
+ : null,
218
+ ].filter(Boolean) as string[]
219
+ ).join('.');
220
+
221
+ // Really, MP3? 😔
222
+ const codecString =
223
+ codecStringWithoutMp3Exception === 'mp4a.6b'
224
+ ? 'mp3' // or "mp4a.6B" would also work, with the uppercasing, but mp3 is probably more obvious
225
+ : codecStringWithoutMp3Exception;
226
+
227
+ return {
228
+ codecString,
229
+ description: codec.description,
230
+ };
231
+ };
232
+
233
+ export const getAudioCodec = (boxes: AnySegment[]): KnownAudioCodecs | null => {
234
+ const moovBox = getMoovBox(boxes);
235
+
236
+ if (moovBox) {
237
+ const codec = getAudioCodecFromIso(moovBox);
238
+
239
+ if (!codec) {
240
+ return null;
241
+ }
242
+
243
+ if (codec.format === 'sowt') {
244
+ return 'aiff';
245
+ }
246
+
247
+ if (codec.format === 'mp4a') {
248
+ if (codec.primarySpecificator === 0x40) {
249
+ return 'aac';
250
+ }
251
+
252
+ if (codec.primarySpecificator === 0x6b) {
253
+ return 'mp3';
254
+ }
255
+
256
+ if (codec.primarySpecificator === null) {
257
+ return 'aac';
258
+ }
259
+
260
+ throw new Error('Unknown mp4a codec: ' + codec.primarySpecificator);
261
+ }
262
+
263
+ throw new Error('Unknown audio format: ' + codec.format);
264
+ }
265
+
266
+ const mainSegment = boxes.find((b) => b.type === 'main-segment');
267
+ if (!mainSegment || mainSegment.type !== 'main-segment') {
268
+ return null;
269
+ }
270
+
271
+ return getAudioCodecFromMatroska(mainSegment);
272
+ };
@@ -1,153 +1,46 @@
1
- import type {MainSegment} from './boxes/webm/segments/main';
1
+ import {getTracks} from './get-tracks';
2
2
  import type {AnySegment} from './parse-result';
3
+ import type {ParserState} from './parser-state';
3
4
 
4
5
  export type Dimensions = {
5
6
  width: number;
6
7
  height: number;
7
8
  };
8
9
 
9
- const getDimensionsFromMatroska = (segments: MainSegment): Dimensions => {
10
- const tracksSegment = segments.children.find(
11
- (b) => b.type === 'tracks-segment',
12
- );
13
- if (!tracksSegment || tracksSegment.type !== 'tracks-segment') {
14
- throw new Error('No tracks segment');
15
- }
16
-
17
- const trackEntrySegment = tracksSegment.children.find((b) => {
18
- if (b.type !== 'track-entry-segment') {
19
- return false;
20
- }
21
-
22
- return (
23
- b.children.find(
24
- (c) => c.type === 'codec-segment' && c.codec.startsWith('V_'),
25
- ) !== undefined
26
- );
27
- });
28
- if (!trackEntrySegment || trackEntrySegment.type !== 'track-entry-segment') {
29
- throw new Error('No track entry segment');
30
- }
31
-
32
- const videoSegment = trackEntrySegment.children.find(
33
- (b) => b.type === 'video-segment',
34
- );
35
- if (!videoSegment || videoSegment.type !== 'video-segment') {
36
- throw new Error('No video segment');
37
- }
10
+ export type ExpandedDimensions = Dimensions & {
11
+ rotation: number;
12
+ unrotatedWidth: number;
13
+ unrotatedHeight: number;
14
+ };
38
15
 
39
- const widthSegment = videoSegment.children.find(
40
- (b) => b.type === 'width-segment',
41
- );
42
- if (!widthSegment || widthSegment.type !== 'width-segment') {
43
- throw new Error('No width segment');
16
+ export const getDimensions = (
17
+ boxes: AnySegment[],
18
+ state: ParserState,
19
+ ): ExpandedDimensions => {
20
+ const {videoTracks} = getTracks(boxes, state);
21
+ if (!videoTracks.length) {
22
+ throw new Error('Expected video track');
44
23
  }
45
24
 
46
- const heightSegment = videoSegment.children.find(
47
- (b) => b.type === 'height-segment',
48
- );
49
- if (!heightSegment || heightSegment.type !== 'height-segment') {
50
- throw new Error('No height segment');
51
- }
25
+ const firstVideoTrack = videoTracks[0];
52
26
 
53
27
  return {
54
- width: widthSegment.width,
55
- height: heightSegment.height,
28
+ width: firstVideoTrack.width,
29
+ height: firstVideoTrack.height,
30
+ rotation: firstVideoTrack.rotation,
31
+ unrotatedHeight: firstVideoTrack.displayAspectHeight,
32
+ unrotatedWidth: firstVideoTrack.displayAspectWidth,
56
33
  };
57
34
  };
58
35
 
59
- export const getDimensions = (boxes: AnySegment[]): Dimensions => {
60
- const matroskaBox = boxes.find((b) => b.type === 'main-segment');
61
- if (matroskaBox && matroskaBox.type === 'main-segment') {
62
- return getDimensionsFromMatroska(matroskaBox);
63
- }
64
-
65
- const moovBox = boxes.find((b) => b.type === 'moov-box');
66
- if (!moovBox || moovBox.type !== 'moov-box') {
67
- throw new Error('Expected moov box');
68
- }
69
-
70
- const {children} = moovBox;
71
- if (!children) {
72
- throw new Error('Expected moov box children');
73
- }
74
-
75
- const t = children.find((b) => b.type === 'trak-box');
76
-
77
- if (!t || t.type !== 'trak-box') {
78
- throw new Error('Expected trak box');
79
- }
80
-
81
- const mdiaBox = t.children.find(
82
- (c) => c.type === 'regular-box' && c.boxType === 'mdia',
83
- );
84
- const tkhdBox = t.children.find((c) => c.type === 'tkhd-box');
85
- if (tkhdBox && tkhdBox.type === 'tkhd-box') {
86
- return {
87
- width: tkhdBox.width,
88
- height: tkhdBox.height,
89
- };
90
- }
91
-
92
- if (!mdiaBox) {
93
- throw new Error('Expected mdia box');
94
- }
95
-
96
- if (mdiaBox.type !== 'regular-box') {
97
- throw new Error('Expected mdia box');
98
- }
99
-
100
- const minfBox = mdiaBox.children.find(
101
- (c) => c.type === 'regular-box' && c.boxType === 'minf',
102
- );
103
- if (!minfBox) {
104
- throw new Error('Expected minf box');
105
- }
106
-
107
- if (minfBox.type !== 'regular-box') {
108
- throw new Error('Expected minf box');
109
- }
110
-
111
- const stblBox = minfBox.children.find(
112
- (c) => c.type === 'regular-box' && c.boxType === 'stbl',
113
- );
114
-
115
- if (!stblBox) {
116
- throw new Error('Expected stbl box');
117
- }
118
-
119
- if (stblBox.type !== 'regular-box') {
120
- throw new Error('Expected stbl box');
121
- }
122
-
123
- const stsdBox = stblBox.children.find((c) => c.type === 'stsd-box');
124
-
125
- if (!stsdBox) {
126
- throw new Error('Expected stsd box');
127
- }
128
-
129
- if (stsdBox.type !== 'stsd-box') {
130
- throw new Error('Expected stsd box');
131
- }
132
-
133
- const videoSamples = stsdBox.samples.filter((s) => s.type === 'video');
134
- if (videoSamples.length === 0) {
135
- throw new Error('Has no video stream');
136
- }
137
-
138
- const [firstTrack] = videoSamples;
139
- if (firstTrack.type !== 'video') {
140
- throw new Error('Expected video track');
141
- }
142
-
143
- return {width: firstTrack.width, height: firstTrack.height};
144
- };
145
-
146
36
  // TODO: An audio track should return 'hasDimensions' = true on an audio file
147
37
  // and stop parsing
148
- export const hasDimensions = (boxes: AnySegment[]): boolean => {
38
+ export const hasDimensions = (
39
+ boxes: AnySegment[],
40
+ state: ParserState,
41
+ ): boolean => {
149
42
  try {
150
- return getDimensions(boxes) !== null;
43
+ return getDimensions(boxes, state) !== null;
151
44
  } catch (err) {
152
45
  return false;
153
46
  }
@@ -1,4 +1,5 @@
1
1
  import type {AnySegment} from './parse-result';
2
+ import {getMoovBox, getMvhdBox} from './traversal';
2
3
 
3
4
  const getDurationFromMatroska = (segments: AnySegment[]): number | null => {
4
5
  const mainSegment = segments.find((s) => s.type === 'main-segment');
@@ -41,17 +42,12 @@ export const getDuration = (boxes: AnySegment[]): number | null => {
41
42
  return getDurationFromMatroska(boxes);
42
43
  }
43
44
 
44
- const moovBox = boxes.find((b) => b.type === 'moov-box');
45
- if (!moovBox || moovBox.type !== 'moov-box') {
45
+ const moovBox = getMoovBox(boxes);
46
+ if (!moovBox) {
46
47
  return null;
47
48
  }
48
49
 
49
- const {children} = moovBox;
50
- if (!children) {
51
- return null;
52
- }
53
-
54
- const mvhdBox = children.find((b) => b.type === 'mvhd-box');
50
+ const mvhdBox = getMvhdBox(moovBox);
55
51
 
56
52
  if (!mvhdBox) {
57
53
  return null;