@remotion/media-parser 4.0.201 → 4.0.204

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 (144) hide show
  1. package/dist/av1-codec-string.d.ts +0 -5
  2. package/dist/av1-codec-string.js +1 -18
  3. package/dist/boxes/iso-base-media/ftype.d.ts +9 -0
  4. package/dist/boxes/iso-base-media/ftype.js +31 -0
  5. package/dist/boxes/iso-base-media/get-sample-positions-from-track.d.ts +4 -0
  6. package/dist/boxes/iso-base-media/get-sample-positions-from-track.js +48 -0
  7. package/dist/boxes/iso-base-media/mvhd.js +2 -2
  8. package/dist/boxes/iso-base-media/stsd/keys.js +1 -1
  9. package/dist/boxes/iso-base-media/tfdt.d.ts +12 -0
  10. package/dist/boxes/iso-base-media/tfdt.js +20 -0
  11. package/dist/boxes/iso-base-media/tfhd.d.ts +16 -0
  12. package/dist/boxes/iso-base-media/tfhd.js +41 -0
  13. package/dist/boxes/iso-base-media/trun.d.ts +21 -0
  14. package/dist/boxes/iso-base-media/trun.js +44 -0
  15. package/dist/boxes/webm/av1-codec-private.js +1 -1
  16. package/dist/boxes/webm/bitstream/av1.js +1 -10
  17. package/dist/boxes/webm/description.d.ts +2 -2
  18. package/dist/boxes/webm/description.js +2 -2
  19. package/dist/boxes/webm/ebml.d.ts +2 -2
  20. package/dist/boxes/webm/ebml.js +23 -1
  21. package/dist/boxes/webm/get-ready-tracks.d.ts +1 -1
  22. package/dist/boxes/webm/get-ready-tracks.js +3 -3
  23. package/dist/boxes/webm/get-sample-from-block.d.ts +17 -0
  24. package/dist/boxes/webm/get-sample-from-block.js +78 -0
  25. package/dist/boxes/webm/get-track.d.ts +2 -2
  26. package/dist/boxes/webm/get-track.js +26 -25
  27. package/dist/boxes/webm/make-header.d.ts +3 -8
  28. package/dist/boxes/webm/make-header.js +43 -20
  29. package/dist/boxes/webm/parse-ebml.d.ts +9 -4
  30. package/dist/boxes/webm/parse-ebml.js +122 -13
  31. package/dist/boxes/webm/segments/all-segments.d.ts +421 -107
  32. package/dist/boxes/webm/segments/all-segments.js +260 -33
  33. package/dist/boxes/webm/segments/track-entry.d.ts +3 -191
  34. package/dist/boxes/webm/segments/track-entry.js +2 -456
  35. package/dist/boxes/webm/segments.d.ts +3 -16
  36. package/dist/boxes/webm/segments.js +12 -196
  37. package/dist/boxes/webm/tracks.d.ts +8 -0
  38. package/dist/boxes/webm/tracks.js +21 -0
  39. package/dist/boxes/webm/traversal.d.ts +5 -6
  40. package/dist/boxes/webm/traversal.js +6 -6
  41. package/dist/buffer-iterator.d.ts +1 -1
  42. package/dist/buffer-iterator.js +3 -3
  43. package/dist/from-web.js +6 -15
  44. package/dist/get-audio-codec.d.ts +1 -1
  45. package/dist/get-audio-codec.js +13 -13
  46. package/dist/get-duration.js +12 -14
  47. package/dist/get-tracks.js +2 -2
  48. package/dist/get-video-codec.js +13 -13
  49. package/dist/get-video-metadata.d.ts +2 -0
  50. package/dist/get-video-metadata.js +44 -0
  51. package/dist/parse-media.js +4 -1
  52. package/dist/parser-context.d.ts +1 -0
  53. package/dist/parser-state.js +3 -2
  54. package/dist/read-and-increment-offset.d.ts +28 -0
  55. package/dist/read-and-increment-offset.js +177 -0
  56. package/dist/samples-from-moof.d.ts +6 -0
  57. package/dist/samples-from-moof.js +74 -0
  58. package/dist/traversal.d.ts +19 -17
  59. package/dist/traversal.js +38 -39
  60. package/dist/understand-vorbis.d.ts +1 -0
  61. package/dist/understand-vorbis.js +12 -0
  62. package/input.webm +0 -0
  63. package/package.json +2 -2
  64. package/src/boxes/iso-base-media/get-sample-positions-from-track.ts +69 -0
  65. package/src/boxes/iso-base-media/make-track.ts +4 -45
  66. package/src/boxes/iso-base-media/mdat/mdat.ts +33 -24
  67. package/src/boxes/iso-base-media/mdhd.ts +10 -7
  68. package/src/boxes/iso-base-media/mvhd.ts +17 -16
  69. package/src/boxes/iso-base-media/process-box.ts +42 -0
  70. package/src/boxes/iso-base-media/stsd/keys.ts +1 -1
  71. package/src/boxes/iso-base-media/tfdt.ts +37 -0
  72. package/src/boxes/iso-base-media/tfhd.ts +66 -0
  73. package/src/boxes/iso-base-media/tkhd.ts +11 -13
  74. package/src/boxes/iso-base-media/trun.ts +74 -0
  75. package/src/boxes/webm/av1-codec-private.ts +1 -1
  76. package/src/boxes/webm/description.ts +7 -4
  77. package/src/boxes/webm/ebml.ts +24 -4
  78. package/src/boxes/webm/get-ready-tracks.ts +4 -4
  79. package/src/boxes/webm/get-sample-from-block.ts +125 -0
  80. package/src/boxes/webm/get-track.ts +40 -33
  81. package/src/boxes/webm/make-header.ts +58 -51
  82. package/src/boxes/webm/parse-ebml.ts +170 -16
  83. package/src/boxes/webm/segments/all-segments.ts +379 -62
  84. package/src/boxes/webm/segments/track-entry.ts +3 -846
  85. package/src/boxes/webm/segments.ts +18 -410
  86. package/src/boxes/webm/traversal.ts +17 -17
  87. package/src/buffer-iterator.ts +8 -6
  88. package/src/get-audio-codec.ts +14 -16
  89. package/src/get-duration.ts +55 -21
  90. package/src/get-tracks.ts +6 -6
  91. package/src/get-video-codec.ts +13 -15
  92. package/src/has-all-info.ts +1 -1
  93. package/src/parse-media.ts +7 -2
  94. package/src/parse-result.ts +7 -1
  95. package/src/parser-context.ts +1 -0
  96. package/src/parser-state.ts +2 -2
  97. package/src/samples-from-moof.ts +101 -0
  98. package/src/test/create-matroska.test.ts +237 -23
  99. package/src/test/matroska.test.ts +283 -348
  100. package/src/test/mvhd.test.ts +1 -1
  101. package/src/test/parse-esds.test.ts +2 -2
  102. package/src/test/parse-stco.test.ts +2 -2
  103. package/src/test/parse-stsc.test.ts +2 -2
  104. package/src/test/parse-stsz.test.ts +2 -2
  105. package/src/test/parse-stts.test.ts +1 -1
  106. package/src/test/samples-from-moof.test.ts +2496 -0
  107. package/src/test/stream-local.test.ts +28 -30
  108. package/src/test/stream-samples.test.ts +153 -231
  109. package/src/test/stsd.test.ts +4 -2
  110. package/src/test/tkhd.test.ts +1 -1
  111. package/src/traversal.ts +118 -86
  112. package/tsconfig.tsbuildinfo +1 -1
  113. package/dist/bitstream/av1.d.ts +0 -2
  114. package/dist/bitstream/av1.js +0 -12
  115. package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +0 -20
  116. package/dist/boxes/iso-base-media/avcc-hvcc.js +0 -73
  117. package/dist/boxes/iso-base-media/avcc.d.ts +0 -18
  118. package/dist/boxes/iso-base-media/avcc.js +0 -27
  119. package/dist/boxes/iso-base-media/esds-descriptors.d.ts +0 -21
  120. package/dist/boxes/iso-base-media/esds-descriptors.js +0 -62
  121. package/dist/boxes/iso-base-media/esds.d.ts +0 -15
  122. package/dist/boxes/iso-base-media/esds.js +0 -27
  123. package/dist/from-input-type-file.d.ts +0 -2
  124. package/dist/from-input-type-file.js +0 -37
  125. package/dist/get-codec.d.ts +0 -4
  126. package/dist/get-codec.js +0 -22
  127. package/dist/web-file.d.ts +0 -2
  128. package/dist/web-file.js +0 -37
  129. package/src/boxes/webm/segments/duration.ts +0 -29
  130. package/src/boxes/webm/segments/info.ts +0 -34
  131. package/src/boxes/webm/segments/main.ts +0 -6
  132. package/src/boxes/webm/segments/muxing.ts +0 -18
  133. package/src/boxes/webm/segments/seek-head.ts +0 -34
  134. package/src/boxes/webm/segments/seek-position.ts +0 -18
  135. package/src/boxes/webm/segments/seek.ts +0 -55
  136. package/src/boxes/webm/segments/timestamp-scale.ts +0 -17
  137. package/src/boxes/webm/segments/tracks.ts +0 -32
  138. package/src/boxes/webm/segments/void.ts +0 -18
  139. package/src/boxes/webm/segments/writing.ts +0 -18
  140. package/src/combine-uint8array.ts +0 -13
  141. /package/dist/{get-samples.d.ts → boxes/webm/bitstream/av1/frame.d.ts} +0 -0
  142. /package/dist/{get-samples.js → boxes/webm/bitstream/av1/frame.js} +0 -0
  143. /package/dist/{sample-aspect-ratio.d.ts → boxes/webm/bitstream/h264/get-h264-descriptor.d.ts} +0 -0
  144. /package/dist/{sample-aspect-ratio.js → boxes/webm/bitstream/h264/get-h264-descriptor.js} +0 -0
@@ -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
- samplePositions: [],
218
- codedHeight: height.height,
219
- codedWidth: width.width,
224
+ codedHeight: height.value.value,
225
+ codedWidth: width.value.value,
220
226
  displayAspectHeight: displayHeight
221
- ? displayHeight.displayHeight
222
- : height.height,
227
+ ? displayHeight.value.value
228
+ : height.value.value,
223
229
  displayAspectWidth: displayWidth
224
- ? displayWidth.displayWidth
225
- : width.width,
230
+ ? displayWidth.value.value
231
+ : width.value.value,
226
232
  rotation: 0,
233
+ trakBox: null,
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) {
@@ -238,11 +245,11 @@ export const getTrack = ({
238
245
  type: 'audio',
239
246
  trackId,
240
247
  codec: getMatroskaAudioCodecString(track),
241
- samplePositions: null,
242
248
  timescale,
243
249
  numberOfChannels,
244
250
  sampleRate,
245
251
  description: getAudioDescription(track),
252
+ trakBox: null,
246
253
  };
247
254
  }
248
255
 
@@ -1,15 +1,12 @@
1
1
  import {getVariableInt} from './ebml';
2
2
  import type {
3
- Ebml,
4
- EbmlWithChildren,
5
- EbmlWithHexString,
6
- EbmlWithString,
7
- EbmlWithUint8,
8
- EmblTypes,
9
- HeaderStructure,
3
+ FloatWithSize,
4
+ PossibleEbml,
5
+ PossibleEbmlOrUint8Array,
6
+ UintWithSize,
10
7
  matroskaElements,
11
8
  } from './segments/all-segments';
12
- import {getIdForName} from './segments/all-segments';
9
+ import {ebmlMap, getIdForName} from './segments/all-segments';
13
10
 
14
11
  export const webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
15
12
 
@@ -26,24 +23,7 @@ const matroskaToHex = (
26
23
  return numbers;
27
24
  };
28
25
 
29
- type Numbers = '0' | '1' | '2' | '3' | '4' | '5' | '6';
30
-
31
- type ChildFields<Struct extends HeaderStructure> = {
32
- [key in keyof Struct &
33
- Numbers as Struct[key]['name']]: EmblTypes[Struct[key]['type']];
34
- };
35
-
36
- type SerializeValue<Struct extends Ebml> = Struct extends EbmlWithChildren
37
- ? ChildFields<Struct['children']>
38
- : Struct extends EbmlWithString
39
- ? string
40
- : Struct extends EbmlWithUint8
41
- ? number
42
- : Struct extends EbmlWithHexString
43
- ? string
44
- : undefined;
45
-
46
- function putUintDynamic(number: number) {
26
+ function putUintDynamic(number: number, minimumLength: number | null) {
47
27
  if (number < 0) {
48
28
  throw new Error(
49
29
  'This function is designed for non-negative integers only.',
@@ -51,7 +31,10 @@ function putUintDynamic(number: number) {
51
31
  }
52
32
 
53
33
  // Calculate the minimum number of bytes needed to store the integer
54
- const length = Math.ceil(Math.log2(number + 1) / 8);
34
+ const length = Math.max(
35
+ minimumLength ?? 0,
36
+ Math.ceil(Math.log2(number + 1) / 8),
37
+ );
55
38
  const bytes = new Uint8Array(length);
56
39
 
57
40
  for (let i = 0; i < length; i++) {
@@ -62,36 +45,42 @@ function putUintDynamic(number: number) {
62
45
  return bytes;
63
46
  }
64
47
 
65
- const makeFromHeaderStructure = <Struct extends Ebml>(
66
- struct: Struct,
67
- fields: SerializeValue<Struct>,
48
+ const makeFromHeaderStructure = (
49
+ fields: PossibleEbmlOrUint8Array,
68
50
  ): Uint8Array => {
51
+ if (fields instanceof Uint8Array) {
52
+ return fields;
53
+ }
54
+
69
55
  const arrays: Uint8Array[] = [];
70
56
 
57
+ const struct = ebmlMap[getIdForName(fields.type)];
58
+
59
+ if (struct.type === 'uint8array') {
60
+ return fields.value as Uint8Array;
61
+ }
62
+
71
63
  if (struct.type === 'children') {
72
- for (const item of struct.children) {
73
- arrays.push(
74
- makeMatroskaHeader(
75
- item,
76
- // @ts-expect-error
77
- fields[item.name],
78
- ),
79
- );
64
+ for (const item of fields.value as PossibleEbml[]) {
65
+ arrays.push(makeMatroskaBytes(item));
80
66
  }
81
67
 
82
68
  return combineUint8Arrays(arrays);
83
69
  }
84
70
 
85
71
  if (struct.type === 'string') {
86
- return new TextEncoder().encode(fields as string);
72
+ return new TextEncoder().encode(fields.value as string);
87
73
  }
88
74
 
89
75
  if (struct.type === 'uint') {
90
- return putUintDynamic(fields as number);
76
+ return putUintDynamic(
77
+ (fields.value as UintWithSize).value,
78
+ (fields.value as UintWithSize).byteLength,
79
+ );
91
80
  }
92
81
 
93
82
  if (struct.type === 'hex-string') {
94
- const hex = (fields as string).substring(2);
83
+ const hex = (fields.value as string).substring(2);
95
84
  const arr = new Uint8Array(hex.length / 2);
96
85
  for (let i = 0; i < hex.length; i += 2) {
97
86
  const byte = parseInt(hex.substring(i, i + 2), 16);
@@ -101,27 +90,45 @@ const makeFromHeaderStructure = <Struct extends Ebml>(
101
90
  return arr;
102
91
  }
103
92
 
104
- if (struct.type === 'void') {
105
- throw new Error('Serializing Void is not implemented');
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);
106
104
  }
107
105
 
108
106
  throw new Error('Unexpected type');
109
107
  };
110
108
 
111
- export const makeMatroskaHeader = <Struct extends Ebml>(
112
- struct: Struct,
113
- fields: SerializeValue<Struct>,
114
- ) => {
115
- const value = makeFromHeaderStructure(struct, fields);
109
+ export const makeMatroskaBytes = (fields: PossibleEbmlOrUint8Array) => {
110
+ if (fields instanceof Uint8Array) {
111
+ return fields;
112
+ }
113
+
114
+ const value = makeFromHeaderStructure(fields);
116
115
 
117
116
  return combineUint8Arrays([
118
- matroskaToHex(getIdForName(struct.name)),
119
- getVariableInt(value.length),
117
+ matroskaToHex(getIdForName(fields.type)),
118
+ getVariableInt(value.length, fields.minVintWidth),
120
119
  value,
121
120
  ]);
122
121
  };
123
122
 
124
- const combineUint8Arrays = (arrays: Uint8Array[]) => {
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
+
125
132
  let totalLength = 0;
126
133
  for (const array of arrays) {
127
134
  totalLength += array.length;