@remotion/media-parser 4.0.192 → 4.0.193

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 (62) hide show
  1. package/boxes.json +1 -0
  2. package/dist/boxes/iso-base-media/esds/esds-descriptors.d.ts +21 -0
  3. package/dist/boxes/iso-base-media/esds/esds-descriptors.js +62 -0
  4. package/dist/boxes/iso-base-media/esds/esds.d.ts +15 -0
  5. package/dist/boxes/iso-base-media/esds/esds.js +27 -0
  6. package/dist/boxes/iso-base-media/ftype.d.ts +9 -0
  7. package/dist/boxes/iso-base-media/ftype.js +31 -0
  8. package/dist/boxes/iso-base-media/process-box.js +17 -0
  9. package/dist/boxes/iso-base-media/stsd/samples.d.ts +2 -0
  10. package/dist/boxes/iso-base-media/stsd/samples.js +27 -8
  11. package/dist/boxes/webm/parse-webm-header.js +3 -3
  12. package/dist/boxes/webm/segments/track-entry.d.ts +20 -0
  13. package/dist/boxes/webm/segments/track-entry.js +37 -2
  14. package/dist/boxes/webm/segments.d.ts +2 -2
  15. package/dist/boxes/webm/segments.js +12 -0
  16. package/dist/buffer-iterator.d.ts +2 -1
  17. package/dist/buffer-iterator.js +27 -8
  18. package/dist/from-node.js +6 -2
  19. package/dist/from-web.js +6 -1
  20. package/dist/get-audio-codec.d.ts +4 -0
  21. package/dist/get-audio-codec.js +106 -0
  22. package/dist/get-dimensions.js +6 -2
  23. package/dist/get-fps.d.ts +1 -0
  24. package/dist/get-fps.js +34 -1
  25. package/dist/get-video-codec.js +3 -0
  26. package/dist/get-video-metadata.d.ts +2 -0
  27. package/dist/get-video-metadata.js +44 -0
  28. package/dist/has-all-info.d.ts +1 -1
  29. package/dist/has-all-info.js +4 -0
  30. package/dist/options.d.ts +7 -3
  31. package/dist/parse-media.js +23 -6
  32. package/dist/parse-result.d.ts +2 -1
  33. package/dist/read-and-increment-offset.d.ts +28 -0
  34. package/dist/read-and-increment-offset.js +177 -0
  35. package/dist/reader.d.ts +5 -1
  36. package/package.json +2 -2
  37. package/src/boxes/iso-base-media/esds/esds-descriptors.ts +104 -0
  38. package/src/boxes/iso-base-media/esds/esds.ts +49 -0
  39. package/src/boxes/iso-base-media/process-box.ts +20 -0
  40. package/src/boxes/iso-base-media/stsd/samples.ts +35 -8
  41. package/src/boxes/webm/parse-webm-header.ts +3 -3
  42. package/src/boxes/webm/segments/track-entry.ts +66 -1
  43. package/src/boxes/webm/segments.ts +29 -1
  44. package/src/buffer-iterator.ts +34 -10
  45. package/src/from-node.ts +6 -4
  46. package/src/from-web.ts +8 -1
  47. package/src/get-audio-codec.ts +143 -0
  48. package/src/get-dimensions.ts +11 -4
  49. package/src/get-fps.ts +48 -0
  50. package/src/get-video-codec.ts +4 -0
  51. package/src/has-all-info.ts +14 -2
  52. package/src/options.ts +18 -3
  53. package/src/parse-media.ts +30 -7
  54. package/src/parse-result.ts +3 -1
  55. package/src/reader.ts +5 -1
  56. package/src/test/matroska.test.ts +6 -7
  57. package/src/test/parse-esds.test.ts +75 -0
  58. package/src/test/stream-local.test.ts +79 -2
  59. package/src/test/stsd.test.ts +52 -5
  60. package/tsconfig.tsbuildinfo +1 -1
  61. package/dist/get-codec.d.ts +0 -4
  62. package/dist/get-codec.js +0 -22
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAudioCodec = exports.hasAudioCodec = void 0;
4
+ const get_fps_1 = require("./get-fps");
5
+ const hasAudioCodec = (boxes) => {
6
+ try {
7
+ return (0, exports.getAudioCodec)(boxes) !== null;
8
+ }
9
+ catch (e) {
10
+ return false;
11
+ }
12
+ };
13
+ exports.hasAudioCodec = hasAudioCodec;
14
+ const onEsdsBox = (child) => {
15
+ if (child && child.type === 'esds-box') {
16
+ const descriptor = child.descriptors.find((d) => d.type === 'decoder-config-descriptor');
17
+ if (descriptor && descriptor.type === 'decoder-config-descriptor') {
18
+ return descriptor.objectTypeIndication;
19
+ }
20
+ }
21
+ return null;
22
+ };
23
+ const onSample = (sample) => {
24
+ if (!sample) {
25
+ return null;
26
+ }
27
+ if (sample.type !== 'audio') {
28
+ return null;
29
+ }
30
+ if (sample.format === 'sowt') {
31
+ return 'aiff';
32
+ }
33
+ const child = sample.children.find((c) => c.type === 'esds-box');
34
+ if (child && child.type === 'esds-box') {
35
+ const ret = onEsdsBox(child);
36
+ if (ret) {
37
+ return ret;
38
+ }
39
+ }
40
+ };
41
+ const getAudioCodec = (boxes) => {
42
+ const moovBox = boxes.find((b) => b.type === 'moov-box');
43
+ if (moovBox && moovBox.type === 'moov-box') {
44
+ const trakBox = moovBox.children.find((b) => b.type === 'trak-box' && (0, get_fps_1.trakBoxContainsAudio)(b));
45
+ if (trakBox && trakBox.type === 'trak-box') {
46
+ const mdiaBox = trakBox.children.find((b) => b.type === 'regular-box' && b.boxType === 'mdia');
47
+ if (mdiaBox &&
48
+ mdiaBox.type === 'regular-box' &&
49
+ mdiaBox.boxType === 'mdia') {
50
+ const minfBox = mdiaBox === null || mdiaBox === void 0 ? void 0 : mdiaBox.children.find((b) => b.type === 'regular-box' && b.boxType === 'minf');
51
+ if (minfBox &&
52
+ minfBox.type === 'regular-box' &&
53
+ minfBox.boxType === 'minf') {
54
+ const stblBox = minfBox === null || minfBox === void 0 ? void 0 : minfBox.children.find((b) => b.type === 'regular-box' && b.boxType === 'stbl');
55
+ if (stblBox && stblBox.type === 'regular-box') {
56
+ const stsdBox = stblBox === null || stblBox === void 0 ? void 0 : stblBox.children.find((b) => b.type === 'stsd-box');
57
+ if (stsdBox && stsdBox.type === 'stsd-box') {
58
+ const sample = stsdBox.samples.find((s) => s.type === 'audio');
59
+ if (sample && sample.type === 'audio') {
60
+ const ret = onSample(sample);
61
+ if (ret) {
62
+ return ret;
63
+ }
64
+ const waveBox = sample.children.find((b) => b.type === 'regular-box' && b.boxType === 'wave');
65
+ if (waveBox &&
66
+ waveBox.type === 'regular-box' &&
67
+ waveBox.boxType === 'wave') {
68
+ const esdsBox = waveBox.children.find((b) => b.type === 'esds-box');
69
+ if (esdsBox && esdsBox.type === 'esds-box') {
70
+ const ret2 = onEsdsBox(esdsBox);
71
+ if (ret2) {
72
+ return ret2;
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ const mainSegment = boxes.find((b) => b.type === 'main-segment');
84
+ if (!mainSegment || mainSegment.type !== 'main-segment') {
85
+ return null;
86
+ }
87
+ const tracksSegment = mainSegment.children.find((b) => b.type === 'tracks-segment');
88
+ if (!tracksSegment || tracksSegment.type !== 'tracks-segment') {
89
+ return null;
90
+ }
91
+ for (const track of tracksSegment.children) {
92
+ if (track.type === 'track-entry-segment') {
93
+ const trackType = track.children.find((b) => b.type === 'codec-segment');
94
+ if (trackType && trackType.type === 'codec-segment') {
95
+ if (trackType.codec === 'A_OPUS') {
96
+ return 'opus';
97
+ }
98
+ if (trackType.codec === 'A_PCM/INT/LIT') {
99
+ return 'pcm';
100
+ }
101
+ }
102
+ }
103
+ }
104
+ return null;
105
+ };
106
+ exports.getAudioCodec = getAudioCodec;
@@ -6,8 +6,12 @@ const getDimensionsFromMatroska = (segments) => {
6
6
  if (!tracksSegment || tracksSegment.type !== 'tracks-segment') {
7
7
  throw new Error('No tracks segment');
8
8
  }
9
- // TODO: What if there are multiple video tracks, or audio track is first?
10
- const trackEntrySegment = tracksSegment.children.find((b) => b.type === 'track-entry-segment');
9
+ const trackEntrySegment = tracksSegment.children.find((b) => {
10
+ if (b.type !== 'track-entry-segment') {
11
+ return false;
12
+ }
13
+ return (b.children.find((c) => c.type === 'codec-segment' && c.codec.startsWith('V_')) !== undefined);
14
+ });
11
15
  if (!trackEntrySegment || trackEntrySegment.type !== 'track-entry-segment') {
12
16
  throw new Error('No track entry segment');
13
17
  }
package/dist/get-fps.d.ts CHANGED
@@ -3,6 +3,7 @@ type TimescaleAndDuration = {
3
3
  timescale: number;
4
4
  duration: number;
5
5
  };
6
+ export declare const trakBoxContainsAudio: (trakBox: AnySegment) => boolean;
6
7
  export declare const trakBoxContainsVideo: (trakBox: AnySegment) => boolean;
7
8
  export declare const getTimescaleAndDuration: (boxes: AnySegment[]) => TimescaleAndDuration | null;
8
9
  export declare const getFps: (segments: AnySegment[]) => number | null;
package/dist/get-fps.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasFps = exports.getFps = exports.getTimescaleAndDuration = exports.trakBoxContainsVideo = void 0;
3
+ exports.hasFps = exports.getFps = exports.getTimescaleAndDuration = exports.trakBoxContainsVideo = exports.trakBoxContainsAudio = void 0;
4
4
  const calculateFps = ({ sttsBox, timeScale, durationInSamples, }) => {
5
5
  let totalSamples = 0;
6
6
  for (const sample of sttsBox.sampleDistribution) {
@@ -10,6 +10,39 @@ const calculateFps = ({ sttsBox, timeScale, durationInSamples, }) => {
10
10
  const fps = totalSamples / durationInSeconds;
11
11
  return fps;
12
12
  };
13
+ const trakBoxContainsAudio = (trakBox) => {
14
+ if (trakBox.type !== 'trak-box') {
15
+ return false;
16
+ }
17
+ const { children } = trakBox;
18
+ const mediaBoxes = children.filter((c) => c.type === 'regular-box' && c.boxType === 'mdia');
19
+ if (!mediaBoxes || mediaBoxes.length === 0) {
20
+ return false;
21
+ }
22
+ const firstMediaBox = mediaBoxes[0];
23
+ if (firstMediaBox.type !== 'regular-box' ||
24
+ firstMediaBox.boxType !== 'mdia') {
25
+ return false;
26
+ }
27
+ const minf = firstMediaBox.children.find((c) => c.type === 'regular-box' && c.boxType === 'minf');
28
+ if (!minf || minf.type !== 'regular-box' || minf.boxType !== 'minf') {
29
+ return false;
30
+ }
31
+ const stbl = minf.children.find((c) => c.type === 'regular-box' && c.boxType === 'stbl');
32
+ if (!stbl || stbl.type !== 'regular-box' || stbl.boxType !== 'stbl') {
33
+ return false;
34
+ }
35
+ const stsd = stbl.children.find((c) => c.type === 'stsd-box');
36
+ if (!stsd || stsd.type !== 'stsd-box') {
37
+ return false;
38
+ }
39
+ const videoSample = stsd.samples.find((s) => s.type === 'audio');
40
+ if (!videoSample || videoSample.type !== 'audio') {
41
+ return false;
42
+ }
43
+ return true;
44
+ };
45
+ exports.trakBoxContainsAudio = trakBoxContainsAudio;
13
46
  const trakBoxContainsVideo = (trakBox) => {
14
47
  if (trakBox.type !== 'trak-box') {
15
48
  return false;
@@ -68,6 +68,9 @@ const getVideoCodec = (boxes) => {
68
68
  if (trackType.codec === 'V_AV1') {
69
69
  return 'av1';
70
70
  }
71
+ if (trackType.codec === 'V_MPEG4/ISO/AVC') {
72
+ return 'h264';
73
+ }
71
74
  }
72
75
  }
73
76
  }
@@ -0,0 +1,2 @@
1
+ import type { ParseMedia } from './options';
2
+ export declare const parseMedia: ParseMedia;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseMedia = void 0;
4
+ const buffer_iterator_1 = require("./buffer-iterator");
5
+ const from_web_1 = require("./from-web");
6
+ const get_dimensions_1 = require("./get-dimensions");
7
+ const get_duration_1 = require("./get-duration");
8
+ const get_fps_1 = require("./get-fps");
9
+ const has_all_info_1 = require("./has-all-info");
10
+ const parse_video_1 = require("./parse-video");
11
+ const parseMedia = async (src, options, readerInterface = from_web_1.webReader) => {
12
+ const reader = await readerInterface.read(src, null);
13
+ const returnValue = {};
14
+ const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(new Uint8Array([]));
15
+ let parseResult = (0, parse_video_1.parseVideo)(iterator);
16
+ while (parseResult.status === 'incomplete') {
17
+ const result = await reader.read();
18
+ if (result.done) {
19
+ break;
20
+ }
21
+ iterator.addData(result.value);
22
+ parseResult = parseResult.continueParsing();
23
+ if ((0, has_all_info_1.hasAllInfo)(options, parseResult)) {
24
+ if (!reader.closed) {
25
+ reader.cancel(new Error('has all information'));
26
+ }
27
+ break;
28
+ }
29
+ }
30
+ if (options.dimensions) {
31
+ returnValue.dimensions = (0, get_dimensions_1.getDimensions)(parseResult.segments);
32
+ }
33
+ if (options.durationInSeconds) {
34
+ returnValue.durationInSeconds = (0, get_duration_1.getDuration)(parseResult.segments);
35
+ }
36
+ if (options.fps) {
37
+ returnValue.fps = (0, get_fps_1.getFps)(parseResult.segments);
38
+ }
39
+ if (options.boxes) {
40
+ returnValue.boxes = parseResult.segments;
41
+ }
42
+ return returnValue;
43
+ };
44
+ exports.parseMedia = parseMedia;
@@ -1,3 +1,3 @@
1
1
  import type { Options } from './options';
2
2
  import type { ParseResult } from './parse-result';
3
- export declare const hasAllInfo: (options: Options<boolean, boolean, boolean, boolean, boolean>, parseResult: ParseResult) => boolean;
3
+ export declare const hasAllInfo: (options: Options<boolean, boolean, boolean, boolean, boolean, boolean>, parseResult: ParseResult) => boolean;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.hasAllInfo = void 0;
4
+ const get_audio_codec_1 = require("./get-audio-codec");
4
5
  const get_dimensions_1 = require("./get-dimensions");
5
6
  const get_duration_1 = require("./get-duration");
6
7
  const get_fps_1 = require("./get-fps");
@@ -25,6 +26,9 @@ const hasAllInfo = (options, parseResult) => {
25
26
  if (key === 'videoCodec') {
26
27
  return (0, get_video_codec_1.hasVideoCodec)(parseResult.segments) !== null;
27
28
  }
29
+ if (key === 'audioCodec') {
30
+ return (0, get_audio_codec_1.hasAudioCodec)(parseResult.segments) !== null;
31
+ }
28
32
  throw new Error(`Unknown key: ${key}`);
29
33
  });
30
34
  };
package/dist/options.d.ts CHANGED
@@ -2,14 +2,16 @@ import type { Dimensions } from './get-dimensions';
2
2
  import type { AnySegment } from './parse-result';
3
3
  import type { ReaderInterface } from './reader';
4
4
  export type KnownVideoCodecs = 'h264' | 'h265' | 'vp8' | 'vp9' | 'av1' | 'prores';
5
- export type Options<EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean> = {
5
+ export type KnownAudioCodecs = 'aac' | 'mp3' | 'aiff' | 'opus' | 'pcm' | 'unknown';
6
+ export type Options<EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean, EnableAudioCodec extends boolean> = {
6
7
  dimensions?: EnableDimensions;
7
8
  durationInSeconds?: EnableDuration;
8
9
  boxes?: EnableBoxes;
9
10
  fps?: EnableFps;
10
11
  videoCodec?: EnableVideoCodec;
12
+ audioCodec?: EnableAudioCodec;
11
13
  };
12
- export type Metadata<EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean> = (EnableDimensions extends true ? {
14
+ export type Metadata<EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean, EnableAudioCodec extends boolean> = (EnableDimensions extends true ? {
13
15
  dimensions: Dimensions;
14
16
  } : {}) & (EnableDuration extends true ? {
15
17
  durationInSeconds: number | null;
@@ -19,5 +21,7 @@ export type Metadata<EnableDimensions extends boolean, EnableDuration extends bo
19
21
  fps: number | null;
20
22
  } : {}) & (EnableVideoCodec extends true ? {
21
23
  videoCodec: KnownVideoCodecs | null;
24
+ } : {}) & (EnableAudioCodec extends true ? {
25
+ audioCodec: KnownAudioCodecs | null;
22
26
  } : {});
23
- export type ParseMedia = <EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean>(src: string, options: Options<EnableDimensions, EnableDuration, EnableBoxes, EnableFps, EnableVideoCodec>, readerInterface?: ReaderInterface) => Promise<Metadata<EnableDimensions, EnableDuration, EnableBoxes, EnableFps, EnableVideoCodec>>;
27
+ export type ParseMedia = <EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean, EnableAudioCodec extends boolean>(src: string, options: Options<EnableDimensions, EnableDuration, EnableBoxes, EnableFps, EnableVideoCodec, EnableAudioCodec>, readerInterface?: ReaderInterface) => Promise<Metadata<EnableDimensions, EnableDuration, EnableBoxes, EnableFps, EnableVideoCodec, EnableAudioCodec>>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseMedia = void 0;
4
4
  const buffer_iterator_1 = require("./buffer-iterator");
5
5
  const from_web_1 = require("./from-web");
6
+ const get_audio_codec_1 = require("./get-audio-codec");
6
7
  const get_dimensions_1 = require("./get-dimensions");
7
8
  const get_duration_1 = require("./get-duration");
8
9
  const get_fps_1 = require("./get-fps");
@@ -10,17 +11,27 @@ const get_video_codec_1 = require("./get-video-codec");
10
11
  const has_all_info_1 = require("./has-all-info");
11
12
  const parse_video_1 = require("./parse-video");
12
13
  const parseMedia = async (src, options, readerInterface = from_web_1.webReader) => {
13
- const reader = await readerInterface.read(src, null);
14
+ const { reader, contentLength } = await readerInterface.read(src, null);
14
15
  const returnValue = {};
15
- const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(new Uint8Array([]));
16
- let parseResult = (0, parse_video_1.parseVideo)(iterator);
17
- while (parseResult.status === 'incomplete') {
16
+ let iterator = null;
17
+ let parseResult = null;
18
+ while (parseResult === null || parseResult.status === 'incomplete') {
18
19
  const result = await reader.read();
19
20
  if (result.done) {
20
21
  break;
21
22
  }
22
- iterator.addData(result.value);
23
- parseResult = parseResult.continueParsing();
23
+ if (iterator) {
24
+ iterator.addData(result.value);
25
+ }
26
+ else {
27
+ iterator = (0, buffer_iterator_1.getArrayBufferIterator)(result.value, contentLength !== null && contentLength !== void 0 ? contentLength : undefined);
28
+ }
29
+ if (parseResult) {
30
+ parseResult = parseResult.continueParsing();
31
+ }
32
+ else {
33
+ parseResult = (0, parse_video_1.parseVideo)(iterator);
34
+ }
24
35
  if ((0, has_all_info_1.hasAllInfo)(options, parseResult)) {
25
36
  if (!reader.closed) {
26
37
  reader.cancel(new Error('has all information'));
@@ -28,6 +39,9 @@ const parseMedia = async (src, options, readerInterface = from_web_1.webReader)
28
39
  break;
29
40
  }
30
41
  }
42
+ if (!parseResult) {
43
+ throw new Error('Could not parse video');
44
+ }
31
45
  if (options.dimensions) {
32
46
  returnValue.dimensions = (0, get_dimensions_1.getDimensions)(parseResult.segments);
33
47
  }
@@ -40,6 +54,9 @@ const parseMedia = async (src, options, readerInterface = from_web_1.webReader)
40
54
  if (options.videoCodec) {
41
55
  returnValue.videoCodec = (0, get_video_codec_1.getVideoCodec)(parseResult.segments);
42
56
  }
57
+ if (options.audioCodec) {
58
+ returnValue.audioCodec = (0, get_audio_codec_1.getAudioCodec)(parseResult.segments);
59
+ }
43
60
  if (options.boxes) {
44
61
  returnValue.boxes = parseResult.segments;
45
62
  }
@@ -1,4 +1,5 @@
1
1
  import type { BaseBox } from './boxes/iso-base-media/base-type';
2
+ import type { EsdsBox } from './boxes/iso-base-media/esds/esds';
2
3
  import type { FtypBox } from './boxes/iso-base-media/ftyp';
3
4
  import type { MdhdBox } from './boxes/iso-base-media/mdhd';
4
5
  import type { MoovBox } from './boxes/iso-base-media/moov/moov';
@@ -17,7 +18,7 @@ interface RegularBox extends BaseBox {
17
18
  offset: number;
18
19
  type: 'regular-box';
19
20
  }
20
- export type IsoBaseMediaBox = RegularBox | FtypBox | MvhdBox | TkhdBox | StsdBox | MebxBox | KeysBox | MoovBox | TrakBox | SttsBox | MdhdBox;
21
+ export type IsoBaseMediaBox = RegularBox | FtypBox | MvhdBox | TkhdBox | StsdBox | MebxBox | KeysBox | MoovBox | TrakBox | SttsBox | MdhdBox | EsdsBox;
21
22
  export type AnySegment = MatroskaSegment | IsoBaseMediaBox;
22
23
  export type ParseResult = {
23
24
  status: 'done';
@@ -0,0 +1,28 @@
1
+ export declare class OffsetCounter {
2
+ #private;
3
+ constructor(initial: number);
4
+ increment(amount: number): void;
5
+ getOffset(): number;
6
+ }
7
+ export declare const getArrayBufferIterator: (data: ArrayBuffer, initialOffset: number) => {
8
+ view: DataView;
9
+ counter: OffsetCounter;
10
+ data: ArrayBuffer;
11
+ discard: (length: number) => void;
12
+ getSlice: (amount: number) => ArrayBuffer;
13
+ getAtom: () => string;
14
+ getMatroskaSegmentId: () => string;
15
+ getVint: (bytes: number) => number;
16
+ getUint8: () => number;
17
+ getEBML: () => number;
18
+ getInt8: () => number;
19
+ getUint16: () => number;
20
+ getInt16: () => number;
21
+ getUint32: () => number;
22
+ getFixedPoint1616Number: () => number;
23
+ getPascalString: () => number[];
24
+ getDecimalBytes(length: number): number;
25
+ getByteString(length: number): string;
26
+ getFloat64: () => number;
27
+ };
28
+ export type BufferIterator = ReturnType<typeof getArrayBufferIterator>;
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _OffsetCounter_offset;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getArrayBufferIterator = exports.OffsetCounter = void 0;
16
+ class OffsetCounter {
17
+ constructor(initial) {
18
+ _OffsetCounter_offset.set(this, void 0);
19
+ __classPrivateFieldSet(this, _OffsetCounter_offset, initial, "f");
20
+ }
21
+ increment(amount) {
22
+ if (amount < 0) {
23
+ throw new Error('Cannot increment by a negative amount');
24
+ }
25
+ __classPrivateFieldSet(this, _OffsetCounter_offset, __classPrivateFieldGet(this, _OffsetCounter_offset, "f") + amount, "f");
26
+ }
27
+ getOffset() {
28
+ return __classPrivateFieldGet(this, _OffsetCounter_offset, "f");
29
+ }
30
+ }
31
+ exports.OffsetCounter = OffsetCounter;
32
+ _OffsetCounter_offset = new WeakMap();
33
+ const makeOffsetCounter = (initial) => {
34
+ return new OffsetCounter(initial);
35
+ };
36
+ const getArrayBufferIterator = (data, initialOffset) => {
37
+ const view = new DataView(data);
38
+ const counter = makeOffsetCounter(initialOffset);
39
+ const getSlice = (amount) => {
40
+ const value = data.slice(counter.getOffset(), counter.getOffset() + amount);
41
+ counter.increment(amount);
42
+ return value;
43
+ };
44
+ const getUint8 = () => {
45
+ const val = view.getUint8(counter.getOffset());
46
+ counter.increment(1);
47
+ return val;
48
+ };
49
+ const getUint32 = () => {
50
+ const val = view.getUint32(counter.getOffset());
51
+ counter.increment(4);
52
+ return val;
53
+ };
54
+ return {
55
+ view,
56
+ counter,
57
+ data,
58
+ discard: (length) => {
59
+ counter.increment(length);
60
+ },
61
+ getSlice,
62
+ getAtom: () => {
63
+ const atom = getSlice(4);
64
+ return new TextDecoder().decode(atom);
65
+ },
66
+ getMatroskaSegmentId: () => {
67
+ const first = getSlice(1);
68
+ const firstOneString = `0x${Array.from(new Uint8Array(first))
69
+ .map((b) => {
70
+ return b.toString(16).padStart(2, '0');
71
+ })
72
+ .join('')}`;
73
+ // Catch void block
74
+ const knownIdsWithOneLength = ['0xec', '0xae'];
75
+ if (knownIdsWithOneLength.includes(firstOneString)) {
76
+ return firstOneString;
77
+ }
78
+ const firstTwo = getSlice(1);
79
+ const knownIdsWithTwoLength = ['0x4dbb', '0x53ac', '0xec01'];
80
+ const firstTwoString = `${firstOneString}${Array.from(new Uint8Array(firstTwo))
81
+ .map((b) => {
82
+ return b.toString(16).padStart(2, '0');
83
+ })
84
+ .join('')}`;
85
+ if (knownIdsWithTwoLength.includes(firstTwoString)) {
86
+ return firstTwoString;
87
+ }
88
+ const knownIdsWithThreeLength = ['0x4d808c', '0x57418c', '0x448988'];
89
+ const firstThree = getSlice(1);
90
+ const firstThreeString = `${firstTwoString}${Array.from(new Uint8Array(firstThree))
91
+ .map((b) => {
92
+ return b.toString(16).padStart(2, '0');
93
+ })
94
+ .join('')}`;
95
+ if (knownIdsWithThreeLength.includes(firstThreeString)) {
96
+ return firstThreeString;
97
+ }
98
+ const segmentId = getSlice(1);
99
+ return `${firstThreeString}${Array.from(new Uint8Array(segmentId))
100
+ .map((b) => {
101
+ return b.toString(16).padStart(2, '0');
102
+ })
103
+ .join('')}`;
104
+ },
105
+ getVint: (bytes) => {
106
+ const slice = getSlice(bytes);
107
+ const d = [...Array.from(new Uint8Array(slice))];
108
+ const totalLength = d[0];
109
+ if (totalLength === 0) {
110
+ return 0;
111
+ }
112
+ // Calculate the actual length of the data based on the first set bit
113
+ let actualLength = 0;
114
+ while (((totalLength >> (7 - actualLength)) & 0x01) === 0) {
115
+ actualLength++;
116
+ }
117
+ actualLength += 1; // Include the first byte set as 1
118
+ // Combine the numbers to form the integer value
119
+ let value = 0;
120
+ // Mask the first byte properly then start combining
121
+ value = totalLength & (0xff >> actualLength);
122
+ for (let i = 1; i < actualLength; i++) {
123
+ value = (value << 8) | d[i];
124
+ }
125
+ return value;
126
+ },
127
+ getUint8,
128
+ getEBML: () => {
129
+ const val = getUint8();
130
+ // https://darkcoding.net/software/reading-mediarecorders-webm-opus-output/#:~:text=The%20first%20four%20bytes%20(%201A,%E2%80%93%20read%20on%20for%20why).
131
+ // You drop the initial 0 bits and the first 1 bit to get the value. 0x81 is 0b10000001, so there are zero inital 0 bits, meaning length one byte, and the value is 1. The 0x9F value for length of the EBML header we saw earlier is 0b10011111, still one byte, value is 0b0011111, which is 31 (the python repl is very helpful for these conversions).
132
+ const actualValue = val & 0x7f; // 0x7F is binary 01111111, which masks out the first bit
133
+ return actualValue;
134
+ },
135
+ getInt8: () => {
136
+ const val = view.getInt8(counter.getOffset());
137
+ counter.increment(1);
138
+ return val;
139
+ },
140
+ getUint16: () => {
141
+ const val = view.getUint16(counter.getOffset());
142
+ counter.increment(2);
143
+ return val;
144
+ },
145
+ getInt16: () => {
146
+ const val = view.getInt16(counter.getOffset());
147
+ counter.increment(2);
148
+ return val;
149
+ },
150
+ getUint32,
151
+ // https://developer.apple.com/documentation/quicktime-file-format/sound_sample_description_version_1
152
+ // A 32-bit unsigned fixed-point number (16.16) that indicates the rate at which the sound samples were obtained.
153
+ getFixedPoint1616Number: () => {
154
+ const val = getUint32();
155
+ return val / 2 ** 16;
156
+ },
157
+ getPascalString: () => {
158
+ const val = getSlice(32);
159
+ return [...Array.from(new Uint8Array(val))];
160
+ },
161
+ getDecimalBytes(length) {
162
+ const bytes = getSlice(length);
163
+ const numbers = [...Array.from(new Uint8Array(bytes))];
164
+ return numbers.reduce((acc, byte, index) => acc + (byte << (8 * (numbers.length - index - 1))), 0);
165
+ },
166
+ getByteString(length) {
167
+ const bytes = getSlice(length);
168
+ return new TextDecoder().decode(bytes);
169
+ },
170
+ getFloat64: () => {
171
+ const val = view.getFloat64(counter.getOffset());
172
+ counter.increment(8);
173
+ return val;
174
+ },
175
+ };
176
+ };
177
+ exports.getArrayBufferIterator = getArrayBufferIterator;
package/dist/reader.d.ts CHANGED
@@ -1,4 +1,8 @@
1
- type ReadContent = (src: string, range: [number, number] | null) => Promise<ReadableStreamDefaultReader<Uint8Array>>;
1
+ type ReadResult = {
2
+ reader: ReadableStreamDefaultReader<Uint8Array>;
3
+ contentLength: number | null;
4
+ };
5
+ type ReadContent = (src: string, range: [number, number] | null) => Promise<ReadResult>;
2
6
  type GetLength = (src: string) => Promise<number>;
3
7
  export type ReaderInterface = {
4
8
  read: ReadContent;
package/package.json CHANGED
@@ -3,11 +3,11 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/media-parser"
4
4
  },
5
5
  "name": "@remotion/media-parser",
6
- "version": "4.0.192",
6
+ "version": "4.0.193",
7
7
  "main": "dist/index.js",
8
8
  "sideEffects": false,
9
9
  "devDependencies": {
10
- "@remotion/renderer": "4.0.192"
10
+ "@remotion/renderer": "4.0.193"
11
11
  },
12
12
  "publishConfig": {
13
13
  "access": "public"