@remotion/media-parser 4.0.200 → 4.0.202

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 (180) hide show
  1. package/dist/av1-codec-string.d.ts +5 -0
  2. package/dist/av1-codec-string.js +18 -1
  3. package/dist/bitstream/av1.d.ts +2 -0
  4. package/dist/bitstream/av1.js +12 -0
  5. package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +20 -0
  6. package/dist/boxes/iso-base-media/avcc-hvcc.js +73 -0
  7. package/dist/boxes/iso-base-media/avcc.d.ts +18 -0
  8. package/dist/boxes/iso-base-media/avcc.js +27 -0
  9. package/dist/boxes/iso-base-media/esds-descriptors.d.ts +21 -0
  10. package/dist/boxes/iso-base-media/esds-descriptors.js +62 -0
  11. package/dist/boxes/iso-base-media/esds.d.ts +15 -0
  12. package/dist/boxes/iso-base-media/esds.js +27 -0
  13. package/dist/boxes/iso-base-media/mdat/mdat.js +2 -1
  14. package/dist/boxes/iso-base-media/moov/moov.js +1 -0
  15. package/dist/boxes/iso-base-media/mvhd.js +2 -2
  16. package/dist/boxes/iso-base-media/process-box.d.ts +4 -2
  17. package/dist/boxes/iso-base-media/process-box.js +56 -40
  18. package/dist/boxes/iso-base-media/stsd/keys.js +1 -1
  19. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
  20. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
  21. package/dist/boxes/iso-base-media/stsd/samples.js +3 -0
  22. package/dist/boxes/iso-base-media/stsd/stco.d.ts +3 -2
  23. package/dist/boxes/iso-base-media/stsd/stco.js +2 -2
  24. package/dist/boxes/iso-base-media/trak/trak.js +1 -0
  25. package/dist/boxes/webm/av1-codec-private.js +1 -1
  26. package/dist/boxes/webm/bitstream/av1.js +10 -1
  27. package/dist/boxes/webm/description.d.ts +2 -2
  28. package/dist/boxes/webm/description.js +2 -2
  29. package/dist/boxes/webm/ebml.d.ts +2 -2
  30. package/dist/boxes/webm/ebml.js +23 -1
  31. package/dist/boxes/webm/get-ready-tracks.d.ts +1 -1
  32. package/dist/boxes/webm/get-ready-tracks.js +3 -3
  33. package/dist/boxes/webm/get-sample-from-block.d.ts +17 -0
  34. package/dist/boxes/webm/get-sample-from-block.js +78 -0
  35. package/dist/boxes/webm/get-track.d.ts +2 -2
  36. package/dist/boxes/webm/get-track.js +26 -25
  37. package/dist/boxes/webm/make-header.d.ts +3 -1
  38. package/dist/boxes/webm/make-header.js +90 -32
  39. package/dist/boxes/webm/parse-ebml.d.ts +12 -0
  40. package/dist/boxes/webm/parse-ebml.js +175 -0
  41. package/dist/boxes/webm/parse-webm-header.js +8 -9
  42. package/dist/boxes/webm/segments/all-segments.d.ts +572 -1
  43. package/dist/boxes/webm/segments/all-segments.js +353 -2
  44. package/dist/boxes/webm/segments/track-entry.d.ts +5 -189
  45. package/dist/boxes/webm/segments/track-entry.js +2 -457
  46. package/dist/boxes/webm/segments.d.ts +3 -16
  47. package/dist/boxes/webm/segments.js +40 -219
  48. package/dist/boxes/webm/traversal.d.ts +5 -5
  49. package/dist/boxes/webm/traversal.js +17 -6
  50. package/dist/buffer-iterator.d.ts +10 -7
  51. package/dist/buffer-iterator.js +83 -7
  52. package/dist/create/create-media.d.ts +2 -0
  53. package/dist/create/create-media.js +36 -0
  54. package/dist/create/matroska-header.d.ts +1 -0
  55. package/dist/create/matroska-header.js +66 -0
  56. package/dist/create/matroska-info.d.ts +4 -0
  57. package/dist/create/matroska-info.js +39 -0
  58. package/dist/create/matroska-segment.d.ts +1 -0
  59. package/dist/create/matroska-segment.js +12 -0
  60. package/dist/create/matroska-trackentry.d.ts +21 -0
  61. package/dist/create/matroska-trackentry.js +191 -0
  62. package/dist/create-media.d.ts +1 -0
  63. package/dist/create-media.js +78 -0
  64. package/dist/from-fetch.js +13 -3
  65. package/dist/from-input-type-file.d.ts +2 -0
  66. package/dist/from-input-type-file.js +37 -0
  67. package/dist/from-node.js +9 -2
  68. package/dist/from-web-file.js +6 -1
  69. package/dist/from-web.js +15 -6
  70. package/dist/get-audio-codec.d.ts +2 -2
  71. package/dist/get-audio-codec.js +13 -13
  72. package/dist/get-codec.d.ts +4 -0
  73. package/dist/get-codec.js +22 -0
  74. package/dist/get-duration.js +12 -14
  75. package/dist/get-sample-positions.js +1 -1
  76. package/dist/get-tracks.js +2 -2
  77. package/dist/get-video-codec.js +13 -13
  78. package/dist/has-all-info.js +1 -1
  79. package/dist/options.d.ts +3 -2
  80. package/dist/parse-media.js +17 -10
  81. package/dist/parse-video.js +16 -0
  82. package/dist/parser-context.d.ts +1 -0
  83. package/dist/parser-state.d.ts +4 -3
  84. package/dist/parser-state.js +16 -3
  85. package/dist/reader.d.ts +1 -1
  86. package/dist/readers/from-fetch.d.ts +2 -0
  87. package/dist/readers/from-fetch.js +64 -0
  88. package/dist/readers/from-node.d.ts +2 -0
  89. package/dist/readers/from-node.js +40 -0
  90. package/dist/readers/from-web-file.d.ts +2 -0
  91. package/dist/readers/from-web-file.js +39 -0
  92. package/dist/readers/reader.d.ts +11 -0
  93. package/dist/readers/reader.js +2 -0
  94. package/dist/traversal.d.ts +19 -17
  95. package/dist/traversal.js +38 -39
  96. package/dist/web-file.d.ts +2 -0
  97. package/dist/web-file.js +37 -0
  98. package/dist/writers/web-fs.d.ts +2 -0
  99. package/dist/writers/web-fs.js +28 -0
  100. package/dist/writers/writer.d.ts +9 -0
  101. package/dist/writers/writer.js +2 -0
  102. package/input.webm +0 -0
  103. package/package.json +2 -2
  104. package/src/boxes/iso-base-media/mdat/mdat.ts +2 -1
  105. package/src/boxes/iso-base-media/moov/moov.ts +1 -0
  106. package/src/boxes/iso-base-media/mvhd.ts +2 -2
  107. package/src/boxes/iso-base-media/process-box.ts +70 -40
  108. package/src/boxes/iso-base-media/stsd/keys.ts +1 -1
  109. package/src/boxes/iso-base-media/stsd/mebx.ts +3 -0
  110. package/src/boxes/iso-base-media/stsd/samples.ts +3 -0
  111. package/src/boxes/iso-base-media/stsd/stco.ts +5 -3
  112. package/src/boxes/iso-base-media/trak/trak.ts +1 -0
  113. package/src/boxes/webm/av1-codec-private.ts +1 -1
  114. package/src/boxes/webm/description.ts +7 -4
  115. package/src/boxes/webm/ebml.ts +24 -4
  116. package/src/boxes/webm/get-ready-tracks.ts +4 -4
  117. package/src/boxes/webm/get-sample-from-block.ts +125 -0
  118. package/src/boxes/webm/get-track.ts +38 -31
  119. package/src/boxes/webm/make-header.ts +129 -32
  120. package/src/boxes/webm/parse-ebml.ts +247 -0
  121. package/src/boxes/webm/parse-webm-header.ts +8 -12
  122. package/src/boxes/webm/segments/all-segments.ts +539 -1
  123. package/src/boxes/webm/segments/track-entry.ts +5 -843
  124. package/src/boxes/webm/segments.ts +48 -435
  125. package/src/boxes/webm/traversal.ts +28 -15
  126. package/src/buffer-iterator.ts +104 -10
  127. package/src/from-fetch.ts +22 -3
  128. package/src/from-node.ts +18 -4
  129. package/src/from-web-file.ts +11 -1
  130. package/src/get-audio-codec.ts +14 -16
  131. package/src/get-duration.ts +15 -16
  132. package/src/get-sample-positions.ts +1 -1
  133. package/src/get-tracks.ts +2 -2
  134. package/src/get-video-codec.ts +13 -15
  135. package/src/has-all-info.ts +1 -1
  136. package/src/options.ts +3 -2
  137. package/src/parse-media.ts +20 -9
  138. package/src/parse-video.ts +17 -0
  139. package/src/parser-context.ts +1 -0
  140. package/src/parser-state.ts +22 -5
  141. package/src/reader.ts +1 -0
  142. package/src/test/create-matroska.test.ts +255 -7
  143. package/src/test/matroska.test.ts +311 -334
  144. package/src/test/mvhd.test.ts +1 -1
  145. package/src/test/parse-esds.test.ts +2 -2
  146. package/src/test/parse-stco.test.ts +4 -2
  147. package/src/test/parse-stsc.test.ts +2 -2
  148. package/src/test/parse-stsz.test.ts +2 -2
  149. package/src/test/parse-stts.test.ts +1 -1
  150. package/src/test/stream-local.test.ts +23 -9
  151. package/src/test/stream-remote.test.ts +23 -19
  152. package/src/test/stsd.test.ts +6 -2
  153. package/src/test/tkhd.test.ts +1 -1
  154. package/src/traversal.ts +62 -85
  155. package/tsconfig.tsbuildinfo +1 -1
  156. package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
  157. package/dist/boxes/iso-base-media/ftype.js +0 -31
  158. package/dist/get-video-metadata.d.ts +0 -2
  159. package/dist/get-video-metadata.js +0 -44
  160. package/dist/read-and-increment-offset.d.ts +0 -28
  161. package/dist/read-and-increment-offset.js +0 -177
  162. package/dist/understand-vorbis.d.ts +0 -1
  163. package/dist/understand-vorbis.js +0 -12
  164. package/src/boxes/webm/segments/duration.ts +0 -29
  165. package/src/boxes/webm/segments/info.ts +0 -34
  166. package/src/boxes/webm/segments/main.ts +0 -6
  167. package/src/boxes/webm/segments/muxing.ts +0 -18
  168. package/src/boxes/webm/segments/seek-head.ts +0 -34
  169. package/src/boxes/webm/segments/seek-position.ts +0 -18
  170. package/src/boxes/webm/segments/seek.ts +0 -45
  171. package/src/boxes/webm/segments/timestamp-scale.ts +0 -17
  172. package/src/boxes/webm/segments/tracks.ts +0 -32
  173. package/src/boxes/webm/segments/unknown.ts +0 -19
  174. package/src/boxes/webm/segments/void.ts +0 -18
  175. package/src/boxes/webm/segments/writing.ts +0 -18
  176. package/src/combine-uint8array.ts +0 -13
  177. /package/dist/{boxes/webm/bitstream/av1/frame.d.ts → get-samples.d.ts} +0 -0
  178. /package/dist/{boxes/webm/bitstream/av1/frame.js → get-samples.js} +0 -0
  179. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.d.ts → sample-aspect-ratio.d.ts} +0 -0
  180. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.js → sample-aspect-ratio.js} +0 -0
@@ -5,7 +5,7 @@ export const parseAv1PrivateData = (
5
5
  data: Uint8Array,
6
6
  colrAtom: ColorParameterBox | null,
7
7
  ) => {
8
- const iterator = getArrayBufferIterator(data);
8
+ const iterator = getArrayBufferIterator(data, data.byteLength);
9
9
  iterator.startReadingBits();
10
10
  if (iterator.getBits(1) !== 1) {
11
11
  iterator.destroy();
@@ -1,12 +1,12 @@
1
1
  import {getArrayBufferIterator} from '../../buffer-iterator';
2
2
  import {getCodecSegment, getPrivateData} from '../../traversal';
3
- import type {TrackEntrySegment} from './segments/track-entry';
3
+ import type {TrackEntry} from './segments/all-segments';
4
4
 
5
5
  export const getAudioDescription = (
6
- track: TrackEntrySegment,
6
+ track: TrackEntry,
7
7
  ): undefined | Uint8Array => {
8
8
  const codec = getCodecSegment(track);
9
- if (!codec || codec.codec !== 'A_VORBIS') {
9
+ if (!codec || codec.value !== 'A_VORBIS') {
10
10
  return undefined;
11
11
  }
12
12
 
@@ -59,7 +59,10 @@ export const getAudioDescription = (
59
59
 
60
60
  const vorbisBooks = privateData.slice(offset);
61
61
 
62
- const bufferIterator = getArrayBufferIterator(vorbisInfo.slice(0));
62
+ const bufferIterator = getArrayBufferIterator(
63
+ vorbisInfo.slice(0),
64
+ vorbisInfo.length,
65
+ );
63
66
 
64
67
  // type
65
68
  bufferIterator.getUint8();
@@ -32,10 +32,9 @@ export const measureEBMLVarInt = (value: number) => {
32
32
  throw new Error('EBML VINT size not supported ' + value);
33
33
  };
34
34
 
35
- export const getVariableInt = (
36
- value: number,
37
- width: number = measureEBMLVarInt(value),
38
- ) => {
35
+ export const getVariableInt = (value: number, minWidth: number | null) => {
36
+ const width = Math.max(measureEBMLVarInt(value), minWidth ?? 0);
37
+
39
38
  switch (width) {
40
39
  case 1:
41
40
  return new Uint8Array([(1 << 7) | value]);
@@ -72,6 +71,27 @@ export const getVariableInt = (
72
71
  value >> 8,
73
72
  value,
74
73
  ]);
74
+ case 7:
75
+ return new Uint8Array([
76
+ (1 << 1) | ((value / 2 ** 48) & 0x1),
77
+ (value / 2 ** 40) | 0,
78
+ (value / 2 ** 32) | 0,
79
+ value >> 24,
80
+ value >> 16,
81
+ value >> 8,
82
+ value,
83
+ ]);
84
+ case 8:
85
+ return new Uint8Array([
86
+ (1 << 0) | ((value / 2 ** 56) & 0x1),
87
+ (value / 2 ** 48) | 0,
88
+ (value / 2 ** 40) | 0,
89
+ (value / 2 ** 32) | 0,
90
+ value >> 24,
91
+ value >> 16,
92
+ value >> 8,
93
+ value,
94
+ ]);
75
95
  default:
76
96
  throw new Error('Bad EBML VINT size ' + width);
77
97
  }
@@ -1,7 +1,7 @@
1
1
  import type {Track} from '../../get-tracks';
2
2
  import {getTracksSegment} from '../../traversal';
3
3
  import {getTrack} from './get-track';
4
- import type {MainSegment} from './segments/main';
4
+ import type {MainSegment} from './segments/all-segments';
5
5
 
6
6
  export const getTracksFromMatroska = (
7
7
  segment: MainSegment,
@@ -14,12 +14,12 @@ export const getTracksFromMatroska = (
14
14
 
15
15
  const tracks: Track[] = [];
16
16
 
17
- for (const trackEntrySegment of tracksSegment.children) {
18
- if (trackEntrySegment.type === 'crc32-segment') {
17
+ for (const trackEntrySegment of tracksSegment.value) {
18
+ if (trackEntrySegment.type === 'Crc32') {
19
19
  continue;
20
20
  }
21
21
 
22
- if (trackEntrySegment.type !== 'track-entry-segment') {
22
+ if (trackEntrySegment.type !== 'TrackEntry') {
23
23
  throw new Error('Expected track entry segment');
24
24
  }
25
25
 
@@ -0,0 +1,125 @@
1
+ import {getArrayBufferIterator} from '../../buffer-iterator';
2
+ import type {ParserContext} from '../../parser-context';
3
+ import type {AudioSample, VideoSample} from '../../webcodec-sample-types';
4
+ import type {BlockSegment, SimpleBlockSegment} from './segments/all-segments';
5
+ import {matroskaElements} from './segments/all-segments';
6
+ import {parseBlockFlags} from './segments/block-simple-block-flags';
7
+
8
+ type SampleResult =
9
+ | {
10
+ type: 'video-sample';
11
+ videoSample: VideoSample;
12
+ }
13
+ | {
14
+ type: 'audio-sample';
15
+ audioSample: AudioSample;
16
+ }
17
+ | {
18
+ type: 'partial-video-sample';
19
+ partialVideoSample: Omit<VideoSample, 'type'>;
20
+ }
21
+ | {
22
+ type: 'no-sample';
23
+ };
24
+
25
+ export const getSampleFromBlock = (
26
+ ebml: BlockSegment | SimpleBlockSegment,
27
+ parserContext: ParserContext,
28
+ offset: number,
29
+ ): SampleResult => {
30
+ const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
31
+ const trackNumber = iterator.getVint();
32
+ if (trackNumber === null) {
33
+ throw new Error('Not enough data to get track number, should not happen');
34
+ }
35
+
36
+ const timecodeRelativeToCluster = iterator.getUint16();
37
+
38
+ const {keyframe} = parseBlockFlags(
39
+ iterator,
40
+ ebml.type === 'SimpleBlock'
41
+ ? matroskaElements.SimpleBlock
42
+ : matroskaElements.Block,
43
+ );
44
+
45
+ const {codec, trackTimescale} =
46
+ parserContext.parserState.getTrackInfoByNumber(trackNumber);
47
+
48
+ const clusterOffset =
49
+ parserContext.parserState.getTimestampOffsetForByteOffset(offset);
50
+
51
+ const timescale = parserContext.parserState.getTimescale();
52
+
53
+ if (clusterOffset === undefined) {
54
+ throw new Error('Could not find offset for byte offset ' + offset);
55
+ }
56
+
57
+ // https://github.com/hubblec4/Matroska-Chapters-Specs/blob/master/notes.md/#timestampscale
58
+ // The TimestampScale Element is used to calculate the Raw Timestamp of a Block. The timestamp is obtained by adding the Block's timestamp to the Cluster's Timestamp Element, and then multiplying that result by the TimestampScale. The result will be the Block's Raw Timestamp in nanoseconds.
59
+ const timecodeInNanoSeconds =
60
+ (timecodeRelativeToCluster + clusterOffset) *
61
+ timescale *
62
+ (trackTimescale ?? 1);
63
+
64
+ // Timecode should be in microseconds
65
+ const timecodeInMicroseconds = timecodeInNanoSeconds / 1000;
66
+
67
+ if (!codec) {
68
+ throw new Error(`Could not find codec for track ${trackNumber}`);
69
+ }
70
+
71
+ const remainingNow = ebml.value.length - (iterator.counter.getOffset() - 0);
72
+
73
+ if (codec.startsWith('V_')) {
74
+ const partialVideoSample: Omit<VideoSample, 'type'> = {
75
+ data: iterator.getSlice(remainingNow),
76
+ cts: null,
77
+ dts: null,
78
+ duration: undefined,
79
+ trackId: trackNumber,
80
+ timestamp: timecodeInMicroseconds,
81
+ };
82
+
83
+ if (keyframe === null) {
84
+ iterator.destroy();
85
+
86
+ return {
87
+ type: 'partial-video-sample',
88
+ partialVideoSample,
89
+ };
90
+ }
91
+
92
+ const sample: VideoSample = {
93
+ ...partialVideoSample,
94
+ type: keyframe ? 'key' : 'delta',
95
+ };
96
+
97
+ iterator.destroy();
98
+
99
+ return {
100
+ type: 'video-sample',
101
+ videoSample: sample,
102
+ };
103
+ }
104
+
105
+ if (codec.startsWith('A_')) {
106
+ const audioSample: AudioSample = {
107
+ data: iterator.getSlice(remainingNow),
108
+ trackId: trackNumber,
109
+ timestamp: timecodeInMicroseconds,
110
+ type: 'key',
111
+ };
112
+
113
+ iterator.destroy();
114
+
115
+ return {
116
+ type: 'audio-sample',
117
+ audioSample,
118
+ };
119
+ }
120
+
121
+ iterator.destroy();
122
+ return {
123
+ type: 'no-sample',
124
+ };
125
+ };
@@ -16,15 +16,16 @@ import {
16
16
  } from '../../traversal';
17
17
  import {parseAv1PrivateData} from './av1-codec-private';
18
18
  import {getAudioDescription} from './description';
19
- import type {CodecSegment, TrackEntrySegment} from './segments/track-entry';
19
+ import type {CodecIdSegment, TrackEntry} from './segments/all-segments';
20
+ import {trackTypeToString} from './segments/track-entry';
20
21
 
21
- const getDescription = (track: TrackEntrySegment): undefined | Uint8Array => {
22
+ const getDescription = (track: TrackEntry): undefined | Uint8Array => {
22
23
  const codec = getCodecSegment(track);
23
24
  if (!codec) {
24
25
  return undefined;
25
26
  }
26
27
 
27
- if (codec.codec === 'V_MPEG4/ISO/AVC' || codec.codec === 'V_MPEGH/ISO/HEVC') {
28
+ if (codec.value === 'V_MPEG4/ISO/AVC' || codec.value === 'V_MPEGH/ISO/HEVC') {
28
29
  const priv = getPrivateData(track);
29
30
  if (priv) {
30
31
  return priv;
@@ -38,14 +39,14 @@ const getMatroskaVideoCodecString = ({
38
39
  track,
39
40
  codecSegment: codec,
40
41
  }: {
41
- track: TrackEntrySegment;
42
- codecSegment: CodecSegment;
42
+ track: TrackEntry;
43
+ codecSegment: CodecIdSegment;
43
44
  }): string | null => {
44
- if (codec.codec === 'V_VP8') {
45
+ if (codec.value === 'V_VP8') {
45
46
  return 'vp8';
46
47
  }
47
48
 
48
- if (codec.codec === 'V_VP9') {
49
+ if (codec.value === 'V_VP9') {
49
50
  const priv = getPrivateData(track);
50
51
  if (priv) {
51
52
  throw new Error(
@@ -56,7 +57,7 @@ const getMatroskaVideoCodecString = ({
56
57
  return 'vp09.00.10.08';
57
58
  }
58
59
 
59
- if (codec.codec === 'V_MPEG4/ISO/AVC') {
60
+ if (codec.value === 'V_MPEG4/ISO/AVC') {
60
61
  const priv = getPrivateData(track);
61
62
  if (priv) {
62
63
  return `avc1.${priv[1].toString(16).padStart(2, '0')}${priv[2].toString(16).padStart(2, '0')}${priv[3].toString(16).padStart(2, '0')}`;
@@ -65,7 +66,7 @@ const getMatroskaVideoCodecString = ({
65
66
  throw new Error('Could not find a CodecPrivate field in TrackEntry');
66
67
  }
67
68
 
68
- if (codec.codec === 'V_AV1') {
69
+ if (codec.value === 'V_AV1') {
69
70
  const priv = getPrivateData(track);
70
71
 
71
72
  if (!priv) {
@@ -75,31 +76,34 @@ const getMatroskaVideoCodecString = ({
75
76
  return parseAv1PrivateData(priv, null);
76
77
  }
77
78
 
78
- if (codec.codec === 'V_MPEGH/ISO/HEVC') {
79
+ if (codec.value === 'V_MPEGH/ISO/HEVC') {
79
80
  const priv = getPrivateData(track);
80
- const iterator = getArrayBufferIterator(priv as Uint8Array);
81
+ const iterator = getArrayBufferIterator(
82
+ priv as Uint8Array,
83
+ (priv as Uint8Array).length,
84
+ );
81
85
 
82
86
  return 'hvc1.' + getHvc1CodecString(iterator);
83
87
  }
84
88
 
85
- throw new Error(`Unknown codec: ${codec.codec}`);
89
+ throw new Error(`Unknown codec: ${codec.value}`);
86
90
  };
87
91
 
88
- const getMatroskaAudioCodecString = (track: TrackEntrySegment): string => {
92
+ const getMatroskaAudioCodecString = (track: TrackEntry): string => {
89
93
  const codec = getCodecSegment(track);
90
94
  if (!codec) {
91
95
  throw new Error('Expected codec segment');
92
96
  }
93
97
 
94
- if (codec.codec === 'A_OPUS') {
98
+ if (codec.value === 'A_OPUS') {
95
99
  return 'opus';
96
100
  }
97
101
 
98
- if (codec.codec === 'A_VORBIS') {
102
+ if (codec.value === 'A_VORBIS') {
99
103
  return 'vorbis';
100
104
  }
101
105
 
102
- if (codec.codec === 'A_PCM/INT/LIT') {
106
+ if (codec.value === 'A_PCM/INT/LIT') {
103
107
  // https://github.com/ietf-wg-cellar/matroska-specification/issues/142#issuecomment-330004950
104
108
  // Audio samples MUST be considered as signed values, except if the audio bit depth is 8 which MUST be interpreted as unsigned values.
105
109
 
@@ -115,10 +119,13 @@ const getMatroskaAudioCodecString = (track: TrackEntrySegment): string => {
115
119
  return 'pcm-s' + bitDepth;
116
120
  }
117
121
 
118
- if (codec.codec === 'A_AAC') {
122
+ if (codec.value === 'A_AAC') {
119
123
  const priv = getPrivateData(track);
120
124
 
121
- const iterator = getArrayBufferIterator(priv as Uint8Array);
125
+ const iterator = getArrayBufferIterator(
126
+ priv as Uint8Array,
127
+ (priv as Uint8Array).length,
128
+ );
122
129
 
123
130
  iterator.startReadingBits();
124
131
  /**
@@ -150,11 +157,11 @@ const getMatroskaAudioCodecString = (track: TrackEntrySegment): string => {
150
157
  return `mp4a.40.${profile.toString().padStart(2, '0')}`;
151
158
  }
152
159
 
153
- if (codec.codec === 'A_MPEG/L3') {
160
+ if (codec.value === 'A_MPEG/L3') {
154
161
  return 'mp3';
155
162
  }
156
163
 
157
- throw new Error(`Unknown codec: ${codec.codec}`);
164
+ throw new Error(`Unknown codec: ${codec.value}`);
158
165
  };
159
166
 
160
167
  export const getTrack = ({
@@ -162,7 +169,7 @@ export const getTrack = ({
162
169
  track,
163
170
  }: {
164
171
  timescale: number;
165
- track: TrackEntrySegment;
172
+ track: TrackEntry;
166
173
  }): VideoTrack | AudioTrack | null => {
167
174
  const trackType = getTrackTypeSegment(track);
168
175
 
@@ -172,7 +179,7 @@ export const getTrack = ({
172
179
 
173
180
  const trackId = getTrackId(track);
174
181
 
175
- if (trackType.trackType === 'video') {
182
+ if (trackTypeToString(trackType.value.value) === 'video') {
176
183
  const width = getWidthSegment(track);
177
184
 
178
185
  if (width === null) {
@@ -207,27 +214,27 @@ export const getTrack = ({
207
214
  trackId,
208
215
  codec: codecString,
209
216
  description: getDescription(track),
210
- height: displayHeight ? displayHeight.displayHeight : height.height,
211
- width: displayWidth ? displayWidth.displayWidth : width.width,
217
+ height: displayHeight ? displayHeight.value.value : height.value.value,
218
+ width: displayWidth ? displayWidth.value.value : width.value.value,
212
219
  sampleAspectRatio: {
213
220
  numerator: 1,
214
221
  denominator: 1,
215
222
  },
216
223
  timescale,
217
224
  samplePositions: [],
218
- codedHeight: height.height,
219
- codedWidth: width.width,
225
+ codedHeight: height.value.value,
226
+ codedWidth: width.value.value,
220
227
  displayAspectHeight: displayHeight
221
- ? displayHeight.displayHeight
222
- : height.height,
228
+ ? displayHeight.value.value
229
+ : height.value.value,
223
230
  displayAspectWidth: displayWidth
224
- ? displayWidth.displayWidth
225
- : width.width,
231
+ ? displayWidth.value.value
232
+ : width.value.value,
226
233
  rotation: 0,
227
234
  };
228
235
  }
229
236
 
230
- if (trackType.trackType === 'audio') {
237
+ if (trackTypeToString(trackType.value.value) === 'audio') {
231
238
  const sampleRate = getSampleRate(track);
232
239
  const numberOfChannels = getNumberOfChannels(track);
233
240
  if (sampleRate === null) {
@@ -1,48 +1,145 @@
1
1
  import {getVariableInt} from './ebml';
2
- import {matroskaElements} from './segments/all-segments';
2
+ import type {
3
+ FloatWithSize,
4
+ PossibleEbml,
5
+ PossibleEbmlOrUint8Array,
6
+ UintWithSize,
7
+ matroskaElements,
8
+ } from './segments/all-segments';
9
+ import {ebmlMap, getIdForName} from './segments/all-segments';
3
10
 
4
11
  export const webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
5
12
 
6
13
  const matroskaToHex = (
7
14
  matrId: (typeof matroskaElements)[keyof typeof matroskaElements],
8
15
  ) => {
9
- const numbers: number[] = [];
16
+ const numbers: Uint8Array = new Uint8Array((matrId.length - 2) / 2);
17
+
10
18
  for (let i = 2; i < matrId.length; i += 2) {
11
- const hex = matrId.substr(i, 2);
12
- numbers.push(parseInt(hex, 16));
19
+ const hex = matrId.substring(i, i + 2);
20
+ numbers[(i - 2) / 2] = parseInt(hex, 16);
13
21
  }
14
22
 
15
23
  return numbers;
16
24
  };
17
25
 
18
- export const makeMatroskaHeader = () => {
19
- const size = 0x23;
20
-
21
- const array = new Uint8Array([
22
- ...webmPattern,
23
- ...getVariableInt(size),
24
- ...matroskaToHex(matroskaElements.EBMLVersion),
25
- ...getVariableInt(1),
26
- 1,
27
- ...matroskaToHex(matroskaElements.EBMLReadVersion),
28
- ...getVariableInt(1),
29
- 1,
30
- ...matroskaToHex(matroskaElements.EBMLMaxIDLength),
31
- ...getVariableInt(1),
32
- 4,
33
- ...matroskaToHex(matroskaElements.EBMLMaxSizeLength),
34
- ...getVariableInt(1),
35
- 8,
36
- ...matroskaToHex(matroskaElements.DocType),
37
- ...getVariableInt(8),
38
- ...new TextEncoder().encode('matroska'),
39
- ...matroskaToHex(matroskaElements.DocTypeVersion),
40
- ...getVariableInt(1),
41
- 4,
42
- ...matroskaToHex(matroskaElements.DocTypeReadVersion),
43
- ...getVariableInt(1),
44
- 2,
26
+ function putUintDynamic(number: number, minimumLength: number | null) {
27
+ if (number < 0) {
28
+ throw new Error(
29
+ 'This function is designed for non-negative integers only.',
30
+ );
31
+ }
32
+
33
+ // Calculate the minimum number of bytes needed to store the integer
34
+ const length = Math.max(
35
+ minimumLength ?? 0,
36
+ Math.ceil(Math.log2(number + 1) / 8),
37
+ );
38
+ const bytes = new Uint8Array(length);
39
+
40
+ for (let i = 0; i < length; i++) {
41
+ // Extract each byte from the number
42
+ bytes[length - 1 - i] = (number >> (8 * i)) & 0xff;
43
+ }
44
+
45
+ return bytes;
46
+ }
47
+
48
+ const makeFromHeaderStructure = (
49
+ fields: PossibleEbmlOrUint8Array,
50
+ ): Uint8Array => {
51
+ if (fields instanceof Uint8Array) {
52
+ return fields;
53
+ }
54
+
55
+ const arrays: Uint8Array[] = [];
56
+
57
+ const struct = ebmlMap[getIdForName(fields.type)];
58
+
59
+ if (struct.type === 'uint8array') {
60
+ return fields.value as Uint8Array;
61
+ }
62
+
63
+ if (struct.type === 'children') {
64
+ for (const item of fields.value as PossibleEbml[]) {
65
+ arrays.push(makeMatroskaBytes(item));
66
+ }
67
+
68
+ return combineUint8Arrays(arrays);
69
+ }
70
+
71
+ if (struct.type === 'string') {
72
+ return new TextEncoder().encode(fields.value as string);
73
+ }
74
+
75
+ if (struct.type === 'uint') {
76
+ return putUintDynamic(
77
+ (fields.value as UintWithSize).value,
78
+ (fields.value as UintWithSize).byteLength,
79
+ );
80
+ }
81
+
82
+ if (struct.type === 'hex-string') {
83
+ const hex = (fields.value as string).substring(2);
84
+ const arr = new Uint8Array(hex.length / 2);
85
+ for (let i = 0; i < hex.length; i += 2) {
86
+ const byte = parseInt(hex.substring(i, i + 2), 16);
87
+ arr[i / 2] = byte;
88
+ }
89
+
90
+ return arr;
91
+ }
92
+
93
+ if (struct.type === 'float') {
94
+ const value = fields.value as FloatWithSize;
95
+ if (value.size === '32') {
96
+ const dataView = new DataView(new ArrayBuffer(4));
97
+ dataView.setFloat32(0, value.value);
98
+ return new Uint8Array(dataView.buffer);
99
+ }
100
+
101
+ const dataView2 = new DataView(new ArrayBuffer(8));
102
+ dataView2.setFloat64(0, value.value);
103
+ return new Uint8Array(dataView2.buffer);
104
+ }
105
+
106
+ throw new Error('Unexpected type');
107
+ };
108
+
109
+ export const makeMatroskaBytes = (fields: PossibleEbmlOrUint8Array) => {
110
+ if (fields instanceof Uint8Array) {
111
+ return fields;
112
+ }
113
+
114
+ const value = makeFromHeaderStructure(fields);
115
+
116
+ return combineUint8Arrays([
117
+ matroskaToHex(getIdForName(fields.type)),
118
+ getVariableInt(value.length, fields.minVintWidth),
119
+ value,
45
120
  ]);
121
+ };
122
+
123
+ export const combineUint8Arrays = (arrays: Uint8Array[]) => {
124
+ if (arrays.length === 0) {
125
+ return new Uint8Array([]);
126
+ }
127
+
128
+ if (arrays.length === 1) {
129
+ return arrays[0];
130
+ }
131
+
132
+ let totalLength = 0;
133
+ for (const array of arrays) {
134
+ totalLength += array.length;
135
+ }
136
+
137
+ const result = new Uint8Array(totalLength);
138
+ let offset = 0;
139
+ for (const array of arrays) {
140
+ result.set(array, offset);
141
+ offset += array.length;
142
+ }
46
143
 
47
- return array;
144
+ return result;
48
145
  };