@remotion/renderer 4.0.0-preload.13 → 4.0.0-spawn.13
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 -0
- package/dist/assets/download-and-map-assets-to-file.js +46 -19
- package/dist/assets/ffmpeg-volume-expression.d.ts +2 -1
- package/dist/assets/ffmpeg-volume-expression.js +15 -12
- package/dist/combine-videos.js +2 -0
- package/dist/cycle-browser-tabs.d.ts +2 -1
- package/dist/cycle-browser-tabs.js +2 -2
- package/dist/extract-frame-from-video.d.ts +18 -0
- package/dist/extract-frame-from-video.js +132 -0
- package/dist/frame-to-ffmpeg-timestamp.d.ts +1 -0
- package/dist/frame-to-ffmpeg-timestamp.js +8 -0
- package/dist/get-compositions.d.ts +4 -2
- package/dist/get-compositions.js +22 -5
- package/dist/index.d.ts +7 -8
- package/dist/index.js +0 -4
- package/dist/merge-audio-track.js +2 -2
- package/dist/offthread-video-server.d.ts +13 -0
- package/dist/offthread-video-server.js +65 -0
- package/dist/open-browser.d.ts +5 -5
- package/dist/prepare-server.d.ts +12 -2
- package/dist/prepare-server.js +22 -5
- package/dist/prespawn-ffmpeg.d.ts +1 -0
- package/dist/prespawn-ffmpeg.js +11 -10
- package/dist/puppeteer-screenshot.js +5 -1
- package/dist/render-frames.d.ts +7 -2
- package/dist/render-frames.js +90 -33
- package/dist/render-media.d.ts +8 -2
- package/dist/render-media.js +52 -3
- package/dist/render-still.d.ts +7 -2
- package/dist/render-still.js +33 -9
- package/dist/serve-static.d.ts +9 -3
- package/dist/serve-static.js +16 -0
- package/dist/set-props-and-env.d.ts +3 -1
- package/dist/set-props-and-env.js +25 -3
- package/dist/stitch-frames-to-video.js +1 -0
- package/dist/stringify-ffmpeg-filter.js +3 -0
- package/dist/tmp-dir.js +5 -1
- package/package.json +4 -5
package/dist/open-browser.d.ts
CHANGED
|
@@ -10,9 +10,9 @@ export declare type ChromiumOptions = {
|
|
|
10
10
|
};
|
|
11
11
|
export declare const killAllBrowsers: () => Promise<void>;
|
|
12
12
|
export declare const openBrowser: (browser: Browser, options?: {
|
|
13
|
-
shouldDumpIo?: boolean
|
|
14
|
-
browserExecutable?: string | null
|
|
15
|
-
chromiumOptions?: ChromiumOptions
|
|
16
|
-
forceDeviceScaleFactor?: number
|
|
17
|
-
}
|
|
13
|
+
shouldDumpIo?: boolean;
|
|
14
|
+
browserExecutable?: string | null;
|
|
15
|
+
chromiumOptions?: ChromiumOptions;
|
|
16
|
+
forceDeviceScaleFactor?: number;
|
|
17
|
+
}) => Promise<puppeteer.Browser>;
|
|
18
18
|
export {};
|
package/dist/prepare-server.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { FfmpegExecutable } from 'remotion';
|
|
2
|
+
import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
3
|
+
export declare const prepareServer: ({ downloadDir, ffmpegExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }: {
|
|
4
|
+
webpackConfigOrServeUrl: string;
|
|
5
|
+
downloadDir: string;
|
|
6
|
+
onDownload: RenderMediaOnDownload;
|
|
7
|
+
onError: (err: Error) => void;
|
|
8
|
+
ffmpegExecutable: FfmpegExecutable;
|
|
9
|
+
port: number | null;
|
|
10
|
+
}) => Promise<{
|
|
2
11
|
serveUrl: string;
|
|
3
|
-
closeServer: () => Promise<
|
|
12
|
+
closeServer: () => Promise<unknown>;
|
|
13
|
+
offthreadPort: number;
|
|
4
14
|
}>;
|
package/dist/prepare-server.js
CHANGED
|
@@ -3,17 +3,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.prepareServer = void 0;
|
|
4
4
|
const is_serve_url_1 = require("./is-serve-url");
|
|
5
5
|
const serve_static_1 = require("./serve-static");
|
|
6
|
-
const prepareServer = async (webpackConfigOrServeUrl) => {
|
|
6
|
+
const prepareServer = async ({ downloadDir, ffmpegExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }) => {
|
|
7
7
|
if ((0, is_serve_url_1.isServeUrl)(webpackConfigOrServeUrl)) {
|
|
8
|
+
const { port: offthreadPort, close: closeProxy } = await (0, serve_static_1.serveStatic)(null, {
|
|
9
|
+
downloadDir,
|
|
10
|
+
onDownload,
|
|
11
|
+
onError,
|
|
12
|
+
ffmpegExecutable,
|
|
13
|
+
port,
|
|
14
|
+
});
|
|
8
15
|
return Promise.resolve({
|
|
9
16
|
serveUrl: webpackConfigOrServeUrl,
|
|
10
|
-
closeServer: () =>
|
|
17
|
+
closeServer: () => closeProxy(),
|
|
18
|
+
offthreadPort,
|
|
11
19
|
});
|
|
12
20
|
}
|
|
13
|
-
const { port, close } = await (0, serve_static_1.serveStatic)(webpackConfigOrServeUrl
|
|
21
|
+
const { port: serverPort, close } = await (0, serve_static_1.serveStatic)(webpackConfigOrServeUrl, {
|
|
22
|
+
downloadDir,
|
|
23
|
+
onDownload,
|
|
24
|
+
onError,
|
|
25
|
+
ffmpegExecutable,
|
|
26
|
+
port,
|
|
27
|
+
});
|
|
14
28
|
return Promise.resolve({
|
|
15
|
-
closeServer: () =>
|
|
16
|
-
|
|
29
|
+
closeServer: () => {
|
|
30
|
+
return close();
|
|
31
|
+
},
|
|
32
|
+
serveUrl: `http://localhost:${serverPort}`,
|
|
33
|
+
offthreadPort: serverPort,
|
|
17
34
|
});
|
|
18
35
|
};
|
|
19
36
|
exports.prepareServer = prepareServer;
|
package/dist/prespawn-ffmpeg.js
CHANGED
|
@@ -57,15 +57,13 @@ const prespawnFfmpeg = async (options) => {
|
|
|
57
57
|
// -c:v is the same as -vcodec as -codec:video
|
|
58
58
|
// and specified the video codec.
|
|
59
59
|
['-c:v', encoderName],
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
['-b:v', '1M'],
|
|
68
|
-
],
|
|
60
|
+
proResProfileName ? ['-profile:v', proResProfileName] : null,
|
|
61
|
+
supportsCrf ? ['-crf', String(crf)] : null,
|
|
62
|
+
['-pix_fmt', pixelFormat],
|
|
63
|
+
// Without explicitly disabling auto-alt-ref,
|
|
64
|
+
// transparent WebM generation doesn't work
|
|
65
|
+
pixelFormat === 'yuva420p' ? ['-auto-alt-ref', '0'] : null,
|
|
66
|
+
['-b:v', '1M'],
|
|
69
67
|
'-y',
|
|
70
68
|
options.outputLocation,
|
|
71
69
|
];
|
|
@@ -75,6 +73,9 @@ const prespawnFfmpeg = async (options) => {
|
|
|
75
73
|
}
|
|
76
74
|
const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
|
|
77
75
|
const task = (0, execa_1.default)((_f = options.ffmpegExecutable) !== null && _f !== void 0 ? _f : 'ffmpeg', ffmpegString);
|
|
76
|
+
const waitForSpawn = new Promise((resolve) => {
|
|
77
|
+
task.on('spawn', () => resolve());
|
|
78
|
+
});
|
|
78
79
|
let ffmpegOutput = '';
|
|
79
80
|
(_g = task.stderr) === null || _g === void 0 ? void 0 : _g.on('data', (data) => {
|
|
80
81
|
const str = data.toString();
|
|
@@ -86,6 +87,6 @@ const prespawnFfmpeg = async (options) => {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
});
|
|
89
|
-
return { task, getLogs: () => ffmpegOutput };
|
|
90
|
+
return { task, getLogs: () => ffmpegOutput, waitForSpawn };
|
|
90
91
|
};
|
|
91
92
|
exports.prespawnFfmpeg = prespawnFfmpeg;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/render-frames.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Browser as PuppeteerBrowser } from 'puppeteer-core';
|
|
3
|
-
import { BrowserExecutable, FrameRange, ImageFormat, SmallTCompMetadata } from 'remotion';
|
|
3
|
+
import { BrowserExecutable, FfmpegExecutable, FrameRange, ImageFormat, SmallTCompMetadata } from 'remotion';
|
|
4
4
|
import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
5
5
|
import { BrowserLog } from './browser-log';
|
|
6
6
|
import { ServeUrlOrWebpackBundle } from './legacy-webpack-config';
|
|
@@ -33,6 +33,11 @@ declare type RenderFramesOptions = {
|
|
|
33
33
|
timeoutInMilliseconds?: number;
|
|
34
34
|
chromiumOptions?: ChromiumOptions;
|
|
35
35
|
scale?: number;
|
|
36
|
+
ffmpegExecutable?: FfmpegExecutable;
|
|
37
|
+
port?: number | null;
|
|
36
38
|
} & ConfigOrComposition & ServeUrlOrWebpackBundle;
|
|
37
|
-
|
|
39
|
+
declare type ReturnTypeWithCancel = Promise<RenderFramesOutput> & {
|
|
40
|
+
cancel: () => void;
|
|
41
|
+
};
|
|
42
|
+
export declare const renderFrames: (options: RenderFramesOptions) => ReturnTypeWithCancel;
|
|
38
43
|
export {};
|
package/dist/render-frames.js
CHANGED
|
@@ -33,7 +33,12 @@ const getComposition = (others) => {
|
|
|
33
33
|
}
|
|
34
34
|
return undefined;
|
|
35
35
|
};
|
|
36
|
-
const
|
|
36
|
+
const getPool = async (pages) => {
|
|
37
|
+
const puppeteerPages = await Promise.all(pages);
|
|
38
|
+
const pool = new pool_1.Pool(puppeteerPages);
|
|
39
|
+
return pool;
|
|
40
|
+
};
|
|
41
|
+
const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, quality, imageFormat = image_format_1.DEFAULT_IMAGE_FORMAT, frameRange, puppeteerInstance, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualParallelism, downloadDir, proxyPort, }) => {
|
|
37
42
|
if (!puppeteerInstance) {
|
|
38
43
|
throw new Error('weird');
|
|
39
44
|
}
|
|
@@ -76,6 +81,8 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, inputProps
|
|
|
76
81
|
serveUrl,
|
|
77
82
|
initialFrame,
|
|
78
83
|
timeoutInMilliseconds,
|
|
84
|
+
proxyPort,
|
|
85
|
+
retriesRemaining: 2,
|
|
79
86
|
});
|
|
80
87
|
await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
|
|
81
88
|
pageFunction: (id) => {
|
|
@@ -91,23 +98,26 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, inputProps
|
|
|
91
98
|
page.off('console', logCallback);
|
|
92
99
|
return page;
|
|
93
100
|
});
|
|
94
|
-
const puppeteerPages = await Promise.all(pages);
|
|
95
|
-
const pool = new pool_1.Pool(puppeteerPages);
|
|
96
101
|
const [firstFrameIndex, lastFrameIndex] = realFrameRange;
|
|
97
102
|
// Substract one because 100 frames will be 00-99
|
|
98
103
|
// --> 2 digits
|
|
99
104
|
const filePadLength = String(lastFrameIndex).length;
|
|
100
105
|
let framesRendered = 0;
|
|
106
|
+
const poolPromise = getPool(pages);
|
|
101
107
|
onStart({
|
|
102
108
|
frameCount,
|
|
103
109
|
});
|
|
104
|
-
const downloadDir = (0, make_assets_download_dir_1.makeAssetsDownloadTmpDir)();
|
|
105
110
|
const assets = new Array(frameCount).fill(undefined);
|
|
106
|
-
|
|
111
|
+
let stopped = false;
|
|
112
|
+
const progress = Promise.all(new Array(frameCount)
|
|
107
113
|
.fill(Boolean)
|
|
108
|
-
.map((
|
|
114
|
+
.map((_x, i) => i)
|
|
109
115
|
.map(async (index) => {
|
|
116
|
+
if (stopped) {
|
|
117
|
+
throw new Error('Render was stopped');
|
|
118
|
+
}
|
|
110
119
|
const frame = realFrameRange[0] + index;
|
|
120
|
+
const pool = await poolPromise;
|
|
111
121
|
const freePage = await pool.acquire();
|
|
112
122
|
const paddedIndex = String(frame).padStart(filePadLength, '0');
|
|
113
123
|
const errorCallbackOnFrame = (err) => {
|
|
@@ -163,7 +173,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, inputProps
|
|
|
163
173
|
(0, download_and_map_assets_to_file_1.downloadAndMapAssetsToFileUrl)({
|
|
164
174
|
asset,
|
|
165
175
|
downloadDir,
|
|
166
|
-
onDownload
|
|
176
|
+
onDownload,
|
|
167
177
|
}).catch((err) => {
|
|
168
178
|
onError(new Error(`Error while downloading asset: ${err.stack}`));
|
|
169
179
|
});
|
|
@@ -175,19 +185,30 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, inputProps
|
|
|
175
185
|
freePage.off('error', errorCallbackOnFrame);
|
|
176
186
|
return compressedAssets;
|
|
177
187
|
}));
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
const prom = Object.assign(new Promise((res, rej) => {
|
|
189
|
+
progress
|
|
190
|
+
.then(() => {
|
|
191
|
+
const returnValue = {
|
|
192
|
+
assetsInfo: {
|
|
193
|
+
assets,
|
|
194
|
+
downloadDir,
|
|
195
|
+
firstFrameIndex,
|
|
196
|
+
imageSequenceName: `element-%0${filePadLength}d.${imageFormat}`,
|
|
197
|
+
},
|
|
198
|
+
frameCount,
|
|
199
|
+
};
|
|
200
|
+
res(returnValue);
|
|
201
|
+
})
|
|
202
|
+
.catch((err) => rej(err));
|
|
203
|
+
}), {
|
|
204
|
+
cancel: () => {
|
|
205
|
+
stopped = true;
|
|
184
206
|
},
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return returnValue;
|
|
207
|
+
});
|
|
208
|
+
return prom;
|
|
188
209
|
};
|
|
189
|
-
const renderFrames =
|
|
190
|
-
var _a, _b, _c;
|
|
210
|
+
const renderFrames = (options) => {
|
|
211
|
+
var _a, _b, _c, _d;
|
|
191
212
|
const composition = getComposition(options);
|
|
192
213
|
if (!composition) {
|
|
193
214
|
throw new Error('No `composition` option has been specified for renderFrames()');
|
|
@@ -202,25 +223,51 @@ const renderFrames = async (options) => {
|
|
|
202
223
|
const selectedServeUrl = (0, legacy_webpack_config_1.getServeUrlWithFallback)(options);
|
|
203
224
|
remotion_1.Internals.validateQuality(options.quality);
|
|
204
225
|
(0, validate_scale_1.validateScale)(options.scale);
|
|
205
|
-
const
|
|
206
|
-
const browserInstance = (_a = options.puppeteerInstance) !== null && _a !== void 0 ? _a : (await (0, open_browser_1.openBrowser)(remotion_1.Internals.DEFAULT_BROWSER, {
|
|
226
|
+
const browserInstance = (_a = options.puppeteerInstance) !== null && _a !== void 0 ? _a : (0, open_browser_1.openBrowser)(remotion_1.Internals.DEFAULT_BROWSER, {
|
|
207
227
|
shouldDumpIo: options.dumpBrowserLogs,
|
|
208
228
|
browserExecutable: options.browserExecutable,
|
|
209
229
|
chromiumOptions: options.chromiumOptions,
|
|
210
230
|
forceDeviceScaleFactor: (_b = options.scale) !== null && _b !== void 0 ? _b : 1,
|
|
211
|
-
})
|
|
212
|
-
const
|
|
231
|
+
});
|
|
232
|
+
const downloadDir = (0, make_assets_download_dir_1.makeAssetsDownloadTmpDir)();
|
|
233
|
+
const onDownload = (_c = options.onDownload) !== null && _c !== void 0 ? _c : (() => () => undefined);
|
|
234
|
+
const actualParallelism = (0, get_concurrency_1.getActualConcurrency)((_d = options.parallelism) !== null && _d !== void 0 ? _d : null);
|
|
213
235
|
const { stopCycling } = (0, cycle_browser_tabs_1.cycleBrowserTabs)(browserInstance, actualParallelism);
|
|
214
236
|
const openedPages = [];
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
237
|
+
let cancel = () => undefined;
|
|
238
|
+
const prom = new Promise((resolve, reject) => {
|
|
239
|
+
var _a, _b;
|
|
240
|
+
let cleanup = null;
|
|
241
|
+
const onError = (err) => reject(err);
|
|
242
|
+
Promise.all([
|
|
243
|
+
(0, prepare_server_1.prepareServer)({
|
|
244
|
+
webpackConfigOrServeUrl: selectedServeUrl,
|
|
245
|
+
downloadDir,
|
|
246
|
+
onDownload,
|
|
247
|
+
onError,
|
|
248
|
+
ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
|
|
249
|
+
port: (_b = options.port) !== null && _b !== void 0 ? _b : null,
|
|
250
|
+
}),
|
|
251
|
+
browserInstance,
|
|
252
|
+
])
|
|
253
|
+
.then(([{ serveUrl, closeServer, offthreadPort }, puppeteerInstance]) => {
|
|
254
|
+
cleanup = closeServer;
|
|
255
|
+
const renderFramesProm = innerRenderFrames({
|
|
256
|
+
...options,
|
|
257
|
+
puppeteerInstance,
|
|
258
|
+
onError,
|
|
259
|
+
pagesArray: openedPages,
|
|
260
|
+
serveUrl,
|
|
261
|
+
composition,
|
|
262
|
+
actualParallelism,
|
|
263
|
+
onDownload,
|
|
264
|
+
downloadDir,
|
|
265
|
+
proxyPort: offthreadPort,
|
|
266
|
+
});
|
|
267
|
+
cancel = () => {
|
|
268
|
+
renderFramesProm.cancel();
|
|
269
|
+
};
|
|
270
|
+
return renderFramesProm;
|
|
224
271
|
})
|
|
225
272
|
.then((res) => resolve(res))
|
|
226
273
|
.catch((err) => reject(err))
|
|
@@ -234,13 +281,23 @@ const renderFrames = async (options) => {
|
|
|
234
281
|
});
|
|
235
282
|
}
|
|
236
283
|
else {
|
|
237
|
-
|
|
284
|
+
Promise.resolve(browserInstance)
|
|
285
|
+
.then((puppeteerInstance) => {
|
|
286
|
+
return puppeteerInstance.close();
|
|
287
|
+
})
|
|
288
|
+
.catch((err) => {
|
|
238
289
|
console.log('Unable to close browser', err);
|
|
239
290
|
});
|
|
240
291
|
}
|
|
241
292
|
stopCycling();
|
|
242
|
-
|
|
293
|
+
cleanup === null || cleanup === void 0 ? void 0 : cleanup();
|
|
243
294
|
});
|
|
244
295
|
});
|
|
296
|
+
const returnType = Object.assign(prom, {
|
|
297
|
+
cancel: () => {
|
|
298
|
+
cancel();
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
return returnType;
|
|
245
302
|
};
|
|
246
303
|
exports.renderFrames = renderFrames;
|
package/dist/render-media.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Browser as PuppeteerBrowser } from 'puppeteer-core';
|
|
2
|
-
import { Codec, FfmpegExecutable, FrameRange, PixelFormat, ProResProfile, SmallTCompMetadata } from 'remotion';
|
|
2
|
+
import { BrowserExecutable, Codec, FfmpegExecutable, FrameRange, PixelFormat, ProResProfile, SmallTCompMetadata } from 'remotion';
|
|
3
3
|
import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
4
4
|
import { BrowserLog } from './browser-log';
|
|
5
5
|
import { ServeUrlOrWebpackBundle } from './legacy-webpack-config';
|
|
@@ -37,5 +37,11 @@ export declare type RenderMediaOptions = {
|
|
|
37
37
|
timeoutInMilliseconds?: number;
|
|
38
38
|
chromiumOptions?: ChromiumOptions;
|
|
39
39
|
scale?: number;
|
|
40
|
+
port?: number | null;
|
|
41
|
+
browserExecutable?: BrowserExecutable;
|
|
40
42
|
} & ServeUrlOrWebpackBundle;
|
|
41
|
-
|
|
43
|
+
declare type RenderMediaReturnType = Promise<void> & {
|
|
44
|
+
cancel: () => void;
|
|
45
|
+
};
|
|
46
|
+
export declare const renderMedia: (options: RenderMediaOptions) => RenderMediaReturnType;
|
|
47
|
+
export {};
|
package/dist/render-media.js
CHANGED
|
@@ -23,7 +23,22 @@ const tmp_dir_1 = require("./tmp-dir");
|
|
|
23
23
|
const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
|
|
24
24
|
const validate_output_filename_1 = require("./validate-output-filename");
|
|
25
25
|
const validate_scale_1 = require("./validate-scale");
|
|
26
|
-
const renderMedia =
|
|
26
|
+
const renderMedia = (options) => {
|
|
27
|
+
let resolve = () => undefined;
|
|
28
|
+
let reject = () => undefined;
|
|
29
|
+
const rejectIfCancel = new Promise((res, rej) => {
|
|
30
|
+
resolve = res;
|
|
31
|
+
reject = rej;
|
|
32
|
+
});
|
|
33
|
+
const prom = innerRenderMedia({ ...options, rejectIfCancel }).then(() => {
|
|
34
|
+
resolve();
|
|
35
|
+
});
|
|
36
|
+
return Object.assign(prom, {
|
|
37
|
+
cancel: () => reject(new Error('Render got cancelled')),
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
exports.renderMedia = renderMedia;
|
|
41
|
+
const innerRenderMedia = async ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, rejectIfCancel, ...options }) => {
|
|
27
42
|
var _a;
|
|
28
43
|
remotion_1.Internals.validateQuality(quality);
|
|
29
44
|
if (typeof crf !== 'undefined' && crf !== null) {
|
|
@@ -39,6 +54,14 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
|
|
|
39
54
|
let renderedFrames = 0;
|
|
40
55
|
let renderedDoneIn = null;
|
|
41
56
|
let encodedDoneIn = null;
|
|
57
|
+
let cancelRenderFrames = () => undefined;
|
|
58
|
+
rejectIfCancel
|
|
59
|
+
.then(() => undefined)
|
|
60
|
+
.catch((err) => {
|
|
61
|
+
preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.task.kill();
|
|
62
|
+
cancelRenderFrames();
|
|
63
|
+
throw err;
|
|
64
|
+
});
|
|
42
65
|
const renderStart = Date.now();
|
|
43
66
|
const tmpdir = (0, tmp_dir_1.tmpDir)('pre-encode');
|
|
44
67
|
const parallelEncoding = (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec);
|
|
@@ -87,7 +110,7 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
|
|
|
87
110
|
}
|
|
88
111
|
const realFrameRange = (0, get_frame_to_render_1.getRealFrameRange)(composition.durationInFrames, frameRange !== null && frameRange !== void 0 ? frameRange : null);
|
|
89
112
|
const { waitForRightTimeOfFrameToBeInserted, setFrameToStitch, waitForFinish, } = (0, ensure_frames_in_order_1.ensureFramesInOrder)(realFrameRange);
|
|
90
|
-
const
|
|
113
|
+
const renderFramesProc = (0, render_frames_1.renderFrames)({
|
|
91
114
|
config: composition,
|
|
92
115
|
onFrameUpdate: (frame) => {
|
|
93
116
|
renderedFrames = frame;
|
|
@@ -121,7 +144,14 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
|
|
|
121
144
|
timeoutInMilliseconds,
|
|
122
145
|
chromiumOptions,
|
|
123
146
|
scale,
|
|
147
|
+
ffmpegExecutable,
|
|
148
|
+
browserExecutable,
|
|
149
|
+
port,
|
|
124
150
|
});
|
|
151
|
+
cancelRenderFrames = () => {
|
|
152
|
+
renderFramesProc.cancel();
|
|
153
|
+
};
|
|
154
|
+
const { assetsInfo } = await renderFramesProc;
|
|
125
155
|
if (stitcherFfmpeg) {
|
|
126
156
|
await waitForFinish();
|
|
127
157
|
(_a = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin) === null || _a === void 0 ? void 0 : _a.end();
|
|
@@ -165,6 +195,26 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
|
|
|
165
195
|
encodedDoneIn = Date.now() - stitchStart;
|
|
166
196
|
callUpdate();
|
|
167
197
|
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
/**
|
|
200
|
+
* When an error is thrown in renderFrames(...) (e.g., when delayRender() is used incorrectly), fs.unlinkSync(...) throws an error that the file is locked because ffmpeg is still running, and renderMedia returns it.
|
|
201
|
+
* Therefore we first kill the FFMPEG process before deleting the file
|
|
202
|
+
*/
|
|
203
|
+
cancelRenderFrames();
|
|
204
|
+
if (stitcherFfmpeg !== undefined && stitcherFfmpeg.exitCode === null) {
|
|
205
|
+
const promise = new Promise((resolve) => {
|
|
206
|
+
setTimeout(() => {
|
|
207
|
+
resolve();
|
|
208
|
+
}, 2000);
|
|
209
|
+
stitcherFfmpeg.on('close', resolve);
|
|
210
|
+
});
|
|
211
|
+
// Can only kill the process once it has spawned, otherwise getting EPIPE error in Node.JS
|
|
212
|
+
await (preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.waitForSpawn);
|
|
213
|
+
stitcherFfmpeg.kill();
|
|
214
|
+
await promise;
|
|
215
|
+
}
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
168
218
|
finally {
|
|
169
219
|
if (preEncodedFileLocation !== null &&
|
|
170
220
|
fs_1.default.existsSync(preEncodedFileLocation)) {
|
|
@@ -172,4 +222,3 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
|
|
|
172
222
|
}
|
|
173
223
|
}
|
|
174
224
|
};
|
|
175
|
-
exports.renderMedia = renderMedia;
|
package/dist/render-still.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Browser as PuppeteerBrowser } from 'puppeteer-core';
|
|
2
|
-
import { BrowserExecutable, StillImageFormat, TCompMetadata } from 'remotion';
|
|
2
|
+
import { BrowserExecutable, FfmpegExecutable, StillImageFormat, TCompMetadata } from 'remotion';
|
|
3
|
+
import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
3
4
|
import { ServeUrlOrWebpackBundle } from './legacy-webpack-config';
|
|
4
5
|
import { ChromiumOptions } from './open-browser';
|
|
5
6
|
declare type InnerStillOptions = {
|
|
@@ -17,8 +18,12 @@ declare type InnerStillOptions = {
|
|
|
17
18
|
timeoutInMilliseconds?: number;
|
|
18
19
|
chromiumOptions?: ChromiumOptions;
|
|
19
20
|
scale?: number;
|
|
21
|
+
onDownload?: RenderMediaOnDownload;
|
|
22
|
+
ffmpegExecutable?: FfmpegExecutable;
|
|
23
|
+
};
|
|
24
|
+
declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle & {
|
|
25
|
+
port?: number | null;
|
|
20
26
|
};
|
|
21
|
-
declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle;
|
|
22
27
|
/**
|
|
23
28
|
* @description Render a still frame from a composition and returns an image path
|
|
24
29
|
*/
|
package/dist/render-still.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -29,6 +33,7 @@ const remotion_1 = require("remotion");
|
|
|
29
33
|
const ensure_output_directory_1 = require("./ensure-output-directory");
|
|
30
34
|
const handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
|
|
31
35
|
const legacy_webpack_config_1 = require("./legacy-webpack-config");
|
|
36
|
+
const make_assets_download_dir_1 = require("./make-assets-download-dir");
|
|
32
37
|
const open_browser_1 = require("./open-browser");
|
|
33
38
|
const prepare_server_1 = require("./prepare-server");
|
|
34
39
|
const provide_screenshot_1 = require("./provide-screenshot");
|
|
@@ -37,7 +42,7 @@ const seek_to_frame_1 = require("./seek-to-frame");
|
|
|
37
42
|
const set_props_and_env_1 = require("./set-props-and-env");
|
|
38
43
|
const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
|
|
39
44
|
const validate_scale_1 = require("./validate-scale");
|
|
40
|
-
const innerRenderStill = async ({ composition, quality, imageFormat = 'png', serveUrl, puppeteerInstance, dumpBrowserLogs = false, onError, inputProps, envVariables, output, frame = 0, overwrite = true, browserExecutable, timeoutInMilliseconds, chromiumOptions, scale, }) => {
|
|
45
|
+
const innerRenderStill = async ({ composition, quality, imageFormat = 'png', serveUrl, puppeteerInstance, dumpBrowserLogs = false, onError, inputProps, envVariables, output, frame = 0, overwrite = true, browserExecutable, timeoutInMilliseconds, chromiumOptions, scale, proxyPort, }) => {
|
|
41
46
|
remotion_1.Internals.validateDimension(composition.height, 'height', 'in the `config` object passed to `renderStill()`');
|
|
42
47
|
remotion_1.Internals.validateDimension(composition.width, 'width', 'in the `config` object passed to `renderStill()`');
|
|
43
48
|
remotion_1.Internals.validateFps(composition.fps, 'in the `config` object of `renderStill()`');
|
|
@@ -103,6 +108,8 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
|
|
|
103
108
|
serveUrl,
|
|
104
109
|
initialFrame: frame,
|
|
105
110
|
timeoutInMilliseconds,
|
|
111
|
+
proxyPort,
|
|
112
|
+
retriesRemaining: 2,
|
|
106
113
|
});
|
|
107
114
|
await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
|
|
108
115
|
pageFunction: (id) => {
|
|
@@ -130,18 +137,35 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
|
|
|
130
137
|
/**
|
|
131
138
|
* @description Render a still frame from a composition and returns an image path
|
|
132
139
|
*/
|
|
133
|
-
const renderStill =
|
|
140
|
+
const renderStill = (options) => {
|
|
141
|
+
var _a;
|
|
134
142
|
const selectedServeUrl = (0, legacy_webpack_config_1.getServeUrlWithFallback)(options);
|
|
135
|
-
const
|
|
143
|
+
const downloadDir = (0, make_assets_download_dir_1.makeAssetsDownloadTmpDir)();
|
|
144
|
+
const onDownload = (_a = options.onDownload) !== null && _a !== void 0 ? _a : (() => () => undefined);
|
|
136
145
|
return new Promise((resolve, reject) => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
146
|
+
var _a, _b;
|
|
147
|
+
const onError = (err) => reject(err);
|
|
148
|
+
let close = null;
|
|
149
|
+
(0, prepare_server_1.prepareServer)({
|
|
150
|
+
webpackConfigOrServeUrl: selectedServeUrl,
|
|
151
|
+
downloadDir,
|
|
152
|
+
onDownload,
|
|
153
|
+
onError,
|
|
154
|
+
ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
|
|
155
|
+
port: (_b = options.port) !== null && _b !== void 0 ? _b : null,
|
|
156
|
+
})
|
|
157
|
+
.then(({ serveUrl, closeServer, offthreadPort }) => {
|
|
158
|
+
close = closeServer;
|
|
159
|
+
return innerRenderStill({
|
|
160
|
+
...options,
|
|
161
|
+
serveUrl,
|
|
162
|
+
onError: (err) => reject(err),
|
|
163
|
+
proxyPort: offthreadPort,
|
|
164
|
+
});
|
|
141
165
|
})
|
|
142
166
|
.then((res) => resolve(res))
|
|
143
167
|
.catch((err) => reject(err))
|
|
144
|
-
.finally(() =>
|
|
168
|
+
.finally(() => close === null || close === void 0 ? void 0 : close());
|
|
145
169
|
});
|
|
146
170
|
};
|
|
147
171
|
exports.renderStill = renderStill;
|
package/dist/serve-static.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { FfmpegExecutable } from 'remotion';
|
|
2
|
+
import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
3
|
+
export declare const serveStatic: (path: string | null, options: {
|
|
4
|
+
port: number | null;
|
|
5
|
+
ffmpegExecutable: FfmpegExecutable;
|
|
6
|
+
downloadDir: string;
|
|
7
|
+
onDownload: RenderMediaOnDownload;
|
|
8
|
+
onError: (err: Error) => void;
|
|
9
|
+
}) => Promise<{
|
|
4
10
|
port: number;
|
|
5
11
|
close: () => Promise<void>;
|
|
6
12
|
}>;
|
package/dist/serve-static.js
CHANGED
|
@@ -8,12 +8,28 @@ const http_1 = __importDefault(require("http"));
|
|
|
8
8
|
const remotion_1 = require("remotion");
|
|
9
9
|
const serve_handler_1 = __importDefault(require("serve-handler"));
|
|
10
10
|
const get_port_1 = require("./get-port");
|
|
11
|
+
const offthread_video_server_1 = require("./offthread-video-server");
|
|
11
12
|
const serveStatic = async (path, options) => {
|
|
12
13
|
var _a, _b;
|
|
13
14
|
const port = await (0, get_port_1.getDesiredPort)((_b = (_a = options === null || options === void 0 ? void 0 : options.port) !== null && _a !== void 0 ? _a : remotion_1.Internals.getServerPort()) !== null && _b !== void 0 ? _b : undefined, 3000, 3100);
|
|
15
|
+
const offthreadRequest = (0, offthread_video_server_1.startOffthreadVideoServer)({
|
|
16
|
+
ffmpegExecutable: options.ffmpegExecutable,
|
|
17
|
+
downloadDir: options.downloadDir,
|
|
18
|
+
onDownload: options.onDownload,
|
|
19
|
+
onError: options.onError,
|
|
20
|
+
});
|
|
14
21
|
try {
|
|
15
22
|
const server = http_1.default
|
|
16
23
|
.createServer((request, response) => {
|
|
24
|
+
var _a;
|
|
25
|
+
if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.startsWith('/proxy')) {
|
|
26
|
+
return offthreadRequest(request, response);
|
|
27
|
+
}
|
|
28
|
+
if (path === null) {
|
|
29
|
+
response.writeHead(404);
|
|
30
|
+
response.end('Server only supports /proxy');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
17
33
|
(0, serve_handler_1.default)(request, response, {
|
|
18
34
|
public: path,
|
|
19
35
|
directoryListing: false,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Page } from 'puppeteer-core';
|
|
2
|
-
export declare const setPropsAndEnv: ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, }: {
|
|
2
|
+
export declare const setPropsAndEnv: ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, retriesRemaining, }: {
|
|
3
3
|
inputProps: unknown;
|
|
4
4
|
envVariables: Record<string, string> | undefined;
|
|
5
5
|
page: Page;
|
|
6
6
|
serveUrl: string;
|
|
7
7
|
initialFrame: number;
|
|
8
8
|
timeoutInMilliseconds: number | undefined;
|
|
9
|
+
proxyPort: number;
|
|
10
|
+
retriesRemaining: number;
|
|
9
11
|
}) => Promise<void>;
|