@remotion/renderer 4.0.0-alpha4 → 4.0.0-alpha6

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 (143) hide show
  1. package/README.md +5 -43
  2. package/dist/assets/download-and-map-assets-to-file.js +6 -6
  3. package/dist/assets/download-file.d.ts +3 -2
  4. package/dist/assets/download-file.js +18 -3
  5. package/dist/assets/download-map.d.ts +0 -26
  6. package/dist/assets/download-map.js +7 -12
  7. package/dist/assets/get-audio-channels.d.ts +1 -2
  8. package/dist/assets/get-audio-channels.js +5 -9
  9. package/dist/assets/read-file.d.ts +1 -1
  10. package/dist/assets/read-file.js +2 -2
  11. package/dist/assets/sanitize-filepath.js +2 -2
  12. package/dist/audio-codec.d.ts +4 -3
  13. package/dist/audio-codec.js +3 -9
  14. package/dist/browser/BrowserFetcher.d.ts +0 -1
  15. package/dist/browser/BrowserFetcher.js +14 -15
  16. package/dist/browser/BrowserRunner.d.ts +1 -1
  17. package/dist/browser/BrowserRunner.js +10 -4
  18. package/dist/browser/FrameManager.js +2 -3
  19. package/dist/browser/LaunchOptions.d.ts +1 -0
  20. package/dist/browser/Launcher.js +6 -5
  21. package/dist/browser/NodeWebSocketTransport.js +4 -4
  22. package/dist/browser/devtools-commands.d.ts +5 -1
  23. package/dist/browser/devtools-types.d.ts +78 -0
  24. package/dist/browser/get-download-destination.js +8 -8
  25. package/dist/browser/is-target-closed-err.d.ts +1 -0
  26. package/dist/browser/is-target-closed-err.js +9 -0
  27. package/dist/call-ffmpeg.d.ts +14 -0
  28. package/dist/call-ffmpeg.js +40 -0
  29. package/dist/check-apple-silicon.js +2 -45
  30. package/dist/client.d.ts +79 -42
  31. package/dist/client.js +27 -1
  32. package/dist/codec-supports-media.d.ts +2 -1
  33. package/dist/codec-supports-media.js +20 -5
  34. package/dist/combine-videos.d.ts +0 -3
  35. package/dist/combine-videos.js +9 -13
  36. package/dist/compositor/compose.d.ts +3 -1
  37. package/dist/compositor/compose.js +41 -18
  38. package/dist/compositor/compositor.d.ts +12 -0
  39. package/dist/compositor/compositor.js +204 -0
  40. package/dist/compositor/get-executable-path.d.ts +1 -1
  41. package/dist/compositor/get-executable-path.js +27 -8
  42. package/dist/compositor/make-nonce.d.ts +1 -0
  43. package/dist/compositor/make-nonce.js +8 -0
  44. package/dist/compositor/payloads.d.ts +34 -7
  45. package/dist/create-ffmpeg-complex-filter.d.ts +5 -5
  46. package/dist/create-ffmpeg-complex-filter.js +2 -4
  47. package/dist/create-ffmpeg-merge-filter.d.ts +2 -5
  48. package/dist/create-ffmpeg-merge-filter.js +2 -10
  49. package/dist/create-silent-audio.d.ts +1 -4
  50. package/dist/create-silent-audio.js +3 -7
  51. package/dist/crf.js +8 -2
  52. package/dist/delete-directory.js +18 -18
  53. package/dist/does-have-m2-bug.js +2 -2
  54. package/dist/ensure-output-directory.js +5 -5
  55. package/dist/ffmpeg-filter-file.js +7 -7
  56. package/dist/file-extensions.d.ts +1 -12
  57. package/dist/file-extensions.js +8 -14
  58. package/dist/find-closest-package-json.js +6 -6
  59. package/dist/get-compositions.d.ts +3 -5
  60. package/dist/get-compositions.js +8 -11
  61. package/dist/get-concurrency.js +3 -3
  62. package/dist/get-extension-from-codec.d.ts +2 -2
  63. package/dist/get-extension-of-filename.js +2 -2
  64. package/dist/get-frame-padded-index.d.ts +2 -1
  65. package/dist/get-local-browser-executable.js +4 -4
  66. package/dist/get-video-threads-flag.js +3 -3
  67. package/dist/guess-extension-for-media.d.ts +1 -3
  68. package/dist/guess-extension-for-media.js +4 -8
  69. package/dist/image-format.d.ts +12 -6
  70. package/dist/image-format.js +16 -13
  71. package/dist/index.d.ts +80 -61
  72. package/dist/index.js +15 -17
  73. package/dist/jpeg-quality.d.ts +1 -0
  74. package/dist/jpeg-quality.js +21 -0
  75. package/dist/merge-audio-track.d.ts +0 -2
  76. package/dist/merge-audio-track.js +5 -12
  77. package/dist/mime-types.js +2 -2
  78. package/dist/offthread-video-server.d.ts +9 -9
  79. package/dist/offthread-video-server.js +65 -58
  80. package/dist/open-browser.d.ts +1 -0
  81. package/dist/open-browser.js +7 -6
  82. package/dist/options/audio-bitrate.d.ts +2 -0
  83. package/dist/options/audio-bitrate.js +11 -0
  84. package/dist/options/crf.d.ts +2 -0
  85. package/dist/options/crf.js +11 -0
  86. package/dist/options/enforce-audio.d.ts +2 -0
  87. package/dist/options/enforce-audio.js +11 -0
  88. package/dist/options/jpeg-quality.d.ts +2 -0
  89. package/dist/options/jpeg-quality.js +11 -0
  90. package/dist/options/mute.d.ts +2 -0
  91. package/dist/options/mute.js +11 -0
  92. package/dist/options/option.d.ts +8 -0
  93. package/dist/options/option.js +2 -0
  94. package/dist/options/scale.d.ts +2 -0
  95. package/dist/options/scale.js +11 -0
  96. package/dist/options/video-bitrate.d.ts +2 -0
  97. package/dist/options/video-bitrate.js +11 -0
  98. package/dist/options/video-codec.d.ts +2 -0
  99. package/dist/options/video-codec.js +11 -0
  100. package/dist/perf.d.ts +1 -1
  101. package/dist/perf.js +9 -7
  102. package/dist/prepare-server.d.ts +3 -4
  103. package/dist/prepare-server.js +9 -9
  104. package/dist/preprocess-audio-track.d.ts +0 -4
  105. package/dist/preprocess-audio-track.js +4 -8
  106. package/dist/prespawn-ffmpeg.d.ts +6 -9
  107. package/dist/prespawn-ffmpeg.js +7 -12
  108. package/dist/prestitcher-memory-usage.d.ts +0 -4
  109. package/dist/prestitcher-memory-usage.js +4 -5
  110. package/dist/prores-profile.d.ts +1 -2
  111. package/dist/prores-profile.js +4 -4
  112. package/dist/provide-screenshot.d.ts +4 -5
  113. package/dist/provide-screenshot.js +2 -2
  114. package/dist/puppeteer-screenshot.d.ts +3 -3
  115. package/dist/puppeteer-screenshot.js +10 -33
  116. package/dist/render-frames.d.ts +13 -25
  117. package/dist/render-frames.js +34 -45
  118. package/dist/render-media.d.ts +16 -18
  119. package/dist/render-media.js +42 -52
  120. package/dist/render-still.d.ts +12 -8
  121. package/dist/render-still.js +30 -18
  122. package/dist/resolve-asset-src.js +2 -2
  123. package/dist/screenshot-dom-element.d.ts +4 -5
  124. package/dist/screenshot-dom-element.js +6 -3
  125. package/dist/screenshot-task.d.ts +2 -3
  126. package/dist/screenshot-task.js +40 -25
  127. package/dist/serve-handler/index.d.ts +1 -1
  128. package/dist/serve-handler/index.js +21 -19
  129. package/dist/serve-handler/is-path-inside.js +3 -3
  130. package/dist/serve-static.d.ts +2 -3
  131. package/dist/serve-static.js +26 -22
  132. package/dist/stitch-frames-to-video.d.ts +2 -12
  133. package/dist/stitch-frames-to-video.js +37 -46
  134. package/dist/take-frame-and-compose.d.ts +4 -5
  135. package/dist/take-frame-and-compose.js +15 -9
  136. package/dist/tmp-dir.js +7 -8
  137. package/dist/validate-concurrency.d.ts +2 -0
  138. package/dist/validate-concurrency.js +11 -5
  139. package/dist/validate-output-filename.d.ts +1 -1
  140. package/dist/validate-puppeteer-timeout.js +1 -0
  141. package/install-toolchain.mjs +36 -0
  142. package/package.json +11 -10
  143. package/types/ws/index.d.ts +5 -5
@@ -1,27 +1,23 @@
1
1
  "use strict";
2
2
  // Combine multiple video chunks, useful for decentralized rendering
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
3
  Object.defineProperty(exports, "__esModule", { value: true });
7
4
  exports.combineVideos = void 0;
8
- const execa_1 = __importDefault(require("execa"));
9
- const fs_1 = require("fs");
10
- const path_1 = require("path");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
11
7
  const audio_codec_1 = require("./audio-codec");
12
- const ffmpeg_flags_1 = require("./ffmpeg-flags");
8
+ const call_ffmpeg_1 = require("./call-ffmpeg");
13
9
  const is_audio_codec_1 = require("./is-audio-codec");
14
10
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
15
11
  const truthy_1 = require("./truthy");
16
12
  const combineVideos = async (options) => {
17
13
  var _a;
18
- const { files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, ffmpegExecutable, remotionRoot, audioCodec, } = options;
14
+ const { files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, audioCodec, } = options;
19
15
  const fileList = files.map((p) => `file '${p}'`).join('\n');
20
- const fileListTxt = (0, path_1.join)(filelistDir, 'files.txt');
21
- (0, fs_1.writeFileSync)(fileListTxt, fileList);
16
+ const fileListTxt = (0, node_path_1.join)(filelistDir, 'files.txt');
17
+ (0, node_fs_1.writeFileSync)(fileListTxt, fileList);
22
18
  const resolvedAudioCodec = audioCodec !== null && audioCodec !== void 0 ? audioCodec : (0, audio_codec_1.getDefaultAudioCodec)({ codec, preferLossless: false });
23
19
  try {
24
- const task = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), [
20
+ const task = (0, call_ffmpeg_1.callFf)('ffmpeg', [
25
21
  (0, is_audio_codec_1.isAudioCodec)(codec) ? null : '-r',
26
22
  (0, is_audio_codec_1.isAudioCodec)(codec) ? null : String(fps),
27
23
  '-f',
@@ -60,10 +56,10 @@ const combineVideos = async (options) => {
60
56
  });
61
57
  await task;
62
58
  onProgress(numberOfFrames);
63
- (fs_1.rmSync !== null && fs_1.rmSync !== void 0 ? fs_1.rmSync : fs_1.rmdirSync)(filelistDir, { recursive: true });
59
+ (0, node_fs_1.rmSync)(filelistDir, { recursive: true });
64
60
  }
65
61
  catch (err) {
66
- (fs_1.rmSync !== null && fs_1.rmSync !== void 0 ? fs_1.rmSync : fs_1.rmdirSync)(filelistDir, { recursive: true });
62
+ (0, node_fs_1.rmSync)(filelistDir, { recursive: true });
67
63
  throw err;
68
64
  }
69
65
  };
@@ -1,13 +1,15 @@
1
1
  import type { DownloadMap } from '../assets/download-map';
2
- import type { CompositorImageFormat, Layer } from './payloads';
2
+ import type { CompositorCommand, CompositorCommandSerialized, CompositorImageFormat, Layer } from './payloads';
3
3
  declare type CompositorInput = {
4
4
  height: number;
5
5
  width: number;
6
6
  layers: Layer[];
7
7
  imageFormat: CompositorImageFormat;
8
8
  };
9
+ export declare const serializeCommand: <Type extends keyof CompositorCommand>(command: Type, params: CompositorCommand[Type]) => CompositorCommandSerialized<Type>;
9
10
  export declare const compose: ({ height, width, layers, output, downloadMap, imageFormat, }: CompositorInput & {
10
11
  downloadMap: DownloadMap;
11
12
  output: string;
12
13
  }) => Promise<void>;
14
+ export declare const callCompositor: (payload: string) => Promise<void>;
13
15
  export {};
@@ -1,31 +1,49 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compose = void 0;
4
- const child_process_1 = require("child_process");
5
- const crypto_1 = require("crypto");
6
- const promises_1 = require("fs/promises");
3
+ exports.callCompositor = exports.compose = exports.serializeCommand = void 0;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_crypto_1 = require("node:crypto");
6
+ const node_fs_1 = require("node:fs");
7
+ const promises_1 = require("node:fs/promises");
8
+ const call_ffmpeg_1 = require("../call-ffmpeg");
7
9
  const get_executable_path_1 = require("./get-executable-path");
10
+ const make_nonce_1 = require("./make-nonce");
8
11
  const getCompositorHash = ({ ...input }) => {
9
- return (0, crypto_1.createHash)('sha256').update(JSON.stringify(input)).digest('base64');
12
+ return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(input)).digest('base64');
10
13
  };
14
+ const serializeCommand = (command, params) => {
15
+ return {
16
+ nonce: (0, make_nonce_1.makeNonce)(),
17
+ payload: {
18
+ type: command,
19
+ params,
20
+ },
21
+ };
22
+ };
23
+ exports.serializeCommand = serializeCommand;
11
24
  const compose = async ({ height, width, layers, output, downloadMap, imageFormat, }) => {
12
- const bin = (0, get_executable_path_1.getExecutablePath)();
13
25
  const hash = getCompositorHash({ height, width, layers, imageFormat });
14
26
  if (downloadMap.compositorCache[hash]) {
15
27
  await (0, promises_1.copyFile)(downloadMap.compositorCache[hash], output);
16
28
  return;
17
29
  }
18
- const payload = {
19
- v: 1,
30
+ const payload = (0, exports.serializeCommand)('Compose', {
20
31
  height,
21
32
  width,
22
33
  layers,
23
34
  output,
24
35
  output_format: imageFormat,
25
- };
26
- await new Promise((resolve, reject) => {
27
- const child = (0, child_process_1.spawn)(bin);
28
- child.stdin.write(JSON.stringify(payload));
36
+ });
37
+ await (0, exports.callCompositor)(JSON.stringify(payload));
38
+ downloadMap.compositorCache[hash] = output;
39
+ };
40
+ exports.compose = compose;
41
+ const callCompositor = (payload) => {
42
+ return new Promise((resolve, reject) => {
43
+ const execPath = (0, get_executable_path_1.getExecutablePath)('compositor');
44
+ (0, node_fs_1.chmodSync)(execPath, 0o755);
45
+ const child = (0, node_child_process_1.spawn)(execPath, [payload], (0, call_ffmpeg_1.dynamicLibraryPathOptions)());
46
+ child.stdin.write(payload);
29
47
  child.stdin.end();
30
48
  const stderrChunks = [];
31
49
  child.stderr.on('data', (d) => stderrChunks.push(d));
@@ -35,13 +53,18 @@ const compose = async ({ height, width, layers, output, downloadMap, imageFormat
35
53
  }
36
54
  else {
37
55
  const message = Buffer.concat(stderrChunks).toString('utf-8');
38
- const parsed = JSON.parse(message);
39
- const err = new Error(parsed.error);
40
- err.stack = parsed.error + '\n' + parsed.backtrace;
41
- reject(err);
56
+ try {
57
+ // Try to see if the error is a JSON
58
+ const parsed = JSON.parse(message);
59
+ const msg = `Compositor error: ${parsed.error}`;
60
+ const err = new Error(`${msg}\n${parsed.backtrace}`);
61
+ reject(err);
62
+ }
63
+ catch (err) {
64
+ reject(new Error(`Compositor panicked: ${message}`));
65
+ }
42
66
  }
43
67
  });
44
68
  });
45
- downloadMap.compositorCache[hash] = output;
46
69
  };
47
- exports.compose = compose;
70
+ exports.callCompositor = callCompositor;
@@ -0,0 +1,12 @@
1
+ /// <reference types="node" />
2
+ import type { CompositorCommand } from './payloads';
3
+ declare type Compositor = {
4
+ finishCommands: () => void;
5
+ executeCommand: <T extends keyof CompositorCommand>(type: T, payload: CompositorCommand[T]) => Promise<Buffer>;
6
+ waitForDone: () => Promise<void>;
7
+ pid: number | null;
8
+ };
9
+ export declare const getIdealMaximumFrameCacheItems: () => number;
10
+ export declare const startLongRunningCompositor: (maximumFrameCacheItems: number, verbose: boolean) => Compositor;
11
+ export declare const startCompositor: <T extends keyof CompositorCommand>(type: T, payload: CompositorCommand[T]) => Compositor;
12
+ export {};
@@ -0,0 +1,204 @@
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.startCompositor = exports.startLongRunningCompositor = exports.getIdealMaximumFrameCacheItems = void 0;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_fs_1 = require("node:fs");
9
+ const node_os_1 = __importDefault(require("node:os"));
10
+ const call_ffmpeg_1 = require("../call-ffmpeg");
11
+ const get_concurrency_1 = require("../get-concurrency");
12
+ const compose_1 = require("./compose");
13
+ const get_executable_path_1 = require("./get-executable-path");
14
+ const make_nonce_1 = require("./make-nonce");
15
+ const getIdealMaximumFrameCacheItems = () => {
16
+ const freeMemory = node_os_1.default.freemem();
17
+ // Assuming 1 frame is approximately 6MB
18
+ // Assuming only half the available memory should be used
19
+ const max = Math.floor(freeMemory / (1024 * 1024 * 6));
20
+ // Never store more than 1000 frames
21
+ // But 100 is needed even if it's going to swap
22
+ return Math.max(100, Math.min(max, 1000));
23
+ };
24
+ exports.getIdealMaximumFrameCacheItems = getIdealMaximumFrameCacheItems;
25
+ const startLongRunningCompositor = (maximumFrameCacheItems, verbose) => {
26
+ return (0, exports.startCompositor)('StartLongRunningProcess', {
27
+ concurrency: (0, get_concurrency_1.getActualConcurrency)(null),
28
+ maximum_frame_cache_items: maximumFrameCacheItems,
29
+ verbose,
30
+ });
31
+ };
32
+ exports.startLongRunningCompositor = startLongRunningCompositor;
33
+ const startCompositor = (type, payload) => {
34
+ var _a;
35
+ const bin = (0, get_executable_path_1.getExecutablePath)('compositor');
36
+ (0, node_fs_1.chmodSync)(bin, 0o755);
37
+ const fullCommand = (0, compose_1.serializeCommand)(type, payload);
38
+ const child = (0, node_child_process_1.spawn)(bin, [JSON.stringify(fullCommand)], (0, call_ffmpeg_1.dynamicLibraryPathOptions)());
39
+ const stderrChunks = [];
40
+ let outputBuffer = Buffer.from('');
41
+ const separator = Buffer.from('remotion_buffer:');
42
+ const waiters = new Map();
43
+ const onMessage = (statusType, nonce, data) => {
44
+ if (nonce === '0') {
45
+ console.log(data.toString('utf8'));
46
+ }
47
+ if (waiters.has(nonce)) {
48
+ if (statusType === 'error') {
49
+ try {
50
+ const parsed = JSON.parse(data.toString('utf8'));
51
+ waiters.get(nonce).reject(new Error(`Compositor error: ${parsed.error}\n${parsed.backtrace}`));
52
+ }
53
+ catch (err) {
54
+ waiters.get(nonce).reject(new Error(data.toString('utf8')));
55
+ }
56
+ }
57
+ else {
58
+ waiters.get(nonce).resolve(data);
59
+ }
60
+ waiters.delete(nonce);
61
+ }
62
+ };
63
+ let quit = false;
64
+ let missingData = null;
65
+ const processInput = () => {
66
+ let separatorIndex = outputBuffer.indexOf(separator);
67
+ if (separatorIndex === -1) {
68
+ return;
69
+ }
70
+ separatorIndex += separator.length;
71
+ let nonceString = '';
72
+ let lengthString = '';
73
+ let statusString = '';
74
+ // Each message from Rust is prefixed with `remotion_buffer;{[nonce]}:{[length]}`
75
+ // Let's read the buffer to extract the nonce, and if the full length is available,
76
+ // we'll extract the data and pass it to the callback.
77
+ // eslint-disable-next-line no-constant-condition
78
+ while (true) {
79
+ const nextDigit = outputBuffer[separatorIndex];
80
+ // 0x3a is the character ":"
81
+ if (nextDigit === 0x3a) {
82
+ separatorIndex++;
83
+ break;
84
+ }
85
+ separatorIndex++;
86
+ nonceString += String.fromCharCode(nextDigit);
87
+ }
88
+ // eslint-disable-next-line no-constant-condition
89
+ while (true) {
90
+ const nextDigit = outputBuffer[separatorIndex];
91
+ if (nextDigit === 0x3a) {
92
+ separatorIndex++;
93
+ break;
94
+ }
95
+ separatorIndex++;
96
+ lengthString += String.fromCharCode(nextDigit);
97
+ }
98
+ // eslint-disable-next-line no-constant-condition
99
+ while (true) {
100
+ const nextDigit = outputBuffer[separatorIndex];
101
+ if (nextDigit === 0x3a) {
102
+ break;
103
+ }
104
+ separatorIndex++;
105
+ statusString += String.fromCharCode(nextDigit);
106
+ }
107
+ const length = Number(lengthString);
108
+ const status = Number(statusString);
109
+ const dataLength = outputBuffer.length - separatorIndex - 1;
110
+ if (dataLength < length) {
111
+ missingData = {
112
+ dataMissing: length - dataLength,
113
+ };
114
+ return;
115
+ }
116
+ const data = outputBuffer.subarray(separatorIndex + 1, separatorIndex + 1 + Number(lengthString));
117
+ onMessage(status === 1 ? 'error' : 'success', nonceString, data);
118
+ missingData = null;
119
+ outputBuffer = outputBuffer.subarray(separatorIndex + Number(lengthString) + 1);
120
+ processInput();
121
+ };
122
+ let unprocessedBuffers = [];
123
+ child.stdout.on('data', (data) => {
124
+ unprocessedBuffers.push(data);
125
+ const separatorIndex = data.indexOf(separator);
126
+ if (separatorIndex === -1) {
127
+ if (missingData) {
128
+ missingData.dataMissing -= data.length;
129
+ }
130
+ if (!missingData || missingData.dataMissing > 0) {
131
+ return;
132
+ }
133
+ }
134
+ unprocessedBuffers.unshift(outputBuffer);
135
+ outputBuffer = Buffer.concat(unprocessedBuffers);
136
+ unprocessedBuffers = [];
137
+ processInput();
138
+ });
139
+ child.stderr.on('data', (data) => {
140
+ stderrChunks.push(data);
141
+ });
142
+ let resolve = null;
143
+ let reject = null;
144
+ child.on('close', (code) => {
145
+ quit = true;
146
+ const waitersToKill = Array.from(waiters.values());
147
+ if (code === 0) {
148
+ resolve === null || resolve === void 0 ? void 0 : resolve();
149
+ for (const waiter of waitersToKill) {
150
+ waiter.reject(new Error(`Compositor already quit`));
151
+ }
152
+ waiters.clear();
153
+ }
154
+ else {
155
+ const error = new Error(`Compositor panicked: ${Buffer.concat(stderrChunks).toString('utf-8')}`);
156
+ for (const waiter of waitersToKill) {
157
+ waiter.reject(error);
158
+ }
159
+ waiters.clear();
160
+ reject === null || reject === void 0 ? void 0 : reject(error);
161
+ }
162
+ });
163
+ return {
164
+ waitForDone: () => {
165
+ return new Promise((res, rej) => {
166
+ if (quit) {
167
+ rej(new Error('Compositor already quit'));
168
+ return;
169
+ }
170
+ resolve = res;
171
+ reject = rej;
172
+ });
173
+ },
174
+ finishCommands: () => {
175
+ if (quit) {
176
+ throw new Error('Compositor already quit');
177
+ }
178
+ child.stdin.write('EOF\n');
179
+ },
180
+ executeCommand: (command, params) => {
181
+ if (quit) {
182
+ throw new Error('Compositor already quit');
183
+ }
184
+ return new Promise((_resolve, _reject) => {
185
+ const nonce = (0, make_nonce_1.makeNonce)();
186
+ const composed = {
187
+ nonce,
188
+ payload: {
189
+ type: command,
190
+ params,
191
+ },
192
+ };
193
+ // TODO: Should have a way to error out a single task
194
+ child.stdin.write(JSON.stringify(composed) + '\n');
195
+ waiters.set(nonce, {
196
+ resolve: _resolve,
197
+ reject: _reject,
198
+ });
199
+ });
200
+ },
201
+ pid: (_a = child.pid) !== null && _a !== void 0 ? _a : null,
202
+ };
203
+ };
204
+ exports.startCompositor = startCompositor;
@@ -1 +1 @@
1
- export declare const getExecutablePath: () => any;
1
+ export declare const getExecutablePath: (type: 'compositor' | 'ffmpeg' | 'ffprobe' | 'ffmpeg-cwd') => string;
@@ -7,21 +7,40 @@ function isMusl() {
7
7
  const { glibcVersionRuntime } = process.report.getReport().header;
8
8
  return !glibcVersionRuntime;
9
9
  }
10
- const getExecutablePath = () => {
10
+ const getExecutablePath = (type) => {
11
+ if (type === 'ffmpeg' && process.env.FFMPEG_BIN_PATH) {
12
+ return '/opt/ffmpeg/remotion/bin/ffmpeg';
13
+ }
14
+ if (type === 'ffprobe' && process.env.FFPROBE_BIN_PATH) {
15
+ return '/opt/ffmpeg/remotion/bin/ffprobe';
16
+ }
17
+ if (type === 'ffmpeg-cwd' && process.env.FFMPEG_CWD) {
18
+ return '/opt/ffmpeg';
19
+ }
20
+ if (type === 'compositor' && process.env.COMPOSITOR_PATH) {
21
+ return './compositor';
22
+ }
23
+ const key = type === 'compositor'
24
+ ? 'binaryPath'
25
+ : type === 'ffmpeg'
26
+ ? 'ffmpegPath'
27
+ : type === 'ffprobe'
28
+ ? 'ffprobePath'
29
+ : 'ffmpegCwd';
11
30
  switch (process.platform) {
12
31
  case 'win32':
13
32
  switch (process.arch) {
14
33
  case 'x64':
15
- return require('@remotion/compositor-win32-x64-msvc').binaryPath;
34
+ return require('@remotion/compositor-win32-x64-msvc')[key];
16
35
  default:
17
36
  throw new Error(`Unsupported architecture on Windows: ${process.arch}`);
18
37
  }
19
38
  case 'darwin':
20
39
  switch (process.arch) {
21
40
  case 'x64':
22
- return require('@remotion/compositor-darwin-x64').binaryPath;
41
+ return require('@remotion/compositor-darwin-x64')[key];
23
42
  case 'arm64':
24
- return require('@remotion/compositor-darwin-arm64').binaryPath;
43
+ return require('@remotion/compositor-darwin-arm64')[key];
25
44
  default:
26
45
  throw new Error(`Unsupported architecture on macOS: ${process.arch}`);
27
46
  }
@@ -29,14 +48,14 @@ const getExecutablePath = () => {
29
48
  switch (process.arch) {
30
49
  case 'x64':
31
50
  if (isMusl()) {
32
- return require('@remotion/compositor-linux-x64-musl').binaryPath;
51
+ return require('@remotion/compositor-linux-x64-musl')[key];
33
52
  }
34
- return require('@remotion/compositor-linux-x64-gnu').binaryPath;
53
+ return require('@remotion/compositor-linux-x64-gnu')[key];
35
54
  case 'arm64':
36
55
  if (isMusl()) {
37
- return require('@remotion/compositor-linux-arm64-musl').binaryPath;
56
+ return require('@remotion/compositor-linux-arm64-musl')[key];
38
57
  }
39
- return require('@remotion/compositor-linux-arm64-gnu').binaryPath;
58
+ return require('@remotion/compositor-linux-arm64-gnu')[key];
40
59
  default:
41
60
  throw new Error(`Unsupported architecture on Linux: ${process.arch}`);
42
61
  }
@@ -0,0 +1 @@
1
+ export declare const makeNonce: () => string;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeNonce = void 0;
4
+ const makeNonce = () => {
5
+ return (Math.random().toString(36).substring(2, 15) +
6
+ Math.random().toString(36).substring(2, 15));
7
+ };
8
+ exports.makeNonce = makeNonce;
@@ -27,13 +27,40 @@ export declare type Layer = {
27
27
  };
28
28
  };
29
29
  export declare type CompositorImageFormat = 'Png' | 'Jpeg';
30
- export declare type CliInput = {
31
- v: number;
32
- output: string;
33
- width: number;
34
- height: number;
35
- layers: Layer[];
36
- output_format: CompositorImageFormat;
30
+ export declare type CompositorCommand = {
31
+ Compose: {
32
+ output: string;
33
+ width: number;
34
+ height: number;
35
+ layers: Layer[];
36
+ output_format: CompositorImageFormat;
37
+ };
38
+ ExtractFrame: {
39
+ input: string;
40
+ time: number;
41
+ transparent: boolean;
42
+ };
43
+ Echo: {
44
+ message: string;
45
+ };
46
+ StartLongRunningProcess: {
47
+ concurrency: number;
48
+ maximum_frame_cache_items: number;
49
+ verbose: boolean;
50
+ };
51
+ GetOpenVideoStats: {};
52
+ DeliberatePanic: {};
53
+ CloseAllVideos: {};
54
+ FreeUpMemory: {
55
+ percent_of_memory: number;
56
+ };
57
+ };
58
+ export declare type CompositorCommandSerialized<T extends keyof CompositorCommand> = {
59
+ nonce: string;
60
+ payload: {
61
+ type: T;
62
+ params: CompositorCommand[T];
63
+ };
37
64
  };
38
65
  export declare type ErrorPayload = {
39
66
  error: string;
@@ -1,12 +1,12 @@
1
1
  import type { DownloadMap } from './assets/download-map';
2
- import type { FfmpegExecutable } from './ffmpeg-executable';
3
2
  import type { PreprocessedAudioTrack } from './preprocess-audio-track';
4
- export declare const createFfmpegComplexFilter: ({ filters, downloadMap, ffmpegExecutable, remotionRoot, }: {
3
+ export declare const createFfmpegComplexFilter: ({ filters, downloadMap, }: {
5
4
  filters: PreprocessedAudioTrack[];
6
5
  downloadMap: DownloadMap;
7
- ffmpegExecutable: FfmpegExecutable;
8
- remotionRoot: string;
9
6
  }) => Promise<{
10
- complexFilterFlag: [string, string] | null;
7
+ complexFilterFlag: [
8
+ string,
9
+ string
10
+ ] | null;
11
11
  cleanup: () => void;
12
12
  }>;
@@ -3,14 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createFfmpegComplexFilter = void 0;
4
4
  const create_ffmpeg_merge_filter_1 = require("./create-ffmpeg-merge-filter");
5
5
  const ffmpeg_filter_file_1 = require("./ffmpeg-filter-file");
6
- const createFfmpegComplexFilter = async ({ filters, downloadMap, ffmpegExecutable, remotionRoot, }) => {
6
+ const createFfmpegComplexFilter = async ({ filters, downloadMap, }) => {
7
7
  if (filters.length === 0) {
8
8
  return { complexFilterFlag: null, cleanup: () => undefined };
9
9
  }
10
- const complexFilter = await (0, create_ffmpeg_merge_filter_1.createFfmpegMergeFilter)({
10
+ const complexFilter = (0, create_ffmpeg_merge_filter_1.createFfmpegMergeFilter)({
11
11
  inputs: filters,
12
- ffmpegExecutable,
13
- remotionRoot,
14
12
  });
15
13
  const { file, cleanup } = await (0, ffmpeg_filter_file_1.makeFfmpegFilterFileStr)(complexFilter, downloadMap);
16
14
  return {
@@ -1,8 +1,5 @@
1
- import type { FfmpegExecutable } from './ffmpeg-executable';
2
1
  import type { PreprocessedAudioTrack } from './preprocess-audio-track';
3
2
  export declare const OUTPUT_FILTER_NAME = "outputaudio";
4
- export declare const createFfmpegMergeFilter: ({ inputs, ffmpegExecutable, remotionRoot, }: {
3
+ export declare const createFfmpegMergeFilter: ({ inputs, }: {
5
4
  inputs: PreprocessedAudioTrack[];
6
- ffmpegExecutable: FfmpegExecutable;
7
- remotionRoot: string;
8
- }) => Promise<string>;
5
+ }) => string;
@@ -1,17 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createFfmpegMergeFilter = exports.OUTPUT_FILTER_NAME = void 0;
4
- const ffmpeg_flags_1 = require("./ffmpeg-flags");
5
4
  const truthy_1 = require("./truthy");
6
5
  exports.OUTPUT_FILTER_NAME = 'outputaudio';
7
- const createFfmpegMergeFilter = async ({ inputs, ffmpegExecutable, remotionRoot, }) => {
8
- const ffmpegVersion = await (0, ffmpeg_flags_1.getFfmpegVersion)({
9
- ffmpegExecutable,
10
- remotionRoot,
11
- });
12
- const supportsNormalize = ffmpegVersion === null ||
13
- (ffmpegVersion[0] === 4 && ffmpegVersion[1] >= 4) ||
14
- ffmpegVersion[0] >= 5;
6
+ const createFfmpegMergeFilter = ({ inputs, }) => {
15
7
  const pads = inputs.map((input, index) => {
16
8
  const filters = [
17
9
  input.filter.pad_start ? input.filter.pad_start : null,
@@ -20,7 +12,7 @@ const createFfmpegMergeFilter = async ({ inputs, ffmpegExecutable, remotionRoot,
20
12
  ];
21
13
  return `[${index}:a]${filters.filter(truthy_1.truthy).join(',')}[padded${index}]`;
22
14
  });
23
- const normalize = supportsNormalize ? ':normalize=0' : '';
15
+ const normalize = ':normalize=0';
24
16
  return [
25
17
  ...pads,
26
18
  `${new Array(inputs.length)
@@ -1,7 +1,4 @@
1
- import type { FfmpegExecutable } from './ffmpeg-executable';
2
- export declare const createSilentAudio: ({ ffmpegExecutable, numberOfSeconds, outName, remotionRoot, }: {
3
- ffmpegExecutable: FfmpegExecutable;
1
+ export declare const createSilentAudio: ({ numberOfSeconds, outName, }: {
4
2
  numberOfSeconds: number;
5
3
  outName: string;
6
- remotionRoot: string;
7
4
  }) => Promise<void>;
@@ -1,14 +1,10 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.createSilentAudio = void 0;
7
- const execa_1 = __importDefault(require("execa"));
8
- const ffmpeg_flags_1 = require("./ffmpeg-flags");
4
+ const call_ffmpeg_1 = require("./call-ffmpeg");
9
5
  const sample_rate_1 = require("./sample-rate");
10
- const createSilentAudio = async ({ ffmpegExecutable, numberOfSeconds, outName, remotionRoot, }) => {
11
- await (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), [
6
+ const createSilentAudio = async ({ numberOfSeconds, outName, }) => {
7
+ await (0, call_ffmpeg_1.callFf)('ffmpeg', [
12
8
  '-f',
13
9
  'lavfi',
14
10
  '-i',
package/dist/crf.js CHANGED
@@ -9,7 +9,7 @@ const getDefaultCrfForCodec = (codec) => {
9
9
  if (codec === 'h264' || codec === 'h264-mkv') {
10
10
  return 18; // FFMPEG default 23
11
11
  }
12
- if (codec === 'h265' || codec === 'gif') {
12
+ if (codec === 'h265') {
13
13
  return 23; // FFMPEG default 28
14
14
  }
15
15
  if (codec === 'vp8') {
@@ -21,6 +21,9 @@ const getDefaultCrfForCodec = (codec) => {
21
21
  if (codec === 'prores') {
22
22
  return 0;
23
23
  }
24
+ if (codec === 'gif') {
25
+ return 0;
26
+ }
24
27
  throw new TypeError(`Got unexpected codec "${codec}"`);
25
28
  };
26
29
  exports.getDefaultCrfForCodec = getDefaultCrfForCodec;
@@ -31,10 +34,13 @@ const getValidCrfRanges = (codec) => {
31
34
  if (codec === 'prores') {
32
35
  return [0, 0];
33
36
  }
37
+ if (codec === 'gif') {
38
+ return [0, 0];
39
+ }
34
40
  if (codec === 'h264' || codec === 'h264-mkv') {
35
41
  return [1, 51];
36
42
  }
37
- if (codec === 'h265' || codec === 'gif') {
43
+ if (codec === 'h265') {
38
44
  return [0, 51];
39
45
  }
40
46
  if (codec === 'vp8') {