@remotion/renderer 4.0.0-preload.17 → 4.0.0-spawn.10

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.
@@ -2,7 +2,7 @@ import { TAsset } from 'remotion';
2
2
  export declare type RenderMediaOnDownload = (src: string) => ((progress: {
3
3
  percent: number;
4
4
  }) => void) | undefined | void;
5
- export declare const waitForAssetToBeDownloaded: (src: string) => Promise<string>;
5
+ export declare const waitForAssetToBeDownloaded: (src: string, to: string) => Promise<void>;
6
6
  export declare const markAllAssetsAsDownloaded: () => void;
7
7
  export declare const getSanitizedFilenameForAssetUrl: ({ src, downloadDir, }: {
8
8
  src: string;
@@ -13,25 +13,38 @@ const sanitize_filepath_1 = require("./sanitize-filepath");
13
13
  const isDownloadingMap = {};
14
14
  const hasBeenDownloadedMap = {};
15
15
  const listeners = {};
16
- const waitForAssetToBeDownloaded = (src) => {
17
- if (hasBeenDownloadedMap[src]) {
18
- return Promise.resolve(hasBeenDownloadedMap[src]);
16
+ const waitForAssetToBeDownloaded = (src, to) => {
17
+ var _a;
18
+ if ((_a = hasBeenDownloadedMap[src]) === null || _a === void 0 ? void 0 : _a[to]) {
19
+ return Promise.resolve();
19
20
  }
20
21
  if (!listeners[src]) {
21
- listeners[src] = [];
22
+ listeners[src] = {};
23
+ }
24
+ if (!listeners[src][to]) {
25
+ listeners[src][to] = [];
22
26
  }
23
27
  return new Promise((resolve) => {
24
- listeners[src].push((to) => resolve(to));
28
+ listeners[src][to].push(() => resolve());
25
29
  });
26
30
  };
27
31
  exports.waitForAssetToBeDownloaded = waitForAssetToBeDownloaded;
28
32
  const notifyAssetIsDownloaded = (src, to) => {
29
33
  if (!listeners[src]) {
30
- listeners[src] = [];
34
+ listeners[src] = {};
35
+ }
36
+ if (!listeners[src][to]) {
37
+ listeners[src][to] = [];
38
+ }
39
+ listeners[src][to].forEach((fn) => fn());
40
+ if (!isDownloadingMap[src]) {
41
+ isDownloadingMap[src] = {};
31
42
  }
32
- listeners[src].forEach((fn) => fn(to));
33
- isDownloadingMap[src] = false;
34
- hasBeenDownloadedMap[src] = to;
43
+ isDownloadingMap[src][to] = false;
44
+ if (!hasBeenDownloadedMap[src]) {
45
+ hasBeenDownloadedMap[src] = {};
46
+ }
47
+ hasBeenDownloadedMap[src][to] = true;
35
48
  };
36
49
  const validateMimeType = (mimeType, src) => {
37
50
  if (!mimeType.includes('/')) {
@@ -73,13 +86,17 @@ function validateBufferEncoding(potentialEncoding, dataUrl) {
73
86
  }
74
87
  }
75
88
  const downloadAsset = async (src, to, onDownload) => {
76
- if (hasBeenDownloadedMap[src]) {
89
+ var _a, _b;
90
+ if ((_a = hasBeenDownloadedMap[src]) === null || _a === void 0 ? void 0 : _a[to]) {
77
91
  return;
78
92
  }
79
- if (isDownloadingMap[src]) {
80
- return (0, exports.waitForAssetToBeDownloaded)(src);
93
+ if ((_b = isDownloadingMap[src]) === null || _b === void 0 ? void 0 : _b[to]) {
94
+ return (0, exports.waitForAssetToBeDownloaded)(src, to);
95
+ }
96
+ if (!isDownloadingMap[src]) {
97
+ isDownloadingMap[src] = {};
81
98
  }
82
- isDownloadingMap[src] = true;
99
+ isDownloadingMap[src][to] = true;
83
100
  const onProgress = onDownload(src);
84
101
  (0, ensure_output_directory_1.ensureOutputDirectory)(to);
85
102
  if (src.startsWith('data:')) {
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { FfmpegExecutable } from 'remotion';
3
4
  import { Readable } from 'stream';
4
5
  export declare function streamToString(stream: Readable): Promise<string>;
@@ -13,5 +13,5 @@ declare type GetCompositionsConfig = {
13
13
  ffmpegExecutable?: FfmpegExecutable;
14
14
  port?: number | null;
15
15
  };
16
- export declare const getCompositions: (serveUrlOrWebpackUrl: string, config?: GetCompositionsConfig | undefined) => Promise<TCompMetadata[]>;
16
+ export declare const getCompositions: (serveUrlOrWebpackUrl: string, config?: GetCompositionsConfig) => Promise<TCompMetadata[]>;
17
17
  export {};
@@ -28,6 +28,7 @@ const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
28
28
  initialFrame: 0,
29
29
  timeoutInMilliseconds: config === null || config === void 0 ? void 0 : config.timeoutInMilliseconds,
30
30
  proxyPort,
31
+ retriesRemaining: 2,
31
32
  });
32
33
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
33
34
  page,
package/dist/index.d.ts CHANGED
@@ -51,7 +51,6 @@ export declare const RenderInternals: {
51
51
  getLogs: () => string;
52
52
  }>;
53
53
  getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "mp4" | "mkv" | "mov" | "webm";
54
- makeAssetsDownloadTmpDir: () => string;
55
54
  tmpDir: (str: string) => string;
56
55
  deleteDirectory: (directory: string) => Promise<void>;
57
56
  isServeUrl: (potentialUrl: string) => boolean;
package/dist/index.js CHANGED
@@ -14,7 +14,6 @@ const get_extension_of_filename_1 = require("./get-extension-of-filename");
14
14
  const get_frame_to_render_1 = require("./get-frame-to-render");
15
15
  const get_local_browser_executable_1 = require("./get-local-browser-executable");
16
16
  const is_serve_url_1 = require("./is-serve-url");
17
- const make_assets_download_dir_1 = require("./make-assets-download-dir");
18
17
  const normalize_serve_url_1 = require("./normalize-serve-url");
19
18
  const open_browser_1 = require("./open-browser");
20
19
  const parse_browser_error_stack_1 = require("./parse-browser-error-stack");
@@ -54,7 +53,6 @@ exports.RenderInternals = {
54
53
  normalizeServeUrl: normalize_serve_url_1.normalizeServeUrl,
55
54
  spawnFfmpeg: stitch_frames_to_video_1.spawnFfmpeg,
56
55
  getFileExtensionFromCodec: get_extension_from_codec_1.getFileExtensionFromCodec,
57
- makeAssetsDownloadTmpDir: make_assets_download_dir_1.makeAssetsDownloadTmpDir,
58
56
  tmpDir: tmp_dir_1.tmpDir,
59
57
  deleteDirectory: delete_directory_1.deleteDirectory,
60
58
  isServeUrl: is_serve_url_1.isServeUrl,
@@ -30,8 +30,8 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
30
30
  });
31
31
  return;
32
32
  }
33
- // FFMPEG has a limit of 64 tracks that can be merged at once
34
- if (files.length > 64) {
33
+ // In FFMPEG, the total number of left and right tracks that can be merged at one time is limited to 64
34
+ if (files.length >= 32) {
35
35
  const chunked = (0, chunk_1.chunk)(files, 10);
36
36
  const tempPath = (0, tmp_dir_1.tmpDir)('remotion-large-audio-mixing');
37
37
  const chunkNames = await Promise.all(chunked.map(async (chunkFiles, i) => {
@@ -35,14 +35,15 @@ const startOffthreadVideoServer = ({ ffmpegExecutable, downloadDir, onDownload,
35
35
  res.setHeader('access-control-allow-origin', '*');
36
36
  res.setHeader('content-type', 'image/jpg');
37
37
  const { src, time } = (0, exports.extractUrlAndSourceFromUrl)(req.url);
38
+ const to = (0, download_and_map_assets_to_file_1.getSanitizedFilenameForAssetUrl)({ downloadDir, src });
38
39
  (0, download_and_map_assets_to_file_1.startDownloadForSrc)({ src, downloadDir, onDownload }).catch((err) => {
39
40
  onError(new Error(`Error while downloading asset: ${err.stack}`));
40
41
  });
41
- (0, download_and_map_assets_to_file_1.waitForAssetToBeDownloaded)(src)
42
- .then((newSrc) => {
42
+ (0, download_and_map_assets_to_file_1.waitForAssetToBeDownloaded)(src, to)
43
+ .then(() => {
43
44
  return (0, extract_frame_from_video_1.extractFrameFromVideo)({
44
45
  time,
45
- src: newSrc,
46
+ src: to,
46
47
  ffmpegExecutable,
47
48
  });
48
49
  })
@@ -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 | undefined;
14
- browserExecutable?: string | null | undefined;
15
- chromiumOptions?: ChromiumOptions | undefined;
16
- forceDeviceScaleFactor?: number | undefined;
17
- } | undefined) => Promise<puppeteer.Browser>;
13
+ shouldDumpIo?: boolean;
14
+ browserExecutable?: string | null;
15
+ chromiumOptions?: ChromiumOptions;
16
+ forceDeviceScaleFactor?: number;
17
+ }) => Promise<puppeteer.Browser>;
18
18
  export {};
@@ -17,5 +17,6 @@ declare type PreSticherOptions = {
17
17
  export declare const prespawnFfmpeg: (options: PreSticherOptions) => Promise<{
18
18
  task: execa.ExecaChildProcess<string>;
19
19
  getLogs: () => string;
20
+ waitForSpawn: Promise<void>;
20
21
  }>;
21
22
  export {};
@@ -73,6 +73,9 @@ const prespawnFfmpeg = async (options) => {
73
73
  }
74
74
  const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
75
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
+ });
76
79
  let ffmpegOutput = '';
77
80
  (_g = task.stderr) === null || _g === void 0 ? void 0 : _g.on('data', (data) => {
78
81
  const str = data.toString();
@@ -84,6 +87,6 @@ const prespawnFfmpeg = async (options) => {
84
87
  }
85
88
  }
86
89
  });
87
- return { task, getLogs: () => ffmpegOutput };
90
+ return { task, getLogs: () => ffmpegOutput, waitForSpawn };
88
91
  };
89
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.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
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];
@@ -77,6 +77,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, inputProps
77
77
  initialFrame,
78
78
  timeoutInMilliseconds,
79
79
  proxyPort,
80
+ retriesRemaining: 2,
80
81
  });
81
82
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
82
83
  pageFunction: (id) => {
@@ -105,7 +106,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, inputProps
105
106
  const assets = new Array(frameCount).fill(undefined);
106
107
  await Promise.all(new Array(frameCount)
107
108
  .fill(Boolean)
108
- .map((x, i) => i)
109
+ .map((_x, i) => i)
109
110
  .map(async (index) => {
110
111
  const frame = realFrameRange[0] + index;
111
112
  const freePage = await pool.acquire();
@@ -168,6 +168,25 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
168
168
  encodedDoneIn = Date.now() - stitchStart;
169
169
  callUpdate();
170
170
  }
171
+ catch (err) {
172
+ /**
173
+ * 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.
174
+ * Therefore we first kill the FFMPEG process before deleting the file
175
+ */
176
+ if (stitcherFfmpeg !== undefined && stitcherFfmpeg.exitCode === null) {
177
+ const promise = new Promise((resolve) => {
178
+ setTimeout(() => {
179
+ resolve();
180
+ }, 2000);
181
+ stitcherFfmpeg.on('close', resolve);
182
+ });
183
+ // Can only kill the process once it has spawned, otherwise getting EPIPE error in Node.JS
184
+ await (preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.waitForSpawn);
185
+ stitcherFfmpeg.kill();
186
+ await promise;
187
+ }
188
+ throw err;
189
+ }
171
190
  finally {
172
191
  if (preEncodedFileLocation !== null &&
173
192
  fs_1.default.existsSync(preEncodedFileLocation)) {
@@ -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.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
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];
@@ -105,6 +109,7 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
105
109
  initialFrame: frame,
106
110
  timeoutInMilliseconds,
107
111
  proxyPort,
112
+ retriesRemaining: 2,
108
113
  });
109
114
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
110
115
  pageFunction: (id) => {
@@ -1,5 +1,5 @@
1
1
  import { Page } from 'puppeteer-core';
2
- export declare const setPropsAndEnv: ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, }: {
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;
@@ -7,4 +7,5 @@ export declare const setPropsAndEnv: ({ inputProps, envVariables, page, serveUrl
7
7
  initialFrame: number;
8
8
  timeoutInMilliseconds: number | undefined;
9
9
  proxyPort: number;
10
+ retriesRemaining: number;
10
11
  }) => Promise<void>;
@@ -5,7 +5,7 @@ const remotion_1 = require("remotion");
5
5
  const normalize_serve_url_1 = require("./normalize-serve-url");
6
6
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
7
7
  const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
8
- const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, }) => {
8
+ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, retriesRemaining, }) => {
9
9
  (0, validate_puppeteer_timeout_1.validatePuppeteerTimeout)(timeoutInMilliseconds);
10
10
  const actualTimeout = timeoutInMilliseconds !== null && timeoutInMilliseconds !== void 0 ? timeoutInMilliseconds : remotion_1.Internals.DEFAULT_PUPPETEER_TIMEOUT;
11
11
  page.setDefaultTimeout(actualTimeout);
@@ -32,6 +32,25 @@ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initia
32
32
  }, [proxyPort]);
33
33
  const pageRes = await page.goto(urlToVisit);
34
34
  const status = pageRes.status();
35
+ // S3 in rare occasions returns a 500 or 503 error code for GET operations.
36
+ // Usually it is fixed by retrying.
37
+ if (status >= 500 && status <= 504 && retriesRemaining > 0) {
38
+ await new Promise((resolve) => {
39
+ setTimeout(() => {
40
+ resolve();
41
+ }, 2000);
42
+ });
43
+ return (0, exports.setPropsAndEnv)({
44
+ envVariables,
45
+ initialFrame,
46
+ inputProps,
47
+ page,
48
+ proxyPort,
49
+ retriesRemaining: retriesRemaining - 1,
50
+ serveUrl,
51
+ timeoutInMilliseconds,
52
+ });
53
+ }
35
54
  if (status !== 200 &&
36
55
  status !== 301 &&
37
56
  status !== 302 &&
package/dist/tmp-dir.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.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "4.0.0-preload.17+14cd6033f",
3
+ "version": "4.0.0-spawn.10+911177607",
4
4
  "description": "Renderer for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "execa": "5.1.1",
24
24
  "puppeteer-core": "13.5.1",
25
- "remotion": "4.0.0-preload.17+14cd6033f",
25
+ "remotion": "4.0.0-spawn.10+911177607",
26
26
  "serve-handler": "6.1.3",
27
27
  "source-map": "^0.8.0-beta.0"
28
28
  },
@@ -46,7 +46,7 @@
46
46
  "react": "18.0.0",
47
47
  "react-dom": "18.0.0",
48
48
  "ts-jest": "^27.0.5",
49
- "typescript": "^4.5.5"
49
+ "typescript": "^4.7.0"
50
50
  },
51
51
  "keywords": [
52
52
  "remotion",
@@ -59,5 +59,5 @@
59
59
  "publishConfig": {
60
60
  "access": "public"
61
61
  },
62
- "gitHead": "14cd6033f4ad0fa75af142d54a4cd1a23aff3f21"
62
+ "gitHead": "911177607ac127d9f4d1c014ad8ae32fd14947dd"
63
63
  }