@remotion/media-parser 4.0.204 → 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 (50) hide show
  1. package/dist/boxes/iso-base-media/esds/decoder-specific-config.js +6 -1
  2. package/dist/boxes/iso-base-media/make-track.js +3 -30
  3. package/dist/boxes/iso-base-media/mdat/mdat.js +25 -22
  4. package/dist/boxes/iso-base-media/mdhd.d.ts +2 -0
  5. package/dist/boxes/iso-base-media/mdhd.js +6 -7
  6. package/dist/boxes/iso-base-media/mvhd.js +11 -13
  7. package/dist/boxes/iso-base-media/process-box.js +36 -0
  8. package/dist/boxes/iso-base-media/tkhd.js +9 -12
  9. package/dist/boxes/webm/ebml.d.ts +1 -1
  10. package/dist/boxes/webm/get-track.js +2 -2
  11. package/dist/buffer-iterator.d.ts +1 -0
  12. package/dist/buffer-iterator.js +3 -2
  13. package/dist/create/cluster-segment.d.ts +10 -0
  14. package/dist/create/cluster-segment.js +41 -0
  15. package/dist/create/create-media.d.ts +7 -0
  16. package/dist/create/create-media.js +90 -0
  17. package/dist/create/matroska-header.d.ts +1 -0
  18. package/dist/create/matroska-header.js +66 -0
  19. package/dist/create/matroska-info.d.ts +4 -0
  20. package/dist/create/matroska-info.js +39 -0
  21. package/dist/create/matroska-segment.d.ts +2 -0
  22. package/dist/create/matroska-segment.js +12 -0
  23. package/dist/create/matroska-trackentry.d.ts +22 -0
  24. package/dist/create/matroska-trackentry.js +191 -0
  25. package/dist/get-duration.d.ts +3 -2
  26. package/dist/get-duration.js +24 -4
  27. package/dist/get-tracks.d.ts +4 -4
  28. package/dist/has-all-info.js +1 -1
  29. package/dist/parse-media.js +1 -1
  30. package/dist/parse-result.d.ts +4 -1
  31. package/dist/readers/from-fetch.d.ts +2 -0
  32. package/dist/readers/from-fetch.js +64 -0
  33. package/dist/readers/from-node.d.ts +2 -0
  34. package/dist/readers/from-node.js +40 -0
  35. package/dist/readers/from-web-file.d.ts +2 -0
  36. package/dist/readers/from-web-file.js +39 -0
  37. package/dist/readers/reader.d.ts +11 -0
  38. package/dist/readers/reader.js +2 -0
  39. package/dist/samples-from-moof.js +2 -1
  40. package/dist/traversal.d.ts +8 -1
  41. package/dist/traversal.js +39 -1
  42. package/dist/writers/web-fs.d.ts +2 -0
  43. package/dist/writers/web-fs.js +44 -0
  44. package/dist/writers/writer.d.ts +11 -0
  45. package/dist/writers/writer.js +2 -0
  46. package/package.json +2 -2
  47. package/src/boxes/iso-base-media/esds/decoder-specific-config.ts +8 -1
  48. package/src/samples-from-moof.ts +2 -1
  49. package/src/test/samples-from-moof.test.ts +3 -3
  50. package/tsconfig.tsbuildinfo +1 -1
@@ -27,12 +27,17 @@ const parseDecoderSpecificConfig = (iterator) => {
27
27
  if (read < layerSize) {
28
28
  iterator.discard(layerSize - read);
29
29
  }
30
+ // Working around Chrome bug
31
+ // https://issues.chromium.org/issues/360083330#comment5
32
+ const patchedAsBytes = bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136
33
+ ? new Uint8Array([17, 144])
34
+ : bytes;
30
35
  return {
31
36
  type: 'audio-specific-config',
32
37
  audioObjectType,
33
38
  samplingFrequencyIndex,
34
39
  channelConfiguration,
35
- asBytes: bytes,
40
+ asBytes: patchedAsBytes,
36
41
  };
37
42
  };
38
43
  exports.parseDecoderSpecificConfig = parseDecoderSpecificConfig;
@@ -4,45 +4,18 @@ exports.makeBaseMediaTrack = void 0;
4
4
  const get_audio_codec_1 = require("../../get-audio-codec");
5
5
  const get_fps_1 = require("../../get-fps");
6
6
  const get_sample_aspect_ratio_1 = require("../../get-sample-aspect-ratio");
7
- const get_sample_positions_1 = require("../../get-sample-positions");
8
7
  const get_video_codec_1 = require("../../get-video-codec");
9
8
  const traversal_1 = require("../../traversal");
10
9
  const makeBaseMediaTrack = (trakBox) => {
11
- const stszBox = (0, traversal_1.getStszBox)(trakBox);
12
- const stcoBox = (0, traversal_1.getStcoBox)(trakBox);
13
- const stscBox = (0, traversal_1.getStscBox)(trakBox);
14
- const stssBox = (0, traversal_1.getStssBox)(trakBox);
15
- const sttsBox = (0, traversal_1.getSttsBox)(trakBox);
16
10
  const tkhdBox = (0, traversal_1.getTkhdBox)(trakBox);
17
- const cttsBox = (0, traversal_1.getCttsBox)(trakBox);
18
11
  const videoDescriptors = (0, traversal_1.getVideoDescriptors)(trakBox);
19
12
  const timescaleAndDuration = (0, get_fps_1.getTimescaleAndDuration)(trakBox);
20
13
  if (!tkhdBox) {
21
14
  throw new Error('Expected tkhd box in trak box');
22
15
  }
23
- if (!stszBox) {
24
- throw new Error('Expected stsz box in trak box');
25
- }
26
- if (!stcoBox) {
27
- throw new Error('Expected stco box in trak box');
28
- }
29
- if (!stscBox) {
30
- throw new Error('Expected stsc box in trak box');
31
- }
32
- if (!sttsBox) {
33
- throw new Error('Expected stts box in trak box');
34
- }
35
16
  if (!timescaleAndDuration) {
36
17
  throw new Error('Expected timescale and duration in trak box');
37
18
  }
38
- const samplePositions = (0, get_sample_positions_1.getSamplePositions)({
39
- stcoBox,
40
- stscBox,
41
- stszBox,
42
- stssBox,
43
- sttsBox,
44
- cttsBox,
45
- });
46
19
  if ((0, get_fps_1.trakBoxContainsAudio)(trakBox)) {
47
20
  const numberOfChannels = (0, get_audio_codec_1.getNumberOfChannelsFromTrak)(trakBox);
48
21
  if (numberOfChannels === null) {
@@ -55,21 +28,21 @@ const makeBaseMediaTrack = (trakBox) => {
55
28
  const { codecString, description } = (0, get_audio_codec_1.getAudioCodecStringFromTrak)(trakBox);
56
29
  return {
57
30
  type: 'audio',
58
- samplePositions,
59
31
  trackId: tkhdBox.trackId,
60
32
  timescale: timescaleAndDuration.timescale,
61
33
  codec: codecString,
62
34
  numberOfChannels,
63
35
  sampleRate,
64
36
  description,
37
+ trakBox,
65
38
  };
66
39
  }
67
40
  if (!(0, get_fps_1.trakBoxContainsVideo)(trakBox)) {
68
41
  return {
69
42
  type: 'other',
70
- samplePositions,
71
43
  trackId: tkhdBox.trackId,
72
44
  timescale: timescaleAndDuration.timescale,
45
+ trakBox,
73
46
  };
74
47
  }
75
48
  const videoSample = (0, get_sample_aspect_ratio_1.getVideoSample)(trakBox);
@@ -92,7 +65,6 @@ const makeBaseMediaTrack = (trakBox) => {
92
65
  }
93
66
  const track = {
94
67
  type: 'video',
95
- samplePositions,
96
68
  trackId: tkhdBox.trackId,
97
69
  description: videoDescriptors !== null && videoDescriptors !== void 0 ? videoDescriptors : undefined,
98
70
  timescale: timescaleAndDuration.timescale,
@@ -106,6 +78,7 @@ const makeBaseMediaTrack = (trakBox) => {
106
78
  displayAspectWidth,
107
79
  displayAspectHeight,
108
80
  rotation,
81
+ trakBox,
109
82
  };
110
83
  return track;
111
84
  };
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseMdat = void 0;
4
4
  const get_tracks_1 = require("../../../get-tracks");
5
+ const traversal_1 = require("../../../traversal");
6
+ const get_sample_positions_from_track_1 = require("../get-sample-positions-from-track");
5
7
  const parseMdat = async ({ data, size, fileOffset, existingBoxes, options, }) => {
6
8
  const alreadyHas = (0, get_tracks_1.hasTracks)(existingBoxes);
7
9
  if (!alreadyHas) {
@@ -21,12 +23,13 @@ const parseMdat = async ({ data, size, fileOffset, existingBoxes, options, }) =>
21
23
  ];
22
24
  const flatSamples = allTracks
23
25
  .map((track) => {
24
- if (!track.samplePositions) {
26
+ const samplePositions = (0, get_sample_positions_from_track_1.getSamplePositionsFromTrack)(track.trakBox, (0, traversal_1.getMoofBox)(existingBoxes));
27
+ if (!samplePositions) {
25
28
  throw new Error('No sample positions');
26
29
  }
27
- return track.samplePositions.map((samplePosition) => {
30
+ return samplePositions.map((samplePosition) => {
28
31
  return {
29
- track,
32
+ track: { ...track },
30
33
  samplePosition,
31
34
  };
32
35
  });
@@ -34,10 +37,10 @@ const parseMdat = async ({ data, size, fileOffset, existingBoxes, options, }) =>
34
37
  .flat(1);
35
38
  // eslint-disable-next-line no-constant-condition
36
39
  while (true) {
37
- const sampleWithIndex = flatSamples.find((sample) => {
40
+ const samplesWithIndex = flatSamples.find((sample) => {
38
41
  return sample.samplePosition.offset === data.counter.getOffset();
39
42
  });
40
- if (!sampleWithIndex) {
43
+ if (!samplesWithIndex) {
41
44
  // There are various reasons why in mdat we find weird stuff:
42
45
  // - iphonevideo.hevc has a fake hoov atom which is not mapped
43
46
  // - corrupted.mp4 has a corrupt table
@@ -54,31 +57,31 @@ const parseMdat = async ({ data, size, fileOffset, existingBoxes, options, }) =>
54
57
  break;
55
58
  }
56
59
  }
57
- if (data.bytesRemaining() < sampleWithIndex.samplePosition.size) {
60
+ if (data.bytesRemaining() < samplesWithIndex.samplePosition.size) {
58
61
  break;
59
62
  }
60
- const bytes = data.getSlice(sampleWithIndex.samplePosition.size);
61
- if (sampleWithIndex.track.type === 'audio') {
62
- await options.parserState.onAudioSample(sampleWithIndex.track.trackId, {
63
+ const bytes = data.getSlice(samplesWithIndex.samplePosition.size);
64
+ if (samplesWithIndex.track.type === 'audio') {
65
+ await options.parserState.onAudioSample(samplesWithIndex.track.trackId, {
63
66
  data: bytes,
64
- timestamp: sampleWithIndex.samplePosition.offset,
65
- trackId: sampleWithIndex.track.trackId,
66
- type: sampleWithIndex.samplePosition.isKeyframe ? 'key' : 'delta',
67
+ timestamp: samplesWithIndex.samplePosition.offset,
68
+ trackId: samplesWithIndex.track.trackId,
69
+ type: samplesWithIndex.samplePosition.isKeyframe ? 'key' : 'delta',
67
70
  });
68
71
  }
69
- if (sampleWithIndex.track.type === 'video') {
70
- const timestamp = (sampleWithIndex.samplePosition.cts * 1000000) /
71
- sampleWithIndex.track.timescale;
72
- const duration = (sampleWithIndex.samplePosition.duration * 1000000) /
73
- sampleWithIndex.track.timescale;
74
- await options.parserState.onVideoSample(sampleWithIndex.track.trackId, {
72
+ if (samplesWithIndex.track.type === 'video') {
73
+ const timestamp = Math.floor((samplesWithIndex.samplePosition.cts * 1000000) /
74
+ samplesWithIndex.track.timescale);
75
+ const duration = Math.floor((samplesWithIndex.samplePosition.duration * 1000000) /
76
+ samplesWithIndex.track.timescale);
77
+ await options.parserState.onVideoSample(samplesWithIndex.track.trackId, {
75
78
  data: bytes,
76
79
  timestamp,
77
80
  duration,
78
- cts: sampleWithIndex.samplePosition.cts,
79
- dts: sampleWithIndex.samplePosition.dts,
80
- trackId: sampleWithIndex.track.trackId,
81
- type: sampleWithIndex.samplePosition.isKeyframe ? 'key' : 'delta',
81
+ cts: samplesWithIndex.samplePosition.cts,
82
+ dts: samplesWithIndex.samplePosition.dts,
83
+ trackId: samplesWithIndex.track.trackId,
84
+ type: samplesWithIndex.samplePosition.isKeyframe ? 'key' : 'delta',
82
85
  });
83
86
  }
84
87
  const remaining = size - (data.counter.getOffset() - fileOffset);
@@ -6,6 +6,8 @@ export interface MdhdBox {
6
6
  duration: number;
7
7
  language: number;
8
8
  quality: number;
9
+ creationTime: number | null;
10
+ modificationTime: number | null;
9
11
  }
10
12
  export declare const parseMdhd: ({ data, size, fileOffset, }: {
11
13
  data: BufferIterator;
@@ -3,17 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseMdhd = void 0;
4
4
  const parseMdhd = ({ data, size, fileOffset, }) => {
5
5
  const version = data.getUint8();
6
- if (version !== 0) {
7
- throw new Error(`Unsupported MDHD version ${version}`);
8
- }
9
6
  // flags, we discard them
10
7
  data.discard(3);
11
8
  // creation time
12
- data.discard(4);
9
+ const creationTime = version === 1 ? Number(data.getUint64()) : data.getUint32();
13
10
  // modification time
14
- data.discard(4);
11
+ const modificationTime = version === 1 ? Number(data.getUint64()) : data.getUint32();
15
12
  const timescale = data.getUint32();
16
- const duration = data.getUint32();
13
+ const duration = version === 1 ? data.getUint64() : data.getUint32();
17
14
  const language = data.getUint16();
18
15
  // quality
19
16
  const quality = data.getUint16();
@@ -23,11 +20,13 @@ const parseMdhd = ({ data, size, fileOffset, }) => {
23
20
  }
24
21
  return {
25
22
  type: 'mdhd-box',
26
- duration,
23
+ duration: Number(duration),
27
24
  timescale,
28
25
  version,
29
26
  language,
30
27
  quality,
28
+ creationTime,
29
+ modificationTime,
31
30
  };
32
31
  };
33
32
  exports.parseMdhd = parseMdhd;
@@ -5,19 +5,13 @@ const buffer_iterator_1 = require("../../buffer-iterator");
5
5
  const to_date_1 = require("./to-date");
6
6
  const parseMvhd = ({ iterator, offset, size, }) => {
7
7
  const version = iterator.getUint8();
8
- if (version !== 0) {
9
- throw new Error(`Unsupported MVHD version ${version}`);
10
- }
11
- if (size !== 108) {
12
- throw new Error(`Expected mvhd size of version 0 to be 108, got ${size}`);
13
- }
14
8
  // Flags, we discard them
15
9
  iterator.discard(3);
16
- const creationTime = iterator.getUint32();
17
- const modificationTime = iterator.getUint32();
10
+ const creationTime = version === 1 ? iterator.getUint64() : iterator.getUint32();
11
+ const modificationTime = version === 1 ? iterator.getUint64() : iterator.getUint32();
18
12
  const timeScale = iterator.getUint32();
19
- const durationInUnits = iterator.getUint32();
20
- const durationInSeconds = durationInUnits / timeScale;
13
+ const durationInUnits = version === 1 ? iterator.getUint64() : iterator.getUint32();
14
+ const durationInSeconds = Number(durationInUnits) / timeScale;
21
15
  const rateArray = iterator.getSlice(4);
22
16
  const rateView = (0, buffer_iterator_1.getArrayBufferIterator)(rateArray, rateArray.length);
23
17
  const rate = rateView.getInt8() * 10 +
@@ -47,11 +41,15 @@ const parseMvhd = ({ iterator, offset, size, }) => {
47
41
  // next track id
48
42
  const nextTrackId = iterator.getUint32();
49
43
  volumeView.destroy();
44
+ const bytesRemaining = size - (iterator.counter.getOffset() - offset);
45
+ if (bytesRemaining !== 0) {
46
+ throw new Error('expected 0 bytes ' + bytesRemaining);
47
+ }
50
48
  return {
51
- creationTime: (0, to_date_1.toUnixTimestamp)(creationTime),
52
- modificationTime: (0, to_date_1.toUnixTimestamp)(modificationTime),
49
+ creationTime: (0, to_date_1.toUnixTimestamp)(Number(creationTime)),
50
+ modificationTime: (0, to_date_1.toUnixTimestamp)(Number(modificationTime)),
53
51
  timeScale,
54
- durationInUnits,
52
+ durationInUnits: Number(durationInUnits),
55
53
  durationInSeconds,
56
54
  rate,
57
55
  volume,
@@ -23,14 +23,19 @@ const stsd_1 = require("./stsd/stsd");
23
23
  const stss_1 = require("./stsd/stss");
24
24
  const stsz_1 = require("./stsd/stsz");
25
25
  const stts_1 = require("./stsd/stts");
26
+ const tfdt_1 = require("./tfdt");
27
+ const tfhd_1 = require("./tfhd");
26
28
  const tkhd_1 = require("./tkhd");
27
29
  const trak_1 = require("./trak/trak");
30
+ const trun_1 = require("./trun");
28
31
  const getChildren = async ({ boxType, iterator, bytesRemainingInBox, options, littleEndian, }) => {
29
32
  const parseChildren = boxType === 'mdia' ||
30
33
  boxType === 'minf' ||
31
34
  boxType === 'stbl' ||
35
+ boxType === 'moof' ||
32
36
  boxType === 'dims' ||
33
37
  boxType === 'wave' ||
38
+ boxType === 'traf' ||
34
39
  boxType === 'stsb';
35
40
  if (parseChildren) {
36
41
  const parsed = await (0, exports.parseBoxes)({
@@ -183,6 +188,24 @@ const processBox = async ({ iterator, allowIncompleteBoxes, parsedBoxes, options
183
188
  skipTo: null,
184
189
  };
185
190
  }
191
+ if (boxType === 'trun') {
192
+ const box = (0, trun_1.parseTrun)({ iterator, offset: fileOffset, size: boxSize });
193
+ return {
194
+ type: 'complete',
195
+ box,
196
+ size: boxSize,
197
+ skipTo: null,
198
+ };
199
+ }
200
+ if (boxType === 'tfdt') {
201
+ const box = (0, tfdt_1.parseTfdt)({ iterator, size: boxSize, offset: fileOffset });
202
+ return {
203
+ type: 'complete',
204
+ box,
205
+ size: boxSize,
206
+ skipTo: null,
207
+ };
208
+ }
186
209
  if (boxType === 'stsd') {
187
210
  const box = await (0, stsd_1.parseStsd)({
188
211
  iterator,
@@ -380,6 +403,19 @@ const processBox = async ({ iterator, allowIncompleteBoxes, parsedBoxes, options
380
403
  skipTo: null,
381
404
  };
382
405
  }
406
+ if (boxType === 'tfhd') {
407
+ const box = (0, tfhd_1.getTfhd)({
408
+ iterator,
409
+ offset: fileOffset,
410
+ size: boxSize,
411
+ });
412
+ return {
413
+ type: 'complete',
414
+ box,
415
+ size: boxSize,
416
+ skipTo: null,
417
+ };
418
+ }
383
419
  if (boxType === 'mdhd') {
384
420
  const box = (0, mdhd_1.parseMdhd)({
385
421
  data: iterator,
@@ -5,6 +5,9 @@ const to_date_1 = require("./to-date");
5
5
  function getRotationAngleFromMatrix(matrix) {
6
6
  // Extract elements from the matrix
7
7
  const [a, b, c, d] = matrix;
8
+ if (a === 0 && b === 0 && c === 0 && d === 0) {
9
+ return 0;
10
+ }
8
11
  // Check if the matrix is a valid rotation matrix
9
12
  if (Math.round(a * a + b * b) !== 1 || Math.round(c * c + d * d) !== 1) {
10
13
  throw new Error('The provided matrix is not a valid rotation matrix.');
@@ -23,21 +26,15 @@ const applyRotation = ({ matrix, width, height, }) => {
23
26
  };
24
27
  };
25
28
  const parseTkhd = ({ iterator, offset, size, }) => {
26
- if (size !== 92) {
27
- throw new Error(`Expected tkhd size of version 0 to be 92, got ${size}`);
28
- }
29
29
  const version = iterator.getUint8();
30
- if (version !== 0) {
31
- throw new Error(`Unsupported TKHD version ${version}`);
32
- }
33
30
  // Flags, we discard them
34
31
  iterator.discard(3);
35
- const creationTime = iterator.getUint32();
36
- const modificationTime = iterator.getUint32();
32
+ const creationTime = version === 1 ? iterator.getUint64() : iterator.getUint32();
33
+ const modificationTime = version === 1 ? iterator.getUint64() : iterator.getUint32();
37
34
  const trackId = iterator.getUint32();
38
35
  // reserved
39
36
  iterator.discard(4);
40
- const duration = iterator.getUint32();
37
+ const duration = version === 1 ? iterator.getUint64() : iterator.getUint32();
41
38
  // reserved 2
42
39
  iterator.discard(4);
43
40
  // reserved 3
@@ -71,10 +68,10 @@ const parseTkhd = ({ iterator, offset, size, }) => {
71
68
  offset,
72
69
  boxSize: size,
73
70
  type: 'tkhd-box',
74
- creationTime: (0, to_date_1.toUnixTimestamp)(creationTime),
75
- modificationTime: (0, to_date_1.toUnixTimestamp)(modificationTime),
71
+ creationTime: (0, to_date_1.toUnixTimestamp)(Number(creationTime)),
72
+ modificationTime: (0, to_date_1.toUnixTimestamp)(Number(modificationTime)),
76
73
  trackId,
77
- duration,
74
+ duration: Number(duration),
78
75
  layer,
79
76
  alternateGroup,
80
77
  volume,
@@ -1,2 +1,2 @@
1
- export declare const measureEBMLVarInt: (value: number) => 2 | 3 | 1 | 4 | 5 | 6;
1
+ export declare const measureEBMLVarInt: (value: number) => 1 | 2 | 3 | 4 | 5 | 6;
2
2
  export declare const getVariableInt: (value: number, minWidth: number | null) => Uint8Array;
@@ -150,7 +150,6 @@ const getTrack = ({ timescale, track, }) => {
150
150
  denominator: 1,
151
151
  },
152
152
  timescale,
153
- samplePositions: [],
154
153
  codedHeight: height.value.value,
155
154
  codedWidth: width.value.value,
156
155
  displayAspectHeight: displayHeight
@@ -160,6 +159,7 @@ const getTrack = ({ timescale, track, }) => {
160
159
  ? displayWidth.value.value
161
160
  : width.value.value,
162
161
  rotation: 0,
162
+ trakBox: null,
163
163
  };
164
164
  }
165
165
  if ((0, track_entry_1.trackTypeToString)(trackType.value.value) === 'audio') {
@@ -172,11 +172,11 @@ const getTrack = ({ timescale, track, }) => {
172
172
  type: 'audio',
173
173
  trackId,
174
174
  codec: getMatroskaAudioCodecString(track),
175
- samplePositions: null,
176
175
  timescale,
177
176
  numberOfChannels,
178
177
  sampleRate,
179
178
  description: (0, description_1.getAudioDescription)(track),
179
+ trakBox: null,
180
180
  };
181
181
  }
182
182
  return null;
@@ -50,6 +50,7 @@ export declare const getArrayBufferIterator: (initialData: Uint8Array, maxBytes:
50
50
  getFloat32: () => number;
51
51
  getUint32Le: () => number;
52
52
  getInt32Le: () => number;
53
+ getInt32: () => number;
53
54
  destroy: () => void;
54
55
  isMp3: () => boolean;
55
56
  };
@@ -392,8 +392,8 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
392
392
  },
393
393
  getUint24: () => {
394
394
  const val1 = view.getUint8(counter.getDiscardedOffset());
395
- const val2 = view.getUint8(counter.getDiscardedOffset());
396
- const val3 = view.getUint8(counter.getDiscardedOffset());
395
+ const val2 = view.getUint8(counter.getDiscardedOffset() + 1);
396
+ const val3 = view.getUint8(counter.getDiscardedOffset() + 2);
397
397
  counter.increment(3);
398
398
  return (val1 << 16) | (val2 << 8) | val3;
399
399
  },
@@ -443,6 +443,7 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
443
443
  },
444
444
  getUint32Le,
445
445
  getInt32Le,
446
+ getInt32,
446
447
  destroy,
447
448
  isMp3,
448
449
  };
@@ -0,0 +1,10 @@
1
+ export declare const CLUSTER_MIN_VINT_WIDTH = 8;
2
+ export declare const createClusterSegment: () => import("../boxes/webm/segments/all-segments").BytesAndOffset;
3
+ export declare const makeSimpleBlock: ({ bytes, trackNumber, timecodeRelativeToCluster, keyframe, invisible, lacing, }: {
4
+ bytes: Uint8Array;
5
+ trackNumber: number;
6
+ timecodeRelativeToCluster: number;
7
+ keyframe: boolean;
8
+ invisible: boolean;
9
+ lacing: number;
10
+ }) => Uint8Array;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeSimpleBlock = exports.createClusterSegment = exports.CLUSTER_MIN_VINT_WIDTH = void 0;
4
+ const ebml_1 = require("../boxes/webm/ebml");
5
+ const make_header_1 = require("../boxes/webm/make-header");
6
+ exports.CLUSTER_MIN_VINT_WIDTH = 8;
7
+ const createClusterSegment = () => {
8
+ return (0, make_header_1.makeMatroskaBytes)({
9
+ type: 'Cluster',
10
+ value: [
11
+ {
12
+ type: 'Timestamp',
13
+ minVintWidth: 4,
14
+ value: {
15
+ value: 0,
16
+ byteLength: null,
17
+ },
18
+ },
19
+ ],
20
+ minVintWidth: exports.CLUSTER_MIN_VINT_WIDTH,
21
+ });
22
+ };
23
+ exports.createClusterSegment = createClusterSegment;
24
+ const makeSimpleBlock = ({ bytes, trackNumber, timecodeRelativeToCluster, keyframe, invisible, lacing, }) => {
25
+ const simpleBlockHeader = (0, make_header_1.matroskaToHex)('0xa3');
26
+ const headerByte = (Number(keyframe) << 7) | (Number(invisible) << 3) | (lacing << 1);
27
+ const body = (0, make_header_1.combineUint8Arrays)([
28
+ (0, ebml_1.getVariableInt)(trackNumber, null),
29
+ // TODO: Cannot encode long videos because of uint16 overflow
30
+ // need to make new cluster
31
+ (0, make_header_1.serializeUint16)(timecodeRelativeToCluster),
32
+ new Uint8Array([headerByte]),
33
+ bytes,
34
+ ]);
35
+ return (0, make_header_1.combineUint8Arrays)([
36
+ simpleBlockHeader,
37
+ (0, ebml_1.getVariableInt)(body.length, null),
38
+ body,
39
+ ]);
40
+ };
41
+ exports.makeSimpleBlock = makeSimpleBlock;
@@ -0,0 +1,7 @@
1
+ import type { WriterInterface } from '../writers/writer';
2
+ export type MediaFn = {
3
+ save: () => Promise<void>;
4
+ addSample: (chunk: EncodedVideoChunk, trackNumber: number) => Promise<void>;
5
+ updateDuration: (duration: number) => Promise<void>;
6
+ };
7
+ export declare const createMedia: (writer: WriterInterface) => Promise<MediaFn>;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMedia = void 0;
4
+ const ebml_1 = require("../boxes/webm/ebml");
5
+ const make_header_1 = require("../boxes/webm/make-header");
6
+ const all_segments_1 = require("../boxes/webm/segments/all-segments");
7
+ const cluster_segment_1 = require("./cluster-segment");
8
+ const matroska_header_1 = require("./matroska-header");
9
+ const matroska_info_1 = require("./matroska-info");
10
+ const matroska_segment_1 = require("./matroska-segment");
11
+ const matroska_trackentry_1 = require("./matroska-trackentry");
12
+ const createMedia = async (writer) => {
13
+ var _a, _b;
14
+ const header = (0, matroska_header_1.makeMatroskaHeader)();
15
+ const w = await writer.createContent();
16
+ await w.write(header.bytes);
17
+ const matroskaInfo = (0, matroska_info_1.makeMatroskaInfo)({
18
+ timescale: 1000000,
19
+ duration: 2658,
20
+ });
21
+ const matroskaTrackEntry = (0, matroska_trackentry_1.makeMatroskaVideoTrackEntryBytes)({
22
+ color: {
23
+ transferChracteristics: 'bt709',
24
+ matrixCoefficients: 'bt709',
25
+ primaries: 'bt709',
26
+ fullRange: true,
27
+ },
28
+ width: 1920,
29
+ height: 1080,
30
+ defaultDuration: 2658,
31
+ trackNumber: 1,
32
+ codecId: 'V_VP8',
33
+ });
34
+ const matroskaTracks = (0, matroska_trackentry_1.makeMatroskaTracks)([matroskaTrackEntry]);
35
+ const matroskaSegment = (0, matroska_segment_1.createMatroskaSegment)([matroskaInfo, matroskaTracks]);
36
+ const durationOffset = ((_b = (_a = matroskaSegment.offsets.children[0].children.find((c) => c.field === 'Duration')) === null || _a === void 0 ? void 0 : _a.offset) !== null && _b !== void 0 ? _b : 0) + w.getWrittenByteCount();
37
+ if (!durationOffset) {
38
+ throw new Error('could not get duration offset');
39
+ }
40
+ await w.write(matroskaSegment.bytes);
41
+ const cluster = (0, cluster_segment_1.createClusterSegment)();
42
+ const clusterVIntPosition = w.getWrittenByteCount() +
43
+ cluster.offsets.offset +
44
+ (0, make_header_1.matroskaToHex)(all_segments_1.matroskaElements.Cluster).byteLength;
45
+ let clusterSize = cluster.bytes.byteLength;
46
+ await w.write(cluster.bytes);
47
+ const addSample = async (chunk, trackNumber) => {
48
+ const arr = new Uint8Array(chunk.byteLength);
49
+ chunk.copyTo(arr);
50
+ const simpleBlock = (0, cluster_segment_1.makeSimpleBlock)({
51
+ bytes: arr,
52
+ invisible: false,
53
+ keyframe: chunk.type === 'key',
54
+ lacing: 0,
55
+ trackNumber,
56
+ // TODO: Maybe this is bad, because it's in microseconds, but should be in timescale
57
+ // Maybe it only works by coincidence
58
+ timecodeRelativeToCluster: Math.round(chunk.timestamp / 1000),
59
+ });
60
+ clusterSize += simpleBlock.byteLength;
61
+ await w.updateDataAt(clusterVIntPosition, (0, ebml_1.getVariableInt)(clusterSize, cluster_segment_1.CLUSTER_MIN_VINT_WIDTH));
62
+ await w.write(simpleBlock);
63
+ };
64
+ const updateDuration = async (newDuration) => {
65
+ const blocks = (0, make_header_1.padMatroskaBytes)({
66
+ type: 'Duration',
67
+ value: {
68
+ value: newDuration,
69
+ size: '64',
70
+ },
71
+ minVintWidth: null,
72
+ }, 1000);
73
+ await w.updateDataAt(durationOffset, (0, make_header_1.combineUint8Arrays)(blocks.map((b) => b.bytes)));
74
+ };
75
+ let operationProm = Promise.resolve();
76
+ return {
77
+ save: async () => {
78
+ await w.save();
79
+ },
80
+ addSample: (chunk, trackNumber) => {
81
+ operationProm = operationProm.then(() => addSample(chunk, trackNumber));
82
+ return operationProm;
83
+ },
84
+ updateDuration: (duration) => {
85
+ operationProm = operationProm.then(() => updateDuration(duration));
86
+ return operationProm;
87
+ },
88
+ };
89
+ };
90
+ exports.createMedia = createMedia;
@@ -0,0 +1 @@
1
+ export declare const makeMatroskaHeader: () => import("../boxes/webm/segments/all-segments").BytesAndOffset;