@remotion/renderer 4.0.0-fastlambda.8 → 4.0.0-lambda.3

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 (191) hide show
  1. package/dist/assets/cleanup-assets.d.ts +2 -0
  2. package/dist/assets/cleanup-assets.js +2 -0
  3. package/dist/assets/download-and-map-assets-to-file.d.ts +6 -0
  4. package/dist/assets/download-and-map-assets-to-file.js +46 -19
  5. package/dist/assets/ffmpeg-volume-expression.d.ts +2 -1
  6. package/dist/assets/ffmpeg-volume-expression.js +15 -12
  7. package/dist/assets/get-audio-channels.d.ts +5 -2
  8. package/dist/assets/get-audio-channels.js +15 -4
  9. package/dist/browser/Accessibility.d.ts +175 -0
  10. package/dist/browser/Accessibility.js +423 -0
  11. package/dist/browser/AriaQueryHandler.d.ts +20 -0
  12. package/dist/browser/AriaQueryHandler.js +108 -0
  13. package/dist/browser/Browser.d.ts +209 -0
  14. package/dist/browser/Browser.js +402 -0
  15. package/dist/browser/BrowserConnector.d.ts +26 -0
  16. package/dist/browser/BrowserConnector.js +49 -0
  17. package/dist/browser/BrowserFetcher.d.ts +89 -0
  18. package/dist/browser/BrowserFetcher.js +512 -0
  19. package/dist/browser/BrowserRunner.d.ts +39 -0
  20. package/dist/browser/BrowserRunner.js +308 -0
  21. package/dist/browser/Connection.d.ts +49 -0
  22. package/dist/browser/Connection.js +262 -0
  23. package/dist/browser/ConnectionTransport.d.ts +21 -0
  24. package/dist/browser/ConnectionTransport.js +17 -0
  25. package/dist/browser/ConsoleMessage.d.ts +55 -0
  26. package/dist/browser/ConsoleMessage.js +75 -0
  27. package/dist/browser/Coverage.d.ts +180 -0
  28. package/dist/browser/Coverage.js +371 -0
  29. package/dist/browser/DOMWorld.d.ts +50 -0
  30. package/dist/browser/DOMWorld.js +280 -0
  31. package/dist/browser/Debug.d.ts +19 -0
  32. package/dist/browser/Debug.js +42 -0
  33. package/dist/browser/DeviceDescriptors.d.ts +40 -0
  34. package/dist/browser/DeviceDescriptors.js +1407 -0
  35. package/dist/browser/EmulationManager.d.ts +7 -0
  36. package/dist/browser/EmulationManager.js +40 -0
  37. package/dist/browser/Errors.d.ts +25 -0
  38. package/dist/browser/Errors.js +35 -0
  39. package/dist/browser/EvalTypes.d.ts +27 -0
  40. package/dist/browser/EvalTypes.js +17 -0
  41. package/dist/browser/EventEmitter.d.ts +70 -0
  42. package/dist/browser/EventEmitter.js +102 -0
  43. package/dist/browser/ExecutionContext.d.ts +35 -0
  44. package/dist/browser/ExecutionContext.js +190 -0
  45. package/dist/browser/FileChooser.d.ts +56 -0
  46. package/dist/browser/FileChooser.js +86 -0
  47. package/dist/browser/FrameManager.d.ts +96 -0
  48. package/dist/browser/FrameManager.js +512 -0
  49. package/dist/browser/HTTPRequest.d.ts +42 -0
  50. package/dist/browser/HTTPRequest.js +82 -0
  51. package/dist/browser/HTTPResponse.d.ts +100 -0
  52. package/dist/browser/HTTPResponse.js +196 -0
  53. package/dist/browser/Input.d.ts +355 -0
  54. package/dist/browser/Input.js +592 -0
  55. package/dist/browser/JSHandle.d.ts +36 -0
  56. package/dist/browser/JSHandle.js +93 -0
  57. package/dist/browser/LaunchOptions.d.ts +117 -0
  58. package/dist/browser/LaunchOptions.js +17 -0
  59. package/dist/browser/Launcher.d.ts +9 -0
  60. package/dist/browser/Launcher.js +602 -0
  61. package/dist/browser/LifecycleWatcher.d.ts +29 -0
  62. package/dist/browser/LifecycleWatcher.js +193 -0
  63. package/dist/browser/NetworkConditions.d.ts +26 -0
  64. package/dist/browser/NetworkConditions.js +33 -0
  65. package/dist/browser/NetworkEventManager.d.ts +35 -0
  66. package/dist/browser/NetworkEventManager.js +128 -0
  67. package/dist/browser/NetworkManager.d.ts +36 -0
  68. package/dist/browser/NetworkManager.js +284 -0
  69. package/dist/browser/NodeWebSocketTransport.d.ts +11 -0
  70. package/dist/browser/NodeWebSocketTransport.js +90 -0
  71. package/dist/browser/PDFOptions.d.ts +165 -0
  72. package/dist/browser/PDFOptions.js +34 -0
  73. package/dist/browser/PipeTransport.d.ts +10 -0
  74. package/dist/browser/PipeTransport.js +86 -0
  75. package/dist/browser/Product.d.ts +16 -0
  76. package/dist/browser/Product.js +17 -0
  77. package/dist/browser/Puppeteer.d.ts +35 -0
  78. package/dist/browser/Puppeteer.js +17 -0
  79. package/dist/browser/PuppeteerNode.d.ts +92 -0
  80. package/dist/browser/PuppeteerNode.js +143 -0
  81. package/dist/browser/PuppeteerViewport.d.ts +5 -0
  82. package/dist/browser/PuppeteerViewport.js +2 -0
  83. package/dist/browser/QueryHandler.d.ts +64 -0
  84. package/dist/browser/QueryHandler.js +183 -0
  85. package/dist/browser/ScreenshotOptions.d.ts +14 -0
  86. package/dist/browser/ScreenshotOptions.js +2 -0
  87. package/dist/browser/SecurityDetails.d.ts +55 -0
  88. package/dist/browser/SecurityDetails.js +95 -0
  89. package/dist/browser/Target.d.ts +61 -0
  90. package/dist/browser/Target.js +146 -0
  91. package/dist/browser/TaskQueue.d.ts +20 -0
  92. package/dist/browser/TaskQueue.js +47 -0
  93. package/dist/browser/TimeoutSettings.d.ts +23 -0
  94. package/dist/browser/TimeoutSettings.js +62 -0
  95. package/dist/browser/Tracing.d.ts +45 -0
  96. package/dist/browser/Tracing.js +136 -0
  97. package/dist/browser/USKeyboardLayout.d.ts +39 -0
  98. package/dist/browser/USKeyboardLayout.js +406 -0
  99. package/dist/browser/WebWorker.d.ts +96 -0
  100. package/dist/browser/WebWorker.js +122 -0
  101. package/dist/browser/assert.d.ts +21 -0
  102. package/dist/browser/assert.js +29 -0
  103. package/dist/browser/compat.d.ts +2 -0
  104. package/dist/browser/compat.js +17 -0
  105. package/dist/browser/create-browser-fetcher.d.ts +17 -0
  106. package/dist/browser/create-browser-fetcher.js +140 -0
  107. package/dist/browser/dialog.d.ts +70 -0
  108. package/dist/browser/dialog.js +114 -0
  109. package/dist/browser/environment.d.ts +16 -0
  110. package/dist/browser/environment.js +19 -0
  111. package/dist/browser/fetch.d.ts +16 -0
  112. package/dist/browser/fetch.js +46 -0
  113. package/dist/browser/find-up.d.ts +4 -0
  114. package/dist/browser/find-up.js +85 -0
  115. package/dist/browser/get-download-destination.d.ts +1 -0
  116. package/dist/browser/get-download-destination.js +38 -0
  117. package/dist/browser/mitt/index.d.ts +22 -0
  118. package/dist/browser/mitt/index.js +49 -0
  119. package/dist/browser/node.d.ts +2 -0
  120. package/dist/browser/node.js +9 -0
  121. package/dist/browser/page.d.ts +78 -0
  122. package/dist/browser/page.js +277 -0
  123. package/dist/browser/pkg-dir.d.ts +3 -0
  124. package/dist/browser/pkg-dir.js +13 -0
  125. package/dist/browser/revisions.d.ts +21 -0
  126. package/dist/browser/revisions.js +22 -0
  127. package/dist/browser/util.d.ts +46 -0
  128. package/dist/browser/util.js +161 -0
  129. package/dist/calculate-ffmpeg-filters.js +2 -2
  130. package/dist/combine-videos.d.ts +2 -1
  131. package/dist/combine-videos.js +8 -1
  132. package/dist/cycle-browser-tabs.d.ts +2 -1
  133. package/dist/cycle-browser-tabs.js +9 -2
  134. package/dist/ensure-presentation-timestamp.d.ts +1 -0
  135. package/dist/ensure-presentation-timestamp.js +57 -0
  136. package/dist/extract-frame-from-video.d.ts +11 -0
  137. package/dist/extract-frame-from-video.js +197 -0
  138. package/dist/frame-to-ffmpeg-timestamp.d.ts +1 -0
  139. package/dist/frame-to-ffmpeg-timestamp.js +8 -0
  140. package/dist/get-compositions.d.ts +5 -2
  141. package/dist/get-compositions.js +23 -5
  142. package/dist/get-duration-of-asset.d.ts +7 -0
  143. package/dist/get-duration-of-asset.js +36 -0
  144. package/dist/get-port.js +26 -24
  145. package/dist/index.d.ts +33 -9
  146. package/dist/index.js +14 -5
  147. package/dist/is-beyond-last-frame.d.ts +2 -0
  148. package/dist/is-beyond-last-frame.js +12 -0
  149. package/dist/last-frame-from-video-cache.d.ts +10 -0
  150. package/dist/last-frame-from-video-cache.js +50 -0
  151. package/dist/make-assets-download-dir.js +6 -1
  152. package/dist/make-cancel-signal.d.ts +7 -0
  153. package/dist/make-cancel-signal.js +25 -0
  154. package/dist/merge-audio-track.js +2 -2
  155. package/dist/offthread-video-server.d.ts +14 -0
  156. package/dist/offthread-video-server.js +67 -0
  157. package/dist/open-browser.d.ts +6 -6
  158. package/dist/open-browser.js +24 -20
  159. package/dist/prepare-server.d.ts +13 -2
  160. package/dist/prepare-server.js +35 -5
  161. package/dist/preprocess-audio-track.d.ts +1 -0
  162. package/dist/preprocess-audio-track.js +2 -2
  163. package/dist/prespawn-ffmpeg.d.ts +2 -0
  164. package/dist/prespawn-ffmpeg.js +10 -9
  165. package/dist/provide-screenshot.js +1 -1
  166. package/dist/puppeteer-screenshot.js +5 -1
  167. package/dist/render-frames.d.ts +6 -1
  168. package/dist/render-frames.js +96 -37
  169. package/dist/render-media.d.ts +12 -2
  170. package/dist/render-media.js +127 -54
  171. package/dist/render-still.d.ts +14 -4
  172. package/dist/render-still.js +58 -19
  173. package/dist/serve-handler/glob-slash.d.ts +1 -0
  174. package/dist/serve-handler/glob-slash.js +12 -0
  175. package/dist/serve-handler/index.d.ts +4 -0
  176. package/dist/serve-handler/index.js +205 -0
  177. package/dist/serve-handler/is-path-inside.d.ts +1 -0
  178. package/dist/serve-handler/is-path-inside.js +27 -0
  179. package/dist/serve-handler/range-parser.d.ts +13 -0
  180. package/dist/serve-handler/range-parser.js +57 -0
  181. package/dist/serve-static.d.ts +10 -3
  182. package/dist/serve-static.js +22 -4
  183. package/dist/set-props-and-env.d.ts +3 -1
  184. package/dist/set-props-and-env.js +28 -6
  185. package/dist/stitch-frames-to-video.d.ts +4 -1
  186. package/dist/stitch-frames-to-video.js +36 -15
  187. package/dist/stringify-ffmpeg-filter.js +3 -0
  188. package/dist/tmp-dir.js +5 -1
  189. package/dist/validate-fps-for-gif.d.ts +2 -0
  190. package/dist/validate-fps-for-gif.js +9 -0
  191. package/package.json +6 -7
@@ -16,6 +16,7 @@ const get_extension_from_codec_1 = require("./get-extension-from-codec");
16
16
  const get_extension_of_filename_1 = require("./get-extension-of-filename");
17
17
  const get_frame_to_render_1 = require("./get-frame-to-render");
18
18
  const legacy_webpack_config_1 = require("./legacy-webpack-config");
19
+ const make_cancel_signal_1 = require("./make-cancel-signal");
19
20
  const prespawn_ffmpeg_1 = require("./prespawn-ffmpeg");
20
21
  const render_frames_1 = require("./render-frames");
21
22
  const stitch_frames_to_video_1 = require("./stitch-frames-to-video");
@@ -23,8 +24,12 @@ const tmp_dir_1 = require("./tmp-dir");
23
24
  const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
24
25
  const validate_output_filename_1 = require("./validate-output-filename");
25
26
  const validate_scale_1 = require("./validate-scale");
26
- const renderMedia = async ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, ...options }) => {
27
- var _a;
27
+ /**
28
+ *
29
+ * @description Render a video from a composition
30
+ * @link https://www.remotion.dev/docs/renderer/render-media
31
+ */
32
+ 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 }) => {
28
33
  remotion_1.Internals.validateQuality(quality);
29
34
  if (typeof crf !== 'undefined' && crf !== null) {
30
35
  remotion_1.Internals.validateSelectedCrfAndCodecCombination(crf, codec);
@@ -39,6 +44,7 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
39
44
  let renderedFrames = 0;
40
45
  let renderedDoneIn = null;
41
46
  let encodedDoneIn = null;
47
+ let cancelled = false;
42
48
  const renderStart = Date.now();
43
49
  const tmpdir = (0, tmp_dir_1.tmpDir)('pre-encode');
44
50
  const parallelEncoding = (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec);
@@ -48,23 +54,31 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
48
54
  : null;
49
55
  const outputDir = parallelEncoding
50
56
  ? null
51
- : await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'react-motion-render'));
57
+ : fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'react-motion-render'));
52
58
  (0, validate_even_dimensions_with_codec_1.validateEvenDimensionsWithCodec)({
53
59
  codec,
54
60
  height: composition.height,
55
61
  scale: scale !== null && scale !== void 0 ? scale : 1,
56
62
  width: composition.width,
57
63
  });
58
- try {
59
- const callUpdate = () => {
60
- onProgress === null || onProgress === void 0 ? void 0 : onProgress({
61
- encodedDoneIn,
62
- encodedFrames,
63
- renderedDoneIn,
64
- renderedFrames,
65
- stitchStage,
66
- });
67
- };
64
+ const callUpdate = () => {
65
+ onProgress === null || onProgress === void 0 ? void 0 : onProgress({
66
+ encodedDoneIn,
67
+ encodedFrames,
68
+ renderedDoneIn,
69
+ renderedFrames,
70
+ stitchStage,
71
+ });
72
+ };
73
+ const realFrameRange = (0, get_frame_to_render_1.getRealFrameRange)(composition.durationInFrames, frameRange !== null && frameRange !== void 0 ? frameRange : null);
74
+ const cancelRenderFrames = (0, make_cancel_signal_1.makeCancelSignal)();
75
+ const cancelPrestitcher = (0, make_cancel_signal_1.makeCancelSignal)();
76
+ const cancelStitcher = (0, make_cancel_signal_1.makeCancelSignal)();
77
+ cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
78
+ cancelRenderFrames.cancel();
79
+ });
80
+ const { waitForRightTimeOfFrameToBeInserted, setFrameToStitch, waitForFinish } = (0, ensure_frames_in_order_1.ensureFramesInOrder)(realFrameRange);
81
+ const createPrestitcherIfNecessary = async () => {
68
82
  if (preEncodedFileLocation) {
69
83
  preStitcher = await (0, prespawn_ffmpeg_1.prespawnFfmpeg)({
70
84
  width: composition.width * (scale !== null && scale !== void 0 ? scale : 1),
@@ -82,12 +96,27 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
82
96
  verbose: remotion_1.Internals.Logging.isEqualOrBelowLogLevel(remotion_1.Internals.Logging.getLogLevel(), 'verbose'),
83
97
  ffmpegExecutable,
84
98
  imageFormat: actualImageFormat,
99
+ signal: cancelPrestitcher.cancelSignal,
85
100
  });
86
101
  stitcherFfmpeg = preStitcher.task;
87
102
  }
88
- const realFrameRange = (0, get_frame_to_render_1.getRealFrameRange)(composition.durationInFrames, frameRange !== null && frameRange !== void 0 ? frameRange : null);
89
- const { waitForRightTimeOfFrameToBeInserted, setFrameToStitch, waitForFinish, } = (0, ensure_frames_in_order_1.ensureFramesInOrder)(realFrameRange);
90
- const { assetsInfo } = await (0, render_frames_1.renderFrames)({
103
+ };
104
+ const waitForPrestitcherIfNecessary = async () => {
105
+ var _a;
106
+ if (stitcherFfmpeg) {
107
+ await waitForFinish();
108
+ (_a = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin) === null || _a === void 0 ? void 0 : _a.end();
109
+ try {
110
+ await stitcherFfmpeg;
111
+ }
112
+ catch (err) {
113
+ throw new Error(preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.getLogs());
114
+ }
115
+ }
116
+ };
117
+ const happyPath = createPrestitcherIfNecessary()
118
+ .then(() => {
119
+ const renderFramesProc = (0, render_frames_1.renderFrames)({
91
120
  config: composition,
92
121
  onFrameUpdate: (frame) => {
93
122
  renderedFrames = frame;
@@ -110,7 +139,12 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
110
139
  ? async (buffer, frame) => {
111
140
  var _a;
112
141
  await waitForRightTimeOfFrameToBeInserted(frame);
142
+ if (cancelled) {
143
+ return;
144
+ }
145
+ const id = remotion_1.Internals.perf.startPerfMeasure('piping');
113
146
  (_a = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin) === null || _a === void 0 ? void 0 : _a.write(buffer);
147
+ remotion_1.Internals.perf.stopPerfMeasure(id);
114
148
  setFrameToStitch(frame + 1);
115
149
  }
116
150
  : undefined,
@@ -121,55 +155,94 @@ const renderMedia = async ({ parallelism, proResProfile, crf, composition, image
121
155
  timeoutInMilliseconds,
122
156
  chromiumOptions,
123
157
  scale,
158
+ ffmpegExecutable,
159
+ ffprobeExecutable,
160
+ browserExecutable,
161
+ port,
162
+ cancelSignal: cancelRenderFrames.cancelSignal,
124
163
  });
125
- if (stitcherFfmpeg) {
126
- await waitForFinish();
127
- (_a = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin) === null || _a === void 0 ? void 0 : _a.end();
128
- try {
129
- await stitcherFfmpeg;
130
- }
131
- catch (err) {
132
- throw new Error(preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.getLogs());
133
- }
134
- }
164
+ return renderFramesProc;
165
+ })
166
+ .then((renderFramesReturn) => {
167
+ return Promise.all([renderFramesReturn, waitForPrestitcherIfNecessary()]);
168
+ })
169
+ .then(([{ assetsInfo }]) => {
135
170
  renderedDoneIn = Date.now() - renderStart;
136
171
  callUpdate();
137
172
  (0, ensure_output_directory_1.ensureOutputDirectory)(outputLocation);
138
173
  const stitchStart = Date.now();
139
- await (0, stitch_frames_to_video_1.stitchFramesToVideo)({
140
- width: composition.width * (scale !== null && scale !== void 0 ? scale : 1),
141
- height: composition.height * (scale !== null && scale !== void 0 ? scale : 1),
142
- fps: composition.fps,
143
- outputLocation,
144
- internalOptions: {
145
- preEncodedFileLocation,
146
- imageFormat: actualImageFormat,
147
- },
148
- force: overwrite !== null && overwrite !== void 0 ? overwrite : remotion_1.Internals.DEFAULT_OVERWRITE,
149
- pixelFormat,
150
- codec,
151
- proResProfile,
152
- crf,
153
- assetsInfo,
154
- ffmpegExecutable,
155
- onProgress: (frame) => {
156
- stitchStage = 'muxing';
157
- encodedFrames = frame;
158
- callUpdate();
159
- },
160
- onDownload,
161
- verbose: remotion_1.Internals.Logging.isEqualOrBelowLogLevel(remotion_1.Internals.Logging.getLogLevel(), 'verbose'),
162
- dir: outputDir !== null && outputDir !== void 0 ? outputDir : undefined,
163
- });
174
+ return Promise.all([
175
+ (0, stitch_frames_to_video_1.stitchFramesToVideo)({
176
+ width: composition.width * (scale !== null && scale !== void 0 ? scale : 1),
177
+ height: composition.height * (scale !== null && scale !== void 0 ? scale : 1),
178
+ fps: composition.fps,
179
+ outputLocation,
180
+ internalOptions: {
181
+ preEncodedFileLocation,
182
+ imageFormat: actualImageFormat,
183
+ },
184
+ force: overwrite !== null && overwrite !== void 0 ? overwrite : remotion_1.Internals.DEFAULT_OVERWRITE,
185
+ pixelFormat,
186
+ codec,
187
+ proResProfile,
188
+ crf,
189
+ assetsInfo,
190
+ ffmpegExecutable,
191
+ ffprobeExecutable,
192
+ onProgress: (frame) => {
193
+ stitchStage = 'muxing';
194
+ encodedFrames = frame;
195
+ callUpdate();
196
+ },
197
+ onDownload,
198
+ verbose: remotion_1.Internals.Logging.isEqualOrBelowLogLevel(remotion_1.Internals.Logging.getLogLevel(), 'verbose'),
199
+ dir: outputDir !== null && outputDir !== void 0 ? outputDir : undefined,
200
+ cancelSignal: cancelStitcher.cancelSignal,
201
+ }),
202
+ stitchStart,
203
+ ]);
204
+ })
205
+ .then(([, stitchStart]) => {
164
206
  encodedFrames = (0, get_duration_from_frame_range_1.getDurationFromFrameRange)(frameRange !== null && frameRange !== void 0 ? frameRange : null, composition.durationInFrames);
165
207
  encodedDoneIn = Date.now() - stitchStart;
166
208
  callUpdate();
167
- }
168
- finally {
209
+ })
210
+ .catch((err) => {
211
+ /**
212
+ * 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.
213
+ * Therefore we first kill the FFMPEG process before deleting the file
214
+ */
215
+ cancelled = true;
216
+ cancelRenderFrames.cancel();
217
+ cancelStitcher.cancel();
218
+ cancelPrestitcher.cancel();
219
+ if (stitcherFfmpeg !== undefined && stitcherFfmpeg.exitCode === null) {
220
+ const promise = new Promise((resolve) => {
221
+ setTimeout(() => {
222
+ resolve();
223
+ }, 2000);
224
+ stitcherFfmpeg.on('close', resolve);
225
+ });
226
+ stitcherFfmpeg.kill();
227
+ return promise.then(() => {
228
+ throw err;
229
+ });
230
+ }
231
+ throw err;
232
+ })
233
+ .finally(() => {
169
234
  if (preEncodedFileLocation !== null &&
170
235
  fs_1.default.existsSync(preEncodedFileLocation)) {
171
236
  fs_1.default.unlinkSync(preEncodedFileLocation);
172
237
  }
173
- }
238
+ });
239
+ return Promise.race([
240
+ happyPath,
241
+ new Promise((_resolve, reject) => {
242
+ cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
243
+ reject(new Error('renderMedia() got cancelled'));
244
+ });
245
+ }),
246
+ ]);
174
247
  };
175
248
  exports.renderMedia = renderMedia;
@@ -1,9 +1,11 @@
1
1
  import { Browser as PuppeteerBrowser } from 'puppeteer-core';
2
- import { BrowserExecutable, StillImageFormat, TCompMetadata } from 'remotion';
2
+ import { BrowserExecutable, FfmpegExecutable, SmallTCompMetadata, StillImageFormat } from 'remotion';
3
+ import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
3
4
  import { ServeUrlOrWebpackBundle } from './legacy-webpack-config';
5
+ import { CancelSignal } from './make-cancel-signal';
4
6
  import { ChromiumOptions } from './open-browser';
5
7
  declare type InnerStillOptions = {
6
- composition: TCompMetadata;
8
+ composition: SmallTCompMetadata;
7
9
  output: string;
8
10
  frame?: number;
9
11
  inputProps?: unknown;
@@ -17,10 +19,18 @@ declare type InnerStillOptions = {
17
19
  timeoutInMilliseconds?: number;
18
20
  chromiumOptions?: ChromiumOptions;
19
21
  scale?: number;
22
+ onDownload?: RenderMediaOnDownload;
23
+ cancelSignal?: CancelSignal;
24
+ ffmpegExecutable?: FfmpegExecutable;
25
+ ffprobeExecutable?: FfmpegExecutable;
26
+ };
27
+ declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle & {
28
+ port?: number | null;
20
29
  };
21
- declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle;
22
30
  /**
23
- * @description Render a still frame from a composition and returns an image path
31
+ *
32
+ * @description Render a still frame from a composition
33
+ * @link https://www.remotion.dev/docs/renderer/render-still
24
34
  */
25
35
  export declare const renderStill: (options: RenderStillOptions) => Promise<void>;
26
36
  export {};
@@ -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];
@@ -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, cancelSignal, }) => {
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()`');
@@ -71,11 +76,20 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
71
76
  forceDeviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
72
77
  }));
73
78
  const page = await browserInstance.newPage();
74
- page.setViewport({
79
+ await page.setViewport({
75
80
  width: composition.width,
76
81
  height: composition.height,
77
82
  deviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
78
83
  });
84
+ const errorCallback = (err) => {
85
+ onError(err);
86
+ cleanup();
87
+ };
88
+ const cleanUpJSException = (0, handle_javascript_exception_1.handleJavascriptException)({
89
+ page,
90
+ onError: errorCallback,
91
+ frame: null,
92
+ });
79
93
  const cleanup = async () => {
80
94
  cleanUpJSException();
81
95
  if (puppeteerInstance) {
@@ -87,14 +101,8 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
87
101
  });
88
102
  }
89
103
  };
90
- const errorCallback = (err) => {
91
- onError(err);
104
+ cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
92
105
  cleanup();
93
- };
94
- const cleanUpJSException = (0, handle_javascript_exception_1.handleJavascriptException)({
95
- page,
96
- onError: errorCallback,
97
- frame: null,
98
106
  });
99
107
  await (0, set_props_and_env_1.setPropsAndEnv)({
100
108
  inputProps,
@@ -103,6 +111,8 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
103
111
  serveUrl,
104
112
  initialFrame: frame,
105
113
  timeoutInMilliseconds,
114
+ proxyPort,
115
+ retriesRemaining: 2,
106
116
  });
107
117
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
108
118
  pageFunction: (id) => {
@@ -128,20 +138,49 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
128
138
  await cleanup();
129
139
  };
130
140
  /**
131
- * @description Render a still frame from a composition and returns an image path
141
+ *
142
+ * @description Render a still frame from a composition
143
+ * @link https://www.remotion.dev/docs/renderer/render-still
132
144
  */
133
- const renderStill = async (options) => {
145
+ const renderStill = (options) => {
146
+ var _a;
134
147
  const selectedServeUrl = (0, legacy_webpack_config_1.getServeUrlWithFallback)(options);
135
- const { closeServer, serveUrl } = await (0, prepare_server_1.prepareServer)(selectedServeUrl);
136
- return new Promise((resolve, reject) => {
137
- innerRenderStill({
138
- ...options,
139
- serveUrl,
140
- onError: (err) => reject(err),
148
+ const downloadDir = (0, make_assets_download_dir_1.makeAssetsDownloadTmpDir)();
149
+ const onDownload = (_a = options.onDownload) !== null && _a !== void 0 ? _a : (() => () => undefined);
150
+ const happyPath = new Promise((resolve, reject) => {
151
+ var _a, _b, _c;
152
+ const onError = (err) => reject(err);
153
+ let close = null;
154
+ (0, prepare_server_1.prepareServer)({
155
+ webpackConfigOrServeUrl: selectedServeUrl,
156
+ downloadDir,
157
+ onDownload,
158
+ onError,
159
+ ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
160
+ ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
161
+ port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
162
+ })
163
+ .then(({ serveUrl, closeServer, offthreadPort }) => {
164
+ close = closeServer;
165
+ return innerRenderStill({
166
+ ...options,
167
+ serveUrl,
168
+ onError: (err) => reject(err),
169
+ proxyPort: offthreadPort,
170
+ });
141
171
  })
142
172
  .then((res) => resolve(res))
143
173
  .catch((err) => reject(err))
144
- .finally(() => closeServer());
174
+ .finally(() => close === null || close === void 0 ? void 0 : close());
145
175
  });
176
+ return Promise.race([
177
+ happyPath,
178
+ new Promise((_resolve, reject) => {
179
+ var _a;
180
+ (_a = options.cancelSignal) === null || _a === void 0 ? void 0 : _a.call(options, () => {
181
+ reject(new Error('renderStill() got cancelled'));
182
+ });
183
+ }),
184
+ ]);
146
185
  };
147
186
  exports.renderStill = renderStill;
@@ -0,0 +1 @@
1
+ export declare const slasher: (value: string) => string;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /* ! The MIT License (MIT) Copyright (c) 2014 Scott Corgan */
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.slasher = void 0;
8
+ // This is adopted from https://github.com/scottcorgan/glob-slash/
9
+ const path_1 = __importDefault(require("path"));
10
+ const normalize = (value) => path_1.default.posix.normalize(path_1.default.posix.join('/', value));
11
+ const slasher = (value) => value.charAt(0) === '!' ? `!${normalize(value.substr(1))}` : normalize(value);
12
+ exports.slasher = slasher;
@@ -0,0 +1,4 @@
1
+ import { IncomingMessage, ServerResponse } from 'http';
2
+ export declare const serveHandler: (request: IncomingMessage, response: ServerResponse, config: {
3
+ public: string;
4
+ }) => Promise<void>;
@@ -0,0 +1,205 @@
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.serveHandler = void 0;
7
+ // Native
8
+ const fs_1 = require("fs");
9
+ const path_1 = __importDefault(require("path"));
10
+ const url_1 = __importDefault(require("url"));
11
+ // Packages
12
+ const mime_types_1 = __importDefault(require("mime-types"));
13
+ const is_path_inside_1 = require("./is-path-inside");
14
+ const range_parser_1 = require("./range-parser");
15
+ const getHeaders = (absolutePath, stats) => {
16
+ const { base } = path_1.default.parse(absolutePath);
17
+ let defaultHeaders = {};
18
+ if (stats) {
19
+ defaultHeaders = {
20
+ 'Content-Length': String(stats.size),
21
+ 'Accept-Ranges': 'bytes',
22
+ };
23
+ defaultHeaders['Last-Modified'] = stats.mtime.toUTCString();
24
+ const contentType = mime_types_1.default.contentType(base);
25
+ if (contentType) {
26
+ defaultHeaders['Content-Type'] = contentType;
27
+ }
28
+ }
29
+ return defaultHeaders;
30
+ };
31
+ const getPossiblePaths = (relativePath, extension) => [
32
+ path_1.default.join(relativePath, `index${extension}`),
33
+ relativePath.endsWith('/')
34
+ ? relativePath.replace(/\/$/g, extension)
35
+ : relativePath + extension,
36
+ ].filter((item) => path_1.default.basename(item) !== extension);
37
+ const findRelated = async (current, relativePath) => {
38
+ const possible = getPossiblePaths(relativePath, '.html');
39
+ let stats = null;
40
+ for (let index = 0; index < possible.length; index++) {
41
+ const related = possible[index];
42
+ const absolutePath = path_1.default.join(current, related);
43
+ try {
44
+ stats = await fs_1.promises.lstat(absolutePath);
45
+ }
46
+ catch (err) {
47
+ if (err.code !== 'ENOENT' &&
48
+ err.code !== 'ENOTDIR') {
49
+ throw err;
50
+ }
51
+ }
52
+ if (stats) {
53
+ return {
54
+ stats,
55
+ absolutePath,
56
+ };
57
+ }
58
+ }
59
+ return null;
60
+ };
61
+ const sendError = (absolutePath, response, spec) => {
62
+ const { message, statusCode } = spec;
63
+ response.statusCode = statusCode;
64
+ const headers = getHeaders(absolutePath, null);
65
+ response.writeHead(statusCode, headers);
66
+ response.setHeader('content-type', 'application/json');
67
+ response.end(JSON.stringify({ statusCode, message }));
68
+ };
69
+ const internalError = (absolutePath, response) => {
70
+ return sendError(absolutePath, response, {
71
+ statusCode: 500,
72
+ code: 'internal_server_error',
73
+ message: 'A server error has occurred',
74
+ });
75
+ };
76
+ const serveHandler = async (request, response, config) => {
77
+ const cwd = process.cwd();
78
+ const current = path_1.default.resolve(cwd, config.public);
79
+ let relativePath = null;
80
+ try {
81
+ relativePath = decodeURIComponent(url_1.default.parse(request.url).pathname);
82
+ }
83
+ catch (err) {
84
+ return sendError('/', response, {
85
+ statusCode: 400,
86
+ code: 'bad_request',
87
+ message: 'Bad Request',
88
+ });
89
+ }
90
+ let absolutePath = path_1.default.join(current, relativePath);
91
+ // Prevent path traversal vulnerabilities. We could do this
92
+ // by ourselves, but using the package covers all the edge cases.
93
+ if (!(0, is_path_inside_1.isPathInside)(absolutePath, current)) {
94
+ return sendError(absolutePath, response, {
95
+ statusCode: 400,
96
+ code: 'bad_request',
97
+ message: 'Bad Request',
98
+ });
99
+ }
100
+ let stats = null;
101
+ // It's extremely important that we're doing multiple stat calls. This one
102
+ // right here could technically be removed, but then the program
103
+ // would be slower. Because for directories, we always want to see if a related file
104
+ // exists and then (after that), fetch the directory itself if no
105
+ // related file was found. However (for files, of which most have extensions), we should
106
+ // always stat right away.
107
+ //
108
+ // When simulating a file system without directory indexes, calculating whether a
109
+ // directory exists requires loading all the file paths and then checking if
110
+ // one of them includes the path of the directory. As that's a very
111
+ // performance-expensive thing to do, we need to ensure it's not happening if not really necessary.
112
+ if (path_1.default.extname(relativePath) !== '') {
113
+ try {
114
+ stats = await fs_1.promises.lstat(absolutePath);
115
+ }
116
+ catch (err) {
117
+ if (err.code !== 'ENOENT' &&
118
+ err.code !== 'ENOTDIR') {
119
+ return internalError(absolutePath, response);
120
+ }
121
+ }
122
+ }
123
+ if (!stats) {
124
+ try {
125
+ const related = await findRelated(current, relativePath);
126
+ if (related) {
127
+ ({ stats, absolutePath } = related);
128
+ }
129
+ }
130
+ catch (err) {
131
+ if (err.code !== 'ENOENT' &&
132
+ err.code !== 'ENOTDIR') {
133
+ return internalError(absolutePath, response);
134
+ }
135
+ }
136
+ try {
137
+ stats = await fs_1.promises.lstat(absolutePath);
138
+ }
139
+ catch (err) {
140
+ if (err.code !== 'ENOENT' &&
141
+ err.code !== 'ENOTDIR') {
142
+ return internalError(absolutePath, response);
143
+ }
144
+ }
145
+ }
146
+ if (stats === null || stats === void 0 ? void 0 : stats.isDirectory()) {
147
+ const directory = null;
148
+ const singleFile = null;
149
+ if (directory) {
150
+ const contentType = 'text/html; charset=utf-8';
151
+ response.statusCode = 200;
152
+ response.setHeader('Content-Type', contentType);
153
+ response.end('Is a directory');
154
+ return;
155
+ }
156
+ if (!singleFile) {
157
+ // The directory listing is disabled, so we want to
158
+ // render a 404 error.
159
+ stats = null;
160
+ }
161
+ }
162
+ const isSymLink = stats === null || stats === void 0 ? void 0 : stats.isSymbolicLink();
163
+ // There are two scenarios in which we want to reply with
164
+ // a 404 error: Either the path does not exist, or it is a
165
+ // symlink while the `symlinks` option is disabled (which it is by default).
166
+ if (!stats || isSymLink) {
167
+ // allow for custom 404 handling
168
+ return sendError(absolutePath, response, {
169
+ statusCode: 404,
170
+ code: 'not_found',
171
+ message: 'The requested path could not be found',
172
+ });
173
+ }
174
+ let streamOpts = null;
175
+ if (request.headers.range && stats.size) {
176
+ const range = (0, range_parser_1.rangeParser)(stats.size, request.headers.range);
177
+ if (typeof range === 'object' && range.type === 'bytes') {
178
+ const { start, end } = range.ranges[0];
179
+ streamOpts = {
180
+ start,
181
+ end,
182
+ };
183
+ response.statusCode = 206;
184
+ }
185
+ else {
186
+ response.statusCode = 416;
187
+ response.setHeader('Content-Range', `bytes */${stats.size}`);
188
+ }
189
+ }
190
+ let stream = null;
191
+ try {
192
+ stream = (0, fs_1.createReadStream)(absolutePath, streamOpts !== null && streamOpts !== void 0 ? streamOpts : {});
193
+ }
194
+ catch (err) {
195
+ return internalError(absolutePath, response);
196
+ }
197
+ const headers = getHeaders(absolutePath, stats);
198
+ if (streamOpts !== null) {
199
+ headers['Content-Range'] = `bytes ${streamOpts.start}-${streamOpts.end}/${stats.size}`;
200
+ headers['Content-Length'] = String(streamOpts.end - streamOpts.start + 1);
201
+ }
202
+ response.writeHead(response.statusCode || 200, headers);
203
+ stream.pipe(response);
204
+ };
205
+ exports.serveHandler = serveHandler;
@@ -0,0 +1 @@
1
+ export declare const isPathInside: (thePath: string, potentialParent: string) => boolean;