@remotion/media-parser 4.0.202 → 4.0.205

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 (106) 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/esds/decoder-specific-config.js +6 -1
  4. package/dist/boxes/iso-base-media/ftype.d.ts +9 -0
  5. package/dist/boxes/iso-base-media/ftype.js +31 -0
  6. package/dist/boxes/iso-base-media/get-sample-positions-from-track.d.ts +4 -0
  7. package/dist/boxes/iso-base-media/get-sample-positions-from-track.js +48 -0
  8. package/dist/boxes/iso-base-media/make-track.js +3 -30
  9. package/dist/boxes/iso-base-media/mdat/mdat.js +25 -22
  10. package/dist/boxes/iso-base-media/mdhd.d.ts +2 -0
  11. package/dist/boxes/iso-base-media/mdhd.js +6 -7
  12. package/dist/boxes/iso-base-media/mvhd.js +11 -13
  13. package/dist/boxes/iso-base-media/process-box.js +36 -0
  14. package/dist/boxes/iso-base-media/tfdt.d.ts +12 -0
  15. package/dist/boxes/iso-base-media/tfdt.js +20 -0
  16. package/dist/boxes/iso-base-media/tfhd.d.ts +16 -0
  17. package/dist/boxes/iso-base-media/tfhd.js +41 -0
  18. package/dist/boxes/iso-base-media/tkhd.js +9 -12
  19. package/dist/boxes/iso-base-media/trun.d.ts +21 -0
  20. package/dist/boxes/iso-base-media/trun.js +44 -0
  21. package/dist/boxes/webm/bitstream/av1.js +1 -10
  22. package/dist/boxes/webm/ebml.d.ts +1 -1
  23. package/dist/boxes/webm/get-track.js +2 -2
  24. package/dist/boxes/webm/segments/seek-position.js +1 -1
  25. package/dist/boxes/webm/segments/seek.d.ts +1 -1
  26. package/dist/boxes/webm/segments/seek.js +8 -2
  27. package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
  28. package/dist/boxes/webm/tracks.d.ts +8 -0
  29. package/dist/boxes/webm/tracks.js +21 -0
  30. package/dist/buffer-iterator.d.ts +1 -0
  31. package/dist/buffer-iterator.js +3 -2
  32. package/dist/create/cluster-segment.d.ts +10 -0
  33. package/dist/create/cluster-segment.js +41 -0
  34. package/dist/create/create-media.d.ts +6 -1
  35. package/dist/create/create-media.js +58 -4
  36. package/dist/create/matroska-header.d.ts +1 -1
  37. package/dist/create/matroska-info.d.ts +1 -1
  38. package/dist/create/matroska-info.js +2 -2
  39. package/dist/create/matroska-segment.d.ts +2 -1
  40. package/dist/create/matroska-trackentry.d.ts +5 -4
  41. package/dist/from-web.js +6 -15
  42. package/dist/get-duration.d.ts +3 -2
  43. package/dist/get-duration.js +24 -4
  44. package/dist/get-tracks.d.ts +4 -4
  45. package/dist/get-video-metadata.d.ts +2 -0
  46. package/dist/get-video-metadata.js +44 -0
  47. package/dist/has-all-info.js +1 -1
  48. package/dist/parse-media.js +1 -1
  49. package/dist/parse-result.d.ts +4 -1
  50. package/dist/read-and-increment-offset.d.ts +28 -0
  51. package/dist/read-and-increment-offset.js +177 -0
  52. package/dist/samples-from-moof.d.ts +6 -0
  53. package/dist/samples-from-moof.js +75 -0
  54. package/dist/traversal.d.ts +8 -1
  55. package/dist/traversal.js +39 -1
  56. package/dist/understand-vorbis.d.ts +1 -0
  57. package/dist/understand-vorbis.js +12 -0
  58. package/dist/writers/web-fs.js +21 -5
  59. package/dist/writers/writer.d.ts +3 -1
  60. package/package.json +2 -2
  61. package/src/boxes/iso-base-media/esds/decoder-specific-config.ts +8 -1
  62. package/src/boxes/iso-base-media/get-sample-positions-from-track.ts +69 -0
  63. package/src/boxes/iso-base-media/make-track.ts +4 -45
  64. package/src/boxes/iso-base-media/mdat/mdat.ts +33 -24
  65. package/src/boxes/iso-base-media/mdhd.ts +10 -7
  66. package/src/boxes/iso-base-media/mvhd.ts +15 -14
  67. package/src/boxes/iso-base-media/process-box.ts +42 -0
  68. package/src/boxes/iso-base-media/tfdt.ts +37 -0
  69. package/src/boxes/iso-base-media/tfhd.ts +66 -0
  70. package/src/boxes/iso-base-media/tkhd.ts +11 -13
  71. package/src/boxes/iso-base-media/trun.ts +74 -0
  72. package/src/boxes/webm/get-track.ts +2 -2
  73. package/src/buffer-iterator.ts +3 -2
  74. package/src/get-duration.ts +40 -5
  75. package/src/get-tracks.ts +4 -4
  76. package/src/has-all-info.ts +1 -1
  77. package/src/parse-media.ts +1 -1
  78. package/src/parse-result.ts +7 -1
  79. package/src/samples-from-moof.ts +102 -0
  80. package/src/test/samples-from-moof.test.ts +2496 -0
  81. package/src/test/stream-local.test.ts +28 -30
  82. package/src/test/stream-samples.test.ts +153 -231
  83. package/src/traversal.ts +56 -1
  84. package/tsconfig.tsbuildinfo +1 -1
  85. package/dist/bitstream/av1.d.ts +0 -2
  86. package/dist/bitstream/av1.js +0 -12
  87. package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +0 -20
  88. package/dist/boxes/iso-base-media/avcc-hvcc.js +0 -73
  89. package/dist/boxes/iso-base-media/avcc.d.ts +0 -18
  90. package/dist/boxes/iso-base-media/avcc.js +0 -27
  91. package/dist/boxes/iso-base-media/esds-descriptors.d.ts +0 -21
  92. package/dist/boxes/iso-base-media/esds-descriptors.js +0 -62
  93. package/dist/boxes/iso-base-media/esds.d.ts +0 -15
  94. package/dist/boxes/iso-base-media/esds.js +0 -27
  95. package/dist/create-media.d.ts +0 -1
  96. package/dist/create-media.js +0 -78
  97. package/dist/from-input-type-file.d.ts +0 -2
  98. package/dist/from-input-type-file.js +0 -37
  99. package/dist/get-codec.d.ts +0 -4
  100. package/dist/get-codec.js +0 -22
  101. package/dist/web-file.d.ts +0 -2
  102. package/dist/web-file.js +0 -37
  103. /package/dist/{get-samples.d.ts → boxes/webm/bitstream/av1/frame.d.ts} +0 -0
  104. /package/dist/{get-samples.js → boxes/webm/bitstream/av1/frame.js} +0 -0
  105. /package/dist/{sample-aspect-ratio.d.ts → boxes/webm/bitstream/h264/get-h264-descriptor.d.ts} +0 -0
  106. /package/dist/{sample-aspect-ratio.js → boxes/webm/bitstream/h264/get-h264-descriptor.js} +0 -0
@@ -138,7 +138,6 @@ test('Should stream AV1', async () => {
138
138
  denominator: 1,
139
139
  numerator: 1,
140
140
  },
141
- samplePositions: [],
142
141
  timescale: 1000000,
143
142
  trackId: 1,
144
143
  codedHeight: 1080,
@@ -148,6 +147,7 @@ test('Should stream AV1', async () => {
148
147
  displayAspectHeight: 1080,
149
148
  displayAspectWidth: 1920,
150
149
  rotation: 0,
150
+ trakBox: null,
151
151
  });
152
152
  expect(parsed.audioTracks.length).toBe(0);
153
153
  expect(videoTracks).toBe(1);
@@ -263,12 +263,12 @@ test('Should stream variable fps video', async () => {
263
263
  boxes: true,
264
264
  },
265
265
  reader: nodeReader,
266
- onAudioTrack: (track) => {
267
- expect(track.type).toBe('audio');
268
- expect(track.trackId).toBe(1);
269
- expect(track.codec).toBe('opus');
270
- expect(track.numberOfChannels).toBe(1);
271
- expect(track.sampleRate).toBe(48000);
266
+ onAudioTrack: (track_) => {
267
+ expect(track_.type).toBe('audio');
268
+ expect(track_.trackId).toBe(1);
269
+ expect(track_.codec).toBe('opus');
270
+ expect(track_.numberOfChannels).toBe(1);
271
+ expect(track_.sampleRate).toBe(48000);
272
272
  audioTracks++;
273
273
  return () => {
274
274
  samples++;
@@ -293,7 +293,6 @@ test('Should stream variable fps video', async () => {
293
293
  denominator: 1,
294
294
  numerator: 1,
295
295
  },
296
- samplePositions: [],
297
296
  timescale: 1000000,
298
297
  trackId: 2,
299
298
  codedHeight: 720,
@@ -303,17 +302,18 @@ test('Should stream variable fps video', async () => {
303
302
  displayAspectHeight: 720,
304
303
  displayAspectWidth: 1280,
305
304
  rotation: 0,
305
+ trakBox: null,
306
306
  });
307
307
  expect(parsed.audioTracks.length).toBe(1);
308
308
  expect(parsed.audioTracks[0]).toEqual({
309
309
  type: 'audio',
310
310
  codec: 'opus',
311
- samplePositions: null,
312
311
  timescale: 1000000,
313
312
  trackId: 1,
314
313
  numberOfChannels: 1,
315
314
  sampleRate: 48000,
316
315
  description: undefined,
316
+ trakBox: null,
317
317
  });
318
318
  expect(audioTracks).toBe(1);
319
319
  expect(samples).toBe(381);
@@ -574,27 +574,25 @@ test('Stretched VP8', async () => {
574
574
  reader: nodeReader,
575
575
  });
576
576
 
577
- expect(videoTracks).toEqual([
578
- {
579
- codec: 'vp8',
580
- codedHeight: 1080,
581
- codedWidth: 1440,
582
- description: undefined,
583
- height: 1080,
584
- sampleAspectRatio: {
585
- denominator: 1,
586
- numerator: 1,
587
- },
588
- samplePositions: [],
589
- timescale: 1000000,
590
- trackId: 1,
591
- type: 'video',
592
- width: 1920,
593
- displayAspectHeight: 1080,
594
- displayAspectWidth: 1920,
595
- rotation: 0,
596
- },
597
- ]);
577
+ const {trakBox, ...track} = videoTracks[0];
578
+ expect(track).toEqual({
579
+ codec: 'vp8',
580
+ codedHeight: 1080,
581
+ codedWidth: 1440,
582
+ description: undefined,
583
+ height: 1080,
584
+ sampleAspectRatio: {
585
+ denominator: 1,
586
+ numerator: 1,
587
+ },
588
+ timescale: 1000000,
589
+ trackId: 1,
590
+ type: 'video',
591
+ width: 1920,
592
+ displayAspectHeight: 1080,
593
+ displayAspectWidth: 1920,
594
+ rotation: 0,
595
+ });
598
596
  });
599
597
 
600
598
  test('HEVC and AAC in Matroska', async () => {
@@ -1,5 +1,7 @@
1
1
  import {RenderInternals} from '@remotion/renderer';
2
2
  import {expect, test} from 'bun:test';
3
+ import {getSamplePositionsFromTrack} from '../boxes/iso-base-media/get-sample-positions-from-track';
4
+ import type {TrakBox} from '../boxes/iso-base-media/trak/trak';
3
5
  import {nodeReader} from '../from-node';
4
6
  import {parseMedia} from '../parse-media';
5
7
 
@@ -20,240 +22,160 @@ test('Stream samples', async () => {
20
22
  140, 176, 1, 0, 6, 104, 235, 224, 140, 178, 44, 253, 248, 248, 0,
21
23
  ]);
22
24
 
23
- expect(videoTracks).toEqual([
24
- {
25
- type: 'video',
26
- trackId: 1,
27
- samplePositions: [
28
- {
29
- offset: 1637,
30
- size: 4834,
31
- isKeyframe: true,
32
- dts: 0,
33
- duration: 512,
34
- cts: 1024,
35
- },
36
- {
37
- offset: 6471,
38
- size: 437,
39
- isKeyframe: false,
40
- dts: 512,
41
- duration: 512,
42
- cts: 1536,
43
- },
44
- {
45
- offset: 7868,
46
- size: 698,
47
- isKeyframe: false,
48
- dts: 1024,
49
- duration: 512,
50
- cts: 2048,
51
- },
52
- {
53
- offset: 10486,
54
- size: 595,
55
- isKeyframe: false,
56
- dts: 1536,
57
- duration: 512,
58
- cts: 2560,
59
- },
60
- {
61
- offset: 12041,
62
- size: 548,
63
- isKeyframe: false,
64
- dts: 2048,
65
- duration: 512,
66
- cts: 3072,
67
- },
68
- {
69
- offset: 14509,
70
- size: 611,
71
- isKeyframe: false,
72
- dts: 2560,
73
- duration: 512,
74
- cts: 3584,
75
- },
76
- {
77
- offset: 16080,
78
- size: 701,
79
- isKeyframe: false,
80
- dts: 3072,
81
- duration: 512,
82
- cts: 4096,
83
- },
84
- {
85
- offset: 17741,
86
- size: 535,
87
- isKeyframe: false,
88
- dts: 3584,
89
- duration: 512,
90
- cts: 4608,
91
- },
92
- {
93
- offset: 20196,
94
- size: 776,
95
- isKeyframe: false,
96
- dts: 4096,
97
- duration: 512,
98
- cts: 5120,
99
- },
100
- {
101
- offset: 21932,
102
- size: 586,
103
- isKeyframe: false,
104
- dts: 4608,
105
- duration: 512,
106
- cts: 5632,
107
- },
108
- ],
109
- description,
110
- timescale: 15360,
111
- codec: 'avc1.640020',
112
- sampleAspectRatio: {
113
- numerator: 1,
114
- denominator: 1,
115
- },
116
- width: 1080,
117
- height: 1080,
118
- codedWidth: 1080,
119
- codedHeight: 1080,
120
- displayAspectHeight: 1080,
121
- displayAspectWidth: 1080,
122
- rotation: 0,
25
+ const {trakBox, ...trackInfo} = videoTracks[0];
26
+ expect(trackInfo).toEqual({
27
+ type: 'video',
28
+ trackId: 1,
29
+ description,
30
+ timescale: 15360,
31
+ codec: 'avc1.640020',
32
+ sampleAspectRatio: {
33
+ numerator: 1,
34
+ denominator: 1,
123
35
  },
124
- ]);
36
+ width: 1080,
37
+ height: 1080,
38
+ codedWidth: 1080,
39
+ codedHeight: 1080,
40
+ displayAspectHeight: 1080,
41
+ displayAspectWidth: 1080,
42
+ rotation: 0,
43
+ });
44
+
45
+ expect(getSamplePositionsFromTrack(trakBox as TrakBox, null));
46
+
47
+ const [firstAudioTrack] = audioTracks;
48
+ const {trakBox: trakBox2, ...audioTrack} = firstAudioTrack;
125
49
 
126
- expect(audioTracks).toEqual([
50
+ expect(audioTrack).toEqual({
51
+ type: 'audio',
52
+ trackId: 2,
53
+ timescale: 48000,
54
+ numberOfChannels: 2,
55
+ codec: 'mp3',
56
+ sampleRate: 48000,
57
+ description: undefined,
58
+ });
59
+ expect(getSamplePositionsFromTrack(trakBox2 as TrakBox, null)).toEqual([
60
+ {
61
+ offset: 6908,
62
+ size: 960,
63
+ isKeyframe: true,
64
+ dts: 0,
65
+ duration: 1152,
66
+ cts: 0,
67
+ },
68
+ {
69
+ offset: 8566,
70
+ size: 960,
71
+ isKeyframe: true,
72
+ dts: 1152,
73
+ duration: 1152,
74
+ cts: 1152,
75
+ },
76
+ {
77
+ offset: 9526,
78
+ size: 960,
79
+ isKeyframe: true,
80
+ dts: 2304,
81
+ duration: 1152,
82
+ cts: 2304,
83
+ },
84
+ {
85
+ offset: 11081,
86
+ size: 960,
87
+ isKeyframe: true,
88
+ dts: 3456,
89
+ duration: 1152,
90
+ cts: 3456,
91
+ },
92
+ {
93
+ offset: 12589,
94
+ size: 960,
95
+ isKeyframe: true,
96
+ dts: 4608,
97
+ duration: 1152,
98
+ cts: 4608,
99
+ },
100
+ {
101
+ offset: 13549,
102
+ size: 960,
103
+ isKeyframe: true,
104
+ dts: 5760,
105
+ duration: 1152,
106
+ cts: 5760,
107
+ },
108
+ {
109
+ offset: 15120,
110
+ size: 960,
111
+ isKeyframe: true,
112
+ dts: 6912,
113
+ duration: 1152,
114
+ cts: 6912,
115
+ },
116
+ {
117
+ offset: 16781,
118
+ size: 960,
119
+ isKeyframe: true,
120
+ dts: 8064,
121
+ duration: 1152,
122
+ cts: 8064,
123
+ },
124
+ {
125
+ offset: 18276,
126
+ size: 960,
127
+ isKeyframe: true,
128
+ dts: 9216,
129
+ duration: 1152,
130
+ cts: 9216,
131
+ },
132
+ {
133
+ offset: 19236,
134
+ size: 960,
135
+ isKeyframe: true,
136
+ dts: 10368,
137
+ duration: 1152,
138
+ cts: 10368,
139
+ },
140
+ {
141
+ offset: 20972,
142
+ size: 960,
143
+ isKeyframe: true,
144
+ dts: 11520,
145
+ duration: 1152,
146
+ cts: 11520,
147
+ },
148
+ {
149
+ offset: 22518,
150
+ size: 960,
151
+ isKeyframe: true,
152
+ dts: 12672,
153
+ duration: 1152,
154
+ cts: 12672,
155
+ },
156
+ {
157
+ offset: 23478,
158
+ size: 960,
159
+ isKeyframe: true,
160
+ dts: 13824,
161
+ duration: 1152,
162
+ cts: 13824,
163
+ },
164
+ {
165
+ offset: 24438,
166
+ size: 960,
167
+ isKeyframe: true,
168
+ dts: 14976,
169
+ duration: 1152,
170
+ cts: 14976,
171
+ },
127
172
  {
128
- type: 'audio',
129
- trackId: 2,
130
- samplePositions: [
131
- {
132
- offset: 6908,
133
- size: 960,
134
- isKeyframe: true,
135
- dts: 0,
136
- duration: 1152,
137
- cts: 0,
138
- },
139
- {
140
- offset: 8566,
141
- size: 960,
142
- isKeyframe: true,
143
- dts: 1152,
144
- duration: 1152,
145
- cts: 1152,
146
- },
147
- {
148
- offset: 9526,
149
- size: 960,
150
- isKeyframe: true,
151
- dts: 2304,
152
- duration: 1152,
153
- cts: 2304,
154
- },
155
- {
156
- offset: 11081,
157
- size: 960,
158
- isKeyframe: true,
159
- dts: 3456,
160
- duration: 1152,
161
- cts: 3456,
162
- },
163
- {
164
- offset: 12589,
165
- size: 960,
166
- isKeyframe: true,
167
- dts: 4608,
168
- duration: 1152,
169
- cts: 4608,
170
- },
171
- {
172
- offset: 13549,
173
- size: 960,
174
- isKeyframe: true,
175
- dts: 5760,
176
- duration: 1152,
177
- cts: 5760,
178
- },
179
- {
180
- offset: 15120,
181
- size: 960,
182
- isKeyframe: true,
183
- dts: 6912,
184
- duration: 1152,
185
- cts: 6912,
186
- },
187
- {
188
- offset: 16781,
189
- size: 960,
190
- isKeyframe: true,
191
- dts: 8064,
192
- duration: 1152,
193
- cts: 8064,
194
- },
195
- {
196
- offset: 18276,
197
- size: 960,
198
- isKeyframe: true,
199
- dts: 9216,
200
- duration: 1152,
201
- cts: 9216,
202
- },
203
- {
204
- offset: 19236,
205
- size: 960,
206
- isKeyframe: true,
207
- dts: 10368,
208
- duration: 1152,
209
- cts: 10368,
210
- },
211
- {
212
- offset: 20972,
213
- size: 960,
214
- isKeyframe: true,
215
- dts: 11520,
216
- duration: 1152,
217
- cts: 11520,
218
- },
219
- {
220
- offset: 22518,
221
- size: 960,
222
- isKeyframe: true,
223
- dts: 12672,
224
- duration: 1152,
225
- cts: 12672,
226
- },
227
- {
228
- offset: 23478,
229
- size: 960,
230
- isKeyframe: true,
231
- dts: 13824,
232
- duration: 1152,
233
- cts: 13824,
234
- },
235
- {
236
- offset: 24438,
237
- size: 960,
238
- isKeyframe: true,
239
- dts: 14976,
240
- duration: 1152,
241
- cts: 14976,
242
- },
243
- {
244
- offset: 25398,
245
- size: 960,
246
- isKeyframe: true,
247
- dts: 16128,
248
- duration: 1152,
249
- cts: 16128,
250
- },
251
- ],
252
- timescale: 48000,
253
- numberOfChannels: 2,
254
- codec: 'mp3',
255
- sampleRate: 48000,
256
- description: undefined,
173
+ offset: 25398,
174
+ size: 960,
175
+ isKeyframe: true,
176
+ dts: 16128,
177
+ duration: 1152,
178
+ cts: 16128,
257
179
  },
258
180
  ]);
259
181
  });
package/src/traversal.ts CHANGED
@@ -9,8 +9,11 @@ import type {StsdBox} from './boxes/iso-base-media/stsd/stsd';
9
9
  import type {StssBox} from './boxes/iso-base-media/stsd/stss';
10
10
  import type {StszBox} from './boxes/iso-base-media/stsd/stsz';
11
11
  import type {SttsBox} from './boxes/iso-base-media/stsd/stts';
12
+ import type {TfdtBox} from './boxes/iso-base-media/tfdt';
13
+ import type {TfhdBox} from './boxes/iso-base-media/tfhd';
12
14
  import type {TkhdBox} from './boxes/iso-base-media/tkhd';
13
15
  import type {TrakBox} from './boxes/iso-base-media/trak/trak';
16
+ import type {TrunBox} from './boxes/iso-base-media/trun';
14
17
  import type {
15
18
  AudioSegment,
16
19
  ClusterSegment,
@@ -25,7 +28,7 @@ import type {
25
28
  VideoSegment,
26
29
  WidthSegment,
27
30
  } from './boxes/webm/segments/all-segments';
28
- import type {AnySegment, RegularBox} from './parse-result';
31
+ import type {AnySegment, IsoBaseMediaBox, RegularBox} from './parse-result';
29
32
 
30
33
  export const getFtypBox = (segments: AnySegment[]): FtypBox | null => {
31
34
  const ftypBox = segments.find((s) => s.type === 'ftyp-box');
@@ -45,6 +48,18 @@ export const getMoovBox = (segments: AnySegment[]): MoovBox | null => {
45
48
  return moovBox;
46
49
  };
47
50
 
51
+ export const getMoofBox = (main: AnySegment[]): IsoBaseMediaBox | null => {
52
+ const moofBox = main.find(
53
+ (s) => s.type === 'regular-box' && s.boxType === 'moof',
54
+ );
55
+
56
+ if (!moofBox || moofBox.type !== 'regular-box') {
57
+ return null;
58
+ }
59
+
60
+ return moofBox;
61
+ };
62
+
48
63
  export const getMvhdBox = (moovBox: MoovBox): MvhdBox | null => {
49
64
  const mvHdBox = moovBox.children.find((s) => s.type === 'mvhd-box');
50
65
 
@@ -239,6 +254,46 @@ export const getStssBox = (trakBox: TrakBox): StssBox | null => {
239
254
  return stssBox;
240
255
  };
241
256
 
257
+ export const getTfdtBox = (segment: IsoBaseMediaBox): TfdtBox | null => {
258
+ if (segment.type !== 'regular-box' || segment.boxType !== 'traf') {
259
+ throw new Error('Expected traf-box');
260
+ }
261
+
262
+ const tfhdBox = segment.children.find((c) => c.type === 'tfdt-box');
263
+
264
+ if (!tfhdBox || tfhdBox.type !== 'tfdt-box') {
265
+ throw new Error('Expected tfhd-box');
266
+ }
267
+
268
+ return tfhdBox;
269
+ };
270
+
271
+ export const getTfhdBox = (segment: IsoBaseMediaBox): TfhdBox | null => {
272
+ if (segment.type !== 'regular-box' || segment.boxType !== 'traf') {
273
+ throw new Error('Expected traf-box');
274
+ }
275
+
276
+ const tfhdBox = segment.children.find(
277
+ (c) => c.type === 'tfhd-box',
278
+ ) as TfhdBox;
279
+
280
+ if (!tfhdBox || tfhdBox.type !== 'tfhd-box') {
281
+ throw new Error('Expected tfhd-box');
282
+ }
283
+
284
+ return tfhdBox;
285
+ };
286
+
287
+ export const getTrunBoxes = (segment: IsoBaseMediaBox): TrunBox[] => {
288
+ if (segment.type !== 'regular-box' || segment.boxType !== 'traf') {
289
+ throw new Error('Expected traf-box');
290
+ }
291
+
292
+ const trunBoxes = segment.children.filter((c) => c.type === 'trun-box');
293
+
294
+ return trunBoxes as TrunBox[];
295
+ };
296
+
242
297
  export const getClusterSegment = (
243
298
  segment: MainSegment,
244
299
  ): ClusterSegment | null => {