@remotion/lambda 4.0.254 → 4.0.256
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/__mocks__/clean-items.d.ts +2 -0
- package/dist/api/__mocks__/clean-items.js +24 -0
- package/dist/api/__mocks__/create-function.d.ts +2 -0
- package/dist/api/__mocks__/create-function.js +21 -0
- package/dist/api/__mocks__/delete-function.d.ts +2 -0
- package/dist/api/__mocks__/delete-function.js +9 -0
- package/dist/api/__mocks__/get-functions.d.ts +2 -0
- package/dist/api/__mocks__/get-functions.js +9 -0
- package/dist/api/__mocks__/upload-dir.d.ts +3 -0
- package/dist/api/__mocks__/upload-dir.js +47 -0
- package/dist/api/mock-functions.d.ts +18 -0
- package/dist/api/mock-functions.js +36 -0
- package/dist/cli/helpers/__mocks__/quit.d.ts +1 -0
- package/dist/cli/helpers/__mocks__/quit.js +7 -0
- package/dist/cli/log.d.ts +4 -4
- package/dist/functions/chunk-optimization/plan-frame-ranges.d.ts +7 -0
- package/dist/functions/chunk-optimization/plan-frame-ranges.js +17 -0
- package/dist/functions/chunk-optimization/types.d.ts +8 -0
- package/dist/functions/chunk-optimization/types.js +2 -0
- package/dist/functions/helpers/__mocks__/get-browser-instance.d.ts +3 -0
- package/dist/functions/helpers/__mocks__/get-browser-instance.js +12 -0
- package/dist/functions/helpers/__mocks__/leak-detection.d.ts +4 -0
- package/dist/functions/helpers/__mocks__/leak-detection.js +9 -0
- package/dist/functions/helpers/__mocks__/timer.d.ts +2 -0
- package/dist/functions/helpers/__mocks__/timer.js +10 -0
- package/dist/functions/helpers/best-frames-per-lambda-param.d.ts +1 -0
- package/dist/functions/helpers/best-frames-per-lambda-param.js +17 -0
- package/dist/functions/helpers/calculate-chunk-times.d.ts +5 -0
- package/dist/functions/helpers/calculate-chunk-times.js +29 -0
- package/dist/functions/helpers/calculate-price-from-bucket.d.ts +15 -0
- package/dist/functions/helpers/calculate-price-from-bucket.js +30 -0
- package/dist/functions/helpers/can-concat-seamlessly.d.ts +3 -0
- package/dist/functions/helpers/can-concat-seamlessly.js +17 -0
- package/dist/functions/helpers/cleanup-props.d.ts +8 -0
- package/dist/functions/helpers/cleanup-props.js +23 -0
- package/dist/functions/helpers/concat-videos.d.ts +23 -0
- package/dist/functions/helpers/concat-videos.js +54 -0
- package/dist/functions/helpers/create-post-render-data.d.ts +17 -0
- package/dist/functions/helpers/create-post-render-data.js +67 -0
- package/dist/functions/helpers/find-output-file-in-bucket.d.ts +14 -0
- package/dist/functions/helpers/find-output-file-in-bucket.js +38 -0
- package/dist/functions/helpers/format-costs-info.d.ts +2 -0
- package/dist/functions/helpers/format-costs-info.js +23 -0
- package/dist/functions/helpers/get-overall-progress-s3.d.ts +10 -0
- package/dist/functions/helpers/get-overall-progress-s3.js +24 -0
- package/dist/functions/helpers/get-overall-progress.d.ts +9 -0
- package/dist/functions/helpers/get-overall-progress.js +23 -0
- package/dist/functions/helpers/get-progress.d.ts +15 -0
- package/dist/functions/helpers/get-progress.js +254 -0
- package/dist/functions/helpers/get-retry-stats.d.ts +5 -0
- package/dist/functions/helpers/get-retry-stats.js +2 -0
- package/dist/functions/helpers/inspect-errors.d.ts +4 -0
- package/dist/functions/helpers/inspect-errors.js +39 -0
- package/dist/functions/helpers/is-warm.d.ts +2 -0
- package/dist/functions/helpers/is-warm.js +10 -0
- package/dist/functions/helpers/leak-detection.d.ts +4 -0
- package/dist/functions/helpers/leak-detection.js +40 -0
- package/dist/functions/helpers/make-timeout-error.d.ts +10 -0
- package/dist/functions/helpers/make-timeout-error.js +31 -0
- package/dist/functions/helpers/make-timeout-message.d.ts +10 -0
- package/dist/functions/helpers/make-timeout-message.js +75 -0
- package/dist/functions/helpers/merge-chunks.d.ts +36 -0
- package/dist/functions/helpers/merge-chunks.js +84 -0
- package/dist/functions/helpers/min-max.d.ts +2 -0
- package/dist/functions/helpers/min-max.js +33 -0
- package/dist/functions/helpers/on-downloads-logger.d.ts +2 -0
- package/dist/functions/helpers/on-downloads-logger.js +29 -0
- package/dist/functions/helpers/overall-render-progress.d.ts +59 -0
- package/dist/functions/helpers/overall-render-progress.js +180 -0
- package/dist/functions/helpers/print-concurrency-curve.d.ts +1 -0
- package/dist/functions/helpers/print-concurrency-curve.js +8 -0
- package/dist/functions/helpers/print-logging-helper.d.ts +4 -0
- package/dist/functions/helpers/print-logging-helper.js +12 -0
- package/dist/functions/helpers/render-has-audio-video.d.ts +6 -0
- package/dist/functions/helpers/render-has-audio-video.js +21 -0
- package/dist/functions/helpers/request-context.d.ts +5 -0
- package/dist/functions/helpers/request-context.js +2 -0
- package/dist/functions/helpers/stream-renderer.d.ts +17 -0
- package/dist/functions/helpers/stream-renderer.js +148 -0
- package/dist/functions/launch.d.ts +10 -0
- package/dist/functions/launch.js +595 -0
- package/dist/functions/progress.d.ts +11 -0
- package/dist/functions/progress.js +51 -0
- package/dist/functions/renderer.d.ts +17 -0
- package/dist/functions/renderer.js +341 -0
- package/dist/functions/start.d.ts +13 -0
- package/dist/functions/start.js +112 -0
- package/dist/functions/still.d.ts +19 -0
- package/dist/functions/still.js +329 -0
- package/dist/shared/__mocks__/aws-clients.d.ts +2 -0
- package/dist/shared/__mocks__/aws-clients.js +62 -0
- package/dist/shared/__mocks__/bundle-site.d.ts +2 -0
- package/dist/shared/__mocks__/bundle-site.js +32 -0
- package/dist/shared/__mocks__/check-credentials.d.ts +1 -0
- package/dist/shared/__mocks__/check-credentials.js +5 -0
- package/dist/shared/__mocks__/get-account-id.d.ts +2 -0
- package/dist/shared/__mocks__/get-account-id.js +11 -0
- package/dist/shared/__mocks__/read-dir.d.ts +2 -0
- package/dist/shared/__mocks__/read-dir.js +13 -0
- package/dist/shared/call-lambda.d.ts +16 -0
- package/dist/shared/call-lambda.js +149 -0
- package/dist/shared/cleanup-serialized-input-props.d.ts +14 -0
- package/dist/shared/cleanup-serialized-input-props.js +34 -0
- package/dist/shared/docs-url.d.ts +1 -0
- package/dist/shared/docs-url.js +4 -0
- package/dist/shared/get-most-expensive-chunks.d.ts +8 -0
- package/dist/shared/get-most-expensive-chunks.js +28 -0
- package/dist/shared/invoke-webhook.d.ts +48 -0
- package/dist/shared/invoke-webhook.js +140 -0
- package/dist/shared/parse-lambda-timings-key.d.ts +5 -0
- package/dist/shared/parse-lambda-timings-key.js +2 -0
- package/dist/shared/return-values.d.ts +16 -0
- package/dist/shared/return-values.js +2 -0
- package/dist/shared/stackback.d.ts +6 -0
- package/dist/shared/stackback.js +59 -0
- package/dist/shared/validate-download-behavior.d.ts +1 -0
- package/dist/shared/validate-download-behavior.js +21 -0
- package/dist/shared/validate-frames-per-lambda.d.ts +4 -0
- package/dist/shared/validate-frames-per-lambda.js +29 -0
- package/dist/shared/validate-privacy.d.ts +2 -0
- package/dist/shared/validate-privacy.js +14 -0
- package/dist/shared/validate.d.ts +4 -0
- package/dist/shared/validate.js +8 -0
- package/dist/shared/why-is-node-running.d.ts +15 -0
- package/dist/shared/why-is-node-running.js +88 -0
- package/package.json +12 -12
- package/remotionlambda-arm64.zip +0 -0
|
@@ -0,0 +1,341 @@
|
|
|
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.rendererHandler = void 0;
|
|
7
|
+
const renderer_1 = require("@remotion/renderer");
|
|
8
|
+
const pure_1 = require("@remotion/renderer/pure");
|
|
9
|
+
const serverless_1 = require("@remotion/serverless");
|
|
10
|
+
const client_1 = require("@remotion/serverless/client");
|
|
11
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
13
|
+
const version_1 = require("remotion/version");
|
|
14
|
+
const constants_1 = require("../shared/constants");
|
|
15
|
+
const is_flaky_error_1 = require("../shared/is-flaky-error");
|
|
16
|
+
const why_is_node_running_1 = require("../shared/why-is-node-running");
|
|
17
|
+
const can_concat_seamlessly_1 = require("./helpers/can-concat-seamlessly");
|
|
18
|
+
const leak_detection_1 = require("./helpers/leak-detection");
|
|
19
|
+
const on_downloads_logger_1 = require("./helpers/on-downloads-logger");
|
|
20
|
+
const timer_1 = require("./helpers/timer");
|
|
21
|
+
const renderHandler = async ({ params, options, logs, onStream, providerSpecifics, }) => {
|
|
22
|
+
if (params.type !== client_1.ServerlessRoutines.renderer) {
|
|
23
|
+
throw new Error('Params must be renderer');
|
|
24
|
+
}
|
|
25
|
+
if (params.launchFunctionConfig.version !== version_1.VERSION) {
|
|
26
|
+
throw new Error(`The version of the function that was specified as "rendererFunctionName" is ${version_1.VERSION} but the version of the function that invoked the render is ${params.launchFunctionConfig.version}. Please make sure that the version of the function that is specified as "rendererFunctionName" is the same as the version of the function that is invoked.`);
|
|
27
|
+
}
|
|
28
|
+
const inputPropsPromise = (0, client_1.decompressInputProps)({
|
|
29
|
+
bucketName: params.bucketName,
|
|
30
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
31
|
+
region: providerSpecifics.getCurrentRegionInFunction(),
|
|
32
|
+
serialized: params.inputProps,
|
|
33
|
+
propsType: 'input-props',
|
|
34
|
+
providerSpecifics,
|
|
35
|
+
forcePathStyle: params.forcePathStyle,
|
|
36
|
+
});
|
|
37
|
+
const resolvedPropsPromise = (0, client_1.decompressInputProps)({
|
|
38
|
+
bucketName: params.bucketName,
|
|
39
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
40
|
+
region: providerSpecifics.getCurrentRegionInFunction(),
|
|
41
|
+
serialized: params.resolvedProps,
|
|
42
|
+
propsType: 'resolved-props',
|
|
43
|
+
providerSpecifics,
|
|
44
|
+
forcePathStyle: params.forcePathStyle,
|
|
45
|
+
});
|
|
46
|
+
const browserInstance = await (0, serverless_1.getBrowserInstance)({
|
|
47
|
+
logLevel: params.logLevel,
|
|
48
|
+
indent: false,
|
|
49
|
+
chromiumOptions: params.chromiumOptions,
|
|
50
|
+
providerSpecifics,
|
|
51
|
+
});
|
|
52
|
+
const outputPath = renderer_1.RenderInternals.tmpDir('remotion-render-');
|
|
53
|
+
if (typeof params.chunk !== 'number') {
|
|
54
|
+
throw new Error('must pass chunk');
|
|
55
|
+
}
|
|
56
|
+
if (!params.frameRange) {
|
|
57
|
+
throw new Error('must pass framerange');
|
|
58
|
+
}
|
|
59
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, `Rendering frames ${params.frameRange[0]}-${params.frameRange[1]} in this Lambda function`);
|
|
60
|
+
const start = Date.now();
|
|
61
|
+
const chunkTimingData = {
|
|
62
|
+
timings: {},
|
|
63
|
+
chunk: params.chunk,
|
|
64
|
+
frameRange: params.frameRange,
|
|
65
|
+
startDate: start,
|
|
66
|
+
};
|
|
67
|
+
const outdir = renderer_1.RenderInternals.tmpDir(constants_1.RENDERER_PATH_TOKEN);
|
|
68
|
+
const chunk = `localchunk-${String(params.chunk).padStart(8, '0')}`;
|
|
69
|
+
const defaultAudioCodec = renderer_1.RenderInternals.getDefaultAudioCodec({
|
|
70
|
+
codec: params.codec,
|
|
71
|
+
preferLossless: params.preferLossless,
|
|
72
|
+
});
|
|
73
|
+
const seamlessAudio = (0, can_concat_seamlessly_1.canConcatAudioSeamlessly)(defaultAudioCodec, params.framesPerLambda);
|
|
74
|
+
const seamlessVideo = (0, can_concat_seamlessly_1.canConcatVideoSeamlessly)(params.codec);
|
|
75
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, `Preparing for rendering a chunk. Audio = ${seamlessAudio ? 'seamless' : 'normal'}, Video = ${seamlessVideo ? 'seamless' : 'normal'}`, params.logLevel);
|
|
76
|
+
const chunkCodec = seamlessVideo && params.codec === 'h264'
|
|
77
|
+
? 'h264-ts'
|
|
78
|
+
: params.codec === 'gif'
|
|
79
|
+
? 'h264-ts'
|
|
80
|
+
: params.codec;
|
|
81
|
+
const audioCodec = defaultAudioCodec === null
|
|
82
|
+
? null
|
|
83
|
+
: seamlessAudio
|
|
84
|
+
? defaultAudioCodec
|
|
85
|
+
: 'pcm-16';
|
|
86
|
+
const videoExtension = renderer_1.RenderInternals.getFileExtensionFromCodec(chunkCodec, audioCodec);
|
|
87
|
+
const audioExtension = audioCodec
|
|
88
|
+
? renderer_1.RenderInternals.getExtensionFromAudioCodec(audioCodec)
|
|
89
|
+
: null;
|
|
90
|
+
const videoOutputLocation = node_path_1.default.join(outdir, `${chunk}.${videoExtension}`);
|
|
91
|
+
const willRenderAudioEval = renderer_1.RenderInternals.getShouldRenderAudio({
|
|
92
|
+
assetsInfo: null,
|
|
93
|
+
codec: params.codec,
|
|
94
|
+
enforceAudioTrack: true,
|
|
95
|
+
muted: params.muted,
|
|
96
|
+
});
|
|
97
|
+
if (willRenderAudioEval === 'maybe') {
|
|
98
|
+
throw new Error('Cannot determine whether to render audio or not');
|
|
99
|
+
}
|
|
100
|
+
const audioOutputLocation = willRenderAudioEval === 'no'
|
|
101
|
+
? null
|
|
102
|
+
: pure_1.NoReactAPIs.isAudioCodec(params.codec)
|
|
103
|
+
? null
|
|
104
|
+
: audioExtension
|
|
105
|
+
? node_path_1.default.join(outdir, `${chunk}.${audioExtension}`)
|
|
106
|
+
: null;
|
|
107
|
+
const resolvedProps = await resolvedPropsPromise;
|
|
108
|
+
const serializedInputPropsWithCustomSchema = await inputPropsPromise;
|
|
109
|
+
const allFrames = renderer_1.RenderInternals.getFramesToRender(params.frameRange, params.everyNthFrame);
|
|
110
|
+
const onArtifact = (artifact) => {
|
|
111
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel: params.logLevel }, `Received artifact on frame ${artifact.frame}:`, artifact.filename, artifact.content.length + 'bytes. Streaming to main function');
|
|
112
|
+
const startTimestamp = Date.now();
|
|
113
|
+
onStream({
|
|
114
|
+
type: 'artifact-emitted',
|
|
115
|
+
payload: {
|
|
116
|
+
artifact: (0, serverless_1.serializeArtifact)(artifact),
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
.then(() => {
|
|
120
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel: params.logLevel }, `Streaming artifact ${artifact.filename} to main function took ${Date.now() - startTimestamp}ms`);
|
|
121
|
+
})
|
|
122
|
+
.catch((e) => {
|
|
123
|
+
renderer_1.RenderInternals.Log.error({ indent: false, logLevel: params.logLevel }, `Error streaming artifact ${artifact.filename} to main function`, e);
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
await new Promise((resolve, reject) => {
|
|
127
|
+
var _a, _b, _c, _d, _e;
|
|
128
|
+
renderer_1.RenderInternals.internalRenderMedia({
|
|
129
|
+
repro: false,
|
|
130
|
+
composition: {
|
|
131
|
+
id: params.composition,
|
|
132
|
+
durationInFrames: params.durationInFrames,
|
|
133
|
+
fps: params.fps,
|
|
134
|
+
height: params.height,
|
|
135
|
+
width: params.width,
|
|
136
|
+
defaultCodec: null,
|
|
137
|
+
},
|
|
138
|
+
imageFormat: params.imageFormat,
|
|
139
|
+
serializedInputPropsWithCustomSchema,
|
|
140
|
+
frameRange: params.frameRange,
|
|
141
|
+
onProgress: ({ renderedFrames, encodedFrames, stitchStage }) => {
|
|
142
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, `Rendered ${renderedFrames} frames, encoded ${encodedFrames} frames, stage = ${stitchStage}`);
|
|
143
|
+
const allFramesRendered = allFrames.length === renderedFrames;
|
|
144
|
+
const allFramesEncoded = allFrames.length === encodedFrames;
|
|
145
|
+
const frameReportPoint = (renderedFrames % params.progressEveryNthFrame === 0 ||
|
|
146
|
+
allFramesRendered) &&
|
|
147
|
+
!allFramesEncoded;
|
|
148
|
+
const encodedFramesReportPoint = (encodedFrames % params.progressEveryNthFrame === 0 ||
|
|
149
|
+
allFramesEncoded) &&
|
|
150
|
+
allFramesRendered;
|
|
151
|
+
if (frameReportPoint || encodedFramesReportPoint) {
|
|
152
|
+
onStream({
|
|
153
|
+
type: 'frames-rendered',
|
|
154
|
+
payload: { rendered: renderedFrames, encoded: encodedFrames },
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if (renderedFrames === allFrames.length) {
|
|
158
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, 'Rendered all frames!');
|
|
159
|
+
}
|
|
160
|
+
chunkTimingData.timings[renderedFrames] = Date.now() - start;
|
|
161
|
+
},
|
|
162
|
+
concurrency: params.concurrencyPerLambda,
|
|
163
|
+
onStart: () => {
|
|
164
|
+
onStream({
|
|
165
|
+
type: 'lambda-invoked',
|
|
166
|
+
payload: {
|
|
167
|
+
attempt: params.attempt,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
puppeteerInstance: browserInstance.instance,
|
|
172
|
+
serveUrl: params.serveUrl,
|
|
173
|
+
jpegQuality: (_a = params.jpegQuality) !== null && _a !== void 0 ? _a : renderer_1.RenderInternals.DEFAULT_JPEG_QUALITY,
|
|
174
|
+
envVariables: (_b = params.envVariables) !== null && _b !== void 0 ? _b : {},
|
|
175
|
+
logLevel: params.logLevel,
|
|
176
|
+
onBrowserLog: (log) => {
|
|
177
|
+
logs.push(log);
|
|
178
|
+
},
|
|
179
|
+
outputLocation: videoOutputLocation,
|
|
180
|
+
codec: chunkCodec,
|
|
181
|
+
crf: (_c = params.crf) !== null && _c !== void 0 ? _c : null,
|
|
182
|
+
pixelFormat: (_d = params.pixelFormat) !== null && _d !== void 0 ? _d : renderer_1.RenderInternals.DEFAULT_PIXEL_FORMAT,
|
|
183
|
+
proResProfile: (_e = params.proResProfile) !== null && _e !== void 0 ? _e : undefined,
|
|
184
|
+
x264Preset: params.x264Preset,
|
|
185
|
+
onDownload: (0, on_downloads_logger_1.onDownloadsHelper)(params.logLevel),
|
|
186
|
+
overwrite: false,
|
|
187
|
+
chromiumOptions: params.chromiumOptions,
|
|
188
|
+
scale: params.scale,
|
|
189
|
+
timeoutInMilliseconds: params.timeoutInMilliseconds,
|
|
190
|
+
port: null,
|
|
191
|
+
everyNthFrame: params.everyNthFrame,
|
|
192
|
+
numberOfGifLoops: null,
|
|
193
|
+
muted: params.muted,
|
|
194
|
+
enforceAudioTrack: true,
|
|
195
|
+
audioBitrate: params.audioBitrate,
|
|
196
|
+
videoBitrate: params.videoBitrate,
|
|
197
|
+
encodingBufferSize: params.encodingBufferSize,
|
|
198
|
+
encodingMaxRate: params.encodingMaxRate,
|
|
199
|
+
audioCodec,
|
|
200
|
+
preferLossless: params.preferLossless,
|
|
201
|
+
browserExecutable: providerSpecifics.getChromiumPath(),
|
|
202
|
+
cancelSignal: undefined,
|
|
203
|
+
disallowParallelEncoding: false,
|
|
204
|
+
ffmpegOverride: ({ args }) => args,
|
|
205
|
+
indent: false,
|
|
206
|
+
onCtrlCExit: () => undefined,
|
|
207
|
+
server: undefined,
|
|
208
|
+
serializedResolvedPropsWithCustomSchema: resolvedProps,
|
|
209
|
+
offthreadVideoCacheSizeInBytes: params.offthreadVideoCacheSizeInBytes,
|
|
210
|
+
colorSpace: params.colorSpace,
|
|
211
|
+
binariesDirectory: null,
|
|
212
|
+
separateAudioTo: audioOutputLocation,
|
|
213
|
+
forSeamlessAacConcatenation: seamlessAudio,
|
|
214
|
+
compositionStart: params.compositionStart,
|
|
215
|
+
onBrowserDownload: () => {
|
|
216
|
+
throw new Error('Should not download a browser in Lambda');
|
|
217
|
+
},
|
|
218
|
+
onArtifact,
|
|
219
|
+
metadata: params.metadata,
|
|
220
|
+
hardwareAcceleration: 'disable',
|
|
221
|
+
})
|
|
222
|
+
.then(({ slowestFrames }) => {
|
|
223
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, `Slowest frames:`);
|
|
224
|
+
slowestFrames.forEach(({ frame, time }) => {
|
|
225
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, ` Frame ${frame} (${time.toFixed(3)}ms)`);
|
|
226
|
+
});
|
|
227
|
+
resolve();
|
|
228
|
+
})
|
|
229
|
+
.catch((err) => reject(err));
|
|
230
|
+
});
|
|
231
|
+
const streamTimer = (0, timer_1.timer)('Streaming chunk to the main function', params.logLevel);
|
|
232
|
+
if (audioOutputLocation) {
|
|
233
|
+
const audioChunkTimer = (0, timer_1.timer)('Sending audio chunk', params.logLevel);
|
|
234
|
+
await onStream({
|
|
235
|
+
type: 'audio-chunk-rendered',
|
|
236
|
+
payload: node_fs_1.default.readFileSync(audioOutputLocation),
|
|
237
|
+
});
|
|
238
|
+
audioChunkTimer.end();
|
|
239
|
+
}
|
|
240
|
+
if (videoOutputLocation) {
|
|
241
|
+
const videoChunkTimer = (0, timer_1.timer)('Sending main chunk', params.logLevel);
|
|
242
|
+
await onStream({
|
|
243
|
+
type: pure_1.NoReactAPIs.isAudioCodec(params.codec)
|
|
244
|
+
? 'audio-chunk-rendered'
|
|
245
|
+
: 'video-chunk-rendered',
|
|
246
|
+
payload: node_fs_1.default.readFileSync(videoOutputLocation),
|
|
247
|
+
});
|
|
248
|
+
videoChunkTimer.end();
|
|
249
|
+
}
|
|
250
|
+
const endRendered = Date.now();
|
|
251
|
+
await onStream({
|
|
252
|
+
type: 'chunk-complete',
|
|
253
|
+
payload: {
|
|
254
|
+
rendered: endRendered,
|
|
255
|
+
start,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
streamTimer.end();
|
|
259
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, 'Cleaning up and writing timings');
|
|
260
|
+
await Promise.all([
|
|
261
|
+
node_fs_1.default.promises.rm(videoOutputLocation, { recursive: true }),
|
|
262
|
+
audioOutputLocation
|
|
263
|
+
? node_fs_1.default.promises.rm(audioOutputLocation, { recursive: true })
|
|
264
|
+
: null,
|
|
265
|
+
node_fs_1.default.promises.rm(outputPath, { recursive: true }),
|
|
266
|
+
].filter(client_1.truthy));
|
|
267
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, 'Done!');
|
|
268
|
+
return {};
|
|
269
|
+
};
|
|
270
|
+
const ENABLE_SLOW_LEAK_DETECTION = false;
|
|
271
|
+
const rendererHandler = async ({ onStream, options, params, providerSpecifics, requestContext, }) => {
|
|
272
|
+
if (params.type !== client_1.ServerlessRoutines.renderer) {
|
|
273
|
+
throw new Error('Params must be renderer');
|
|
274
|
+
}
|
|
275
|
+
const logs = [];
|
|
276
|
+
const leakDetection = (0, why_is_node_running_1.enableNodeIntrospection)(ENABLE_SLOW_LEAK_DETECTION);
|
|
277
|
+
let shouldKeepBrowserOpen = true;
|
|
278
|
+
try {
|
|
279
|
+
await renderHandler({
|
|
280
|
+
params,
|
|
281
|
+
options,
|
|
282
|
+
logs,
|
|
283
|
+
onStream,
|
|
284
|
+
providerSpecifics,
|
|
285
|
+
});
|
|
286
|
+
return {
|
|
287
|
+
type: 'success',
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
if (process.env.NODE_ENV === 'test') {
|
|
292
|
+
console.log({ err });
|
|
293
|
+
throw err;
|
|
294
|
+
}
|
|
295
|
+
// If this error is encountered, we can just retry as it
|
|
296
|
+
// is a very rare error to occur
|
|
297
|
+
const isRetryableError = (0, is_flaky_error_1.isFlakyError)(err);
|
|
298
|
+
if (isRetryableError) {
|
|
299
|
+
shouldKeepBrowserOpen = false;
|
|
300
|
+
}
|
|
301
|
+
const shouldNotRetry = err.name === 'CancelledError';
|
|
302
|
+
const shouldRetry = isRetryableError && params.retriesLeft > 0 && !shouldNotRetry;
|
|
303
|
+
renderer_1.RenderInternals.Log.error({ indent: false, logLevel: params.logLevel }, `Error occurred (will retry = ${String(shouldRetry)})`);
|
|
304
|
+
renderer_1.RenderInternals.Log.error({ indent: false, logLevel: params.logLevel }, err.stack);
|
|
305
|
+
onStream({
|
|
306
|
+
type: 'error-occurred',
|
|
307
|
+
payload: {
|
|
308
|
+
error: err.stack,
|
|
309
|
+
shouldRetry,
|
|
310
|
+
errorInfo: {
|
|
311
|
+
name: err.name,
|
|
312
|
+
message: err.message,
|
|
313
|
+
stack: err.stack,
|
|
314
|
+
chunk: params.chunk,
|
|
315
|
+
frame: null,
|
|
316
|
+
type: 'renderer',
|
|
317
|
+
isFatal: !shouldRetry,
|
|
318
|
+
tmpDir: (0, serverless_1.getTmpDirStateIfENoSp)(err.stack, providerSpecifics),
|
|
319
|
+
attempt: params.attempt,
|
|
320
|
+
totalAttempts: params.retriesLeft + params.attempt,
|
|
321
|
+
willRetry: shouldRetry,
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
327
|
+
finally {
|
|
328
|
+
if (shouldKeepBrowserOpen) {
|
|
329
|
+
(0, serverless_1.forgetBrowserEventLoop)(params.logLevel);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel: params.logLevel }, 'Lambda did not succeed with flaky error, not keeping browser open.');
|
|
333
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel: params.logLevel }, 'Quitting Lambda forcefully now to force not keeping the Lambda warm.');
|
|
334
|
+
process.exit(0);
|
|
335
|
+
}
|
|
336
|
+
if (ENABLE_SLOW_LEAK_DETECTION) {
|
|
337
|
+
(0, leak_detection_1.startLeakDetection)(leakDetection, requestContext.awsRequestId);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
exports.rendererHandler = rendererHandler;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CloudProvider, ProviderSpecifics } from '@remotion/serverless';
|
|
2
|
+
import type { ServerlessPayload } from '@remotion/serverless/client';
|
|
3
|
+
type Options = {
|
|
4
|
+
expectedBucketOwner: string;
|
|
5
|
+
timeoutInMilliseconds: number;
|
|
6
|
+
renderId: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const startHandler: <Provider extends CloudProvider>(params: ServerlessPayload<Provider>, options: Options, providerSpecifics: ProviderSpecifics<Provider>) => Promise<{
|
|
9
|
+
type: "success";
|
|
10
|
+
bucketName: string;
|
|
11
|
+
renderId: string;
|
|
12
|
+
}>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startHandler = void 0;
|
|
4
|
+
const client_lambda_1 = require("@aws-sdk/client-lambda");
|
|
5
|
+
const client_1 = require("@remotion/serverless/client");
|
|
6
|
+
const version_1 = require("remotion/version");
|
|
7
|
+
const aws_clients_1 = require("../shared/aws-clients");
|
|
8
|
+
const lifecycle_1 = require("./helpers/lifecycle");
|
|
9
|
+
const overall_render_progress_1 = require("./helpers/overall-render-progress");
|
|
10
|
+
const startHandler = async (params, options, providerSpecifics) => {
|
|
11
|
+
var _a, _b, _c, _d;
|
|
12
|
+
if (params.type !== client_1.ServerlessRoutines.start) {
|
|
13
|
+
throw new TypeError('Expected type start');
|
|
14
|
+
}
|
|
15
|
+
if (params.version !== version_1.VERSION) {
|
|
16
|
+
if (!params.version) {
|
|
17
|
+
throw new Error(`Version mismatch: When calling renderMediaOnLambda(), you called the function ${process.env.AWS_LAMBDA_FUNCTION_NAME} which has the version ${version_1.VERSION} but the @remotion/lambda package is an older version. Deploy a new function and use it to call renderMediaOnLambda(). See: https://www.remotion.dev/docs/lambda/upgrading`);
|
|
18
|
+
}
|
|
19
|
+
throw new Error(`Version mismatch: When calling renderMediaOnLambda(), you passed ${process.env.AWS_LAMBDA_FUNCTION_NAME} as the function, which has the version ${version_1.VERSION}, but the @remotion/lambda package you used to invoke the function has version ${params.version}. Deploy a new function and use it to call renderMediaOnLambda(). See: https://www.remotion.dev/docs/lambda/upgrading`);
|
|
20
|
+
}
|
|
21
|
+
const region = providerSpecifics.getCurrentRegionInFunction();
|
|
22
|
+
const bucketName = (_a = params.bucketName) !== null && _a !== void 0 ? _a : (await (0, client_1.internalGetOrCreateBucket)({
|
|
23
|
+
region: providerSpecifics.getCurrentRegionInFunction(),
|
|
24
|
+
enableFolderExpiry: null,
|
|
25
|
+
customCredentials: null,
|
|
26
|
+
providerSpecifics,
|
|
27
|
+
forcePathStyle: params.forcePathStyle,
|
|
28
|
+
})).bucketName;
|
|
29
|
+
const realServeUrl = providerSpecifics.convertToServeUrl({
|
|
30
|
+
urlOrId: params.serveUrl,
|
|
31
|
+
region,
|
|
32
|
+
bucketName,
|
|
33
|
+
});
|
|
34
|
+
(0, lifecycle_1.validateDeleteAfter)(params.deleteAfter);
|
|
35
|
+
const initialFile = providerSpecifics.writeFile({
|
|
36
|
+
bucketName,
|
|
37
|
+
downloadBehavior: null,
|
|
38
|
+
region,
|
|
39
|
+
body: JSON.stringify((0, overall_render_progress_1.makeInitialOverallRenderProgress)(options.timeoutInMilliseconds + Date.now())),
|
|
40
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
41
|
+
key: (0, client_1.overallProgressKey)(options.renderId),
|
|
42
|
+
privacy: 'private',
|
|
43
|
+
customCredentials: null,
|
|
44
|
+
forcePathStyle: params.forcePathStyle,
|
|
45
|
+
});
|
|
46
|
+
const payload = {
|
|
47
|
+
type: client_1.ServerlessRoutines.launch,
|
|
48
|
+
framesPerLambda: params.framesPerLambda,
|
|
49
|
+
composition: params.composition,
|
|
50
|
+
serveUrl: realServeUrl,
|
|
51
|
+
inputProps: params.inputProps,
|
|
52
|
+
bucketName,
|
|
53
|
+
renderId: options.renderId,
|
|
54
|
+
codec: params.codec,
|
|
55
|
+
imageFormat: params.imageFormat,
|
|
56
|
+
crf: (_b = params.crf) !== null && _b !== void 0 ? _b : null,
|
|
57
|
+
envVariables: params.envVariables,
|
|
58
|
+
pixelFormat: (_c = params.pixelFormat) !== null && _c !== void 0 ? _c : null,
|
|
59
|
+
proResProfile: (_d = params.proResProfile) !== null && _d !== void 0 ? _d : null,
|
|
60
|
+
x264Preset: params.x264Preset,
|
|
61
|
+
jpegQuality: params.jpegQuality,
|
|
62
|
+
maxRetries: params.maxRetries,
|
|
63
|
+
privacy: params.privacy,
|
|
64
|
+
logLevel: params.logLevel,
|
|
65
|
+
frameRange: params.frameRange,
|
|
66
|
+
outName: params.outName,
|
|
67
|
+
timeoutInMilliseconds: params.timeoutInMilliseconds,
|
|
68
|
+
chromiumOptions: params.chromiumOptions,
|
|
69
|
+
scale: params.scale,
|
|
70
|
+
numberOfGifLoops: params.numberOfGifLoops,
|
|
71
|
+
everyNthFrame: params.everyNthFrame,
|
|
72
|
+
concurrencyPerLambda: params.concurrencyPerLambda,
|
|
73
|
+
downloadBehavior: params.downloadBehavior,
|
|
74
|
+
muted: params.muted,
|
|
75
|
+
overwrite: params.overwrite,
|
|
76
|
+
webhook: params.webhook,
|
|
77
|
+
audioBitrate: params.audioBitrate,
|
|
78
|
+
videoBitrate: params.videoBitrate,
|
|
79
|
+
encodingBufferSize: params.encodingBufferSize,
|
|
80
|
+
encodingMaxRate: params.encodingMaxRate,
|
|
81
|
+
forceHeight: params.forceHeight,
|
|
82
|
+
forceWidth: params.forceWidth,
|
|
83
|
+
rendererFunctionName: params.rendererFunctionName,
|
|
84
|
+
audioCodec: params.audioCodec,
|
|
85
|
+
offthreadVideoCacheSizeInBytes: params.offthreadVideoCacheSizeInBytes,
|
|
86
|
+
deleteAfter: params.deleteAfter,
|
|
87
|
+
colorSpace: params.colorSpace,
|
|
88
|
+
preferLossless: params.preferLossless,
|
|
89
|
+
forcePathStyle: params.forcePathStyle,
|
|
90
|
+
metadata: params.metadata,
|
|
91
|
+
};
|
|
92
|
+
const stringifiedPayload = JSON.stringify(payload);
|
|
93
|
+
if (stringifiedPayload.length > 256 * 1024) {
|
|
94
|
+
throw new Error(`Payload is too big: ${stringifiedPayload.length} bytes. Maximum size is 256 KB. This should not happen, please report this to the Remotion team. Payload: ${stringifiedPayload}`);
|
|
95
|
+
}
|
|
96
|
+
// Don't replace with callLambda(), we want to return before the render is snone
|
|
97
|
+
const result = await (0, aws_clients_1.getLambdaClient)(providerSpecifics.getCurrentRegionInFunction()).send(new client_lambda_1.InvokeCommand({
|
|
98
|
+
FunctionName: process.env.AWS_LAMBDA_FUNCTION_NAME,
|
|
99
|
+
Payload: stringifiedPayload,
|
|
100
|
+
InvocationType: 'Event',
|
|
101
|
+
}));
|
|
102
|
+
if (result.FunctionError) {
|
|
103
|
+
throw new Error(`Lambda function returned error: ${result.FunctionError} ${result.LogResult}`);
|
|
104
|
+
}
|
|
105
|
+
await initialFile;
|
|
106
|
+
return {
|
|
107
|
+
type: 'success',
|
|
108
|
+
bucketName,
|
|
109
|
+
renderId: options.renderId,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
exports.startHandler = startHandler;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CloudProvider, OnStream } from '@remotion/serverless';
|
|
2
|
+
import { type ProviderSpecifics } from '@remotion/serverless';
|
|
3
|
+
import type { ServerlessPayload } from '@remotion/serverless/client';
|
|
4
|
+
type Options<Provider extends CloudProvider> = {
|
|
5
|
+
params: ServerlessPayload<Provider>;
|
|
6
|
+
renderId: string;
|
|
7
|
+
expectedBucketOwner: string;
|
|
8
|
+
onStream: OnStream<Provider>;
|
|
9
|
+
timeoutInMilliseconds: number;
|
|
10
|
+
providerSpecifics: ProviderSpecifics<Provider>;
|
|
11
|
+
};
|
|
12
|
+
export declare const stillHandler: <Provider extends CloudProvider>(options: Options<Provider>) => Promise<{
|
|
13
|
+
type: "success";
|
|
14
|
+
} | {
|
|
15
|
+
type: "error";
|
|
16
|
+
message: string;
|
|
17
|
+
stack: string;
|
|
18
|
+
}>;
|
|
19
|
+
export {};
|