@remotion/lambda 4.0.43 → 4.0.45
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/functions/helpers/get-progress.js +20 -3
- package/dist/functions/helpers/make-timeout-error.d.ts +2 -1
- package/dist/functions/helpers/make-timeout-error.js +1 -9
- package/dist/functions/helpers/merge-chunks.d.ts +30 -0
- package/dist/functions/helpers/merge-chunks.js +199 -0
- package/dist/functions/index.js +14 -0
- package/dist/functions/launch.js +158 -265
- package/dist/functions/merge.d.ts +9 -0
- package/dist/functions/merge.js +56 -0
- package/dist/functions/still.js +2 -0
- package/dist/shared/constants.d.ts +17 -4
- package/dist/shared/constants.js +1 -0
- package/dist/shared/return-values.d.ts +2 -0
- package/package.json +8 -8
- package/remotionlambda-arm64.zip +0 -0
|
@@ -4,6 +4,7 @@ exports.getProgress = void 0;
|
|
|
4
4
|
const renderer_1 = require("@remotion/renderer");
|
|
5
5
|
const remotion_1 = require("remotion");
|
|
6
6
|
const constants_1 = require("../../shared/constants");
|
|
7
|
+
const parse_chunk_key_1 = require("../../shared/parse-chunk-key");
|
|
7
8
|
const calculate_chunk_times_1 = require("./calculate-chunk-times");
|
|
8
9
|
const calculate_price_from_bucket_1 = require("./calculate-price-from-bucket");
|
|
9
10
|
const check_if_render_exists_1 = require("./check-if-render-exists");
|
|
@@ -167,16 +168,32 @@ const getProgress = async ({ bucketName, renderId, expectedBucketOwner, region,
|
|
|
167
168
|
const chunkCount = outputFile
|
|
168
169
|
? (_g = renderMetadata === null || renderMetadata === void 0 ? void 0 : renderMetadata.totalChunks) !== null && _g !== void 0 ? _g : 0
|
|
169
170
|
: chunks.length;
|
|
171
|
+
const availableChunks = chunks.map((c) => (0, parse_chunk_key_1.parseLambdaChunkKey)(c.Key));
|
|
172
|
+
const missingChunks = renderMetadata
|
|
173
|
+
? new Array(renderMetadata.totalChunks)
|
|
174
|
+
.fill(true)
|
|
175
|
+
.map((_, i) => i)
|
|
176
|
+
.filter((index) => {
|
|
177
|
+
return !availableChunks.find((c) => c.chunk === index);
|
|
178
|
+
})
|
|
179
|
+
: null;
|
|
170
180
|
// We add a 20 second buffer for it, since AWS timeshifts can be quite a lot. Once it's 20sec over the limit, we consider it timed out
|
|
171
|
-
|
|
172
|
-
|
|
181
|
+
// 1. If we have missing chunks, we consider it timed out
|
|
182
|
+
const isBeyondTimeoutAndMissingChunks = renderMetadata &&
|
|
183
|
+
Date.now() > renderMetadata.startedDate + timeoutInMilliseconds + 20000 &&
|
|
184
|
+
missingChunks &&
|
|
185
|
+
missingChunks.length > 0;
|
|
186
|
+
// 2. If we have no missing chunks, but the encoding is not done, even after the additional `merge` function has been spawned, we consider it timed out
|
|
187
|
+
const isBeyondTimeoutAndHasStitchTimeout = renderMetadata &&
|
|
188
|
+
Date.now() > renderMetadata.startedDate + timeoutInMilliseconds * 2 + 20000;
|
|
173
189
|
const allErrors = [
|
|
174
|
-
|
|
190
|
+
isBeyondTimeoutAndMissingChunks || isBeyondTimeoutAndHasStitchTimeout
|
|
175
191
|
? (0, make_timeout_error_1.makeTimeoutError)({
|
|
176
192
|
timeoutInMilliseconds,
|
|
177
193
|
renderMetadata,
|
|
178
194
|
chunks,
|
|
179
195
|
renderId,
|
|
196
|
+
missingChunks: missingChunks !== null && missingChunks !== void 0 ? missingChunks : [],
|
|
180
197
|
})
|
|
181
198
|
: null,
|
|
182
199
|
...errorExplanations,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { _Object } from '@aws-sdk/client-s3';
|
|
2
2
|
import type { RenderMetadata } from '../../defaults';
|
|
3
3
|
import type { EnhancedErrorInfo } from './write-lambda-error';
|
|
4
|
-
export declare const makeTimeoutError: ({ timeoutInMilliseconds,
|
|
4
|
+
export declare const makeTimeoutError: ({ timeoutInMilliseconds, missingChunks, renderMetadata, renderId, }: {
|
|
5
5
|
timeoutInMilliseconds: number;
|
|
6
6
|
chunks: _Object[];
|
|
7
7
|
renderMetadata: RenderMetadata;
|
|
8
8
|
renderId: string;
|
|
9
|
+
missingChunks: number[];
|
|
9
10
|
}) => EnhancedErrorInfo;
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.makeTimeoutError = void 0;
|
|
4
|
-
const parse_chunk_key_1 = require("../../shared/parse-chunk-key");
|
|
5
4
|
const make_timeout_message_1 = require("./make-timeout-message");
|
|
6
|
-
const makeTimeoutError = ({ timeoutInMilliseconds,
|
|
7
|
-
const availableChunks = chunks.map((c) => (0, parse_chunk_key_1.parseLambdaChunkKey)(c.Key));
|
|
8
|
-
const missingChunks = new Array(renderMetadata.totalChunks)
|
|
9
|
-
.fill(true)
|
|
10
|
-
.map((_, i) => i)
|
|
11
|
-
.filter((index) => {
|
|
12
|
-
return !availableChunks.find((c) => c.chunk === index);
|
|
13
|
-
});
|
|
5
|
+
const makeTimeoutError = ({ timeoutInMilliseconds, missingChunks, renderMetadata, renderId, }) => {
|
|
14
6
|
const message = (0, make_timeout_message_1.makeTimeoutMessage)({
|
|
15
7
|
missingChunks,
|
|
16
8
|
renderMetadata,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AudioCodec } from '@remotion/renderer';
|
|
2
|
+
import type { CustomCredentials } from '../../shared/aws-clients';
|
|
3
|
+
import type { PostRenderData, Privacy, RenderMetadata, SerializedInputProps } from '../../shared/constants';
|
|
4
|
+
import type { DownloadBehavior } from '../../shared/content-disposition-header';
|
|
5
|
+
import type { LambdaCodec } from '../../shared/validate-lambda-codec';
|
|
6
|
+
export type OnAllChunksAvailable = (options: {
|
|
7
|
+
inputProps: SerializedInputProps;
|
|
8
|
+
serializedResolvedProps: SerializedInputProps;
|
|
9
|
+
}) => void;
|
|
10
|
+
export declare const mergeChunksAndFinishRender: (options: {
|
|
11
|
+
bucketName: string;
|
|
12
|
+
renderId: string;
|
|
13
|
+
expectedBucketOwner: string;
|
|
14
|
+
frameCountLength: number;
|
|
15
|
+
codec: LambdaCodec;
|
|
16
|
+
chunkCount: number;
|
|
17
|
+
fps: number;
|
|
18
|
+
numberOfGifLoops: number | null;
|
|
19
|
+
audioCodec: AudioCodec | null;
|
|
20
|
+
renderBucketName: string;
|
|
21
|
+
customCredentials: CustomCredentials | null;
|
|
22
|
+
downloadBehavior: DownloadBehavior;
|
|
23
|
+
key: string;
|
|
24
|
+
privacy: Privacy;
|
|
25
|
+
inputProps: SerializedInputProps;
|
|
26
|
+
verbose: boolean;
|
|
27
|
+
serializedResolvedProps: SerializedInputProps;
|
|
28
|
+
renderMetadata: RenderMetadata;
|
|
29
|
+
onAllChunks: OnAllChunksAvailable;
|
|
30
|
+
}) => Promise<PostRenderData>;
|
|
@@ -0,0 +1,199 @@
|
|
|
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.mergeChunksAndFinishRender = void 0;
|
|
7
|
+
const renderer_1 = require("@remotion/renderer");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const cleanup_serialized_input_props_1 = require("../../shared/cleanup-serialized-input-props");
|
|
12
|
+
const constants_1 = require("../../shared/constants");
|
|
13
|
+
const concat_videos_1 = require("./concat-videos");
|
|
14
|
+
const create_post_render_data_1 = require("./create-post-render-data");
|
|
15
|
+
const delete_chunks_1 = require("./delete-chunks");
|
|
16
|
+
const get_current_region_1 = require("./get-current-region");
|
|
17
|
+
const get_files_to_delete_1 = require("./get-files-to-delete");
|
|
18
|
+
const get_output_url_from_metadata_1 = require("./get-output-url-from-metadata");
|
|
19
|
+
const inspect_errors_1 = require("./inspect-errors");
|
|
20
|
+
const io_1 = require("./io");
|
|
21
|
+
const write_lambda_error_1 = require("./write-lambda-error");
|
|
22
|
+
const write_post_render_data_1 = require("./write-post-render-data");
|
|
23
|
+
const mergeChunksAndFinishRender = async (options) => {
|
|
24
|
+
let lastProgressUploaded = 0;
|
|
25
|
+
const onProgress = (framesEncoded) => {
|
|
26
|
+
const relativeProgress = framesEncoded / options.frameCountLength;
|
|
27
|
+
const deltaSinceLastProgressUploaded = relativeProgress - lastProgressUploaded;
|
|
28
|
+
if (deltaSinceLastProgressUploaded < 0.1) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
lastProgressUploaded = relativeProgress;
|
|
32
|
+
(0, io_1.lambdaWriteFile)({
|
|
33
|
+
bucketName: options.bucketName,
|
|
34
|
+
key: (0, constants_1.encodingProgressKey)(options.renderId),
|
|
35
|
+
body: String(Math.round(framesEncoded / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
|
|
36
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
37
|
+
privacy: 'private',
|
|
38
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
39
|
+
downloadBehavior: null,
|
|
40
|
+
customCredentials: null,
|
|
41
|
+
}).catch((err) => {
|
|
42
|
+
(0, write_lambda_error_1.writeLambdaError)({
|
|
43
|
+
bucketName: options.bucketName,
|
|
44
|
+
errorInfo: {
|
|
45
|
+
chunk: null,
|
|
46
|
+
frame: null,
|
|
47
|
+
isFatal: false,
|
|
48
|
+
name: err.name,
|
|
49
|
+
message: err.message,
|
|
50
|
+
stack: `Could not upload stitching progress ${err.stack}`,
|
|
51
|
+
tmpDir: null,
|
|
52
|
+
type: 'stitcher',
|
|
53
|
+
attempt: 1,
|
|
54
|
+
totalAttempts: 1,
|
|
55
|
+
willRetry: false,
|
|
56
|
+
},
|
|
57
|
+
renderId: options.renderId,
|
|
58
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const onErrors = (errors) => {
|
|
63
|
+
renderer_1.RenderInternals.Log.error('Found Errors', errors);
|
|
64
|
+
const firstError = errors[0];
|
|
65
|
+
if (firstError.chunk !== null) {
|
|
66
|
+
throw new Error(`Stopping Lambda function because error occurred while rendering chunk ${firstError.chunk}:\n${errors[0].stack
|
|
67
|
+
.split('\n')
|
|
68
|
+
.map((s) => ` ${s}`)
|
|
69
|
+
.join('\n')}`);
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`Stopping Lambda function because error occurred: ${errors[0].stack}`);
|
|
72
|
+
};
|
|
73
|
+
const outdir = (0, node_path_1.join)(renderer_1.RenderInternals.tmpDir(constants_1.CONCAT_FOLDER_TOKEN), 'bucket');
|
|
74
|
+
if ((0, node_fs_1.existsSync)(outdir)) {
|
|
75
|
+
(0, node_fs_1.rmSync)(outdir, {
|
|
76
|
+
recursive: true,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
(0, node_fs_1.mkdirSync)(outdir);
|
|
80
|
+
const files = await (0, concat_videos_1.getAllFilesS3)({
|
|
81
|
+
bucket: options.bucketName,
|
|
82
|
+
expectedFiles: options.chunkCount,
|
|
83
|
+
outdir,
|
|
84
|
+
renderId: options.renderId,
|
|
85
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
86
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
87
|
+
onErrors,
|
|
88
|
+
});
|
|
89
|
+
options.onAllChunks({
|
|
90
|
+
inputProps: options.inputProps,
|
|
91
|
+
serializedResolvedProps: options.serializedResolvedProps,
|
|
92
|
+
});
|
|
93
|
+
const encodingStart = Date.now();
|
|
94
|
+
const { outfile, cleanupChunksProm } = await (0, concat_videos_1.concatVideosS3)({
|
|
95
|
+
onProgress,
|
|
96
|
+
numberOfFrames: options.frameCountLength,
|
|
97
|
+
codec: options.codec,
|
|
98
|
+
fps: options.fps,
|
|
99
|
+
numberOfGifLoops: options.numberOfGifLoops,
|
|
100
|
+
files,
|
|
101
|
+
outdir,
|
|
102
|
+
audioCodec: options.audioCodec,
|
|
103
|
+
});
|
|
104
|
+
const encodingStop = Date.now();
|
|
105
|
+
const outputSize = fs_1.default.statSync(outfile);
|
|
106
|
+
await (0, io_1.lambdaWriteFile)({
|
|
107
|
+
bucketName: options.renderBucketName,
|
|
108
|
+
key: options.key,
|
|
109
|
+
body: fs_1.default.createReadStream(outfile),
|
|
110
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
111
|
+
privacy: options.privacy,
|
|
112
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
113
|
+
downloadBehavior: options.downloadBehavior,
|
|
114
|
+
customCredentials: options.customCredentials,
|
|
115
|
+
});
|
|
116
|
+
const contents = await (0, io_1.lambdaLs)({
|
|
117
|
+
bucketName: options.bucketName,
|
|
118
|
+
prefix: (0, constants_1.rendersPrefix)(options.renderId),
|
|
119
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
120
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
121
|
+
});
|
|
122
|
+
const finalEncodingProgressProm = (0, io_1.lambdaWriteFile)({
|
|
123
|
+
bucketName: options.bucketName,
|
|
124
|
+
key: (0, constants_1.encodingProgressKey)(options.renderId),
|
|
125
|
+
body: String(Math.ceil(options.frameCountLength / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
|
|
126
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
127
|
+
privacy: 'private',
|
|
128
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
129
|
+
downloadBehavior: null,
|
|
130
|
+
customCredentials: null,
|
|
131
|
+
});
|
|
132
|
+
const errorExplanationsProm = (0, inspect_errors_1.inspectErrors)({
|
|
133
|
+
contents,
|
|
134
|
+
renderId: options.renderId,
|
|
135
|
+
bucket: options.bucketName,
|
|
136
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
137
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
138
|
+
});
|
|
139
|
+
const jobs = (0, get_files_to_delete_1.getFilesToDelete)({
|
|
140
|
+
chunkCount: options.chunkCount,
|
|
141
|
+
renderId: options.renderId,
|
|
142
|
+
});
|
|
143
|
+
const deletProm = options.verbose
|
|
144
|
+
? Promise.resolve(0)
|
|
145
|
+
: (0, delete_chunks_1.cleanupFiles)({
|
|
146
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
147
|
+
bucket: options.bucketName,
|
|
148
|
+
contents,
|
|
149
|
+
jobs,
|
|
150
|
+
});
|
|
151
|
+
const cleanupSerializedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedInputProps)({
|
|
152
|
+
bucketName: options.bucketName,
|
|
153
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
154
|
+
serialized: options.inputProps,
|
|
155
|
+
});
|
|
156
|
+
const cleanupResolvedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedResolvedProps)({
|
|
157
|
+
bucketName: options.bucketName,
|
|
158
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
159
|
+
serialized: options.serializedResolvedProps,
|
|
160
|
+
});
|
|
161
|
+
const outputUrl = (0, get_output_url_from_metadata_1.getOutputUrlFromMetadata)(options.renderMetadata, options.bucketName, options.customCredentials);
|
|
162
|
+
const postRenderData = (0, create_post_render_data_1.createPostRenderData)({
|
|
163
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
164
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
165
|
+
renderId: options.renderId,
|
|
166
|
+
memorySizeInMb: Number(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE),
|
|
167
|
+
renderMetadata: options.renderMetadata,
|
|
168
|
+
contents,
|
|
169
|
+
errorExplanations: await errorExplanationsProm,
|
|
170
|
+
timeToEncode: encodingStop - encodingStart,
|
|
171
|
+
timeToDelete: (await Promise.all([
|
|
172
|
+
deletProm,
|
|
173
|
+
cleanupSerializedInputPropsProm,
|
|
174
|
+
cleanupResolvedInputPropsProm,
|
|
175
|
+
])).reduce((a, b) => a + b, 0),
|
|
176
|
+
outputFile: {
|
|
177
|
+
lastModified: Date.now(),
|
|
178
|
+
size: outputSize.size,
|
|
179
|
+
url: outputUrl,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
await finalEncodingProgressProm;
|
|
183
|
+
await (0, write_post_render_data_1.writePostRenderData)({
|
|
184
|
+
bucketName: options.bucketName,
|
|
185
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
186
|
+
postRenderData,
|
|
187
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
188
|
+
renderId: options.renderId,
|
|
189
|
+
});
|
|
190
|
+
await (0, io_1.lambdaDeleteFile)({
|
|
191
|
+
bucketName: options.bucketName,
|
|
192
|
+
key: (0, constants_1.initalizedMetadataKey)(options.renderId),
|
|
193
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
194
|
+
customCredentials: null,
|
|
195
|
+
});
|
|
196
|
+
await Promise.all([cleanupChunksProm, fs_1.default.promises.rm(outfile)]);
|
|
197
|
+
return postRenderData;
|
|
198
|
+
};
|
|
199
|
+
exports.mergeChunksAndFinishRender = mergeChunksAndFinishRender;
|
package/dist/functions/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const streamify_response_1 = require("./helpers/streamify-response");
|
|
|
12
12
|
const streaming_payloads_1 = require("./helpers/streaming-payloads");
|
|
13
13
|
const info_1 = require("./info");
|
|
14
14
|
const launch_1 = require("./launch");
|
|
15
|
+
const merge_1 = require("./merge");
|
|
15
16
|
const progress_1 = require("./progress");
|
|
16
17
|
const renderer_2 = require("./renderer");
|
|
17
18
|
const start_1 = require("./start");
|
|
@@ -123,6 +124,19 @@ const innerHandler = async (params, responseStream, context) => {
|
|
|
123
124
|
});
|
|
124
125
|
return;
|
|
125
126
|
}
|
|
127
|
+
if (params.type === constants_1.LambdaRoutines.merge) {
|
|
128
|
+
(0, print_cloudwatch_helper_1.printCloudwatchHelper)(constants_1.LambdaRoutines.merge, {
|
|
129
|
+
renderId: params.renderId,
|
|
130
|
+
isWarm,
|
|
131
|
+
});
|
|
132
|
+
renderer_1.RenderInternals.setLogLevel(params.logLevel);
|
|
133
|
+
const response = await (0, merge_1.mergeHandler)(params, {
|
|
134
|
+
expectedBucketOwner: currentUserId,
|
|
135
|
+
});
|
|
136
|
+
responseStream.write(JSON.stringify(response), () => {
|
|
137
|
+
responseStream.end();
|
|
138
|
+
});
|
|
139
|
+
}
|
|
126
140
|
if (params.type === constants_1.LambdaRoutines.compositions) {
|
|
127
141
|
(0, print_cloudwatch_helper_1.printCloudwatchHelper)(constants_1.LambdaRoutines.compositions, {
|
|
128
142
|
isWarm,
|
package/dist/functions/launch.js
CHANGED
|
@@ -1,39 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = 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);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
3
|
exports.launchHandler = void 0;
|
|
27
4
|
const client_lambda_1 = require("@aws-sdk/client-lambda");
|
|
28
5
|
const renderer_1 = require("@remotion/renderer");
|
|
29
|
-
const node_fs_1 = __importStar(require("node:fs"));
|
|
30
|
-
const node_path_1 = require("node:path");
|
|
31
6
|
const version_1 = require("remotion/version");
|
|
32
7
|
const aws_clients_1 = require("../shared/aws-clients");
|
|
33
|
-
const cleanup_serialized_input_props_1 = require("../shared/cleanup-serialized-input-props");
|
|
34
8
|
const compress_props_1 = require("../shared/compress-props");
|
|
35
9
|
const constants_1 = require("../shared/constants");
|
|
36
10
|
const docs_url_1 = require("../shared/docs-url");
|
|
11
|
+
const get_aws_urls_1 = require("../shared/get-aws-urls");
|
|
37
12
|
const invoke_webhook_1 = require("../shared/invoke-webhook");
|
|
38
13
|
const validate_1 = require("../shared/validate");
|
|
39
14
|
const validate_frames_per_lambda_1 = require("../shared/validate-frames-per-lambda");
|
|
@@ -41,21 +16,15 @@ const validate_outname_1 = require("../shared/validate-outname");
|
|
|
41
16
|
const validate_privacy_1 = require("../shared/validate-privacy");
|
|
42
17
|
const plan_frame_ranges_1 = require("./chunk-optimization/plan-frame-ranges");
|
|
43
18
|
const best_frames_per_lambda_param_1 = require("./helpers/best-frames-per-lambda-param");
|
|
44
|
-
const concat_videos_1 = require("./helpers/concat-videos");
|
|
45
|
-
const create_post_render_data_1 = require("./helpers/create-post-render-data");
|
|
46
|
-
const delete_chunks_1 = require("./helpers/delete-chunks");
|
|
47
19
|
const expected_out_name_1 = require("./helpers/expected-out-name");
|
|
48
20
|
const find_output_file_in_bucket_1 = require("./helpers/find-output-file-in-bucket");
|
|
49
21
|
const get_browser_instance_1 = require("./helpers/get-browser-instance");
|
|
50
22
|
const get_current_region_1 = require("./helpers/get-current-region");
|
|
51
|
-
const get_files_to_delete_1 = require("./helpers/get-files-to-delete");
|
|
52
|
-
const get_output_url_from_metadata_1 = require("./helpers/get-output-url-from-metadata");
|
|
53
|
-
const inspect_errors_1 = require("./helpers/inspect-errors");
|
|
54
23
|
const io_1 = require("./helpers/io");
|
|
24
|
+
const merge_chunks_1 = require("./helpers/merge-chunks");
|
|
55
25
|
const timer_1 = require("./helpers/timer");
|
|
56
26
|
const validate_composition_1 = require("./helpers/validate-composition");
|
|
57
27
|
const write_lambda_error_1 = require("./helpers/write-lambda-error");
|
|
58
|
-
const write_post_render_data_1 = require("./helpers/write-post-render-data");
|
|
59
28
|
const callFunctionWithRetry = async ({ payload, retries, functionName, }) => {
|
|
60
29
|
try {
|
|
61
30
|
await (0, aws_clients_1.getLambdaClient)((0, get_current_region_1.getCurrentRegionInFunction)()).send(new client_lambda_1.InvokeCommand({
|
|
@@ -81,14 +50,12 @@ const callFunctionWithRetry = async ({ payload, retries, functionName, }) => {
|
|
|
81
50
|
throw err;
|
|
82
51
|
}
|
|
83
52
|
};
|
|
84
|
-
const innerLaunchHandler = async (params, options) => {
|
|
85
|
-
var _a, _b, _c, _d, _e
|
|
53
|
+
const innerLaunchHandler = async ({ functionName, params, options, onAllChunksAvailable, verbose, }) => {
|
|
54
|
+
var _a, _b, _c, _d, _e;
|
|
86
55
|
if (params.type !== constants_1.LambdaRoutines.launch) {
|
|
87
56
|
throw new Error('Expected launch type');
|
|
88
57
|
}
|
|
89
|
-
const functionName = (_a = params.rendererFunctionName) !== null && _a !== void 0 ? _a : process.env.AWS_LAMBDA_FUNCTION_NAME;
|
|
90
58
|
const startedDate = Date.now();
|
|
91
|
-
const verbose = renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose');
|
|
92
59
|
const browserInstance = await (0, get_browser_instance_1.getBrowserInstance)(params.logLevel, false, params.chromiumOptions);
|
|
93
60
|
const inputPropsPromise = (0, compress_props_1.decompressInputProps)({
|
|
94
61
|
bucketName: params.bucketName,
|
|
@@ -104,7 +71,7 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
104
71
|
composition: params.composition,
|
|
105
72
|
browserInstance,
|
|
106
73
|
serializedInputPropsWithCustomSchema,
|
|
107
|
-
envVariables: (
|
|
74
|
+
envVariables: (_a = params.envVariables) !== null && _a !== void 0 ? _a : {},
|
|
108
75
|
timeoutInMilliseconds: params.timeoutInMilliseconds,
|
|
109
76
|
chromiumOptions: params.chromiumOptions,
|
|
110
77
|
port: null,
|
|
@@ -131,15 +98,11 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
131
98
|
});
|
|
132
99
|
const realFrameRange = renderer_1.RenderInternals.getRealFrameRange(comp.durationInFrames, params.frameRange);
|
|
133
100
|
const frameCount = renderer_1.RenderInternals.getFramesToRender(realFrameRange, params.everyNthFrame);
|
|
134
|
-
const framesPerLambda = (
|
|
101
|
+
const framesPerLambda = (_b = params.framesPerLambda) !== null && _b !== void 0 ? _b : (0, best_frames_per_lambda_param_1.bestFramesPerLambdaParam)(frameCount.length);
|
|
135
102
|
(0, validate_frames_per_lambda_1.validateFramesPerLambda)({
|
|
136
103
|
framesPerLambda,
|
|
137
104
|
durationInFrames: frameCount.length,
|
|
138
105
|
});
|
|
139
|
-
const chunkCount = Math.ceil(frameCount.length / framesPerLambda);
|
|
140
|
-
if (chunkCount > constants_1.MAX_FUNCTIONS_PER_RENDER) {
|
|
141
|
-
throw new Error(`Too many functions: This render would cause ${chunkCount} functions to spawn. We limit this amount to ${constants_1.MAX_FUNCTIONS_PER_RENDER} functions as more would result in diminishing returns. Values set: frameCount = ${frameCount}, framesPerLambda=${framesPerLambda}. See ${docs_url_1.DOCS_URL}/docs/lambda/concurrency#too-many-functions for help.`);
|
|
142
|
-
}
|
|
143
106
|
(0, validate_outname_1.validateOutname)(params.outName, params.codec, params.audioCodec);
|
|
144
107
|
(0, validate_privacy_1.validatePrivacy)(params.privacy, true);
|
|
145
108
|
renderer_1.RenderInternals.validatePuppeteerTimeout(params.timeoutInMilliseconds);
|
|
@@ -148,6 +111,9 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
148
111
|
frameRange: realFrameRange,
|
|
149
112
|
everyNthFrame: params.everyNthFrame,
|
|
150
113
|
});
|
|
114
|
+
if (chunks.length > constants_1.MAX_FUNCTIONS_PER_RENDER) {
|
|
115
|
+
throw new Error(`Too many functions: This render would cause ${chunks.length} functions to spawn. We limit this amount to ${constants_1.MAX_FUNCTIONS_PER_RENDER} functions as more would result in diminishing returns. Values set: frameCount = ${frameCount}, framesPerLambda=${framesPerLambda}. See ${docs_url_1.DOCS_URL}/docs/lambda/concurrency#too-many-functions for help.`);
|
|
116
|
+
}
|
|
151
117
|
const sortedChunks = chunks.slice().sort((a, b) => a[0] - b[0]);
|
|
152
118
|
const reqSend = (0, timer_1.timer)('sending off requests');
|
|
153
119
|
const serializedResolved = (0, compress_props_1.serializeOrThrow)(comp.props, 'resolved-props');
|
|
@@ -232,16 +198,18 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
232
198
|
memorySizeInMb: Number(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE),
|
|
233
199
|
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
234
200
|
renderId: params.renderId,
|
|
235
|
-
outName: (
|
|
201
|
+
outName: (_c = params.outName) !== null && _c !== void 0 ? _c : undefined,
|
|
236
202
|
privacy: params.privacy,
|
|
237
203
|
everyNthFrame: params.everyNthFrame,
|
|
238
204
|
frameRange: realFrameRange,
|
|
239
205
|
audioCodec: params.audioCodec,
|
|
240
206
|
deleteAfter: params.deleteAfter,
|
|
207
|
+
numberOfGifLoops: params.numberOfGifLoops,
|
|
208
|
+
downloadBehavior: params.downloadBehavior,
|
|
241
209
|
};
|
|
242
210
|
const { key, renderBucketName, customCredentials } = (0, expected_out_name_1.getExpectedOutName)(renderMetadata, params.bucketName, typeof params.outName === 'string' || typeof params.outName === 'undefined'
|
|
243
211
|
? null
|
|
244
|
-
: (
|
|
212
|
+
: (_e = (_d = params.outName) === null || _d === void 0 ? void 0 : _d.s3OutputProvider) !== null && _e !== void 0 ? _e : null);
|
|
245
213
|
const output = await (0, find_output_file_in_bucket_1.findOutputFileInBucket)({
|
|
246
214
|
bucketName: params.bucketName,
|
|
247
215
|
customCredentials,
|
|
@@ -276,209 +244,78 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
276
244
|
await callFunctionWithRetry({ payload, retries: 0, functionName });
|
|
277
245
|
}));
|
|
278
246
|
reqSend.end();
|
|
279
|
-
let lastProgressUploaded = 0;
|
|
280
|
-
const onProgress = (framesEncoded) => {
|
|
281
|
-
const relativeProgress = framesEncoded / frameCount.length;
|
|
282
|
-
const deltaSinceLastProgressUploaded = relativeProgress - lastProgressUploaded;
|
|
283
|
-
if (deltaSinceLastProgressUploaded < 0.1) {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
lastProgressUploaded = relativeProgress;
|
|
287
|
-
(0, io_1.lambdaWriteFile)({
|
|
288
|
-
bucketName: params.bucketName,
|
|
289
|
-
key: (0, constants_1.encodingProgressKey)(params.renderId),
|
|
290
|
-
body: String(Math.round(framesEncoded / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
|
|
291
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
292
|
-
privacy: 'private',
|
|
293
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
294
|
-
downloadBehavior: null,
|
|
295
|
-
customCredentials: null,
|
|
296
|
-
}).catch((err) => {
|
|
297
|
-
(0, write_lambda_error_1.writeLambdaError)({
|
|
298
|
-
bucketName: params.bucketName,
|
|
299
|
-
errorInfo: {
|
|
300
|
-
chunk: null,
|
|
301
|
-
frame: null,
|
|
302
|
-
isFatal: false,
|
|
303
|
-
name: err.name,
|
|
304
|
-
message: err.message,
|
|
305
|
-
stack: `Could not upload stitching progress ${err.stack}`,
|
|
306
|
-
tmpDir: null,
|
|
307
|
-
type: 'stitcher',
|
|
308
|
-
attempt: 1,
|
|
309
|
-
totalAttempts: 1,
|
|
310
|
-
willRetry: false,
|
|
311
|
-
},
|
|
312
|
-
renderId: params.renderId,
|
|
313
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
};
|
|
317
|
-
const onErrors = (errors) => {
|
|
318
|
-
renderer_1.RenderInternals.Log.error('Found Errors', errors);
|
|
319
|
-
const firstError = errors[0];
|
|
320
|
-
if (firstError.chunk !== null) {
|
|
321
|
-
throw new Error(`Stopping Lambda function because error occurred while rendering chunk ${firstError.chunk}:\n${errors[0].stack
|
|
322
|
-
.split('\n')
|
|
323
|
-
.map((s) => ` ${s}`)
|
|
324
|
-
.join('\n')}`);
|
|
325
|
-
}
|
|
326
|
-
throw new Error(`Stopping Lambda function because error occurred: ${errors[0].stack}`);
|
|
327
|
-
};
|
|
328
247
|
const fps = comp.fps / params.everyNthFrame;
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
(0, node_fs_1.rmSync)(outdir, {
|
|
332
|
-
recursive: true,
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
(0, node_fs_1.mkdirSync)(outdir);
|
|
336
|
-
const files = await (0, concat_videos_1.getAllFilesS3)({
|
|
337
|
-
bucket: params.bucketName,
|
|
338
|
-
expectedFiles: chunkCount,
|
|
339
|
-
outdir,
|
|
248
|
+
const postRenderData = await (0, merge_chunks_1.mergeChunksAndFinishRender)({
|
|
249
|
+
bucketName: params.bucketName,
|
|
340
250
|
renderId: params.renderId,
|
|
341
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
342
251
|
expectedBucketOwner: options.expectedBucketOwner,
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const { outfile, cleanupChunksProm } = await (0, concat_videos_1.concatVideosS3)({
|
|
347
|
-
onProgress,
|
|
348
|
-
numberOfFrames: frameCount.length,
|
|
252
|
+
frameCountLength: frameCount.length,
|
|
253
|
+
audioCodec: params.audioCodec,
|
|
254
|
+
chunkCount: chunks.length,
|
|
349
255
|
codec: params.codec,
|
|
256
|
+
customCredentials,
|
|
257
|
+
downloadBehavior: params.downloadBehavior,
|
|
350
258
|
fps,
|
|
351
|
-
numberOfGifLoops: params.numberOfGifLoops,
|
|
352
|
-
files,
|
|
353
|
-
outdir,
|
|
354
|
-
audioCodec: params.audioCodec,
|
|
355
|
-
});
|
|
356
|
-
const encodingStop = Date.now();
|
|
357
|
-
const outputSize = node_fs_1.default.statSync(outfile);
|
|
358
|
-
await (0, io_1.lambdaWriteFile)({
|
|
359
|
-
bucketName: renderBucketName,
|
|
360
259
|
key,
|
|
361
|
-
|
|
362
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
260
|
+
numberOfGifLoops: params.numberOfGifLoops,
|
|
363
261
|
privacy: params.privacy,
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const contents = await (0, io_1.lambdaLs)({
|
|
369
|
-
bucketName: params.bucketName,
|
|
370
|
-
prefix: (0, constants_1.rendersPrefix)(params.renderId),
|
|
371
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
372
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
373
|
-
});
|
|
374
|
-
const finalEncodingProgressProm = (0, io_1.lambdaWriteFile)({
|
|
375
|
-
bucketName: params.bucketName,
|
|
376
|
-
key: (0, constants_1.encodingProgressKey)(params.renderId),
|
|
377
|
-
body: String(Math.ceil(frameCount.length / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
|
|
378
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
379
|
-
privacy: 'private',
|
|
380
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
381
|
-
downloadBehavior: null,
|
|
382
|
-
customCredentials: null,
|
|
383
|
-
});
|
|
384
|
-
const errorExplanationsProm = (0, inspect_errors_1.inspectErrors)({
|
|
385
|
-
contents,
|
|
386
|
-
renderId: params.renderId,
|
|
387
|
-
bucket: params.bucketName,
|
|
388
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
389
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
390
|
-
});
|
|
391
|
-
const jobs = (0, get_files_to_delete_1.getFilesToDelete)({
|
|
392
|
-
chunkCount,
|
|
393
|
-
renderId: params.renderId,
|
|
394
|
-
});
|
|
395
|
-
const deletProm = verbose
|
|
396
|
-
? Promise.resolve(0)
|
|
397
|
-
: (0, delete_chunks_1.cleanupFiles)({
|
|
398
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
399
|
-
bucket: params.bucketName,
|
|
400
|
-
contents,
|
|
401
|
-
jobs,
|
|
402
|
-
});
|
|
403
|
-
const cleanupSerializedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedInputProps)({
|
|
404
|
-
bucketName: params.bucketName,
|
|
405
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
406
|
-
serialized: params.inputProps,
|
|
407
|
-
});
|
|
408
|
-
const cleanupResolvedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedResolvedProps)({
|
|
409
|
-
bucketName: params.bucketName,
|
|
410
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
411
|
-
serialized: serializedResolvedProps,
|
|
412
|
-
});
|
|
413
|
-
const outputUrl = (0, get_output_url_from_metadata_1.getOutputUrlFromMetadata)(renderMetadata, params.bucketName, customCredentials);
|
|
414
|
-
const postRenderData = (0, create_post_render_data_1.createPostRenderData)({
|
|
415
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
416
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
417
|
-
renderId: params.renderId,
|
|
418
|
-
memorySizeInMb: Number(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE),
|
|
262
|
+
renderBucketName,
|
|
263
|
+
inputProps: params.inputProps,
|
|
264
|
+
serializedResolvedProps,
|
|
265
|
+
verbose,
|
|
419
266
|
renderMetadata,
|
|
420
|
-
|
|
421
|
-
errorExplanations: await errorExplanationsProm,
|
|
422
|
-
timeToEncode: encodingStop - encodingStart,
|
|
423
|
-
timeToDelete: (await Promise.all([
|
|
424
|
-
deletProm,
|
|
425
|
-
cleanupSerializedInputPropsProm,
|
|
426
|
-
cleanupResolvedInputPropsProm,
|
|
427
|
-
])).reduce((a, b) => a + b, 0),
|
|
428
|
-
outputFile: {
|
|
429
|
-
lastModified: Date.now(),
|
|
430
|
-
size: outputSize.size,
|
|
431
|
-
url: outputUrl,
|
|
432
|
-
},
|
|
267
|
+
onAllChunks: onAllChunksAvailable,
|
|
433
268
|
});
|
|
434
|
-
await finalEncodingProgressProm;
|
|
435
|
-
await (0, write_post_render_data_1.writePostRenderData)({
|
|
436
|
-
bucketName: params.bucketName,
|
|
437
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
438
|
-
postRenderData,
|
|
439
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
440
|
-
renderId: params.renderId,
|
|
441
|
-
});
|
|
442
|
-
await (0, io_1.lambdaDeleteFile)({
|
|
443
|
-
bucketName: params.bucketName,
|
|
444
|
-
key: (0, constants_1.initalizedMetadataKey)(params.renderId),
|
|
445
|
-
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
446
|
-
customCredentials: null,
|
|
447
|
-
});
|
|
448
|
-
await Promise.all([cleanupChunksProm, node_fs_1.default.promises.rm(outfile)]);
|
|
449
269
|
return postRenderData;
|
|
450
270
|
};
|
|
451
271
|
const launchHandler = async (params, options) => {
|
|
452
|
-
var _a, _b;
|
|
272
|
+
var _a, _b, _c;
|
|
453
273
|
if (params.type !== constants_1.LambdaRoutines.launch) {
|
|
454
274
|
throw new Error('Expected launch type');
|
|
455
275
|
}
|
|
456
|
-
let
|
|
457
|
-
const
|
|
276
|
+
let allChunksAvailable = null;
|
|
277
|
+
const functionName = (_a = params.rendererFunctionName) !== null && _a !== void 0 ? _a : process.env.AWS_LAMBDA_FUNCTION_NAME;
|
|
278
|
+
const verbose = renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose');
|
|
279
|
+
const onTimeout = async () => {
|
|
458
280
|
var _a;
|
|
459
|
-
if (
|
|
281
|
+
if (allChunksAvailable) {
|
|
282
|
+
renderer_1.RenderInternals.Log.info('All chunks are available, but the function is about to time out.');
|
|
283
|
+
renderer_1.RenderInternals.Log.info('Spawning another function to merge chunks.');
|
|
460
284
|
try {
|
|
461
|
-
await (
|
|
462
|
-
|
|
463
|
-
secret: params.webhook.secret,
|
|
285
|
+
await callFunctionWithRetry({
|
|
286
|
+
functionName,
|
|
464
287
|
payload: {
|
|
465
|
-
type:
|
|
288
|
+
type: constants_1.LambdaRoutines.merge,
|
|
466
289
|
renderId: params.renderId,
|
|
467
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
468
290
|
bucketName: params.bucketName,
|
|
469
|
-
|
|
291
|
+
verbose,
|
|
292
|
+
outName: params.outName,
|
|
293
|
+
serializedResolvedProps: allChunksAvailable.serializedResolvedProps,
|
|
294
|
+
inputProps: allChunksAvailable.inputProps,
|
|
295
|
+
logLevel: params.logLevel,
|
|
470
296
|
},
|
|
297
|
+
retries: 2,
|
|
471
298
|
});
|
|
472
|
-
|
|
299
|
+
renderer_1.RenderInternals.Log.info(`New function successfully invoked. See the CloudWatch logs for it:`);
|
|
300
|
+
renderer_1.RenderInternals.Log.info((0, get_aws_urls_1.getCloudwatchMethodUrl)({
|
|
301
|
+
functionName: process.env.AWS_LAMBDA_FUNCTION_NAME,
|
|
302
|
+
method: constants_1.LambdaRoutines.merge,
|
|
303
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
304
|
+
rendererFunctionName: params.rendererFunctionName,
|
|
305
|
+
renderId: params.renderId,
|
|
306
|
+
}));
|
|
307
|
+
renderer_1.RenderInternals.Log.info('This function will now time out.');
|
|
473
308
|
}
|
|
474
309
|
catch (err) {
|
|
475
310
|
if (process.env.NODE_ENV === 'test') {
|
|
476
311
|
throw err;
|
|
477
312
|
}
|
|
313
|
+
renderer_1.RenderInternals.Log.error('Failed to invoke additional function to merge videos:');
|
|
314
|
+
renderer_1.RenderInternals.Log.error(err);
|
|
478
315
|
await (0, write_lambda_error_1.writeLambdaError)({
|
|
479
316
|
bucketName: params.bucketName,
|
|
480
317
|
errorInfo: {
|
|
481
|
-
type: '
|
|
318
|
+
type: 'stitcher',
|
|
482
319
|
message: err.message,
|
|
483
320
|
name: err.name,
|
|
484
321
|
stack: err.stack,
|
|
@@ -493,60 +330,116 @@ const launchHandler = async (params, options) => {
|
|
|
493
330
|
renderId: params.renderId,
|
|
494
331
|
expectedBucketOwner: options.expectedBucketOwner,
|
|
495
332
|
});
|
|
496
|
-
renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
|
|
497
|
-
renderer_1.RenderInternals.Log.error(err);
|
|
498
333
|
}
|
|
499
334
|
}
|
|
500
|
-
|
|
335
|
+
if (!params.webhook) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (webhookInvoked) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
await (0, invoke_webhook_1.invokeWebhook)({
|
|
343
|
+
url: params.webhook.url,
|
|
344
|
+
secret: params.webhook.secret,
|
|
345
|
+
payload: {
|
|
346
|
+
type: 'timeout',
|
|
347
|
+
renderId: params.renderId,
|
|
348
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
349
|
+
bucketName: params.bucketName,
|
|
350
|
+
customData: (_a = params.webhook.customData) !== null && _a !== void 0 ? _a : null,
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
webhookInvoked = true;
|
|
354
|
+
}
|
|
355
|
+
catch (err) {
|
|
356
|
+
if (process.env.NODE_ENV === 'test') {
|
|
357
|
+
throw err;
|
|
358
|
+
}
|
|
359
|
+
renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
|
|
360
|
+
renderer_1.RenderInternals.Log.error(err);
|
|
361
|
+
await (0, write_lambda_error_1.writeLambdaError)({
|
|
362
|
+
bucketName: params.bucketName,
|
|
363
|
+
errorInfo: {
|
|
364
|
+
type: 'webhook',
|
|
365
|
+
message: err.message,
|
|
366
|
+
name: err.name,
|
|
367
|
+
stack: err.stack,
|
|
368
|
+
tmpDir: null,
|
|
369
|
+
frame: 0,
|
|
370
|
+
chunk: 0,
|
|
371
|
+
isFatal: false,
|
|
372
|
+
attempt: 1,
|
|
373
|
+
willRetry: false,
|
|
374
|
+
totalAttempts: 1,
|
|
375
|
+
},
|
|
376
|
+
renderId: params.renderId,
|
|
377
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
let webhookInvoked = false;
|
|
382
|
+
const webhookDueToTimeout = setTimeout(onTimeout, Math.max(options.getRemainingTimeInMillis() - 1000, 1000));
|
|
501
383
|
renderer_1.RenderInternals.Log.info(`Function has ${Math.max(options.getRemainingTimeInMillis() - 1000, 1000)} before it times out`);
|
|
502
384
|
try {
|
|
503
|
-
const postRenderData = await innerLaunchHandler(
|
|
385
|
+
const postRenderData = await innerLaunchHandler({
|
|
386
|
+
functionName,
|
|
387
|
+
params,
|
|
388
|
+
options,
|
|
389
|
+
onAllChunksAvailable: ({ inputProps, serializedResolvedProps }) => {
|
|
390
|
+
allChunksAvailable = { inputProps, serializedResolvedProps };
|
|
391
|
+
},
|
|
392
|
+
verbose,
|
|
393
|
+
});
|
|
504
394
|
clearTimeout(webhookDueToTimeout);
|
|
505
|
-
if (params.webhook
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
outputUrl: postRenderData.outputFile,
|
|
517
|
-
lambdaErrors: postRenderData.errors,
|
|
518
|
-
outputFile: postRenderData.outputFile,
|
|
519
|
-
timeToFinish: postRenderData.timeToFinish,
|
|
520
|
-
costs: postRenderData.cost,
|
|
521
|
-
},
|
|
522
|
-
});
|
|
523
|
-
webhookInvoked = true;
|
|
524
|
-
}
|
|
525
|
-
catch (err) {
|
|
526
|
-
if (process.env.NODE_ENV === 'test') {
|
|
527
|
-
throw err;
|
|
528
|
-
}
|
|
529
|
-
await (0, write_lambda_error_1.writeLambdaError)({
|
|
530
|
-
bucketName: params.bucketName,
|
|
531
|
-
errorInfo: {
|
|
532
|
-
type: 'webhook',
|
|
533
|
-
message: err.message,
|
|
534
|
-
name: err.name,
|
|
535
|
-
stack: err.stack,
|
|
536
|
-
tmpDir: null,
|
|
537
|
-
frame: 0,
|
|
538
|
-
chunk: 0,
|
|
539
|
-
isFatal: false,
|
|
540
|
-
attempt: 1,
|
|
541
|
-
willRetry: false,
|
|
542
|
-
totalAttempts: 1,
|
|
543
|
-
},
|
|
395
|
+
if (!params.webhook || webhookInvoked) {
|
|
396
|
+
return {
|
|
397
|
+
type: 'success',
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
try {
|
|
401
|
+
await (0, invoke_webhook_1.invokeWebhook)({
|
|
402
|
+
url: params.webhook.url,
|
|
403
|
+
secret: params.webhook.secret,
|
|
404
|
+
payload: {
|
|
405
|
+
type: 'success',
|
|
544
406
|
renderId: params.renderId,
|
|
545
407
|
expectedBucketOwner: options.expectedBucketOwner,
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
408
|
+
bucketName: params.bucketName,
|
|
409
|
+
customData: (_b = params.webhook.customData) !== null && _b !== void 0 ? _b : null,
|
|
410
|
+
outputUrl: postRenderData.outputFile,
|
|
411
|
+
lambdaErrors: postRenderData.errors,
|
|
412
|
+
outputFile: postRenderData.outputFile,
|
|
413
|
+
timeToFinish: postRenderData.timeToFinish,
|
|
414
|
+
costs: postRenderData.cost,
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
webhookInvoked = true;
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
if (process.env.NODE_ENV === 'test') {
|
|
421
|
+
throw err;
|
|
549
422
|
}
|
|
423
|
+
await (0, write_lambda_error_1.writeLambdaError)({
|
|
424
|
+
bucketName: params.bucketName,
|
|
425
|
+
errorInfo: {
|
|
426
|
+
type: 'webhook',
|
|
427
|
+
message: err.message,
|
|
428
|
+
name: err.name,
|
|
429
|
+
stack: err.stack,
|
|
430
|
+
tmpDir: null,
|
|
431
|
+
frame: 0,
|
|
432
|
+
chunk: 0,
|
|
433
|
+
isFatal: false,
|
|
434
|
+
attempt: 1,
|
|
435
|
+
willRetry: false,
|
|
436
|
+
totalAttempts: 1,
|
|
437
|
+
},
|
|
438
|
+
renderId: params.renderId,
|
|
439
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
440
|
+
});
|
|
441
|
+
renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
|
|
442
|
+
renderer_1.RenderInternals.Log.error(err);
|
|
550
443
|
}
|
|
551
444
|
return {
|
|
552
445
|
type: 'success',
|
|
@@ -586,7 +479,7 @@ const launchHandler = async (params, options) => {
|
|
|
586
479
|
renderId: params.renderId,
|
|
587
480
|
expectedBucketOwner: options.expectedBucketOwner,
|
|
588
481
|
bucketName: params.bucketName,
|
|
589
|
-
customData: (
|
|
482
|
+
customData: (_c = params.webhook.customData) !== null && _c !== void 0 ? _c : null,
|
|
590
483
|
errors: [err].map((e) => ({
|
|
591
484
|
message: e.message,
|
|
592
485
|
name: e.name,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LambdaPayload, PostRenderData } from '../defaults';
|
|
2
|
+
type Options = {
|
|
3
|
+
expectedBucketOwner: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const mergeHandler: (params: LambdaPayload, options: Options) => Promise<{
|
|
6
|
+
type: 'success';
|
|
7
|
+
postRenderData: PostRenderData;
|
|
8
|
+
}>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeHandler = void 0;
|
|
4
|
+
const renderer_1 = require("@remotion/renderer");
|
|
5
|
+
const defaults_1 = require("../defaults");
|
|
6
|
+
const expected_out_name_1 = require("./helpers/expected-out-name");
|
|
7
|
+
const get_current_region_1 = require("./helpers/get-current-region");
|
|
8
|
+
const get_render_metadata_1 = require("./helpers/get-render-metadata");
|
|
9
|
+
const merge_chunks_1 = require("./helpers/merge-chunks");
|
|
10
|
+
const mergeHandler = async (params, options) => {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
if (params.type !== defaults_1.LambdaRoutines.merge) {
|
|
13
|
+
throw new Error('Expected launch type');
|
|
14
|
+
}
|
|
15
|
+
renderer_1.RenderInternals.Log.info('This function has been started because the previous main function has timed out while merging together the chunks.');
|
|
16
|
+
renderer_1.RenderInternals.Log.info('The merging of chunks will now restart.');
|
|
17
|
+
const renderMetadata = await (0, get_render_metadata_1.getRenderMetadata)({
|
|
18
|
+
bucketName: params.bucketName,
|
|
19
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
20
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
21
|
+
renderId: params.renderId,
|
|
22
|
+
});
|
|
23
|
+
if (!renderMetadata.codec) {
|
|
24
|
+
throw new Error('expected codec');
|
|
25
|
+
}
|
|
26
|
+
const { key, renderBucketName, customCredentials } = (0, expected_out_name_1.getExpectedOutName)(renderMetadata, params.bucketName, typeof params.outName === 'string' || typeof params.outName === 'undefined'
|
|
27
|
+
? null
|
|
28
|
+
: (_b = (_a = params.outName) === null || _a === void 0 ? void 0 : _a.s3OutputProvider) !== null && _b !== void 0 ? _b : null);
|
|
29
|
+
const frameCount = renderer_1.RenderInternals.getFramesToRender(renderMetadata.frameRange, renderMetadata.everyNthFrame);
|
|
30
|
+
const fps = renderMetadata.videoConfig.fps / renderMetadata.everyNthFrame;
|
|
31
|
+
const postRenderData = await (0, merge_chunks_1.mergeChunksAndFinishRender)({
|
|
32
|
+
audioCodec: renderMetadata.audioCodec,
|
|
33
|
+
bucketName: params.bucketName,
|
|
34
|
+
chunkCount: renderMetadata.totalChunks,
|
|
35
|
+
codec: renderMetadata.codec,
|
|
36
|
+
customCredentials,
|
|
37
|
+
downloadBehavior: renderMetadata.downloadBehavior,
|
|
38
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
39
|
+
fps,
|
|
40
|
+
frameCountLength: frameCount.length,
|
|
41
|
+
inputProps: params.inputProps,
|
|
42
|
+
key,
|
|
43
|
+
numberOfGifLoops: renderMetadata.numberOfGifLoops,
|
|
44
|
+
privacy: renderMetadata.privacy,
|
|
45
|
+
renderBucketName,
|
|
46
|
+
renderId: params.renderId,
|
|
47
|
+
renderMetadata,
|
|
48
|
+
serializedResolvedProps: params.serializedResolvedProps,
|
|
49
|
+
verbose: params.verbose,
|
|
50
|
+
onAllChunks: () => {
|
|
51
|
+
renderer_1.RenderInternals.Log.info('All chunks have been downloaded now.');
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return { type: 'success', postRenderData };
|
|
55
|
+
};
|
|
56
|
+
exports.mergeHandler = mergeHandler;
|
package/dist/functions/still.js
CHANGED
|
@@ -115,6 +115,8 @@ const innerStillHandler = async ({ params: lambdaParams, expectedBucketOwner, re
|
|
|
115
115
|
frameRange: [lambdaParams.frame, lambdaParams.frame],
|
|
116
116
|
audioCodec: null,
|
|
117
117
|
deleteAfter: lambdaParams.deleteAfter,
|
|
118
|
+
numberOfGifLoops: null,
|
|
119
|
+
downloadBehavior: lambdaParams.downloadBehavior,
|
|
118
120
|
};
|
|
119
121
|
await (0, io_1.lambdaWriteFile)({
|
|
120
122
|
bucketName,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AudioCodec, ChromiumOptions,
|
|
1
|
+
import type { AudioCodec, ChromiumOptions, ColorSpace, FrameRange, LogLevel, PixelFormat, ProResProfile, StillImageFormat, ToOptions, VideoImageFormat, X264Preset } from '@remotion/renderer';
|
|
2
2
|
import type { BrowserSafeApis } from '@remotion/renderer/client';
|
|
3
3
|
import type { VideoConfig } from 'remotion';
|
|
4
4
|
import type { ChunkRetry } from '../functions/helpers/get-retry-stats';
|
|
@@ -95,7 +95,8 @@ export declare enum LambdaRoutines {
|
|
|
95
95
|
status = "status",
|
|
96
96
|
renderer = "renderer",
|
|
97
97
|
still = "still",
|
|
98
|
-
compositions = "compositions"
|
|
98
|
+
compositions = "compositions",
|
|
99
|
+
merge = "merge"
|
|
99
100
|
}
|
|
100
101
|
type Prettify<T> = {
|
|
101
102
|
[K in keyof T]: T[K];
|
|
@@ -264,7 +265,7 @@ export type LambdaPayloads = {
|
|
|
264
265
|
timeoutInMilliseconds: number;
|
|
265
266
|
chromiumOptions: ChromiumOptions;
|
|
266
267
|
scale: number;
|
|
267
|
-
downloadBehavior: DownloadBehavior
|
|
268
|
+
downloadBehavior: DownloadBehavior;
|
|
268
269
|
version: string;
|
|
269
270
|
forceHeight: number | null;
|
|
270
271
|
forceWidth: number | null;
|
|
@@ -284,6 +285,16 @@ export type LambdaPayloads = {
|
|
|
284
285
|
bucketName: string | null;
|
|
285
286
|
offthreadVideoCacheSizeInBytes: number | null;
|
|
286
287
|
};
|
|
288
|
+
merge: {
|
|
289
|
+
type: LambdaRoutines.merge;
|
|
290
|
+
bucketName: string;
|
|
291
|
+
renderId: string;
|
|
292
|
+
outName: OutNameInput | null;
|
|
293
|
+
inputProps: SerializedInputProps;
|
|
294
|
+
serializedResolvedProps: SerializedInputProps;
|
|
295
|
+
verbose: boolean;
|
|
296
|
+
logLevel: LogLevel;
|
|
297
|
+
};
|
|
287
298
|
};
|
|
288
299
|
export type LambdaPayload = LambdaPayloads[LambdaRoutines];
|
|
289
300
|
export type EncodingProgress = {
|
|
@@ -304,7 +315,7 @@ export type RenderMetadata = Discriminated & {
|
|
|
304
315
|
estimatedTotalLambdaInvokations: number;
|
|
305
316
|
estimatedRenderLambdaInvokations: number;
|
|
306
317
|
compositionId: string;
|
|
307
|
-
codec:
|
|
318
|
+
codec: LambdaCodec | null;
|
|
308
319
|
audioCodec: AudioCodec | null;
|
|
309
320
|
inputProps: SerializedInputProps;
|
|
310
321
|
framesPerLambda: number;
|
|
@@ -317,6 +328,8 @@ export type RenderMetadata = Discriminated & {
|
|
|
317
328
|
frameRange: [number, number];
|
|
318
329
|
everyNthFrame: number;
|
|
319
330
|
deleteAfter: DeleteAfter | null;
|
|
331
|
+
numberOfGifLoops: number | null;
|
|
332
|
+
downloadBehavior: DownloadBehavior;
|
|
320
333
|
};
|
|
321
334
|
export type AfterRenderCost = {
|
|
322
335
|
estimatedCost: number;
|
package/dist/shared/constants.js
CHANGED
|
@@ -103,6 +103,7 @@ var LambdaRoutines;
|
|
|
103
103
|
LambdaRoutines["renderer"] = "renderer";
|
|
104
104
|
LambdaRoutines["still"] = "still";
|
|
105
105
|
LambdaRoutines["compositions"] = "compositions";
|
|
106
|
+
LambdaRoutines["merge"] = "merge";
|
|
106
107
|
})(LambdaRoutines = exports.LambdaRoutines || (exports.LambdaRoutines = {}));
|
|
107
108
|
exports.LAMBDA_CONCURRENCY_LIMIT_QUOTA = 'L-B99A9384';
|
|
108
109
|
exports.LAMBDA_BURST_LIMIT_QUOTA = 'L-548AE339';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { compositionsHandler } from '../functions/compositions';
|
|
2
2
|
import type { infoHandler } from '../functions/info';
|
|
3
3
|
import type { launchHandler } from '../functions/launch';
|
|
4
|
+
import type { mergeHandler } from '../functions/merge';
|
|
4
5
|
import type { progressHandler } from '../functions/progress';
|
|
5
6
|
import type { rendererHandler } from '../functions/renderer';
|
|
6
7
|
import type { startHandler } from '../functions/start';
|
|
@@ -19,4 +20,5 @@ export interface LambdaReturnValues {
|
|
|
19
20
|
[LambdaRoutines.info]: ReturnType<typeof infoHandler>;
|
|
20
21
|
[LambdaRoutines.still]: ReturnType<typeof stillHandler>;
|
|
21
22
|
[LambdaRoutines.compositions]: ReturnType<typeof compositionsHandler>;
|
|
23
|
+
[LambdaRoutines.merge]: ReturnType<typeof mergeHandler>;
|
|
22
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/lambda",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.45",
|
|
4
4
|
"description": "Distributed renderer for Remotion based on AWS Lambda",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"aws-policies": "^1.0.1",
|
|
27
27
|
"mime-types": "2.1.34",
|
|
28
28
|
"zod": "3.21.4",
|
|
29
|
-
"@remotion/
|
|
30
|
-
"remotion": "4.0.
|
|
31
|
-
"@remotion/renderer": "4.0.
|
|
32
|
-
"
|
|
29
|
+
"@remotion/cli": "4.0.45",
|
|
30
|
+
"@remotion/bundler": "4.0.45",
|
|
31
|
+
"@remotion/renderer": "4.0.45",
|
|
32
|
+
"remotion": "4.0.45"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@jonny/eslint-config": "3.0.266",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"ts-node": "^10.8.0",
|
|
44
44
|
"vitest": "0.31.1",
|
|
45
45
|
"zip-lib": "^0.7.2",
|
|
46
|
-
"@remotion/bundler": "4.0.
|
|
47
|
-
"@remotion/compositor-linux-arm64-gnu": "4.0.
|
|
46
|
+
"@remotion/bundler": "4.0.45",
|
|
47
|
+
"@remotion/compositor-linux-arm64-gnu": "4.0.45"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@remotion/bundler": "4.0.
|
|
50
|
+
"@remotion/bundler": "4.0.45"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
package/remotionlambda-arm64.zip
CHANGED
|
Binary file
|