@remotion/media-parser 4.0.230 → 4.0.232

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 (110) hide show
  1. package/dist/add-avc-profile-to-track.d.ts +3 -0
  2. package/dist/add-avc-profile-to-track.js +35 -0
  3. package/dist/add-new-matroska-tracks.d.ts +6 -1
  4. package/dist/add-new-matroska-tracks.js +16 -1
  5. package/dist/boxes/avc/parse-avc.d.ts +18 -0
  6. package/dist/boxes/avc/parse-avc.js +96 -0
  7. package/dist/boxes/iso-base-media/make-track.js +3 -3
  8. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +2 -2
  9. package/dist/boxes/iso-base-media/mdat/mdat.js +5 -2
  10. package/dist/boxes/iso-base-media/moov/moov.js +2 -2
  11. package/dist/boxes/iso-base-media/process-box.d.ts +5 -5
  12. package/dist/boxes/iso-base-media/process-box.js +38 -37
  13. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -2
  14. package/dist/boxes/iso-base-media/stsd/samples.d.ts +2 -2
  15. package/dist/boxes/iso-base-media/stsd/samples.js +9 -9
  16. package/dist/boxes/iso-base-media/trak/trak.js +2 -2
  17. package/dist/boxes/iso-base-media/traversal.d.ts +1 -1
  18. package/dist/boxes/riff/expect-riff-box.d.ts +16 -0
  19. package/dist/boxes/riff/expect-riff-box.js +49 -0
  20. package/dist/boxes/riff/get-tracks-from-avi.d.ts +21 -0
  21. package/dist/boxes/riff/get-tracks-from-avi.js +108 -0
  22. package/dist/boxes/riff/is-movi.d.ts +2 -0
  23. package/dist/boxes/riff/is-movi.js +12 -0
  24. package/dist/boxes/riff/parse-avih.d.ts +6 -0
  25. package/dist/boxes/riff/parse-avih.js +32 -0
  26. package/dist/boxes/riff/parse-box.d.ts +13 -0
  27. package/dist/boxes/riff/parse-box.js +113 -0
  28. package/dist/boxes/riff/parse-fmt-box.d.ts +7 -0
  29. package/dist/boxes/riff/parse-fmt-box.js +33 -0
  30. package/dist/boxes/riff/parse-list-box.d.ts +8 -0
  31. package/dist/boxes/riff/parse-list-box.js +30 -0
  32. package/dist/boxes/riff/parse-movi.d.ts +17 -0
  33. package/dist/boxes/riff/parse-movi.js +122 -0
  34. package/dist/boxes/riff/parse-riff-box.d.ts +10 -0
  35. package/dist/boxes/riff/parse-riff-box.js +33 -0
  36. package/dist/boxes/riff/parse-strf.d.ts +7 -0
  37. package/dist/boxes/riff/parse-strf.js +67 -0
  38. package/dist/boxes/riff/parse-strh.d.ts +6 -0
  39. package/dist/boxes/riff/parse-strh.js +46 -0
  40. package/dist/boxes/riff/riff-box.d.ts +81 -0
  41. package/dist/boxes/riff/riff-box.js +2 -0
  42. package/dist/boxes/riff/strf.d.ts +7 -0
  43. package/dist/boxes/riff/strf.js +67 -0
  44. package/dist/boxes/riff/timescale.d.ts +1 -0
  45. package/dist/boxes/riff/timescale.js +4 -0
  46. package/dist/boxes/riff/traversal.d.ts +8 -0
  47. package/dist/boxes/riff/traversal.js +36 -0
  48. package/dist/boxes/webm/parse-ebml.js +2 -2
  49. package/dist/boxes/webm/parse-webm-header.d.ts +2 -2
  50. package/dist/boxes/webm/parse-webm-header.js +23 -4
  51. package/dist/boxes/webm/segments/parse-children.d.ts +12 -7
  52. package/dist/boxes/webm/segments/parse-children.js +67 -57
  53. package/dist/boxes/webm/segments.d.ts +8 -3
  54. package/dist/boxes/webm/segments.js +70 -39
  55. package/dist/boxes/webm/traversal.d.ts +2 -2
  56. package/dist/buffer-iterator.d.ts +6 -1
  57. package/dist/buffer-iterator.js +24 -5
  58. package/dist/create/iso-base-media/create-iso-base-media.d.ts +1 -1
  59. package/dist/create/iso-base-media/create-iso-base-media.js +4 -9
  60. package/dist/create/matroska/cluster.d.ts +7 -1
  61. package/dist/create/matroska/cluster.js +8 -5
  62. package/dist/create/matroska/create-matroska-media.d.ts +1 -1
  63. package/dist/create/matroska/create-matroska-media.js +27 -14
  64. package/dist/create/media-fn.d.ts +1 -1
  65. package/dist/create/mp3/create-mp3.d.ts +2 -0
  66. package/dist/create/mp3/create-mp3.js +49 -0
  67. package/dist/create/wav/create-wav.d.ts +2 -0
  68. package/dist/create/wav/create-wav.js +108 -0
  69. package/dist/emit-available-info.d.ts +2 -2
  70. package/dist/emit-available-info.js +28 -13
  71. package/dist/esm/buffer.mjs +2 -2
  72. package/dist/esm/from-node.mjs +2 -1
  73. package/dist/esm/index.mjs +1513 -331
  74. package/dist/esm/web-fs.mjs +2 -2
  75. package/dist/get-audio-codec.d.ts +3 -3
  76. package/dist/get-audio-codec.js +1 -6
  77. package/dist/get-container.d.ts +3 -3
  78. package/dist/get-container.js +9 -7
  79. package/dist/get-dimensions.d.ts +3 -3
  80. package/dist/get-duration.d.ts +8 -3
  81. package/dist/get-duration.js +37 -15
  82. package/dist/get-fps.d.ts +3 -3
  83. package/dist/get-fps.js +36 -2
  84. package/dist/get-tracks.d.ts +4 -7
  85. package/dist/get-tracks.js +55 -27
  86. package/dist/get-video-codec.d.ts +5 -4
  87. package/dist/get-video-codec.js +39 -15
  88. package/dist/has-all-info.d.ts +2 -2
  89. package/dist/has-all-info.js +9 -9
  90. package/dist/index.d.ts +5 -3
  91. package/dist/index.js +5 -1
  92. package/dist/options.d.ts +17 -10
  93. package/dist/parse-media.js +43 -14
  94. package/dist/parse-result.d.ts +35 -6
  95. package/dist/parse-video.d.ts +3 -3
  96. package/dist/parse-video.js +8 -16
  97. package/dist/parser-context.d.ts +1 -0
  98. package/dist/parser-state.d.ts +11 -0
  99. package/dist/parser-state.js +30 -0
  100. package/dist/readers/from-node.js +2 -1
  101. package/dist/readers/reader.d.ts +2 -2
  102. package/dist/register-track.d.ts +13 -0
  103. package/dist/register-track.js +25 -0
  104. package/dist/version.d.ts +1 -0
  105. package/dist/version.js +5 -0
  106. package/dist/writers/buffer-implementation/writer.d.ts +2 -2
  107. package/dist/writers/buffer-implementation/writer.js +2 -2
  108. package/dist/writers/web-fs.js +2 -3
  109. package/dist/writers/writer.d.ts +5 -3
  110. package/package.json +3 -3
package/dist/options.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Dimensions } from './get-dimensions';
2
2
  import type { AudioTrack, MediaParserAudioCodec, MediaParserVideoCodec, VideoTrack } from './get-tracks';
3
3
  import type { LogLevel } from './log';
4
- import type { AnySegment } from './parse-result';
4
+ import type { Structure } from './parse-result';
5
5
  import type { InternalStats } from './parser-state';
6
6
  import type { ReaderInterface } from './readers/reader';
7
7
  import type { OnAudioTrack, OnVideoTrack } from './webcodec-sample-types';
@@ -9,7 +9,7 @@ export type KnownAudioCodecs = 'aac' | 'mp3' | 'aiff' | 'opus' | 'pcm' | 'vorbis
9
9
  export type ParseMediaFields = {
10
10
  dimensions: boolean;
11
11
  durationInSeconds: boolean;
12
- boxes: boolean;
12
+ structure: boolean;
13
13
  fps: boolean;
14
14
  videoCodec: boolean;
15
15
  audioCodec: boolean;
@@ -24,7 +24,7 @@ export type ParseMediaFields = {
24
24
  export type AllParseMediaFields = {
25
25
  dimensions: true;
26
26
  durationInSeconds: true;
27
- boxes: true;
27
+ structure: true;
28
28
  fps: true;
29
29
  videoCodec: true;
30
30
  audioCodec: true;
@@ -39,7 +39,7 @@ export type AllParseMediaFields = {
39
39
  export type Options<Fields extends ParseMediaFields> = {
40
40
  dimensions?: Fields['dimensions'];
41
41
  durationInSeconds?: Fields['durationInSeconds'];
42
- boxes?: Fields['boxes'];
42
+ structure?: Fields['structure'];
43
43
  fps?: Fields['fps'];
44
44
  videoCodec?: Fields['videoCodec'];
45
45
  audioCodec?: Fields['audioCodec'];
@@ -55,13 +55,13 @@ export type TracksField = {
55
55
  videoTracks: VideoTrack[];
56
56
  audioTracks: AudioTrack[];
57
57
  };
58
- export type ParseMediaContainer = 'mp4' | 'webm';
58
+ export type ParseMediaContainer = 'mp4' | 'webm' | 'avi';
59
59
  export type ParseMediaCallbacks<Fields extends Options<ParseMediaFields>> = (Fields['dimensions'] extends true ? {
60
60
  onDimensions?: (dimensions: Dimensions) => void;
61
61
  } : {}) & (Fields['durationInSeconds'] extends true ? {
62
62
  onDurationInSeconds?: (durationInSeconds: number | null) => void;
63
- } : {}) & (Fields['boxes'] extends true ? {
64
- onBoxes?: (boxes: AnySegment[]) => void;
63
+ } : {}) & (Fields['structure'] extends true ? {
64
+ onStructure?: (structure: Structure) => void;
65
65
  } : {}) & (Fields['fps'] extends true ? {
66
66
  onFps?: (fps: number | null) => void;
67
67
  } : {}) & (Fields['videoCodec'] extends true ? {
@@ -87,8 +87,8 @@ export type ParseMediaResult<Fields extends Options<ParseMediaFields>> = (Fields
87
87
  dimensions: Dimensions;
88
88
  } : {}) & (Fields['durationInSeconds'] extends true ? {
89
89
  durationInSeconds: number | null;
90
- } : {}) & (Fields['boxes'] extends true ? {
91
- boxes: AnySegment[];
90
+ } : {}) & (Fields['structure'] extends true ? {
91
+ structure: Structure;
92
92
  } : {}) & (Fields['fps'] extends true ? {
93
93
  fps: number | null;
94
94
  } : {}) & (Fields['videoCodec'] extends true ? {
@@ -111,12 +111,19 @@ export type ParseMediaResult<Fields extends Options<ParseMediaFields>> = (Fields
111
111
  export type ParseMediaDynamicOptions<F extends Options<ParseMediaFields>> = {
112
112
  fields?: F;
113
113
  } & ParseMediaCallbacks<F>;
114
+ export type ParseMediaProgress = {
115
+ bytes: number;
116
+ percentage: number | null;
117
+ totalBytes: number | null;
118
+ };
119
+ export type ParseMediaOnProgress = (progress: ParseMediaProgress) => void | Promise<void>;
114
120
  export type ParseMediaOptions<F extends Options<ParseMediaFields>> = {
115
- src: string | File;
121
+ src: string | Blob;
116
122
  reader?: ReaderInterface;
117
123
  onAudioTrack?: OnAudioTrack;
118
124
  onVideoTrack?: OnVideoTrack;
119
125
  signal?: AbortSignal;
120
126
  logLevel?: LogLevel;
127
+ onParseProgress?: ParseMediaOnProgress;
121
128
  } & ParseMediaDynamicOptions<F>;
122
129
  export type ParseMedia = <F extends Options<ParseMediaFields>>(options: ParseMediaOptions<F>) => Promise<ParseMediaResult<F>>;
@@ -4,10 +4,11 @@ exports.parseMedia = void 0;
4
4
  const buffer_iterator_1 = require("./buffer-iterator");
5
5
  const emit_available_info_1 = require("./emit-available-info");
6
6
  const has_all_info_1 = require("./has-all-info");
7
+ const log_1 = require("./log");
7
8
  const parse_video_1 = require("./parse-video");
8
9
  const parser_state_1 = require("./parser-state");
9
10
  const from_fetch_1 = require("./readers/from-fetch");
10
- const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.fetchReader, onAudioTrack, onVideoTrack, signal, logLevel = 'info', ...more }) => {
11
+ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.fetchReader, onAudioTrack, onVideoTrack, signal, logLevel = 'info', onParseProgress, ...more }) => {
11
12
  const state = (0, parser_state_1.makeParserState)({
12
13
  hasAudioCallbacks: onAudioTrack !== null,
13
14
  hasVideoCallbacks: onVideoTrack !== null,
@@ -23,8 +24,16 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
23
24
  const moreFields = more;
24
25
  let iterator = null;
25
26
  let parseResult = null;
27
+ // TODO: Should be possible to skip if `null` is returned
28
+ const canSkipVideoData = !onVideoTrack && !onAudioTrack;
29
+ if (canSkipVideoData) {
30
+ log_1.Log.verbose(logLevel, 'Only parsing metadata, because no onVideoTrack and onAudioTrack callbacks were passed.');
31
+ }
32
+ else {
33
+ log_1.Log.verbose(logLevel, 'Parsing video data, because onVideoTrack/onAudioTrack callbacks were passed.');
34
+ }
26
35
  const options = {
27
- canSkipVideoData: !(onAudioTrack || onVideoTrack),
36
+ canSkipVideoData,
28
37
  onAudioTrack: onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : null,
29
38
  onVideoTrack: onVideoTrack !== null && onVideoTrack !== void 0 ? onVideoTrack : null,
30
39
  parserState: state,
@@ -32,7 +41,28 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
32
41
  typeof process.env !== 'undefined' &&
33
42
  process.env.KEEP_SAMPLES === 'true'),
34
43
  supportsContentRange,
44
+ nextTrackIndex: 0,
45
+ };
46
+ const hasAllInfo = () => {
47
+ if (parseResult === null) {
48
+ return false;
49
+ }
50
+ const availableInfo = (0, has_all_info_1.getAvailableInfo)(fields !== null && fields !== void 0 ? fields : {}, parseResult, state);
51
+ return Object.values(availableInfo).every(Boolean);
52
+ };
53
+ const triggerInfoEmit = () => {
54
+ const availableInfo = (0, has_all_info_1.getAvailableInfo)(fields !== null && fields !== void 0 ? fields : {}, parseResult, state);
55
+ (0, emit_available_info_1.emitAvailableInfo)({
56
+ hasInfo: availableInfo,
57
+ moreFields,
58
+ parseResult,
59
+ state,
60
+ returnValue,
61
+ contentLength,
62
+ name,
63
+ });
35
64
  };
65
+ triggerInfoEmit();
36
66
  while (parseResult === null || parseResult.status === 'incomplete') {
37
67
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
38
68
  throw new Error('Aborted');
@@ -60,7 +90,16 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
60
90
  if (!iterator) {
61
91
  throw new Error('Unexpected null');
62
92
  }
93
+ await (onParseProgress === null || onParseProgress === void 0 ? void 0 : onParseProgress({
94
+ bytes: iterator.counter.getOffset(),
95
+ percentage: contentLength
96
+ ? iterator.counter.getOffset() / contentLength
97
+ : null,
98
+ totalBytes: contentLength,
99
+ }));
100
+ triggerInfoEmit();
63
101
  if (parseResult && parseResult.status === 'incomplete') {
102
+ log_1.Log.verbose(logLevel, 'Continuing parsing of file, currently at position', iterator.counter.getOffset(), (0, has_all_info_1.getAvailableInfo)(fields !== null && fields !== void 0 ? fields : {}, parseResult, state));
64
103
  parseResult = await parseResult.continueParsing();
65
104
  }
66
105
  else {
@@ -71,20 +110,9 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
71
110
  logLevel,
72
111
  });
73
112
  }
74
- const availableInfo = (0, has_all_info_1.getAvailableInfo)(fields !== null && fields !== void 0 ? fields : {}, parseResult, state);
75
- const hasAllInfo = Object.values(availableInfo).every(Boolean);
76
- (0, emit_available_info_1.emitAvailableInfo)({
77
- hasInfo: availableInfo,
78
- moreFields,
79
- parseResult,
80
- state,
81
- returnValue,
82
- contentLength,
83
- name,
84
- });
85
113
  // TODO Better: Check if no active listeners are registered
86
114
  // Also maybe check for canSkipVideoData
87
- if (hasAllInfo && !onVideoTrack && !onAudioTrack) {
115
+ if (hasAllInfo() && !onVideoTrack && !onAudioTrack) {
88
116
  break;
89
117
  }
90
118
  if (parseResult &&
@@ -99,6 +127,7 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
99
127
  iterator.skipTo(parseResult.skipTo, true);
100
128
  }
101
129
  }
130
+ log_1.Log.verbose(logLevel, 'Finished parsing file');
102
131
  // Force assign
103
132
  (0, emit_available_info_1.emitAvailableInfo)({
104
133
  hasInfo: Object.keys(fields !== null && fields !== void 0 ? fields : {}).reduce((acc, key) => {
@@ -25,22 +25,51 @@ import type { TkhdBox } from './boxes/iso-base-media/tkhd';
25
25
  import type { TrakBox } from './boxes/iso-base-media/trak/trak';
26
26
  import type { TrunBox } from './boxes/iso-base-media/trun';
27
27
  import type { VoidBox } from './boxes/iso-base-media/void-box';
28
+ import type { RiffBox } from './boxes/riff/riff-box';
28
29
  import type { MatroskaSegment } from './boxes/webm/segments';
29
30
  export interface RegularBox extends BaseBox {
30
31
  boxType: string;
31
32
  boxSize: number;
32
- children: AnySegment[];
33
+ children: IsoBaseMediaBox[];
33
34
  offset: number;
34
35
  type: 'regular-box';
35
36
  }
36
37
  export type IsoBaseMediaBox = RegularBox | FtypBox | MvhdBox | TkhdBox | StsdBox | MebxBox | KeysBox | MoovBox | TrakBox | SttsBox | MdhdBox | EsdsBox | MdatBox | StszBox | StcoBox | StscBox | AvccBox | HvccBox | VoidBox | StssBox | PaspBox | CttsBox | Av1CBox | TrunBox | ColorParameterBox | TfdtBox | TfhdBox;
37
- export type AnySegment = MatroskaSegment | IsoBaseMediaBox;
38
- export type ParseResult = {
38
+ export type AnySegment = MatroskaSegment | IsoBaseMediaBox | RiffBox;
39
+ export type IsoBaseMediaStructure = {
40
+ type: 'iso-base-media';
41
+ boxes: IsoBaseMediaBox[];
42
+ };
43
+ export type RiffStructure = {
44
+ type: 'riff';
45
+ boxes: RiffBox[];
46
+ };
47
+ export type MatroskaStructure = {
48
+ type: 'matroska';
49
+ boxes: MatroskaSegment[];
50
+ };
51
+ export type Structure = IsoBaseMediaStructure | RiffStructure | MatroskaStructure;
52
+ export type ParseResult<TStructure extends Structure> = {
53
+ status: 'done';
54
+ segments: TStructure;
55
+ } | {
56
+ status: 'incomplete';
57
+ segments: TStructure;
58
+ skipTo: number | null;
59
+ continueParsing: () => Promise<ParseResult<TStructure>>;
60
+ };
61
+ export type MatroskaParseResult = {
39
62
  status: 'done';
40
- segments: AnySegment[];
41
63
  } | {
42
64
  status: 'incomplete';
43
- segments: AnySegment[];
44
65
  skipTo: number | null;
45
- continueParsing: () => Promise<ParseResult>;
66
+ continueParsing: () => Promise<MatroskaParseResult>;
67
+ };
68
+ export type ExpectSegmentParseResult = {
69
+ status: 'done';
70
+ segment: MatroskaSegment;
71
+ } | {
72
+ status: 'incomplete';
73
+ segment: MatroskaSegment | null;
74
+ continueParsing: () => Promise<ExpectSegmentParseResult>;
46
75
  };
@@ -1,6 +1,6 @@
1
1
  import type { BufferIterator } from './buffer-iterator';
2
- import type { LogLevel } from './log';
3
- import type { IsoBaseMediaBox, ParseResult } from './parse-result';
2
+ import { type LogLevel } from './log';
3
+ import type { IsoBaseMediaBox, ParseResult, Structure } from './parse-result';
4
4
  import type { ParserContext } from './parser-context';
5
5
  export type PartialMdatBox = {
6
6
  type: 'partial-mdat-box';
@@ -20,4 +20,4 @@ export declare const parseVideo: ({ iterator, options, signal, logLevel, }: {
20
20
  options: ParserContext;
21
21
  signal: AbortSignal | null;
22
22
  logLevel: LogLevel;
23
- }) => Promise<ParseResult>;
23
+ }) => Promise<ParseResult<Structure>>;
@@ -2,28 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseVideo = void 0;
4
4
  const process_box_1 = require("./boxes/iso-base-media/process-box");
5
+ const parse_box_1 = require("./boxes/riff/parse-box");
5
6
  const parse_webm_header_1 = require("./boxes/webm/parse-webm-header");
7
+ const log_1 = require("./log");
6
8
  const parseVideo = ({ iterator, options, signal, logLevel, }) => {
7
9
  if (iterator.bytesRemaining() === 0) {
8
- return Promise.resolve({
9
- status: 'incomplete',
10
- segments: [],
11
- continueParsing: () => {
12
- return (0, exports.parseVideo)({
13
- iterator,
14
- options,
15
- signal,
16
- logLevel,
17
- });
18
- },
19
- skipTo: null,
20
- });
10
+ return Promise.reject(new Error('no bytes'));
21
11
  }
22
12
  if (iterator.isRiff()) {
23
- throw new Error('AVI files are not yet supported');
13
+ return Promise.resolve((0, parse_box_1.parseRiff)({ iterator, options }));
24
14
  }
25
15
  if (iterator.isIsoBaseMedia()) {
26
- return (0, process_box_1.parseBoxes)({
16
+ log_1.Log.verbose(logLevel, 'Detected ISO Base Media container');
17
+ return (0, process_box_1.parseIsoBaseMediaBoxes)({
27
18
  iterator,
28
19
  maxBytes: Infinity,
29
20
  allowIncompleteBoxes: true,
@@ -35,7 +26,8 @@ const parseVideo = ({ iterator, options, signal, logLevel, }) => {
35
26
  });
36
27
  }
37
28
  if (iterator.isWebm()) {
38
- return Promise.resolve((0, parse_webm_header_1.parseWebm)(iterator, options));
29
+ log_1.Log.verbose(logLevel, 'Detected Matroska container');
30
+ return (0, parse_webm_header_1.parseWebm)(iterator, options);
39
31
  }
40
32
  if (iterator.isMp3()) {
41
33
  return Promise.reject(new Error('MP3 files are not yet supported'));
@@ -7,4 +7,5 @@ export type ParserContext = {
7
7
  parserState: ParserState;
8
8
  nullifySamples: boolean;
9
9
  supportsContentRange: boolean;
10
+ nextTrackIndex: number;
10
11
  };
@@ -1,13 +1,21 @@
1
+ import type { AvcPPs, AvcProfileInfo } from './boxes/avc/parse-avc';
1
2
  import type { OnTrackEntrySegment } from './boxes/webm/segments';
2
3
  import type { TrackInfo } from './boxes/webm/segments/track-entry';
3
4
  import type { AudioOrVideoSample, OnAudioSample, OnVideoSample } from './webcodec-sample-types';
4
5
  export type InternalStats = {};
6
+ export type SpsAndPps = {
7
+ sps: AvcProfileInfo;
8
+ pps: AvcPPs;
9
+ };
10
+ type AvcProfileInfoCallback = (profile: SpsAndPps) => Promise<void>;
5
11
  export declare const makeParserState: ({ hasAudioCallbacks, hasVideoCallbacks, signal, }: {
6
12
  hasAudioCallbacks: boolean;
7
13
  hasVideoCallbacks: boolean;
8
14
  signal: AbortSignal | undefined;
9
15
  }) => {
10
16
  onTrackEntrySegment: OnTrackEntrySegment;
17
+ onProfile: (profile: SpsAndPps) => Promise<void>;
18
+ registerOnAvcProfileCallback: (callback: AvcProfileInfoCallback) => void;
11
19
  getTrackInfoByNumber: (id: number) => TrackInfo;
12
20
  registerVideoSampleCallback: (id: number, callback: OnVideoSample | null) => Promise<void>;
13
21
  setTimestampOffset: (byteOffset: number, timestamp: number) => void;
@@ -18,5 +26,8 @@ export declare const makeParserState: ({ hasAudioCallbacks, hasVideoCallbacks, s
18
26
  getInternalStats: () => {};
19
27
  getTimescale: () => number;
20
28
  setTimescale: (newTimescale: number) => void;
29
+ getSamplesForTrack: (trackId: number) => number;
30
+ getAvcProfile: () => SpsAndPps | null;
21
31
  };
22
32
  export type ParserState = ReturnType<typeof makeParserState>;
33
+ export {};
@@ -59,8 +59,23 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, signal, }) => {
59
59
  }
60
60
  return timestampMap.get(byteOffset);
61
61
  };
62
+ const samplesForTrack = {};
63
+ const profileCallbacks = [];
64
+ const registerOnAvcProfileCallback = (callback) => {
65
+ profileCallbacks.push(callback);
66
+ };
67
+ let avcProfile = null;
68
+ const onProfile = async (profile) => {
69
+ avcProfile = profile;
70
+ for (const callback of profileCallbacks) {
71
+ await callback(profile);
72
+ }
73
+ profileCallbacks.length = 0;
74
+ };
62
75
  return {
63
76
  onTrackEntrySegment,
77
+ onProfile,
78
+ registerOnAvcProfileCallback,
64
79
  getTrackInfoByNumber: (id) => trackEntries[id],
65
80
  registerVideoSampleCallback: async (id, callback) => {
66
81
  var _a;
@@ -94,6 +109,10 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, signal, }) => {
94
109
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
95
110
  throw new Error('Aborted');
96
111
  }
112
+ if (typeof samplesForTrack[trackId] === 'undefined') {
113
+ samplesForTrack[trackId] = 0;
114
+ }
115
+ samplesForTrack[trackId]++;
97
116
  const callback = audioSampleCallbacks[trackId];
98
117
  if (callback) {
99
118
  await callback(audioSample);
@@ -111,6 +130,10 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, signal, }) => {
111
130
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
112
131
  throw new Error('Aborted');
113
132
  }
133
+ if (typeof samplesForTrack[trackId] === 'undefined') {
134
+ samplesForTrack[trackId] = 0;
135
+ }
136
+ samplesForTrack[trackId]++;
114
137
  const callback = videoSampleCallbacks[trackId];
115
138
  if (callback) {
116
139
  await callback(videoSample);
@@ -127,6 +150,13 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, signal, }) => {
127
150
  getInternalStats: () => ({}),
128
151
  getTimescale,
129
152
  setTimescale,
153
+ getSamplesForTrack: (trackId) => {
154
+ var _a;
155
+ return (_a = samplesForTrack[trackId]) !== null && _a !== void 0 ? _a : 0;
156
+ },
157
+ getAvcProfile: () => {
158
+ return avcProfile;
159
+ },
130
160
  };
131
161
  };
132
162
  exports.makeParserState = makeParserState;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nodeReader = void 0;
4
4
  const fs_1 = require("fs");
5
5
  const promises_1 = require("node:fs/promises");
6
+ const path_1 = require("path");
6
7
  const stream_1 = require("stream");
7
8
  exports.nodeReader = {
8
9
  read: async (src, range, signal) => {
@@ -37,7 +38,7 @@ exports.nodeReader = {
37
38
  },
38
39
  },
39
40
  contentLength: stats.size,
40
- name: src.split('/').pop(),
41
+ name: src.split(path_1.sep).pop(),
41
42
  supportsContentRange: true,
42
43
  };
43
44
  },
@@ -8,8 +8,8 @@ type ReadResult = {
8
8
  name: string;
9
9
  supportsContentRange: boolean;
10
10
  };
11
- type ReadContent = (src: string | File, range: [number, number] | number | null, signal: AbortSignal | undefined) => Promise<ReadResult>;
12
- type GetLength = (src: string | File) => Promise<number>;
11
+ type ReadContent = (src: string | Blob, range: [number, number] | number | null, signal: AbortSignal | undefined) => Promise<ReadResult>;
12
+ type GetLength = (src: string | Blob) => Promise<number>;
13
13
  export type ReaderInterface = {
14
14
  read: ReadContent;
15
15
  getLength: GetLength;
@@ -0,0 +1,13 @@
1
+ import type { Track, VideoTrack } from './get-tracks';
2
+ import type { ParserContext } from './parser-context';
3
+ import type { ParserState } from './parser-state';
4
+ export declare const registerTrack: ({ state, options, track, }: {
5
+ state: ParserState;
6
+ options: ParserContext;
7
+ track: Track;
8
+ }) => Promise<void>;
9
+ export declare const registerVideoTrackWhenProfileIsAvailable: ({ options, state, track, }: {
10
+ state: ParserState;
11
+ options: ParserContext;
12
+ track: VideoTrack;
13
+ }) => void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerVideoTrackWhenProfileIsAvailable = exports.registerTrack = void 0;
4
+ const add_avc_profile_to_track_1 = require("./add-avc-profile-to-track");
5
+ const registerTrack = async ({ state, options, track, }) => {
6
+ if (track.type === 'video' && options.onVideoTrack) {
7
+ const callback = await options.onVideoTrack(track);
8
+ await state.registerVideoSampleCallback(track.trackId, callback !== null && callback !== void 0 ? callback : null);
9
+ }
10
+ if (track.type === 'audio' && options.onAudioTrack) {
11
+ const callback = await options.onAudioTrack(track);
12
+ await state.registerAudioSampleCallback(track.trackId, callback !== null && callback !== void 0 ? callback : null);
13
+ }
14
+ };
15
+ exports.registerTrack = registerTrack;
16
+ const registerVideoTrackWhenProfileIsAvailable = ({ options, state, track, }) => {
17
+ state.registerOnAvcProfileCallback(async (profile) => {
18
+ await (0, exports.registerTrack)({
19
+ options,
20
+ state,
21
+ track: (0, add_avc_profile_to_track_1.addAvcProfileToTrack)(track, profile),
22
+ });
23
+ });
24
+ };
25
+ exports.registerVideoTrackWhenProfileIsAvailable = registerVideoTrackWhenProfileIsAvailable;
@@ -0,0 +1 @@
1
+ export declare const VERSION = "4.0.232";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERSION = void 0;
4
+ // Automatically generated on publish
5
+ exports.VERSION = '4.0.232';
@@ -1,2 +1,2 @@
1
- import type { Writer } from '../writer';
2
- export declare const createContent: () => Promise<Writer>;
1
+ import type { CreateContent } from '../writer';
2
+ export declare const createContent: CreateContent;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createContent = void 0;
4
- const createContent = () => {
4
+ const createContent = ({ filename, mimeType }) => {
5
5
  const buf = new ArrayBuffer(0, {
6
6
  // TODO: Educate that the buffer is limited to 2GB
7
7
  maxByteLength: 2000000000,
@@ -34,7 +34,7 @@ const createContent = () => {
34
34
  const arr = new Uint8Array(buf);
35
35
  return Promise.resolve(
36
36
  // TODO: Unhardcode MIME type and file name
37
- new File([arr.slice()], 'hi', { type: 'video/webm' }));
37
+ new File([arr.slice()], filename, { type: mimeType }));
38
38
  },
39
39
  remove() {
40
40
  removed = true;
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canUseWebFsWriter = exports.webFsWriter = void 0;
4
- const createContent = async () => {
4
+ const createContent = async ({ filename }) => {
5
5
  const directoryHandle = await navigator.storage.getDirectory();
6
- // TODO: Unhardcode WebM
7
- const filename = `media-parser-${Math.random().toString().replace('0.', '')}.webm`;
6
+ directoryHandle.removeEntry(filename);
8
7
  const fileHandle = await directoryHandle.getFileHandle(filename, {
9
8
  create: true,
10
9
  });
@@ -1,13 +1,15 @@
1
1
  export type Writer = {
2
2
  write: (arr: Uint8Array) => Promise<void>;
3
- save: () => Promise<File | Blob>;
3
+ save: () => Promise<Blob>;
4
4
  getWrittenByteCount: () => number;
5
5
  updateDataAt: (position: number, data: Uint8Array) => Promise<void>;
6
6
  waitForFinish: () => Promise<void>;
7
7
  remove: () => Promise<void>;
8
8
  };
9
- type CreateContent = () => Promise<Writer>;
9
+ export type CreateContent = (options: {
10
+ filename: string;
11
+ mimeType: string;
12
+ }) => Promise<Writer>;
10
13
  export type WriterInterface = {
11
14
  createContent: CreateContent;
12
15
  };
13
- export {};
package/package.json CHANGED
@@ -3,14 +3,14 @@
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.230",
6
+ "version": "4.0.232",
7
7
  "main": "dist/index.js",
8
8
  "sideEffects": false,
9
9
  "devDependencies": {
10
10
  "@types/wicg-file-system-access": "2023.10.5",
11
11
  "eslint": "9.14.0",
12
- "@remotion/example-videos": "4.0.230",
13
- "@remotion/eslint-config-internal": "4.0.230"
12
+ "@remotion/example-videos": "4.0.232",
13
+ "@remotion/eslint-config-internal": "4.0.232"
14
14
  },
15
15
  "publishConfig": {
16
16
  "access": "public"