@remotion/renderer 3.0.24 → 3.0.27

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 (44) hide show
  1. package/dist/assets/download-and-map-assets-to-file.d.ts +21 -8
  2. package/dist/assets/download-and-map-assets-to-file.js +68 -42
  3. package/dist/assets/download-file.d.ts +10 -5
  4. package/dist/assets/download-file.js +18 -5
  5. package/dist/assets/ffmpeg-volume-expression.d.ts +1 -2
  6. package/dist/assets/ffmpeg-volume-expression.js +2 -3
  7. package/dist/assets/read-file.js +4 -1
  8. package/dist/browser/Browser.d.ts +5 -0
  9. package/dist/browser/Browser.js +2 -1
  10. package/dist/browser/DOMWorld.d.ts +4 -1
  11. package/dist/browser/DOMWorld.js +11 -3
  12. package/dist/browser/FrameManager.d.ts +2 -1
  13. package/dist/browser/FrameManager.js +2 -2
  14. package/dist/browser/Page.d.ts +5 -3
  15. package/dist/browser/Page.js +6 -5
  16. package/dist/browser/Target.js +1 -1
  17. package/dist/browser/util.d.ts +2 -1
  18. package/dist/browser/util.js +10 -2
  19. package/dist/calculate-sar-dar-pixels.d.ts +9 -0
  20. package/dist/calculate-sar-dar-pixels.js +19 -0
  21. package/dist/extract-frame-from-video.d.ts +2 -4
  22. package/dist/get-compositions.js +1 -1
  23. package/dist/get-port.js +5 -14
  24. package/dist/get-video-info.d.ts +0 -0
  25. package/dist/get-video-info.js +7 -2
  26. package/dist/index.d.ts +14 -6
  27. package/dist/index.js +3 -0
  28. package/dist/last-frame-from-video-cache.d.ts +1 -0
  29. package/dist/offthread-video-server.js +2 -6
  30. package/dist/prepare-server.js +5 -2
  31. package/dist/provide-screenshot.d.ts +1 -0
  32. package/dist/puppeteer-screenshot.d.ts +1 -0
  33. package/dist/render-frames.js +39 -44
  34. package/dist/render-media.d.ts +3 -2
  35. package/dist/render-media.js +8 -3
  36. package/dist/screenshot-dom-element.d.ts +1 -0
  37. package/dist/screenshot-task.d.ts +1 -0
  38. package/dist/seek-to-frame.js +2 -2
  39. package/dist/stitch-frames-to-video.d.ts +4 -3
  40. package/dist/stitch-frames-to-video.js +31 -13
  41. package/dist/stringify-ffmpeg-filter.js +6 -7
  42. package/dist/wait-for-symbolication-error-to-be-done.d.ts +3 -0
  43. package/dist/wait-for-symbolication-error-to-be-done.js +34 -0
  44. package/package.json +3 -3
@@ -1,9 +1,7 @@
1
+ /// <reference types="node" />
1
2
  import type { FfmpegExecutable, OffthreadVideoImageFormat } from 'remotion';
2
3
  import type { LastFrameOptions } from './last-frame-from-video-cache';
3
- export declare const determineResizeParams: (needsResize: [
4
- number,
5
- number
6
- ] | null) => string[];
4
+ export declare const determineResizeParams: (needsResize: [number, number] | null) => string[];
7
5
  export declare const getLastFrameOfVideo: (options: LastFrameOptions) => Promise<Buffer>;
8
6
  declare type Options = {
9
7
  time: number;
@@ -40,7 +40,7 @@ const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
40
40
  frame: null,
41
41
  args: [],
42
42
  });
43
- await page.waitForFunction('window.ready === true');
43
+ await page.waitForFunction(page.browser, 'window.ready === true');
44
44
  const result = await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
45
45
  pageFunction: () => {
46
46
  return window.getStaticCompositions();
package/dist/get-port.js CHANGED
@@ -14,7 +14,7 @@ const getAvailablePort = (portToTry) => new Promise((resolve) => {
14
14
  status = 'unavailable';
15
15
  socket.destroy();
16
16
  });
17
- socket.setTimeout(1000);
17
+ socket.setTimeout(3000);
18
18
  socket.on('timeout', () => {
19
19
  status = 'unavailable';
20
20
  socket.destroy();
@@ -26,15 +26,9 @@ const getAvailablePort = (portToTry) => new Promise((resolve) => {
26
26
  socket.on('close', () => resolve(status));
27
27
  socket.connect(portToTry, host);
28
28
  });
29
- const portCheckSequence = function* (ports) {
30
- if (ports) {
31
- yield* ports;
32
- }
33
- yield 0; // Fall back to 0 if anything else failed
34
- };
35
29
  const getPort = async (from, to) => {
36
30
  const ports = makeRange(from, to);
37
- for (const port of portCheckSequence(ports)) {
31
+ for (const port of ports) {
38
32
  if ((await getAvailablePort(port)) === 'available') {
39
33
  return port;
40
34
  }
@@ -71,10 +65,7 @@ const makeRange = (from, to) => {
71
65
  if (to < from) {
72
66
  throw new RangeError('`to` must be greater than or equal to `from`');
73
67
  }
74
- const generator = function* (f, t) {
75
- for (let port = f; port <= t; port++) {
76
- yield port;
77
- }
78
- };
79
- return generator(from, to);
68
+ return new Array(to - from + 1).fill(true).map((_, i) => {
69
+ return i + from;
70
+ });
80
71
  };
File without changes
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getVideoInfo = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
+ const calculate_sar_dar_pixels_1 = require("./calculate-sar-dar-pixels");
8
9
  const p_limit_1 = require("./p-limit");
9
10
  const isVp9VideoCache = {};
10
11
  const limit = (0, p_limit_1.pLimit)(1);
@@ -26,8 +27,12 @@ async function getVideoInfoUnlimited(src, ffprobeExecutable) {
26
27
  const height = parseInt(dimensions[2], 10);
27
28
  const darWidth = parseInt(dar[1], 10);
28
29
  const darHeight = parseInt(dar[2], 10);
29
- const actualWidth = Math.round(width * (darWidth / darHeight));
30
- const actualHeight = Math.round(height * (darHeight / darWidth));
30
+ const { width: actualWidth, height: actualHeight } = (0, calculate_sar_dar_pixels_1.calculateDisplayVideoSize)({
31
+ darX: darWidth,
32
+ darY: darHeight,
33
+ x: width,
34
+ y: height,
35
+ });
31
36
  if (actualWidth !== width || actualHeight !== height) {
32
37
  needsResize = [actualWidth, actualHeight];
33
38
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import execa from 'execa';
2
3
  import mime from 'mime-types';
3
4
  import { SymbolicateableError } from './error-handling/symbolicateable-error';
@@ -51,7 +52,7 @@ export declare const RenderInternals: {
51
52
  }) => void;
52
53
  normalizeServeUrl: (unnormalized: string) => string;
53
54
  spawnFfmpeg: (options: import("./stitch-frames-to-video").StitcherOptions) => Promise<{
54
- task: Promise<void>;
55
+ task: Promise<Buffer | null>;
55
56
  getLogs: () => string;
56
57
  }>;
57
58
  getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "mp4" | "mkv" | "mov" | "webm";
@@ -61,12 +62,17 @@ export declare const RenderInternals: {
61
62
  ensureOutputDirectory: (outputLocation: string) => void;
62
63
  getRealFrameRange: (durationInFrames: number, frameRange: import("remotion").FrameRange | null) => [number, number];
63
64
  validatePuppeteerTimeout: (timeoutInMilliseconds: unknown) => void;
64
- downloadFile: (url: string, to: string, onProgress: ((progress: {
65
- progress: number;
66
- downloaded: number;
67
- totalSize: number;
68
- }) => void) | undefined) => Promise<{
65
+ downloadFile: ({ onProgress, url, to: toFn, }: {
66
+ url: string;
67
+ to: (contentDisposition: string | null) => string;
68
+ onProgress: ((progress: {
69
+ percent: number | null;
70
+ downloaded: number;
71
+ totalSize: number | null;
72
+ }) => void) | undefined;
73
+ }) => Promise<{
69
74
  sizeInBytes: number;
75
+ to: string;
70
76
  }>;
71
77
  validateScale: (scale: unknown) => void;
72
78
  killAllBrowsers: () => Promise<void>;
@@ -96,4 +102,6 @@ export declare const RenderInternals: {
96
102
  node(scriptPath: string, options?: execa.Options<string> | undefined): execa.ExecaChildProcess<string>;
97
103
  node(scriptPath: string, options?: execa.Options<null> | undefined): execa.ExecaChildProcess<Buffer>;
98
104
  };
105
+ registerErrorSymbolicationLock: () => number;
106
+ unlockErrorSymbolicationLock: (id: number) => void;
99
107
  };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ const validate_even_dimensions_with_codec_1 = require("./validate-even-dimension
31
31
  const validate_ffmpeg_1 = require("./validate-ffmpeg");
32
32
  const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
33
33
  const validate_scale_1 = require("./validate-scale");
34
+ const wait_for_symbolication_error_to_be_done_1 = require("./wait-for-symbolication-error-to-be-done");
34
35
  var combine_videos_1 = require("./combine-videos");
35
36
  Object.defineProperty(exports, "combineVideos", { enumerable: true, get: function () { return combine_videos_1.combineVideos; } });
36
37
  var handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
@@ -80,4 +81,6 @@ exports.RenderInternals = {
80
81
  mime: mime_types_1.default,
81
82
  isPathInside: is_path_inside_1.isPathInside,
82
83
  execa: execa_1.default,
84
+ registerErrorSymbolicationLock: wait_for_symbolication_error_to_be_done_1.registerErrorSymbolicationLock,
85
+ unlockErrorSymbolicationLock: wait_for_symbolication_error_to_be_done_1.unlockErrorSymbolicationLock,
83
86
  };
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { FfmpegExecutable, OffthreadVideoImageFormat } from 'remotion';
2
3
  import type { SpecialVCodecForTransparency } from './get-video-info';
3
4
  export declare type LastFrameOptions = {
@@ -45,12 +45,8 @@ const startOffthreadVideoServer = ({ ffmpegExecutable, ffprobeExecutable, downlo
45
45
  const { src, time, imageFormat } = (0, exports.extractUrlAndSourceFromUrl)(req.url);
46
46
  res.setHeader('access-control-allow-origin', '*');
47
47
  res.setHeader('content-type', `image/${imageFormat === 'jpeg' ? 'jpg' : 'png'}`);
48
- const to = (0, download_and_map_assets_to_file_1.getSanitizedFilenameForAssetUrl)({ downloadDir, src });
49
- (0, download_and_map_assets_to_file_1.startDownloadForSrc)({ src, downloadDir, onDownload }).catch((err) => {
50
- onError(new Error(`Error while downloading asset: ${err.stack}`));
51
- });
52
- (0, download_and_map_assets_to_file_1.waitForAssetToBeDownloaded)(src, to)
53
- .then(() => {
48
+ (0, download_and_map_assets_to_file_1.downloadAsset)({ src, downloadDir, onDownload })
49
+ .then((to) => {
54
50
  return (0, extract_frame_from_video_1.extractFrameFromVideo)({
55
51
  time,
56
52
  src: to,
@@ -8,6 +8,7 @@ const fs_1 = require("fs");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const is_serve_url_1 = require("./is-serve-url");
10
10
  const serve_static_1 = require("./serve-static");
11
+ const wait_for_symbolication_error_to_be_done_1 = require("./wait-for-symbolication-error-to-be-done");
11
12
  const prepareServer = async ({ downloadDir, ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }) => {
12
13
  if ((0, is_serve_url_1.isServeUrl)(webpackConfigOrServeUrl)) {
13
14
  const { port: offthreadPort, close: closeProxy } = await (0, serve_static_1.serveStatic)(null, {
@@ -20,7 +21,9 @@ const prepareServer = async ({ downloadDir, ffmpegExecutable, ffprobeExecutable,
20
21
  });
21
22
  return Promise.resolve({
22
23
  serveUrl: webpackConfigOrServeUrl,
23
- closeServer: () => closeProxy(),
24
+ closeServer: () => {
25
+ return closeProxy();
26
+ },
24
27
  offthreadPort,
25
28
  });
26
29
  }
@@ -40,7 +43,7 @@ const prepareServer = async ({ downloadDir, ffmpegExecutable, ffprobeExecutable,
40
43
  });
41
44
  return Promise.resolve({
42
45
  closeServer: () => {
43
- return close();
46
+ return (0, wait_for_symbolication_error_to_be_done_1.waitForSymbolicationToBeDone)().then(() => close());
44
47
  },
45
48
  serveUrl: `http://localhost:${serverPort}`,
46
49
  offthreadPort: serverPort,
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { ImageFormat } from 'remotion';
2
3
  import type { Page } from './browser/Page';
3
4
  export declare const provideScreenshot: ({ page, imageFormat, options, quality, }: {
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { Page } from './browser/Page';
2
3
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
3
4
  export declare const screenshot: (page: Page, options: ScreenshotOptions) => Promise<Buffer | string | void>;
@@ -203,18 +203,11 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
203
203
  };
204
204
  return returnValue;
205
205
  });
206
- return Promise.race([
207
- happyPath
208
- .then(() => {
209
- return Promise.all(downloadPromises);
210
- })
211
- .then(() => happyPath),
212
- new Promise((_resolve, reject) => {
213
- cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
214
- reject(new Error('renderFrames() got cancelled'));
215
- });
216
- }),
217
- ]);
206
+ return happyPath
207
+ .then(() => {
208
+ return Promise.all(downloadPromises);
209
+ })
210
+ .then(() => happyPath);
218
211
  };
219
212
  const renderFrames = (options) => {
220
213
  var _a, _b, _c, _d;
@@ -248,40 +241,42 @@ const renderFrames = (options) => {
248
241
  const onError = (err) => {
249
242
  reject(err);
250
243
  };
251
- Promise.all([
252
- (0, prepare_server_1.prepareServer)({
253
- webpackConfigOrServeUrl: selectedServeUrl,
254
- downloadDir,
255
- onDownload,
256
- onError,
257
- ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
258
- ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
259
- port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
244
+ Promise.race([
245
+ new Promise((_, rej) => {
246
+ var _a;
247
+ (_a = options.cancelSignal) === null || _a === void 0 ? void 0 : _a.call(options, () => {
248
+ rej(new Error('renderFrames() got cancelled'));
249
+ });
250
+ }),
251
+ Promise.all([
252
+ (0, prepare_server_1.prepareServer)({
253
+ webpackConfigOrServeUrl: selectedServeUrl,
254
+ downloadDir,
255
+ onDownload,
256
+ onError,
257
+ ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
258
+ ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
259
+ port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
260
+ }),
261
+ browserInstance,
262
+ ]).then(([{ serveUrl, closeServer, offthreadPort }, puppeteerInstance]) => {
263
+ const { stopCycling } = (0, cycle_browser_tabs_1.cycleBrowserTabs)(puppeteerInstance, actualParallelism);
264
+ cleanup.push(stopCycling);
265
+ cleanup.push(closeServer);
266
+ return innerRenderFrames({
267
+ ...options,
268
+ puppeteerInstance,
269
+ onError,
270
+ pagesArray: openedPages,
271
+ serveUrl,
272
+ composition,
273
+ actualParallelism,
274
+ onDownload,
275
+ downloadDir,
276
+ proxyPort: offthreadPort,
277
+ });
260
278
  }),
261
- browserInstance,
262
279
  ])
263
- .then(([{ serveUrl, closeServer, offthreadPort }, puppeteerInstance]) => {
264
- var _a;
265
- const { stopCycling } = (0, cycle_browser_tabs_1.cycleBrowserTabs)(puppeteerInstance, actualParallelism);
266
- cleanup.push(stopCycling);
267
- (_a = options.cancelSignal) === null || _a === void 0 ? void 0 : _a.call(options, () => {
268
- stopCycling();
269
- closeServer();
270
- });
271
- cleanup.push(closeServer);
272
- return innerRenderFrames({
273
- ...options,
274
- puppeteerInstance,
275
- onError,
276
- pagesArray: openedPages,
277
- serveUrl,
278
- composition,
279
- actualParallelism,
280
- onDownload,
281
- downloadDir,
282
- proxyPort: offthreadPort,
283
- });
284
- })
285
280
  .then((res) => {
286
281
  return resolve(res);
287
282
  })
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { BrowserExecutable, Codec, FfmpegExecutable, FrameRange, PixelFormat, ProResProfile, SmallTCompMetadata } from 'remotion';
2
3
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
3
4
  import type { BrowserLog } from './browser-log';
@@ -15,7 +16,7 @@ export declare type RenderMediaOnProgress = (progress: {
15
16
  stitchStage: StitchingState;
16
17
  }) => void;
17
18
  export declare type RenderMediaOptions = {
18
- outputLocation: string;
19
+ outputLocation?: string | null;
19
20
  codec: Codec;
20
21
  composition: SmallTCompMetadata;
21
22
  inputProps?: unknown;
@@ -48,4 +49,4 @@ export declare type RenderMediaOptions = {
48
49
  * @description Render a video from a composition
49
50
  * @link https://www.remotion.dev/docs/renderer/render-media
50
51
  */
51
- export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }: RenderMediaOptions) => Promise<void>;
52
+ export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }: RenderMediaOptions) => Promise<Buffer | null>;
@@ -34,7 +34,9 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
34
34
  if (typeof crf !== 'undefined' && crf !== null) {
35
35
  remotion_1.Internals.validateSelectedCrfAndCodecCombination(crf, codec);
36
36
  }
37
- (0, validate_output_filename_1.validateOutputFilename)(codec, (0, get_extension_of_filename_1.getExtensionOfFilename)(outputLocation));
37
+ if (outputLocation) {
38
+ (0, validate_output_filename_1.validateOutputFilename)(codec, (0, get_extension_of_filename_1.getExtensionOfFilename)(outputLocation));
39
+ }
38
40
  (0, validate_scale_1.validateScale)(scale);
39
41
  const serveUrl = (0, legacy_webpack_config_1.getServeUrlWithFallback)(options);
40
42
  let stitchStage = 'encoding';
@@ -169,7 +171,9 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
169
171
  .then(([{ assetsInfo }]) => {
170
172
  renderedDoneIn = Date.now() - renderStart;
171
173
  callUpdate();
172
- (0, ensure_output_directory_1.ensureOutputDirectory)(outputLocation);
174
+ if (outputLocation) {
175
+ (0, ensure_output_directory_1.ensureOutputDirectory)(outputLocation);
176
+ }
173
177
  const stitchStart = Date.now();
174
178
  return Promise.all([
175
179
  (0, stitch_frames_to_video_1.stitchFramesToVideo)({
@@ -202,10 +206,11 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
202
206
  stitchStart,
203
207
  ]);
204
208
  })
205
- .then(([, stitchStart]) => {
209
+ .then(([buffer, stitchStart]) => {
206
210
  encodedFrames = (0, get_duration_from_frame_range_1.getDurationFromFrameRange)(frameRange !== null && frameRange !== void 0 ? frameRange : null, composition.durationInFrames);
207
211
  encodedDoneIn = Date.now() - stitchStart;
208
212
  callUpdate();
213
+ return buffer;
209
214
  })
210
215
  .catch((err) => {
211
216
  /**
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { ImageFormat } from 'remotion';
2
3
  import type { Page } from './browser/Page';
3
4
  export declare const screenshotDOMElement: ({ page, imageFormat, quality, opts, }: {
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { StillImageFormat } from 'remotion';
2
3
  import type { Page } from './browser/Page';
3
4
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.seekToFrame = void 0;
4
4
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
5
5
  const seekToFrame = async ({ frame, page, }) => {
6
- await page.waitForFunction('window.ready === true');
6
+ await page.waitForFunction(page.browser, 'window.ready === true');
7
7
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
8
8
  pageFunction: (f) => {
9
9
  window.remotion_setFrame(f);
@@ -12,7 +12,7 @@ const seekToFrame = async ({ frame, page, }) => {
12
12
  frame,
13
13
  page,
14
14
  });
15
- await page.waitForFunction('window.ready === true');
15
+ await page.waitForFunction(page.browser, 'window.ready === true');
16
16
  await page.evaluateHandle('document.fonts.ready');
17
17
  };
18
18
  exports.seekToFrame = seekToFrame;
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { Codec, FfmpegExecutable, ImageFormat, PixelFormat, ProResProfile, RenderAssetInfo } from 'remotion';
2
3
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
3
4
  import type { CancelSignal } from './make-cancel-signal';
@@ -5,7 +6,7 @@ export declare type StitcherOptions = {
5
6
  fps: number;
6
7
  width: number;
7
8
  height: number;
8
- outputLocation: string;
9
+ outputLocation?: string | null;
9
10
  force: boolean;
10
11
  assetsInfo: RenderAssetInfo;
11
12
  pixelFormat?: PixelFormat;
@@ -25,9 +26,9 @@ export declare type StitcherOptions = {
25
26
  };
26
27
  };
27
28
  declare type ReturnType = {
28
- task: Promise<void>;
29
+ task: Promise<Buffer | null>;
29
30
  getLogs: () => string;
30
31
  };
31
32
  export declare const spawnFfmpeg: (options: StitcherOptions) => Promise<ReturnType>;
32
- export declare const stitchFramesToVideo: (options: StitcherOptions) => Promise<void>;
33
+ export declare const stitchFramesToVideo: (options: StitcherOptions) => Promise<Buffer | null>;
33
34
  export {};
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.stitchFramesToVideo = exports.spawnFfmpeg = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
+ const promises_1 = require("fs/promises");
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const remotion_1 = require("remotion");
11
12
  const calculate_asset_positions_1 = require("./assets/calculate-asset-positions");
@@ -14,6 +15,7 @@ const download_and_map_assets_to_file_1 = require("./assets/download-and-map-ass
14
15
  const delete_directory_1 = require("./delete-directory");
15
16
  const get_audio_codec_name_1 = require("./get-audio-codec-name");
16
17
  const get_codec_name_1 = require("./get-codec-name");
18
+ const get_extension_from_codec_1 = require("./get-extension-from-codec");
17
19
  const get_prores_profile_name_1 = require("./get-prores-profile-name");
18
20
  const merge_audio_track_1 = require("./merge-audio-track");
19
21
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
@@ -69,7 +71,7 @@ const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFra
69
71
  return outName;
70
72
  };
71
73
  const spawnFfmpeg = async (options) => {
72
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
74
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
73
75
  remotion_1.Internals.validateDimension(options.height, 'height', 'passed to `stitchFramesToVideo()`');
74
76
  remotion_1.Internals.validateDimension(options.width, 'width', 'passed to `stitchFramesToVideo()`');
75
77
  remotion_1.Internals.validateFps(options.fps, 'passed to `stitchFramesToVideo()`');
@@ -88,6 +90,9 @@ const spawnFfmpeg = async (options) => {
88
90
  const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec, options.proResProfile);
89
91
  const isAudioOnly = encoderName === null;
90
92
  const supportsCrf = encoderName && codec !== 'prores';
93
+ const tempFile = options.outputLocation
94
+ ? null
95
+ : path_1.default.join((0, tmp_dir_1.tmpDir)('remotion-stitch-temp-dir'), `out.${(0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, 'final')}`);
91
96
  if (options.verbose) {
92
97
  console.log('[verbose] ffmpeg', (_e = options.ffmpegExecutable) !== null && _e !== void 0 ? _e : 'ffmpeg in PATH');
93
98
  console.log('[verbose] encoder', encoderName);
@@ -132,22 +137,23 @@ const spawnFfmpeg = async (options) => {
132
137
  '-b:a',
133
138
  '320k',
134
139
  options.force ? '-y' : null,
135
- options.outputLocation,
140
+ (_j = options.outputLocation) !== null && _j !== void 0 ? _j : tempFile,
136
141
  ].filter(remotion_1.Internals.truthy));
137
- (_j = options.cancelSignal) === null || _j === void 0 ? void 0 : _j.call(options, () => {
142
+ (_k = options.cancelSignal) === null || _k === void 0 ? void 0 : _k.call(options, () => {
138
143
  ffmpegTask.kill();
139
144
  });
140
145
  await ffmpegTask;
141
- (_k = options.onProgress) === null || _k === void 0 ? void 0 : _k.call(options, expectedFrames);
146
+ (_l = options.onProgress) === null || _l === void 0 ? void 0 : _l.call(options, expectedFrames);
147
+ const file = tempFile ? await (0, promises_1.readFile)(tempFile) : null;
142
148
  return {
143
149
  getLogs: () => '',
144
- task: Promise.resolve(),
150
+ task: Promise.resolve(file),
145
151
  };
146
152
  }
147
153
  const ffmpegArgs = [
148
154
  ['-r', String(options.fps)],
149
- ...(((_l = options.internalOptions) === null || _l === void 0 ? void 0 : _l.preEncodedFileLocation)
150
- ? [['-i', (_m = options.internalOptions) === null || _m === void 0 ? void 0 : _m.preEncodedFileLocation]]
155
+ ...(((_m = options.internalOptions) === null || _m === void 0 ? void 0 : _m.preEncodedFileLocation)
156
+ ? [['-i', (_o = options.internalOptions) === null || _o === void 0 ? void 0 : _o.preEncodedFileLocation]]
151
157
  : [
152
158
  ['-f', 'image2'],
153
159
  ['-s', `${options.width}x${options.height}`],
@@ -158,7 +164,7 @@ const spawnFfmpeg = async (options) => {
158
164
  // -c:v is the same as -vcodec as -codec:video
159
165
  // and specified the video codec.
160
166
  ['-c:v', encoderName],
161
- ...(((_o = options.internalOptions) === null || _o === void 0 ? void 0 : _o.preEncodedFileLocation)
167
+ ...(((_p = options.internalOptions) === null || _p === void 0 ? void 0 : _p.preEncodedFileLocation)
162
168
  ? []
163
169
  : [
164
170
  proResProfileName ? ['-profile:v', proResProfileName] : null,
@@ -181,22 +187,22 @@ const spawnFfmpeg = async (options) => {
181
187
  [`Made with Remotion`, packageJson ? packageJson.version : null].join(' '),
182
188
  ],
183
189
  options.force ? '-y' : null,
184
- options.outputLocation,
190
+ (_q = options.outputLocation) !== null && _q !== void 0 ? _q : tempFile,
185
191
  ];
186
192
  if (options.verbose) {
187
193
  console.log('Generated FFMPEG command:');
188
194
  console.log(ffmpegArgs);
189
195
  }
190
196
  const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
191
- const task = (0, execa_1.default)((_p = options.ffmpegExecutable) !== null && _p !== void 0 ? _p : 'ffmpeg', ffmpegString, {
197
+ const task = (0, execa_1.default)((_r = options.ffmpegExecutable) !== null && _r !== void 0 ? _r : 'ffmpeg', ffmpegString, {
192
198
  cwd: options.dir,
193
199
  });
194
- (_q = options.cancelSignal) === null || _q === void 0 ? void 0 : _q.call(options, () => {
200
+ (_s = options.cancelSignal) === null || _s === void 0 ? void 0 : _s.call(options, () => {
195
201
  task.kill();
196
202
  });
197
203
  let ffmpegOutput = '';
198
204
  let isFinished = false;
199
- (_r = task.stderr) === null || _r === void 0 ? void 0 : _r.on('data', (data) => {
205
+ (_t = task.stderr) === null || _t === void 0 ? void 0 : _t.on('data', (data) => {
200
206
  var _a;
201
207
  const str = data.toString();
202
208
  ffmpegOutput += str;
@@ -218,7 +224,19 @@ const spawnFfmpeg = async (options) => {
218
224
  }
219
225
  }
220
226
  });
221
- return { task: task.then(() => undefined), getLogs: () => ffmpegOutput };
227
+ return {
228
+ task: task.then(() => {
229
+ if (options.outputLocation) {
230
+ return null;
231
+ }
232
+ return (0, promises_1.readFile)(tempFile)
233
+ .then((file) => {
234
+ return Promise.all([file, (0, promises_1.unlink)(tempFile)]);
235
+ })
236
+ .then(([file]) => file);
237
+ }),
238
+ getLogs: () => ffmpegOutput,
239
+ };
222
240
  };
223
241
  exports.spawnFfmpeg = spawnFfmpeg;
224
242
  const stitchFramesToVideo = async (options) => {
@@ -12,7 +12,6 @@ const stringifyFfmpegFilter = ({ trimLeft, trimRight, channels, startInVideo, vo
12
12
  }
13
13
  const volumeFilter = (0, ffmpeg_volume_expression_1.ffmpegVolumeExpression)({
14
14
  volume,
15
- startInVideo,
16
15
  fps,
17
16
  trimLeft,
18
17
  });
@@ -29,6 +28,12 @@ const stringifyFfmpegFilter = ({ trimLeft, trimRight, channels, startInVideo, vo
29
28
  `atrim=${trimLeft.toFixed(6)}:${actualTrimRight.toFixed(6)}`,
30
29
  // then set the tempo
31
30
  (0, calculate_atempo_1.calculateATempo)(playbackRate),
31
+ // set the volume if needed
32
+ // The timings for volume must include whatever is in atrim, unless the volume
33
+ // filter gets applied before atrim
34
+ volumeFilter.value === '1'
35
+ ? null
36
+ : `volume=${volumeFilter.value}:eval=${volumeFilter.eval}`,
32
37
  // For n channels, we delay n + 1 channels.
33
38
  // This is because `ffprobe` for some audio files reports the wrong amount
34
39
  // of channels.
@@ -40,12 +45,6 @@ const stringifyFfmpegFilter = ({ trimLeft, trimRight, channels, startInVideo, vo
40
45
  : `adelay=${new Array(channels + 1)
41
46
  .fill((startInVideoSeconds * 1000).toFixed(0))
42
47
  .join('|')}`,
43
- // set the volume if needed
44
- // The timings for volume must include whatever is in atrim, unless the volume
45
- // filter gets applied before atrim
46
- volumeFilter.value === '1'
47
- ? null
48
- : `volume=${volumeFilter.value}:eval=${volumeFilter.eval}`,
49
48
  // Only in the end, we pad to the full length.
50
49
  padAtEnd > 0.0000001
51
50
  ? 'apad=pad_len=' + Math.round(padAtEnd * sample_rate_1.DEFAULT_SAMPLE_RATE)
@@ -0,0 +1,3 @@
1
+ export declare const registerErrorSymbolicationLock: () => number;
2
+ export declare const unlockErrorSymbolicationLock: (id: number) => void;
3
+ export declare const waitForSymbolicationToBeDone: () => Promise<unknown>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.waitForSymbolicationToBeDone = exports.unlockErrorSymbolicationLock = exports.registerErrorSymbolicationLock = void 0;
4
+ let locks = [];
5
+ const waiters = [];
6
+ const registerErrorSymbolicationLock = () => {
7
+ const id = Math.random();
8
+ locks.push(id);
9
+ return id;
10
+ };
11
+ exports.registerErrorSymbolicationLock = registerErrorSymbolicationLock;
12
+ const unlockErrorSymbolicationLock = (id) => {
13
+ locks = locks.filter((l) => l !== id);
14
+ resolveWaiters();
15
+ };
16
+ exports.unlockErrorSymbolicationLock = unlockErrorSymbolicationLock;
17
+ const resolveWaiters = () => {
18
+ if (locks.length === 0) {
19
+ waiters.forEach((w) => w());
20
+ }
21
+ };
22
+ const waitForSymbolicationToBeDone = () => {
23
+ const success = new Promise((resolve) => {
24
+ waiters.push(() => {
25
+ resolve();
26
+ });
27
+ });
28
+ const timeout = new Promise((resolve) => {
29
+ setTimeout(() => resolve(), 5000);
30
+ });
31
+ resolveWaiters();
32
+ return Promise.all([success, timeout]);
33
+ };
34
+ exports.waitForSymbolicationToBeDone = waitForSymbolicationToBeDone;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "3.0.24",
3
+ "version": "3.0.27",
4
4
  "description": "Renderer for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "execa": "5.1.1",
24
24
  "extract-zip": "2.0.1",
25
25
  "mime-types": "2.1.35",
26
- "remotion": "3.0.24",
26
+ "remotion": "3.0.27",
27
27
  "source-map": "^0.8.0-beta.0",
28
28
  "ws": "8.7.0"
29
29
  },
@@ -63,5 +63,5 @@
63
63
  "publishConfig": {
64
64
  "access": "public"
65
65
  },
66
- "gitHead": "7a9b3937f3d7eb41894a338cd92991e6d1226725"
66
+ "gitHead": "16f54241ee403a938c1af372bebc4ac83a4a24f0"
67
67
  }