@remotion/renderer 4.0.0-alpha13 → 4.0.0-alpha14
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.
- package/dist/assets/download-and-map-assets-to-file.d.ts +6 -4
- package/dist/assets/download-and-map-assets-to-file.js +30 -6
- package/dist/assets/download-file.d.ts +2 -2
- package/dist/assets/download-map.d.ts +3 -3
- package/dist/assets/ffmpeg-volume-expression.d.ts +2 -2
- package/dist/assets/get-audio-channels.d.ts +1 -0
- package/dist/assets/get-audio-channels.js +10 -5
- package/dist/assets/get-video-stream-duration.d.ts +9 -0
- package/dist/assets/get-video-stream-duration.js +71 -0
- package/dist/assets/read-file.js +1 -1
- package/dist/assets/types.d.ts +4 -4
- package/dist/audio-codec.d.ts +2 -2
- package/dist/browser/Browser.d.ts +9 -9
- package/dist/browser/Browser.js +26 -32
- package/dist/browser/BrowserFetcher.d.ts +1 -1
- package/dist/browser/BrowserPage.d.ts +11 -2
- package/dist/browser/BrowserPage.js +47 -12
- package/dist/browser/BrowserRunner.js +19 -2
- package/dist/browser/ConsoleMessage.d.ts +1 -1
- package/dist/browser/DOMWorld.js +8 -8
- package/dist/browser/EvalTypes.d.ts +7 -7
- package/dist/browser/FrameManager.js +11 -11
- package/dist/browser/JSHandle.js +14 -14
- package/dist/browser/LaunchOptions.d.ts +1 -1
- package/dist/browser/Launcher.js +0 -1
- package/dist/browser/LifecycleWatcher.d.ts +1 -1
- package/dist/browser/NetworkEventManager.d.ts +4 -4
- package/dist/browser/NodeWebSocketTransport.js +16 -16
- package/dist/browser/Product.d.ts +1 -1
- package/dist/browser/Target.d.ts +2 -1
- package/dist/browser/Target.js +8 -2
- package/dist/browser/devtools-types.d.ts +10 -10
- package/dist/browser/mitt/index.d.ts +6 -6
- package/dist/browser/revisions.d.ts +1 -1
- package/dist/browser/should-log-message.d.ts +24 -0
- package/dist/browser/should-log-message.js +72 -0
- package/dist/browser-executable.d.ts +1 -1
- package/dist/browser-log.d.ts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/calculate-sar-dar-pixels.d.ts +9 -0
- package/dist/calculate-sar-dar-pixels.js +19 -0
- package/dist/chalk/index.d.ts +4 -4
- package/dist/codec-supports-media.d.ts +1 -1
- package/dist/codec.d.ts +2 -2
- package/dist/combine-videos.d.ts +1 -1
- package/dist/compositor/compose.d.ts +11 -2
- package/dist/compositor/compose.js +15 -4
- package/dist/compositor/compositor.d.ts +1 -1
- package/dist/compositor/compositor.js +1 -1
- package/dist/compositor/payloads.d.ts +5 -5
- package/dist/create-ffmpeg-complex-filter.d.ts +4 -1
- package/dist/crf.d.ts +1 -1
- package/dist/determine-resize-params.d.ts +1 -0
- package/dist/determine-resize-params.js +10 -0
- package/dist/determine-vcodec-ffmpeg-flags.d.ts +2 -0
- package/dist/determine-vcodec-ffmpeg-flags.js +13 -0
- package/dist/ensure-ffmpeg.d.ts +18 -0
- package/dist/ensure-ffmpeg.js +58 -0
- package/dist/ensure-presentation-timestamp.d.ts +15 -0
- package/dist/ensure-presentation-timestamp.js +88 -0
- package/dist/error-handling/symbolicate-error.js +4 -2
- package/dist/extract-frame-from-video.d.ts +16 -0
- package/dist/extract-frame-from-video.js +191 -0
- package/dist/ffmpeg-executable.d.ts +1 -0
- package/dist/ffmpeg-executable.js +2 -0
- package/dist/ffmpeg-flags.d.ts +31 -0
- package/dist/ffmpeg-flags.js +245 -0
- package/dist/ffmpeg-override.d.ts +1 -1
- package/dist/file-extensions.d.ts +1 -1
- package/dist/frame-range.d.ts +1 -1
- package/dist/frame-to-ffmpeg-timestamp.d.ts +1 -0
- package/dist/frame-to-ffmpeg-timestamp.js +8 -0
- package/dist/get-browser-instance.d.ts +6 -1
- package/dist/get-browser-instance.js +9 -4
- package/dist/get-can-extract-frames-fast.d.ts +14 -0
- package/dist/get-can-extract-frames-fast.js +71 -0
- package/dist/get-compositions.d.ts +18 -11
- package/dist/get-compositions.js +66 -49
- package/dist/get-frame-of-video-slow.d.ts +17 -0
- package/dist/get-frame-of-video-slow.js +72 -0
- package/dist/get-frame-padded-index.d.ts +1 -1
- package/dist/get-video-info.d.ts +8 -0
- package/dist/get-video-info.js +59 -0
- package/dist/image-format.d.ts +3 -3
- package/dist/index.d.ts +110 -21
- package/dist/index.js +25 -13
- package/dist/is-beyond-last-frame.d.ts +3 -0
- package/dist/is-beyond-last-frame.js +12 -0
- package/dist/jpeg-quality.d.ts +1 -0
- package/dist/jpeg-quality.js +2 -1
- package/dist/last-frame-from-video-cache.d.ts +17 -0
- package/dist/last-frame-from-video-cache.js +55 -0
- package/dist/legacy-webpack-config.d.ts +9 -0
- package/dist/legacy-webpack-config.js +13 -0
- package/dist/log-level.d.ts +1 -1
- package/dist/logger.d.ts +4 -2
- package/dist/logger.js +12 -5
- package/dist/make-cancel-signal.d.ts +2 -2
- package/dist/merge-audio-track.d.ts +1 -1
- package/dist/mime-types.js +1 -1
- package/dist/offthread-video-server.d.ts +36 -4
- package/dist/offthread-video-server.js +48 -4
- package/dist/open-browser.d.ts +19 -10
- package/dist/open-browser.js +34 -21
- package/dist/options/option.d.ts +1 -1
- package/dist/parse-browser-error-stack.d.ts +1 -1
- package/dist/perf.d.ts +1 -1
- package/dist/pixel-format.d.ts +1 -1
- package/dist/prepare-server.d.ts +20 -8
- package/dist/prepare-server.js +52 -8
- package/dist/preprocess-audio-track.d.ts +2 -2
- package/dist/prespawn-ffmpeg.d.ts +1 -1
- package/dist/prespawn-ffmpeg.js +7 -7
- package/dist/prores-profile.d.ts +1 -1
- package/dist/provide-screenshot.d.ts +0 -1
- package/dist/puppeteer-screenshot.d.ts +0 -1
- package/dist/puppeteer-screenshot.js +1 -2
- package/dist/quality.d.ts +1 -0
- package/dist/quality.js +21 -0
- package/dist/render-frames.d.ts +32 -11
- package/dist/render-frames.js +112 -77
- package/dist/render-media.d.ts +50 -21
- package/dist/render-media.js +249 -197
- package/dist/render-still.d.ts +33 -18
- package/dist/render-still.js +71 -43
- package/dist/replace-browser.d.ts +1 -1
- package/dist/screenshot-dom-element.d.ts +0 -1
- package/dist/screenshot-task.d.ts +0 -1
- package/dist/select-composition.d.ts +19 -11
- package/dist/select-composition.js +79 -42
- package/dist/serve-static.d.ts +2 -3
- package/dist/serve-static.js +2 -4
- package/dist/set-props-and-env.d.ts +1 -1
- package/dist/stitch-frames-to-video.d.ts +32 -11
- package/dist/stitch-frames-to-video.js +121 -99
- package/dist/stringify-ffmpeg-filter.d.ts +2 -2
- package/dist/symbolicate-stacktrace.d.ts +16 -3
- package/dist/symbolicate-stacktrace.js +49 -24
- package/dist/take-frame-and-compose.d.ts +0 -1
- package/dist/truthy.d.ts +1 -1
- package/dist/try-to-extract-frame-of-video-fast.d.ts +12 -0
- package/dist/try-to-extract-frame-of-video-fast.js +55 -0
- package/dist/types.d.ts +2 -2
- package/dist/validate-ffmpeg.d.ts +7 -0
- package/dist/validate-ffmpeg.js +77 -0
- package/dist/validate-opengl-renderer.d.ts +1 -1
- package/dist/warn-about-ffmpeg-version.d.ts +5 -0
- package/dist/warn-about-ffmpeg-version.js +37 -0
- package/package.json +11 -11
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.stitchFramesToVideo = void 0;
|
|
29
|
+
exports.stitchFramesToVideo = exports.internalStitchFramesToVideo = void 0;
|
|
30
30
|
const node_fs_1 = __importStar(require("node:fs"));
|
|
31
31
|
const node_path_1 = __importDefault(require("node:path"));
|
|
32
32
|
const remotion_1 = require("remotion");
|
|
@@ -100,101 +100,97 @@ const getAssetsData = async ({ assets, onDownload, fps, expectedFrames, verbose,
|
|
|
100
100
|
});
|
|
101
101
|
return outName;
|
|
102
102
|
};
|
|
103
|
-
const
|
|
104
|
-
var _a
|
|
105
|
-
remotion_1.Internals.validateDimension(
|
|
106
|
-
remotion_1.Internals.validateDimension(
|
|
107
|
-
const codec = (_a = options.codec) !== null && _a !== void 0 ? _a : codec_1.DEFAULT_CODEC;
|
|
103
|
+
const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec, cancelSignal, codec, crf, dir, enforceAudioTrack, ffmpegOverride, force, fps, height, indent, muted, onDownload, outputLocation, pixelFormat, preEncodedFileLocation, preferLossless, proResProfile, verbose, videoBitrate, width, numberOfGifLoops, onProgress, }, remotionRoot) => {
|
|
104
|
+
var _a;
|
|
105
|
+
remotion_1.Internals.validateDimension(height, 'height', 'passed to `stitchFramesToVideo()`');
|
|
106
|
+
remotion_1.Internals.validateDimension(width, 'width', 'passed to `stitchFramesToVideo()`');
|
|
108
107
|
(0, validate_even_dimensions_with_codec_1.validateEvenDimensionsWithCodec)({
|
|
109
|
-
width
|
|
110
|
-
height
|
|
108
|
+
width,
|
|
109
|
+
height,
|
|
111
110
|
codec,
|
|
112
111
|
scale: 1,
|
|
113
112
|
});
|
|
114
113
|
(0, prores_profile_1.validateSelectedCodecAndProResCombination)({
|
|
115
114
|
codec,
|
|
116
|
-
proResProfile
|
|
115
|
+
proResProfile,
|
|
117
116
|
});
|
|
118
|
-
(0, validate_videobitrate_1.validateBitrate)(
|
|
119
|
-
(0, validate_videobitrate_1.validateBitrate)(
|
|
120
|
-
remotion_1.Internals.validateFps(
|
|
121
|
-
const pixelFormat = (_b = options.pixelFormat) !== null && _b !== void 0 ? _b : pixel_format_1.DEFAULT_PIXEL_FORMAT;
|
|
117
|
+
(0, validate_videobitrate_1.validateBitrate)(audioBitrate, 'audioBitrate');
|
|
118
|
+
(0, validate_videobitrate_1.validateBitrate)(videoBitrate, 'videoBitrate');
|
|
119
|
+
remotion_1.Internals.validateFps(fps, 'in `stitchFramesToVideo()`', false);
|
|
122
120
|
const encoderName = (0, get_codec_name_1.getCodecName)(codec);
|
|
123
|
-
const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec,
|
|
121
|
+
const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec, proResProfile);
|
|
124
122
|
const mediaSupport = (0, codec_supports_media_1.codecSupportsMedia)(codec);
|
|
125
123
|
const shouldRenderAudio = mediaSupport.audio &&
|
|
126
|
-
(
|
|
127
|
-
|
|
128
|
-
!options.muted;
|
|
124
|
+
(assetsInfo.assets.flat(1).length > 0 || enforceAudioTrack) &&
|
|
125
|
+
!muted;
|
|
129
126
|
const shouldRenderVideo = mediaSupport.video;
|
|
130
127
|
if (!shouldRenderAudio && !shouldRenderVideo) {
|
|
131
128
|
throw new Error('The output format has neither audio nor video. This can happen if you are rendering an audio codec and the output file has no audio or the muted flag was passed.');
|
|
132
129
|
}
|
|
133
130
|
// Explanation: https://github.com/remotion-dev/remotion/issues/1647
|
|
134
|
-
const resolvedAudioCodec =
|
|
131
|
+
const resolvedAudioCodec = preferLossless
|
|
135
132
|
? (0, audio_codec_1.getDefaultAudioCodec)({ codec, preferLossless: true })
|
|
136
|
-
:
|
|
137
|
-
const tempFile =
|
|
133
|
+
: audioCodec !== null && audioCodec !== void 0 ? audioCodec : (0, audio_codec_1.getDefaultAudioCodec)({ codec, preferLossless: false });
|
|
134
|
+
const tempFile = outputLocation
|
|
138
135
|
? null
|
|
139
|
-
: node_path_1.default.join(
|
|
136
|
+
: node_path_1.default.join(assetsInfo.downloadMap.stitchFrames, `out.${(0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, resolvedAudioCodec)}`);
|
|
140
137
|
logger_1.Log.verboseAdvanced({
|
|
141
|
-
indent
|
|
142
|
-
logLevel:
|
|
143
|
-
tag: '
|
|
138
|
+
indent,
|
|
139
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
140
|
+
tag: 'stitchFramesToVideo()',
|
|
144
141
|
}, 'encoder', encoderName);
|
|
145
142
|
logger_1.Log.verboseAdvanced({
|
|
146
|
-
indent
|
|
147
|
-
logLevel:
|
|
148
|
-
tag: '
|
|
143
|
+
indent,
|
|
144
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
145
|
+
tag: 'stitchFramesToVideo()',
|
|
149
146
|
}, 'audioCodec', resolvedAudioCodec);
|
|
150
147
|
logger_1.Log.verboseAdvanced({
|
|
151
|
-
indent
|
|
152
|
-
logLevel:
|
|
153
|
-
tag: '
|
|
148
|
+
indent,
|
|
149
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
150
|
+
tag: 'stitchFramesToVideo()',
|
|
154
151
|
}, 'pixelFormat', pixelFormat);
|
|
155
152
|
logger_1.Log.verboseAdvanced({
|
|
156
|
-
indent
|
|
157
|
-
logLevel:
|
|
158
|
-
tag: '
|
|
153
|
+
indent,
|
|
154
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
155
|
+
tag: 'stitchFramesToVideo()',
|
|
159
156
|
}, 'codec', codec);
|
|
160
157
|
logger_1.Log.verboseAdvanced({
|
|
161
|
-
indent
|
|
162
|
-
logLevel:
|
|
163
|
-
tag: '
|
|
158
|
+
indent,
|
|
159
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
160
|
+
tag: 'stitchFramesToVideo()',
|
|
164
161
|
}, 'shouldRenderAudio', shouldRenderAudio);
|
|
165
162
|
logger_1.Log.verboseAdvanced({
|
|
166
|
-
indent
|
|
167
|
-
logLevel:
|
|
168
|
-
tag: '
|
|
163
|
+
indent,
|
|
164
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
165
|
+
tag: 'stitchFramesToVideo()',
|
|
169
166
|
}, 'shouldRenderVideo', shouldRenderVideo);
|
|
170
167
|
logger_1.Log.verboseAdvanced({
|
|
171
|
-
indent
|
|
172
|
-
logLevel:
|
|
173
|
-
tag: '
|
|
168
|
+
indent,
|
|
169
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
170
|
+
tag: 'stitchFramesToVideo()',
|
|
174
171
|
}, 'proResProfileName', proResProfileName);
|
|
175
172
|
(0, crf_1.validateQualitySettings)({
|
|
176
|
-
crf
|
|
173
|
+
crf,
|
|
177
174
|
codec,
|
|
178
|
-
videoBitrate
|
|
175
|
+
videoBitrate,
|
|
179
176
|
});
|
|
180
177
|
(0, pixel_format_1.validateSelectedPixelFormatAndCodecCombination)(pixelFormat, codec);
|
|
181
|
-
const expectedFrames =
|
|
178
|
+
const expectedFrames = assetsInfo.assets.length;
|
|
182
179
|
const updateProgress = (preStitchProgress, muxProgress) => {
|
|
183
|
-
var _a;
|
|
184
180
|
const totalFrameProgress = 0.5 * preStitchProgress * expectedFrames + muxProgress * 0.5;
|
|
185
|
-
|
|
181
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(Math.round(totalFrameProgress));
|
|
186
182
|
};
|
|
187
183
|
const audio = shouldRenderAudio
|
|
188
184
|
? await getAssetsData({
|
|
189
|
-
assets:
|
|
190
|
-
onDownload
|
|
191
|
-
fps
|
|
185
|
+
assets: assetsInfo.assets,
|
|
186
|
+
onDownload,
|
|
187
|
+
fps,
|
|
192
188
|
expectedFrames,
|
|
193
|
-
verbose
|
|
189
|
+
verbose,
|
|
194
190
|
onProgress: (prog) => updateProgress(prog, 0),
|
|
195
|
-
downloadMap:
|
|
191
|
+
downloadMap: assetsInfo.downloadMap,
|
|
196
192
|
remotionRoot,
|
|
197
|
-
indent
|
|
193
|
+
indent,
|
|
198
194
|
})
|
|
199
195
|
: null;
|
|
200
196
|
if (mediaSupport.audio && !mediaSupport.video) {
|
|
@@ -208,15 +204,15 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
208
204
|
(0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec),
|
|
209
205
|
// Set bitrate up to 320k, for aac it might effectively be lower
|
|
210
206
|
'-b:a',
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
207
|
+
audioBitrate !== null && audioBitrate !== void 0 ? audioBitrate : '320k',
|
|
208
|
+
force ? '-y' : null,
|
|
209
|
+
outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile,
|
|
214
210
|
].filter(remotion_1.Internals.truthy));
|
|
215
|
-
|
|
211
|
+
cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
|
|
216
212
|
ffmpegTask.kill();
|
|
217
213
|
});
|
|
218
214
|
await ffmpegTask;
|
|
219
|
-
|
|
215
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(expectedFrames);
|
|
220
216
|
if (audio) {
|
|
221
217
|
(0, delete_directory_1.deleteDirectory)(node_path_1.default.dirname(audio));
|
|
222
218
|
}
|
|
@@ -233,33 +229,30 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
233
229
|
resolve(null);
|
|
234
230
|
}
|
|
235
231
|
});
|
|
236
|
-
(0, delete_directory_1.deleteDirectory)(
|
|
232
|
+
(0, delete_directory_1.deleteDirectory)(assetsInfo.downloadMap.stitchFrames);
|
|
237
233
|
return {
|
|
238
234
|
getLogs: () => '',
|
|
239
235
|
task: Promise.resolve(file),
|
|
240
236
|
};
|
|
241
237
|
}
|
|
242
238
|
const ffmpegArgs = [
|
|
243
|
-
...(
|
|
244
|
-
? [['-i',
|
|
239
|
+
...(preEncodedFileLocation
|
|
240
|
+
? [['-i', preEncodedFileLocation]]
|
|
245
241
|
: [
|
|
246
|
-
['-r', String(
|
|
242
|
+
['-r', String(fps)],
|
|
247
243
|
['-f', 'image2'],
|
|
248
|
-
['-s', `${
|
|
249
|
-
['-start_number', String(
|
|
250
|
-
['-i',
|
|
244
|
+
['-s', `${width}x${height}`],
|
|
245
|
+
['-start_number', String(assetsInfo.firstFrameIndex)],
|
|
246
|
+
['-i', assetsInfo.imageSequenceName],
|
|
251
247
|
]),
|
|
252
248
|
audio ? ['-i', audio] : null,
|
|
253
|
-
|
|
249
|
+
numberOfGifLoops === null
|
|
254
250
|
? null
|
|
255
|
-
: [
|
|
256
|
-
'-loop',
|
|
257
|
-
(0, convert_number_of_gif_loops_to_ffmpeg_1.convertNumberOfGifLoopsToFfmpegSyntax)((_4 = options.numberOfGifLoops) !== null && _4 !== void 0 ? _4 : null),
|
|
258
|
-
],
|
|
251
|
+
: ['-loop', (0, convert_number_of_gif_loops_to_ffmpeg_1.convertNumberOfGifLoopsToFfmpegSyntax)(numberOfGifLoops)],
|
|
259
252
|
// -c:v is the same as -vcodec as -codec:video
|
|
260
253
|
// and specified the video codec.
|
|
261
254
|
['-c:v', encoderName],
|
|
262
|
-
...(
|
|
255
|
+
...(preEncodedFileLocation
|
|
263
256
|
? []
|
|
264
257
|
: [
|
|
265
258
|
proResProfileName ? ['-profile:v', proResProfileName] : null,
|
|
@@ -268,8 +261,8 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
268
261
|
// transparent WebM generation doesn't work
|
|
269
262
|
pixelFormat === 'yuva420p' ? ['-auto-alt-ref', '0'] : null,
|
|
270
263
|
...(0, crf_1.validateQualitySettings)({
|
|
271
|
-
crf
|
|
272
|
-
videoBitrate
|
|
264
|
+
crf,
|
|
265
|
+
videoBitrate,
|
|
273
266
|
codec,
|
|
274
267
|
}),
|
|
275
268
|
]),
|
|
@@ -278,7 +271,7 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
278
271
|
? ['-c:a', (0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec)]
|
|
279
272
|
: null,
|
|
280
273
|
// Set max bitrate up to 1024kbps, will choose lower if that's too much
|
|
281
|
-
resolvedAudioCodec ? ['-b:a',
|
|
274
|
+
resolvedAudioCodec ? ['-b:a', audioBitrate || '512K'] : null,
|
|
282
275
|
// Ignore metadata that may come from remote media
|
|
283
276
|
['-map_metadata', '-1'],
|
|
284
277
|
[
|
|
@@ -286,36 +279,36 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
286
279
|
`comment=` +
|
|
287
280
|
[`Made with Remotion`, packageJson ? packageJson.version : null].join(' '),
|
|
288
281
|
],
|
|
289
|
-
|
|
290
|
-
|
|
282
|
+
force ? '-y' : null,
|
|
283
|
+
outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile,
|
|
291
284
|
];
|
|
292
285
|
const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
|
|
293
|
-
const finalFfmpegString =
|
|
294
|
-
?
|
|
286
|
+
const finalFfmpegString = ffmpegOverride
|
|
287
|
+
? ffmpegOverride({ type: 'stitcher', args: ffmpegString })
|
|
295
288
|
: ffmpegString;
|
|
296
289
|
logger_1.Log.verboseAdvanced({
|
|
297
|
-
indent:
|
|
298
|
-
logLevel:
|
|
299
|
-
tag: '
|
|
290
|
+
indent: indent !== null && indent !== void 0 ? indent : false,
|
|
291
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
292
|
+
tag: 'stitchFramesToVideo()',
|
|
300
293
|
}, 'Generated final FFMPEG command:');
|
|
301
294
|
logger_1.Log.verboseAdvanced({
|
|
302
|
-
indent
|
|
303
|
-
logLevel:
|
|
304
|
-
tag: '
|
|
295
|
+
indent,
|
|
296
|
+
logLevel: verbose ? 'verbose' : 'info',
|
|
297
|
+
tag: 'stitchFramesToVideo()',
|
|
305
298
|
}, finalFfmpegString.join(' '));
|
|
306
299
|
const task = (0, call_ffmpeg_1.callFf)('ffmpeg', finalFfmpegString, {
|
|
307
|
-
cwd:
|
|
300
|
+
cwd: dir,
|
|
308
301
|
});
|
|
309
|
-
|
|
302
|
+
cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
|
|
310
303
|
task.kill();
|
|
311
304
|
});
|
|
312
305
|
let ffmpegOutput = '';
|
|
313
306
|
let isFinished = false;
|
|
314
|
-
(
|
|
307
|
+
(_a = task.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
315
308
|
var _a;
|
|
316
309
|
const str = data.toString();
|
|
317
310
|
ffmpegOutput += str;
|
|
318
|
-
if (
|
|
311
|
+
if (onProgress) {
|
|
319
312
|
const parsed = (0, parse_ffmpeg_progress_1.parseFfmpegProgress)(str);
|
|
320
313
|
// FFMPEG bug: In some cases, FFMPEG does hang after it is finished with it's job
|
|
321
314
|
// Example repo: https://github.com/JonnyBurger/ffmpeg-repro (access can be given upon request)
|
|
@@ -335,9 +328,9 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
335
328
|
});
|
|
336
329
|
return {
|
|
337
330
|
task: task.then(() => {
|
|
338
|
-
(0, delete_directory_1.deleteDirectory)(
|
|
331
|
+
(0, delete_directory_1.deleteDirectory)(assetsInfo.downloadMap.audioPreprocessing);
|
|
339
332
|
if (tempFile === null) {
|
|
340
|
-
(0, delete_directory_1.deleteDirectory)(
|
|
333
|
+
(0, delete_directory_1.deleteDirectory)(assetsInfo.downloadMap.stitchFrames);
|
|
341
334
|
return null;
|
|
342
335
|
}
|
|
343
336
|
return node_fs_1.promises
|
|
@@ -346,7 +339,7 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
346
339
|
return Promise.all([
|
|
347
340
|
file,
|
|
348
341
|
(0, delete_directory_1.deleteDirectory)(node_path_1.default.dirname(tempFile)),
|
|
349
|
-
(0, delete_directory_1.deleteDirectory)(
|
|
342
|
+
(0, delete_directory_1.deleteDirectory)(assetsInfo.downloadMap.stitchFrames),
|
|
350
343
|
]);
|
|
351
344
|
})
|
|
352
345
|
.then(([file]) => file);
|
|
@@ -354,18 +347,13 @@ const spawnFfmpeg = async (options, remotionRoot) => {
|
|
|
354
347
|
getLogs: () => ffmpegOutput,
|
|
355
348
|
};
|
|
356
349
|
};
|
|
357
|
-
|
|
358
|
-
* @description Takes a series of images and audio information generated by renderFrames() and encodes it to a video.
|
|
359
|
-
* @see [Documentation](https://www.remotion.dev/docs/renderer/stitch-frames-to-video)
|
|
360
|
-
*/
|
|
361
|
-
const stitchFramesToVideo = async (options) => {
|
|
362
|
-
var _a, _b;
|
|
350
|
+
const internalStitchFramesToVideo = async (options) => {
|
|
363
351
|
const remotionRoot = (0, find_closest_package_json_1.findRemotionRoot)();
|
|
364
|
-
|
|
352
|
+
(0, does_have_m2_bug_1.warnAboutM2Bug)(options.codec, options.pixelFormat);
|
|
353
|
+
const { task, getLogs } = await innerStitchFramesToVideo(options, remotionRoot);
|
|
365
354
|
const happyPath = task.catch(() => {
|
|
366
355
|
throw new Error(getLogs());
|
|
367
356
|
});
|
|
368
|
-
(0, does_have_m2_bug_1.warnAboutM2Bug)((_a = options.codec) !== null && _a !== void 0 ? _a : null, (_b = options.pixelFormat) !== null && _b !== void 0 ? _b : null);
|
|
369
357
|
return Promise.race([
|
|
370
358
|
happyPath,
|
|
371
359
|
new Promise((_resolve, reject) => {
|
|
@@ -376,4 +364,38 @@ const stitchFramesToVideo = async (options) => {
|
|
|
376
364
|
}),
|
|
377
365
|
]);
|
|
378
366
|
};
|
|
367
|
+
exports.internalStitchFramesToVideo = internalStitchFramesToVideo;
|
|
368
|
+
/**
|
|
369
|
+
* @description Takes a series of images and audio information generated by renderFrames() and encodes it to a video.
|
|
370
|
+
* @see [Documentation](https://www.remotion.dev/docs/renderer/stitch-frames-to-video)
|
|
371
|
+
*/
|
|
372
|
+
const stitchFramesToVideo = ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, dir, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, }) => {
|
|
373
|
+
return (0, exports.internalStitchFramesToVideo)({
|
|
374
|
+
assetsInfo,
|
|
375
|
+
audioBitrate: audioBitrate !== null && audioBitrate !== void 0 ? audioBitrate : null,
|
|
376
|
+
audioCodec: audioCodec !== null && audioCodec !== void 0 ? audioCodec : null,
|
|
377
|
+
cancelSignal: cancelSignal !== null && cancelSignal !== void 0 ? cancelSignal : null,
|
|
378
|
+
codec: codec !== null && codec !== void 0 ? codec : codec_1.DEFAULT_CODEC,
|
|
379
|
+
crf: crf !== null && crf !== void 0 ? crf : null,
|
|
380
|
+
dir,
|
|
381
|
+
enforceAudioTrack: enforceAudioTrack !== null && enforceAudioTrack !== void 0 ? enforceAudioTrack : false,
|
|
382
|
+
ffmpegOverride: ffmpegOverride !== null && ffmpegOverride !== void 0 ? ffmpegOverride : null,
|
|
383
|
+
force,
|
|
384
|
+
fps,
|
|
385
|
+
height,
|
|
386
|
+
indent: false,
|
|
387
|
+
muted: muted !== null && muted !== void 0 ? muted : false,
|
|
388
|
+
numberOfGifLoops: numberOfGifLoops !== null && numberOfGifLoops !== void 0 ? numberOfGifLoops : null,
|
|
389
|
+
onDownload: onDownload !== null && onDownload !== void 0 ? onDownload : undefined,
|
|
390
|
+
onProgress,
|
|
391
|
+
outputLocation: outputLocation !== null && outputLocation !== void 0 ? outputLocation : null,
|
|
392
|
+
pixelFormat: pixelFormat !== null && pixelFormat !== void 0 ? pixelFormat : pixel_format_1.DEFAULT_PIXEL_FORMAT,
|
|
393
|
+
proResProfile,
|
|
394
|
+
verbose: verbose !== null && verbose !== void 0 ? verbose : false,
|
|
395
|
+
videoBitrate: videoBitrate !== null && videoBitrate !== void 0 ? videoBitrate : null,
|
|
396
|
+
width,
|
|
397
|
+
preEncodedFileLocation: null,
|
|
398
|
+
preferLossless: false,
|
|
399
|
+
});
|
|
400
|
+
};
|
|
379
401
|
exports.stitchFramesToVideo = stitchFramesToVideo;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AssetVolume } from './assets/types';
|
|
2
|
-
export
|
|
2
|
+
export type FilterWithoutPaddingApplied = ProcessedTrack & {
|
|
3
3
|
filter: string;
|
|
4
4
|
};
|
|
5
|
-
export
|
|
5
|
+
export type ProcessedTrack = {
|
|
6
6
|
pad_start: string | null;
|
|
7
7
|
pad_end: string | null;
|
|
8
8
|
};
|
|
@@ -1,15 +1,28 @@
|
|
|
1
|
+
import type { BasicSourceMapConsumer, IndexedSourceMapConsumer } from 'source-map';
|
|
2
|
+
import { SourceMapConsumer } from 'source-map';
|
|
1
3
|
import type { UnsymbolicatedStackFrame } from './parse-browser-error-stack';
|
|
2
|
-
|
|
4
|
+
type ScriptLine = {
|
|
3
5
|
lineNumber: number;
|
|
4
6
|
content: string;
|
|
5
7
|
highlight: boolean;
|
|
6
8
|
};
|
|
7
|
-
export
|
|
9
|
+
export type SymbolicatedStackFrame = {
|
|
8
10
|
originalFunctionName: string | null;
|
|
9
11
|
originalFileName: string | null;
|
|
10
12
|
originalLineNumber: number | null;
|
|
11
13
|
originalColumnNumber: number | null;
|
|
12
14
|
originalScriptCode: ScriptLine[] | null;
|
|
13
15
|
};
|
|
14
|
-
export declare const
|
|
16
|
+
export declare const symbolicateStackTraceFromRemoteFrames: (frames: UnsymbolicatedStackFrame[]) => Promise<SymbolicatedStackFrame[]>;
|
|
17
|
+
export declare const symbolicateFromSources: (frames: UnsymbolicatedStackFrame[], mapValues: Record<string, SourceMapConsumer | null>) => SymbolicatedStackFrame[];
|
|
18
|
+
export declare const symbolicateStackFrame: (frame: UnsymbolicatedStackFrame, map: SourceMapConsumer) => {
|
|
19
|
+
originalColumnNumber: number | null;
|
|
20
|
+
originalFileName: string | null;
|
|
21
|
+
originalFunctionName: string | null;
|
|
22
|
+
originalLineNumber: number | null;
|
|
23
|
+
originalScriptCode: ScriptLine[] | null;
|
|
24
|
+
};
|
|
25
|
+
export declare const getSourceMapFromRemoteFile: (fileName: string) => Promise<IndexedSourceMapConsumer | null>;
|
|
26
|
+
export declare const getSourceMapFromLocalFile: (fileName: string) => Promise<IndexedSourceMapConsumer | null>;
|
|
27
|
+
export type AnySourceMapConsumer = BasicSourceMapConsumer | IndexedSourceMapConsumer;
|
|
15
28
|
export {};
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
6
|
+
exports.getSourceMapFromLocalFile = exports.getSourceMapFromRemoteFile = exports.symbolicateStackFrame = exports.symbolicateFromSources = exports.symbolicateStackTraceFromRemoteFrames = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
4
9
|
const source_map_1 = require("source-map");
|
|
5
10
|
const read_file_1 = require("./assets/read-file");
|
|
6
11
|
const truthy_1 = require("./truthy");
|
|
@@ -19,7 +24,7 @@ function extractSourceMapUrl(fileContents) {
|
|
|
19
24
|
}
|
|
20
25
|
return match[1].toString();
|
|
21
26
|
}
|
|
22
|
-
async
|
|
27
|
+
const getSourceMap = async (filePath, fileContents, type) => {
|
|
23
28
|
const sm = extractSourceMapUrl(fileContents);
|
|
24
29
|
if (sm === null) {
|
|
25
30
|
return null;
|
|
@@ -33,11 +38,16 @@ async function getSourceMap(fileUri, fileContents) {
|
|
|
33
38
|
const converted = window.atob(sm.substring(match2[0].length));
|
|
34
39
|
return new source_map_1.SourceMapConsumer(JSON.parse(converted));
|
|
35
40
|
}
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
if (type === 'local') {
|
|
42
|
+
// Find adjacent file: bundle.js -> bundle.js.map
|
|
43
|
+
const newFilePath = path_1.default.join(path_1.default.dirname(filePath), sm);
|
|
44
|
+
return new source_map_1.SourceMapConsumer((0, fs_1.readFileSync)(newFilePath, 'utf8'));
|
|
45
|
+
}
|
|
46
|
+
const index = filePath.lastIndexOf('/');
|
|
47
|
+
const url = filePath.substring(0, index + 1) + sm;
|
|
38
48
|
const obj = await fetchUrl(url);
|
|
39
49
|
return new source_map_1.SourceMapConsumer(obj);
|
|
40
|
-
}
|
|
50
|
+
};
|
|
41
51
|
const fetchUrl = async (url) => {
|
|
42
52
|
const res = await (0, read_file_1.readFile)(url);
|
|
43
53
|
return new Promise((resolve, reject) => {
|
|
@@ -69,42 +79,57 @@ const getOriginalPosition = (source_map, line, column) => {
|
|
|
69
79
|
});
|
|
70
80
|
return { line: result.line, column: result.column, source: result.source };
|
|
71
81
|
};
|
|
72
|
-
const
|
|
82
|
+
const symbolicateStackTraceFromRemoteFrames = async (frames) => {
|
|
73
83
|
const uniqueFileNames = [
|
|
74
84
|
...new Set(frames
|
|
75
85
|
.map((f) => f.fileName)
|
|
76
86
|
.filter((f) => f.startsWith('http://') || f.startsWith('https://'))
|
|
77
87
|
.filter(truthy_1.truthy)),
|
|
78
88
|
];
|
|
79
|
-
const maps = await Promise.all(uniqueFileNames.map(
|
|
80
|
-
|
|
81
|
-
return getSourceMap(fileName, fileContents);
|
|
89
|
+
const maps = await Promise.all(uniqueFileNames.map((fileName) => {
|
|
90
|
+
return (0, exports.getSourceMapFromRemoteFile)(fileName);
|
|
82
91
|
}));
|
|
83
92
|
const mapValues = {};
|
|
84
93
|
for (let i = 0; i < uniqueFileNames.length; i++) {
|
|
85
94
|
mapValues[uniqueFileNames[i]] = maps[i];
|
|
86
95
|
}
|
|
96
|
+
return (0, exports.symbolicateFromSources)(frames, mapValues);
|
|
97
|
+
};
|
|
98
|
+
exports.symbolicateStackTraceFromRemoteFrames = symbolicateStackTraceFromRemoteFrames;
|
|
99
|
+
const symbolicateFromSources = (frames, mapValues) => {
|
|
87
100
|
return frames
|
|
88
101
|
.map((frame) => {
|
|
89
102
|
const map = mapValues[frame.fileName];
|
|
90
103
|
if (!map) {
|
|
91
104
|
return null;
|
|
92
105
|
}
|
|
93
|
-
|
|
94
|
-
const { functionName } = frame;
|
|
95
|
-
let hasSource = null;
|
|
96
|
-
hasSource = pos.source ? map.sourceContentFor(pos.source, false) : null;
|
|
97
|
-
const scriptCode = hasSource && pos.line
|
|
98
|
-
? getLinesAround(pos.line, 3, hasSource.split('\n'))
|
|
99
|
-
: null;
|
|
100
|
-
return {
|
|
101
|
-
originalColumnNumber: pos.column,
|
|
102
|
-
originalFileName: pos.source,
|
|
103
|
-
originalFunctionName: functionName,
|
|
104
|
-
originalLineNumber: pos.line ? pos.line : null,
|
|
105
|
-
originalScriptCode: scriptCode,
|
|
106
|
-
};
|
|
106
|
+
return (0, exports.symbolicateStackFrame)(frame, map);
|
|
107
107
|
})
|
|
108
108
|
.filter(truthy_1.truthy);
|
|
109
109
|
};
|
|
110
|
-
exports.
|
|
110
|
+
exports.symbolicateFromSources = symbolicateFromSources;
|
|
111
|
+
const symbolicateStackFrame = (frame, map) => {
|
|
112
|
+
const pos = getOriginalPosition(map, frame.lineNumber, frame.columnNumber);
|
|
113
|
+
const hasSource = pos.source ? map.sourceContentFor(pos.source, false) : null;
|
|
114
|
+
const scriptCode = hasSource && pos.line
|
|
115
|
+
? getLinesAround(pos.line, 3, hasSource.split('\n'))
|
|
116
|
+
: null;
|
|
117
|
+
return {
|
|
118
|
+
originalColumnNumber: pos.column,
|
|
119
|
+
originalFileName: pos.source,
|
|
120
|
+
originalFunctionName: frame.functionName,
|
|
121
|
+
originalLineNumber: pos.line,
|
|
122
|
+
originalScriptCode: scriptCode,
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
exports.symbolicateStackFrame = symbolicateStackFrame;
|
|
126
|
+
const getSourceMapFromRemoteFile = async (fileName) => {
|
|
127
|
+
const fileContents = await fetchUrl(fileName);
|
|
128
|
+
return getSourceMap(fileName, fileContents, 'remote');
|
|
129
|
+
};
|
|
130
|
+
exports.getSourceMapFromRemoteFile = getSourceMapFromRemoteFile;
|
|
131
|
+
const getSourceMapFromLocalFile = (fileName) => {
|
|
132
|
+
const fileContents = (0, fs_1.readFileSync)(fileName, 'utf8');
|
|
133
|
+
return getSourceMap(fileName, fileContents, 'local');
|
|
134
|
+
};
|
|
135
|
+
exports.getSourceMapFromLocalFile = getSourceMapFromLocalFile;
|
package/dist/truthy.d.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OffthreadVideoImageFormat } from 'remotion';
|
|
2
|
+
import type { NeedsResize, SpecialVCodecForTransparency } from './assets/download-map';
|
|
3
|
+
import type { FfmpegExecutable } from './ffmpeg-executable';
|
|
4
|
+
export declare const tryToExtractFrameOfVideoFast: ({ ffmpegExecutable, remotionRoot, specialVCodecForTransparency, imageFormat, needsResize, src, actualOffset, }: {
|
|
5
|
+
ffmpegExecutable: FfmpegExecutable;
|
|
6
|
+
remotionRoot: string;
|
|
7
|
+
imageFormat: OffthreadVideoImageFormat;
|
|
8
|
+
needsResize: NeedsResize;
|
|
9
|
+
src: string;
|
|
10
|
+
specialVCodecForTransparency: SpecialVCodecForTransparency;
|
|
11
|
+
actualOffset: string;
|
|
12
|
+
}) => Promise<readonly [string, Buffer]>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.tryToExtractFrameOfVideoFast = void 0;
|
|
7
|
+
const execa_1 = __importDefault(require("execa"));
|
|
8
|
+
const determine_resize_params_1 = require("./determine-resize-params");
|
|
9
|
+
const determine_vcodec_ffmpeg_flags_1 = require("./determine-vcodec-ffmpeg-flags");
|
|
10
|
+
const ffmpeg_flags_1 = require("./ffmpeg-flags");
|
|
11
|
+
const truthy_1 = require("./truthy");
|
|
12
|
+
const tryToExtractFrameOfVideoFast = async ({ ffmpegExecutable, remotionRoot, specialVCodecForTransparency, imageFormat, needsResize, src, actualOffset, }) => {
|
|
13
|
+
const { stdout, stderr } = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), [
|
|
14
|
+
'-ss',
|
|
15
|
+
actualOffset,
|
|
16
|
+
...(0, determine_vcodec_ffmpeg_flags_1.determineVcodecFfmpegFlags)(specialVCodecForTransparency),
|
|
17
|
+
'-i',
|
|
18
|
+
src,
|
|
19
|
+
'-frames:v',
|
|
20
|
+
'1',
|
|
21
|
+
'-c:v',
|
|
22
|
+
imageFormat === 'jpeg' ? 'mjpeg' : 'png',
|
|
23
|
+
'-f',
|
|
24
|
+
'image2pipe',
|
|
25
|
+
...(0, determine_resize_params_1.determineResizeParams)(needsResize),
|
|
26
|
+
'-',
|
|
27
|
+
].filter(truthy_1.truthy));
|
|
28
|
+
if (!stderr) {
|
|
29
|
+
throw new Error('unexpectedly did not get stderr');
|
|
30
|
+
}
|
|
31
|
+
if (!stdout) {
|
|
32
|
+
throw new Error('unexpectedly did not get stdout');
|
|
33
|
+
}
|
|
34
|
+
const stderrChunks = [];
|
|
35
|
+
const stdoutChunks = [];
|
|
36
|
+
const stdErrString = new Promise((resolve, reject) => {
|
|
37
|
+
stderr.on('data', (d) => stderrChunks.push(d));
|
|
38
|
+
stderr.on('error', (err) => reject(err));
|
|
39
|
+
stderr.on('end', () => resolve(Buffer.concat(stderrChunks).toString('utf-8')));
|
|
40
|
+
});
|
|
41
|
+
const stdoutChunk = new Promise((resolve, reject) => {
|
|
42
|
+
stdout.on('data', (d) => {
|
|
43
|
+
stdoutChunks.push(d);
|
|
44
|
+
});
|
|
45
|
+
stdout.on('error', (err) => {
|
|
46
|
+
reject(err);
|
|
47
|
+
});
|
|
48
|
+
stdout.on('end', () => {
|
|
49
|
+
resolve(Buffer.concat(stdoutChunks));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
|
|
53
|
+
return [stdErr, stdoutBuffer];
|
|
54
|
+
};
|
|
55
|
+
exports.tryToExtractFrameOfVideoFast = tryToExtractFrameOfVideoFast;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { RenderAssetInfo } from './assets/download-map';
|
|
2
|
-
export
|
|
2
|
+
export type RenderFramesOutput = {
|
|
3
3
|
frameCount: number;
|
|
4
4
|
assetsInfo: RenderAssetInfo;
|
|
5
5
|
};
|
|
6
|
-
export
|
|
6
|
+
export type OnStartData = {
|
|
7
7
|
frameCount: number;
|
|
8
8
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const customExecutableExists: (localExecutable: string) => boolean;
|
|
2
|
+
export declare const binaryExists: (name: 'ffmpeg' | 'ffprobe') => boolean;
|
|
3
|
+
export declare const checkAndValidateFfmpegVersion: (options: {
|
|
4
|
+
ffmpegExecutable: string | null;
|
|
5
|
+
remotionRoot: string;
|
|
6
|
+
}) => Promise<void>;
|
|
7
|
+
export declare const validateFfmpeg: (customFfmpegBinary: string | null, remotionRoot: string, binary: 'ffmpeg' | 'ffprobe') => Promise<void>;
|